文档树
集合里的页面没有顺序。文档树决定它们怎样组织:侧边栏按它渲染,上一页和下一页按它的顺序计算。
定义
// src/lib/docs.ts
import { getCollection } from 'astro:content';
import { defineTree } from '@minidocs/astro/runtime';
const entries = await getCollection('docs');
export const tree = await defineTree(entries, ({ page, group, dir, link }) => [
page('index'),
page('install'),
group('指南', dir('guides')),
link('GitHub', 'https://github.com/example/repo'),
]);
defineTree 的回调返回一组节点。节点是文档树里的一项,比如一个页面或一个分组,这一组节点就是侧边栏的第一层。
四个函数
| 函数 | 产出 |
|---|---|
page(id, children?) |
一个页面,可以带子节点 |
group(label, children) |
一个没有自己页面的分组 |
dir(path, { compare? }) |
目录里的页面和子目录,不含目录自己的 index |
link(label, href) |
一个外部链接 |
dir 不含目录自己的 index,所以一个目录可以有两种写法:
group('指南', dir('guides')); // 分组只是一个标题
page('guides', dir('guides')); // 分组本身也是页面,就是 guides/index.mdx
dir 遇到子目录时也是这样:有 index 的子目录成为带子节点的页面,没有的成为分组,标题是目录名。
节点
渲染时你拿到的每个节点都有这几个字段:
| 字段 | 含义 |
|---|---|
label |
显示的文字:页面取 frontmatter 的 title,分组取你给的标题或目录名 |
children |
子节点,没有时是空数组 |
page |
页面节点才有,page.entry 是集合里的原始条目 |
href |
外部链接才有 |
怎样把它渲染成侧边栏,见侧边栏。
排序
dir 默认按文件名排序。想按别的方式排,传一个 compare,比如按 frontmatter 里的 order:
import { type DocNode } from '@minidocs/astro/runtime';
type Entry = (typeof entries)[number];
const byOrder = (a: DocNode<Entry>, b: DocNode<Entry>) =>
(a.page?.entry.data.order ?? Infinity) - (b.page?.entry.data.order ?? Infinity);
group('指南', dir('guides', { compare: byOrder }));
compare 对 dir 列出的每一层都生效。order 是你自己在 schema 里声明的字段;分组节点没有 page,上面的写法会把它们排在最后。
多语言站点
回调对每种语言各执行一次,tree 是按语言索引的对象,渲染时用 tree[locale]。回调参数里的 locale 可以用来翻译分组的标题:
export const tree = await defineTree(entries, ({ locale, page, group, dir }) => [
page('index'),
group(locale === 'zh' ? '指南' : 'Guides', dir('guides')),
]);
规则
- 文档树只决定导航,不影响地址。调整顺序或者把页面挪进别的分组,地址都不会变
- 同一个页面可以在树里出现多次,但只有第一次出现的位置算作当前位置,翻页也按它计算