├── .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 |
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 |
16 |
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------