-
Notifications
You must be signed in to change notification settings - Fork 45
fix(docs): /docs 根路由 404 — 加 landing page 列出所有分区 #290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,140 @@ | ||||||
| import { source } from "@/lib/source"; | ||||||
| import { DocsPage, DocsBody } from "fumadocs-ui/page"; | ||||||
| import { Card, Cards } from "fumadocs-ui/components/card"; | ||||||
| import type { PageTree } from "fumadocs-core/server"; | ||||||
| import type { Metadata } from "next"; | ||||||
| import { cookies } from "next/headers"; | ||||||
|
|
||||||
| /** | ||||||
| * /docs 根路由的 landing 页。 | ||||||
| * | ||||||
| * 为什么需要这个文件: | ||||||
| * - Header 导航栏 "文档 / Docs" 直接指向 /docs | ||||||
| * - 但路由目录下只有 app/docs/[...slug]/page.tsx(catch-all,不匹配空 slug)和 layout.tsx, | ||||||
| * 没有任何东西匹配 /docs 本身 → 用户点导航就 404 | ||||||
| * - 修法:加这个 server component,复用 app/docs/layout.tsx 里已经挂好的 DocsLayout | ||||||
| * (侧边栏 + copy tracking + view tracking 都继承下来),自己只负责渲染中间内容区 | ||||||
| * | ||||||
| * 内容策略: | ||||||
| * - 不硬编码 ai / computer-science / ... 这些分区,直接读 source.pageTree 顶层 children | ||||||
| * → 以后新增分区(比如又搞一个 "research-logs" 目录)landing 自动带上 | ||||||
| * - 卡片标题 / 描述用分区 index.mdx 的 frontmatter.title / description | ||||||
| * 没 index 的分区降级用目录名 + 空描述(jobs / all-projects 目前就是这个情况) | ||||||
| * - 仅从 cookie 读 locale 用于 H1/intro 的中英切换;卡片内容来自 frontmatter 本身, | ||||||
| * 所以已经由 [...slug] 的 locale fallback 负责,这里不重复处理 | ||||||
| */ | ||||||
|
|
||||||
| type FolderNode = Extract<PageTree.Node, { type: "folder" }>; | ||||||
| type PageNode = Extract<PageTree.Node, { type: "page" }>; | ||||||
|
|
||||||
| interface SectionCard { | ||||||
| title: string; | ||||||
| description?: string; | ||||||
| href: string; | ||||||
| } | ||||||
|
|
||||||
| async function getLocaleFromCookie(): Promise<"zh" | "en"> { | ||||||
| const cookieStore = await cookies(); | ||||||
| const val = cookieStore.get("locale")?.value; | ||||||
| return val === "en" ? "en" : "zh"; | ||||||
| } | ||||||
|
|
||||||
| /** 把 pageTree 顶层 node 映射成 landing 卡片;遇到 separator / 孤立 page 就跳过 */ | ||||||
| function toSectionCard(node: PageTree.Node): SectionCard | null { | ||||||
| if (node.type === "separator") return null; | ||||||
| if (node.type === "page") { | ||||||
| // 顶层直接挂的文件(比如目录只有一个文件被 pruneEmptyFolders 提出来了) | ||||||
| const pageNode = node as PageNode; | ||||||
| return { | ||||||
| title: asPlainText(pageNode.name), | ||||||
| description: pageNode.description | ||||||
| ? asPlainText(pageNode.description) | ||||||
| : undefined, | ||||||
| href: pageNode.url, | ||||||
| }; | ||||||
| } | ||||||
| // folder 分支 | ||||||
| const folder = node as FolderNode; | ||||||
| const indexUrl = folder.index?.url; | ||||||
| // folder 没 index 时指向它第一个 page 后代,保证 landing 上点击不落空 | ||||||
| const fallbackUrl = | ||||||
| indexUrl ?? findFirstPageUrl(folder.children) ?? undefined; | ||||||
| if (!fallbackUrl) return null; | ||||||
| return { | ||||||
| title: asPlainText(folder.name), | ||||||
|
||||||
| title: asPlainText(folder.name), | |
| title: asPlainText(folder.index?.name ?? folder.name), |
Copilot
AI
Apr 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里读取的是未处理过的 source.pageTree,但 docs 的 layout.tsx 会对 tree 做 pruneEmptyFolders(source.pageTree) 后再交给 DocsLayout。landing 用原始 tree 可能会把 layout 已经 prune 掉/提升成 page 的节点也展示出来,导致 landing 卡片与侧边栏结构不一致。建议复用同一份 prune 逻辑(例如将 pruneEmptyFolders 提到共享 util 并在这里也使用)。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
注释“遇到 separator / 孤立 page 就跳过”与实际逻辑不一致:当前
node.type === "page"会被映射成卡片而不是跳过。建议更新注释以匹配真实行为,避免后续维护者误解。