minidocs

文档树

集合里的页面没有顺序。文档树决定它们怎样组织:侧边栏按它渲染,上一页和下一页按它的顺序计算。

定义

// 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')),
]);

规则

  • 文档树只决定导航,不影响地址。调整顺序或者把页面挪进别的分组,地址都不会变
  • 同一个页面可以在树里出现多次,但只有第一次出现的位置算作当前位置,翻页也按它计算
本页目录
搜索范围
输入关键词开始搜索