108 lines
4.1 KiB
TypeScript
108 lines
4.1 KiB
TypeScript
import type { Metadata } from "next"
|
|
import Image from "next/image"
|
|
import Link from "next/link"
|
|
import { notFound } from "next/navigation"
|
|
import { BLOG_POSTS } from "@/lib/blog-data"
|
|
|
|
interface Props {
|
|
params: Promise<{ slug: string }>
|
|
}
|
|
|
|
export async function generateStaticParams() {
|
|
return BLOG_POSTS.map((post) => ({ slug: post.slug }))
|
|
}
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { slug } = await params
|
|
const post = BLOG_POSTS.find((p) => p.slug === slug)
|
|
if (!post) return { title: "文章未找到" }
|
|
return {
|
|
title: `${post.title} | DAL Code`,
|
|
description: post.excerpt,
|
|
openGraph: {
|
|
title: `${post.title} | DAL Code`,
|
|
description: post.excerpt,
|
|
images: [{ url: post.image }],
|
|
},
|
|
}
|
|
}
|
|
|
|
export default async function BlogPostPage({ params }: Props) {
|
|
const { slug } = await params
|
|
const post = BLOG_POSTS.find((p) => p.slug === slug)
|
|
if (!post) notFound()
|
|
|
|
return (
|
|
<main>
|
|
<section className="section-small top overflow-hidden">
|
|
<div className="w-layout-blockcontainer container-default w-container">
|
|
<div className="inner-container _650px center">
|
|
<div className="text-center">
|
|
<div className="blog-details-wrapper" style={{ justifyContent: "center" }}>
|
|
<div className="item-details">{post.date}</div>
|
|
<div className="item-details-divider">·</div>
|
|
<div className="item-details">{post.category}</div>
|
|
</div>
|
|
<div className="mg-top-4x-extra-small">
|
|
<h1>{post.title}</h1>
|
|
</div>
|
|
<div className="mg-top-4x-extra-small">
|
|
<p>{post.excerpt}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mg-top-regular">
|
|
<div className="corner-gradient-container">
|
|
<div className="border-wrapper" style={{ position: "relative", aspectRatio: "16/9" }}>
|
|
<Image
|
|
src={post.image}
|
|
alt={post.imageAlt}
|
|
fill
|
|
style={{ objectFit: "cover", borderRadius: 12 }}
|
|
priority
|
|
/>
|
|
</div>
|
|
<div className="corner-gradient-wrapper">
|
|
<div className="corner-gradient-horizontal top-left" />
|
|
<div className="corner-gradient-horizontal bottom-left" />
|
|
<div className="corner-gradient-horizontal top-right" />
|
|
<div className="corner-gradient-horizontal bottom-right" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mg-top-regular">
|
|
<div className="inner-container _650px center">
|
|
<div className="blog-post-rich-text w-richtext">
|
|
{post.sections.map((section) => (
|
|
<section key={section.title}>
|
|
<h2>{section.title}</h2>
|
|
{section.paragraphs.map((paragraph) => (
|
|
<p key={paragraph}>{paragraph}</p>
|
|
))}
|
|
</section>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="mg-top-regular">
|
|
<div className="inner-container _650px center text-center">
|
|
<Link href="/blog" className="primary-button w-inline-block">
|
|
<div className="button-content">
|
|
<div>返回全部文章</div>
|
|
<div className="button-icon-wrapper primary">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 17 17" fill="none" className="squared-icon">
|
|
<path d="M6.25391 3.45312L10.7458 8.01563L6.25391 12.5781" stroke="currentColor" strokeWidth="1.5" strokeLinecap="square" />
|
|
</svg>
|
|
<div className="button-icon-bg" />
|
|
<div className="button-icon-bg-inside" />
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
)
|
|
}
|