diff --git a/muxplex/frontend/app.js b/muxplex/frontend/app.js index 24f45f2..56d614e 100644 --- a/muxplex/frontend/app.js +++ b/muxplex/frontend/app.js @@ -898,6 +898,62 @@ function closeViewDropdown() { if (trigger) trigger.setAttribute('aria-expanded', 'false'); } +/** + * Render the sidebar view dropdown menu (same data as the header dropdown, + * but no action buttons — navigation only). + */ +function renderSidebarViewDropdown() { + var menu = $('sidebar-view-dropdown-menu'); + if (!menu) return; + + var views = (_serverSettings && _serverSettings.views) || []; + var hidden = (_serverSettings && _serverSettings.hidden_sessions) || []; + var hiddenCount = hidden.length; + + var html = ''; + + // — All Sessions (always first) + var allActive = _activeView === 'all' ? ' view-dropdown-item--active' : ''; + html += ''; + + // — User views + if (views.length > 0) { + html += '
'; + for (var i = 0; i < views.length && i < 7; i++) { + var v = views[i]; + var vActive = _activeView === v.name ? ' view-dropdown-item--active' : ''; + html += ''; + } + } + + // — Hidden (N) (always last system view) + html += ''; + var hiddenActive = _activeView === 'hidden' ? ' view-dropdown-item--active' : ''; + html += ''; + + menu.innerHTML = html; +} + +/** + * Toggle the sidebar view dropdown open/closed. + * Calls renderSidebarViewDropdown() when opening to ensure fresh content. + */ +function toggleSidebarViewDropdown() { + var menu = $('sidebar-view-dropdown-menu'); + var trigger = $('sidebar-view-dropdown-trigger'); + if (!menu) return; + + var isOpen = !menu.classList.contains('hidden'); + if (isOpen) { + menu.classList.add('hidden'); + if (trigger) trigger.setAttribute('aria-expanded', 'false'); + } else { + menu.classList.remove('hidden'); + if (trigger) trigger.setAttribute('aria-expanded', 'true'); + renderSidebarViewDropdown(); + } +} + /** * Show an inline text input inside the view dropdown for creating a new view. * Replaces the '+ New View' button with a text input inside the dropdown menu. @@ -1235,6 +1291,17 @@ function switchView(viewName) { renderGrid(_currentSessions || []); renderSidebar(_currentSessions || [], _viewingSession); renderViewDropdown(); + // Update sidebar view label to match the active view + var sidebarLabel = $('sidebar-view-label'); + if (sidebarLabel) { + if (viewName === 'all') { + sidebarLabel.textContent = 'All Sessions'; + } else if (viewName === 'hidden') { + sidebarLabel.textContent = 'Hidden'; + } else { + sidebarLabel.textContent = viewName; + } + } // Persist active view — fire and forget api('PATCH', '/api/state', { active_view: viewName }).catch(function() {}); } @@ -2777,6 +2844,23 @@ function bindStaticEventListeners() { }); } + // Sidebar view dropdown — trigger opens/closes, delegated item clicks switch view + var sidebarViewTrigger = $('sidebar-view-dropdown-trigger'); + if (sidebarViewTrigger) on(sidebarViewTrigger, 'click', toggleSidebarViewDropdown); + + var sidebarViewMenu = $('sidebar-view-dropdown-menu'); + if (sidebarViewMenu) { + sidebarViewMenu.addEventListener('click', function(e) { + var item = e.target.closest('[data-view]'); + if (item) { + switchView(item.dataset.view); + // Close sidebar dropdown after selection + sidebarViewMenu.classList.add('hidden'); + if (sidebarViewTrigger) sidebarViewTrigger.setAttribute('aria-expanded', 'false'); + } + }); + } + // Click-outside closes the dropdown document.addEventListener('click', function(e) { var dropdown = $('view-dropdown-menu'); @@ -3204,6 +3288,9 @@ if (typeof module !== 'undefined' && module.exports) { closeViewDropdown, showNewViewInput, switchView, + // Sidebar view dropdown + renderSidebarViewDropdown, + toggleSidebarViewDropdown, // Manage Views settings tab renderViewsSettingsTab, _saveViewsAndRerender, diff --git a/muxplex/frontend/index.html b/muxplex/frontend/index.html index d4f3ad8..aa197c6 100644 --- a/muxplex/frontend/index.html +++ b/muxplex/frontend/index.html @@ -49,7 +49,13 @@