123 lines
5.1 KiB
JavaScript
123 lines
5.1 KiB
JavaScript
// 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 = '<nav class="sidebar-nav">' +
|
||
_SIDEBAR_LINKS.map(link => {
|
||
const active = currentPath === link.href ? ' active' : '';
|
||
const adm = link.admin ? ' sidebar-admin' : '';
|
||
return `<a href="${link.href}" class="sidebar-link${active}${adm}">` +
|
||
`<i class="bi ${link.icon}"></i><span>${link.label}</span></a>`;
|
||
}).join('') +
|
||
'</nav>';
|
||
}
|
||
|
||
// ── 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);
|
||
});
|
||
}
|