// MeshDD-Bot – Shared page module // Provides: initPage(), escapeHtml(), applyTheme() // ── Sidebar definition ──────────────────────────────────────── const _SIDEBAR_LINKS = [ { href: '/', icon: 'bi-speedometer2', label: 'Dashboard', admin: false }, { href: '/scheduler', icon: 'bi-clock-history', label: 'Scheduler', admin: true }, { href: '/map', icon: 'bi-map', label: 'Karte', admin: false }, { href: '/packets', icon: 'bi-reception-4', label: 'Pakete', admin: false }, { href: '/settings', icon: 'bi-gear', label: 'Einstellungen',admin: true }, { href: '/admin', icon: 'bi-people', label: 'Benutzer', admin: true }, ]; function _injectSidebar() { const sidebar = document.getElementById('sidebar'); if (!sidebar) return; const currentPath = window.location.pathname; sidebar.innerHTML = ''; } // ── Navbar ──────────────────────────────────────────────────── function _updateNavbar(user) { const userMenu = document.getElementById('userMenu'); const loginBtn = document.getElementById('loginBtn'); const userName = document.getElementById('userName'); if (user) { if (userName) userName.textContent = user.name; if (userMenu) userMenu.classList.remove('d-none'); if (loginBtn) loginBtn.classList.add('d-none'); } else { if (userMenu) userMenu.classList.add('d-none'); if (loginBtn) loginBtn.classList.remove('d-none'); } } function _updateSidebar(user) { const isAdmin = user && user.role === 'admin'; document.querySelectorAll('.sidebar-admin').forEach(el => { el.style.display = isAdmin ? '' : 'none'; }); } // ── Theme ───────────────────────────────────────────────────── function applyTheme(theme) { document.documentElement.setAttribute('data-bs-theme', theme); const icon = document.getElementById('themeIcon'); if (icon) icon.className = theme === 'dark' ? 'bi bi-sun-fill' : 'bi bi-moon-fill'; localStorage.setItem('theme', theme); document.dispatchEvent(new CustomEvent('themechange', { detail: { theme } })); } function _setupTheme() { applyTheme(localStorage.getItem('theme') || 'light'); const btn = document.getElementById('themeToggle'); if (btn) { btn.addEventListener('click', () => { const current = document.documentElement.getAttribute('data-bs-theme'); applyTheme(current === 'dark' ? 'light' : 'dark'); }); } } // ── Sidebar toggle (mobile) ─────────────────────────────────── function _setupSidebarToggle() { const toggle = document.getElementById('sidebarToggle'); const sidebar = document.getElementById('sidebar'); const backdrop = document.getElementById('sidebarBackdrop'); if (toggle && sidebar) toggle.addEventListener('click', () => sidebar.classList.toggle('open')); if (backdrop && sidebar) backdrop.addEventListener('click', () => sidebar.classList.remove('open')); } // ── Utilities ───────────────────────────────────────────────── function escapeHtml(str) { if (!str) return ''; const div = document.createElement('div'); div.textContent = str; return div.innerHTML; } // ── Public init ─────────────────────────────────────────────── function _injectFooter(version) { const footer = document.getElementById('pageFooter'); if (!footer) return; const now = new Date(); const mm = String(now.getMonth() + 1).padStart(2, '0'); const yyyy = now.getFullYear(); const ver = version ? ` · v${version}` : ''; footer.textContent = `© MeshDD / PPfeiffer${ver} · ${mm}/${yyyy}`; } function initPage({ onAuth = null } = {}) { _injectSidebar(); _setupTheme(); fetch('/api/auth/me') .then(r => r.ok ? r.json() : null) .then(user => { _updateNavbar(user); _updateSidebar(user); _setupSidebarToggle(); if (onAuth) onAuth(user); }); const vl = document.getElementById('versionLabel'); fetch('/api/stats') .then(r => r.ok ? r.json() : null) .then(d => { if (d?.version && vl) vl.textContent = `v${d.version}`; _injectFooter(d?.version); }); }