feat: add markdown table renderer to the workbench ui (#2255)

This commit is contained in:
Iván Martínez
2026-06-03 15:44:46 +02:00
committed by GitHub
parent f2e6685951
commit d1ac2e29ad

View File

@@ -1369,10 +1369,42 @@
.markdown p,
.markdown ul,
.markdown ol,
.markdown table,
.markdown pre {
margin: 0;
}
.markdown-table-scroll {
max-width: 100%;
overflow-x: auto;
}
.markdown table {
width: 100%;
border-collapse: collapse;
overflow: hidden;
border: 1px solid var(--border-soft);
border-radius: 12px;
background: rgba(0, 0, 0, 0.14);
font-size: 0.94em;
white-space: normal;
}
.markdown th,
.markdown td {
padding: 8px 10px;
border: 1px solid var(--border-soft);
text-align: left;
vertical-align: top;
overflow-wrap: break-word;
}
.markdown th {
color: rgba(255, 255, 255, 0.96);
background: rgba(255, 255, 255, 0.08);
font-weight: 750;
}
.markdown ul,
.markdown ol {
padding-left: 22px;
@@ -5022,12 +5054,32 @@
list = null;
}
};
for (const raw of lines) {
for (let index = 0; index < lines.length; index += 1) {
const raw = lines[index];
const line = raw.trimEnd();
if (!line.trim()) {
closeList();
continue;
}
const nextLine = lines[index + 1]?.trimEnd() || "";
if (isMarkdownTableHeader(line, nextLine)) {
closeList();
const header = parseMarkdownTableRow(line);
const alignments = parseMarkdownTableAlignments(nextLine);
const rows = [];
index += 2;
while (index < lines.length) {
const rowLine = lines[index].trimEnd();
if (!rowLine.trim() || !rowLine.includes("|")) break;
const row = parseMarkdownTableRow(rowLine);
if (row.length < 2) break;
rows.push(row);
index += 1;
}
index -= 1;
html.push(renderMarkdownTable(header, alignments, rows));
continue;
}
const bullet = line.match(/^\s*[-*]\s+(.+)$/);
const ordered = line.match(/^\s*\d+[.)]\s+(.+)$/);
const heading = line.match(/^(#{1,3})\s+(.+)$/);
@@ -5050,6 +5102,49 @@
return html.join("");
}
function isMarkdownTableHeader(headerLine, dividerLine) {
const divider = parseMarkdownTableRow(dividerLine);
return headerLine.includes("|") &&
parseMarkdownTableRow(headerLine).length >= 2 &&
/^:?-{3,}:?$/.test(divider[0] || "") &&
divider.every(cell => /^:?-{3,}:?$/.test(cell));
}
function parseMarkdownTableRow(line) {
let trimmed = String(line || "").trim();
if (trimmed.startsWith("|")) trimmed = trimmed.slice(1);
if (trimmed.endsWith("|")) trimmed = trimmed.slice(0, -1);
return trimmed.split("|").map(cell => cell.trim());
}
function parseMarkdownTableAlignments(line) {
return parseMarkdownTableRow(line).map(cell => {
const left = cell.startsWith(":");
const right = cell.endsWith(":");
if (left && right) return "center";
if (right) return "right";
return "left";
});
}
function renderMarkdownTable(header, alignments, rows) {
const cellStyle = index => alignments[index] && alignments[index] !== "left"
? ` style="text-align:${alignments[index]}"`
: "";
const columnCount = header.length;
const renderCells = (cells, tag) => Array.from({ length: columnCount }, (_unused, index) =>
`<${tag}${cellStyle(index)}>${inlineMarkdown(cells[index] || "")}</${tag}>`
).join("");
return `
<div class="markdown-table-scroll">
<table>
<thead><tr>${renderCells(header, "th")}</tr></thead>
<tbody>${rows.map(row => `<tr>${renderCells(row, "td")}</tr>`).join("")}</tbody>
</table>
</div>
`;
}
function inlineMarkdown(value) {
let text = escapeHtml(value);
text = text.replace(/`([^`]+)`/g, "<code>$1</code>");