// A clean, self-contained HTML page for a Ladder, in the spirit of a // Claude Artifact: readable typography, light/dark aware, no build step // or external resources, collapsible nesting via plain
so it // needs no JS at all. import type { ResolvedRung } from "../../engine/ladderRender.js"; function escapeHtml(s: string): string { return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function renderNode(rung: ResolvedRung, depth: number): string { const sources = rung.sources.length ? `` : ""; const touches = rung.touches?.length ? `

touches: ${rung.touches.map((t) => `${escapeHtml(t)}`).join(", ")}

` : ""; const children = rung.children.map((c) => renderNode(c, depth + 1)).join(""); const header = `${escapeHtml(rung.kind)} ${escapeHtml(rung.path)}`; const body = `

${escapeHtml(rung.summary)}

${sources}${touches}${children ? `
${children}
` : ""}`; if (depth === 0) { return `
${header}${body}
`; } //
by default so the page reads top-to-bottom like the // text/JSON forms; a reader can collapse branches they don't care about. return `
${header}${body}
`; } export function renderHtml(tree: ResolvedRung, meta: { repoSlug: string; generatedAt: string; stats: { rungs: number; notes: number } }): string { return ` Ladder: ${escapeHtml(meta.repoSlug)}

Ladder: ${escapeHtml(meta.repoSlug)}

${meta.stats.rungs} rungs, from ${meta.stats.notes} git notes. Generated ${escapeHtml(meta.generatedAt)}.

${renderNode(tree, 0)} `; }