Opas-sivun markdown-renderöijä laajennettu: taulukot, inline-muotoilu, listat
Lisätty tuki: - Taulukot (| header | ... | -parsinta, thead/tbody, border-collapse) - Inline: **bold**, *italic*, \`code\` (kaikissa elementeissä) - Numeroidut listat (1. 2. 3.) - Parempi tyhjien rivien käsittely (8px spacer, ei <br>) - Otsikkojen border-bottom h1/h2:lle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -906,18 +906,71 @@ OUTPUT FORMAT:
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
function renderMd(md) {
|
function renderMd(md) {
|
||||||
|
const lines = md.split('\n');
|
||||||
let html = '', inCode = false, lang = '', buf = '';
|
let html = '', inCode = false, lang = '', buf = '';
|
||||||
for (const line of md.split('\n')) {
|
let inTable = false, tableRows = [];
|
||||||
if (line.startsWith('```')) { if (inCode) { html += `<pre class="code-block"><code class="language-${lang}">${buf.replace(/</g,'<')}</code></pre>`; inCode=false; buf=''; } else { inCode=true; lang=line.slice(3).trim()||'plaintext'; } continue; }
|
|
||||||
if (inCode) { buf += (buf?'\n':'') + line; continue; }
|
function inline(text) {
|
||||||
if (!line.trim()) { html += '<br>'; continue; }
|
return text
|
||||||
if (line.startsWith('# ')) html += `<h1 style="color:#e6edf3;font-size:24px;margin:24px 0 8px;border-bottom:1px solid var(--border);padding-bottom:6px">${line.slice(2)}</h1>`;
|
.replace(/\*\*(.+?)\*\*/g, '<strong style="color:#e6edf3">$1</strong>')
|
||||||
else if (line.startsWith('## ')) html += `<h2 style="color:#e6edf3;font-size:20px;margin:20px 0 8px">${line.slice(3)}</h2>`;
|
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
||||||
else if (line.startsWith('### ')) html += `<h3 style="color:#e6edf3;font-size:16px;margin:16px 0 6px">${line.slice(4)}</h3>`;
|
.replace(/`([^`]+)`/g, '<code style="background:var(--panel);padding:1px 5px;border-radius:3px;font-size:13px;color:#e6edf3">$1</code>');
|
||||||
else if (line.startsWith('---')) html += '<hr style="border:none;border-top:1px solid var(--border);margin:16px 0">';
|
|
||||||
else if (line.match(/^[\-\*] /)) html += `<div style="padding:2px 0 2px 20px">${line.replace(/^[\-\*] /,'• ').replace(/\*\*(.+?)\*\*/g,'<strong>$1</strong>').replace(/`(.+?)`/g,'<code style="background:var(--panel);padding:1px 4px;border-radius:3px;font-size:13px">$1</code>')}</div>`;
|
|
||||||
else html += `<p style="margin:4px 0">${line.replace(/\*\*(.+?)\*\*/g,'<strong>$1</strong>').replace(/`(.+?)`/g,'<code style="background:var(--panel);padding:1px 4px;border-radius:3px;font-size:13px">$1</code>')}</p>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function flushTable() {
|
||||||
|
if (!inTable || tableRows.length < 2) { inTable = false; tableRows = []; return; }
|
||||||
|
const hdr = tableRows[0].split('|').filter(c => c.trim());
|
||||||
|
const body = tableRows.slice(2);
|
||||||
|
html += '<div style="overflow-x:auto;margin:12px 0"><table style="width:100%;border-collapse:collapse;font-size:14px">';
|
||||||
|
html += '<thead><tr>' + hdr.map(c => `<th style="text-align:left;padding:8px 12px;border-bottom:2px solid var(--border);color:var(--accent);font-weight:600">${inline(c.trim())}</th>`).join('') + '</tr></thead><tbody>';
|
||||||
|
for (const row of body) {
|
||||||
|
const cells = row.split('|').filter(c => c.trim());
|
||||||
|
if (cells.length) html += '<tr>' + cells.map(c => `<td style="padding:6px 12px;border-bottom:1px solid #21262d">${inline(c.trim())}</td>`).join('') + '</tr>';
|
||||||
|
}
|
||||||
|
html += '</tbody></table></div>';
|
||||||
|
inTable = false; tableRows = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
// Koodiblokit
|
||||||
|
if (line.startsWith('```')) {
|
||||||
|
if (inCode) {
|
||||||
|
html += `<pre class="code-block"><code class="language-${lang}">${buf.replace(/</g,'<')}</code></pre>`;
|
||||||
|
inCode = false; buf = '';
|
||||||
|
} else {
|
||||||
|
flushTable();
|
||||||
|
inCode = true; lang = line.slice(3).trim() || 'plaintext';
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inCode) { buf += (buf ? '\n' : '') + line; continue; }
|
||||||
|
|
||||||
|
// Taulukot
|
||||||
|
if (line.includes('|') && line.trim().startsWith('|')) {
|
||||||
|
if (!inTable) inTable = true;
|
||||||
|
tableRows.push(line);
|
||||||
|
continue;
|
||||||
|
} else { flushTable(); }
|
||||||
|
|
||||||
|
// Tyhjä rivi
|
||||||
|
if (!line.trim()) { html += '<div style="height:8px"></div>'; continue; }
|
||||||
|
|
||||||
|
// Otsikot
|
||||||
|
if (line.startsWith('# ')) { html += `<h1 style="color:#e6edf3;font-size:26px;margin:28px 0 10px;border-bottom:1px solid var(--border);padding-bottom:8px">${inline(line.slice(2))}</h1>`; continue; }
|
||||||
|
if (line.startsWith('## ')) { html += `<h2 style="color:#e6edf3;font-size:21px;margin:24px 0 8px;border-bottom:1px solid #21262d;padding-bottom:6px">${inline(line.slice(3))}</h2>`; continue; }
|
||||||
|
if (line.startsWith('### ')) { html += `<h3 style="color:#e6edf3;font-size:17px;margin:18px 0 6px">${inline(line.slice(4))}</h3>`; continue; }
|
||||||
|
|
||||||
|
// Viiva
|
||||||
|
if (line.match(/^-{3,}$/)) { html += '<hr style="border:none;border-top:1px solid var(--border);margin:20px 0">'; continue; }
|
||||||
|
|
||||||
|
// Listat
|
||||||
|
if (line.match(/^[\-\*] /)) { html += `<div style="padding:2px 0 2px 20px">${inline(line.replace(/^[\-\*] /, '• '))}</div>`; continue; }
|
||||||
|
if (line.match(/^\d+\. /)) { html += `<div style="padding:2px 0 2px 20px">${inline(line)}</div>`; continue; }
|
||||||
|
|
||||||
|
// Normaali teksti
|
||||||
|
html += `<p style="margin:4px 0">${inline(line)}</p>`;
|
||||||
|
}
|
||||||
|
flushTable();
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
// === Settings panel ===
|
// === Settings panel ===
|
||||||
|
|||||||
Reference in New Issue
Block a user