From 14dc49dc8849f9de23c30f8adb321d0fc1964d68 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 14 Sep 2026 14:17:09 -0700 Subject: [PATCH 1/2] improvement(sidebar): allow dragging the sidebar slightly narrower than the default --- apps/sim/app/layout.tsx | 6 +++--- .../components/workflow-item/avatars/avatars.tsx | 4 ++-- .../[workspaceId]/w/components/sidebar/sidebar.tsx | 4 ++-- apps/sim/stores/constants.ts | 3 ++- apps/sim/stores/sidebar/store.test.ts | 9 +++++++++ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/sim/app/layout.tsx b/apps/sim/app/layout.tsx index ab09b550b13..ecb416526e4 100644 --- a/apps/sim/app/layout.tsx +++ b/apps/sim/app/layout.tsx @@ -120,7 +120,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) } // Sidebar width. Mirror getMaxSidebarWidth() in stores/sidebar/store.ts: - // 30% of the viewport capped at 400px, and never below the 256px + // 30% of the viewport capped at 400px, and never below the 224px // minimum, so a narrow window yields a width >= MIN instead of a // sub-minimum sliver. var defaultSidebarWidth = 256; @@ -149,10 +149,10 @@ export default function RootLayout({ children }: { children: React.ReactNode }) // collapsed, because the desktop hover-peek renders the sidebar at // its restore width while --sidebar-width still reads collapsed. var width = state && state.sidebarWidth; - var maxSidebarWidth = Math.max(256, Math.min(400, window.innerWidth * 0.3)); + var maxSidebarWidth = Math.max(224, Math.min(400, window.innerWidth * 0.3)); var expandedWidth = typeof width === 'number' && isFinite(width) - ? Math.min(Math.max(width, 256), maxSidebarWidth) + ? Math.min(Math.max(width, 224), maxSidebarWidth) : defaultSidebarWidth; document.documentElement.style.setProperty( '--sidebar-expanded-width', diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/avatars/avatars.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/avatars/avatars.tsx index 19b29832c61..858ba468258 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/avatars/avatars.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/avatars/avatars.tsx @@ -33,10 +33,10 @@ export function Avatars({ workflowId }: AvatarsProps) { /** * Scale the max visible avatars between MIN_COUNT and MAX_COUNT as the sidebar - * widens. + * widens past its default width. */ const maxVisible = useMemo(() => { - const widthDelta = sidebarWidth - SIDEBAR_WIDTH.MIN + const widthDelta = sidebarWidth - SIDEBAR_WIDTH.DEFAULT const additionalAvatars = Math.floor(widthDelta / AVATAR_CONFIG.WIDTH_PER_AVATAR) const calculated = AVATAR_CONFIG.MIN_COUNT + additionalAvatars return Math.max(AVATAR_CONFIG.MIN_COUNT, Math.min(AVATAR_CONFIG.MAX_COUNT, calculated)) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx index dc76a2fa158..6355bdfee7b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx @@ -824,7 +824,7 @@ export const Sidebar = memo(function Sidebar() { const handleOpenSettings = (section: SettingsSection) => { if (!isCollapsedRef.current) { - setSidebarWidth(SIDEBAR_WIDTH.MIN) + setSidebarWidth(SIDEBAR_WIDTH.DEFAULT) } navigateToSettings({ section }) } @@ -898,7 +898,7 @@ export const Sidebar = memo(function Sidebar() { const navigateToPage = useCallback( (path: string) => { if (!isCollapsedRef.current) { - setSidebarWidth(SIDEBAR_WIDTH.MIN) + setSidebarWidth(SIDEBAR_WIDTH.DEFAULT) } router.push(path) }, diff --git a/apps/sim/stores/constants.ts b/apps/sim/stores/constants.ts index 45320008489..23540428fb7 100644 --- a/apps/sim/stores/constants.ts +++ b/apps/sim/stores/constants.ts @@ -29,7 +29,8 @@ export const CONTENT_WINDOW_GAP = 0 /** Sidebar width constraints */ export const SIDEBAR_WIDTH = { DEFAULT: 256, - MIN: 256, + /** Narrowest the expanded rail can be dragged — slightly under the default */ + MIN: 224, /** Width when sidebar is collapsed to icon-only mode */ COLLAPSED: 48, /** diff --git a/apps/sim/stores/sidebar/store.test.ts b/apps/sim/stores/sidebar/store.test.ts index 29fde806bc1..a9f36fbe9f2 100644 --- a/apps/sim/stores/sidebar/store.test.ts +++ b/apps/sim/stores/sidebar/store.test.ts @@ -54,6 +54,15 @@ describe('sidebar width CSS variables', () => { expect(widthVars()).toEqual({ width: '300px', expanded: '300px' }) }) + it('allows narrowing below the default down to the minimum', () => { + useSidebarStore.getState().setSidebarWidth(SIDEBAR_WIDTH.MIN) + expect(useSidebarStore.getState().sidebarWidth).toBe(SIDEBAR_WIDTH.MIN) + expect(SIDEBAR_WIDTH.MIN).toBeLessThan(SIDEBAR_WIDTH.DEFAULT) + + useSidebarStore.getState().setSidebarWidth(SIDEBAR_WIDTH.MIN - 1) + expect(useSidebarStore.getState().sidebarWidth).toBe(SIDEBAR_WIDTH.MIN) + }) + it('keeps the expanded variable at the restore width while collapsed', () => { useSidebarStore.getState().setSidebarWidth(300) useSidebarStore.getState().toggleCollapsed() From 4403e2056780eaa6052afff69c8eab917cbfefd1 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 14 Sep 2026 14:22:59 -0700 Subject: [PATCH 2/2] fix(sidebar): clamp the default width fallback to the viewport maximum --- apps/sim/app/layout.tsx | 2 +- apps/sim/stores/sidebar/store.test.ts | 15 +++++++++++++++ apps/sim/stores/sidebar/store.ts | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/layout.tsx b/apps/sim/app/layout.tsx index ecb416526e4..12b5a343521 100644 --- a/apps/sim/app/layout.tsx +++ b/apps/sim/app/layout.tsx @@ -153,7 +153,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) var expandedWidth = typeof width === 'number' && isFinite(width) ? Math.min(Math.max(width, 224), maxSidebarWidth) - : defaultSidebarWidth; + : Math.min(defaultSidebarWidth, maxSidebarWidth); document.documentElement.style.setProperty( '--sidebar-expanded-width', expandedWidth + 'px' diff --git a/apps/sim/stores/sidebar/store.test.ts b/apps/sim/stores/sidebar/store.test.ts index a9f36fbe9f2..acb29350917 100644 --- a/apps/sim/stores/sidebar/store.test.ts +++ b/apps/sim/stores/sidebar/store.test.ts @@ -102,6 +102,21 @@ describe('sidebar width CSS variables', () => { expect(widthVars().expanded).toBe(`${SIDEBAR_WIDTH.MIN}px`) }) + + it('clamps the default fallback to a viewport maximum below the default', () => { + const innerWidth = window.innerWidth + window.innerWidth = 800 + try { + useSidebarStore.setState({ isCollapsed: false, sidebarWidth: Number.NaN }) + + useSidebarStore.getState().syncWidth() + + expect(widthVars().expanded).toBe(`${getMaxSidebarWidth(800)}px`) + expect(getMaxSidebarWidth(800)).toBeLessThan(SIDEBAR_WIDTH.DEFAULT) + } finally { + window.innerWidth = innerWidth + } + }) }) describe('getMaxSidebarWidth', () => { diff --git a/apps/sim/stores/sidebar/store.ts b/apps/sim/stores/sidebar/store.ts index 9dc2f69caf4..3f90d28148d 100644 --- a/apps/sim/stores/sidebar/store.ts +++ b/apps/sim/stores/sidebar/store.ts @@ -21,10 +21,10 @@ export function getMaxSidebarWidth(viewportWidth: number): number { /** Clamps an expanded sidebar width into the valid range for the current viewport. */ function clampSidebarWidth(width: number): number { - if (!Number.isFinite(width)) return SIDEBAR_WIDTH.DEFAULT + const target = Number.isFinite(width) ? width : SIDEBAR_WIDTH.DEFAULT const max = typeof window === 'undefined' ? Number.POSITIVE_INFINITY : getMaxSidebarWidth(window.innerWidth) - return Math.min(Math.max(width, SIDEBAR_WIDTH.MIN), max) + return Math.min(Math.max(target, SIDEBAR_WIDTH.MIN), max) } /**