Fix sidebar toggle persisting across navigations

- Add updated() callback to SidebarCollapse hook so state is re-applied
  after LiveView DOM patches (which strip client-side classes)
- Add inline script for synchronous state restore (no flash on nav)
- Sidebar now stays expanded/collapsed until manually toggled
This commit is contained in:
Graham McIntire 2026-03-13 14:02:19 -05:00
parent 509e4f7eb3
commit 7149ab71cd
2 changed files with 28 additions and 7 deletions

View file

@ -1375,18 +1375,30 @@ const StatusTitle = {
} }
} }
// Sidebar collapse - restore state from localStorage and persist toggle // Sidebar collapse - restore state from localStorage and persist toggle.
// Uses both mounted() and updated() because LiveView DOM patching can
// strip the client-side "sidebar-collapsed" class on live navigations.
const SidebarCollapse = { const SidebarCollapse = {
mounted(this: any) { mounted(this: any) {
this._apply()
this._listen()
},
updated(this: any) {
this._apply()
},
_apply(this: any) {
if (localStorage.getItem('sidebarCollapsed') === 'true') { if (localStorage.getItem('sidebarCollapsed') === 'true') {
this.el.classList.add('sidebar-collapsed') this.el.classList.add('sidebar-collapsed')
} }
this.el.querySelector('[data-sidebar-toggle]')?.addEventListener('click', () => { },
// The JS.toggle_class will fire, so we check after a tick _listen(this: any) {
requestAnimationFrame(() => { this.el.addEventListener('click', (e: Event) => {
const collapsed = this.el.classList.contains('sidebar-collapsed') if ((e.target as HTMLElement).closest('[data-sidebar-toggle]')) {
localStorage.setItem('sidebarCollapsed', String(collapsed)) requestAnimationFrame(() => {
}) const collapsed = this.el.classList.contains('sidebar-collapsed')
localStorage.setItem('sidebarCollapsed', String(collapsed))
})
}
}) })
} }
} }

View file

@ -149,6 +149,15 @@ defmodule ToweropsWeb.Layouts do
~H""" ~H"""
<div id="sidebar-wrapper" phx-hook="SidebarCollapse" class="min-h-screen bg-gray-50 dark:bg-gray-950"> <div id="sidebar-wrapper" phx-hook="SidebarCollapse" class="min-h-screen bg-gray-50 dark:bg-gray-950">
<script>
// Apply sidebar state synchronously to prevent flash on navigation
(function() {
var w = document.getElementById('sidebar-wrapper');
if (w && localStorage.getItem('sidebarCollapsed') === 'true') {
w.classList.add('sidebar-collapsed');
}
})();
</script>
<!-- Impersonation Banner --> <!-- Impersonation Banner -->
<%= if @current_scope && @current_scope.impersonating? do %> <%= if @current_scope && @current_scope.impersonating? do %>
<div class="bg-yellow-400 border-b-2 border-yellow-600 relative z-50"> <div class="bg-yellow-400 border-b-2 border-yellow-600 relative z-50">