minidocs

多棵树

文档站常常分成几块,比如「指南」和「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/ 下、每篇都带日期的更新日志,应该是另一个集合,见多个集合。

本页目录
搜索范围
输入关键词开始搜索