├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── app ├── api │ ├── favorites │ │ ├── [name] │ │ │ └── route.ts │ │ └── route.ts │ ├── getPokemon │ │ └── route.js │ └── nvisionParser │ │ └── route.js ├── components │ ├── FavoriteCard.tsx │ ├── PokemonList.tsx │ ├── SavePokemon.tsx │ └── ServerCard.tsx ├── favorites │ └── page.tsx ├── layout.tsx ├── loading.tsx ├── models │ └── FavoritesModel.ts ├── nvisionDashboard │ ├── Wrapper.tsx │ └── page.tsx ├── page.tsx └── whos │ └── [name] │ └── page.tsx ├── assets ├── TableGifHigh.gif └── treeGif.gif ├── instrumentation.js ├── next.config.js ├── nvisionServer.js ├── package.json ├── postcss.config.js ├── styles └── globals.css ├── tailwind.config.js ├── tsconfig.json ├── types.ts └── utils └── dbConnect.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | /dist 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | .env 39 | dev.db* 40 | node_modules 41 | package-lock.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 OSLabs Beta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nVision 2 | 3 | nVision is an open-source developer tool for Next.js applications that provides users server-side network request metrics and an interactive hierarchical file tree, aiding with rapid debugging and deployment. 4 | 5 | _Note: nVision currently only supports App Router_ 6 | 7 | ## Getting Started 8 | 9 | Run the following commands to install nVision's npm package and add the necessary files required to implement nVision: 10 | ```bash 11 | npm install nvisionjs 12 | npx nvisionjs-create 13 | ``` 14 | 15 | Add the below to your `next.config.js` 16 | ```javascript 17 | experimental: { instrumentationHook: true }, 18 | ``` 19 | 20 | Add the following script to your `package.json` 21 | ```json 22 | "nvision": "node --require ./nvisionServer.js & next dev" 23 | ``` 24 | 25 | Run the following command to start the development server 26 | ```bash 27 | npm run nvision 28 | ``` 29 | 30 | Open your dashboard by going [http://localhost:3000/nvisionDashboard](http://localhost:3000/nvisionDashboard) (or wherever your app is hosted) 31 | 32 | Open your application in a new window to view real time updates on the dashboard 33 | 34 | 35 | ## Features 36 | - Users can interact with their app and view server-side network activity on the dashboard table such as routes, status codes, methods and duration of network calls 37 | - Users can view the directory structure of their app in tree form to help visualize complex applications 38 | 39 | 40 | ## Examples 41 | ### Table view 42 |

43 |    44 |

45 | 46 | ### Tree view 47 |

48 |    49 |

