├── 6_nextgram ├── public │ ├── uploads │ │ ├── undefined │ │ ├── 1713189743.png │ │ ├── 1714153884.png │ │ ├── Thumb Discord.png │ │ ├── Thumb Discord (1).png │ │ ├── Comprovacao udemy 3.png │ │ ├── Capa plataforma (10).png │ │ ├── Capa de Ebook Amazon KDP (3).png │ │ ├── WhatsApp Image 2024-04-29 at 16.05.57.jpeg │ │ ├── DALL·E 2024-04-18 15.24.44 - A wide-angle view of a cityscape at night, subtly modern yet traditional in style. The city features high-rise buildings with lit windows and a calm, .webp │ │ └── DALL·E 2024-04-18 15.44.07 - A wide-angle view of a cityscape at night, designed with a darker and more mysterious tone. The city features high-rise buildings with fewer lights, c.webp │ ├── vercel.svg │ └── next.svg ├── .env ├── .eslintrc.json ├── src │ ├── middleware.ts │ ├── app │ │ ├── globals.css │ │ ├── favicon.ico │ │ ├── api │ │ │ └── [...nextauth] │ │ │ │ └── route.ts │ │ ├── post │ │ │ └── new │ │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── page.tsx │ │ ├── profile │ │ │ └── page.tsx │ │ ├── signin │ │ │ └── page.tsx │ │ └── my-posts │ │ │ └── page.tsx │ ├── components │ │ ├── Label.tsx │ │ ├── ButtonLink.tsx │ │ ├── Button.tsx │ │ ├── FlashMessage.tsx │ │ ├── Post │ │ │ ├── LikeButton.tsx │ │ │ └── CommentModal.tsx │ │ ├── CreatePostForm.tsx │ │ ├── ImagePreview.tsx │ │ ├── ProfileForm.tsx │ │ ├── Navbar.tsx │ │ └── Post.tsx │ └── actions.ts ├── .env.example ├── prisma │ ├── dev.db │ ├── migrations │ │ ├── migration_lock.toml │ │ └── 20240516213823_ │ │ │ └── migration.sql │ └── schema.prisma ├── postcss.config.mjs ├── types │ ├── next-auth.d.ts │ ├── Like.ts │ ├── Comment.ts │ ├── User.ts │ └── Post.ts ├── next.config.mjs ├── tailwind.config.ts ├── .gitignore ├── tsconfig.json ├── package.json ├── auth.ts └── README.md ├── 5_auth ├── .eslintrc.json ├── src │ ├── middleware.ts │ ├── app │ │ ├── favicon.ico │ │ ├── api │ │ │ └── [...nextauth] │ │ │ │ └── route.ts │ │ ├── middleware │ │ │ └── page.tsx │ │ ├── server │ │ │ └── page.tsx │ │ ├── client │ │ │ └── page.tsx │ │ ├── page.tsx │ │ ├── globals.css │ │ └── layout.tsx │ └── components │ │ └── Navbar.tsx ├── prisma │ ├── dev.db │ ├── migrations │ │ ├── migration_lock.toml │ │ └── 20240510151330_ │ │ │ └── migration.sql │ └── schema.prisma ├── .env.example ├── next.config.mjs ├── postcss.config.mjs ├── .env ├── .gitignore ├── tailwind.config.ts ├── public │ ├── vercel.svg │ └── next.svg ├── tsconfig.json ├── package.json ├── auth.ts └── README.md ├── 3_estilos ├── .eslintrc.json ├── src │ ├── app │ │ ├── favicon.ico │ │ ├── page.module.css │ │ ├── globals.css │ │ ├── layout.js │ │ └── page.js │ ├── components │ │ ├── Button.module.scss │ │ ├── Button.jsx │ │ ├── MyComponent.jsx │ │ ├── Container.jsx │ │ └── CustomButton.jsx │ ├── css │ │ └── styles.sass │ └── lib │ │ └── registry.jsx ├── jsconfig.json ├── postcss.config.js ├── next.config.mjs ├── .gitignore ├── tailwind.config.js ├── package.json ├── public │ ├── vercel.svg │ └── next.svg └── README.md ├── 4_data_fetching ├── .eslintrc.json ├── src │ ├── app │ │ ├── globals.css │ │ ├── favicon.ico │ │ ├── todos │ │ │ ├── [id] │ │ │ │ ├── loading.js │ │ │ │ ├── edit │ │ │ │ │ ├── error.js │ │ │ │ │ └── page.js │ │ │ │ ├── not-found.js │ │ │ │ └── page.js │ │ │ └── create │ │ │ │ └── page.js │ │ ├── not-found.js │ │ ├── layout.js │ │ └── page.js │ ├── db.js │ ├── components │ │ ├── Button.js │ │ ├── Checkbox.js │ │ ├── Header.js │ │ └── TodoForm.js │ └── actions.js ├── prisma │ ├── dev.db │ ├── migrations │ │ ├── migration_lock.toml │ │ └── 20240312114821_ │ │ │ └── migration.sql │ └── schema.prisma ├── jsconfig.json ├── postcss.config.js ├── next.config.mjs ├── .env ├── .gitignore ├── tailwind.config.js ├── public │ ├── vercel.svg │ └── next.svg ├── package.json ├── tsconfig.json └── README.md ├── 7_animes_list ├── .eslintrc.json ├── app │ ├── favicon.ico │ ├── globals.css │ ├── page.tsx │ ├── most-rated │ │ └── page.tsx │ ├── most-popular │ │ └── page.tsx │ ├── action.tsx │ └── layout.tsx ├── public │ ├── weapon.png │ ├── vercel.svg │ ├── next.svg │ └── logo.svg ├── postcss.config.js ├── components │ ├── MotionDiv.tsx │ ├── Title.tsx │ ├── Content.tsx │ ├── Container.tsx │ ├── LoadMore.tsx │ ├── Footer.tsx │ ├── Card.tsx │ └── Navbar.tsx ├── types │ └── Anime.ts ├── next.config.js ├── README.md ├── .gitignore ├── tailwind.config.ts ├── .vscode │ └── settings.json ├── tsconfig.json └── package.json └── 2_paginas_e_navegacao ├── .eslintrc.json ├── jsconfig.json ├── next.config.mjs ├── postcss.config.js ├── src ├── app │ ├── favicon.ico │ ├── dashboard │ │ ├── page.js │ │ └── layout.js │ ├── produtos │ │ └── [categoria] │ │ │ ├── [produto] │ │ │ └── page.js │ │ │ └── page.js │ ├── posts │ │ ├── [id] │ │ │ └── page.js │ │ └── page.js │ ├── sobre │ │ └── page.js │ ├── exemplo │ │ └── page.js │ ├── profile │ │ └── page.js │ ├── globals.css │ ├── layout.js │ └── page.js └── components │ ├── Footer.jsx │ ├── BotaoRedirect.jsx │ └── Nav.jsx ├── .gitignore ├── package.json ├── tailwind.config.js ├── public ├── vercel.svg └── next.svg └── README.md /6_nextgram/public/uploads/undefined: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /5_auth/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /5_auth/src/middleware.ts: -------------------------------------------------------------------------------- 1 | export { auth as middleware } from "auth"; 2 | -------------------------------------------------------------------------------- /3_estilos/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /6_nextgram/.env: -------------------------------------------------------------------------------- 1 | AUTH_GOOGLE_ID=x 2 | AUTH_GOOGLE_SECRET=x 3 | AUTH_SECRET=x -------------------------------------------------------------------------------- /6_nextgram/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /6_nextgram/src/middleware.ts: -------------------------------------------------------------------------------- 1 | export { auth as middleware } from "auth"; 2 | -------------------------------------------------------------------------------- /4_data_fetching/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /6_nextgram/.env.example: -------------------------------------------------------------------------------- 1 | AUTH_GOOGLE_ID=x 2 | AUTH_GOOGLE_SECRET=x 3 | AUTH_SECRET=x -------------------------------------------------------------------------------- /7_animes_list/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /6_nextgram/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /5_auth/prisma/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/5_auth/prisma/dev.db -------------------------------------------------------------------------------- /5_auth/.env.example: -------------------------------------------------------------------------------- 1 | AUTH_GOOGLE_ID=ID 2 | AUTH_GOOGLE_SECRET=SECRET 3 | AUTH_SECRET=sadhuihuaydvnncxnryeuqo3$8 -------------------------------------------------------------------------------- /6_nextgram/prisma/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/prisma/dev.db -------------------------------------------------------------------------------- /5_auth/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/5_auth/src/app/favicon.ico -------------------------------------------------------------------------------- /3_estilos/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/3_estilos/src/app/favicon.ico -------------------------------------------------------------------------------- /4_data_fetching/prisma/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/4_data_fetching/prisma/dev.db -------------------------------------------------------------------------------- /4_data_fetching/src/db.js: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | export const db = new PrismaClient(); 4 | -------------------------------------------------------------------------------- /7_animes_list/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/7_animes_list/app/favicon.ico -------------------------------------------------------------------------------- /3_estilos/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /5_auth/src/app/api/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import { handlers } from "auth"; 2 | 3 | export const { GET, POST } = handlers; 4 | -------------------------------------------------------------------------------- /6_nextgram/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/src/app/favicon.ico -------------------------------------------------------------------------------- /7_animes_list/public/weapon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/7_animes_list/public/weapon.png -------------------------------------------------------------------------------- /5_auth/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /6_nextgram/src/app/api/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import { handlers } from "auth"; 2 | 3 | export const { GET, POST } = handlers; 4 | -------------------------------------------------------------------------------- /3_estilos/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /4_data_fetching/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/4_data_fetching/src/app/favicon.ico -------------------------------------------------------------------------------- /7_animes_list/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /4_data_fetching/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/2_paginas_e_navegacao/src/app/favicon.ico -------------------------------------------------------------------------------- /6_nextgram/public/uploads/1713189743.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/1713189743.png -------------------------------------------------------------------------------- /6_nextgram/public/uploads/1714153884.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/1714153884.png -------------------------------------------------------------------------------- /6_nextgram/public/uploads/Thumb Discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/Thumb Discord.png -------------------------------------------------------------------------------- /7_animes_list/components/MotionDiv.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion } from "framer-motion"; 4 | 5 | export const MotionDiv = motion.div; 6 | -------------------------------------------------------------------------------- /6_nextgram/public/uploads/Thumb Discord (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/Thumb Discord (1).png -------------------------------------------------------------------------------- /6_nextgram/public/uploads/Comprovacao udemy 3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/Comprovacao udemy 3.png -------------------------------------------------------------------------------- /4_data_fetching/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | distDir: "build", 4 | }; 5 | 6 | export default nextConfig; 7 | -------------------------------------------------------------------------------- /6_nextgram/public/uploads/Capa plataforma (10).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/Capa plataforma (10).png -------------------------------------------------------------------------------- /5_auth/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /6_nextgram/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /7_animes_list/components/Title.tsx: -------------------------------------------------------------------------------- 1 | export const Title = ({ title }: { title: string }) => { 2 | return

{title}

; 3 | }; 4 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/dashboard/page.js: -------------------------------------------------------------------------------- 1 | export default function DashboardPage() { 2 | return ( 3 |
4 |

Dashboard

5 |
6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /4_data_fetching/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /6_nextgram/public/uploads/Capa de Ebook Amazon KDP (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/Capa de Ebook Amazon KDP (3).png -------------------------------------------------------------------------------- /4_data_fetching/src/app/todos/[id]/loading.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Loading = () => { 4 | return
Carregando dado...
; 5 | }; 6 | 7 | export default Loading; 8 | -------------------------------------------------------------------------------- /5_auth/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /5_auth/src/app/middleware/page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Page = () => { 4 | return
Página protegida por middleware
; 5 | }; 6 | 7 | export default Page; 8 | -------------------------------------------------------------------------------- /3_estilos/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | compiler: { 4 | styledComponents: true, 5 | }, 6 | }; 7 | 8 | export default nextConfig; 9 | -------------------------------------------------------------------------------- /3_estilos/src/app/page.module.css: -------------------------------------------------------------------------------- 1 | .heading_module { 2 | color: #321; 3 | background-color: #abc; 4 | font-size: 2rem; 5 | } 6 | 7 | .container p { 8 | color: purple; 9 | } 10 | -------------------------------------------------------------------------------- /6_nextgram/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /6_nextgram/public/uploads/WhatsApp Image 2024-04-29 at 16.05.57.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/WhatsApp Image 2024-04-29 at 16.05.57.jpeg -------------------------------------------------------------------------------- /3_estilos/src/components/Button.module.scss: -------------------------------------------------------------------------------- 1 | $button-color: blueviolet; 2 | 3 | .button { 4 | background-color: $button-color; 5 | color: #fff; 6 | padding: 10px; 7 | border-radius: 5px; 8 | } 9 | -------------------------------------------------------------------------------- /7_animes_list/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | background-color: #000; 7 | } 8 | 9 | :root { 10 | color-scheme: dark; 11 | } 12 | -------------------------------------------------------------------------------- /3_estilos/src/components/Button.jsx: -------------------------------------------------------------------------------- 1 | import styles from "./Button.module.scss"; 2 | 3 | function Button() { 4 | return ; 5 | } 6 | 7 | export default Button; 8 | -------------------------------------------------------------------------------- /4_data_fetching/src/components/Button.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | const Button = ({ children, className }) => { 4 | return ; 5 | }; 6 | 7 | export default Button; 8 | -------------------------------------------------------------------------------- /3_estilos/src/components/MyComponent.jsx: -------------------------------------------------------------------------------- 1 | export default function MyComponent() { 2 | return ( 3 |
4 | Next com Tailwind CSS! 5 |
6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /6_nextgram/types/next-auth.d.ts: -------------------------------------------------------------------------------- 1 | import NextAuth from "next-auth"; 2 | 3 | declare module "next-auth" { 4 | interface Session { 5 | user: { 6 | userId: string | undefined; 7 | } & DefaultSession["user"]; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Footer = () => { 4 | return ( 5 | 8 | ); 9 | }; 10 | 11 | export default Footer; 12 | -------------------------------------------------------------------------------- /7_animes_list/types/Anime.ts: -------------------------------------------------------------------------------- 1 | export type Anime = { 2 | id: string; 3 | name: string; 4 | image: { 5 | original: string; 6 | }; 7 | kind: string; 8 | episodes: number; 9 | episodes_aired: number; 10 | score: string; 11 | }; 12 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/dashboard/layout.js: -------------------------------------------------------------------------------- 1 | export default function DashboardLayout({ children }) { 2 | return ( 3 |
4 | 5 | 6 |
{children}
7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/todos/[id]/edit/error.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | const ErrorShowTodo = () => { 4 | return ( 5 |
Infelizmente ocorreu um problema, tente novamente mais tarde!
6 | ); 7 | }; 8 | 9 | export default ErrorShowTodo; 10 | -------------------------------------------------------------------------------- /6_nextgram/types/Like.ts: -------------------------------------------------------------------------------- 1 | import { User } from "./User"; 2 | import { Post } from "./Post"; 3 | 4 | export interface Like { 5 | id: string; 6 | userId: string; 7 | postId: string; 8 | createdAt: Date; 9 | user?: User; 10 | post?: Post; 11 | } 12 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/produtos/[categoria]/[produto]/page.js: -------------------------------------------------------------------------------- 1 | export default function ProdutoPage({ params }) { 2 | return ( 3 |
4 |

Produto: {params.produto}

5 |

Categoria: {params.categoria}

6 |
7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /6_nextgram/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | images: { 6 | domains: ["lh3.googleusercontent.com"], 7 | }, 8 | }; 9 | 10 | export default nextConfig; 11 | -------------------------------------------------------------------------------- /3_estilos/src/css/styles.sass: -------------------------------------------------------------------------------- 1 | // Definindo variáveis 2 | $primary-color: #A12 3 | $padding: 16px 4 | 5 | // Utilizando variáveis e aninhamento 6 | .main-container 7 | padding: $padding 8 | background-color: $primary-color 9 | 10 | .header 11 | color: white 12 | 13 | -------------------------------------------------------------------------------- /7_animes_list/components/Content.tsx: -------------------------------------------------------------------------------- 1 | export const Content = ({ children }: { children: React.ReactNode }) => { 2 | return ( 3 |
4 | {children} 5 |
6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/posts/[id]/page.js: -------------------------------------------------------------------------------- 1 | const Post = ({ params }) => { 2 | const id = params.id; 3 | 4 | return ( 5 |
6 |

Post: {id}

7 |

Conteúdo do post com o ID: {id}

8 |
9 | ); 10 | }; 11 | 12 | export default Post; 13 | -------------------------------------------------------------------------------- /7_animes_list/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | remotePatterns: [ 5 | { 6 | protocol: "https", 7 | hostname: "*", 8 | }, 9 | ], 10 | }, 11 | }; 12 | 13 | module.exports = nextConfig; 14 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/not-found.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import React from "react"; 3 | 4 | const NotFound = () => { 5 | return ( 6 |
7 |

Página não encontrada!

8 | Voltar 9 |
10 | ); 11 | }; 12 | 13 | export default NotFound; 14 | -------------------------------------------------------------------------------- /6_nextgram/types/Comment.ts: -------------------------------------------------------------------------------- 1 | import { User } from "./User"; 2 | import { Post } from "./Post"; 3 | 4 | export interface Comment { 5 | id: string; 6 | userId: string; 7 | postId: string; 8 | content: string; 9 | createdAt: Date; 10 | updatedAt: Date; 11 | user: User; 12 | post?: Post; 13 | } 14 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/sobre/page.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export default function SobrePage() { 4 | return ( 5 |
6 |

Página Sobre

7 |

Esta é a página sobre.

8 | Voltar para a Página Inicial 9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/todos/[id]/not-found.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import React from "react"; 3 | 4 | const NotFound = () => { 5 | return ( 6 |
7 |

Todo não encontrado!

8 | Voltar 9 |
10 | ); 11 | }; 12 | 13 | export default NotFound; 14 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/produtos/[categoria]/page.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export default function CategoriaPage({ params }) { 4 | return ( 5 |
6 |

Categoria: {params.categoria}

7 | Produto A 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /3_estilos/src/components/Container.jsx: -------------------------------------------------------------------------------- 1 | // Importando o arquivo Sass em um componente 2 | import "@/css/styles.sass"; 3 | 4 | export default function Container() { 5 | return ( 6 |
7 |
Cabeçalho
8 |

Conteúdo principal

9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /3_estilos/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | h1 { 6 | font-size: 20px; 7 | background-color: #333; 8 | color: #fff; 9 | padding: 10px; 10 | } 11 | 12 | .p-global { 13 | color: red; 14 | } 15 | 16 | #heading-global { 17 | background-color: #383234; 18 | color: #ff1; 19 | } 20 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/components/BotaoRedirect.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useRouter } from "next/navigation"; 4 | 5 | export default function BotaoRedirect() { 6 | const router = useRouter(); 7 | 8 | return ( 9 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /5_auth/src/app/server/page.tsx: -------------------------------------------------------------------------------- 1 | import { auth } from "auth"; 2 | import React from "react"; 3 | 4 | const page = async () => { 5 | const session = await auth(); 6 | 7 | if (!session || !session.user) return

Você precisa estar autenticado!

; 8 | 9 | return
Esta é uma página de server components protegida.
; 10 | }; 11 | 12 | export default page; 13 | -------------------------------------------------------------------------------- /4_data_fetching/prisma/migrations/20240312114821_/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "Todo" ( 3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 4 | "titulo" TEXT NOT NULL, 5 | "descricao" TEXT, 6 | "status" TEXT NOT NULL DEFAULT 'pendente', 7 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 8 | "updatedAt" DATETIME NOT NULL 9 | ); 10 | -------------------------------------------------------------------------------- /6_nextgram/types/User.ts: -------------------------------------------------------------------------------- 1 | import { Like } from "./Like"; 2 | import { Post } from "./Post"; 3 | 4 | export interface User { 5 | id: string; 6 | name: string | null; 7 | email: string | null; 8 | emailVerified: Date | null; 9 | image: string | null; 10 | createdAt: Date; 11 | updatedAt: Date; 12 | posts?: Post[]; 13 | likes?: Like[]; 14 | comments?: Comment[]; 15 | } 16 | -------------------------------------------------------------------------------- /4_data_fetching/src/components/Checkbox.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | const Checkbox = ({ checked }) => { 4 | return ( 5 | e.target.form.requestSubmit()} 9 | className="form-checkbox h-5 w-5" 10 | style={{ marginTop: "0.5rem" }} 11 | /> 12 | ); 13 | }; 14 | 15 | export default Checkbox; 16 | -------------------------------------------------------------------------------- /6_nextgram/types/Post.ts: -------------------------------------------------------------------------------- 1 | import { User } from "./User"; 2 | import { Like } from "./Like"; 3 | import { Comment } from "./Comment"; 4 | 5 | export interface Post { 6 | id: string; 7 | imageUrl: string; 8 | caption?: string | null; 9 | userId: string; 10 | createdAt: Date; 11 | updatedAt: Date; 12 | user: User; 13 | likes?: Like[] | []; 14 | comments?: Comment[] | []; 15 | } 16 | -------------------------------------------------------------------------------- /6_nextgram/src/components/Label.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentProps } from "react"; 2 | 3 | type LabelProps = ComponentProps<"label"> & { 4 | text: string; 5 | }; 6 | 7 | const Label: React.FC = ({ text, ...props }) => { 8 | return ( 9 | 12 | ); 13 | }; 14 | 15 | export default Label; 16 | -------------------------------------------------------------------------------- /4_data_fetching/src/components/Header.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | const Header = () => { 4 | return ( 5 |
6 | 10 |
11 | ); 12 | }; 13 | 14 | export default Header; 15 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/exemplo/page.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useSearchParams } from "next/navigation"; 4 | 5 | const Exemplo = () => { 6 | const searchParams = useSearchParams(); 7 | 8 | const param = searchParams.get("parametro"); 9 | 10 | return ( 11 |
12 |

Página de Exemplo

13 |

O parâmetro recebido é: {param}

14 |
15 | ); 16 | }; 17 | 18 | export default Exemplo; 19 | -------------------------------------------------------------------------------- /7_animes_list/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { fetchAnime } from "./action"; 2 | 3 | import { Container } from "@/components/Container"; 4 | import { Content } from "@/components/Content"; 5 | 6 | async function Home() { 7 | const data = await fetchAnime(1, "name"); 8 | 9 | return ( 10 | 11 | {data} 12 | 13 | ); 14 | } 15 | 16 | export default Home; 17 | -------------------------------------------------------------------------------- /5_auth/src/app/client/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useSession } from "next-auth/react"; 4 | import React from "react"; 5 | 6 | const Page = () => { 7 | const { data: session } = useSession(); 8 | 9 | if (!session || !session.user) return

Você precisa estar autenticado!

; 10 | 11 | return ( 12 |
13 |

Página client component protegida

14 |
15 | ); 16 | }; 17 | 18 | export default Page; 19 | -------------------------------------------------------------------------------- /6_nextgram/public/uploads/DALL·E 2024-04-18 15.24.44 - A wide-angle view of a cityscape at night, subtly modern yet traditional in style. The city features high-rise buildings with lit windows and a calm, .webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/DALL·E 2024-04-18 15.24.44 - A wide-angle view of a cityscape at night, subtly modern yet traditional in style. The city features high-rise buildings with lit windows and a calm, .webp -------------------------------------------------------------------------------- /6_nextgram/public/uploads/DALL·E 2024-04-18 15.44.07 - A wide-angle view of a cityscape at night, designed with a darker and more mysterious tone. The city features high-rise buildings with fewer lights, c.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matheusbattisti/curso_nextjs/HEAD/6_nextgram/public/uploads/DALL·E 2024-04-18 15.44.07 - A wide-angle view of a cityscape at night, designed with a darker and more mysterious tone. The city features high-rise buildings with fewer lights, c.webp -------------------------------------------------------------------------------- /7_animes_list/app/most-rated/page.tsx: -------------------------------------------------------------------------------- 1 | import { fetchAnime } from "../action"; 2 | 3 | import { Container } from "@/components/Container"; 4 | import { Content } from "@/components/Content"; 5 | 6 | async function MostRated() { 7 | const data = await fetchAnime(1, "ranked"); 8 | 9 | return ( 10 | 11 | {data} 12 | 13 | ); 14 | } 15 | 16 | export default MostRated; 17 | -------------------------------------------------------------------------------- /4_data_fetching/.env: -------------------------------------------------------------------------------- 1 | # Environment variables declared in this file are automatically made available to Prisma. 2 | # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema 3 | 4 | # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. 5 | # See the documentation for all the connection string options: https://pris.ly/d/connection-strings 6 | 7 | DATABASE_URL="file:./dev.db" 8 | -------------------------------------------------------------------------------- /6_nextgram/src/components/ButtonLink.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | type ButtonProps = { 4 | text: string; 5 | url: string; 6 | }; 7 | 8 | const ButtonLink: React.FC = ({ text, url }) => { 9 | return ( 10 | 14 | {text} 15 | 16 | ); 17 | }; 18 | 19 | export default ButtonLink; 20 | -------------------------------------------------------------------------------- /7_animes_list/app/most-popular/page.tsx: -------------------------------------------------------------------------------- 1 | import { fetchAnime } from "../action"; 2 | 3 | import { Container } from "@/components/Container"; 4 | import { Content } from "@/components/Content"; 5 | 6 | async function MostPopular() { 7 | const data = await fetchAnime(1, "popularity"); 8 | 9 | return ( 10 | 11 | {data} 12 | 13 | ); 14 | } 15 | 16 | export default MostPopular; 17 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/posts/page.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export default function HomePage() { 4 | // Suponha que temos um array de IDs de posts 5 | const postIds = [1, 2, 3]; 6 | 7 | return ( 8 |
9 |

Página Inicial

10 |
    11 | {postIds.map((id) => ( 12 |
  • 13 | Ver Post {id} 14 |
  • 15 | ))} 16 |
17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /7_animes_list/app/action.tsx: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import { Card } from "@/components/Card"; 4 | import { Anime } from "@/types/Anime"; 5 | 6 | export const fetchAnime = async (page: number, order: string) => { 7 | const response = await fetch( 8 | `https://shikimori.one/api/animes?page=${page}&limit=8&order=${order}` 9 | ); 10 | 11 | const data = await response.json(); 12 | 13 | return data.map((item: Anime, index: number) => ( 14 | 15 | )); 16 | }; 17 | -------------------------------------------------------------------------------- /5_auth/.env: -------------------------------------------------------------------------------- 1 | # Environment variables declared in this file are automatically made available to Prisma. 2 | # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema 3 | 4 | # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. 5 | # See the documentation for all the connection string options: https://pris.ly/d/connection-strings 6 | 7 | DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" -------------------------------------------------------------------------------- /7_animes_list/components/Container.tsx: -------------------------------------------------------------------------------- 1 | import { Title } from "./Title"; 2 | import { LoadMore } from "./LoadMore"; 3 | 4 | type ContainerProps = { 5 | title: string; 6 | order: string; 7 | children: React.ReactNode; 8 | }; 9 | 10 | export const Container = ({ title, order, children }: ContainerProps) => { 11 | return ( 12 |
13 | 14 | {children} 15 | <LoadMore order={order} /> 16 | </main> 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /5_auth/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | 3 | export default function Home() { 4 | return ( 5 | <main className="flex min-h-screen flex-col items-center justify-between p-24"> 6 | <div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex"> 7 | <Link href="/client">Página client component</Link> 8 | <Link href="/server">Página server component</Link> 9 | <Link href="/middleware">Página middleware</Link> 10 | </div> 11 | </main> 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/todos/[id]/page.js: -------------------------------------------------------------------------------- 1 | // 5 - pagina dinamica com request 2 | import { db } from "@/db"; 3 | import { notFound } from "next/navigation"; 4 | 5 | export default async function TodoShow(props) { 6 | // Para testar o loading 7 | await new Promise((a) => setTimeout(a, 2000)); 8 | 9 | const id = Number(props.params.id); 10 | 11 | const todo = await db.todo.findFirst({ 12 | where: { id }, 13 | }); 14 | 15 | console.log(todo); 16 | 17 | if (!todo) return notFound(); 18 | 19 | return <div>{todo.titulo}</div>; 20 | } 21 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/profile/page.js: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation"; 2 | 3 | export default async function Profile({ params }) { 4 | const userExists = false; 5 | 6 | if (!userExists) { 7 | redirect("/"); // Redireciona para a página inicial se a condição for falsa 8 | } 9 | 10 | // Se a condição fosse verdadeira, renderizaria o perfil do usuário 11 | return ( 12 | <div> 13 | <h1>Perfil do Usuário</h1> 14 | <p>Informações do usuário seriam exibidas aqui se existissem.</p> 15 | </div> 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /7_animes_list/README.md: -------------------------------------------------------------------------------- 1 | # Build Modern Next 14 Server Side App with Server Actions, Infinite Scroll & Framer Motion Animations 2 | 3 | ![Anime Website](https://i.ibb.co/MG1nbqt/YT-Thumbnails-2.png) 4 | 5 | ### [🌟 Become a top 1% Next.js 14 developer in only one course](https://jsmastery.pro/next14) 6 | ### [🚀 Land your dream programming job in 6 months](https://jsmastery.pro/masterclass) 7 | ### [📙 Free Three.js Cheatsheet](https://resource.jsmastery.pro/threejs-cheatsheet) 8 | ### [🌐 Best Hosting for Your Websites](https://hostinger.com/javascript10) 9 | 10 | -------------------------------------------------------------------------------- /3_estilos/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 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 | -------------------------------------------------------------------------------- /5_auth/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 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 | -------------------------------------------------------------------------------- /4_data_fetching/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 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 | -------------------------------------------------------------------------------- /7_animes_list/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 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 | -------------------------------------------------------------------------------- /3_estilos/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 5 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 12 | "gradient-conic": 13 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | }; 19 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from "next/font/google"; 2 | import "./globals.css"; 3 | 4 | const inter = Inter({ subsets: ["latin"] }); 5 | 6 | import Header from "@/components/Header"; 7 | 8 | export const metadata = { 9 | title: "Create Next App", 10 | description: "Generated by create next app", 11 | }; 12 | 13 | export default function RootLayout({ children }) { 14 | return ( 15 | <html lang="en"> 16 | <body className={inter.className}> 17 | <Header /> 18 | {children} 19 | </body> 20 | </html> 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 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 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "2_paginas_e_navegacao", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "react": "^18", 13 | "react-dom": "^18", 14 | "next": "14.1.0" 15 | }, 16 | "devDependencies": { 17 | "autoprefixer": "^10.0.1", 18 | "postcss": "^8", 19 | "tailwindcss": "^3.3.0", 20 | "eslint": "^8", 21 | "eslint-config-next": "14.1.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /4_data_fetching/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 5 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 12 | "gradient-conic": 13 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | }; 19 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 5 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 12 | "gradient-conic": 13 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | }; 19 | -------------------------------------------------------------------------------- /3_estilos/src/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from "next/font/google"; 2 | import "./globals.css"; 3 | import StyledComponentsRegistry from "@/lib/registry"; 4 | 5 | const inter = Inter({ subsets: ["latin"] }); 6 | 7 | export const metadata = { 8 | title: "Create Next App", 9 | description: "Generated by create next app", 10 | }; 11 | 12 | export default function RootLayout({ children }) { 13 | return ( 14 | <html lang="en"> 15 | <body className={inter.className}> 16 | <StyledComponentsRegistry>{children}</StyledComponentsRegistry> 17 | </body> 18 | </html> 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /5_auth/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 13 | "gradient-conic": 14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | }; 20 | export default config; 21 | -------------------------------------------------------------------------------- /6_nextgram/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 13 | "gradient-conic": 14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | }; 20 | export default config; 21 | -------------------------------------------------------------------------------- /3_estilos/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "3_estilos", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "next": "14.1.0", 13 | "react": "^18", 14 | "react-dom": "^18", 15 | "styled-components": "^6.1.8" 16 | }, 17 | "devDependencies": { 18 | "autoprefixer": "^10.0.1", 19 | "eslint": "^8", 20 | "eslint-config-next": "14.1.0", 21 | "postcss": "^8", 22 | "sass": "^1.71.1", 23 | "tailwindcss": "^3.3.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /6_nextgram/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 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 | /public/uploads 39 | /public/dev.db 40 | .env -------------------------------------------------------------------------------- /5_auth/public/vercel.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> -------------------------------------------------------------------------------- /3_estilos/public/vercel.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> -------------------------------------------------------------------------------- /6_nextgram/public/vercel.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> -------------------------------------------------------------------------------- /4_data_fetching/public/vercel.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> -------------------------------------------------------------------------------- /6_nextgram/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentProps } from "react"; 2 | 3 | type ButtonProps = ComponentProps<"button"> & { 4 | text: string; 5 | danger?: boolean; 6 | }; 7 | 8 | const Button: React.FC<ButtonProps> = ({ text, danger = false, ...props }) => { 9 | return ( 10 | <button 11 | data-danger={danger} 12 | className="h-8 text-sm font-medium text-white py-1 px-6 rounded flex items-center bg-blue-800 hover:bg-blue-700 data-[danger=true]:bg-red-500 data-[danger=true]:hover:bg-red-400" 13 | {...props} 14 | > 15 | {text} 16 | </button> 17 | ); 18 | }; 19 | 20 | export default Button; 21 | -------------------------------------------------------------------------------- /7_animes_list/public/vercel.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> -------------------------------------------------------------------------------- /2_paginas_e_navegacao/public/vercel.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> -------------------------------------------------------------------------------- /4_data_fetching/src/app/todos/[id]/edit/page.js: -------------------------------------------------------------------------------- 1 | import { editTodo, findTodoById } from "@/actions"; 2 | import TodoForm from "@/components/TodoForm"; 3 | 4 | import { notFound } from "next/navigation"; 5 | 6 | export default async function TodoEdit(props) { 7 | const id = parseInt(props.params.id); 8 | 9 | const todo = await findTodoById(id); 10 | 11 | if (!todo) return notFound(); 12 | 13 | return ( 14 | <div className="max-w-md mx-auto mt-10"> 15 | <h1 className="text-2xl font-bold text-center mb-6"> 16 | Editando: {todo.titulo} 17 | </h1> 18 | <TodoForm todo={todo} /> 19 | </div> 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /7_animes_list/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 13 | "gradient-conic": 14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 15 | hero: 'url("/hero.png")', 16 | }, 17 | }, 18 | }, 19 | plugins: [], 20 | }; 21 | export default config; 22 | -------------------------------------------------------------------------------- /3_estilos/src/components/CustomButton.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import styled from "styled-components"; 4 | 5 | // Definindo um componente de botão estilizado 6 | const MyStyledButton = styled.button` 7 | background-color: #4caf50; 8 | border: none; 9 | color: white; 10 | padding: 15px 32px; 11 | text-align: center; 12 | text-decoration: none; 13 | display: inline-block; 14 | font-size: 16px; 15 | margin: 4px 2px; 16 | cursor: pointer; 17 | 18 | &:hover { 19 | background-color: #45a049; 20 | } 21 | `; 22 | 23 | export default function CustomButton({ children }) { 24 | return <MyStyledButton>{children}</MyStyledButton>; 25 | } 26 | -------------------------------------------------------------------------------- /7_animes_list/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.eslint": "explicit", 6 | "source.addMissingImports": "explicit" 7 | }, 8 | "[typescriptreact]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "[typescript]": { 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | }, 14 | "[javascript]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode" 16 | }, 17 | "typescript.tsdk": "node_modules/typescript/lib", 18 | "svg.preview.background": "transparent" 19 | } 20 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/components/Nav.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { usePathname } from "next/navigation"; 4 | import Link from "next/link"; 5 | 6 | export function Nav() { 7 | const pathname = usePathname(); 8 | 9 | return ( 10 | <nav> 11 | <ul> 12 | <li> 13 | <Link className={`link ${pathname === "/" ? "active" : ""}`} href="/"> 14 | Home 15 | </Link> 16 | </li> 17 | <li> 18 | <Link 19 | className={`link ${pathname === "/sobre" ? "active" : ""}`} 20 | href="/sobre" 21 | > 22 | Sobre 23 | </Link> 24 | </li> 25 | </ul> 26 | </nav> 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /4_data_fetching/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "4_data_fetching", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@prisma/client": "^5.10.2", 13 | "next": "^14.2.3", 14 | "react": "^18", 15 | "react-dom": "^18" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "20.11.26", 19 | "@types/react": "18.2.65", 20 | "autoprefixer": "^10.0.1", 21 | "eslint": "^8", 22 | "eslint-config-next": "14.1.1", 23 | "postcss": "^8", 24 | "prisma": "^5.10.2", 25 | "tailwindcss": "^3.3.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /7_animes_list/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /5_auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"], 22 | "auth": ["./auth.ts"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /7_animes_list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "7_animes_list", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "framer-motion": "^11.2.6", 13 | "next": "14.0.3", 14 | "react": "^18", 15 | "react-dom": "^18", 16 | "react-icons": "^5.2.1" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^20", 20 | "@types/react": "^18", 21 | "@types/react-dom": "^18", 22 | "autoprefixer": "^10.0.1", 23 | "eslint": "^8", 24 | "eslint-config-next": "14.0.3", 25 | "postcss": "^8", 26 | "tailwindcss": "^3.3.0", 27 | "typescript": "^5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* Estilo Global */ 6 | body { 7 | background-color: #121212; 8 | color: #edebeb; 9 | font-family: "Arial", sans-serif; 10 | margin: 0; 11 | padding: 0; 12 | box-sizing: border-box; 13 | display: flex; 14 | flex-direction: column; 15 | justify-content: space-around; 16 | align-items: center; 17 | height: 100vh; 18 | } 19 | 20 | h1 { 21 | font-size: 2.5em; 22 | } 23 | 24 | a { 25 | color: #2595e5; 26 | text-decoration: none; 27 | } 28 | 29 | a:hover { 30 | text-decoration: underline; 31 | } 32 | 33 | .center { 34 | text-align: center; 35 | } 36 | 37 | .active { 38 | background-color: #fff; 39 | color: #121212; 40 | } 41 | -------------------------------------------------------------------------------- /5_auth/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | 29 | @layer utilities { 30 | .text-balance { 31 | text-wrap: balance; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /6_nextgram/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"], 22 | "auth": ["./auth.ts"], 23 | "types/*": ["./types/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from "next/font/google"; 2 | import "./globals.css"; 3 | import Footer from "@/components/Footer"; 4 | import { Nav } from "@/components/Nav"; 5 | 6 | const inter = Inter({ subsets: ["latin"] }); 7 | 8 | export const metadata = { 9 | title: "Create Next App", 10 | description: "Generated by create next app", 11 | }; 12 | 13 | export default function RootLayout({ children }) { 14 | return ( 15 | <html lang="en"> 16 | <body className={inter.className}> 17 | {/* 5 - Layout */} 18 | <h1>Cabeçalho do site</h1> 19 | {/* 8 - Link ativo */} 20 | <Nav /> 21 | {children} 22 | {/* 6 - Componentes */} 23 | <Footer /> 24 | </body> 25 | </html> 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /5_auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "5_auth", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@auth/prisma-adapter": "^2.0.0", 13 | "@prisma/client": "^5.13.0", 14 | "next": "14.2.3", 15 | "next-auth": "^5.0.0-beta.17", 16 | "react": "^18", 17 | "react-dom": "^18" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^20", 21 | "@types/react": "^18", 22 | "@types/react-dom": "^18", 23 | "eslint": "^8", 24 | "eslint-config-next": "14.2.3", 25 | "postcss": "^8", 26 | "prisma": "^5.13.0", 27 | "tailwindcss": "^3.4.1", 28 | "typescript": "^5" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /6_nextgram/src/app/post/new/page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import CreatePostForm from "@/components/CreatePostForm"; 3 | import { auth } from "auth"; 4 | import { redirect } from "next/navigation"; 5 | 6 | const CreatePostPage: React.FC = async () => { 7 | const session = await auth(); 8 | 9 | // Não tem session, vai para home 10 | if (!session || !session.user?.email) return redirect(`/`); 11 | 12 | return ( 13 | <div className="w-[35rem] mx-auto p-4 my-10"> 14 | <h1 className="text-[2rem] leading-10 text-center font-semibold"> 15 | Criar novo post 16 | </h1> 17 | <div className="border border-zinc-300 p-4 rounded mt-8"> 18 | <CreatePostForm /> 19 | </div> 20 | </div> 21 | ); 22 | }; 23 | 24 | export default CreatePostPage; 25 | -------------------------------------------------------------------------------- /4_data_fetching/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? 5 | // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init 6 | 7 | generator client { 8 | provider = "prisma-client-js" 9 | } 10 | 11 | datasource db { 12 | provider = "sqlite" 13 | url = env("DATABASE_URL") 14 | } 15 | 16 | model Todo { 17 | id Int @id @default(autoincrement()) 18 | titulo String 19 | descricao String? 20 | status String @default("pendente") // Exemplos de status: "pendente", "concluído" 21 | createdAt DateTime @default(now()) 22 | updatedAt DateTime @updatedAt 23 | } 24 | 25 | -------------------------------------------------------------------------------- /5_auth/auth.ts: -------------------------------------------------------------------------------- 1 | import type { NextAuthConfig } from "next-auth"; 2 | import NextAuth from "next-auth"; 3 | 4 | import google from "next-auth/providers/google"; 5 | 6 | import { PrismaAdapter } from "@auth/prisma-adapter"; 7 | import { PrismaClient } from "@prisma/client"; 8 | 9 | const prisma = new PrismaClient(); 10 | 11 | const config = { 12 | adapter: PrismaAdapter(prisma), 13 | session: { strategy: "jwt" }, 14 | providers: [google], 15 | callbacks: { 16 | authorized({ request, auth }) { 17 | const { pathname } = request.nextUrl; 18 | 19 | if (pathname === "/middleware") { 20 | return !!auth; 21 | } 22 | 23 | return true; 24 | }, 25 | }, 26 | } satisfies NextAuthConfig; 27 | 28 | export const { handlers, auth, signIn, signOut } = NextAuth(config); 29 | -------------------------------------------------------------------------------- /5_auth/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | import Navbar from "@/components/Navbar"; 5 | import { SessionProvider } from "next-auth/react"; 6 | 7 | const inter = Inter({ subsets: ["latin"] }); 8 | 9 | export const metadata: Metadata = { 10 | title: "Create Next App", 11 | description: "Generated by create next app", 12 | }; 13 | 14 | export default function RootLayout({ 15 | children, 16 | }: Readonly<{ 17 | children: React.ReactNode; 18 | }>) { 19 | return ( 20 | <html lang="en"> 21 | <body className={inter.className}> 22 | <SessionProvider> 23 | <Navbar /> 24 | {children} 25 | </SessionProvider> 26 | </body> 27 | </html> 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /6_nextgram/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | import Navbar from "@/components/Navbar"; 5 | import { SessionProvider } from "next-auth/react"; 6 | 7 | const inter = Inter({ subsets: ["latin"] }); 8 | 9 | export const metadata: Metadata = { 10 | title: "NextGram", 11 | description: "Aplicativo clone do Instagram com Next JS", 12 | }; 13 | 14 | export default function RootLayout({ 15 | children, 16 | }: Readonly<{ 17 | children: React.ReactNode; 18 | }>) { 19 | return ( 20 | <html lang="pt_BR"> 21 | <body className={inter.className}> 22 | <SessionProvider> 23 | <Navbar /> 24 | {children} 25 | </SessionProvider> 26 | </body> 27 | </html> 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /6_nextgram/src/components/FlashMessage.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | 3 | interface FlashMessageProps { 4 | message: string; 5 | type: string; 6 | } 7 | 8 | const FlashMessage: React.FC<FlashMessageProps> = ({ message, type }) => { 9 | const [visible, setVisible] = useState(true); 10 | 11 | useEffect(() => { 12 | const timer = setTimeout(() => { 13 | setVisible(false); 14 | }, 3000); 15 | 16 | return () => clearTimeout(timer); 17 | }, []); 18 | 19 | if (!visible) return null; 20 | 21 | return ( 22 | <div 23 | className={`fixed top-6 right-6 p-4 rounded shadow-md text-white ${ 24 | type === "success" ? "bg-emerald-600" : "bg-red-600" 25 | }`} 26 | > 27 | {message} 28 | </div> 29 | ); 30 | }; 31 | 32 | export default FlashMessage; 33 | -------------------------------------------------------------------------------- /7_animes_list/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { DM_Sans } from "next/font/google"; 3 | import { Footer } from "@/components/Footer"; 4 | 5 | import "./globals.css"; 6 | import { Navbar } from "@/components/Navbar"; 7 | 8 | const dmSans = DM_Sans({ subsets: ["latin"] }); 9 | 10 | export const metadata: Metadata = { 11 | title: "Animes List", 12 | description: "Fique por dentro do mundo dos animes.", 13 | }; 14 | 15 | export default function RootLayout({ 16 | children, 17 | }: { 18 | children: React.ReactNode; 19 | }) { 20 | return ( 21 | <html lang="pt_BR"> 22 | <body className={dmSans.className}> 23 | <main className="max-w-7xl mx-auto bg-[#0F1117]"> 24 | <Navbar /> 25 | {children} 26 | <Footer /> 27 | </main> 28 | </body> 29 | </html> 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /4_data_fetching/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": [ 5 | "./src/*" 6 | ] 7 | }, 8 | "lib": [ 9 | "dom", 10 | "dom.iterable", 11 | "esnext" 12 | ], 13 | "allowJs": true, 14 | "skipLibCheck": true, 15 | "strict": false, 16 | "noEmit": true, 17 | "incremental": true, 18 | "esModuleInterop": true, 19 | "module": "esnext", 20 | "moduleResolution": "node", 21 | "resolveJsonModule": true, 22 | "isolatedModules": true, 23 | "jsx": "preserve", 24 | "plugins": [ 25 | { 26 | "name": "next" 27 | } 28 | ] 29 | }, 30 | "include": [ 31 | "next-env.d.ts", 32 | ".next/types/**/*.ts", 33 | "**/*.ts", 34 | "**/*.tsx", 35 | "build/types/**/*.ts" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /6_nextgram/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "5_auth", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@auth/prisma-adapter": "^2.0.0", 13 | "@prisma/client": "^5.13.0", 14 | "@types/react-modal": "^3.16.3", 15 | "next": "14.2.3", 16 | "next-auth": "^5.0.0-beta.17", 17 | "react": "^18", 18 | "react-dom": "^18", 19 | "react-icons": "^5.2.1", 20 | "react-modal": "^3.16.1" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^20", 24 | "@types/react": "^18", 25 | "@types/react-dom": "^18", 26 | "eslint": "^8", 27 | "eslint-config-next": "14.2.3", 28 | "postcss": "^8", 29 | "prisma": "^5.13.0", 30 | "tailwindcss": "^3.4.1", 31 | "typescript": "^5" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /3_estilos/src/lib/registry.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import { useServerInsertedHTML } from "next/navigation"; 5 | import { ServerStyleSheet, StyleSheetManager } from "styled-components"; 6 | 7 | export default function StyledComponentsRegistry({ children }) { 8 | // Only create stylesheet once with lazy initial state 9 | // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state 10 | const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet()); 11 | 12 | useServerInsertedHTML(() => { 13 | const styles = styledComponentsStyleSheet.getStyleElement(); 14 | styledComponentsStyleSheet.instance.clearTag(); 15 | return <>{styles}</>; 16 | }); 17 | 18 | if (typeof window !== "undefined") return <>{children}</>; 19 | 20 | return ( 21 | <StyleSheetManager sheet={styledComponentsStyleSheet.instance}> 22 | {children} 23 | </StyleSheetManager> 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /6_nextgram/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { getAllPosts } from "@/actions"; 2 | import Post from "@/components/Post"; 3 | import { auth } from "auth"; 4 | 5 | export default async function Home() { 6 | const posts = await getAllPosts(); 7 | 8 | const session = await auth(); 9 | 10 | let userId = null; 11 | 12 | if (session) { 13 | userId = session.user.userId; 14 | } 15 | 16 | return ( 17 | <main className="flex min-h-screen flex-col items-center p-4 my-10"> 18 | <h1 className="text-[2rem] leading-10 font-semibold"> 19 | Confira os posts mais recentes 20 | </h1> 21 | <div> 22 | {posts && posts.length > 0 ? ( 23 | <div className="mt-8"> 24 | {posts.map((post) => ( 25 | <Post post={post} currentUserId={userId} key={post.id} /> 26 | ))} 27 | </div> 28 | ) : ( 29 | <p className="mt-6 font-medium">Ainda não há posts</p> 30 | )} 31 | </div> 32 | </main> 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /3_estilos/src/app/page.js: -------------------------------------------------------------------------------- 1 | import MyComponent from "@/components/MyComponent"; 2 | import styles from "./page.module.css"; 3 | import Container from "@/components/Container"; 4 | import CustomButton from "@/components/CustomButton"; 5 | import Button from "@/components/Button"; 6 | 7 | export default function Home() { 8 | return ( 9 | <main> 10 | {/* 1 - CSS Global */} 11 | <h1>Eu tenho CSS global</h1> 12 | <p className="p-global">Eu também</p> 13 | <h2 id="heading-global">Me too</h2> 14 | {/* 2 - CSS Modules */} 15 | <h2 className={styles.heading_module}>Testando CSS Module</h2> 16 | <div className={styles.container}> 17 | <p>Testando</p> 18 | </div> 19 | {/* 3 - Tailwind */} 20 | <MyComponent /> 21 | {/* 4 - SASS */} 22 | <Container /> 23 | {/* 5 - SASS Com CSS MOdules */} 24 | <Button /> 25 | {/*6 - Styled Components */} 26 | <CustomButton>Clique aqui!</CustomButton> 27 | </main> 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /7_animes_list/components/LoadMore.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { fetchAnime } from "@/app/action"; 4 | import { useState } from "react"; 5 | 6 | let page = 2; 7 | 8 | export const LoadMore = ({ order }: { order: string }) => { 9 | const [data, setData] = useState<JSX.Element[]>([]); 10 | 11 | const showMoreItems = () => { 12 | fetchAnime(page, order).then((res) => { 13 | setData([...data, ...res]); 14 | page++; 15 | }); 16 | }; 17 | 18 | return ( 19 | <> 20 | <section className="grid lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-10"> 21 | {data} 22 | </section> 23 | 24 | <section className="flex justify-center items-center w-full"> 25 | <button 26 | onClick={showMoreItems} 27 | className="h-10 sm:h-8 px-6 py-1 w-full sm:w-auto text-sm font-medium rounded-lg border border-white bg-slate-800 hover:bg-slate-700 flex justify-center items-center" 28 | > 29 | Carregar mais 30 | </button> 31 | </section> 32 | </> 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/src/app/page.js: -------------------------------------------------------------------------------- 1 | import BotaoRedirect from "@/components/BotaoRedirect"; 2 | import Link from "next/link"; 3 | 4 | export default function Home() { 5 | return ( 6 | <div> 7 | <div> 8 | {/* 1 - Criando e navegando entre páginas */} 9 | <h1>Aula 1</h1> 10 | <h2>Página Inicial</h2> 11 | <Link href="/sobre">Ir para a página Sobre</Link> 12 | {/* 2 - Páginas Dinâmicas */} 13 | <h1>Aula 2</h1> 14 | <Link href="/posts">Ir para a página Posts</Link> 15 | {/* 3 - Rotas com Parâmetros */} 16 | <h1>Aula 3</h1> 17 | <Link href="/exemplo?parametro=valor"> 18 | Abrir a Página de Exemplo com Parâmetro 19 | </Link> 20 | {/* 4 - Nested routes */} 21 | <h1>Aula 4</h1> 22 | <Link href="/produtos/roupas">Ir para categoria de Roupas</Link> 23 | {/* 7 - Nested layout */} 24 | <h1>Aula 7</h1> 25 | <Link href="/dashboard">Ir para dashboard</Link> 26 | {/* 8 - useRouter */} 27 | <h1>Aula 8</h1> 28 | <BotaoRedirect /> 29 | {/* 9 - redirect */} 30 | <h1>Aula 9</h1> 31 | <Link href="/profile">Ir para Perfil</Link> 32 | </div> 33 | </div> 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /6_nextgram/auth.ts: -------------------------------------------------------------------------------- 1 | import type { NextAuthConfig } from "next-auth"; 2 | import NextAuth from "next-auth"; 3 | 4 | import google from "next-auth/providers/google"; 5 | 6 | import { PrismaAdapter } from "@auth/prisma-adapter"; 7 | import { PrismaClient } from "@prisma/client"; 8 | 9 | import type { Provider } from "next-auth/providers"; 10 | 11 | const prisma = new PrismaClient(); 12 | 13 | const config = { 14 | adapter: PrismaAdapter(prisma), 15 | session: { strategy: "jwt" }, 16 | providers: [google], 17 | callbacks: { 18 | session({ session, token }) { 19 | // Adiciona o ID do usuário à sessão 20 | if (token.sub) session.user.userId = token.sub; 21 | return session; 22 | }, 23 | }, 24 | pages: { 25 | signIn: "/signin", 26 | }, 27 | } satisfies NextAuthConfig; 28 | 29 | export const { handlers, auth, signIn, signOut } = NextAuth(config); 30 | 31 | // Definir o tipo do provedor 32 | interface ProviderWithId { 33 | id: string; 34 | name: string; 35 | } 36 | 37 | // Mapeando os provedores manualmente 38 | export const providerMap = config.providers.map((provider) => { 39 | const typedProvider = provider as unknown as ProviderWithId; 40 | return { id: typedProvider.id, name: typedProvider.name }; 41 | }); 42 | -------------------------------------------------------------------------------- /6_nextgram/src/app/profile/page.tsx: -------------------------------------------------------------------------------- 1 | import { getUserByEmail } from "@/actions"; 2 | import ProfileForm from "@/components/ProfileForm"; 3 | import { auth } from "auth"; 4 | import Image from "next/image"; 5 | import { redirect } from "next/navigation"; 6 | 7 | export default async function UserProfile() { 8 | const session = await auth(); 9 | 10 | // Não tem session, vai para home 11 | if (!session || !session.user?.email) return redirect(`/`); 12 | 13 | const user = await getUserByEmail(session.user.email); 14 | 15 | // Não tem usuário vai para home 16 | if (!user) { 17 | return redirect(`/`); 18 | } 19 | 20 | return ( 21 | <div className="w-[35rem] mx-auto my-10 p-4"> 22 | <h1 className="text-[2rem] leading-10 font-semibold text-center"> 23 | Perfil de {user.name} 24 | </h1> 25 | 26 | {user.image && ( 27 | <div className="w-full flex justify-center my-6"> 28 | <Image 29 | src={user.image} 30 | alt={`Imagem de perfil de ${user.name}`} 31 | className="w-80 h-80 p-4 object-cover" 32 | width={320} 33 | height={320} 34 | /> 35 | </div> 36 | )} 37 | 38 | <ProfileForm user={user} /> 39 | </div> 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /5_auth/public/next.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> -------------------------------------------------------------------------------- /3_estilos/public/next.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> -------------------------------------------------------------------------------- /6_nextgram/public/next.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> -------------------------------------------------------------------------------- /4_data_fetching/public/next.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> -------------------------------------------------------------------------------- /6_nextgram/src/components/Post/LikeButton.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { likePost } from "@/actions"; 5 | import { BsFillHeartFill, BsHeart } from "react-icons/bs"; 6 | 7 | interface LikeButtonProps { 8 | postId: string; 9 | initialLikesCount: number; 10 | isLiked: boolean; 11 | currentUserId?: string; 12 | } 13 | 14 | const LikeButton: React.FC<LikeButtonProps> = ({ 15 | postId, 16 | initialLikesCount, 17 | isLiked, 18 | currentUserId, 19 | }) => { 20 | const [likesCount, setLikesCount] = React.useState(initialLikesCount); 21 | const [liked, setLiked] = React.useState(isLiked); 22 | 23 | const handleLike = async () => { 24 | if (!currentUserId) { 25 | window.location.href = "/signin"; 26 | return; 27 | } 28 | 29 | await likePost(postId, currentUserId); 30 | setLiked(!liked); 31 | setLikesCount(liked ? likesCount - 1 : likesCount + 1); 32 | }; 33 | 34 | return ( 35 | <div className="flex items-center"> 36 | <button onClick={handleLike} className="mr-2"> 37 | {liked ? ( 38 | <BsFillHeartFill className="w-6 h-6 text-red-500" /> 39 | ) : ( 40 | <BsHeart className="w-6 h-6 text-gray-500" /> 41 | )} 42 | </button> 43 | <span>{likesCount}</span> 44 | </div> 45 | ); 46 | }; 47 | 48 | export default LikeButton; 49 | -------------------------------------------------------------------------------- /7_animes_list/public/next.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> -------------------------------------------------------------------------------- /2_paginas_e_navegacao/public/next.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> -------------------------------------------------------------------------------- /6_nextgram/src/app/signin/page.tsx: -------------------------------------------------------------------------------- 1 | import { signIn, providerMap } from "auth"; 2 | import { BsGoogle } from "react-icons/bs"; 3 | 4 | const icons = [{ name: "Google", icon: <BsGoogle /> }]; 5 | 6 | export default async function SignInPage() { 7 | const findIcon = (name: string) => { 8 | const icon = icons.find((item) => item.name === name); 9 | return icon?.icon ?? ""; 10 | }; 11 | 12 | return ( 13 | <div className="w-1/2 mx-auto my-10 px-4 flex flex-col gap-2"> 14 | <h2 className="text-[2rem] leading-10 font-semibold text-center"> 15 | Acesse ou crie sua conta com uma das opções disponíveis 16 | </h2> 17 | {Object.values(providerMap).map((provider) => ( 18 | <form 19 | key={provider.id} 20 | action={async () => { 21 | "use server"; 22 | await signIn(provider.id, { redirectTo: "/" }); 23 | }} 24 | className="mt-10 flex justify-center" 25 | > 26 | <button 27 | type="submit" 28 | className="h-10 px-6 py-1 font-medium border border-zinc-600 flex items-center gap-2 rounded hover:bg-slate-50" 29 | > 30 | {findIcon(provider.name)} 31 | <span> 32 | Entrar com o <strong>{provider.name}</strong> 33 | </span> 34 | </button> 35 | </form> 36 | ))} 37 | </div> 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /6_nextgram/src/components/CreatePostForm.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { useFormState } from "react-dom"; 5 | import { createPost } from "@/actions"; 6 | import FlashMessage from "./FlashMessage"; 7 | import ImagePreview from "./ImagePreview"; 8 | import Button from "./Button"; 9 | import Label from "./Label"; 10 | 11 | const CreatePostForm: React.FC = () => { 12 | const [formState, formAction] = useFormState(createPost, { 13 | message: "", 14 | type: "success", 15 | }); 16 | 17 | return ( 18 | <> 19 | {formState.message && ( 20 | <FlashMessage message={formState.message} type={formState.type} /> 21 | )} 22 | <form 23 | action={formAction} 24 | encType="multipart/form-data" 25 | className="flex flex-col gap-4" 26 | > 27 | <ImagePreview /> 28 | 29 | <div> 30 | <Label text="Conteúdo do post" htmlFor="content" /> 31 | <textarea 32 | id="content" 33 | name="caption" 34 | className="w-full h-32 p-2 border border-zinc-300 rounded text-sm font-medium placeholder:text-zinc-500 focus:ring-0 focus:outline-none" 35 | placeholder="Digite algo" 36 | ></textarea> 37 | </div> 38 | 39 | <div className="flex justify-end"> 40 | <Button type="submit" text="Criar Post" /> 41 | </div> 42 | </form> 43 | </> 44 | ); 45 | }; 46 | 47 | export default CreatePostForm; 48 | -------------------------------------------------------------------------------- /5_auth/src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { auth, signIn, signOut } from "auth"; 2 | import Link from "next/link"; 3 | 4 | async function Navbar() { 5 | const session = await auth(); 6 | 7 | return ( 8 | <div className="bg-gray-800 text-white p-4 flex justify-between items-center"> 9 | <Link href="/" className="text-white text-lg font-bold"> 10 | Home 11 | </Link> 12 | <div> 13 | {session && session.user ? ( 14 | <div className="flex gap-4 items-center"> 15 | <p>{session.user.name}</p> 16 | <form 17 | action={async () => { 18 | "use server"; 19 | await signOut(); 20 | }} 21 | > 22 | <button 23 | type="submit" 24 | className="bg-red-500 hover:bg-red-700 text-white py-2 px-4 rounded" 25 | > 26 | Sair 27 | </button> 28 | </form> 29 | </div> 30 | ) : ( 31 | <form 32 | action={async () => { 33 | "use server"; 34 | await signIn(); 35 | }} 36 | > 37 | <button 38 | type="submit" 39 | className="bg-blue-500 hover:bg-blue-700 text-white py-2 px-4 rounded" 40 | > 41 | Entrar 42 | </button> 43 | </form> 44 | )} 45 | </div> 46 | </div> 47 | ); 48 | } 49 | 50 | export default Navbar; 51 | -------------------------------------------------------------------------------- /7_animes_list/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import Link from "next/link"; 3 | import { IoLogoYoutube } from "react-icons/io5"; 4 | import { IoLogoLinkedin } from "react-icons/io5"; 5 | import { IoLogoInstagram } from "react-icons/io5"; 6 | 7 | export const Footer = () => { 8 | return ( 9 | <footer className="sm:px-16 py-4 px-8 flex flex-col sm:flex-row justify-between items-center gap-6 sm:gap-2 flex-wrap bg-slate-800"> 10 | <p className="text-base font-bold text-white order-3 sm:order-1"> 11 | © Animes List - 2024 12 | </p> 13 | 14 | <div className="relative w-12 h-12 order-1 sm:order-2"> 15 | <Image 16 | src="/weapon.png" 17 | alt="logo" 18 | fill 19 | sizes="auto" 20 | className="object-fill" 21 | /> 22 | </div> 23 | 24 | <div className="flex items-center gap-6 order-2 sm:order-3"> 25 | <Link href="https://www.youtube.com/@MatheusBattisti" target="_blanck"> 26 | <IoLogoYoutube className="text-[1.5rem]" /> 27 | </Link> 28 | 29 | <Link href="https://www.instagram.com/horadecodar/" target="_blanck"> 30 | <IoLogoInstagram className="text-[1.5rem]" /> 31 | </Link> 32 | 33 | <Link 34 | href="https://www.linkedin.com/in/matheusbattisti/" 35 | target="_blanck" 36 | > 37 | <IoLogoLinkedin className="text-[1.5rem]" /> 38 | </Link> 39 | </div> 40 | </footer> 41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /3_estilos/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /5_auth/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /4_data_fetching/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /6_nextgram/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /2_paginas_e_navegacao/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /6_nextgram/src/components/ImagePreview.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import Label from "./Label"; 5 | import Image from "next/image"; 6 | 7 | const ImagePreview = () => { 8 | const [imagePreview, setImagePreview] = useState<string | null>(null); 9 | const [selectedImage, setSelectedImage] = useState<File | null>(null); 10 | 11 | const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => { 12 | const file = event.target.files?.[0]; 13 | if (file) { 14 | const reader = new FileReader(); 15 | reader.onloadend = () => { 16 | setImagePreview(reader.result as string); 17 | setSelectedImage(file); 18 | }; 19 | reader.readAsDataURL(file); 20 | } 21 | }; 22 | 23 | return ( 24 | <div> 25 | {imagePreview && ( 26 | <div className="flex justify-center mb-4"> 27 | <Image 28 | src={imagePreview} 29 | alt="Pré-visualização da Imagem" 30 | className="w-[494px] h-[294px] object-cover" 31 | width={494} 32 | height={294} 33 | /> 34 | </div> 35 | )} 36 | <Label text="Selecione uma imagem" htmlFor="image" /> 37 | <input 38 | id="image" 39 | name="image" 40 | type="file" 41 | accept="image/*" 42 | onChange={handleImageChange} 43 | className="p-2 border border-zinc-300 rounded w-full file:text-sm file:font-medium text-sm font-medium" 44 | /> 45 | {selectedImage && ( 46 | <input type="hidden" name="imageFile" value={selectedImage.name} /> 47 | )} 48 | </div> 49 | ); 50 | }; 51 | 52 | export default ImagePreview; 53 | -------------------------------------------------------------------------------- /6_nextgram/src/components/ProfileForm.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { useFormState } from "react-dom"; 5 | import { updateUserProfile } from "@/actions"; 6 | import FlashMessage from "./FlashMessage"; 7 | import ImagePreview from "./ImagePreview"; 8 | import { User } from "next-auth"; 9 | import Button from "./Button"; 10 | import Label from "./Label"; 11 | 12 | type ProfileFormProps = { 13 | user: User; 14 | }; 15 | 16 | const ProfileForm: React.FC<ProfileFormProps> = ({ user }) => { 17 | const [formState, formAction] = useFormState(updateUserProfile, { 18 | message: "", 19 | type: "success", 20 | }); 21 | 22 | return ( 23 | <div className="w-full p-4 border border-zinc-300 rounded"> 24 | {formState.message && ( 25 | <FlashMessage message={formState.message} type={formState.type} /> 26 | )} 27 | <form 28 | action={formAction} 29 | method="POST" 30 | encType="multipart/form-data" 31 | className="flex flex-col gap-4" 32 | > 33 | <input type="hidden" name="id" value={user.id} /> 34 | <div> 35 | <Label text="Nome" htmlFor="name" /> 36 | <input 37 | type="text" 38 | id="name" 39 | name="name" 40 | placeholder="Digite seu nome" 41 | defaultValue={user.name || ""} 42 | className="p-2 border border-zinc-300 rounded w-full text-sm placeholder:text-zinc-500 focus:ring-0 focus:outline-none" 43 | /> 44 | </div> 45 | 46 | <ImagePreview /> 47 | 48 | <div className="flex justify-end"> 49 | <Button type="submit" text="Salvar" /> 50 | </div> 51 | </form> 52 | </div> 53 | ); 54 | }; 55 | 56 | export default ProfileForm; 57 | -------------------------------------------------------------------------------- /4_data_fetching/src/components/TodoForm.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { updateTodo } from "@/actions"; 4 | import { useFormState } from "react-dom"; 5 | 6 | const TodoForm = ({ todo }) => { 7 | const [formState, action] = useFormState(updateTodo, { errors: "" }); 8 | 9 | return ( 10 | <form 11 | className="flex flex-col gap-4 p-4 bg-white shadow-lg rounded-lg" 12 | action={action} 13 | > 14 | {formState.errors ? ( 15 | <div className="my-4 p-2 bg-red-400 border border-red-600"> 16 | {formState.errors} 17 | </div> 18 | ) : ( 19 | "" 20 | )} 21 | 22 | <input type="hidden" name="id" defaultValue={todo.id} /> 23 | 24 | <label 25 | htmlFor="titulo" 26 | className="block text-sm font-medium text-gray-700" 27 | > 28 | Título 29 | <input 30 | type="text" 31 | id="titulo" 32 | name="titulo" 33 | placeholder="Insira o título" 34 | required 35 | className="mt-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 w-full" 36 | defaultValue={todo.titulo} 37 | /> 38 | </label> 39 | <label 40 | htmlFor="descricao" 41 | className="block text-sm font-medium text-gray-700" 42 | > 43 | Descrição 44 | <textarea 45 | id="descricao" 46 | name="descricao" 47 | placeholder="Descreva a tarefa" 48 | required 49 | className="mt-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 w-full h-32 resize-none" 50 | defaultValue={todo.descricao} 51 | ></textarea> 52 | </label> 53 | <button 54 | type="submit" 55 | className="px-4 py-2 bg-blue-500 text-white font-semibold rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" 56 | > 57 | Editar 58 | </button> 59 | </form> 60 | ); 61 | }; 62 | 63 | export default TodoForm; 64 | -------------------------------------------------------------------------------- /7_animes_list/components/Card.tsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import { MotionDiv } from "./MotionDiv"; 3 | import { FaStar } from "react-icons/fa6"; 4 | import { MdOutlineVideoLibrary } from "react-icons/md"; 5 | import { Anime } from "@/types/Anime"; 6 | 7 | type CardProps = { 8 | anime: Anime; 9 | index: number; 10 | }; 11 | 12 | const variants = { 13 | hidden: { opacity: 0 }, 14 | visible: { opacity: 1 }, 15 | }; 16 | 17 | export const Card = ({ anime, index }: CardProps) => { 18 | return ( 19 | <MotionDiv 20 | variants={variants} 21 | initial="hidden" 22 | animate="visible" 23 | transition={{ delay: index * 0.25, ease: "easeInOut", duration: 0.5 }} 24 | viewport={{ amount: 0 }} 25 | className="max-w-sm rounded relative w-full hover:scale-105 cursor-pointer duration-200" 26 | > 27 | <div className="relative w-full h-[330px]"> 28 | <Image 29 | src={`https://shikimori.one${anime.image.original}`} 30 | alt={anime.name} 31 | fill 32 | sizes="auto" 33 | className="rounded-xl object-fill" 34 | /> 35 | </div> 36 | 37 | <div className="py-4 flex flex-col gap-3"> 38 | <div className="flex justify-between items-center gap-1"> 39 | <h2 className="font-bold text-white text-xl line-clamp-1 w-full"> 40 | {anime.name} 41 | </h2> 42 | 43 | <div className="py-1 px-2 bg-slate-800 rounded-sm"> 44 | <p className="text-white text-sm font-bold capitalize"> 45 | {anime.kind} 46 | </p> 47 | </div> 48 | </div> 49 | 50 | <div className="flex gap-4 items-center"> 51 | <div className="flex flex-row gap-2 items-center font-medium"> 52 | <MdOutlineVideoLibrary color="green" /> 53 | <small>Episódios - {anime.episodes || anime.episodes_aired}</small> 54 | </div> 55 | 56 | <div className="flex flex-row gap-2 items-center"> 57 | <FaStar color="gold" /> 58 | <small>Média - {anime.score}</small> 59 | </div> 60 | </div> 61 | </div> 62 | </MotionDiv> 63 | ); 64 | }; 65 | -------------------------------------------------------------------------------- /6_nextgram/src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { auth, signOut } from "auth"; 2 | import Link from "next/link"; 3 | import Image from "next/image"; 4 | import { getUserByEmail } from "@/actions"; 5 | import Button from "./Button"; 6 | import ButtonLink from "./ButtonLink"; 7 | 8 | async function Navbar() { 9 | const session = await auth(); 10 | const user = await getUserByEmail(session?.user.email); 11 | 12 | return ( 13 | <div className="bg-gray-800 text-white px-10 py-5 flex justify-between items-center"> 14 | <Link 15 | href="/" 16 | className="text-white hover:text-zinc-200 text-lg font-bold" 17 | > 18 | NextGram 19 | </Link> 20 | <div> 21 | {user ? ( 22 | <div className="flex gap-4 items-center"> 23 | <p className="text-white font-medium">{user.name}</p> 24 | {user.image && ( 25 | <Image 26 | src={user.image} 27 | alt={`${user.name}'s profile picture`} 28 | className="w-10 h-10 rounded-full" 29 | width={40} 30 | height={40} 31 | /> 32 | )} 33 | <Link 34 | href={`/profile/`} 35 | className="text-white font-medium hover:text-zinc-200" 36 | > 37 | Perfil 38 | </Link> 39 | <Link 40 | href={`/post/new`} 41 | className="text-white font-medium hover:text-zinc-200" 42 | > 43 | Criar postagem 44 | </Link> 45 | <Link 46 | href={`/my-posts`} 47 | className="text-white font-medium hover:text-zinc-200" 48 | > 49 | Minhas Postagens 50 | </Link> 51 | <form 52 | action={async () => { 53 | "use server"; 54 | await signOut(); 55 | }} 56 | > 57 | <Button type="submit" text="Sair" danger={true} /> 58 | </form> 59 | </div> 60 | ) : ( 61 | <ButtonLink text="Entrar" url="/signin" /> 62 | )} 63 | </div> 64 | </div> 65 | ); 66 | } 67 | 68 | export default Navbar; 69 | -------------------------------------------------------------------------------- /5_auth/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "sqlite" 3 | url = "file:./dev.db" 4 | } 5 | 6 | generator client { 7 | provider = "prisma-client-js" 8 | } 9 | 10 | model User { 11 | id String @id @default(cuid()) 12 | name String? 13 | email String? @unique 14 | emailVerified DateTime? 15 | image String? 16 | accounts Account[] 17 | sessions Session[] 18 | // Optional for WebAuthn support 19 | Authenticator Authenticator[] 20 | 21 | createdAt DateTime @default(now()) 22 | updatedAt DateTime @updatedAt 23 | } 24 | 25 | model Account { 26 | id String @id @default(cuid()) 27 | userId String 28 | type String 29 | provider String 30 | providerAccountId String 31 | refresh_token String? 32 | access_token String? 33 | expires_at Int? 34 | token_type String? 35 | scope String? 36 | id_token String? 37 | session_state String? 38 | 39 | createdAt DateTime @default(now()) 40 | updatedAt DateTime @updatedAt 41 | 42 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 43 | 44 | @@unique([provider, providerAccountId]) 45 | } 46 | 47 | model Session { 48 | id String @id @default(cuid()) 49 | sessionToken String @unique 50 | userId String 51 | expires DateTime 52 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 53 | 54 | createdAt DateTime @default(now()) 55 | updatedAt DateTime @updatedAt 56 | } 57 | 58 | model VerificationToken { 59 | identifier String 60 | token String 61 | expires DateTime 62 | 63 | @@unique([identifier, token]) 64 | } 65 | 66 | // Optional for WebAuthn support 67 | model Authenticator { 68 | id String @id @default(cuid()) 69 | credentialID String @unique 70 | userId String 71 | providerAccountId String 72 | credentialPublicKey String 73 | counter Int 74 | credentialDeviceType String 75 | credentialBackedUp Boolean 76 | transports String? 77 | 78 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 79 | } -------------------------------------------------------------------------------- /6_nextgram/src/app/my-posts/page.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import Link from "next/link"; 3 | import { getUserPosts, deletePost } from "@/actions"; 4 | import { Post as PostType } from "types/Post"; 5 | import { auth } from "auth"; 6 | import { redirect } from "next/navigation"; 7 | import Button from "@/components/Button"; 8 | import ButtonLink from "@/components/ButtonLink"; 9 | import Image from "next/image"; 10 | 11 | const MyPosts: React.FC = async () => { 12 | const session = await auth(); 13 | 14 | let userId = null; 15 | 16 | if (session) { 17 | userId = session.user.userId; 18 | } else { 19 | redirect("/"); 20 | } 21 | 22 | const posts = await getUserPosts(userId); 23 | 24 | return ( 25 | <div className="container mx-auto px-4 my-10"> 26 | <h1 className="text-[2rem] leading-20 font-semibold mb-8"> 27 | Minhas Postagens 28 | </h1> 29 | {posts.length === 0 ? ( 30 | <div className="text-center"> 31 | <p className="mb-4 font-medium"> 32 | Você ainda não tem nenhuma postagem. 33 | </p> 34 | 35 | <div className="flex justify-center"> 36 | <ButtonLink text="Criar nova postagem" url="/post/new" /> 37 | </div> 38 | </div> 39 | ) : ( 40 | <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6"> 41 | {posts.map((post) => ( 42 | <div key={post.id} className="border rounded p-4 shadow-sm"> 43 | <Image 44 | src={post.imageUrl} 45 | alt={post.caption || "Post image"} 46 | className="w-[366px] h-[218px] object-cover mb-4 rounded" 47 | width={366} 48 | height={218} 49 | /> 50 | {post.caption && ( 51 | <p className="mb-2 text-sm font-medium">{post.caption}</p> 52 | )} 53 | <form action={deletePost}> 54 | <input type="hidden" name="userId" value={userId} /> 55 | <input type="hidden" name="postId" value={post.id} /> 56 | <div className="flex justify-end"> 57 | <Button type="submit" text="Excluir" danger={true} /> 58 | </div> 59 | </form> 60 | </div> 61 | ))} 62 | </div> 63 | )} 64 | </div> 65 | ); 66 | }; 67 | 68 | export default MyPosts; 69 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/todos/create/page.js: -------------------------------------------------------------------------------- 1 | import { db } from "@/db.js"; 2 | import { redirect } from "next/navigation"; 3 | 4 | import { addTodo } from "@/actions"; 5 | 6 | // 1 - Criacao do form 7 | export default async function TodoCreate() { 8 | // const addTodo = async (formData) => { 9 | // "use server"; 10 | 11 | // console.log(formData); 12 | 13 | // // 2 - Inserindo dados no banco 14 | // const titulo = formData.get("titulo"); 15 | // const descricao = formData.get("descricao"); 16 | // const status = "pendente"; 17 | 18 | // const todo = await db.todo.create({ 19 | // data: { 20 | // titulo, 21 | // descricao, 22 | // status, 23 | // }, 24 | // }); 25 | 26 | // console.log(todo); 27 | 28 | // redirect("/"); 29 | // }; 30 | 31 | return ( 32 | <div className="max-w-md mx-auto mt-10"> 33 | <h1 className="text-2xl font-bold text-center mb-6">Criar Nova Tarefa</h1> 34 | <form 35 | action={addTodo} 36 | className="flex flex-col gap-4 p-4 bg-white shadow-lg rounded-lg" 37 | > 38 | <label 39 | htmlFor="titulo" 40 | className="block text-sm font-medium text-gray-700" 41 | > 42 | Título 43 | <input 44 | type="text" 45 | id="titulo" 46 | name="titulo" 47 | placeholder="Insira o título" 48 | required 49 | className="mt-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 w-full" 50 | /> 51 | </label> 52 | <label 53 | htmlFor="descricao" 54 | className="block text-sm font-medium text-gray-700" 55 | > 56 | Descrição 57 | <textarea 58 | id="descricao" 59 | name="descricao" 60 | placeholder="Descreva a tarefa" 61 | required 62 | className="mt-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 w-full h-32 resize-none" 63 | ></textarea> 64 | </label> 65 | <button 66 | type="submit" 67 | className="px-4 py-2 bg-blue-500 text-white font-semibold rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" 68 | > 69 | Criar Todo 70 | </button> 71 | </form> 72 | </div> 73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /6_nextgram/src/components/Post.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import { Post as PostType } from "types/Post"; 5 | import LikeButton from "./Post/LikeButton"; 6 | import { FiMessageSquare } from "react-icons/fi"; 7 | import CommentModal from "./Post/CommentModal"; 8 | import Image from "next/image"; 9 | 10 | interface PostProps { 11 | post: PostType; 12 | currentUserId?: string; 13 | } 14 | 15 | const Post: React.FC<PostProps> = ({ post, currentUserId }) => { 16 | let isLiked = false; 17 | 18 | if (post.likes) { 19 | isLiked = post.likes.some((like) => like.userId === currentUserId); 20 | } 21 | 22 | const [isCommentModalOpen, setIsCommentModalOpen] = useState(false); 23 | 24 | return ( 25 | <div className="w-fit mx-auto mb-6 p-4 border rounded shadow-sm"> 26 | <Image 27 | src={post.imageUrl} 28 | alt={post.caption || "Imagem sem legenda"} 29 | className="w-[670px] h-[400px] object-cover mb-4 rounded" 30 | width={670} 31 | height={400} 32 | /> 33 | {post.caption && ( 34 | <p className="mb-4 text-sm font-medium">{post.caption}</p> 35 | )} 36 | <div className="flex items-center"> 37 | {post.user.image && ( 38 | <Image 39 | src={post.user.image} 40 | alt={`${post.user.name}'s profile`} 41 | className="w-10 h-10 object-cover rounded-full mr-3" 42 | width={40} 43 | height={40} 44 | /> 45 | )} 46 | <p className="text-sm font-medium">{post.user.name}</p> 47 | </div> 48 | <div className="flex items-center mt-4"> 49 | <LikeButton 50 | postId={post.id} 51 | initialLikesCount={post.likes?.length ? post.likes.length : 0} 52 | isLiked={isLiked} 53 | currentUserId={currentUserId} 54 | /> 55 | <button 56 | onClick={() => setIsCommentModalOpen(true)} 57 | className="ml-4 flex items-center" 58 | > 59 | <FiMessageSquare className="w-6 h-6 text-gray-500" /> 60 | <span className="ml-1"> 61 | {post.comments ? post.comments.length : 0} 62 | </span> 63 | </button> 64 | </div> 65 | <CommentModal 66 | post={post} 67 | currentUserId={currentUserId} 68 | isOpen={isCommentModalOpen} 69 | onRequestClose={() => setIsCommentModalOpen(false)} 70 | /> 71 | </div> 72 | ); 73 | }; 74 | 75 | export default Post; 76 | -------------------------------------------------------------------------------- /4_data_fetching/src/actions.js: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import { db } from "@/db"; 4 | import { revalidatePath } from "next/cache"; 5 | import { redirect } from "next/navigation"; 6 | 7 | export async function deleteTodo(formData) { 8 | const id = parseInt(formData.get("id")); 9 | 10 | await db.todo.delete({ 11 | where: { id }, 12 | }); 13 | 14 | revalidatePath("/"); 15 | 16 | redirect("/"); 17 | } 18 | 19 | export async function addTodo(formData) { 20 | const titulo = formData.get("titulo"); 21 | const descricao = formData.get("descricao"); 22 | const status = "pendente"; 23 | 24 | const todo = await db.todo.create({ 25 | data: { 26 | titulo, 27 | descricao, 28 | status, 29 | }, 30 | }); 31 | 32 | console.log(todo); 33 | 34 | redirect("/"); 35 | } 36 | 37 | export async function findTodoById(id) { 38 | // 11 - erro backend - error.js 39 | // throw new Error("Ops!"); 40 | 41 | const todo = await db.todo.findFirst({ 42 | where: { id }, 43 | }); 44 | 45 | return todo; 46 | } 47 | 48 | export async function updateTodo(formState, formData) { 49 | const id = parseInt(formData.get("id")); 50 | const titulo = formData.get("titulo"); 51 | const descricao = formData.get("descricao"); 52 | 53 | if (titulo.length < 5) { 54 | return { 55 | errors: "O título precisa de pelo menos 5 caracteres.", 56 | }; 57 | } 58 | 59 | if (descricao.length < 10) { 60 | return { 61 | errors: "A descrição precisa de pelo menos 10 caracteres.", 62 | }; 63 | } 64 | 65 | await db.todo.update({ 66 | where: { id }, 67 | data: { 68 | titulo, 69 | descricao, 70 | }, 71 | }); 72 | 73 | redirect("/"); 74 | } 75 | 76 | export async function toggleTodoStatus(formData) { 77 | const todoId = parseInt(formData.get("id")); 78 | 79 | // Busca o todo com o ID fornecido. 80 | const todo = await db.todo.findUnique({ 81 | where: { 82 | id: todoId, 83 | }, 84 | }); 85 | 86 | // Verifica se o todo existe; se não, lança um erro. 87 | if (!todo) { 88 | throw new Error("Todo não encontrado"); 89 | } 90 | 91 | // Determina o novo status baseado no status atual. 92 | const novoStatus = todo.status === "pendente" ? "completa" : "pendente"; 93 | 94 | // Atualiza o todo no banco de dados com o novo status. 95 | await db.todo.update({ 96 | where: { 97 | id: todoId, 98 | }, 99 | data: { 100 | status: novoStatus, 101 | }, 102 | }); 103 | 104 | // Redireciona o usuário para a página inicial (ou outra página conforme necessário). 105 | redirect("/"); 106 | } 107 | -------------------------------------------------------------------------------- /5_auth/prisma/migrations/20240510151330_/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "User" ( 3 | "id" TEXT NOT NULL PRIMARY KEY, 4 | "name" TEXT, 5 | "email" TEXT, 6 | "emailVerified" DATETIME, 7 | "image" TEXT, 8 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 9 | "updatedAt" DATETIME NOT NULL 10 | ); 11 | 12 | -- CreateTable 13 | CREATE TABLE "Account" ( 14 | "id" TEXT NOT NULL PRIMARY KEY, 15 | "userId" TEXT NOT NULL, 16 | "type" TEXT NOT NULL, 17 | "provider" TEXT NOT NULL, 18 | "providerAccountId" TEXT NOT NULL, 19 | "refresh_token" TEXT, 20 | "access_token" TEXT, 21 | "expires_at" INTEGER, 22 | "token_type" TEXT, 23 | "scope" TEXT, 24 | "id_token" TEXT, 25 | "session_state" TEXT, 26 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 27 | "updatedAt" DATETIME NOT NULL, 28 | CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE 29 | ); 30 | 31 | -- CreateTable 32 | CREATE TABLE "Session" ( 33 | "id" TEXT NOT NULL PRIMARY KEY, 34 | "sessionToken" TEXT NOT NULL, 35 | "userId" TEXT NOT NULL, 36 | "expires" DATETIME NOT NULL, 37 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 38 | "updatedAt" DATETIME NOT NULL, 39 | CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE 40 | ); 41 | 42 | -- CreateTable 43 | CREATE TABLE "VerificationToken" ( 44 | "identifier" TEXT NOT NULL, 45 | "token" TEXT NOT NULL, 46 | "expires" DATETIME NOT NULL 47 | ); 48 | 49 | -- CreateTable 50 | CREATE TABLE "Authenticator" ( 51 | "id" TEXT NOT NULL PRIMARY KEY, 52 | "credentialID" TEXT NOT NULL, 53 | "userId" TEXT NOT NULL, 54 | "providerAccountId" TEXT NOT NULL, 55 | "credentialPublicKey" TEXT NOT NULL, 56 | "counter" INTEGER NOT NULL, 57 | "credentialDeviceType" TEXT NOT NULL, 58 | "credentialBackedUp" BOOLEAN NOT NULL, 59 | "transports" TEXT, 60 | CONSTRAINT "Authenticator_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE 61 | ); 62 | 63 | -- CreateIndex 64 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); 65 | 66 | -- CreateIndex 67 | CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); 68 | 69 | -- CreateIndex 70 | CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); 71 | 72 | -- CreateIndex 73 | CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token"); 74 | 75 | -- CreateIndex 76 | CREATE UNIQUE INDEX "Authenticator_credentialID_key" ON "Authenticator"("credentialID"); 77 | -------------------------------------------------------------------------------- /7_animes_list/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Image from "next/image"; 4 | import Link from "next/link"; 5 | import { usePathname } from "next/navigation"; 6 | import { useState } from "react"; 7 | import { GiHamburgerMenu } from "react-icons/gi"; 8 | 9 | type NavbarLink = { 10 | id: number; 11 | name: string; 12 | path: string; 13 | }; 14 | 15 | const links: NavbarLink[] = [ 16 | { id: 1, name: "Todos", path: "/" }, 17 | { id: 2, name: "Mais avaliados", path: "/most-rated" }, 18 | { id: 3, name: "Mais populares", path: "/most-popular" }, 19 | ]; 20 | 21 | export const Navbar = () => { 22 | const pathname = usePathname(); 23 | 24 | const [showMenu, setShowMenu] = useState(false); 25 | 26 | return ( 27 | <header className="max-w-7xl mx-auto w-full px-10 py-4 flex justify-between items-center bg-slate-800 fixed z-10"> 28 | <Link href="/" className="flex items-center gap-4"> 29 | <div className="relative w-12 h-12"> 30 | <Image 31 | src="/weapon.png" 32 | alt="logo" 33 | fill 34 | sizes="auto" 35 | className="object-fill" 36 | /> 37 | </div> 38 | <span className="font-medium tracking-wide">Animes List</span> 39 | </Link> 40 | 41 | <nav className="hidden sm:block"> 42 | <ul className="flex gap-3 font-medium tracking-wide"> 43 | {links.map((link) => ( 44 | <li key={link.id}> 45 | <Link 46 | href={link.path} 47 | passHref 48 | className={`hover:underline hover:underline-offset-4 hover:text-slate-100 ${ 49 | pathname === link.path 50 | ? "text-slate-100 underline underline-offset-4" 51 | : "" 52 | }`} 53 | > 54 | {link.name} 55 | </Link> 56 | </li> 57 | ))} 58 | </ul> 59 | </nav> 60 | 61 | <div className="sm:hidden"> 62 | <button onClick={() => setShowMenu((prev) => !prev)}> 63 | <GiHamburgerMenu className="text-[2rem]" /> 64 | </button> 65 | 66 | <nav 67 | className={`absolute z-10 top-[80px] bg-slate-700 transition-all duration-300 ${ 68 | showMenu ? "right-0" : "-right-[100%]" 69 | }`} 70 | > 71 | <ul className="flex flex-col items-center gap-4 font-medium tracking-wide w-full h-screen p-10"> 72 | {links.map((link) => ( 73 | <li key={link.id}> 74 | <Link 75 | href={link.path} 76 | passHref 77 | className={ 78 | pathname === link.path 79 | ? "text-slate-100 underline underline-offset-4" 80 | : "" 81 | } 82 | > 83 | {link.name} 84 | </Link> 85 | </li> 86 | ))} 87 | </ul> 88 | </nav> 89 | </div> 90 | </header> 91 | ); 92 | }; 93 | -------------------------------------------------------------------------------- /4_data_fetching/src/app/page.js: -------------------------------------------------------------------------------- 1 | import Button from "@/components/Button"; 2 | import { db } from "@/db"; 3 | import Link from "next/link"; 4 | import { redirect } from "next/navigation"; 5 | 6 | import Checkbox from "@/components/Checkbox"; 7 | 8 | import { deleteTodo, toggleTodoStatus, updateTodo } from "@/actions"; 9 | 10 | // Cache - Revalidando por tempo 11 | // export const revalidate = 20; 12 | 13 | // Remoção de completa de cache 14 | // export const dynamic = "force-dynamic"; 15 | 16 | export default async function Home() { 17 | // 3 - Resgatando dados do banco 18 | const todos = await db.todo.findMany(); 19 | 20 | console.log(todos); 21 | 22 | // 8 - componente cliente em server 23 | // async function deleteTodo(formData) { 24 | // "use server"; 25 | 26 | // const id = parseInt(formData.get("id")); 27 | 28 | // await db.todo.delete({ 29 | // where: { id }, 30 | // }); 31 | 32 | // redirect("/"); 33 | // } 34 | 35 | return ( 36 | <> 37 | <main className="container mx-auto p-4"> 38 | <h1 className="text-2xl font-bold mb-4">Todos!</h1> 39 | <div className="space-y-4"> 40 | {todos.map((todo) => ( 41 | <div 42 | key={todo.id} 43 | className={`bg-gray-100 p-4 rounded-lg shadow ${ 44 | todo.status === "completa" ? "bg-green-100" : "" 45 | }`} 46 | > 47 | <div className="flex justify-between items-start"> 48 | <div> 49 | <h2 className="text-xl font-semibold">{todo.titulo}</h2> 50 | <p>{todo.descricao}</p> 51 | </div> 52 | {/* Formulário para alternar o status */} 53 | <div className="flex items-center gap-2"> 54 | <p className="italic">completar?</p> 55 | <form action={toggleTodoStatus}> 56 | <input type="hidden" name="id" value={todo.id} /> 57 | <Checkbox checked={todo.status === "completa"} /> 58 | </form> 59 | </div> 60 | </div> 61 | 62 | <div className="flex space-x-2 mt-3"> 63 | <Link 64 | href={`/todos/${todo.id}`} 65 | className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" 66 | > 67 | Visualizar 68 | </Link> 69 | <Link 70 | href={`/todos/${todo.id}/edit/`} 71 | className="bg-yellow-500 hover:bg-yellow-700 text-white font-bold py-2 px-4 rounded" 72 | > 73 | Editar 74 | </Link> 75 | {/* <button className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"> 76 | Excluir 77 | </button> */} 78 | <form action={deleteTodo}> 79 | <input type="hidden" name="id" value={todo.id} /> 80 | <Button className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"> 81 | Excluir 82 | </Button> 83 | </form> 84 | </div> 85 | </div> 86 | ))} 87 | </div> 88 | </main> 89 | </> 90 | ); 91 | } 92 | -------------------------------------------------------------------------------- /6_nextgram/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // Excluir dados do projeto antigo 2 | // npx prisma migrate dev 3 | // npx prisma generate 4 | // npx prisma migrate reset 5 | 6 | datasource db { 7 | provider = "sqlite" 8 | url = "file:./dev.db" 9 | } 10 | 11 | generator client { 12 | provider = "prisma-client-js" 13 | } 14 | 15 | model User { 16 | id String @id @default(cuid()) 17 | name String? 18 | email String? @unique 19 | emailVerified DateTime? 20 | image String? 21 | accounts Account[] 22 | sessions Session[] 23 | // Optional for WebAuthn support 24 | Authenticator Authenticator[] 25 | 26 | // Relações da aplicação 27 | posts Post[] 28 | likes Like[] 29 | comments Comment[] 30 | 31 | createdAt DateTime @default(now()) 32 | updatedAt DateTime @updatedAt 33 | } 34 | 35 | model Account { 36 | id String @id @default(cuid()) 37 | userId String 38 | type String 39 | provider String 40 | providerAccountId String 41 | refresh_token String? 42 | access_token String? 43 | expires_at Int? 44 | token_type String? 45 | scope String? 46 | id_token String? 47 | session_state String? 48 | 49 | createdAt DateTime @default(now()) 50 | updatedAt DateTime @updatedAt 51 | 52 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 53 | 54 | @@unique([provider, providerAccountId]) 55 | } 56 | 57 | model Session { 58 | id String @id @default(cuid()) 59 | sessionToken String @unique 60 | userId String 61 | expires DateTime 62 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 63 | 64 | createdAt DateTime @default(now()) 65 | updatedAt DateTime @updatedAt 66 | } 67 | 68 | model VerificationToken { 69 | identifier String 70 | token String 71 | expires DateTime 72 | 73 | @@unique([identifier, token]) 74 | } 75 | 76 | // Optional for WebAuthn support 77 | model Authenticator { 78 | id String @id @default(cuid()) 79 | credentialID String @unique 80 | userId String 81 | providerAccountId String 82 | credentialPublicKey String 83 | counter Int 84 | credentialDeviceType String 85 | credentialBackedUp Boolean 86 | transports String? 87 | 88 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 89 | } 90 | 91 | model Post { 92 | id String @id @default(cuid()) 93 | imageUrl String 94 | caption String? 95 | userId String 96 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 97 | likes Like[] 98 | comments Comment[] 99 | createdAt DateTime @default(now()) 100 | updatedAt DateTime @updatedAt 101 | } 102 | 103 | model Like { 104 | id String @id @default(cuid()) 105 | userId String 106 | postId String 107 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 108 | post Post @relation(fields: [postId], references: [id], onDelete: Cascade) 109 | createdAt DateTime @default(now()) 110 | } 111 | 112 | model Comment { 113 | id String @id @default(cuid()) 114 | content String 115 | userId String 116 | postId String 117 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 118 | post Post @relation(fields: [postId], references: [id], onDelete: Cascade) 119 | createdAt DateTime @default(now()) 120 | updatedAt DateTime @updatedAt 121 | } -------------------------------------------------------------------------------- /6_nextgram/src/components/Post/CommentModal.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import Modal from "react-modal"; 5 | import { Post as PostType } from "types/Post"; 6 | import { addComment } from "@/actions"; 7 | import FlashMessage from "../FlashMessage"; 8 | import { GrClose } from "react-icons/gr"; 9 | import Button from "../Button"; 10 | import Image from "next/image"; 11 | 12 | interface CommentModalProps { 13 | post: PostType; 14 | currentUserId?: string; 15 | isOpen: boolean; 16 | onRequestClose: () => void; 17 | } 18 | 19 | const CommentModal: React.FC<CommentModalProps> = ({ 20 | post, 21 | currentUserId, 22 | isOpen, 23 | onRequestClose, 24 | }) => { 25 | const [content, setContent] = useState(""); 26 | const [flashMessage, setFlashMessage] = useState<{ 27 | message: string; 28 | type: "error" | "success"; 29 | } | null>(null); 30 | 31 | const handleAddComment = async () => { 32 | if (!currentUserId) { 33 | window.location.href = "/signin"; 34 | return; 35 | } 36 | 37 | if (!content.trim()) { 38 | setFlashMessage({ 39 | message: "O comentário não pode estar vazio.", 40 | type: "error", 41 | }); 42 | return; 43 | } 44 | 45 | await addComment(post.id, currentUserId, content); 46 | setFlashMessage({ 47 | message: "Comentário adicionado com sucesso.", 48 | type: "success", 49 | }); 50 | setContent(""); 51 | }; 52 | 53 | return ( 54 | <Modal 55 | isOpen={isOpen} 56 | onRequestClose={onRequestClose} 57 | contentLabel="Comments" 58 | ariaHideApp={false} 59 | className={ 60 | "w-[704px] mx-auto mt-28 bg-white rounded border border-zinc-300" 61 | } 62 | > 63 | <div className="p-4"> 64 | <div className="flex justify-between items-center"> 65 | <h2 className="text-xl font-bold mb-4">Comentários</h2> 66 | <button 67 | onClick={onRequestClose} 68 | className="bg-red-600 hover:bg-red-400 text-white p-2 rounded-full" 69 | > 70 | <GrClose /> 71 | </button> 72 | </div> 73 | {flashMessage && ( 74 | <FlashMessage 75 | message={flashMessage.message} 76 | type={flashMessage.type} 77 | /> 78 | )} 79 | <div className="mb-4 flex flex-col gap-0.5"> 80 | {post.comments && post.comments.length > 0 ? ( 81 | post.comments.map((comment) => ( 82 | <div key={comment.id} className="flex items-center"> 83 | {post.user.image && ( 84 | <Image 85 | src={post.user.image} 86 | alt={`${post.user.name}'s profile`} 87 | className="w-10 h-10 object-cover rounded-full mr-3" 88 | width={40} 89 | height={40} 90 | /> 91 | )} 92 | <p className="text-sm"> 93 | <strong>{comment.user.name}:</strong> {comment.content} 94 | </p> 95 | </div> 96 | )) 97 | ) : ( 98 | <p>Nenhum comentário ainda. Seja o primeiro a comentar!</p> 99 | )} 100 | </div> 101 | {currentUserId && ( 102 | <div className="mb-4 flex flex-col gap-6"> 103 | <textarea 104 | className="w-full h-32 p-2 border border-zinc-300 rounded text-sm font-medium placeholder:text-zinc-500 focus:ring-0 focus:outline-none" 105 | value={content} 106 | onChange={(e) => setContent(e.target.value)} 107 | placeholder="Adicione um comentário" 108 | /> 109 | 110 | <div className="flex justify-end"> 111 | <Button 112 | type="button" 113 | text="Comentar" 114 | onClick={handleAddComment} 115 | /> 116 | </div> 117 | </div> 118 | )} 119 | </div> 120 | </Modal> 121 | ); 122 | }; 123 | 124 | export default CommentModal; 125 | -------------------------------------------------------------------------------- /6_nextgram/prisma/migrations/20240516213823_/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "User" ( 3 | "id" TEXT NOT NULL PRIMARY KEY, 4 | "name" TEXT, 5 | "email" TEXT, 6 | "emailVerified" DATETIME, 7 | "image" TEXT, 8 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 9 | "updatedAt" DATETIME NOT NULL 10 | ); 11 | 12 | -- CreateTable 13 | CREATE TABLE "Account" ( 14 | "id" TEXT NOT NULL PRIMARY KEY, 15 | "userId" TEXT NOT NULL, 16 | "type" TEXT NOT NULL, 17 | "provider" TEXT NOT NULL, 18 | "providerAccountId" TEXT NOT NULL, 19 | "refresh_token" TEXT, 20 | "access_token" TEXT, 21 | "expires_at" INTEGER, 22 | "token_type" TEXT, 23 | "scope" TEXT, 24 | "id_token" TEXT, 25 | "session_state" TEXT, 26 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 27 | "updatedAt" DATETIME NOT NULL, 28 | CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE 29 | ); 30 | 31 | -- CreateTable 32 | CREATE TABLE "Session" ( 33 | "id" TEXT NOT NULL PRIMARY KEY, 34 | "sessionToken" TEXT NOT NULL, 35 | "userId" TEXT NOT NULL, 36 | "expires" DATETIME NOT NULL, 37 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 38 | "updatedAt" DATETIME NOT NULL, 39 | CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE 40 | ); 41 | 42 | -- CreateTable 43 | CREATE TABLE "VerificationToken" ( 44 | "identifier" TEXT NOT NULL, 45 | "token" TEXT NOT NULL, 46 | "expires" DATETIME NOT NULL 47 | ); 48 | 49 | -- CreateTable 50 | CREATE TABLE "Authenticator" ( 51 | "id" TEXT NOT NULL PRIMARY KEY, 52 | "credentialID" TEXT NOT NULL, 53 | "userId" TEXT NOT NULL, 54 | "providerAccountId" TEXT NOT NULL, 55 | "credentialPublicKey" TEXT NOT NULL, 56 | "counter" INTEGER NOT NULL, 57 | "credentialDeviceType" TEXT NOT NULL, 58 | "credentialBackedUp" BOOLEAN NOT NULL, 59 | "transports" TEXT, 60 | CONSTRAINT "Authenticator_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE 61 | ); 62 | 63 | -- CreateTable 64 | CREATE TABLE "Post" ( 65 | "id" TEXT NOT NULL PRIMARY KEY, 66 | "imageUrl" TEXT NOT NULL, 67 | "caption" TEXT, 68 | "userId" TEXT NOT NULL, 69 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 70 | "updatedAt" DATETIME NOT NULL, 71 | CONSTRAINT "Post_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE 72 | ); 73 | 74 | -- CreateTable 75 | CREATE TABLE "Like" ( 76 | "id" TEXT NOT NULL PRIMARY KEY, 77 | "userId" TEXT NOT NULL, 78 | "postId" TEXT NOT NULL, 79 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 80 | CONSTRAINT "Like_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE, 81 | CONSTRAINT "Like_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post" ("id") ON DELETE CASCADE ON UPDATE CASCADE 82 | ); 83 | 84 | -- CreateTable 85 | CREATE TABLE "Comment" ( 86 | "id" TEXT NOT NULL PRIMARY KEY, 87 | "content" TEXT NOT NULL, 88 | "userId" TEXT NOT NULL, 89 | "postId" TEXT NOT NULL, 90 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 91 | "updatedAt" DATETIME NOT NULL, 92 | CONSTRAINT "Comment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE, 93 | CONSTRAINT "Comment_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post" ("id") ON DELETE CASCADE ON UPDATE CASCADE 94 | ); 95 | 96 | -- CreateIndex 97 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); 98 | 99 | -- CreateIndex 100 | CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); 101 | 102 | -- CreateIndex 103 | CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); 104 | 105 | -- CreateIndex 106 | CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token"); 107 | 108 | -- CreateIndex 109 | CREATE UNIQUE INDEX "Authenticator_credentialID_key" ON "Authenticator"("credentialID"); 110 | -------------------------------------------------------------------------------- /6_nextgram/src/actions.ts: -------------------------------------------------------------------------------- 1 | "use server"; 2 | 3 | import { PrismaClient } from "@prisma/client"; 4 | 5 | const prisma = new PrismaClient(); 6 | 7 | import { User } from "@prisma/client"; 8 | import path from "path"; 9 | import { promises as fs } from "fs"; 10 | import { auth } from "auth"; 11 | import { revalidatePath } from "next/cache"; 12 | import { redirect } from "next/navigation"; 13 | 14 | type FormState = { 15 | message: string; 16 | type: string; 17 | }; 18 | 19 | export async function getUserProfileData(id: string): Promise<User | null> { 20 | const userId = id; 21 | 22 | const user = await prisma.user.findFirst({ 23 | where: { id: userId }, 24 | include: { 25 | // posts: true, // Assumindo que você tem um relacionamento 'posts' no modelo de usuário 26 | }, 27 | }); 28 | 29 | return user; 30 | } 31 | 32 | // Resgate de usuário por email 33 | export async function getUserByEmail( 34 | email: string | null 35 | ): Promise<User | null> { 36 | if (!email) return null; 37 | 38 | const user = await prisma.user.findFirst({ 39 | where: { email: email }, 40 | }); 41 | 42 | return user; 43 | } 44 | 45 | // Atualização de perfil usuario 46 | export async function updateUserProfile( 47 | formState: FormState, 48 | formData: FormData 49 | ): Promise<FormState> { 50 | const session = await auth(); 51 | 52 | if (!session) { 53 | redirect("/"); 54 | } 55 | 56 | const id = formData.get("id") as string; 57 | const name = formData.get("name") as string; 58 | const imageFile = formData.get("image") as File; 59 | 60 | if (session.user.userId !== id) { 61 | return { message: "Unauthorized", type: "error" }; 62 | } 63 | 64 | let imageUrl = ""; 65 | if (imageFile) { 66 | const uploadDir = path.join(process.cwd(), "public", "uploads"); 67 | await fs.mkdir(uploadDir, { recursive: true }); 68 | const filePath = path.join(uploadDir, imageFile.name); 69 | const arrayBuffer = await imageFile.arrayBuffer(); 70 | await fs.writeFile(filePath, Buffer.from(arrayBuffer)); 71 | imageUrl = `/uploads/${imageFile.name}`; 72 | } 73 | 74 | await prisma.user.update({ 75 | where: { id }, 76 | data: { name, image: imageUrl || undefined }, 77 | }); 78 | 79 | revalidatePath("/profile"); 80 | 81 | return { message: "Perfil atualizado com sucesso!", type: "success" }; 82 | } 83 | 84 | export async function createPost( 85 | formState: FormState, 86 | formData: FormData 87 | ): Promise<FormState> { 88 | const session = await auth(); 89 | 90 | if (!session) { 91 | redirect("/"); 92 | } 93 | 94 | const caption = formData.get("caption") as string; 95 | const imageFile = formData.get("image") as File; 96 | 97 | console.log(imageFile, caption); 98 | 99 | if (!caption || imageFile.size === 0) { 100 | return { message: "Preencha o formulário!", type: "error" }; 101 | } 102 | 103 | const uploadDir = path.join(process.cwd(), "public", "uploads"); 104 | await fs.mkdir(uploadDir, { recursive: true }); 105 | const filePath = path.join(uploadDir, imageFile.name); 106 | const arrayBuffer = await imageFile.arrayBuffer(); 107 | await fs.writeFile(filePath, Buffer.from(arrayBuffer)); 108 | const imageUrl = `/uploads/${imageFile.name}`; 109 | 110 | await prisma.post.create({ 111 | data: { 112 | imageUrl, 113 | caption, 114 | userId: session.user.userId, 115 | }, 116 | }); 117 | 118 | revalidatePath("/"); 119 | 120 | redirect("/"); 121 | } 122 | 123 | // Resgatar todos os posts 124 | export async function getAllPosts() { 125 | return await prisma.post.findMany({ 126 | orderBy: { 127 | createdAt: "desc", 128 | }, 129 | include: { 130 | user: true, 131 | likes: true, 132 | comments: { 133 | include: { 134 | user: true, 135 | }, 136 | }, 137 | }, 138 | }); 139 | } 140 | 141 | // Like no post 142 | export async function likePost(postId: string, userId: string) { 143 | const session = await auth(); 144 | 145 | if (!session) { 146 | redirect("/signin"); 147 | } 148 | 149 | console.log(session.user.userId, userId); 150 | 151 | if (session.user.userId !== userId) { 152 | throw new Error("Unauthorized"); 153 | } 154 | 155 | const existingLike = await prisma.like.findFirst({ 156 | where: { 157 | postId, 158 | userId, 159 | }, 160 | }); 161 | 162 | if (existingLike) { 163 | await prisma.like.delete({ 164 | where: { 165 | id: existingLike.id, 166 | }, 167 | }); 168 | } else { 169 | await prisma.like.create({ 170 | data: { 171 | postId, 172 | userId, 173 | }, 174 | }); 175 | } 176 | 177 | revalidatePath("/"); 178 | } 179 | 180 | export async function addComment( 181 | postId: string, 182 | userId: string, 183 | content: string 184 | ) { 185 | const session = await auth(); 186 | 187 | if (!session) { 188 | redirect("/signin"); 189 | } 190 | 191 | if (session.user.userId !== userId) { 192 | throw new Error("Unauthorized"); 193 | } 194 | 195 | await prisma.comment.create({ 196 | data: { 197 | postId, 198 | userId, 199 | content, 200 | }, 201 | }); 202 | 203 | revalidatePath("/"); 204 | } 205 | 206 | // Posts do usuarios 207 | export async function getUserPosts(userId: string) { 208 | const session = await auth(); 209 | 210 | if (!session) { 211 | redirect("/signin"); 212 | } 213 | 214 | if (session.user.userId !== userId) { 215 | throw new Error("Unauthorized"); 216 | } 217 | 218 | return await prisma.post.findMany({ 219 | where: { userId }, 220 | include: { 221 | user: true, 222 | likes: true, 223 | comments: true, 224 | }, 225 | orderBy: { 226 | createdAt: "desc", 227 | }, 228 | }); 229 | } 230 | 231 | // Excluir posts 232 | export async function deletePost(formData: FormData) { 233 | const session = await auth(); 234 | 235 | if (!session) { 236 | redirect("/signin"); 237 | } 238 | 239 | const userId = formData.get("userId") as string; 240 | const postId = formData.get("postId") as string; 241 | 242 | console.log(userId, session.user.userId); 243 | 244 | if (session.user.userId !== userId) { 245 | throw new Error("Unauthorized"); 246 | } 247 | 248 | await prisma.post.delete({ 249 | where: { id: postId }, 250 | }); 251 | 252 | revalidatePath("/my-posts"); 253 | } 254 | -------------------------------------------------------------------------------- /7_animes_list/public/logo.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" width="47" height="44" viewBox="0 0 47 44" fill="none"> 2 | <g clip-path="url(#clip0_1678_2172)"> 3 | <path fill-rule="evenodd" clip-rule="evenodd" d="M21.6717 43.7311C21.5882 43.7311 21.5047 43.6985 21.4463 43.6333L13.2234 34.7926C12.0296 35.4607 10.9193 35.9822 9.9175 36.3326C8.68198 36.8378 7.58837 37.0904 6.67843 37.0904C6.54486 37.0904 6.41685 37.0849 6.29441 37.0741C6.16919 37.0659 6.05232 36.9763 6.01892 36.8459C5.99388 36.7237 6.04397 36.5852 6.16084 36.52C6.17754 36.5037 8.06422 35.3385 11.4452 32.8859L1.52763 22.2119C1.4191 22.0978 1.4191 21.9267 1.52763 21.8126L6.83704 16.1007L6.65338 15.9378L5.67665 15.017C5.35386 14.7074 5.03663 14.4032 4.72496 14.1044C3.26404 12.703 1.84486 11.3096 0.509155 9.95704C0.267059 9.71259 0.292103 9.29704 0.567591 9.01185L1.74468 7.75704C1.90329 7.58593 2.12034 7.48815 2.32905 7.48815C2.49601 7.48815 2.64628 7.55333 2.7548 7.65926C4.1072 9.0363 5.50969 10.4215 6.92887 11.7904C7.44645 12.2847 7.96126 12.7736 8.47328 13.257C8.49554 13.2733 8.51502 13.2923 8.53171 13.3141C8.64024 7.80593 11.2198 1.15704 12.5806 0.985928C12.6028 0.980495 12.6251 0.977779 12.6473 0.977779C12.9395 0.977779 13.3569 1.20593 14.3504 2.82741C14.893 3.70741 15.5274 4.88889 16.1202 6.11926L21.4463 0.391112C21.5047 0.334075 21.5882 0.293335 21.6717 0.293335C21.7552 0.293335 21.8386 0.334075 21.8971 0.391112L27.1648 6.06222C29.0765 2.32222 29.9029 0.977779 30.6042 0.977779C30.6209 0.977779 30.6404 0.980495 30.6626 0.985928C32.0067 1.14074 34.0186 6.55111 34.6029 11.4563C34.8033 11.4644 34.9869 11.5459 35.1122 11.6844L35.9386 12.6296C38.5933 10.12 41.198 7.53704 43.6941 4.94593C43.8026 4.83185 43.9612 4.76667 44.1282 4.76667C44.2784 4.76667 44.4287 4.81556 44.5539 4.91333C45.0548 5.28815 45.539 5.85037 45.8061 6.24148C45.9731 6.50222 45.9564 6.82815 45.7477 7.04C44.3285 8.44963 41.4234 11.2933 37.7585 14.7237L38.6184 15.7015C38.8772 15.9948 38.8438 16.443 38.5349 16.6956L38.4347 16.777C38.3012 16.8911 38.1425 16.9481 37.9672 16.9481C37.7502 16.9481 37.5498 16.8585 37.4163 16.7037L36.6232 15.7911L36.3894 15.9948L41.7155 21.7311C41.8241 21.8452 41.8241 22.0244 41.7239 22.1385L32.2237 32.4378C34.6447 34.1163 36.1306 35.0615 36.1473 35.0696C36.2225 35.1185 36.2809 35.2 36.2893 35.2815C36.2976 35.3711 36.2726 35.4607 36.2058 35.5259L36.1891 35.5504C35.588 36.1859 34.7449 36.5363 33.8266 36.5363C33.1921 36.5363 32.5576 36.3652 31.9983 36.0474C31.4056 35.7052 30.7377 35.2978 30.0198 34.8333L21.9054 43.6333C21.847 43.6985 21.7635 43.7311 21.6717 43.7311ZM34.7198 13.64C34.7254 13.64 34.7309 13.6373 34.7365 13.6319L34.7198 13.6156C34.7198 13.6264 34.7198 13.6346 34.7198 13.64Z" fill="url(#paint0_radial_1678_2172)"/> 4 | <path fill-rule="evenodd" clip-rule="evenodd" d="M22.1309 0.187378L27.0897 5.53256C29.2351 1.36886 29.8529 0.676266 30.6042 0.676266C30.6321 0.676266 30.6627 0.678982 30.6961 0.684414C31.1636 0.741451 31.5893 1.12441 32.0819 1.92293C32.4575 2.54219 32.8499 3.39775 33.2255 4.39182C33.9936 6.4696 34.5946 8.91404 34.8785 11.1955C35.0621 11.2526 35.2291 11.3503 35.346 11.4889L35.9554 12.1896C38.5266 9.7533 41.0561 7.25182 43.4604 4.74219C43.6357 4.56293 43.8778 4.46515 44.1282 4.46515C44.3453 4.46515 44.5623 4.53849 44.746 4.66886C45.2719 5.06812 45.7811 5.66293 46.065 6.07849C46.3154 6.46145 46.2737 6.94219 45.9648 7.25182C44.5707 8.63701 41.7573 11.4074 38.1843 14.74L38.8522 15.5059C39.2195 15.9296 39.1694 16.5652 38.7353 16.9237L38.6351 17.0133C38.4515 17.16 38.2177 17.2496 37.9756 17.2496L41.9493 21.5274C42.1664 21.7555 42.1664 22.1059 41.9493 22.3422L32.6913 32.3889C34.9369 33.937 36.306 34.8089 36.3144 34.817C36.473 34.9148 36.5732 35.0696 36.5982 35.2489C36.6149 35.42 36.5565 35.5992 36.4396 35.7296L36.4145 35.754C35.755 36.4548 34.8367 36.8377 33.8266 36.8377C33.1421 36.8377 32.4492 36.6503 31.8398 36.3081C31.3055 35.9985 30.7128 35.64 30.07 35.2244L22.1309 43.837C22.014 43.9592 21.847 44.0326 21.6717 44.0326C21.4964 44.0326 21.3295 43.9592 21.2126 43.837L13.165 35.1755C12.038 35.7948 10.9861 36.2755 10.0344 36.6177C8.74047 37.1392 7.63852 37.3918 6.67848 37.3918C6.53934 37.3918 6.40299 37.3864 6.26942 37.3755C6.01063 37.3511 5.78523 37.1718 5.71844 36.9192C5.66001 36.6666 5.76853 36.4059 5.99393 36.2674C6.01063 36.2511 7.78878 35.1511 10.9861 32.837L1.30228 22.4155C1.08523 22.1874 1.08523 21.837 1.30228 21.6089L6.40299 16.117C6.3529 16.0681 6.30281 16.0192 6.25272 15.9703C6.18594 15.9106 6.12194 15.8508 6.06072 15.7911L5.45965 15.2289C5.13686 14.9247 4.81963 14.6205 4.50797 14.3163C3.04704 12.9148 1.61951 11.5215 0.283808 10.1607C-0.0668136 9.81034 -0.0417687 9.20738 0.333897 8.80812L1.51933 7.54515C1.73639 7.31701 2.02857 7.18664 2.3291 7.18664C2.57955 7.18664 2.81329 7.28441 2.98026 7.45552C4.32431 8.82441 5.72679 10.2096 7.14598 11.5703C7.51329 11.9289 7.88061 12.2792 8.24793 12.6214C8.37315 10.3318 8.88239 7.74886 9.69216 5.32886C10.1096 4.11478 10.5687 3.03923 11.0195 2.22441C11.7291 0.937007 12.2049 0.725155 12.5472 0.684414C12.5806 0.678982 12.614 0.676266 12.6474 0.676266C13.1065 0.676266 13.5991 1.01034 14.6176 2.67256C15.1017 3.46293 15.6611 4.4896 16.2037 5.58145L21.2126 0.187378C21.3295 0.0651554 21.4964 -0.00817871 21.6717 -0.00817871C21.847 -0.00817871 22.014 0.0651554 22.1309 0.187378ZM16.0367 6.65701C14.7929 4.02515 13.2067 1.28738 12.6474 1.28738C12.6363 1.28738 12.6279 1.28738 12.6224 1.28738C11.5454 1.41775 8.72377 8.19701 8.849 14.0229C8.65421 13.8437 8.45663 13.659 8.25628 13.4689C7.74426 12.9908 7.22946 12.5019 6.71187 12.0022C5.34278 10.6822 3.94864 9.30515 2.5378 7.87108C2.47937 7.81404 2.40423 7.7896 2.3291 7.7896C2.21223 7.7896 2.07866 7.84664 1.97848 7.96071L0.793045 9.21552C0.63443 9.38664 0.601038 9.61478 0.734608 9.74515C2.02857 11.057 3.44775 12.4503 4.94207 13.8844C5.25373 14.1886 5.57096 14.4928 5.89376 14.797C6.08855 14.9817 6.28612 15.1691 6.48647 15.3592C6.61448 15.4787 6.7397 15.5982 6.86214 15.7177C6.99571 15.8427 7.12928 15.9676 7.26285 16.0926L1.76143 22.0163L11.9044 32.9266C8.29802 35.5503 6.31951 36.7726 6.31951 36.7726C6.43639 36.7834 6.55604 36.7889 6.67848 36.7889C7.58008 36.7889 8.63194 36.5281 9.80903 36.0555C10.8943 35.6644 12.0547 35.1103 13.2902 34.4096L21.6717 43.4296L29.9614 34.434C30.7545 34.9555 31.4891 35.4037 32.157 35.7866C32.6829 36.0881 33.2589 36.2348 33.8266 36.2348C34.628 36.2348 35.4044 35.9333 35.9554 35.3466C35.9665 35.3412 35.9749 35.3331 35.9804 35.3222C35.9804 35.3222 34.3859 34.3118 31.7646 32.4866L41.4902 21.9348L35.9554 15.9785C36.1836 15.7666 36.4145 15.5575 36.6483 15.3511L37.6501 16.5081C37.7335 16.5977 37.8504 16.6466 37.9673 16.6466C38.0591 16.6466 38.1593 16.614 38.2344 16.5489L38.3346 16.4674C38.5099 16.3207 38.5266 16.0681 38.3847 15.897L37.3412 14.6992C41.0978 11.1955 44.0865 8.26219 45.5224 6.82812C45.6309 6.72219 45.6392 6.55108 45.5474 6.41256C45.2886 6.0296 44.8211 5.49182 44.362 5.1496C44.2952 5.09256 44.2117 5.06812 44.1282 5.06812C44.0531 5.06812 43.9696 5.10071 43.9195 5.15775C41.2147 7.96886 38.535 10.6089 35.9137 13.0696L34.8785 11.88C34.8033 11.7985 34.6865 11.7577 34.5696 11.7577C34.4861 11.7577 34.4026 11.7822 34.3275 11.8229C33.7765 6.50219 31.6227 1.40145 30.6293 1.28738C30.6182 1.28738 30.6098 1.28738 30.6042 1.28738C29.9781 1.27923 28.6675 3.78071 27.2399 6.59182L21.6717 0.594785L16.0367 6.65701ZM34.3943 14.2918C34.4193 13.8029 34.4193 13.3059 34.411 12.7926L35.1623 13.6563C34.9174 13.8844 34.6726 14.1098 34.4277 14.3326L34.3943 14.2918Z" fill="white"/> 5 | <path d="M21.6718 0.594727L1.76147 22.0162L21.6718 43.4295L41.4902 21.9347L21.6718 0.594727Z" fill="url(#paint1_linear_1678_2172)"/> 6 | <path d="M21.6718 1.31177L2.42102 22.0162L21.6718 42.7125L40.8308 21.9347L21.6718 1.31177Z" fill="url(#paint2_linear_1678_2172)"/> 7 | <path d="M21.6634 2.77026L3.77332 22.0162L21.6634 41.254L39.4783 21.9429L21.6634 2.77026Z" fill="url(#paint3_radial_1678_2172)"/> 8 | <path d="M6.31116 36.7725C6.31116 36.7725 17.4977 29.8548 35.3209 13.4933L36.6399 15.0007C25.5369 25.1614 12.2467 37.2533 6.31116 36.7725Z" fill="url(#paint4_linear_1678_2172)"/> 9 | <path d="M44.3453 5.14958C44.8044 5.49181 45.2719 6.02958 45.5307 6.41255C45.6225 6.55106 45.6142 6.72218 45.5056 6.8281C44.0614 8.26218 41.0561 11.22 37.266 14.7481L35.8385 13.1185C38.4765 10.6414 41.1813 7.98514 43.9028 5.15773C44.0113 5.04366 44.2033 5.03551 44.3453 5.14958Z" fill="url(#paint5_linear_1678_2172)"/> 10 | <path d="M36.1223 14.5607L36.7317 15.2614C26.6555 24.4525 15.6944 34.5481 8.74878 36.3814C21.63 29.5207 36.1223 14.5607 36.1223 14.5607Z" fill="#F7F7F7"/> 11 | <path d="M34.1355 12.4911L37.6334 16.5C37.7837 16.6711 38.0425 16.6955 38.2178 16.5489L38.3179 16.4674C38.4933 16.3207 38.5099 16.0681 38.368 15.897L34.8618 11.8881C34.7115 11.717 34.4528 11.6926 34.2774 11.8392L34.1773 11.9207C34.002 12.0674 33.9853 12.32 34.1355 12.4911Z" fill="url(#paint6_linear_1678_2172)"/> 12 | <path d="M37.5499 13.0859L38.1259 13.1347C38.2011 13.1347 38.2595 13.0859 38.2679 13.0125L38.3096 12.4503C38.318 12.3851 38.2679 12.3199 38.1927 12.3199L37.6167 12.271C37.5499 12.2629 37.4831 12.3199 37.4748 12.3851L37.433 12.9473C37.4247 13.0207 37.4831 13.0777 37.5499 13.0859Z" fill="url(#paint7_linear_1678_2172)"/> 13 | <path d="M38.7854 11.9532L39.3614 12.0021C39.4365 12.0021 39.495 11.9532 39.5033 11.8799L39.5451 11.3258C39.5534 11.2525 39.5033 11.1955 39.4282 11.1873L38.8522 11.1384C38.7854 11.1384 38.7186 11.1873 38.7186 11.2606L38.6685 11.8147C38.6602 11.8881 38.7186 11.9532 38.7854 11.9532Z" fill="url(#paint8_linear_1678_2172)"/> 14 | <path d="M39.9958 10.7963L40.5719 10.837C40.647 10.8452 40.7054 10.7963 40.7138 10.723L40.7555 10.1608C40.7639 10.0956 40.7138 10.0304 40.6386 10.0222L40.0626 9.98149C39.9958 9.97334 39.9291 10.0304 39.9291 10.0956L39.879 10.6578C39.8706 10.7311 39.9291 10.7882 39.9958 10.7963Z" fill="url(#paint9_linear_1678_2172)"/> 15 | <path d="M41.0895 9.73698L41.6655 9.77772C41.7323 9.78587 41.7991 9.73698 41.8074 9.66365L41.8491 9.10142C41.8575 9.03624 41.7991 8.97105 41.7323 8.96291L41.1562 8.92217C41.0811 8.91402 41.0227 8.97105 41.0143 9.03624L40.9726 9.59846C40.9642 9.6718 41.0143 9.72883 41.0895 9.73698Z" fill="url(#paint10_linear_1678_2172)"/> 16 | <path d="M42.2833 8.56362L42.8593 8.60437C42.9345 8.61251 42.9929 8.55548 43.0013 8.49029L43.043 7.92807C43.0513 7.85474 43.0013 7.7977 42.9261 7.78955L42.3501 7.74881C42.2833 7.74066 42.2165 7.78955 42.2165 7.86288L42.1664 8.42511C42.1581 8.49029 42.2165 8.55548 42.2833 8.56362Z" fill="url(#paint11_linear_1678_2172)"/> 17 | <path d="M43.427 7.5451L44.0113 7.5288C44.0781 7.5288 44.1365 7.47177 44.1365 7.39843L44.1198 6.83621C44.1198 6.77103 44.0614 6.71399 43.9863 6.71399L43.4103 6.73029C43.3435 6.73029 43.285 6.78732 43.285 6.86066L43.3017 7.42288C43.3017 7.48806 43.3602 7.5451 43.427 7.5451Z" fill="url(#paint12_linear_1678_2172)"/> 18 | <path d="M35.9721 35.3222C35.9665 35.3331 35.9582 35.3412 35.947 35.3466C35.0037 36.3407 33.4259 36.52 32.1486 35.7866C26.7474 32.6985 16.5042 24.5503 9.51683 18.1785C9.15508 17.8471 8.79611 17.5158 8.43992 17.1844C8.23957 16.9997 8.03921 16.815 7.83886 16.6303C7.71085 16.5108 7.58285 16.3913 7.45484 16.2718C7.25449 16.0871 7.05691 15.9024 6.86212 15.7177C6.73412 15.5982 6.60611 15.4787 6.47811 15.3592C6.27775 15.1691 6.08018 14.9817 5.88539 14.797C5.5626 14.4928 5.24537 14.1886 4.9337 13.8844C3.43939 12.4503 2.02021 11.057 0.726244 9.74516C0.601022 9.61479 0.626066 9.38664 0.784681 9.21553L1.97012 7.96071C2.13708 7.7733 2.39587 7.73256 2.52944 7.87108C3.94028 9.30516 5.33441 10.6822 6.70351 12.0022C7.22109 12.5019 7.73589 12.9908 8.24791 13.4689C8.44827 13.659 8.64862 13.8464 8.84898 14.0311C8.97698 14.1506 9.10499 14.2701 9.233 14.3896C9.43335 14.5743 9.6337 14.759 9.83406 14.9437C9.96206 15.0632 10.0901 15.1827 10.2181 15.3022C10.4184 15.4869 10.6216 15.6716 10.8275 15.8563C10.9833 15.9975 11.1419 16.1415 11.3033 16.2881C23.8673 27.6466 35.9721 35.3222 35.9721 35.3222Z" fill="url(#paint13_linear_1678_2172)"/> 19 | <path d="M6.70352 12.0022C7.2211 12.502 7.7359 12.9908 8.24792 13.4689C8.44828 13.659 8.64864 13.8464 8.84899 14.0311C8.977 14.1506 9.105 14.2701 9.23301 14.3896C9.43336 14.5743 9.63371 14.759 9.83407 14.9437C9.96207 15.0632 10.0901 15.1827 10.2181 15.3022C10.4184 15.4869 10.6216 15.6716 10.8275 15.8563C10.9833 15.9975 11.1419 16.1415 11.3033 16.2881L9.51684 18.1785C9.15509 17.8471 8.79612 17.5158 8.43993 17.1844C8.23958 16.9997 8.03922 16.815 7.83887 16.6303C7.71086 16.5108 7.58286 16.3913 7.45485 16.2718C7.2545 16.0871 7.05693 15.9024 6.86214 15.7178C6.73413 15.5982 6.60613 15.4787 6.47812 15.3592C6.27777 15.1691 6.08019 14.9817 5.8854 14.797C5.56261 14.4928 5.24538 14.1886 4.93372 13.8844L6.70352 12.0022Z" fill="url(#paint14_linear_1678_2172)"/> 20 | <path d="M10.2181 15.3022C10.4184 15.4869 10.6216 15.6716 10.8275 15.8563L8.43993 17.1845C8.23958 16.9998 8.03922 16.8151 7.83887 16.6304L10.2181 15.3022Z" fill="url(#paint15_linear_1678_2172)"/> 21 | <path d="M9.23305 14.3896C9.43341 14.5743 9.63376 14.759 9.83412 14.9437L7.4549 16.2719C7.25454 16.0872 7.05697 15.9025 6.86218 15.7178L9.23305 14.3896Z" fill="url(#paint16_linear_1678_2172)"/> 22 | <path d="M8.2479 13.4689C8.44825 13.659 8.64861 13.8464 8.84896 14.0311L6.47809 15.3592C6.27774 15.1691 6.08017 14.9817 5.88538 14.797L8.2479 13.4689Z" fill="url(#paint17_linear_1678_2172)"/> 23 | <path d="M18.3158 11.7495C18.3158 11.7495 13.8913 1.15696 12.6224 1.28733C11.3535 1.4177 8.39822 9.09325 8.88241 14.8377C9.05772 16.997 9.56696 18.8303 9.56696 18.8303L18.3158 11.7495Z" fill="url(#paint18_linear_1678_2172)"/> 24 | <path d="M24.9275 11.7495C24.9275 11.7495 29.352 1.15696 30.6209 1.28733C31.8898 1.4177 34.8451 9.09325 34.3609 14.8377C34.1856 16.997 33.6763 18.8303 33.6763 18.8303L24.9275 11.7495Z" fill="url(#paint19_linear_1678_2172)"/> 25 | <path d="M26.9812 12.5236C26.9812 12.5236 29.7611 3.49548 30.3789 3.49548C30.4791 3.49548 30.621 4.52215 30.7546 4.68511C30.8297 4.78289 31.2221 4.09845 31.3139 4.24511C32.3324 6.02956 33.3592 11.1059 33.1505 14.0473C33.0336 15.6607 32.6579 16.614 32.6579 16.614L26.9812 12.5236Z" fill="url(#paint20_linear_1678_2172)"/> 26 | <path d="M16.2705 12.5236C16.2705 12.5236 13.4906 3.49548 12.8728 3.49548C12.7643 3.49548 12.6224 4.52215 12.4972 4.68511C12.4137 4.78289 12.0213 4.09845 11.9378 4.24511C10.911 6.02956 9.88421 11.1059 10.0929 14.0473C10.2098 15.6607 10.5938 16.614 10.5938 16.614L16.2705 12.5236Z" fill="url(#paint21_linear_1678_2172)"/> 27 | <path d="M34.3359 21.5762C34.3359 24.1347 34.1689 25.9762 33.8767 27.2962C33.7098 28.0784 33.4927 28.6732 33.2423 29.1376C33.0085 29.5695 32.7414 29.8873 32.4492 30.1154C31.9817 30.4821 31.4474 30.6288 30.8798 30.7021C30.7072 30.7293 30.5347 30.7618 30.3622 30.7999C28.5256 31.2154 26.5554 32.5191 25.9961 33.5458C25.3867 34.6702 21.9222 35.8599 21.6217 35.8599C21.3211 35.8599 17.8567 34.6702 17.2473 33.5458C16.6879 32.5191 14.7178 31.2154 12.8812 30.7999C12.7087 30.7618 12.5361 30.7293 12.3636 30.7021C11.7959 30.6288 11.2616 30.4821 10.7941 30.1154C10.502 29.8873 10.2348 29.5695 10.0011 29.1376C9.75063 28.6732 9.53358 28.0784 9.36662 27.2962C9.07443 25.9762 8.90747 24.1347 8.90747 21.5762C8.90747 13.8354 16.2956 9.72876 21.6217 9.72876C26.9478 9.72876 34.3359 13.8354 34.3359 21.5762Z" fill="url(#paint22_linear_1678_2172)"/> 28 | <path d="M15.6193 29.1703C15.5609 29.1459 14.3421 28.6733 12.6307 28.934C11.4703 29.1052 10.6605 29.1948 10.001 29.1377C9.75059 28.6733 9.53354 28.0785 9.36658 27.2963C9.67546 27.4674 10.1763 27.6874 10.8776 27.7852C12.1549 27.9726 14.125 27.8422 15.6193 29.1703Z" fill="url(#paint23_linear_1678_2172)"/> 29 | <path d="M15.0017 30.4414C15.0017 30.4414 14.1668 30.3029 13.14 30.7021C13.051 30.7347 12.9647 30.7673 12.8812 30.7999C12.7087 30.7619 12.5362 30.7293 12.3636 30.7021C11.796 30.6288 11.2617 30.4821 10.7942 30.1155C10.9945 30.1888 11.3786 30.2784 11.9045 30.2458C12.7143 30.1806 13.8913 29.8384 15.0017 30.4414Z" fill="url(#paint24_linear_1678_2172)"/> 30 | <path d="M10.5353 19.9221C10.5353 19.9221 10.7357 21.7555 13.0481 22.6436C15.3522 23.5399 17.8733 24.5095 18.6998 26.8236C19.5346 29.1458 19.2424 30.6858 19.2424 30.6858C19.2424 30.6858 19.2758 28.6977 17.3808 27.8992C16.2788 27.4347 12.2968 27.2962 10.8442 24.0125C10.1763 22.5214 10.5353 19.9221 10.5353 19.9221Z" fill="url(#paint25_linear_1678_2172)"/> 31 | <path d="M11.5706 22.334C11.5706 22.334 12.0881 22.9695 14.5425 23.7355C16.9885 24.5014 19.1173 25.6503 19.2425 29.4473C19.2425 29.4473 19.0839 28.2007 16.5043 27.6629C13.9247 27.1169 12.0631 24.8844 11.5706 22.334Z" fill="url(#paint26_linear_1678_2172)"/> 32 | <path d="M21.6217 32.8777C19.9437 32.9266 19.71 33.5458 19.8269 33.9125C19.9437 34.2873 21.1542 35.2488 21.6217 35.2488C22.0892 35.2488 23.2997 34.2873 23.4166 33.9125C23.5334 33.5458 23.2997 32.9266 21.6217 32.8777Z" fill="url(#paint27_linear_1678_2172)"/> 33 | <path d="M33.8768 27.2963C33.7098 28.0785 33.4928 28.6733 33.2423 29.1377C32.5828 29.1948 31.773 29.1052 30.6127 28.934C28.9013 28.6733 27.6825 29.1459 27.624 29.1703C29.1183 27.8422 31.0885 27.9726 32.3658 27.7852C33.0587 27.6874 33.5679 27.4674 33.8768 27.2963Z" fill="url(#paint28_linear_1678_2172)"/> 34 | <path d="M32.4492 30.1155C31.9817 30.4821 31.4474 30.6288 30.8797 30.7021C30.7072 30.7293 30.5347 30.7619 30.3621 30.7999C30.2786 30.7673 30.1924 30.7347 30.1033 30.7021C29.0682 30.3029 28.2417 30.4414 28.2417 30.4414C29.352 29.8384 30.5291 30.1806 31.3389 30.2458C31.8648 30.2784 32.2488 30.1888 32.4492 30.1155Z" fill="url(#paint29_linear_1678_2172)"/> 35 | <path d="M32.7079 19.9221C32.7079 19.9221 32.5076 21.7555 30.1952 22.6436C27.8911 23.5399 25.3699 24.5095 24.5435 26.8236C23.7086 29.1458 24.0008 30.6858 24.0008 30.6858C24.0008 30.6858 23.9674 28.6977 25.8625 27.8992C26.9644 27.4347 30.9465 27.2962 32.3991 24.0125C33.0669 22.5214 32.7079 19.9221 32.7079 19.9221Z" fill="url(#paint30_linear_1678_2172)"/> 36 | <path d="M31.6728 22.334C31.6728 22.334 31.1552 22.9695 28.7009 23.7355C26.2548 24.5014 24.1261 25.6503 24.0009 29.4473C24.0009 29.4473 24.1595 28.2007 26.739 27.6629C29.3186 27.1169 31.1803 24.8844 31.6728 22.334Z" fill="url(#paint31_linear_1678_2172)"/> 37 | <path d="M16.4541 13.5991C16.4541 13.5991 16.4625 13.5421 16.4959 13.4199C16.5126 13.371 16.5376 13.2976 16.5793 13.2162C16.6211 13.1428 16.6795 13.0532 16.7714 12.9717C16.8548 12.8984 16.9717 12.8251 17.122 12.8006C17.1971 12.7843 17.2722 12.7843 17.3557 12.7925L17.4058 12.8006C17.4281 12.806 17.4503 12.8115 17.4726 12.8169C17.5143 12.8251 17.5561 12.8414 17.5978 12.8739C17.6396 12.8984 17.6813 12.931 17.7063 12.9799C17.7397 13.0206 17.7481 13.0695 17.7564 13.1265C17.7731 13.2243 17.7564 13.3221 17.7314 13.4117C17.6813 13.591 17.5895 13.7539 17.4809 13.9251C17.3808 14.088 17.2555 14.2591 17.1387 14.4221C17.0218 14.5851 16.9133 14.7562 16.8298 14.9436C16.7407 15.1337 16.6712 15.3347 16.6211 15.5465C16.5793 15.7584 16.546 15.9784 16.5376 16.2065C16.5209 16.6547 16.596 17.1273 16.7213 17.5917L16.7714 17.7628L16.8298 17.9421L16.8882 18.1213L16.955 18.2843C16.9968 18.3984 17.0468 18.5125 17.0969 18.6184C17.147 18.7325 17.2055 18.8384 17.2639 18.9525C17.4976 19.3843 17.7898 19.7754 18.1238 20.1339C18.4577 20.4925 18.825 20.8184 19.1923 21.128C19.2814 21.2041 19.3704 21.2801 19.4595 21.3562C19.5596 21.4458 19.6348 21.511 19.7182 21.6088C19.7628 21.6522 19.8045 21.6984 19.8435 21.7473C19.8824 21.7907 19.9214 21.8342 19.9603 21.8776C20.0355 21.9673 20.0939 22.0651 20.1607 22.1628C20.4111 22.5376 20.5781 22.9288 20.695 23.3036C20.8119 23.6702 20.8703 24.0206 20.8953 24.3302C20.9204 24.4851 20.9204 24.6317 20.9204 24.7702C20.9204 24.906 20.9204 25.0283 20.9204 25.1369C20.9037 25.3569 20.8953 25.5362 20.8703 25.6502C20.8619 25.7725 20.8536 25.8295 20.8536 25.8295C20.8536 25.8295 20.8536 25.7725 20.8536 25.6502C20.8536 25.5932 20.8536 25.5199 20.8536 25.4302C20.848 25.3488 20.8425 25.251 20.8369 25.1369C20.8313 25.0283 20.8202 24.9088 20.8035 24.7784C20.7868 24.648 20.7785 24.5013 20.7451 24.3547C20.6866 24.0532 20.6032 23.7191 20.4696 23.3769C20.336 23.0265 20.1524 22.668 19.9103 22.3258C19.8435 22.2443 19.785 22.1547 19.7099 22.0732C19.6709 22.0352 19.6348 21.9944 19.6014 21.951C19.5624 21.9184 19.5235 21.8831 19.4845 21.8451L19.4261 21.788L19.3593 21.731C19.3203 21.693 19.2786 21.6549 19.2341 21.6169C19.145 21.5409 19.0532 21.4648 18.9586 21.3888C18.5829 21.0873 18.1905 20.7695 17.8316 20.3947C17.4809 20.0199 17.1554 19.5962 16.9049 19.1317C16.8465 19.0176 16.7797 18.9036 16.7296 18.7814C16.6795 18.6673 16.6211 18.5451 16.5793 18.4228L16.5126 18.2354L16.4541 18.0562L16.3957 17.8769L16.3456 17.6895C16.212 17.1925 16.1536 16.6791 16.1786 16.1902C16.1953 15.9376 16.2371 15.7013 16.2955 15.4651C16.3623 15.2369 16.4541 15.0169 16.5543 14.8132C16.6628 14.6176 16.7881 14.4302 16.9216 14.2591C17.0552 14.1043 17.1804 13.9576 17.2889 13.8028C17.3975 13.648 17.4893 13.5013 17.5477 13.3547C17.5728 13.2813 17.5895 13.208 17.5895 13.1428C17.5839 13.0776 17.5589 13.0288 17.5143 12.9962C17.4893 12.9799 17.4559 12.9636 17.4309 12.9473L17.3808 12.9391L17.3307 12.9228C17.2639 12.9147 17.1971 12.9065 17.1387 12.9147C17.0135 12.9228 16.9049 12.9717 16.8214 13.0369C16.738 13.0939 16.6712 13.1754 16.6211 13.2406C16.571 13.3139 16.546 13.3791 16.5209 13.428C16.4708 13.5421 16.4541 13.5991 16.4541 13.5991Z" fill="url(#paint32_linear_1678_2172)"/> 38 | <path d="M20.4195 19.6776C20.4195 19.6776 18.8333 19.2947 18.107 17.551C17.698 16.5895 17.9735 15.9458 18.441 15.9539C18.9085 15.9621 18.9001 16.3939 18.9252 17.0621C18.9669 18.3087 19.7015 19.2458 20.4195 19.6776Z" fill="url(#paint33_linear_1678_2172)"/> 39 | <path d="M26.7891 13.5991C26.7891 13.5991 26.7724 13.5421 26.7223 13.428C26.6973 13.3791 26.6723 13.3139 26.6222 13.2406C26.5721 13.1754 26.5053 13.0939 26.4218 13.0369C26.3383 12.9717 26.2298 12.9228 26.1046 12.9147C26.0461 12.9065 25.9794 12.9147 25.9126 12.9228L25.8625 12.9391L25.8124 12.9473C25.7874 12.9636 25.754 12.9799 25.7289 12.9962C25.6844 13.0288 25.6593 13.0776 25.6538 13.1428C25.6538 13.208 25.6705 13.2813 25.6955 13.3547C25.754 13.5013 25.8458 13.648 25.9543 13.8028C26.0628 13.9576 26.1881 14.1043 26.3216 14.2591C26.4552 14.4302 26.5804 14.6176 26.689 14.8132C26.7891 15.0169 26.881 15.2369 26.9477 15.4651C27.0062 15.7013 27.0479 15.9376 27.0646 16.1902C27.0897 16.6791 27.0312 17.1925 26.8977 17.6895L26.8476 17.8769L26.7891 18.0562L26.7307 18.2354L26.6639 18.4228C26.6222 18.5451 26.5637 18.6673 26.5136 18.7814C26.4635 18.9036 26.3968 19.0176 26.3383 19.1317C26.0879 19.5962 25.7623 20.0199 25.4117 20.3947C25.0527 20.7695 24.6604 21.0873 24.2847 21.3888C24.1901 21.4648 24.0982 21.5409 24.0092 21.6169C23.9647 21.6549 23.9229 21.693 23.884 21.731L23.8172 21.788L23.7588 21.8451C23.7198 21.8831 23.6808 21.9184 23.6419 21.951C23.6085 21.9944 23.5723 22.0352 23.5334 22.0732C23.4582 22.1547 23.3998 22.2443 23.333 22.3258C23.0909 22.668 22.9072 23.0265 22.7737 23.3769C22.6401 23.7191 22.5566 24.0532 22.4982 24.3547C22.4648 24.5013 22.4564 24.648 22.4397 24.7784C22.4231 24.9088 22.4119 25.0283 22.4064 25.1369C22.4008 25.251 22.3952 25.3488 22.3897 25.4302C22.3897 25.5199 22.3897 25.5932 22.3897 25.6502C22.3897 25.7725 22.3897 25.8295 22.3897 25.8295C22.3897 25.8295 22.3813 25.7725 22.373 25.6502C22.3479 25.5362 22.3396 25.3569 22.3229 25.1369C22.3229 25.0283 22.3229 24.906 22.3229 24.7702C22.3229 24.6317 22.3229 24.4851 22.3479 24.3302C22.373 24.0206 22.4314 23.6702 22.5483 23.3036C22.6652 22.9288 22.8321 22.5376 23.0826 22.1628C23.1493 22.0651 23.2078 21.9673 23.2829 21.8776C23.3219 21.8342 23.3608 21.7907 23.3998 21.7473C23.4387 21.6984 23.4805 21.6522 23.525 21.6088C23.6085 21.511 23.6836 21.4458 23.7838 21.3562C23.8728 21.2801 23.9619 21.2041 24.0509 21.128C24.4183 20.8184 24.7856 20.4925 25.1195 20.1339C25.4534 19.7754 25.7456 19.3843 25.9794 18.9525C26.0378 18.8384 26.0962 18.7325 26.1463 18.6184C26.1964 18.5125 26.2465 18.3984 26.2882 18.2843L26.355 18.1213L26.4135 17.9421L26.4719 17.7628L26.522 17.5917C26.6472 17.1273 26.7223 16.6547 26.7056 16.2065C26.6973 15.9784 26.6639 15.7584 26.6222 15.5465C26.5721 15.3347 26.5025 15.1337 26.4135 14.9436C26.33 14.7562 26.2215 14.5851 26.1046 14.4221C25.9877 14.2591 25.8625 14.088 25.7623 13.9251C25.6538 13.7539 25.562 13.591 25.5119 13.4117C25.4868 13.3221 25.4701 13.2243 25.4868 13.1265C25.4952 13.0695 25.5035 13.0206 25.5369 12.9799C25.562 12.931 25.6037 12.8984 25.6454 12.8739C25.6872 12.8414 25.7289 12.8251 25.7707 12.8169C25.7929 12.8115 25.8152 12.806 25.8374 12.8006L25.8875 12.7925C25.971 12.7843 26.0461 12.7843 26.1213 12.8006C26.2715 12.8251 26.3884 12.8984 26.4719 12.9717C26.5637 13.0532 26.6222 13.1428 26.6639 13.2162C26.7056 13.2976 26.7307 13.371 26.7474 13.4199C26.7808 13.5421 26.7891 13.5991 26.7891 13.5991Z" fill="url(#paint34_linear_1678_2172)"/> 40 | <path d="M22.974 15.351C22.8738 14.528 21.8887 13.8354 21.6216 12.8495C21.3544 13.8354 20.3694 14.528 20.2692 15.351C20.1607 16.1821 21.6216 19.9547 21.6216 19.9547C21.6216 19.9547 23.0825 16.1821 22.974 15.351Z" fill="url(#paint35_linear_1678_2172)"/> 41 | <path d="M22.8237 19.6776C22.8237 19.6776 24.4099 19.2947 25.1362 17.551C25.5452 16.5895 25.2697 15.9458 24.8022 15.9539C24.3347 15.9621 24.3431 16.3939 24.318 17.0621C24.2763 18.3087 23.5417 19.2458 22.8237 19.6776Z" fill="url(#paint36_linear_1678_2172)"/> 42 | <path d="M27.3401 21.3725C27.3401 21.3725 28.2751 21.3969 28.6007 20.7125C28.8845 20.1013 28.25 20.191 28.3085 19.2539C28.3753 18.325 29.569 18.0643 30.1785 18.8954C30.7879 19.7184 30.2118 20.908 28.9596 21.2828C28.0079 21.5762 27.3401 21.3725 27.3401 21.3725Z" fill="url(#paint37_linear_1678_2172)"/> 43 | <path d="M26.2799 22.4969C26.33 22.7087 26.547 22.8472 26.7641 22.7984C26.9895 22.7495 27.1231 22.5376 27.073 22.3258C27.0229 22.1058 26.8058 21.9754 26.5888 22.0243C26.3634 22.0732 26.2298 22.285 26.2799 22.4969Z" fill="url(#paint38_linear_1678_2172)"/> 44 | <path d="M25.2615 23.2954C25.3032 23.4665 25.4786 23.5724 25.6455 23.5398C25.8208 23.4991 25.9293 23.328 25.8876 23.1569C25.8459 22.9858 25.6789 22.8798 25.5036 22.9206C25.3283 22.9532 25.2198 23.1243 25.2615 23.2954Z" fill="url(#paint39_linear_1678_2172)"/> 45 | <path d="M24.5269 24.2651C24.5519 24.371 24.6604 24.4362 24.7606 24.4117C24.8608 24.3873 24.9276 24.2895 24.9025 24.1836C24.8775 24.0858 24.7773 24.0206 24.6771 24.0451C24.5686 24.0614 24.5102 24.1673 24.5269 24.2651Z" fill="url(#paint40_linear_1678_2172)"/> 46 | <path d="M23.9925 25.1613C24.0092 25.2346 24.076 25.2835 24.1512 25.2672C24.2263 25.2509 24.268 25.1776 24.2513 25.1042C24.2346 25.039 24.1595 24.9902 24.0927 25.0065C24.0176 25.0228 23.9758 25.0961 23.9925 25.1613Z" fill="url(#paint41_linear_1678_2172)"/> 47 | <path d="M15.9032 21.3725C15.9032 21.3725 14.9682 21.3969 14.6427 20.7125C14.3588 20.1013 14.9933 20.191 14.9348 19.2539C14.8681 18.325 13.6743 18.0643 13.0649 18.8954C12.4554 19.7184 13.0315 20.908 14.2837 21.2828C15.2354 21.5762 15.9032 21.3725 15.9032 21.3725Z" fill="url(#paint42_linear_1678_2172)"/> 48 | <path d="M16.9635 22.4969C16.9134 22.7087 16.6963 22.8472 16.4793 22.7984C16.2539 22.7495 16.1203 22.5376 16.1704 22.3258C16.2205 22.1058 16.4375 21.9754 16.6546 22.0243C16.88 22.0732 17.0136 22.285 16.9635 22.4969Z" fill="url(#paint43_linear_1678_2172)"/> 49 | <path d="M17.982 23.2954C17.9402 23.4665 17.7649 23.5724 17.598 23.5398C17.4226 23.4991 17.3141 23.328 17.3559 23.1569C17.3976 22.9858 17.5646 22.8798 17.7399 22.9206C17.9152 22.9532 18.0237 23.1243 17.982 23.2954Z" fill="url(#paint44_linear_1678_2172)"/> 50 | <path d="M18.7166 24.2651C18.6916 24.371 18.5831 24.4362 18.4829 24.4117C18.3827 24.3873 18.3159 24.2895 18.341 24.1836C18.366 24.0858 18.4662 24.0206 18.5664 24.0451C18.6749 24.0614 18.7333 24.1673 18.7166 24.2651Z" fill="url(#paint45_linear_1678_2172)"/> 51 | <path d="M19.2509 25.1613C19.2342 25.2346 19.1674 25.2835 19.0922 25.2672C19.0171 25.2509 18.9754 25.1776 18.9921 25.1042C19.0088 25.039 19.0839 24.9902 19.1507 25.0065C19.2258 25.0228 19.2675 25.0961 19.2509 25.1613Z" fill="url(#paint46_linear_1678_2172)"/> 52 | </g> 53 | <defs> 54 | <radialGradient id="paint0_radial_1678_2172" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(23.1313 22.0128) scale(22.5212 21.9817)"> 55 | <stop offset="0.767" stop-color="#F23434"/> 56 | <stop offset="1" stop-color="#FF5956"/> 57 | </radialGradient> 58 | <linearGradient id="paint1_linear_1678_2172" x1="1.7583" y1="0.596437" x2="41.4904" y2="0.596437" gradientUnits="userSpaceOnUse"> 59 | <stop offset="0.024" stop-color="#B839E2"/> 60 | <stop offset="0.499" stop-color="#F79800"/> 61 | <stop offset="1" stop-color="#B70D22"/> 62 | </linearGradient> 63 | <linearGradient id="paint2_linear_1678_2172" x1="70.6194" y1="17.7621" x2="20.2349" y2="69.3833" gradientUnits="userSpaceOnUse"> 64 | <stop stop-color="#FFDB2F"/> 65 | <stop offset="0.49" stop-color="#F79800"/> 66 | <stop offset="1" stop-color="#FFDB2F"/> 67 | </linearGradient> 68 | <radialGradient id="paint3_radial_1678_2172" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.6243 22.0128) scale(21.5761 21.0592)"> 69 | <stop stop-color="#210601"/> 70 | <stop offset="1" stop-color="#B70D22"/> 71 | </radialGradient> 72 | <linearGradient id="paint4_linear_1678_2172" x1="1.7777" y1="20.2267" x2="9.03263" y2="15.2518" gradientUnits="userSpaceOnUse"> 73 | <stop offset="0.204" stop-color="#CCCCCC"/> 74 | <stop offset="1" stop-color="white"/> 75 | </linearGradient> 76 | <linearGradient id="paint5_linear_1678_2172" x1="35.2325" y1="4.45895" x2="45.4885" y2="5.1955" gradientUnits="userSpaceOnUse"> 77 | <stop offset="0.024" stop-color="#B70D22"/> 78 | <stop offset="1" stop-color="#F79800"/> 79 | </linearGradient> 80 | <linearGradient id="paint6_linear_1678_2172" x1="30.8985" y1="13.9087" x2="37.6704" y2="7.75603" gradientUnits="userSpaceOnUse"> 81 | <stop offset="0.024" stop-color="#B70D22"/> 82 | <stop offset="1" stop-color="#F79800"/> 83 | </linearGradient> 84 | <linearGradient id="paint7_linear_1678_2172" x1="37.432" y1="12.2721" x2="38.3125" y2="12.2721" gradientUnits="userSpaceOnUse"> 85 | <stop stop-color="#FFDB2F"/> 86 | <stop offset="0.993" stop-color="#F79800"/> 87 | </linearGradient> 88 | <linearGradient id="paint8_linear_1678_2172" x1="38.6687" y1="11.1411" x2="39.5492" y2="11.1411" gradientUnits="userSpaceOnUse"> 89 | <stop stop-color="#FFDB2F"/> 90 | <stop offset="0.993" stop-color="#F79800"/> 91 | </linearGradient> 92 | <linearGradient id="paint9_linear_1678_2172" x1="39.8795" y1="9.9806" x2="40.7599" y2="9.9806" gradientUnits="userSpaceOnUse"> 93 | <stop stop-color="#FFDB2F"/> 94 | <stop offset="0.993" stop-color="#F79800"/> 95 | </linearGradient> 96 | <linearGradient id="paint10_linear_1678_2172" x1="40.969" y1="8.92078" x2="41.8495" y2="8.92078" gradientUnits="userSpaceOnUse"> 97 | <stop stop-color="#FFDB2F"/> 98 | <stop offset="0.993" stop-color="#F79800"/> 99 | </linearGradient> 100 | <linearGradient id="paint11_linear_1678_2172" x1="42.167" y1="7.74539" x2="43.0475" y2="7.74539" gradientUnits="userSpaceOnUse"> 101 | <stop stop-color="#FFDB2F"/> 102 | <stop offset="0.993" stop-color="#F79800"/> 103 | </linearGradient> 104 | <linearGradient id="paint12_linear_1678_2172" x1="43.285" y1="6.71562" x2="44.1343" y2="6.71562" gradientUnits="userSpaceOnUse"> 105 | <stop stop-color="#FFDB2F"/> 106 | <stop offset="0.993" stop-color="#F79800"/> 107 | </linearGradient> 108 | <linearGradient id="paint13_linear_1678_2172" x1="10.8509" y1="-7.82706" x2="49.1059" y2="24.3753" gradientUnits="userSpaceOnUse"> 109 | <stop offset="0.024" stop-color="#B70D22"/> 110 | <stop offset="0.979" stop-color="#FF5956"/> 111 | </linearGradient> 112 | <linearGradient id="paint14_linear_1678_2172" x1="8.08706" y1="20.8174" x2="3.282" y2="16.5391" gradientUnits="userSpaceOnUse"> 113 | <stop stop-color="#210601"/> 114 | <stop offset="1" stop-color="#6A1705"/> 115 | </linearGradient> 116 | <linearGradient id="paint15_linear_1678_2172" x1="7.83912" y1="15.2989" x2="10.8235" y2="15.2989" gradientUnits="userSpaceOnUse"> 117 | <stop stop-color="#FFDB2F"/> 118 | <stop offset="0.993" stop-color="#F79800"/> 119 | </linearGradient> 120 | <linearGradient id="paint16_linear_1678_2172" x1="6.85801" y1="14.3895" x2="9.83019" y2="14.3895" gradientUnits="userSpaceOnUse"> 121 | <stop stop-color="#FFDB2F"/> 122 | <stop offset="0.993" stop-color="#F79800"/> 123 | </linearGradient> 124 | <linearGradient id="paint17_linear_1678_2172" x1="5.88538" y1="13.4727" x2="8.84679" y2="13.4727" gradientUnits="userSpaceOnUse"> 125 | <stop stop-color="#FFDB2F"/> 126 | <stop offset="0.993" stop-color="#F79800"/> 127 | </linearGradient> 128 | <linearGradient id="paint18_linear_1678_2172" x1="-3.45538" y1="17.1593" x2="-3.45538" y2="1.53462" gradientUnits="userSpaceOnUse"> 129 | <stop stop-color="#C6BCDD"/> 130 | <stop offset="1" stop-color="white"/> 131 | </linearGradient> 132 | <linearGradient id="paint19_linear_1678_2172" x1="12.6452" y1="17.1593" x2="12.6452" y2="1.53462" gradientUnits="userSpaceOnUse"> 133 | <stop stop-color="#C6BCDD"/> 134 | <stop offset="1" stop-color="white"/> 135 | </linearGradient> 136 | <linearGradient id="paint20_linear_1678_2172" x1="15.5145" y1="13.5649" x2="15.5145" y2="4.74671" gradientUnits="userSpaceOnUse"> 137 | <stop offset="0.223" stop-color="#B70D22"/> 138 | <stop offset="0.979" stop-color="#FF5956"/> 139 | </linearGradient> 140 | <linearGradient id="paint21_linear_1678_2172" x1="27.7317" y1="13.5649" x2="27.7317" y2="4.74671" gradientUnits="userSpaceOnUse"> 141 | <stop offset="0.223" stop-color="#B70D22"/> 142 | <stop offset="0.979" stop-color="#FF5956"/> 143 | </linearGradient> 144 | <linearGradient id="paint22_linear_1678_2172" x1="7.52469" y1="36.815" x2="7.52469" y2="14.1188" gradientUnits="userSpaceOnUse"> 145 | <stop stop-color="#C6BCDD"/> 146 | <stop offset="1" stop-color="white"/> 147 | </linearGradient> 148 | <linearGradient id="paint23_linear_1678_2172" x1="9.36349" y1="27.2959" x2="15.6193" y2="27.2959" gradientUnits="userSpaceOnUse"> 149 | <stop offset="0.024" stop-color="#B70D22"/> 150 | <stop offset="1" stop-color="#F79800"/> 151 | </linearGradient> 152 | <linearGradient id="paint24_linear_1678_2172" x1="10.7971" y1="30.0903" x2="14.9999" y2="30.0903" gradientUnits="userSpaceOnUse"> 153 | <stop offset="0.024" stop-color="#B70D22"/> 154 | <stop offset="1" stop-color="#F79800"/> 155 | </linearGradient> 156 | <linearGradient id="paint25_linear_1678_2172" x1="12.8532" y1="35.9727" x2="4.29689" y2="26.1972" gradientUnits="userSpaceOnUse"> 157 | <stop offset="0.024" stop-color="#B70D22"/> 158 | <stop offset="1" stop-color="#F79800"/> 159 | </linearGradient> 160 | <linearGradient id="paint26_linear_1678_2172" x1="15.7576" y1="32.5619" x2="8.61682" y2="26.4232" gradientUnits="userSpaceOnUse"> 161 | <stop offset="0.107" stop-color="#210601"/> 162 | <stop offset="1" stop-color="#6A1705"/> 163 | </linearGradient> 164 | <linearGradient id="paint27_linear_1678_2172" x1="22.4312" y1="33.0032" x2="22.4312" y2="35.0497" gradientUnits="userSpaceOnUse"> 165 | <stop stop-color="#210601"/> 166 | <stop offset="1" stop-color="#6A1705"/> 167 | </linearGradient> 168 | <linearGradient id="paint28_linear_1678_2172" x1="33.9407" y1="29.1721" x2="27.4746" y2="29.1721" gradientUnits="userSpaceOnUse"> 169 | <stop offset="0.024" stop-color="#B70D22"/> 170 | <stop offset="1" stop-color="#F79800"/> 171 | </linearGradient> 172 | <linearGradient id="paint29_linear_1678_2172" x1="32.4247" y1="30.7592" x2="28.3127" y2="30.8454" gradientUnits="userSpaceOnUse"> 173 | <stop offset="0.024" stop-color="#B70D22"/> 174 | <stop offset="1" stop-color="#F79800"/> 175 | </linearGradient> 176 | <linearGradient id="paint30_linear_1678_2172" x1="17.696" y1="23.3802" x2="26.7289" y2="14.7594" gradientUnits="userSpaceOnUse"> 177 | <stop offset="0.024" stop-color="#B70D22"/> 178 | <stop offset="1" stop-color="#F79800"/> 179 | </linearGradient> 180 | <linearGradient id="paint31_linear_1678_2172" x1="20.9484" y1="25.0692" x2="27.8884" y2="19.2632" gradientUnits="userSpaceOnUse"> 181 | <stop stop-color="#210601"/> 182 | <stop offset="1" stop-color="#6A1705"/> 183 | </linearGradient> 184 | <linearGradient id="paint32_linear_1678_2172" x1="-0.242231" y1="25.6144" x2="-0.242231" y2="12.983" gradientUnits="userSpaceOnUse"> 185 | <stop offset="0.024" stop-color="#B70D22"/> 186 | <stop offset="1" stop-color="#F79800"/> 187 | </linearGradient> 188 | <linearGradient id="paint33_linear_1678_2172" x1="17.4432" y1="16.3011" x2="19.1879" y2="20.1754" gradientUnits="userSpaceOnUse"> 189 | <stop offset="0.024" stop-color="#B70D22"/> 190 | <stop offset="1" stop-color="#F79800"/> 191 | </linearGradient> 192 | <linearGradient id="paint34_linear_1678_2172" x1="5.90418" y1="25.6144" x2="5.90418" y2="12.983" gradientUnits="userSpaceOnUse"> 193 | <stop offset="0.024" stop-color="#B70D22"/> 194 | <stop offset="1" stop-color="#F79800"/> 195 | </linearGradient> 196 | <linearGradient id="paint35_linear_1678_2172" x1="31.3551" y1="14.1686" x2="31.3551" y2="19.3704" gradientUnits="userSpaceOnUse"> 197 | <stop offset="0.024" stop-color="#B70D22"/> 198 | <stop offset="1" stop-color="#F79800"/> 199 | </linearGradient> 200 | <linearGradient id="paint36_linear_1678_2172" x1="25.8" y1="16.3011" x2="24.0553" y2="20.1754" gradientUnits="userSpaceOnUse"> 201 | <stop offset="0.024" stop-color="#B70D22"/> 202 | <stop offset="1" stop-color="#F79800"/> 203 | </linearGradient> 204 | <linearGradient id="paint37_linear_1678_2172" x1="25.8838" y1="19.9982" x2="28.5135" y2="16.8728" gradientUnits="userSpaceOnUse"> 205 | <stop offset="0.024" stop-color="#B70D22"/> 206 | <stop offset="1" stop-color="#F79800"/> 207 | </linearGradient> 208 | <linearGradient id="paint38_linear_1678_2172" x1="26.1483" y1="22.1897" x2="26.8911" y2="21.8805" gradientUnits="userSpaceOnUse"> 209 | <stop offset="0.024" stop-color="#B70D22"/> 210 | <stop offset="0.979" stop-color="#FF5956"/> 211 | </linearGradient> 212 | <linearGradient id="paint39_linear_1678_2172" x1="25.1571" y1="23.052" x2="25.7471" y2="22.8064" gradientUnits="userSpaceOnUse"> 213 | <stop offset="0.024" stop-color="#B70D22"/> 214 | <stop offset="0.979" stop-color="#FF5956"/> 215 | </linearGradient> 216 | <linearGradient id="paint40_linear_1678_2172" x1="24.4668" y1="24.1215" x2="24.82" y2="23.9744" gradientUnits="userSpaceOnUse"> 217 | <stop offset="0.024" stop-color="#B70D22"/> 218 | <stop offset="0.979" stop-color="#FF5956"/> 219 | </linearGradient> 220 | <linearGradient id="paint41_linear_1678_2172" x1="23.947" y1="25.0632" x2="24.1919" y2="24.9613" gradientUnits="userSpaceOnUse"> 221 | <stop offset="0.024" stop-color="#B70D22"/> 222 | <stop offset="0.979" stop-color="#FF5956"/> 223 | </linearGradient> 224 | <linearGradient id="paint42_linear_1678_2172" x1="14.1049" y1="22.8493" x2="11.3645" y2="19.7897" gradientUnits="userSpaceOnUse"> 225 | <stop offset="0.024" stop-color="#B70D22"/> 226 | <stop offset="1" stop-color="#F79800"/> 227 | </linearGradient> 228 | <linearGradient id="paint43_linear_1678_2172" x1="17.095" y1="22.1897" x2="16.3523" y2="21.8805" gradientUnits="userSpaceOnUse"> 229 | <stop offset="0.024" stop-color="#B70D22"/> 230 | <stop offset="0.979" stop-color="#FF5956"/> 231 | </linearGradient> 232 | <linearGradient id="paint44_linear_1678_2172" x1="18.0863" y1="23.052" x2="17.4964" y2="22.8064" gradientUnits="userSpaceOnUse"> 233 | <stop offset="0.024" stop-color="#B70D22"/> 234 | <stop offset="0.979" stop-color="#FF5956"/> 235 | </linearGradient> 236 | <linearGradient id="paint45_linear_1678_2172" x1="18.7767" y1="24.1215" x2="18.4235" y2="23.9744" gradientUnits="userSpaceOnUse"> 237 | <stop offset="0.024" stop-color="#B70D22"/> 238 | <stop offset="0.979" stop-color="#FF5956"/> 239 | </linearGradient> 240 | <linearGradient id="paint46_linear_1678_2172" x1="19.2964" y1="25.0632" x2="19.0515" y2="24.9613" gradientUnits="userSpaceOnUse"> 241 | <stop offset="0.024" stop-color="#B70D22"/> 242 | <stop offset="0.979" stop-color="#FF5956"/> 243 | </linearGradient> 244 | <clipPath id="clip0_1678_2172"> 245 | <rect width="47" height="44" fill="white"/> 246 | </clipPath> 247 | </defs> 248 | </svg> --------------------------------------------------------------------------------