diff --git a/src/app/(layout)/(shell)/(category)/[category]/page.tsx b/src/app/(layout)/(shell)/(category)/[category]/page.tsx index 4906d03..d8d4976 100644 --- a/src/app/(layout)/(shell)/(category)/[category]/page.tsx +++ b/src/app/(layout)/(shell)/(category)/[category]/page.tsx @@ -1,16 +1,54 @@ import CategoryPage from "@/app/(layout)/(shell)/(category)/[category]/_components/CategoryPage"; import { CATEGORY_CONFIG, CategorySlug } from "@/config/categories"; - import { SearchParams } from "@/types/route.types"; +import { Metadata } from "next"; import { notFound } from "next/navigation"; +type CategoryPageProps = { + params: Promise<{ category: string }>; + searchParams: Promise; +}; + +export async function generateMetadata( + { params }: Pick +): Promise { + const { category } = await params; + if (!(category in CATEGORY_CONFIG)) { + return {}; + } + + const slug = category as CategorySlug; + const config = CATEGORY_CONFIG[slug]; + + const baseUrl = "https://b0o0a.com"; + const url = `${baseUrl}/category/${slug}`; + + const title = config.title; + const description = + config.description ?? ""; + + return { + title, + description, + alternates: { + canonical: url, + }, + openGraph: { + type: "website", + url, + title, + description, + }, + twitter: { + card: "summary_large_image", + }, + }; +} + export default async function CategoryRoutePage({ params, searchParams, -}: { - params: Promise<{ category: string }>; - searchParams: Promise; -}) { +}: CategoryPageProps) { const { category } = await params; const slug = category as CategorySlug; diff --git a/src/app/(layout)/(shell)/page.tsx b/src/app/(layout)/(shell)/page.tsx index 291d1d5..5e3ece6 100644 --- a/src/app/(layout)/(shell)/page.tsx +++ b/src/app/(layout)/(shell)/page.tsx @@ -24,7 +24,7 @@ export default async function HomePage({ return (
- + ; + params: Promise; }; +export function generateStaticParams() { + return velitePosts.map((post) => ({ + slug: post.slug, + })) +} + export async function generateMetadata({ params, }: PageProps): Promise { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index ae245ab..87ec62a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,15 +1,30 @@ +import { Analytics } from "@vercel/analytics/react"; import { Metadata } from "next"; import { ThemeProvider } from "next-themes"; import localFont from "next/font/local"; import "./globals.css"; -import { Analytics } from "@vercel/analytics/react"; export const metadata: Metadata = { - title: "B-log", - description: "boa's dev blog", + metadataBase: new URL("https://b0o0a.com"), + title: { + default: "B-log", + template: "%s | B-log", + }, + description: "FE 개발자 최보아의 프로젝트, 기술 인사이트, 개발 기록 블로그", icons: { icon: "/favicon.svg", }, + twitter: { + card: "summary_large_image", + images: ["/post-fallback.png"], + }, + openGraph: { + type: "website", + siteName: "B-log", + }, + alternates: { + canonical: "/", + }, }; const pretendard = localFont({ diff --git a/src/app/robots.ts b/src/app/robots.ts new file mode 100644 index 0000000..cfc2e4c --- /dev/null +++ b/src/app/robots.ts @@ -0,0 +1,13 @@ +import type { MetadataRoute } from "next"; + +export default function robots(): MetadataRoute.Robots { + const baseUrl = "https://b0o0a.com"; + + return { + rules: { + userAgent: "*", + allow: "/", + }, + sitemap: `${baseUrl}/sitemap.xml`, + }; +} diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts new file mode 100644 index 0000000..a624437 --- /dev/null +++ b/src/app/sitemap.ts @@ -0,0 +1,28 @@ +import type { MetadataRoute } from "next"; +import { velitePosts } from "@/lib/posts"; +import { CATEGORY_CONFIG } from "@/config/categories"; + +export default function sitemap(): MetadataRoute.Sitemap { + const baseUrl = "https://b0o0a.com"; + + const posts = velitePosts + .filter((post) => !post.draft) + .map((post) => ({ + url: `${baseUrl}/posts/${post.slug}`, + lastModified: new Date(post.date), + })); + + const categories = Object.values(CATEGORY_CONFIG).map((category) => ({ + url: `${baseUrl}/category/${category.slug}`, + lastModified: new Date(), + })); + + const staticPages: MetadataRoute.Sitemap = [ + { + url: baseUrl, + lastModified: new Date(), + }, + ]; + + return [...staticPages, ...categories, ...posts]; +}