| 1 | /** |
| 2 | * MAPS Connect - Layout compartido (menú lateral plegable) |
| 3 | */ |
| 4 | |
| 5 | const NAV_ITEMS = [ |
| 6 | { href: 'inicio.html', label: 'Inicio' }, |
| 7 | { href: 'perfil.html', label: 'Mi Perfil' }, |
| 8 | { href: 'foro.html', label: 'Foro de Dudas' }, |
| 9 | { href: 'tips.html', label: 'Tips Académicos' }, |
| 10 | { href: 'recursos.html', label: 'Apuntes' }, |
| 11 | { href: 'mensajes.html', label: 'Mensajes' }, |
| 12 | { href: 'empresarial.html', label: 'Semestre Empresarial' }, |
| 13 | { href: 'circulos.html', label: 'Círculos de Estudio' } |
| 14 | ]; |
| 15 | |
| 16 | const Layout = { |
| 17 | init(currentPage) { |
| 18 | if (!Auth.requireAuth()) return; |
| 19 | |
| 20 | this.renderSidebar(currentPage); |
| 21 | this.renderTopbar(); |
| 22 | this.bindToggle(); |
| 23 | }, |
| 24 | |
| 25 | renderSidebar(currentPage) { |
| 26 | const sidebar = document.getElementById('sidebar'); |
| 27 | if (!sidebar) return; |
| 28 | |
| 29 | const user = Auth.getUser(); |
| 30 | const navLinks = NAV_ITEMS.map(item => { |
| 31 | const active = item.href === currentPage ? 'active' : ''; |
| 32 | return `<li><a href="${item.href}" class="${active}">${item.label}</a></li>`; |
| 33 | }).join(''); |
| 34 | |
| 35 | sidebar.innerHTML = ` |
| 36 | <div class="sidebar-header"> |
| 37 | <h1>MAPS Connect</h1> |
| 38 | <small>${user?.nombre || 'Usuario'}</small> |
| 39 | </div> |
| 40 | <ul class="sidebar-nav">${navLinks}</ul> |
| 41 | <div class="sidebar-footer"> |
| 42 | <button class="btn btn-sm btn-outline" id="btn-logout">Cerrar sesión</button> |
| 43 | </div> |
| 44 | `; |
| 45 | |
| 46 | document.getElementById('btn-logout')?.addEventListener('click', () => Auth.logout()); |
| 47 | }, |
| 48 | |
| 49 | renderTopbar() { |
| 50 | const topbar = document.getElementById('topbar'); |
| 51 | if (!topbar) return; |
| 52 | |
| 53 | topbar.innerHTML = ` |
| 54 | <button class="menu-backdrop" id="menu-backdrop" type="button" aria-label="Cerrar menú"></button> |
| 55 | <button class="menu-toggle" id="sidebar-toggle" type="button" |
| 56 | aria-label="Abrir menú" aria-controls="sidebar" aria-expanded="false"> |
| 57 | <span aria-hidden="true">☰</span> |
| 58 | </button> |
| 59 | <span id="topbar-title" class="visually-hidden"></span> |
| 60 | `; |
| 61 | }, |
| 62 | |
| 63 | bindToggle() { |
| 64 | const toggle = document.getElementById('sidebar-toggle'); |
| 65 | const sidebar = document.getElementById('sidebar'); |
| 66 | const layout = document.querySelector('.app-layout'); |
| 67 | const backdrop = document.getElementById('menu-backdrop'); |
| 68 | |
| 69 | const setMenuState = isOpen => { |
| 70 | sidebar?.classList.toggle('open', isOpen); |
| 71 | layout?.classList.toggle('menu-open', isOpen); |
| 72 | toggle.setAttribute('aria-expanded', String(isOpen)); |
| 73 | toggle.setAttribute('aria-label', isOpen ? 'Cerrar menú' : 'Abrir menú'); |
| 74 | }; |
| 75 | |
| 76 | toggle?.addEventListener('click', () => setMenuState(!sidebar?.classList.contains('open'))); |
| 77 | backdrop?.addEventListener('click', () => setMenuState(false)); |
| 78 | document.addEventListener('keydown', event => { |
| 79 | if (event.key === 'Escape' && sidebar?.classList.contains('open')) setMenuState(false); |
| 80 | }); |
| 81 | }, |
| 82 | |
| 83 | setPageTitle(title) { |
| 84 | const el = document.getElementById('topbar-title'); |
| 85 | if (el) el.textContent = title; |
| 86 | document.title = `${title} | MAPS Connect`; |
| 87 | } |
| 88 | }; |