From b59d8bfe9da3006899ce4dcad901d2f8918bdfd7 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Thu, 20 Aug 2026 18:13:03 +0200 Subject: [PATCH] ui : track sidebar expanded state in a shared ui store Move the desktop sidebar expanded/collapsed state out of deviceStore into a dedicated uiStore so the chat tab bar can react to it. Assisted-by: pi --- .../SidebarNavigation.svelte | 51 ++++++++++--------- tools/ui/src/lib/stores/index.ts | 3 ++ tools/ui/src/lib/stores/ui.svelte.ts | 14 +++++ 3 files changed, 43 insertions(+), 25 deletions(-) create mode 100644 tools/ui/src/lib/stores/ui.svelte.ts diff --git a/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte b/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte index aa63c2915f..86b97325eb 100644 --- a/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte +++ b/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte @@ -14,7 +14,7 @@ import { useKeyboardShortcuts } from '$lib/hooks/use-keyboard-shortcuts.svelte'; import { useMarqueeSelection } from '$lib/hooks/use-marquee-selection.svelte'; import { RouterService } from '$lib/services/router.service'; - import { chatStore, conversationsStore, deviceStore, settingsStore } from '$lib/stores'; + import { chatStore, conversationsStore, deviceStore, settingsStore, uiStore } from '$lib/stores'; import { buildConversationTree } from '$lib/utils'; import { circIn } from 'svelte/easing'; import { SvelteSet } from 'svelte/reactivity'; @@ -31,30 +31,29 @@ toggleSidebar: () => toggleExpandedMode() }); - let isExpandedMode = $state(false); let hoveredTooltip = $state(null); let logoHovered = $state(false); - const isStripExpanded = $derived(isExpandedMode || hoveredTooltip !== null); + const isStripExpanded = $derived(uiStore.isSidebarExpanded || hoveredTooltip !== null); const isOnMobile = $derived(deviceStore.isMobile); const alwaysShowOnDesktop = $derived(settingsStore.config.alwaysShowSidebarOnDesktop as boolean); $effect(() => { if (alwaysShowOnDesktop && !isOnMobile) { - isExpandedMode = true; + uiStore.isSidebarExpanded = true; } }); function toggleExpandedMode() { - isExpandedMode = !isExpandedMode; + uiStore.isSidebarExpanded = !uiStore.isSidebarExpanded; - if (!isExpandedMode) { + if (!uiStore.isSidebarExpanded) { hoveredTooltip = null; } } $effect(() => { - if (!isExpandedMode) { + if (!uiStore.isSidebarExpanded) { isSearchModeActive = false; searchQuery = ''; @@ -66,7 +65,7 @@ $effect(() => { if (deviceStore.isMobile && page.url.hash.includes(ROUTES.SEARCH)) { - isExpandedMode = false; + uiStore.isSidebarExpanded = false; } }); @@ -294,7 +293,7 @@ } pendingCollapse = setTimeout(() => { - isExpandedMode = false; + uiStore.isSidebarExpanded = false; pendingCollapse = null; }, 100); } @@ -314,7 +313,7 @@ class={[ 'fixed md:sticky top-2 left-2 md:left-0 md:ml-2 md:mt-2 pt-2 z-10 w-[calc(100dvw-1rem)]', 'md:h-[calc(100dvh-1.125rem)]', - isExpandedMode && + uiStore.isSidebarExpanded && (deviceStore.isStandalone ? 'h-[calc(100dvh-2rem)]' : deviceStore.isIOSDevice @@ -323,9 +322,9 @@ 'rounded-3xl md:rounded-2xl', 'flex flex-col justify-between', 'md:transition-[width,padding] duration-200 ease-out', - isStripExpanded && 'md:w-72 md:bg-muted/60 md:backdrop-blur-xl border-border shadow-md', + isStripExpanded && 'md:w-72 md:bg-muted/60 md:backdrop-blur-xl shadow-md', !isStripExpanded && 'md:w-12', - isExpandedMode && 'is-expanded' + uiStore.isSidebarExpanded && 'is-expanded' ]} >
@@ -337,24 +336,26 @@ onmouseleave={() => (logoHovered = false)} > 768 ? PanelLeftOpen : Logo} + icon={!uiStore.isSidebarExpanded && logoHovered && innerWidth > 768 + ? PanelLeftOpen + : Logo} size="lg" iconSize="h-4.5 w-4.5 md:h-4 md:w-4" - class="{isExpandedMode + class="{uiStore.isSidebarExpanded ? 'bg-muted! md:bg-foreground/5!' - : 'bg-transparent!'} md:h-9 md:w-9 h-10 w-10 rounded-full md:hover:bg-foreground/10! pointer-events-auto" - href={isExpandedMode ? ROUTES.START : undefined} - onclick={isExpandedMode ? undefined : toggleExpandedMode} - tooltip={isExpandedMode ? undefined : 'Open Sidebar'} + : 'bg-transparent'} md:h-9 md:w-9 h-10 w-10 rounded-full md:hover:bg-foreground/10! pointer-events-auto" + href={uiStore.isSidebarExpanded ? ROUTES.START : undefined} + onclick={uiStore.isSidebarExpanded ? undefined : toggleExpandedMode} + tooltip={uiStore.isSidebarExpanded ? undefined : 'Open Sidebar'} tooltipSide={TooltipSide.RIGHT} - ariaLabel={isExpandedMode ? 'Go to start' : 'Expand navigation'} + ariaLabel={uiStore.isSidebarExpanded ? 'Go to start' : 'Expand navigation'} />
- {#if isOnMobile || (isExpandedMode && !alwaysShowOnDesktop)} + {#if isOnMobile || (uiStore.isSidebarExpanded && !alwaysShowOnDesktop)}
768 ? isExpandedMode : true} + isExpandedMode={innerWidth > 768 ? uiStore.isSidebarExpanded : true} class="px-2" bind:isSearchModeActive bind:searchQuery @@ -391,7 +392,7 @@ searchQuery = ''; }} onSearchClick={() => { - isExpandedMode = true; + uiStore.isSidebarExpanded = true; isSearchModeActive = true; }} onNewChat={() => { @@ -401,7 +402,7 @@ }} /> - {#if isExpandedMode || isOnMobile} + {#if uiStore.isSidebarExpanded || isOnMobile}