diff --git a/src/app/changelog/page.jsx b/src/app/changelog/page.jsx index 65f4709..950e692 100644 --- a/src/app/changelog/page.jsx +++ b/src/app/changelog/page.jsx @@ -132,6 +132,75 @@ function RenderMarkdown({ text }) { continue } + // Tables: a |…| header row directly followed by a |---|---| + // separator row. Consumes every consecutive row line after that. + if (isTableRow(line) && i + 1 < lines.length && isTableSeparator(lines[i + 1])) { + let header = splitTableRow(line) + let aligns = tableAlignments(lines[i + 1]) + let rows = [] + let j = i + 2 + while (j < lines.length && isTableRow(lines[j])) { + rows.push(splitTableRow(lines[j])) + j++ + } + elements.push( +
+ + + + {header.map((cell, c) => ( + + ))} + + + + {rows.map((row, r) => ( + + {row.map((cell, c) => ( + + ))} + + ))} + +
+ {renderInline(cell)} +
+ {renderInline(cell)} +
+
+ ) + i = j - 1 + continue + } + + // Blockquotes: consecutive `>` lines folded into one
+ if (/^\s*>/.test(line)) { + let quoted = [] + let j = i + while (j < lines.length && /^\s*>/.test(lines[j])) { + quoted.push(lines[j].replace(/^\s*>\s?/, '')) + j++ + } + elements.push( +
+ {quoted.filter(q => q.trim()).map((q, qi) => ( +

{renderInline(q)}

+ ))} +
+ ) + i = j - 1 + continue + } + // Empty lines if (line.trim() === '') continue @@ -159,6 +228,37 @@ function RenderMarkdown({ text }) { return
{elements}
} +// A GFM table row: the line starts and ends with a pipe +function isTableRow(line) { + return /^\s*\|.*\|\s*$/.test(line) +} + +// The |---|:---:|---| separator line under a table header row +function isTableSeparator(line) { + return /^\s*\|(\s*:?-+:?\s*\|)+\s*$/.test(line) +} + +// Split a |…|…| row into trimmed cell strings, dropping the empty +// leading/trailing entries created by the outer pipes. +function splitTableRow(line) { + let cells = line.trim().split('|') + if (cells.length && cells[0].trim() === '') cells.shift() + if (cells.length && cells[cells.length - 1].trim() === '') cells.pop() + return cells.map(c => c.trim()) +} + +// Map each separator cell to a Tailwind text-align class: `:---:` → +// center, `---:` → right, everything else left. +function tableAlignments(sepLine) { + return splitTableRow(sepLine).map(c => { + let left = c.startsWith(':') + let right = c.endsWith(':') + if (left && right) return 'text-center' + if (right) return 'text-right' + return 'text-left' + }) +} + // Render inline markdown (bold, code, links) function renderInline(text) { if (!text) return text