2026-06-30 18:47:14 +08:00
|
|
|
|
import yaml from "js-yaml";
|
|
|
|
|
|
|
2026-06-25 21:04:53 +08:00
|
|
|
|
export interface DocEntry {
|
|
|
|
|
|
tag: string;
|
|
|
|
|
|
icon: string;
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
description: string;
|
|
|
|
|
|
syntax: string;
|
|
|
|
|
|
props: { name: string; type: string; default?: string; desc: string }[];
|
2026-06-30 18:47:14 +08:00
|
|
|
|
/** Markdown body (everything after frontmatter ---) */
|
|
|
|
|
|
body: string;
|
2026-06-25 21:04:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-30 18:47:14 +08:00
|
|
|
|
/** Splits frontmatter and markdown body from a raw .md string. */
|
|
|
|
|
|
function parseFrontmatter(raw: string): Record<string, unknown> | null {
|
|
|
|
|
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
|
|
|
|
if (!match) return null;
|
|
|
|
|
|
try {
|
|
|
|
|
|
return yaml.load(match[1]) as Record<string, unknown>;
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-25 21:04:53 +08:00
|
|
|
|
|
2026-06-30 18:47:14 +08:00
|
|
|
|
function getBody(raw: string): string {
|
|
|
|
|
|
const match = raw.match(/^---\n[\s\S]*?\n---\n?([\s\S]*)$/);
|
|
|
|
|
|
return match ? match[1] : raw;
|
|
|
|
|
|
}
|
2026-06-25 21:04:53 +08:00
|
|
|
|
|
2026-06-30 18:54:34 +08:00
|
|
|
|
function parseEntry(raw: string): DocEntry | null {
|
|
|
|
|
|
const fm = parseFrontmatter(raw);
|
|
|
|
|
|
if (!fm) return null;
|
|
|
|
|
|
return {
|
|
|
|
|
|
tag: fm.tag as string,
|
|
|
|
|
|
icon: fm.icon as string,
|
|
|
|
|
|
title: fm.title as string,
|
|
|
|
|
|
description: fm.description as string,
|
|
|
|
|
|
syntax: fm.syntax as string,
|
|
|
|
|
|
props: (fm.props as DocEntry["props"]) ?? [],
|
|
|
|
|
|
body: getBody(raw),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2026-06-30 18:47:14 +08:00
|
|
|
|
|
2026-06-30 18:54:34 +08:00
|
|
|
|
// Static imports – each .md file is asset/source so imports are strings.
|
|
|
|
|
|
// Add a new import here when creating a new doc entry.
|
|
|
|
|
|
import mdDiceRaw from "../doc-entries/md-dice.md";
|
|
|
|
|
|
import mdTableRaw from "../doc-entries/md-table.md";
|
|
|
|
|
|
import mdLinkRaw from "../doc-entries/md-link.md";
|
|
|
|
|
|
import mdPinsRaw from "../doc-entries/md-pins.md";
|
|
|
|
|
|
import mdFontRaw from "../doc-entries/md-font.md";
|
|
|
|
|
|
import mdBgRaw from "../doc-entries/md-bg.md";
|
|
|
|
|
|
import mdBorderRaw from "../doc-entries/md-border.md";
|
|
|
|
|
|
import mdEmbedRaw from "../doc-entries/md-embed.md";
|
|
|
|
|
|
import mdDeckRaw from "../doc-entries/md-deck.md";
|
|
|
|
|
|
import mdYarnRaw from "../doc-entries/md-yarn-spinner.md";
|
|
|
|
|
|
import mdTokenRaw from "../doc-entries/md-token.md";
|
|
|
|
|
|
import mdTokenViewerRaw from "../doc-entries/md-token-viewer.md";
|
|
|
|
|
|
import mdCommanderRaw from "../doc-entries/md-commander.md";
|
2026-06-30 18:47:14 +08:00
|
|
|
|
|
2026-06-30 18:54:34 +08:00
|
|
|
|
const rawDocuments: string[] = [
|
|
|
|
|
|
mdDiceRaw,
|
|
|
|
|
|
mdTableRaw,
|
|
|
|
|
|
mdLinkRaw,
|
|
|
|
|
|
mdPinsRaw,
|
|
|
|
|
|
mdFontRaw,
|
|
|
|
|
|
mdBgRaw,
|
|
|
|
|
|
mdBorderRaw,
|
|
|
|
|
|
mdEmbedRaw,
|
|
|
|
|
|
mdDeckRaw,
|
|
|
|
|
|
mdYarnRaw,
|
|
|
|
|
|
mdTokenRaw,
|
|
|
|
|
|
mdTokenViewerRaw,
|
|
|
|
|
|
mdCommanderRaw,
|
|
|
|
|
|
];
|
2026-06-30 18:47:14 +08:00
|
|
|
|
|
2026-06-30 18:54:34 +08:00
|
|
|
|
let _entries: DocEntry[] | null = null;
|
2026-06-30 18:47:14 +08:00
|
|
|
|
|
2026-06-30 18:54:34 +08:00
|
|
|
|
function loadDocEntries(): DocEntry[] {
|
|
|
|
|
|
if (_entries) return _entries;
|
|
|
|
|
|
_entries = rawDocuments.map(parseEntry).filter(Boolean) as DocEntry[];
|
|
|
|
|
|
_entries.sort((a, b) => a.tag.localeCompare(b.tag));
|
|
|
|
|
|
return _entries;
|
2026-06-30 18:47:14 +08:00
|
|
|
|
}
|
2026-06-25 21:04:53 +08:00
|
|
|
|
|
2026-06-30 18:47:14 +08:00
|
|
|
|
export const docEntries = loadDocEntries();
|