Organize document URLs by category and collection with compact navigation
Verify and deploy Tabularium / verify-and-deploy (pull_request) Has been cancelled

This commit is contained in:
2026-10-28 18:38:13 +08:00
parent 8be53c1e25
commit 422d6622a2
8 changed files with 221 additions and 48 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ export function collectionIcon(name?: string): "book" | "code" | "layers" | "nod
export function collectionEntries(docs: DocLink[]) {
return [...new Set(docs.map((doc) => doc.collection))].map((name) => {
const items = docs.filter((doc) => doc.collection === name);
const entry = items.find((doc) => doc.slug.endsWith("/00-overview")) ?? items[0];
const entry = items.find((doc) => doc.slug.endsWith("/overview")) ?? items[0];
return { name, entry, count: items.length };
});
}
+13 -7
View File
@@ -4,20 +4,24 @@ import catalog from "../../../../content/catalog.json";
const directory = path.resolve(process.cwd(), "../../content/docs");
const validSlug = /^[a-z0-9]+(?:-[a-z0-9]+)*(?:\/[a-z0-9]+(?:-[a-z0-9]+)*)*$/;
type Metadata = { collection?: string; group?: string; description?: string; draft?: boolean; featured?: boolean };
type Metadata = { slug?: string; category?: string; collection?: string; group?: string; description?: string; draft?: boolean; featured?: boolean };
export type DocLink = {
slug: string; title: string; searchText?: string;
slug: string; sourceSlug: string; category: 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 sourceSlug = Object.entries(catalog.documents).find(([, metadata]) => metadata.slug === slug)?.[0] ?? slug;
const content = await fs.readFile(path.join(directory, `${sourceSlug}.md`), "utf8");
const title = content.match(/^# (.+)$/m)?.[1]?.trim() ?? slug;
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,
const collection = catalog.collections.find((c) => !c.path || sourceSlug.startsWith(`${c.path}/`))!;
const metadata: Metadata = (catalog.documents as Record<string, Metadata>)[sourceSlug] ?? {};
if (!metadata.slug || !metadata.category || !validSlug.test(metadata.slug) || metadata.slug.split("/").some((part) => /^\d+-/.test(part))) {
throw new Error(`Register a semantic slug and category in content/catalog.json: ${sourceSlug}`);
}
return { slug: metadata.slug, sourceSlug, category: metadata.category, title, content, searchText: content,
group: metadata.group ?? collection.title, collection: metadata.collection ?? collection.title,
description: metadata.description ?? collection.description,
draft: metadata.draft ?? false, featured: metadata.featured ?? false,
@@ -36,9 +40,11 @@ export async function listDocs(): Promise<DocLink[]> {
}));
return files.flat();
}
return Promise.all((await walk("")).sort().map(async (slug) => {
const docs = await Promise.all((await walk("")).sort().map(async (slug) => {
const { content: _, searchText: __, ...doc } = await readDoc(slug);
void _; void __;
return doc;
}));
if (new Set(docs.map((doc) => doc.slug)).size !== docs.length) throw new Error("Duplicate public document slug");
return docs;
}