Expand document collections with Pretext tutorial and simplify library navigation
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 5m47s
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 5m47s
This commit is contained in:
+30
-13
@@ -1,27 +1,44 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import catalog from "../../../../content/catalog.json";
|
||||
|
||||
const directory = path.resolve(process.cwd(), "../../content/docs");
|
||||
const validSlug = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
||||
|
||||
export type DocLink = { slug: string; title: string; searchText: string };
|
||||
const validSlug = /^[a-z0-9]+(?:-[a-z0-9]+)*(?:\/[a-z0-9]+(?:-[a-z0-9]+)*)*$/;
|
||||
type Metadata = { group?: string; description?: string; draft?: boolean; featured?: boolean };
|
||||
export type DocLink = {
|
||||
slug: string; title: string; searchText?: string;
|
||||
group: string; collection: string; description: string; draft: boolean; featured: boolean;
|
||||
};
|
||||
export type Doc = DocLink & { content: string };
|
||||
|
||||
export async function readDoc(slug: string): Promise<Doc> {
|
||||
if (!validSlug.test(slug)) throw new Error("Invalid document slug");
|
||||
const content = await fs.readFile(path.join(directory, `${slug}.md`), "utf8");
|
||||
const title = content.match(/^# (.+)$/m)?.[1]?.trim() ?? slug;
|
||||
return { slug, title, content, searchText: content };
|
||||
const collection = catalog.collections.find((c) => !c.path || slug.startsWith(`${c.path}/`))!;
|
||||
const metadata: Metadata = (catalog.documents as Record<string, Metadata>)[slug] ?? {};
|
||||
return { slug, title, content, searchText: content,
|
||||
group: metadata.group ?? collection.title, collection: collection.title,
|
||||
description: metadata.description ?? collection.description,
|
||||
draft: metadata.draft ?? false, featured: metadata.featured ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
export async function listDocs(): Promise<DocLink[]> {
|
||||
const files = (await fs.readdir(directory))
|
||||
.filter((file) => file.endsWith(".md") && validSlug.test(file.slice(0, -3)))
|
||||
.sort();
|
||||
return Promise.all(
|
||||
files.map(async (file) => {
|
||||
const { slug, title, searchText } = await readDoc(file.slice(0, -3));
|
||||
return { slug, title, searchText };
|
||||
}),
|
||||
);
|
||||
async function walk(folder: string): Promise<string[]> {
|
||||
const entries = await fs.readdir(path.join(directory, folder), { withFileTypes: true });
|
||||
const files = await Promise.all(entries.map(async (entry) => {
|
||||
const relative = folder ? `${folder}/${entry.name}` : entry.name;
|
||||
if (entry.isDirectory()) return walk(relative);
|
||||
if (entry.isFile() && relative.endsWith(".md") && validSlug.test(relative.slice(0, -3)))
|
||||
return [relative.slice(0, -3)];
|
||||
return [];
|
||||
}));
|
||||
return files.flat();
|
||||
}
|
||||
return Promise.all((await walk("")).sort().map(async (slug) => {
|
||||
const { content: _, searchText: __, ...doc } = await readDoc(slug);
|
||||
void _; void __;
|
||||
return doc;
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1,45 +1,3 @@
|
||||
export type Section = {
|
||||
group: string;
|
||||
description: string;
|
||||
label: string;
|
||||
symbol: string;
|
||||
};
|
||||
export function sectionFor(slug: string): Section {
|
||||
if (slug.includes("endor-purpose"))
|
||||
return {
|
||||
group: "项目讨论",
|
||||
label: "讨论草案",
|
||||
symbol: "○",
|
||||
description: "逐步讨论 Endor 的意义:从程序入口走向用户与 AI 的对象操作。",
|
||||
};
|
||||
if (slug.includes("endor-concepts"))
|
||||
return {
|
||||
group: "架构设计",
|
||||
label: "系统架构",
|
||||
symbol: "◇",
|
||||
description: "从全球入口、区域运行时到对象数据,了解 Endor 的系统架构。",
|
||||
};
|
||||
if (slug.includes("mounting"))
|
||||
return {
|
||||
group: "架构设计",
|
||||
label: "讨论草案",
|
||||
symbol: "◇",
|
||||
description: "探索节点、对象与统一接入协议,记录仍在演进的设计。",
|
||||
};
|
||||
if (slug.includes("figures"))
|
||||
return {
|
||||
group: "图形档案",
|
||||
label: "工具与工作流",
|
||||
symbol: "⌘",
|
||||
description: "从 Python 源码到可编辑 SVG,让图形与文档一起演进。",
|
||||
};
|
||||
return {
|
||||
group: "开始使用",
|
||||
label: "指南",
|
||||
symbol: "↗",
|
||||
description: "搭建本地工作台,添加第一篇文档,了解检查与发布流程。",
|
||||
};
|
||||
}
|
||||
export type Heading = { id: string; text: string; level: number; line: number };
|
||||
export function headingsFor(content: string): Heading[] {
|
||||
let fenced = false;
|
||||
|
||||
Reference in New Issue
Block a user