多棵树
文档站常常分成几块,比如「指南」和「API 参考」:每块有自己的侧边栏,翻页也不会从一块翻到另一块。对同一个集合多次调用 defineTree,每棵树只放自己那部分页面就行。
定义
// src/lib/docs.ts
const guides = await defineTree(entries, ({ page, dir }) => [page('guides', dir('guides'))]);
const api = await defineTree(entries, ({ page, dir }) => [page('api', dir('api'))]);
export const sections = [
{ label: '指南', href: toHref('docs', 'guides'), tree: guides },
{ label: 'API 参考', href: toHref('docs', 'api'), tree: api },
];
sections 是你自己的数据,minidocs 不认识它。名字、入口页、要不要图标,都由你决定。
当前页面在哪棵树
用 findPath 找出包含当前页面的那棵树:
const section = sections.find((section) => findPath(section.tree, id).length > 0) ?? sections[0];
const nav = navState(section.tree, id);
const { prev, next } = neighbors(section.tree, id);
之后的侧边栏、翻页都用 section.tree,写法和只有一棵树时一样。
用 findPath 而不是 id.startsWith('api') 判断,这样树的结构只写在一个地方。
不在任何树里的页面,比如首页,会落到 ?? sections[0]。你也可以改成不显示侧边栏。同一篇文档出现在两棵树里时,find 取 sections 里排在前面的那棵。
切换器
切换器是你自己写的 HTML,和语言切换器一样:
<nav aria-label="分区">
{sections.map((item) => (
<a href={item.href} aria-current={item === section ? 'true' : undefined}>
{item.label}
</a>
))}
</nav>
链接指向的是这一块的入口页,不一定是当前页面,所以 aria-current 用 true 而不是 page。
多语言
把 sections 写成按语言返回的函数,t 是你自己的界面文案:
export const sections = (locale: Locale) => [
{ label: t[locale].guides, href: toHref('docs', 'guides', locale), tree: guides[locale] },
{ label: t[locale].api, href: toHref('docs', 'api', locale), tree: api[locale] },
];
llms.txt 和搜索
- llms.txt:每棵树各生成一份,或者把节点拼起来生成一份:
toLlmsTxt([...guides, ...api], { title })。每棵树最上面那个带子节点的节点会成为一节,见 llms.txt - 搜索:把树的名字写进过滤条件,比如
data-pagefind-filter={`tree:${section.label}`},再放一组name="tree"的单选框,见按分组过滤
什么时候用多个集合
几棵树共用一个集合,所以也共用地址前缀和 frontmatter 的 schema。地址前缀不同、字段也不同的内容,比如放在 /changelog/ 下、每篇都带日期的更新日志,应该是另一个集合,见多个集合。