/* Sage — knowledge base app */ let allArticles = []; let navIndex = null; let currentArticleId = null; async function loadData() { const [indexRes, ...articleRes] = await Promise.all([ fetch('/sage/api/_index.json'), ...ARTICLE_IDS.map(id => fetch(`/sage/api/${id}.json`)) ]); navIndex = await indexRes.json(); allArticles = await Promise.all(articleRes.map(r => r.json())); } const ARTICLE_IDS = [ 'ssh-keys', 'ssh-access-controls', 'nginx-config', 'disk-logs', 'file-permissions', 'cron-jobs', 'time-sync', 'package-management' ]; const CATEGORY_LABELS = { access: 'Access & Authentication', web: 'Web Services', storage: 'Storage & Logs', sysadmin: 'System Administration', packages: 'Package Management' }; // ── Sidebar ─────────────────────────────────────────────────────────────────── function buildNav() { const sidebar = document.getElementById('sidebar'); sidebar.innerHTML = ''; // Home link const homeWrap = document.createElement('div'); homeWrap.className = 'nav-section'; const homeLink = document.createElement('a'); homeLink.className = 'nav-link'; homeLink.textContent = '⌂ Home'; homeLink.dataset.home = '1'; homeLink.onclick = (e) => { e.preventDefault(); showHome(); }; homeWrap.appendChild(homeLink); sidebar.appendChild(homeWrap); navIndex.categories.forEach(cat => { const section = document.createElement('div'); section.className = 'nav-section'; const label = document.createElement('div'); label.className = 'nav-category'; label.textContent = cat.label; section.appendChild(label); cat.articles.forEach(id => { const article = allArticles.find(a => a.id === id); if (!article) return; const link = document.createElement('a'); link.className = 'nav-link'; link.textContent = article.title; link.dataset.articleId = id; link.onclick = (e) => { e.preventDefault(); showArticle(id); }; section.appendChild(link); }); sidebar.appendChild(section); }); } function setActiveNav(articleId) { document.querySelectorAll('.nav-link').forEach(el => { el.classList.toggle('active', articleId ? el.dataset.articleId === articleId : !!el.dataset.home ); }); } // ── Home ────────────────────────────────────────────────────────────────────── function showHome() { currentArticleId = null; clearSearch(); setActiveNav(null); const main = document.getElementById('main'); main.classList.remove('hidden'); document.getElementById('search-results').classList.remove('visible'); main.innerHTML = ''; const home = document.createElement('div'); home.id = 'home-page'; const h1 = document.createElement('h1'); h1.textContent = 'Sage — Internal Knowledge Base'; const subtitle = document.createElement('p'); subtitle.className = 'home-subtitle'; subtitle.textContent = 'Runbooks, reference guides, and procedures for Axiom Works infrastructure.'; home.appendChild(h1); home.appendChild(subtitle); const grid = document.createElement('div'); grid.className = 'home-grid'; navIndex.categories.forEach(cat => { const catLabel = document.createElement('div'); catLabel.className = 'home-category-label'; catLabel.textContent = cat.label; home.appendChild(catLabel); const catGrid = document.createElement('div'); catGrid.className = 'home-grid'; cat.articles.forEach(id => { const article = allArticles.find(a => a.id === id); if (!article) return; const card = document.createElement('div'); card.className = 'home-card'; card.innerHTML = `
${esc(article.summary)}
`; article.sections.forEach(section => { html += `${esc(section.code)}`;
}
html += `Loading…
'; try { await loadData(); } catch (err) { main.innerHTML = `Failed to load knowledge base: ${esc(err.message)}
`; return; } buildNav(); showHome(); document.getElementById('search').addEventListener('input', onSearchInput); // Keyboard shortcut: / to focus search document.addEventListener('keydown', e => { if (e.key === '/' && document.activeElement !== document.getElementById('search')) { e.preventDefault(); document.getElementById('search').focus(); } if (e.key === 'Escape') { clearSearch(); if (currentArticleId) setActiveNav(currentArticleId); else showHome(); } }); } document.addEventListener('DOMContentLoaded', init);