├── .github └── assets │ ├── Nextjs-ChakraUI.png │ └── login-rocketseat.png ├── .gitignore ├── components ├── Divider.tsx └── Input.tsx ├── config └── emotion.ts ├── contexts └── theme │ └── ThemeContainer.tsx ├── next-env.d.ts ├── package.json ├── pages ├── _app.tsx ├── _document.tsx ├── api │ └── subscribe.ts └── index.tsx ├── public ├── favicon.ico ├── rocketseat.svg └── vercel.svg ├── styles └── theme.ts ├── tsconfig.json └── yarn.lock /.github/assets/Nextjs-ChakraUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketseat-content/youtube-vercel-nextjs-serverless/7aa4707253289b355d64b0606ee5fd5a2f5dd1e0/.github/assets/Nextjs-ChakraUI.png -------------------------------------------------------------------------------- /.github/assets/login-rocketseat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketseat-content/youtube-vercel-nextjs-serverless/7aa4707253289b355d64b0606ee5fd5a2f5dd1e0/.github/assets/login-rocketseat.png -------------------------------------------------------------------------------- /.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 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env 29 | .env.local 30 | .env.development.local 31 | .env.test.local 32 | .env.production.local 33 | 34 | # vercel 35 | .vercel 36 | -------------------------------------------------------------------------------- /components/Divider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Divider as ChakraDivider, Grid } from '@chakra-ui/core' 3 | 4 | // import { Container } from './styles'; 5 | 6 | const Divider: React.FC = () => { 7 | return ( 8 | 13 | 14 | 15 | 16 | ); 17 | } 18 | 19 | export default Divider; -------------------------------------------------------------------------------- /components/Input.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input as ChakraInput, InputProps as ChakraInputProps } from '@chakra-ui/core' 3 | 4 | const Input: React.FC = (props) => { 5 | return ( 6 | 13 | ) 14 | } 15 | 16 | export default Input; -------------------------------------------------------------------------------- /config/emotion.ts: -------------------------------------------------------------------------------- 1 | import styled, { CreateStyled } from '@emotion/styled'; 2 | 3 | import theme from '../styles/theme'; 4 | 5 | export default styled as CreateStyled; 6 | -------------------------------------------------------------------------------- /contexts/theme/ThemeContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { 4 | ThemeProvider as ChakraThemeProvider, 5 | ColorModeProvider, 6 | CSSReset 7 | } from '@chakra-ui/core'; 8 | 9 | import { ThemeProvider as EmotionThemeProvider } from 'emotion-theming' 10 | 11 | import theme from '../../styles/theme'; 12 | 13 | const ThemeContainer: React.FC = ({ children }) => { 14 | return ( 15 | 16 | 17 | 18 | 19 | {children} 20 | 21 | 22 | 23 | ); 24 | } 25 | 26 | export default ThemeContainer; -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "skylabnext", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "@chakra-ui/core": "^0.8.0", 12 | "@emotion/core": "^10.0.35", 13 | "@emotion/styled": "^10.0.27", 14 | "@vercel/node": "^1.8.2", 15 | "axios": "^0.20.0", 16 | "emotion-theming": "^10.0.27", 17 | "mongodb": "^3.6.1", 18 | "next": "9.5.2", 19 | "react": "16.13.1", 20 | "react-dom": "16.13.1" 21 | }, 22 | "devDependencies": { 23 | "@types/mongodb": "^3.5.27", 24 | "@types/node": "^14.6.0", 25 | "@types/react": "^16.9.46", 26 | "typescript": "^3.9.7" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import ThemeContainer from "../contexts/theme/ThemeContainer" 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return ( 5 | 6 | 7 | 8 | ) 9 | } 10 | 11 | export default MyApp 12 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import Document, { DocumentProps, Html, Head, Main, NextScript } from 'next/document' 2 | 3 | class MyDocument extends Document { 4 | render(): JSX.Element { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | ); 16 | } 17 | } 18 | 19 | export default MyDocument; -------------------------------------------------------------------------------- /pages/api/subscribe.ts: -------------------------------------------------------------------------------- 1 | import { NowRequest, NowResponse } from '@vercel/node' 2 | import { MongoClient, Db } from 'mongodb' 3 | import url from 'url'; 4 | 5 | let cachedDb: Db = null; 6 | 7 | async function connectToDatabase(uri: string) { 8 | if (cachedDb) { 9 | return cachedDb; 10 | } 11 | 12 | const client = await MongoClient.connect(uri, { 13 | useNewUrlParser: true, 14 | useUnifiedTopology: true, 15 | }); 16 | 17 | const dbName = url.parse(uri).pathname.substr(1); 18 | 19 | const db = client.db(dbName); 20 | 21 | cachedDb = db; 22 | 23 | return db; 24 | } 25 | 26 | export default async (request: NowRequest, response: NowResponse) => { 27 | const { email } = request.body; 28 | 29 | const db = await connectToDatabase(process.env.MONGODB_URI); 30 | 31 | const collection = db.collection('subscribers'); 32 | 33 | await collection.insertOne({ 34 | email, 35 | subscribedAt: new Date(), 36 | }) 37 | 38 | return response.status(201).json({ ok: true }); 39 | } -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { useState, FormEvent } from 'react'; 2 | import { Flex, Image, Button, Text } from '@chakra-ui/core' 3 | import Input from '../components/Input' 4 | import axios from 'axios'; 5 | 6 | export default function Home() { 7 | const [email, setEmail] = useState(''); 8 | 9 | function handleSignUpToNewsletter(event: FormEvent) { 10 | event.preventDefault(); 11 | 12 | axios.post('/api/subscribe', { email }); 13 | } 14 | 15 | return ( 16 | 22 | 34 | Rocketseat 35 | 36 | 37 | Assine a newsletter da Rocketseat e receba os melhores conteúdos sobre programação! 38 | 39 | 40 | setEmail(e.target.value)} 45 | /> 46 | 47 | 57 | 58 | 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rocketseat-content/youtube-vercel-nextjs-serverless/7aa4707253289b355d64b0606ee5fd5a2f5dd1e0/public/favicon.ico -------------------------------------------------------------------------------- /public/rocketseat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /styles/theme.ts: -------------------------------------------------------------------------------- 1 | import { theme, DefaultTheme } from '@chakra-ui/core' 2 | 3 | const customTheme: DefaultTheme = { 4 | ...theme, 5 | fonts: { 6 | body: 'Roboto, system-ui, sans-serif', 7 | heading: 'Roboto, system-ui, sans-serif', 8 | mono: 'Menlo, monospace' 9 | }, 10 | fontWeights: { 11 | ...theme.fontWeights, 12 | normal: 400, 13 | medium: 600, 14 | bold: 700, 15 | }, 16 | radii: { 17 | ...theme.radii, 18 | sm: '5px', 19 | md: '8px', 20 | }, 21 | colors: { 22 | ...theme.colors, 23 | purple: { 24 | ...theme.colors.purple, 25 | 500: '#8257e5', 26 | }, 27 | gray: { 28 | ...theme.colors.gray, 29 | 300: '#e1e1e6', 30 | 600: '#29292e', 31 | 700: '#202024', 32 | 800: '#121214' 33 | }, 34 | }, 35 | } 36 | 37 | export default customTheme; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "strict": false, 12 | "forceConsistentCasingInFileNames": true, 13 | "noEmit": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve" 20 | }, 21 | "include": [ 22 | "next-env.d.ts", 23 | "**/*.ts", 24 | "**/*.tsx" 25 | ], 26 | "exclude": [ 27 | "node_modules" 28 | ] 29 | } 30 | --------------------------------------------------------------------------------