import { Callout } from "@/components/mdx/Callout"; import MDXComponents from "@/components/mdx/MDXComponents"; import TableOfContents from "@/components/mdx/TableOfContents.client"; import { Locale } from "@/i18n/routing"; import { getPostDetail } from "@/lib/getBlogDetail"; import { constructMetadata } from "@/lib/metadata"; import { BlogPost } from "@/types/blog"; import { Metadata } from "next"; import { MDXRemote } from "next-mdx-remote-client/rsc"; import { notFound } from "next/navigation"; interface TableOfContentsItem { id: string; text: string; level: number; } // 解析MDX内容并提取标题 async function parseMDXContent(content: string): Promise { if (!content) { return []; } try { const headingRegex = /^#{2,4}\s+(.+)$/gm; const headings: TableOfContentsItem[] = []; let match; while ((match = headingRegex.exec(content)) !== null) { const fullMatch = match[0]; const text = match[1]?.trim(); if (!text) continue; // 确定标题级别 let level = 2; if (fullMatch.startsWith("###")) { level = fullMatch.startsWith("####") ? 4 : 3; } // 生成ID(将文本转换为URL友好的格式) const id = text .toLowerCase() .replace(/[^a-z0-9\u4e00-\u9fa5\s-]/g, "") .replace(/\s+/g, "-"); headings.push({ id, text, level }); } return headings; } catch (error) { console.error("Error parsing MDX content for TOC:", error); return []; } } type Params = Promise<{ locale: string; slug: string; }>; type MetadataProps = { params: Params; }; export async function generateMetadata({ params, }: MetadataProps): Promise { const { locale, slug } = await params; let post: BlogPost = await getPostDetail(slug); console.log(post); if (!post) { return constructMetadata({ title: "404", description: "Page not found", noIndex: true, locale: locale as Locale, path: `/blog/${slug}`, canonicalUrl: `/blog/${slug}`, }); } return constructMetadata({ page: "blog", title: post.title, description: post.description, images: post.image ? [post.image] : [], locale: locale as Locale, path: `/blog/${slug}`, canonicalUrl: `/blog/${slug}`, }); } export default async function BlogPage({ params }: { params: Params }) { const { locale, slug } = await params; let post: BlogPost = await getPostDetail(slug); if (!post) { return notFound(); } console.log(post); // 提取博客内容中的标题用于目录 const tocItems = await parseMDXContent(post.content || ""); // 使用默认目录标题 const tocTitle = "目录"; return (
{/* 侧边目录 - 在移动端显示在内容上方 */}
{/* 主要内容 */}

{post.title}

{post.image && ( {post.title} )} {post.tags && post.tags.split(",").length ? (
{post.tags.split(",").map((tag) => { return (
{tag.trim()}
); })}
) : ( <> )} {post.description && {post.description}}
); } // export async function generateStaticParams() { // let post = (await getPostDetail()); // // Filter out posts without a slug // posts = posts.filter((post) => post.slug); // return LOCALES.flatMap((locale) => // posts.map((post) => { // const slugPart = post.slug.replace(/^\//, "").replace(/^blog\//, ""); // return { // locale, // slug: slugPart, // }; // }) // ); // }