diff --git a/frontend/js/app.js b/frontend/js/app.js index 905c9cb..dc6be99 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -319,20 +319,48 @@ document.addEventListener('alpine:init', () => { }) // ── Composant: sidebar ────────────────────────────────────────────────── + // Items CORE : toujours visibles. + // Items modules : visibles seulement si le module est activé en DB. + const _coreNavItems = [ + { id: 'dashboard', iconClass: 'lnid-dashboard-square-1', iconColor: '#6c8ef4', labelKey: 'nav.dashboard', href: '/dashboard.html' }, + { id: 'proxmox', iconClass: 'lnid-server-1', iconColor: '#22c55e', labelKey: 'nav.proxmox', href: '/proxmox.html' }, + { id: 'updates', iconClass: 'lnid-arrow-upward', iconColor: '#f59e0b', labelKey: 'nav.updates', href: '/updates.html' }, + { id: 'settings', iconClass: 'lnid-gear-1', iconColor: '#94a3b8', labelKey: 'nav.settings', href: '/settings.html' }, + { id: 'modules', iconClass: 'lnid-puzzle', iconColor: '#f472b6', labelKey: 'nav.modules', href: '/modules.html' }, + ] + // Définition des items de navigation pour les modules optionnels. + // Un module dont l'id n'est pas ici n'aura pas d'entrée dans la sidebar. + const _moduleNavDef = { + terminal: { iconClass: 'lnid-terminal', iconColor: '#a78bfa', labelKey: 'nav.terminal', href: '/terminal.html' }, + files: { iconClass: 'lnid-folder-1', iconColor: '#84cc16', labelKey: 'nav.files', href: '/files.html' }, + services: { iconClass: 'lnid-gear-2', iconColor: '#fb923c', labelKey: 'nav.services', href: '/services.html' }, + logs: { iconClass: 'lnid-scroll-angular-1', iconColor: '#38bdf8', labelKey: 'nav.logs', href: '/logs.html' }, + } + Alpine.data('sidebar', () => ({ get collapsed() { return Alpine.store('ui').sidebarCollapsed }, get currentPage() { return Alpine.store('ui').currentPage }, - navItems: [ - { id: 'dashboard', iconClass: 'lnid-dashboard-square-1', iconColor: '#6c8ef4', labelKey: 'nav.dashboard', href: '/dashboard.html' }, - { id: 'proxmox', iconClass: 'lnid-server-1', iconColor: '#22c55e', labelKey: 'nav.proxmox', href: '/proxmox.html' }, - { id: 'updates', iconClass: 'lnid-arrow-upward', iconColor: '#f59e0b', labelKey: 'nav.updates', href: '/updates.html' }, - { id: 'terminal', iconClass: 'lnid-terminal', iconColor: '#a78bfa', labelKey: 'nav.terminal', href: '/terminal.html' }, - { id: 'services', iconClass: 'lnid-gear-2', iconColor: '#fb923c', labelKey: 'nav.services', href: '/services.html' }, - { id: 'logs', iconClass: 'lnid-scroll-angular-1', iconColor: '#38bdf8', labelKey: 'nav.logs', href: '/logs.html' }, - { id: 'settings', iconClass: 'lnid-gear-1', iconColor: '#94a3b8', labelKey: 'nav.settings', href: '/settings.html' }, - { id: 'modules', iconClass: 'lnid-puzzle', iconColor: '#f472b6', labelKey: 'nav.modules', href: '/modules.html' }, - ], + // Commence avec les items CORE ; init() ajoute les modules activés + navItems: [..._coreNavItems], + + async init() { + try { + const res = await apiFetch('/api/modules') + if (!res.ok) return + const modules = await res.json() || [] + const moduleItems = modules + .filter(m => m.is_enabled && !m.is_core && _moduleNavDef[m.id]) + .map(m => ({ id: m.id, ..._moduleNavDef[m.id] })) + // Insérer les modules entre Updates et Settings + const insertAt = this.navItems.findIndex(i => i.id === 'settings') + this.navItems = [ + ...this.navItems.slice(0, insertAt), + ...moduleItems, + ...this.navItems.slice(insertAt), + ] + } catch(e) {} + }, iconStyle(item) { return this.isActive(item.id) ? '' : `color: ${item.iconColor}`