librelad 875a60f90f LibrePortal v0.1.0 — initial release
A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys,
Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun
VPN routing, and a web dashboard to manage it all.

Free & open forever to self-host; optional paid hosted services fund it.
See PROMISE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-21 20:37:54 +01:00

71 lines
2.2 KiB
JavaScript
Executable File

// Mobile Menu Handler — wires the topbar burger to the slide-in drawer
// (#mobile-drawer). On pages that ship a page sidebar (#sidebar), the
// drawer borrows its contents while open so the user gets one unified
// nav surface on mobile.
function setupMobileMenu() {
const toggle = document.getElementById('mobile-menu-toggle');
const drawer = document.getElementById('mobile-drawer');
const overlay = document.getElementById('mobile-overlay');
if (!toggle || !drawer || !overlay) {
setTimeout(setupMobileMenu, 100);
return;
}
const pageSection = document.getElementById('mobile-drawer-page-section');
let borrowedNodes = [];
let sidebarOrigin = null;
function borrowSidebar() {
const sidebar = document.getElementById('sidebar');
if (!sidebar || !pageSection) return;
sidebarOrigin = sidebar;
borrowedNodes = Array.from(sidebar.children);
borrowedNodes.forEach((node) => pageSection.appendChild(node));
}
function returnSidebar() {
if (!sidebarOrigin || borrowedNodes.length === 0) return;
borrowedNodes.forEach((node) => sidebarOrigin.appendChild(node));
borrowedNodes = [];
sidebarOrigin = null;
}
function openMenu() {
borrowSidebar();
drawer.classList.add('mobile-open');
overlay.classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeMenu() {
drawer.classList.remove('mobile-open');
overlay.classList.remove('active');
document.body.style.overflow = '';
returnSidebar();
}
function toggleMenu() {
if (drawer.classList.contains('mobile-open')) closeMenu();
else openMenu();
}
toggle.addEventListener('click', toggleMenu);
overlay.addEventListener('click', closeMenu);
// Close when any nav-item, sidebar-item, or category gets clicked
// (they trigger navigation, so the drawer should dismiss itself).
drawer.addEventListener('click', (e) => {
const dismisser = e.target.closest('.nav-item, .sidebar-item, .category');
if (dismisser) closeMenu();
});
window.addEventListener('resize', () => {
if (window.innerWidth > 768 && drawer.classList.contains('mobile-open')) {
closeMenu();
}
});
window.closeMobileMenu = closeMenu;
}