From afe1cd0918e182b8107ffa81b9f9d6cdec4615ae Mon Sep 17 00:00:00 2001 From: Clawd Date: Sat, 28 Feb 2026 13:45:59 -0800 Subject: Add markdown table rendering support - Add renderTable() function to parse markdown tables - Process tables before other markdown transformations - Handle header row, separator row, and body rows - Add table CSS styling (borders, alternating row colors, padding) --- renderer/src/components/DocumentPane.tsx | 67 +++++++++++++++++++++++++++++++- renderer/src/styles/globals.css | 19 +++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/renderer/src/components/DocumentPane.tsx b/renderer/src/components/DocumentPane.tsx index a22ecad..c2e1b2c 100644 --- a/renderer/src/components/DocumentPane.tsx +++ b/renderer/src/components/DocumentPane.tsx @@ -9,9 +9,72 @@ interface DocumentPaneProps { showOnboarding?: boolean; } +function renderTable(tableLines: string[]): string { + if (tableLines.length < 2) return tableLines.join("\n"); + + const parseRow = (line: string): string[] => { + return line + .split("|") + .slice(1, -1) // Remove empty first/last from |col|col| + .map((cell) => cell.trim()); + }; + + const headerCells = parseRow(tableLines[0]); + // Skip separator row (index 1) + const bodyRows = tableLines.slice(2); + + let html = ''; + headerCells.forEach((cell) => { + html += ``; + }); + html += ''; + + bodyRows.forEach((row) => { + if (row.trim()) { + html += ''; + parseRow(row).forEach((cell) => { + html += ``; + }); + html += ''; + } + }); + + html += '
${cell}
${cell}
'; + return html; +} + function renderMarkdown(md: string): string { + // First, handle tables (before other transformations) + const lines = md.split("\n"); + const processedLines: string[] = []; + let tableBuffer: string[] = []; + let inTable = false; + + for (const line of lines) { + const isTableLine = /^\|.*\|$/.test(line.trim()); + + if (isTableLine) { + inTable = true; + tableBuffer.push(line); + } else { + if (inTable && tableBuffer.length > 0) { + processedLines.push(renderTable(tableBuffer)); + tableBuffer = []; + inTable = false; + } + processedLines.push(line); + } + } + + // Handle table at end of content + if (tableBuffer.length > 0) { + processedLines.push(renderTable(tableBuffer)); + } + + let result = processedLines.join("\n"); + return ( - md + result // Headers .replace(/^### (.*$)/gm, "

$1

") .replace(/^## (.*$)/gm, "

$1

") @@ -43,6 +106,8 @@ function renderMarkdown(md: string): string { .replace(/(<\/pre>)<\/p>/g, "$1") .replace(/

()<\/p>/g, "$1") + .replace(/

()/g, "$1") + .replace(/(<\/table>)<\/p>/g, "$1") ); } diff --git a/renderer/src/styles/globals.css b/renderer/src/styles/globals.css index e1d945a..380a744 100644 --- a/renderer/src/styles/globals.css +++ b/renderer/src/styles/globals.css @@ -200,6 +200,25 @@ body { .document-content.rendered li.task.done { color: var(--success); } +.document-content.rendered table { + width: 100%; + border-collapse: collapse; + margin: 16px 0; + font-size: 14px; +} +.document-content.rendered th, +.document-content.rendered td { + padding: 10px 12px; + text-align: left; + border: 1px solid var(--border); +} +.document-content.rendered th { + background: var(--bg-tertiary); + font-weight: 600; +} +.document-content.rendered tr:nth-child(even) td { + background: var(--bg-secondary); +} .document-content.rendered mark.review { background: var(--warning); color: black; -- cgit v1.2.3