├── .eslintrc.json ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── app ├── [categories] │ └── page.tsx ├── favicon.ico ├── globals.css ├── layout.tsx ├── loading.tsx ├── opengraph-image.jpg ├── page.tsx ├── post │ └── [slug] │ │ ├── opengraph-image.tsx │ │ ├── page.tsx │ │ ├── postBody.tsx │ │ └── postHero.tsx ├── robots.txt └── sitemap.ts ├── atoms └── popupAtom.ts ├── components ├── brand │ └── logo.tsx ├── buttons │ └── primaryButton.tsx ├── elements │ ├── ctaCard.tsx │ ├── loadingSkelton.tsx │ ├── shareLinks.tsx │ └── socialLink.tsx ├── layouts │ └── paddingContainer.tsx ├── navigation │ ├── footer.tsx │ └── navbar.tsx ├── popups │ └── popup.tsx └── post │ ├── postCard.tsx │ ├── postCardContent.tsx │ └── postCardList.tsx ├── lib ├── directus │ ├── directusClientInstance.ts │ └── directusInstance.ts ├── getAllCategories.ts ├── getAllPosts.ts ├── getCategoryData.ts ├── getParsedHTML.tsx ├── getPostData.ts ├── getReadingTime.ts ├── getRelativeDate.ts └── supabase │ ├── supabasePublic.ts │ └── supabaseServer.ts ├── next.config.js ├── package.json ├── postcss.config.js ├── public └── _favicon.ico ├── supabase ├── .temp │ └── project-ref ├── config.toml └── seed.sql ├── tailwind.config.js ├── tsconfig.json ├── types ├── database.ts └── supabase.ts └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "typescript.enablePromptUseWorkspaceTsdk": true 4 | } -------------------------------------------------------------------------------- /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 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 18 | 19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 20 | 21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 22 | 23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 24 | 25 | ## Learn More 26 | 27 | To learn more about Next.js, take a look at the following resources: 28 | 29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 31 | 32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 33 | 34 | ## Deploy on Vercel 35 | 36 | 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. 37 | 38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 39 | -------------------------------------------------------------------------------- /app/[categories]/page.tsx: -------------------------------------------------------------------------------- 1 | import PaddingContainer from "@/components/layouts/paddingContainer"; 2 | import PostCardList from "@/components/post/postCardList"; 3 | import getAllCategories from "@/lib/getAllCategories"; 4 | import getCategoryData from "@/lib/getCategoryData"; 5 | import { notFound } from "next/navigation"; 6 | 7 | export async function generateMetadata({ 8 | params: { categories }, 9 | }: { 10 | params: { 11 | categories: string; 12 | }; 13 | }) { 14 | try { 15 | const category = await getCategoryData(categories); 16 | if (!category) 17 | return { 18 | title: "Not Found", 19 | description: "The page you are looking for does not exist.", 20 | }; 21 | return { 22 | title: category.title, 23 | description: category.description, 24 | robots: { 25 | index: false, 26 | follow: true, 27 | nocache: true, 28 | }, 29 | }; 30 | } catch (error) { 31 | console.error(error); 32 | return { 33 | title: "Not Found", 34 | description: "The page you are looking for does not exist.", 35 | }; 36 | } 37 | } 38 | 39 | export async function generateStaticParams() { 40 | const categories = await getAllCategories(); 41 | 42 | if (!categories) return []; 43 | 44 | return categories.map((category) => ({ 45 | categories: category.slug, 46 | })); 47 | } 48 | 49 | const CategoryPage = async ({ 50 | params: { categories }, 51 | }: { 52 | params: { 53 | categories: string; 54 | }; 55 | }) => { 56 | const category = await getCategoryData(categories); 57 | if (!category) return notFound(); 58 | 59 | return ( 60 | 61 |
62 | {/* Hero */} 63 |
64 |

65 | {category?.title} 66 |

67 |

{category?.description}

68 |
69 |
70 | {/* Posts */} 71 | 72 |
73 | ); 74 | }; 75 | 76 | export default CategoryPage; 77 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batuhanbilginn/nextjs13-seo/b91dc9f9a9c5dc168451e015f33aa0fea69ff3e3/app/favicon.ico -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer utilities { 6 | .blog-rich-text h2 { 7 | @apply text-3xl font-semibold text-neutral-900 mb-3; 8 | } 9 | 10 | .blog-rich-text p { 11 | @apply text-neutral-700 mb-2 leading-normal; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import Footer from "@/components/navigation/footer"; 2 | import Navbar from "@/components/navigation/navbar"; 3 | import "./globals.css"; 4 | 5 | export const metadata = { 6 | metadataBase: new URL("https://nextjs13-seo.vercel.app"), 7 | title: { 8 | default: "Explorer", 9 | template: `%s | Explorer`, 10 | }, 11 | description: "Explore the latest posts from my travel blog.", 12 | verification: { 13 | google: "google-site-verification=123123123", 14 | }, 15 | }; 16 | 17 | export default function RootLayout({ 18 | children, 19 | }: { 20 | children: React.ReactNode; 21 | }) { 22 | return ( 23 | 24 | 25 | 26 | {/* Padding for Navbar */} 27 |
{children}
28 |