-
Notifications
You must be signed in to change notification settings - Fork 45
Expand file tree
/
Copy pathpage.tsx
More file actions
130 lines (119 loc) · 4.26 KB
/
page.tsx
File metadata and controls
130 lines (119 loc) · 4.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { source } from "@/lib/source";
import { DocsPage, DocsBody } from "fumadocs-ui/page";
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import { getMDXComponents } from "@/mdx-components";
import { GiscusComments } from "@/app/components/GiscusComments";
import { EditOnGithub } from "@/app/components/EditOnGithub";
import { buildDocsEditUrl } from "@/lib/github";
import {
getDocContributorsByPath,
getDocContributorsByDocId,
} from "@/lib/contributors";
import { Contributors } from "@/app/components/Contributors";
import { DocsAssistant } from "@/app/components/DocsAssistant";
import { LicenseNotice } from "@/app/components/LicenseNotice";
import fs from "fs/promises";
import path from "path";
// Extract clean text content from MDX
function extractTextFromMDX(content: string): string {
let text = content
.replace(/^---[\s\S]*?---/m, "") // Remove frontmatter
.replace(/```[\s\S]*?```/g, "") // Remove code blocks
.replace(/`([^`]+)`/g, "$1"); // Remove inline code
// Remove HTML/MDX tags recursively to prevent incomplete multi-character sanitization
let prevText;
do {
prevText = text;
text = text.replace(/<[^>]+>/g, "");
} while (text !== prevText);
return text
.replace(/\*\*([^*]+)\*\*/g, "$1") // Remove bold
.replace(/\*([^*]+)\*/g, "$1") // Remove italic
.replace(/#{1,6}\s+/g, "") // Remove headers
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1") // Remove links, keep text
.replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1") // Remove images, keep alt text
.replace(/[#*`\[\]()!]/g, "") // Remove common markdown symbols
.replace(/\n{2,}/g, "\n") // Normalize line breaks
.trim();
}
interface Param {
params: Promise<{
slug?: string[];
}>;
}
export default async function DocPage({ params }: Param) {
const { slug } = await params;
const page = source.getPage(slug);
if (page == null) {
notFound();
}
// 统一通过工具函数生成 Edit 链接,内部已处理中文目录编码
const editUrl = buildDocsEditUrl(page.path);
const docIdFromPage =
(page.data as { docId?: string; frontmatter?: { docId?: string } })
?.docId ??
(page.data as { docId?: string; frontmatter?: { docId?: string } })
?.frontmatter?.docId;
const contributorsEntry =
getDocContributorsByPath(page.file.path) ||
getDocContributorsByDocId(docIdFromPage);
const Mdx = page.data.body;
// Prepare page content for AI assistant
let pageContentForAI = "";
try {
const fullFilePath = path.join(process.cwd(), "app/docs", page.file.path);
const rawContent = await fs.readFile(fullFilePath, "utf-8");
const extractedText = extractTextFromMDX(rawContent);
// Use full extracted content without truncation
pageContentForAI = extractedText;
} catch (error) {
console.warn("Failed to read file content for AI assistant:", error);
// Fallback to using page metadata
pageContentForAI = `${page.data.title}\n${page.data.description || ""}`;
}
return (
<>
<DocsPage toc={page.data.toc}>
<DocsBody>
<div className="mb-6 flex flex-col gap-3 border-b border-border pb-6 md:mb-8 md:flex-row md:items-start md:justify-between">
<h1 className="text-3xl font-extrabold tracking-tight md:text-4xl">
{page.data.title}
</h1>
<EditOnGithub href={editUrl} />
</div>
<Mdx components={getMDXComponents()} />
<Contributors entry={contributorsEntry} />
<section className="mt-16">
<GiscusComments docId={docIdFromPage ?? null} />
</section>
<LicenseNotice className="mt-16" />
</DocsBody>
</DocsPage>
<DocsAssistant
pageContext={{
title: page.data.title,
description: page.data.description,
content: pageContentForAI,
slug: slug?.join("/"),
}}
/>
</>
);
}
export async function generateStaticParams() {
return source.getPages().map((page) => ({
slug: page.slugs,
}));
}
export async function generateMetadata({ params }: Param): Promise<Metadata> {
const { slug } = await params;
const page = source.getPage(slug);
if (page == null) {
notFound();
}
return {
title: page.data.title,
description: page.data.description,
};
}