);
return { push, node };
}
// Module color
function moduleColor(m) {
const map = {
orders: "#a78bfa",
kalk: "#f472b6",
"tg-bot": "#60a5fa",
seo: "#34d399",
auth: "#fb923c",
docs: "#94a3b8",
scaffold: "#cbd5e1",
watchdog: "#ec4899",
notifications: "#f59e0b",
spec: "#a3e635",
};
return map[m] || "#a1a1aa";
}
function ModuleTag({ name, small }) {
return (
{name}
);
}
// Tiny syntax-highlighted YAML
function highlightYaml(src) {
return src
.split("\n")
.map((ln) => {
// comment
let m = ln.match(/^(\s*)(#.*)$/);
if (m) return `${m[1]}${escapeHtml(m[2])}`;
// key: value
m = ln.match(/^(\s*-?\s*)([A-Za-z_][\w-]*)(\s*:\s*)(.*)$/);
if (m) {
const val = m[4];
const valHtml = val
? (val.startsWith('"') || val.startsWith("'")
? `${escapeHtml(val)}`
: (/^-?\d+(\.\d+)?$/.test(val) ? `${escapeHtml(val)}` : escapeHtml(val)))
: "";
return `${escapeHtml(m[1])}${escapeHtml(m[2])}${escapeHtml(m[3])}${valHtml}`;
}
return escapeHtml(ln);
})
.join("\n");
}
function escapeHtml(s) { return s.replace(/[&<>]/g, (c) => ({ "&": "&", "<": "<", ">": ">" }[c])); }
function YamlBlock({ code }) {
return ;
}
// Tiny markdown renderer (headings, lists, paragraphs, inline `code`).
// We highlight individual "points" — lines/blocks corresponding to subsections —
// by injecting className when a section title matches a known reference.
function renderMarkdown(src, highlights = {}) {
// highlights: { "3.1": "active", "1.2": "alert" }
const lines = src.split("\n");
const out = [];
let i = 0;
let currentPt = null; // section like "3.1" or "1"
let currentTone = null;
const pushP = (chunk) => {
const html = chunk
.replace(/`([^`]+)`/g, '$1')
.replace(/\*\*([^*]+)\*\*/g, '$1');
out.push(html);
};
while (i < lines.length) {
const ln = lines[i];
// Headings — h2 (## …), h3 (### …)
let m = ln.match(/^##\s+(\d+(?:\.\d+)?)\.\s+(.*)$/);
if (m) {
const pt = m[1];
const title = m[2];
const tone = highlights[pt];
currentPt = pt;
currentTone = tone;
const ptClass = tone === "active" ? "pt pt-active" : tone === "alert" ? "pt pt-alert" : "pt";
out.push(`
${pt}. ${escapeHtml(title)}
`);
i++;
// collect content until next h2/h3 or eof
let buf = [];
while (i < lines.length && !lines[i].match(/^##\s+\d/) && !lines[i].match(/^###\s+\d/) ) {
buf.push(lines[i]); i++;
}
out.push(renderBlock(buf.join("\n")));
out.push(`
`);
continue;
}
m = ln.match(/^###\s+(\d+\.\d+)\s+(.*)$/);
if (m) {
const pt = m[1];
const title = m[2];
const tone = highlights[pt];
const ptClass = tone === "active" ? "pt pt-active" : tone === "alert" ? "pt pt-alert" : "pt";
out.push(`
${pt} ${escapeHtml(title)}
`);
i++;
let buf = [];
while (i < lines.length && !lines[i].match(/^##\s+\d/) && !lines[i].match(/^###\s+\d/)) {
buf.push(lines[i]); i++;
}
out.push(renderBlock(buf.join("\n")));
out.push(`
`);
continue;
}
if (ln.startsWith("# ")) {
out.push(`
${escapeHtml(ln.slice(2))}
`);
i++;
continue;
}
// skip blank
i++;
}
return out.join("\n");
}
function renderBlock(src) {
const lines = src.split("\n");
let html = "";
let listOpen = false;
let para = [];
const flushPara = () => {
if (para.length) {
html += `
`;
para = [];
}
};
const closeList = () => { if (listOpen) { html += ""; listOpen = false; } };
for (const ln of lines) {
if (/^\s*-\s+/.test(ln)) {
flushPara();
if (!listOpen) { html += "