From 5807a5009228262f5f6a36ab215a4b292bb32132 Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Wed, 18 Mar 2026 16:40:00 +0100 Subject: [PATCH] fix: center icons in collapsed sidebar, eliminate white flash on click MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Icons now use justify-center + px-0 when collapsed so they sit perfectly centered in the 56px rail. Track pending navigation href optimistically — clicked item shows orange immediately instead of flashing through the inactive hover state during route transition. --- components/dashboard/Sidebar.tsx | 110 +++++++++++++++++-------------- 1 file changed, 62 insertions(+), 48 deletions(-) diff --git a/components/dashboard/Sidebar.tsx b/components/dashboard/Sidebar.tsx index 84acc61..f63f2db 100644 --- a/components/dashboard/Sidebar.tsx +++ b/components/dashboard/Sidebar.tsx @@ -19,7 +19,6 @@ import { ChevronUpDownIcon, PlusIcon, XIcon, - MenuIcon, } from '@ciphera-net/ui' const SIDEBAR_KEY = 'pulse_sidebar_collapsed' @@ -108,29 +107,27 @@ function SitePicker({ ) return ( -
+
{open && ( -
+
void + pendingHref: string | null + onNavigate: (href: string) => void }) { const pathname = usePathname() const href = item.href(siteId) - const active = item.matchPrefix ? pathname.startsWith(href) : pathname === href + + // Active if pathname matches OR if this link was just clicked (optimistic) + const matchesPathname = item.matchPrefix ? pathname.startsWith(href) : pathname === href + const matchesPending = pendingHref !== null && (item.matchPrefix ? pendingHref.startsWith(href) : pendingHref === href) + const active = matchesPathname || matchesPending + + const handleClick = () => { + onNavigate(href) + onClick?.() + } return ( - - {item.label} - + {!collapsed && ( + + {item.label} + + )} ) } @@ -240,6 +248,7 @@ export default function Sidebar({ const canEdit = user?.role === 'owner' || user?.role === 'admin' const pathname = usePathname() const [sites, setSites] = useState([]) + const [pendingHref, setPendingHref] = useState(null) const [collapsed, setCollapsed] = useState(() => { if (typeof window === 'undefined') return false return localStorage.getItem(SIDEBAR_KEY) === 'true' @@ -249,8 +258,9 @@ export default function Sidebar({ listSites().then(setSites).catch(() => {}) }, []) - // Close mobile on navigation + // Clear pending href once navigation completes useEffect(() => { + setPendingHref(null) onMobileClose() }, [pathname, onMobileClose]) @@ -276,6 +286,10 @@ export default function Sidebar({ }) }, []) + const handleNavigate = useCallback((href: string) => { + setPendingHref(href) + }, []) + const sidebarContent = (isMobile: boolean) => { const isCollapsed = isMobile ? false : collapsed @@ -284,40 +298,36 @@ export default function Sidebar({ {/* Logo */} Pulse - - Pulse - + {!isCollapsed && ( + + Pulse + + )} {/* Site Picker */} {/* Nav Groups */} -