// ===================================================== // App — router, sidebar, theme toggle // ===================================================== const view = document.getElementById('view'); const crumbCurrent = document.getElementById('crumbCurrent'); function parseRoute() { const hash = location.hash.replace(/^#\/?/, ''); if (!hash || hash === '/') return { name: 'home' }; const parts = hash.split('/').filter(Boolean); if (parts[0] === 'uke' && parts[1]) return { name: 'uke', weekId: parseInt(parts[1], 10) }; if (parts[0] === 'tema' && parts[1]) return { name: 'tema', temaId: parts[1] }; if (parts[0] === 'fast-track') { return parts[1] ? { name: 'fasttrack-module', moduleId: parseInt(parts[1], 10) } : { name: 'fasttrack' }; } if (parts[0] === 'tldr') return { name: 'tldr' }; if (parts[0] === 'flashcards') return { name: 'flashcards' }; if (parts[0] === 'quiz') return { name: 'quiz' }; if (parts[0] === 'eksamen') return { name: 'eksamen' }; return { name: 'home' }; } async function route() { const r = parseRoute(); view.innerHTML = ''; let content; let crumb = 'Oversikt'; switch (r.name) { case 'home': content = SMF.renderHome(); crumb = 'Oversikt'; break; case 'uke': content = await SMF.renderLesson(r.weekId); const w = SMF.WEEKS.find(x => x.id === r.weekId); crumb = w ? `Uke ${w.id} · ${w.title}` : 'Ukjent uke'; break; case 'tema': content = await SMF.renderTema(r.temaId); const t = SMF.getTheme(r.temaId); crumb = t ? t.label : 'Tema'; break; case 'fasttrack': content = await SMF.renderFastTrackHome(); crumb = 'Fast-track'; break; case 'fasttrack-module': content = await SMF.renderFastTrackModule(r.moduleId); const m = SMF.getFastTrack(r.moduleId); crumb = m ? `Fast-track · ${m.title}` : 'Fast-track'; break; case 'tldr': content = await SMF.renderTldr(); crumb = 'tl;dr · i farta'; break; case 'flashcards': content = document.getElementById('t-flashcards').content.cloneNode(true); crumb = 'Flashcards'; break; case 'quiz': content = document.getElementById('t-quiz').content.cloneNode(true); crumb = 'Selvtest'; break; case 'eksamen': content = document.getElementById('t-eksamen').content.cloneNode(true); crumb = 'Eksamenstrener'; break; } view.appendChild(content); crumbCurrent.textContent = crumb; // After DOM is in place, init relevant mode if (r.name === 'flashcards') await SMF.fcInit(); else if (r.name === 'quiz') await SMF.quizInit(); else if (r.name === 'eksamen') await SMF.examInit(); updateActiveLinks(r); closeSidebar(); window.scrollTo(0, 0); } function updateActiveLinks(r) { document.querySelectorAll('.sidebar__link').forEach(a => { a.classList.remove('sidebar__link--active'); }); if (r.name === 'home') { document.querySelector('.sidebar__link[data-route="home"]')?.classList.add('sidebar__link--active'); } else if (r.name === 'tldr') { document.querySelector('.sidebar__link[data-route="tldr"]')?.classList.add('sidebar__link--active'); } else if (r.name === 'fasttrack' || r.name === 'fasttrack-module') { document.querySelector('.sidebar__link[data-route="fasttrack"]')?.classList.add('sidebar__link--active'); } else if (r.name === 'flashcards') { document.querySelector('.sidebar__link[data-route="flashcards"]')?.classList.add('sidebar__link--active'); } else if (r.name === 'quiz') { document.querySelector('.sidebar__link[data-route="quiz"]')?.classList.add('sidebar__link--active'); } else if (r.name === 'eksamen') { document.querySelector('.sidebar__link[data-route="eksamen"]')?.classList.add('sidebar__link--active'); } else if (r.name === 'uke') { document.querySelector(`.sidebar__link[data-week="${r.weekId}"]`)?.classList.add('sidebar__link--active'); } else if (r.name === 'tema') { // No specific active link for tema (could be added) } } function renderWeekNav() { const nav = document.getElementById('weekNav'); if (!nav) return; nav.innerHTML = SMF.WEEKS.map(w => { return ` ${String(w.id).padStart(2, '0')} ${w.title} `; }).join(''); } // ============= Sidebar (mobile) ============= function openSidebar() { document.getElementById('sidebar').classList.add('sidebar--open'); document.getElementById('sidebarScrim').classList.add('sidebar-scrim--open'); } function closeSidebar() { document.getElementById('sidebar').classList.remove('sidebar--open'); document.getElementById('sidebarScrim').classList.remove('sidebar-scrim--open'); } document.getElementById('sidebarToggle')?.addEventListener('click', () => { if (document.getElementById('sidebar').classList.contains('sidebar--open')) closeSidebar(); else openSidebar(); }); document.getElementById('sidebarScrim')?.addEventListener('click', closeSidebar); // ============= Theme toggle ============= function applyTheme(theme) { document.documentElement.dataset.theme = theme; localStorage.setItem('smf-theme', theme); // Update icon const icon = document.getElementById('themeIcon'); if (theme === 'dark') { icon.innerHTML = ``; } else { icon.innerHTML = ``; } } function initTheme() { // dark default; only switch to light if explicitly saved const saved = localStorage.getItem('smf-theme'); applyTheme(saved === 'light' ? 'light' : 'dark'); } document.getElementById('themeBtn').addEventListener('click', () => { const current = document.documentElement.dataset.theme; applyTheme(current === 'dark' ? 'light' : 'dark'); }); // ============= Countdown ============= function updateCountdown() { const el = document.getElementById('examCountdown'); if (!el) return; const c = SMF.daysToExam(); el.textContent = c.label; } // ============= Init ============= async function init() { initTheme(); renderWeekNav(); updateCountdown(); SMF.attachSearch(); // Sidebar brand link document.querySelectorAll('[data-route="home"]').forEach(a => { a.addEventListener('click', (e) => { e.preventDefault(); location.hash = ''; }); }); // Initial route await route(); // Build search index in background setTimeout(() => SMF.buildSearchIndex().catch(console.warn), 500); } window.addEventListener('hashchange', route); window.addEventListener('DOMContentLoaded', init); if (document.readyState !== 'loading') init();