arnaucube
arnaucube/study-labPublic Self-hosted repository
fix tables rendering
arnaucube git@arnaucube.com
Thu, 20 Aug 2026 21:52:23 +0200
commit

4f34cebf8db9e15c4cd4d042432048706ad4c0cd

parent

a04001efe397605c9da275153600aa71a8456eb6

2 files changed, 66 insertions(+), 1 deletions(-)

jump to
M app.js → app.js

@@ -291,6 +291,47 @@ output = output.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');

return output; } + function tableCells(line) { + let source = line.trim(); + if (source.startsWith('|')) source = source.slice(1); + if (source.endsWith('|') && !source.endsWith('\\|')) source = source.slice(0, -1); + const cells = []; + let cell = ''; + let code = false; + for (let index = 0; index < source.length; index += 1) { + const char = source[index]; + if (char === '\\' && source[index + 1] === '|') { + cell += '|'; + index += 1; + } else if (char === '`') { + code = !code; + cell += char; + } else if (char === '|' && !code) { + cells.push(cell.trim()); + cell = ''; + } else cell += char; + } + cells.push(cell.trim()); + return cells; + } + + function tableDelimiter(line) { + const cells = tableCells(line); + if (!line.includes('|') || !cells.length || cells.some(cell => !/^:?-{3,}:?$/.test(cell))) return null; + return cells.map(cell => cell.startsWith(':') && cell.endsWith(':') ? 'center' : cell.endsWith(':') ? 'right' : cell.startsWith(':') ? 'left' : ''); + } + + function renderTable(header, alignments, rows) { + const cellHTML = (cell, tag, index) => { + const alignment = alignments[index] ? ` style="text-align: ${alignments[index]}"` : ''; + const scope = tag === 'th' ? ' scope="col"' : ''; + return `<${tag}${scope}${alignment}>${inlineMarkdown(cell || '')}</${tag}>`; + }; + const head = header.map((cell, index) => cellHTML(cell, 'th', index)).join(''); + const body = rows.map(row => `<tr>${header.map((_, index) => cellHTML(row[index], 'td', index)).join('')}</tr>`).join(''); + return `<div class="table-scroll"><table><thead><tr>${head}</tr></thead>${body ? `<tbody>${body}</tbody>` : ''}</table></div>`; + } + function renderMath(source, displayMode) { if (!globalThis.katex) return `<code class="math-fallback">${escapeHTML(source)}</code>`; try { return katex.renderToString(source, { displayMode, throwOnError: false, strict: false, trust: false }); }

@@ -317,7 +358,24 @@ paragraph = [];

}; const closeList = () => { if (list) html.push(`</${list}>`); list = null; }; - for (const line of lines) { + for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) { + const line = lines[lineIndex]; + const alignments = lineIndex + 1 < lines.length ? tableDelimiter(lines[lineIndex + 1]) : null; + if (alignments) { + const header = tableCells(line); + if (header.length === alignments.length) { + flushParagraph(); closeList(); + const rows = []; + lineIndex += 2; + while (lineIndex < lines.length && lines[lineIndex].trim() && lines[lineIndex].includes('|')) { + rows.push(tableCells(lines[lineIndex])); + lineIndex += 1; + } + html.push(renderTable(header, alignments, rows)); + lineIndex -= 1; + continue; + } + } const heading = line.match(/^(#{1,3})\s+(.+)/); const bullet = line.match(/^\s*[-*+]\s+(.+)/); const numbered = line.match(/^\s*\d+[.)]\s+(.+)/);
M styles.css → styles.css

@@ -153,6 +153,13 @@ .answer-body pre { overflow: auto; padding: 15px; background: #202724; color: #f3f5f2; border-radius: 12px; line-height: 1.5; tab-size: 2; }

.answer-body pre code { background: none; padding: 0; font-size: .84rem; } .answer-body blockquote { border-left: 3px solid var(--sage); margin-left: 0; padding-left: 15px; color: var(--muted); } .answer-body a { color: var(--sage-dark); text-underline-offset: 3px; } +.answer-body .table-scroll { max-width: 100%; margin: 0 0 1em; overflow-x: auto; border: 1px solid var(--line); border-radius: 10px; } +.answer-body table { width: 100%; border-collapse: collapse; background: rgba(255,255,255,.45); font-size: .92em; overflow-wrap: normal; } +.answer-body th, .answer-body td { padding: 9px 12px; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; } +.answer-body th:last-child, .answer-body td:last-child { border-right: 0; } +.answer-body tbody tr:last-child td { border-bottom: 0; } +.answer-body th { background: #e5e9e4; color: var(--ink); font-weight: 750; } +.answer-body tbody tr:nth-child(even) { background: rgba(230,233,227,.46); } .answer-body .katex-display { overflow-x: auto; overflow-y: hidden; padding: 5px 0; } .answer-attribution { display: flex; align-items: baseline; gap: 6px; min-width: 0; margin-top: 8px; color: var(--muted); line-height: 1.2; } .answer-attribution span { overflow: hidden; font-size: .65rem; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }