Opas-välilehti: GUIDE.md renderöidään sivustolle omana näkymänä
Uusi "Opas"-välilehti (panel-guide) lataa GUIDE.md:n fetchillä ja renderöi sen inline markdown→HTML -parserilla: - Otsikot (h1-h3) GitHub-tyylisesti - Koodiblokit highlight.js-korostuksella - Taulukot (header + body, border-collapse) - Listat (bullet + numeroitu) - Inline-muotoilu: **bold**, *italic*, `code` - Horisontaaliviivat GUIDE.md siirretty static/-hakemistoon jotta hub servaa sen suoraan. Navigointi: #guide hash tai klikkaa "Opas"-välilehteä. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -143,6 +143,13 @@
|
||||
}
|
||||
.code-output .hljs { background: transparent; padding: 0; }
|
||||
|
||||
#guide-content { scrollbar-color: #30363d transparent; }
|
||||
#guide-content h1 { color: #e6edf3; }
|
||||
#guide-content h2 { color: #e6edf3; }
|
||||
#guide-content a { color: #58a6ff; }
|
||||
#guide-content table { border: 1px solid #30363d; border-radius: 6px; overflow: hidden; }
|
||||
#guide-content pre { scrollbar-color: #30363d transparent; }
|
||||
|
||||
.code-task-card {
|
||||
background: #0d1117;
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -701,6 +708,7 @@
|
||||
<div class="main-tab active" onclick="switchMainTab('network')" data-i18n="tab_network">Laskentaverkko</div>
|
||||
<div class="main-tab" onclick="switchMainTab('codelab')" data-i18n="tab_codelab">Koodilaboratorio</div>
|
||||
<div class="main-tab" onclick="switchMainTab('agents')" data-i18n="tab_agents">Kipinä Agentic Playground</div>
|
||||
<div class="main-tab" onclick="switchMainTab('guide')" data-i18n="tab_guide">Opas</div>
|
||||
</div>
|
||||
|
||||
<!-- PANEELI 1: Laskentaverkko -->
|
||||
@@ -1115,6 +1123,13 @@
|
||||
</div>
|
||||
</div><!-- /panel-agents -->
|
||||
|
||||
<!-- PANEELI 4: Opas -->
|
||||
<div id="panel-guide" class="main-panel">
|
||||
<div id="guide-content" style="max-width:800px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:var(--text-color);line-height:1.7;font-size:15px">
|
||||
<p style="color:#8b949e">Ladataan opasta...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
@@ -1469,7 +1484,7 @@
|
||||
|
||||
// URL-hash navigointi
|
||||
const initHash = window.location.hash.replace('#', '');
|
||||
if (['codelab', 'agents'].includes(initHash)) {
|
||||
if (['codelab', 'agents', 'guide'].includes(initHash)) {
|
||||
switchMainTab(initHash);
|
||||
}
|
||||
|
||||
@@ -3463,6 +3478,111 @@ Write the corrected code.`;
|
||||
if (window.selectAgent) window.selectAgent('client');
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// GUIDE.md:n lataus ja renderöinti
|
||||
(async function loadGuide() {
|
||||
const container = document.getElementById('guide-content');
|
||||
if (!container) return;
|
||||
try {
|
||||
const res = await fetch('/GUIDE.md');
|
||||
if (!res.ok) { container.innerHTML = '<p style="color:#f85149">Oppaan lataus epäonnistui.</p>'; return; }
|
||||
const md = await res.text();
|
||||
container.innerHTML = renderMarkdown(md);
|
||||
// Syntaksikorostus koodiblokeille
|
||||
container.querySelectorAll('pre code').forEach(block => {
|
||||
if (typeof hljs !== 'undefined') hljs.highlightElement(block);
|
||||
});
|
||||
} catch(e) {
|
||||
container.innerHTML = '<p style="color:#f85149">Virhe: ' + e.message + '</p>';
|
||||
}
|
||||
})();
|
||||
|
||||
function renderMarkdown(md) {
|
||||
const lines = md.split('\n');
|
||||
let html = '';
|
||||
let inCode = false;
|
||||
let codeLang = '';
|
||||
let codeBuffer = '';
|
||||
let inTable = false;
|
||||
let tableRows = [];
|
||||
|
||||
function flushTable() {
|
||||
if (!inTable) return;
|
||||
inTable = false;
|
||||
if (tableRows.length < 2) return;
|
||||
const headerCells = tableRows[0].split('|').filter(c => c.trim());
|
||||
const bodyRows = tableRows.slice(2); // Skip header + separator
|
||||
html += '<div style="overflow-x:auto;margin:16px 0"><table style="width:100%;border-collapse:collapse;font-size:14px">';
|
||||
html += '<thead><tr>' + headerCells.map(c => `<th style="text-align:left;padding:8px 12px;border-bottom:2px solid #30363d;color:#58a6ff;font-weight:600">${inlineFormat(c.trim())}</th>`).join('') + '</tr></thead>';
|
||||
html += '<tbody>';
|
||||
for (const row of bodyRows) {
|
||||
const cells = row.split('|').filter(c => c.trim());
|
||||
if (cells.length === 0) continue;
|
||||
html += '<tr>' + cells.map(c => `<td style="padding:6px 12px;border-bottom:1px solid #21262d">${inlineFormat(c.trim())}</td>`).join('') + '</tr>';
|
||||
}
|
||||
html += '</tbody></table></div>';
|
||||
tableRows = [];
|
||||
}
|
||||
|
||||
function inlineFormat(text) {
|
||||
return text
|
||||
.replace(/`([^`]+)`/g, '<code style="background:#161b22;padding:2px 6px;border-radius:3px;font-size:13px;color:#e6edf3">$1</code>')
|
||||
.replace(/\*\*([^*]+)\*\*/g, '<strong style="color:#e6edf3">$1</strong>')
|
||||
.replace(/\*([^*]+)\*/g, '<em>$1</em>');
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
// Koodiblokit
|
||||
if (line.startsWith('```')) {
|
||||
if (inCode) {
|
||||
html += `<pre style="background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:14px;margin:12px 0;overflow-x:auto"><code class="language-${codeLang}">${codeBuffer.replace(/</g,'<')}</code></pre>`;
|
||||
inCode = false;
|
||||
codeBuffer = '';
|
||||
} else {
|
||||
flushTable();
|
||||
inCode = true;
|
||||
codeLang = line.slice(3).trim() || 'plaintext';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (inCode) { codeBuffer += (codeBuffer ? '\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:28px;margin:32px 0 12px;border-bottom:1px solid #30363d;padding-bottom:8px">${inlineFormat(line.slice(2))}</h1>`; continue; }
|
||||
if (line.startsWith('## ')) { html += `<h2 style="color:#e6edf3;font-size:22px;margin:28px 0 10px;border-bottom:1px solid #21262d;padding-bottom:6px">${inlineFormat(line.slice(3))}</h2>`; continue; }
|
||||
if (line.startsWith('### ')) { html += `<h3 style="color:#e6edf3;font-size:17px;margin:20px 0 8px">${inlineFormat(line.slice(4))}</h3>`; continue; }
|
||||
|
||||
// Horisontaalinen viiva
|
||||
if (line.match(/^-{3,}$/)) { html += '<hr style="border:none;border-top:1px solid #30363d;margin:20px 0">'; continue; }
|
||||
|
||||
// Lista
|
||||
if (line.match(/^[\-\*] /)) {
|
||||
html += `<div style="padding:2px 0 2px 20px">${inlineFormat(line.replace(/^[\-\*] /, '• '))}</div>`;
|
||||
continue;
|
||||
}
|
||||
if (line.match(/^\d+\. /)) {
|
||||
html += `<div style="padding:2px 0 2px 20px">${inlineFormat(line)}</div>`;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Normaali tekstirivi
|
||||
html += `<p style="margin:4px 0">${inlineFormat(line)}</p>`;
|
||||
}
|
||||
flushTable();
|
||||
return html;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user