From 7d935efa44ef9396258b4f540a8140855d4229aa Mon Sep 17 00:00:00 2001 From: King-of-Infinite-Space <27502578+King-of-Infinite-Space@users.noreply.github.com> Date: Fri, 5 Jun 2026 00:06:15 -0700 Subject: [PATCH] feat: improve chat overview with persistent viewport and pinning Introduces viewport state persistence and a pin toggle for the chat overview (tree view), along with minor fix and cleanup. - Added a "Viewport Pinned" toggle to disable auto-focus on active node. - Persists viewport coordinates (x, y, zoom), layout direction, and pin state to localStorage. - Debounced the localStorage viewport save (300ms) to prevent blocking during smooth pan/zoom gestures. - Structured overviewViewports cache as a self-pruning 50-item LRU to prevent unbounded storage bloat. - Resolved an existing memory leak by properly cleaning up nodesInitialized, width, and height store subscriptions on component destroy. - Fixed a scroll alignment bug when navigating from the Overview tree. Defers scrollIntoView to the next event loop tick (0ms) so dynamic elements can layout properly before calculating the target scroll coordinate. - Removed unused imports. --- src/lib/components/chat/Chat.svelte | 10 +- src/lib/components/chat/Overview/Flow.svelte | 27 ++-- src/lib/components/chat/Overview/View.svelte | 149 ++++++++++++++----- 3 files changed, 136 insertions(+), 50 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 69652dbe41..8f4f7106fb 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -454,10 +454,12 @@ await tick(); if (($settings?.scrollOnBranchChange ?? true) && scroll) { - const messageElement = document.getElementById(`message-${message.id}`); - if (messageElement) { - messageElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); - } + setTimeout(() => { + const messageElement = document.getElementById(`message-${message.id}`); + if (messageElement) { + messageElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + }, 0); } await tick(); diff --git a/src/lib/components/chat/Overview/Flow.svelte b/src/lib/components/chat/Overview/Flow.svelte index d3963e22ae..707c0b760e 100644 --- a/src/lib/components/chat/Overview/Flow.svelte +++ b/src/lib/components/chat/Overview/Flow.svelte @@ -1,7 +1,7 @@ dispatch('nodeclick', e.detail)} - oninit={() => { - console.log('Flow initialized'); - }} + on:nodeclick={(e) => onNodeClick?.(e.detail)} + oninit={() => {}} > + (viewportPinned = !viewportPinned)} + title={viewportPinned ? $i18n.t('Viewport Pinned') : $i18n.t('Viewport Unpinned')} + > + {#if viewportPinned} + + {:else} + + {/if} + setLayoutDirection('vertical')} title="Vertical Layout"> diff --git a/src/lib/components/chat/Overview/View.svelte b/src/lib/components/chat/Overview/View.svelte index d757c69dd2..6a88f12c7a 100644 --- a/src/lib/components/chat/Overview/View.svelte +++ b/src/lib/components/chat/Overview/View.svelte @@ -1,25 +1,20 @@