54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import { ImageWrapper } from '@/components/common/ImageWrapper'
|
|
import { TableOfContents } from '@/components/common/TableOfContents'
|
|
import { getAllPostSlugs, getPostBySlug } from '@/lib/posts'
|
|
import type { Metadata } from 'next'
|
|
|
|
export async function generateStaticParams() {
|
|
return getAllPostSlugs().map((slug) => ({ slug }))
|
|
}
|
|
|
|
export const dynamicParams = false
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: {
|
|
params: Promise<{ slug: string }>
|
|
}): Promise<Metadata> {
|
|
const { slug } = await params
|
|
const { meta } = await getPostBySlug(slug)
|
|
return { title: meta.title, description: meta.description }
|
|
}
|
|
|
|
export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
|
|
const { slug } = await params
|
|
const { meta, content, tableOfContents } = await getPostBySlug(slug)
|
|
|
|
return (
|
|
<article className="flex w-full">
|
|
<main className="max-w-3xl mx-auto px-4 py-8 lg:py-16">
|
|
{meta.categories.length > 0 && (
|
|
<div className="flex flex-wrap gap-2 mb-2">
|
|
{meta.categories.map((category) => (
|
|
<span
|
|
key={category}
|
|
className="bg-accent/20 text-accent px-2 py-1 rounded-full text-sm"
|
|
>
|
|
{category}
|
|
</span>
|
|
))}
|
|
</div>
|
|
)}
|
|
<h1 className="text-5xl font-bold mb-4">{meta.title}</h1>
|
|
<span>{meta.readingTimeText}</span>
|
|
<time>{new Date(meta.date).toLocaleDateString()}</time>
|
|
<p>{meta.description}</p>
|
|
{meta.coverImage && <ImageWrapper src={meta.coverImage} alt={meta.coverImageAlt} />}
|
|
<div className="prose">{content}</div>
|
|
</main>
|
|
|
|
<aside className="hidden lg:block w-80">
|
|
<TableOfContents items={tableOfContents} />
|
|
</aside>
|
|
</article>
|
|
)
|
|
}
|