diff --git a/packages/dashboard/app/components/LeftSidebarNav.css b/packages/dashboard/app/components/LeftSidebarNav.css index 0187fee084..1d5114c0b6 100644 --- a/packages/dashboard/app/components/LeftSidebarNav.css +++ b/packages/dashboard/app/components/LeftSidebarNav.css @@ -110,6 +110,10 @@ The active sidebar item must use the defined --status-todo-bg token so the dashb right: calc(var(--space-xs) * -1); } +/* +FNXC:Navigation 2026-06-21-00:00: +The narrower resizable sidebar must preserve row rhythm by truncating labels instead of wrapping or pushing badges/toggles out of place. Rail mode still hides labels entirely through the collapsed sidebar rule. +*/ .left-sidebar-nav__label { flex: 1; min-width: 0; diff --git a/packages/dashboard/app/components/LeftSidebarNav.tsx b/packages/dashboard/app/components/LeftSidebarNav.tsx index 785482e05a..902d7352fc 100644 --- a/packages/dashboard/app/components/LeftSidebarNav.tsx +++ b/packages/dashboard/app/components/LeftSidebarNav.tsx @@ -57,9 +57,12 @@ interface SidebarNavEntry { /* FNXC:Navigation 2026-06-20-00:00: The experimental sidebar default is intentionally narrower than the original 256px layout so desktop/tablet navigation preserves more board content while keeping the existing resize clamps. + +FNXC:Navigation 2026-06-21-00:00: +The minimum resizable width is lowered so users can recover board/content space without forcing full rail collapse. Keep the floor at the narrowest label-legible width; below this point users should switch to collapse/rail mode to preserve icons, badges, and labels. */ const LEFT_SIDEBAR_DEFAULT_WIDTH = 224; -const LEFT_SIDEBAR_MIN_WIDTH = 192; +const LEFT_SIDEBAR_MIN_WIDTH = 160; const LEFT_SIDEBAR_MAX_WIDTH = 384; const LEFT_SIDEBAR_WIDTH_STORAGE_KEY = "fusion:left-sidebar-width"; const LEFT_SIDEBAR_COLLAPSED_STORAGE_KEY = "fusion:left-sidebar-collapsed"; diff --git a/packages/dashboard/app/components/__tests__/LeftSidebarNav.test.tsx b/packages/dashboard/app/components/__tests__/LeftSidebarNav.test.tsx index ad81a7b01b..b6efbe3e51 100644 --- a/packages/dashboard/app/components/__tests__/LeftSidebarNav.test.tsx +++ b/packages/dashboard/app/components/__tests__/LeftSidebarNav.test.tsx @@ -388,6 +388,21 @@ describe("LeftSidebarNav", () => { expect(window.localStorage.getItem("fusion:left-sidebar-width")).toBe("384"); }); + it("clamps and persists the narrower minimum drag resize width", () => { + renderSidebar(); + const sidebar = screen.getByTestId("left-sidebar-nav"); + const handle = screen.getByTestId("sidebar-nav-resize-handle"); + + expect(handle).toHaveAttribute("aria-valuemin", "160"); + + fireEvent.pointerDown(handle, { clientX: 224, pointerId: 1 }); + fireEvent.pointerMove(document, { clientX: 0 }); + fireEvent.pointerUp(document, { clientX: 0, pointerId: 1 }); + + expect(sidebar).toHaveStyle({ width: "160px", minWidth: "160px" }); + expect(window.localStorage.getItem("fusion:left-sidebar-width")).toBe("160"); + }); + it("restores persisted width and keyboard-resizes within clamps", () => { window.localStorage.setItem("fusion:left-sidebar-width", "999"); renderSidebar(); @@ -401,6 +416,28 @@ describe("LeftSidebarNav", () => { expect(window.localStorage.getItem("fusion:left-sidebar-width")).toBe("336"); }); + it("restores below-minimum persisted width to the narrower minimum", () => { + window.localStorage.setItem("fusion:left-sidebar-width", "120"); + renderSidebar(); + + expect(screen.getByTestId("left-sidebar-nav")).toHaveStyle({ width: "160px", minWidth: "160px" }); + expect(screen.getByTestId("sidebar-nav-resize-handle")).toHaveAttribute("aria-valuenow", "160"); + }); + + it("keyboard resizing clamps and persists the narrower minimum width", () => { + renderSidebar(); + + const sidebar = screen.getByTestId("left-sidebar-nav"); + const handle = screen.getByTestId("sidebar-nav-resize-handle"); + + fireEvent.keyDown(handle, { key: "ArrowLeft", shiftKey: true }); + fireEvent.keyDown(handle, { key: "ArrowLeft", shiftKey: true }); + + expect(sidebar).toHaveStyle({ width: "160px", minWidth: "160px" }); + expect(handle).toHaveAttribute("aria-valuenow", "160"); + expect(window.localStorage.getItem("fusion:left-sidebar-width")).toBe("160"); + }); + it("routes clicks to view changes, todos view, and settings callback", () => { const onOpenSettings = vi.fn(); const { onChangeView } = renderSidebar({ todosEnabled: true, onOpenSettings });