${escapeHtml(title)}
${subtitle ? `${escapeHtml(subtitle)}
` : ''}Palette
Typography
Components
Production-quality artifact
Sample card showing how surfaces, borders, and accent text behave in this system.
/** * Build a showcase HTML page from a DESIGN.md so the user can see what each * design system looks like *before* generating anything. We don't try to * render a unique product mockup — we extract the palette, typography, and * a couple of component conventions, then drop them into one fixed * template. The full DESIGN.md is rendered below as prose for reference. * * Parsing is deliberately permissive: imported systems vary in section * naming and bullet style, so we use loose regexes and fall back to sane * defaults when a token isn't found. */ export function renderDesignSystemPreview(id, raw) { const titleMatch = /^#\s+(.+?)\s*$/m.exec(raw); const title = cleanTitle(titleMatch?.[1] ?? id); const subtitle = extractSubtitle(raw); const colors = extractColors(raw); const fonts = extractFonts(raw); const bg = pickColor(colors, ['page background', 'background', 'canvas', 'paper', 'bg ', 'page bg']) ?? pickColor(colors, ['white']) ?? '#ffffff'; const fg = pickColor(colors, ['heading', 'foreground', 'ink', 'fg', 'text', 'navy', 'graphite']) ?? '#111111'; // Accent: brand/primary names first, then fall back to the first color // that doesn't look like a neutral white/black/grey so we always show // something punchy in the showcase header. const accent = pickColor(colors, ['primary brand', 'brand primary', 'primary', 'brand', 'accent']) ?? firstNonNeutral(colors) ?? '#2f6feb'; const muted = pickColor(colors, ['muted', 'secondary', 'neutral', 'subtle', 'caption']) ?? '#777777'; const border = pickColor(colors, ['border', 'divider', 'rule', 'stroke']) ?? '#e5e5e5'; const surface = pickColor(colors, ['surface', 'card', 'background-secondary', 'panel', 'elevated']) ?? '#ffffff'; const display = fonts.display ?? fonts.heading ?? "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif"; const body = fonts.body ?? display; const mono = fonts.mono ?? "ui-monospace, 'JetBrains Mono', monospace"; const renderedMarkdown = renderMarkdownLite(raw); return `
${escapeHtml(subtitle)}
` : ''}Sample card showing how surfaces, borders, and accent text behave in this system.
');
inCode = true;
} else {
out.push('');
inCode = false;
}
i++;
continue;
}
if (inCode) {
out.push(escapeHtml(raw));
i++;
continue;
}
if (!line.trim()) {
closeList();
closeBlockquote();
i++;
continue;
}
// GFM pipe table — at least a header row, a separator row of dashes,
// and one body row. Look ahead from `i` so we can consume the whole
// block in one step.
if (looksLikeTableHeader(line) && i + 1 < lines.length && isTableSeparator(lines[i + 1] ?? '')) {
closeList();
closeBlockquote();
const headerCells = splitTableRow(line);
const aligns = parseAlignments(lines[i + 1] ?? '', headerCells.length);
const bodyRows = [];
let j = i + 2;
while (j < lines.length) {
const next = (lines[j] ?? '').trimEnd();
if (!next.trim() || !next.includes('|')) break;
bodyRows.push(splitTableRow(next));
j++;
}
out.push(renderTable(headerCells, bodyRows, aligns));
i = j;
continue;
}
// ATX headings #..####
const h = /^(#{1,4})\s+(.+)$/.exec(line);
if (h) {
closeList();
closeBlockquote();
const level = h[1].length;
out.push(`'); inBlockquote = true; } out.push(`${inline(bq[1] || '')}
`); i++; continue; } closeBlockquote(); const li = /^([-*])\s+(.+)$/.exec(line); if (li) { if (inList !== 'ul') { closeList(); out.push(''); inList = 'ul'; } out.push(`
- ${inline(li[2])}
`); i++; continue; } const oli = /^\d+\.\s+(.+)$/.exec(line); if (oli) { if (inList !== 'ol') { closeList(); out.push(''); inList = 'ol'; } out.push(`
- ${inline(oli[1])}
`); i++; continue; } closeList(); out.push(`${inline(line)}
`); i++; } closeList(); closeBlockquote(); if (inCode) out.push(''); return out.join('\n'); } function looksLikeTableHeader(line) { const trimmed = line.trim(); if (!trimmed.includes('|')) return false; // At least one pipe between non-pipe content. return /\|/.test(trimmed.replace(/^\||\|$/g, '')); } function isTableSeparator(line) { const trimmed = line.trim(); if (!trimmed.includes('|')) return false; // Each cell must be only dashes / colons / whitespace. return splitTableRow(trimmed).every((cell) => /^:?-{1,}:?$/.test(cell.trim())); } function splitTableRow(line) { let s = line.trim(); if (s.startsWith('|')) s = s.slice(1); if (s.endsWith('|')) s = s.slice(0, -1); return s.split('|').map((c) => c.trim()); } function parseAlignments(separatorLine, count) { const cells = splitTableRow(separatorLine); const aligns = []; for (let k = 0; k < count; k++) { const cell = (cells[k] ?? '').trim(); const left = cell.startsWith(':'); const right = cell.endsWith(':'); if (left && right) aligns.push('center'); else if (right) aligns.push('right'); else aligns.push(null); } return aligns; } function renderTable(header, rows, aligns) { const th = header .map((cell, k) => { const align = aligns[k]; const attr = align ? ` align="${align}"` : ''; return `${inline(cell)} `; }) .join(''); const body = rows .map((row) => { const tds = row .map((cell, k) => { const align = aligns[k]; const attr = align ? ` align="${align}"` : ''; return `${inline(cell)} `; }) .join(''); return `${tds} `; }) .join(''); return ``; } function inline(s) { // Process inline tokens. Order matters: code spans first so their content // isn't further parsed; then bold/italic; then links; finally bare URLs. const escaped = escapeHtml(s); return escaped .replace(/`([^`]+)`/g, '
${th} ${body}$1') .replace(/\*\*([^*]+)\*\*/g, '$1') .replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/g, '$1$2') .replace(/(^|[\s(])_([^_\n]+)_(?=[\s).,;:!?]|$)/g, '$1$2') .replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, '$1'); }