50 | 51 | 52 | ## Upcoming Features 53 | - Augmented metrics for client-side and database requests 54 | - Expanded network activity visualization 55 | - Support for Pages Router 56 | - New dashboard tab to display route connections between pages 57 | 58 | 59 | ## Contributors 60 | 61 | Caitlin O'Donohue - [GitHub](https://github.com/codeFromCO) | [Linkedin](https://www.linkedin.com/in/caitlin-odonohue/) 62 | 63 | Sunny Pacheco - [GitHub](https://github.com/xsunnibunnix) | [Linkedin](https://www.linkedin.com/in/sunnypacheco/) 64 | 65 | Jiyoung Lee - [GitHub](https://github.com/jiyoungglee/) | [Linkedin](https://www.linkedin.com/in/jiyoung-g-lee/) 66 | 67 | Isaac Lee - [GitHub](https://github.com/Third-Isaac) | [Linkedin](https://www.linkedin.com/in/thirdisaac/) 68 | 69 | Bennett Ma - [GitHub](https://github.com/bmgitcode) | [Linkedin](https://www.linkedin.com/in/bennett-ma/) 70 | 71 | 72 | ## Special Mentions 73 | Special thanks to the [NetPulse](https://github.com/oslabs-beta/NetPulse) team for their advice and inspiration. 74 | 75 | 76 | ## License 77 | 78 | Distributed under the MIT License. See [License](https://choosealicense.com/licenses/mit/) for more information. 79 | 80 | ## Tech Stack 81 |
82 | 83 | ![JavaScript](https://img.shields.io/badge/javascript-%23323330.svg?style=for-the-badge&logo=javascript&logoColor=%23F7DF1E) 84 | ![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white) 85 | ![Next.js](https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white) 86 | ![React](https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB) 87 | ![NPM](https://img.shields.io/badge/npm-CB3837?style=for-the-badge&logo=npm&logoColor=white) 88 | ![NodeJS](https://img.shields.io/badge/node.js-6DA55F?style=for-the-badge&logo=node.js&logoColor=white) 89 | ![Express](https://img.shields.io/badge/Express.js-000000?style=for-the-badge&logo=express&logoColor=white) 90 | ![WebSocket](https://img.shields.io/badge/WS-Websocket-2ea44f?style=for-the-badge&logo=appveyor) 91 | ![MUI](https://img.shields.io/badge/Material%20UI-007FFF?style=for-the-badge&logo=mui&logoColor=white) 92 | ![OpenTelemetry](https://img.shields.io/badge/OpenTelemetry-3d348b?style=for-the-badge&logo=opentelemetry&logoColor=white) 93 | ![d3js](https://img.shields.io/badge/d3-red?style=for-the-badge&logo=d3.js) 94 | ![Webpack](https://img.shields.io/badge/webpack-%238DD6F9.svg?style=for-the-badge&logo=webpack&logoColor=black) 95 | 96 |
97 | -------------------------------------------------------------------------------- /app/api/favorites/[name]/route.ts: -------------------------------------------------------------------------------- 1 | import Favorite from "@/app/models/FavoritesModel"; 2 | import { connectToDB } from "@/utils/dbConnect"; 3 | 4 | export async function POST(request: Request, { params }: { params: { name: string } }) { 5 | try { 6 | await connectToDB(); 7 | const newFavorite = new Favorite({name: params.name}) 8 | await newFavorite.save(); 9 | return new Response(JSON.stringify(newFavorite), { status: 201 }); 10 | } catch(err) { 11 | return new Response("Failed to add to favorites", { status: 500 }); 12 | } 13 | } 14 | 15 | export async function DELETE(request: Request, { params }: { params: { name: string } }) { 16 | try { 17 | await connectToDB(); 18 | const deleted = await Favorite.findOneAndDelete({name: params.name}); 19 | return new Response(JSON.stringify(deleted), { status: 200 }); 20 | } catch(err) { 21 | return new Response("Failed to remove from favorites", { status: 500 }); 22 | } 23 | } -------------------------------------------------------------------------------- /app/api/favorites/route.ts: -------------------------------------------------------------------------------- 1 | import Favorite from '@/app/models/FavoritesModel'; 2 | import { connectToDB } from '@/utils/dbConnect'; 3 | 4 | export async function GET(request: Request) { 5 | try { 6 | await connectToDB(); 7 | const favorites = await Favorite.find(); 8 | 9 | return new Response(JSON.stringify(favorites), { status: 200 }); 10 | } catch (err) { 11 | return new Response('Failed to get favorites', { status: 500 }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/api/getPokemon/route.js: -------------------------------------------------------------------------------- 1 | import { NextResponse } from 'next/server'; 2 | 3 | export async function GET() { 4 | const res = await fetch(`https://pokeapi.co/api/v2/pokemon/`, { 5 | cache: 'no-store', 6 | }); 7 | const data = await res.json(); 8 | return NextResponse.json(data, { status: 200 }); 9 | } 10 | -------------------------------------------------------------------------------- /app/api/nvisionParser/route.js: -------------------------------------------------------------------------------- 1 | import fileParser from '@nvisionjs/parse' 2 | 3 | const path = require('path'); 4 | 5 | export async function GET(request) { 6 | try { 7 | const appDirPath = path.join(process.cwd(), 'app'); 8 | const results = await fileParser(appDirPath) 9 | return new Response(JSON.stringify(results)) 10 | } 11 | catch(e) { 12 | console.error(e) 13 | } 14 | } -------------------------------------------------------------------------------- /app/components/FavoriteCard.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import { useEffect, useState } from 'react'; 3 | 4 | interface CardProps { 5 | name: string; 6 | deleteFunc?: Function; 7 | } 8 | 9 | const FavoriteCard = (props: CardProps) => { 10 | const [pokemonPhoto, setPokemonPhoto] = useState(''); 11 | 12 | useEffect(() => { 13 | async function fetchPokemonInfo() { 14 | const response = await fetch( 15 | `https://pokeapi.co/api/v2/pokemon/${props.name}` 16 | ); 17 | const data = await response.json(); 18 | 19 | setPokemonPhoto(data.sprites.front_default); 20 | } 21 | 22 | fetchPokemonInfo(); 23 | }, [props.name]); 24 | 25 | return ( 26 |
27 |

28 | {props.name[0].toUpperCase().concat(props.name.slice(1))} 29 |

30 | {`A 31 | 32 | 33 | 34 | {props.deleteFunc && ( 35 | 43 | )} 44 |
45 | ); 46 | }; 47 | 48 | export default FavoriteCard; 49 | -------------------------------------------------------------------------------- /app/components/PokemonList.tsx: -------------------------------------------------------------------------------- 1 | import { v4 as uuid } from 'uuid'; 2 | import ServerCard from './ServerCard'; 3 | 4 | const fetchAllPokemon = async () => { 5 | try { 6 | const response = await fetch('https://pokeapi.co/api/v2/pokemon/', { 7 | method: 'GET', 8 | }); 9 | const data = await response.json(); 10 | return data.results; 11 | } catch (err) { 12 | console.error(err); 13 | } 14 | }; 15 | 16 | const PokemonList = async () => { 17 | const pokemon = await fetchAllPokemon(); 18 | return ( 19 |
20 | {pokemon.map(({name}: {name: string}) => { 21 | return ; 22 | })} 23 |
24 | ); 25 | }; 26 | 27 | export default PokemonList; -------------------------------------------------------------------------------- /app/components/SavePokemon.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import Link from "next/link"; 4 | 5 | export const SavePokemon = (props) => { 6 | const { pokemonName } = props; 7 | function savePokemon(name: String) { 8 | fetch(`/api/favorites/${name}/`, { 9 | method: 'POST', 10 | }); 11 | } 12 | 13 | return ( 14 |
15 | 16 | 22 | 23 |
24 | ) 25 | } -------------------------------------------------------------------------------- /app/components/ServerCard.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | 3 | interface CardProps { 4 | name: string; 5 | deleteFunc?: Function; 6 | } 7 | 8 | const fetchPokemonInfo = async (name: string) => { 9 | const response = await fetch( 10 | `https://pokeapi.co/api/v2/pokemon/${name}` 11 | ); 12 | const data = await response.json(); 13 | 14 | return data.sprites.front_default; 15 | }; 16 | 17 | const ServerCard = async (props: CardProps) => { 18 | const pokemonPhoto = await fetchPokemonInfo(props.name) 19 | 20 | return ( 21 |
22 |

23 | {props.name[0].toUpperCase().concat(props.name.slice(1))} 24 |

25 | 26 | 27 | 28 | 29 | {props.deleteFunc && ( 30 | 38 | )} 39 |
40 | ); 41 | }; 42 | 43 | export default ServerCard; -------------------------------------------------------------------------------- /app/favorites/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import Link from 'next/link'; 3 | import { useEffect, useState } from 'react'; 4 | import FavoriteCard from '../components/FavoriteCard'; 5 | import { v4 as uuid } from 'uuid'; 6 | 7 | interface PokemonObj { 8 | name: string; 9 | } 10 | 11 | const Favorites = () => { 12 | const [favorites, setFavorites] = useState<[]>([]); 13 | 14 | async function deletePokemon(name: String) { 15 | await fetch(`/api/favorites/${name}/`, { 16 | method: 'DELETE', 17 | }); 18 | getFavs(); 19 | } 20 | 21 | const getFavs = async () => { 22 | try { 23 | const response = await fetch('/api/favorites', { 24 | method: 'GET', 25 | }); 26 | const data = await response.json(); 27 | setFavorites(data); 28 | } catch (err) { 29 | console.error(err); 30 | } 31 | }; 32 | 33 | useEffect(() => { 34 | getFavs(); 35 | }, []); 36 | 37 | return ( 38 |
39 |

Favorite Pokemon

40 |
41 | 42 | 43 | 44 |
45 |
46 | {favorites.map((pokemon: PokemonObj) => ( 47 | 52 | ))} 53 |
54 |
55 | ); 56 | }; 57 | 58 | export default Favorites; 59 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css'; 2 | 3 | export const metadata = { 4 | title: 'nVision demo app', 5 | description: 'created by nVision', 6 | }; 7 | 8 | export default function RootLayout({ 9 | children, 10 | }: { 11 | children: React.ReactNode; 12 | }) { 13 | return ( 14 | 15 | 16 |
17 |
18 |
19 | 20 |
{children}
21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /app/loading.tsx: -------------------------------------------------------------------------------- 1 | const Loading = () => { 2 | return

Loading...

; 3 | }; 4 | 5 | export default Loading; 6 | -------------------------------------------------------------------------------- /app/models/FavoritesModel.ts: -------------------------------------------------------------------------------- 1 | import { Schema, model, models } from 'mongoose'; 2 | 3 | interface Favorite { 4 | name: object; 5 | } 6 | 7 | const FavoriteSchema = new Schema({ 8 | name: { 9 | type: String, 10 | unique: [true, 'You can only favorite a pokemon once'], 11 | }, 12 | }); 13 | 14 | const Favorite = models.Favorite || model('Favorite', FavoriteSchema); 15 | 16 | export default Favorite; 17 | -------------------------------------------------------------------------------- /app/nvisionDashboard/Wrapper.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import Dashboard from '@nvisionjs/dashboard'; 4 | import React from 'react'; 5 | 6 | const Wrapper = (props) => { 7 | const {info} = props 8 | return ( 9 | 10 | ) 11 | } 12 | 13 | export default Wrapper; -------------------------------------------------------------------------------- /app/nvisionDashboard/page.tsx: -------------------------------------------------------------------------------- 1 | import Wrapper from './Wrapper'; 2 | 3 | async function getFiles() { 4 | const files = await fetch('http://localhost:3000/api/nvisionParser', { 5 | method: 'GET', 6 | cache: 'no-store' 7 | }); 8 | const parsedFiles = await files.json(); 9 | return parsedFiles; 10 | } 11 | 12 | export default async function Dashboard() { 13 | const result = await getFiles(); 14 | 15 | return ( 16 | <> 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import PokemonList from './components/PokemonList'; 3 | 4 | const Home = () => { 5 | return ( 6 |
7 |

Pokemon

8 | 9 | 10 | 11 | 12 |
13 | ); 14 | }; 15 | 16 | export default Home; 17 | -------------------------------------------------------------------------------- /app/whos/[name]/page.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import { SavePokemon } from '@/app/components/SavePokemon'; 3 | 4 | async function fetchPokemonInfo(name: String) { 5 | const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`); 6 | 7 | const data = await response.json(); 8 | 9 | return data; 10 | } 11 | 12 | interface pokemonObj { 13 | name: String; 14 | } 15 | 16 | interface contextObj { 17 | params: pokemonObj; 18 | } 19 | 20 | const PokemonInfo = async (context: contextObj) => { 21 | const pokemonName = context.params.name; 22 | const charStats = await fetchPokemonInfo(pokemonName); 23 | 24 | return ( 25 |
26 |

Get Stats

27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 |

39 | Name: 40 | {charStats.forms[0].name[0] 41 | .toUpperCase() 42 | .concat(charStats.forms[0].name.slice(1))}{' '} 43 |

44 |

45 | Type: 46 | {charStats.types[0].type.name} 47 |

48 |

49 | Height: 50 | {charStats.height} 51 |

52 |

53 | Weight: 54 | {charStats.weight} 55 |

56 |
57 |
58 | {`A 62 |
63 | 64 |
65 |
66 |
67 | ); 68 | }; 69 | 70 | export default PokemonInfo; 71 | -------------------------------------------------------------------------------- /assets/TableGifHigh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/nVision/d7f3e3379deefa08708729d59cc7fa4af193de6a/assets/TableGifHigh.gif -------------------------------------------------------------------------------- /assets/treeGif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/nVision/d7f3e3379deefa08708729d59cc7fa4af193de6a/assets/treeGif.gif -------------------------------------------------------------------------------- /instrumentation.js: -------------------------------------------------------------------------------- 1 | export async function register() { 2 | console.log('registered'); 3 | if (process.env.NEXT_RUNTIME === 'nodejs') { 4 | const {startTrace} = await import('@nvisionjs/trace'); 5 | startTrace(); 6 | } 7 | } -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | experimental: { 4 | instrumentationHook: true 5 | }, 6 | // webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => { 7 | // config.externals.push({ 8 | // 'utf-8-validate': 'commonjs utf-8-validate', 9 | // 'bufferutil': 'commonjs bufferutil', 10 | // }) 11 | // return config 12 | // }, 13 | } 14 | 15 | module.exports = nextConfig 16 | -------------------------------------------------------------------------------- /nvisionServer.js: -------------------------------------------------------------------------------- 1 | require('@nvisionjs/server'); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pokemon", 3 | "version": "0.1.0", 4 | "private": true, 5 | "contributors": [ 6 | "Bennett Ma", 7 | "Caitlin O'Donohue", 8 | "Isaac Lee", 9 | "Jiyoung Lee", 10 | "Sunny Pacheco" 11 | ], 12 | "keywords": [ 13 | "nextjs", 14 | "next", 15 | "react", 16 | "devtool" 17 | ], 18 | "license": "MIT", 19 | "homepage": "http://nvisionjs.com", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/oslabs-beta/nVision" 23 | }, 24 | "scripts": { 25 | "nvision": "node --require ./nvisionServer.js & next dev", 26 | "dev": "next dev", 27 | "build": "next build", 28 | "start": "next start", 29 | "server": "node server.js && npm run start", 30 | "lint": "next lint" 31 | }, 32 | "dependencies": { 33 | "@types/node": "^20.4.0", 34 | "@types/react": "18.2.14", 35 | "@types/react-dom": "18.2.6", 36 | "autoprefixer": "10.4.14", 37 | "dotenv": "^16.3.1", 38 | "eslint": "8.44.0", 39 | "eslint-config-next": "13.4.3", 40 | "express": "^4.18.2", 41 | "mongoose": "^7.4.0", 42 | "next": "^13.4.12", 43 | "nvisionjs": "^1.2.5", 44 | "react": "18.2.0", 45 | "react-dom": "18.2.0", 46 | "uuid": "^9.0.0" 47 | }, 48 | "devDependencies": { 49 | "@types/uuid": "^9.0.2", 50 | "autoprefixer": "^10.4.14", 51 | "daisyui": "^3.2.1", 52 | "nodemon": "^3.0.1", 53 | "postcss": "^8.4.25", 54 | "prisma": "^4.16.2", 55 | "tailwindcss": "^3.3.2", 56 | "ts-node": "^10.9.1", 57 | "typescript": "^5.1.6" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"); 2 | 3 | @tailwind base; 4 | @tailwind components; 5 | @tailwind utilities; 6 | 7 | /* 8 | Note: The styles for this gradient grid background is heavily inspired by the creator of this amazing site (https://dub.sh) – all credits go to them! 9 | */ 10 | 11 | .main { 12 | width: 100vw; 13 | min-height: 100vh; 14 | position: fixed; 15 | display: flex; 16 | justify-content: center; 17 | padding: 120px 24px 160px 24px; 18 | pointer-events: none; 19 | } 20 | 21 | .main:before { 22 | background: radial-gradient(circle, rgba(2, 0, 36, 0) 0, #fafafa 100%); 23 | position: absolute; 24 | content: ""; 25 | z-index: 2; 26 | width: 100%; 27 | height: 100%; 28 | top: 0; 29 | } 30 | 31 | .main:after { 32 | content: ""; 33 | z-index: 1; 34 | position: absolute; 35 | width: 100%; 36 | height: 100%; 37 | top: 0; 38 | opacity: 0.4; 39 | filter: invert(1); 40 | } 41 | 42 | .gradient { 43 | height: fit-content; 44 | z-index: 3; 45 | width: 100%; 46 | max-width: 640px; 47 | background-image: radial-gradient( 48 | at 27% 37%, 49 | hsla(215, 98%, 61%, 1) 0px, 50 | transparent 0% 51 | ), 52 | radial-gradient(at 97% 21%, hsla(125, 98%, 72%, 1) 0px, transparent 50%), 53 | radial-gradient(at 52% 99%, hsla(354, 98%, 61%, 1) 0px, transparent 50%), 54 | radial-gradient(at 10% 29%, hsla(256, 96%, 67%, 1) 0px, transparent 50%), 55 | radial-gradient(at 97% 96%, hsla(38, 60%, 74%, 1) 0px, transparent 50%), 56 | radial-gradient(at 33% 50%, hsla(222, 67%, 73%, 1) 0px, transparent 50%), 57 | radial-gradient(at 79% 53%, hsla(343, 68%, 79%, 1) 0px, transparent 50%); 58 | position: absolute; 59 | content: ""; 60 | width: 100%; 61 | height: 100%; 62 | filter: blur(100px) saturate(150%); 63 | top: 80px; 64 | opacity: 0.15; 65 | } 66 | 67 | @media screen and (max-width: 640px) { 68 | .main { 69 | padding: 0; 70 | } 71 | } 72 | 73 | /* Tailwind Styles */ 74 | 75 | .app { 76 | @apply relative z-10 flex justify-center items-center flex-col max-w-7xl mx-auto sm:px-16 px-6; 77 | } -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const daisyui = require('daisyui'); 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | content: [ 6 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 7 | './components/**/*.{js,ts,jsx,tsx,mdx}', 8 | './app/**/*.{js,ts,jsx,tsx,mdx}', 9 | ], 10 | theme: { 11 | extend: { 12 | fontFamily: { 13 | satoshi: ['Satoshi', 'sans-serif'], 14 | inter: ['Inter', 'sans-serif'], 15 | }, 16 | }, 17 | }, 18 | daisyui: { 19 | themes: ['acid', 'night'], 20 | darkTheme: 'night', 21 | base: true, 22 | styled: true, 23 | utils: true, 24 | }, 25 | plugins: [require('daisyui')], 26 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2015", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noEmit": true, 13 | "esModuleInterop": true, 14 | "module": "CommonJS", 15 | "moduleResolution": "NodeNext", 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "jsx": "preserve", 19 | "incremental": true, 20 | "allowSyntheticDefaultImports": true, 21 | "strict": false, 22 | "plugins": [ 23 | { 24 | "name": "next" 25 | } 26 | ], 27 | "paths": { 28 | "@/*": [ 29 | "./*" 30 | ], 31 | "@/pages": [ 32 | "./app" 33 | ] 34 | }, 35 | }, 36 | "include": [ 37 | "next-env.d.ts", 38 | "**/*.ts", 39 | "**/*.tsx", 40 | ".next/types/**/*.ts", 41 | ], 42 | "exclude": [ 43 | "node_modules" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /types.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/nVision/d7f3e3379deefa08708729d59cc7fa4af193de6a/types.ts -------------------------------------------------------------------------------- /utils/dbConnect.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose'; 2 | 3 | let isConnected = false; 4 | 5 | export const connectToDB = async () => { 6 | mongoose.set('strictQuery', true); 7 | 8 | if (isConnected) { 9 | console.log('MongoDB is already connected'); 10 | return; 11 | } 12 | try { 13 | await mongoose.connect(process.env.MONGODB_URI, { 14 | dbName: 'favorite-pokemon', 15 | useNewUrlParser: true, 16 | useUnifiedTopology: true, 17 | }); 18 | isConnected = true; 19 | } catch (error) { 20 | console.log(error); 21 | } 22 | }; 23 | --------------------------------------------------------------------------------