Files
newznab-tmux-NNTmux/resources/js/alpine/components/mobile-nav.js
T
2026-08-27 19:01:30 +02:00

160 lines
5.8 KiB
JavaScript

/**
* Alpine.data('mobileNav') - Mobile navigation panel + search toggle
*/
import Alpine from '@alpinejs/csp';
Alpine.data('mobileNav', () => ({
navOpen: false,
searchOpen: false,
toggleNav() {
this.navOpen = !this.navOpen;
if (this.navOpen) this.searchOpen = false;
},
toggleSearch() {
this.searchOpen = !this.searchOpen;
if (this.searchOpen) this.navOpen = false;
},
closeAll() {
this.navOpen = false;
this.searchOpen = false;
},
init() {
// Close on resize past lg breakpoint
window.addEventListener('resize', () => {
if (window.innerWidth >= 1024) this.closeAll();
});
}
}));
Alpine.data('mobileNavSection', () => ({
open: false,
toggle() {
this.open = !this.open;
}
}));
Alpine.data('mobileSidebar', () => ({
open: false,
toggle() {
this.open = !this.open;
}
}));
/**
* Document-level delegation for mobile menu elements without x-data.
*/
(function() {
document.querySelectorAll('#sidebar a[href]').forEach(function(link) {
try {
var linkUrl = new URL(link.href, window.location.origin);
if (linkUrl.origin === window.location.origin && linkUrl.pathname === window.location.pathname) {
link.setAttribute('aria-current', 'page');
}
} catch (_error) {
// Ignore malformed or non-navigational URLs.
}
});
var toggle = document.getElementById('mobile-menu-toggle');
var panel = document.getElementById('mobile-nav-panel');
var iconOpen = document.getElementById('mobile-menu-icon-open');
var iconClose = document.getElementById('mobile-menu-icon-close');
var searchToggle = document.getElementById('mobile-search-toggle');
var searchForm = document.getElementById('mobile-search-form');
if (toggle && panel && !toggle.closest('[x-data]')) {
toggle.addEventListener('click', function() {
var isOpen = !panel.classList.contains('hidden');
if (isOpen) { panel.classList.add('hidden'); toggle.setAttribute('aria-expanded', 'false'); }
else { panel.classList.remove('hidden'); toggle.setAttribute('aria-expanded', 'true'); if (searchForm) searchForm.classList.add('hidden'); }
if (iconOpen && iconClose) { iconOpen.classList.toggle('hidden'); iconClose.classList.toggle('hidden'); }
});
}
document.querySelectorAll('.mobile-nav-toggle').forEach(function(t) {
if (t.closest('[x-data]')) return;
t.addEventListener('click', function() {
var section = this.closest('.mobile-nav-section');
if (!section) return;
var submenu = section.querySelector('.mobile-nav-submenu');
var chevron = this.querySelector('.mobile-nav-chevron');
if (submenu) submenu.classList.toggle('hidden');
if (chevron) chevron.classList.toggle('rotate-180');
});
});
if (searchToggle && searchForm && !searchToggle.closest('[x-data]')) {
searchToggle.addEventListener('click', function(ev) {
ev.preventDefault();
searchForm.classList.toggle('hidden');
searchToggle.setAttribute('aria-expanded', searchForm.classList.contains('hidden') ? 'false' : 'true');
if (panel && !searchForm.classList.contains('hidden')) {
panel.classList.add('hidden');
if (iconOpen && iconClose) { iconOpen.classList.remove('hidden'); iconClose.classList.add('hidden'); }
if (toggle) toggle.setAttribute('aria-expanded', 'false');
}
});
}
var mobileSidebarToggle = document.getElementById('mobile-sidebar-toggle');
var mobileSidebarClose = document.getElementById('mobile-sidebar-close');
var mobileSidebarBackdrop = document.getElementById('mobile-sidebar-backdrop');
function setMobileSidebar(open) {
var sidebar = document.getElementById('sidebar');
if (!sidebar || !mobileSidebarToggle) return;
sidebar.classList.toggle('hidden', !open);
sidebar.classList.toggle('flex', open);
mobileSidebarBackdrop?.classList.toggle('hidden', !open);
mobileSidebarToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
mobileSidebarToggle.setAttribute('aria-label', open ? 'Close navigation' : 'Open navigation');
if (open) {
mobileSidebarClose?.focus();
} else if (window.innerWidth < 768) {
mobileSidebarToggle.focus();
}
}
if (mobileSidebarToggle && !mobileSidebarToggle.closest('[x-data]')) {
mobileSidebarToggle.addEventListener('click', function() {
var sidebar = document.getElementById('sidebar');
if (sidebar) setMobileSidebar(sidebar.classList.contains('hidden'));
});
mobileSidebarClose?.addEventListener('click', function() {
setMobileSidebar(false);
});
mobileSidebarBackdrop?.addEventListener('click', function() {
setMobileSidebar(false);
});
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && mobileSidebarToggle.getAttribute('aria-expanded') === 'true') {
setMobileSidebar(false);
}
});
}
window.addEventListener('resize', function() {
if (window.innerWidth >= 1024) {
if (panel) panel.classList.add('hidden');
if (searchForm) searchForm.classList.add('hidden');
if (iconOpen && iconClose) { iconOpen.classList.remove('hidden'); iconClose.classList.add('hidden'); }
if (toggle) toggle.setAttribute('aria-expanded', 'false');
}
if (window.innerWidth >= 768 && mobileSidebarToggle) {
setMobileSidebar(false);
}
});
})();