From ff067f76dd8e9e05f0528056f1274adf01a54d70 Mon Sep 17 00:00:00 2001 From: Pascal Date: Sun, 26 Jul 2026 06:51:10 +0200 Subject: [PATCH] ui: fix context gauge card regressions and land at the conversation end (#26099) The context gauge card starts monitoring like the dial does, because its own processing state instance only follows the live stream while its monitoring flag is set. It also gets back the text-sm and ring classes the removed hover card wrapper used to inject, which restores its layout. Routing to a conversation now lands at the bottom instantly and keeps the pin one frame at a time until the page height settles, since content-visibility size realizations and syntax highlight passes grow the page without DOM mutations. --- .../ContextGaugePopup.svelte | 9 ++++- .../app/chat/ChatScreen/ChatScreen.svelte | 40 ++++++++++++++++++- tools/ui/src/lib/constants/auto-scroll.ts | 6 +++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormContextGauge/ContextGaugePopup.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormContextGauge/ContextGaugePopup.svelte index 81acdbaf7..af9ad010e 100644 --- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormContextGauge/ContextGaugePopup.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormContextGauge/ContextGaugePopup.svelte @@ -13,6 +13,13 @@ const gauge = useContextGauge(); + // The gauge hook wraps a processing state instance that only follows the + // live stream while its own monitoring flag is set, so the card instance + // starts monitoring like the dial does. + $effect(() => { + gauge.startMonitoring(); + }); + let cardEl = $state(null); // Any press outside the card and outside the dial closes the card. @@ -44,7 +51,7 @@
{ + if (autoScroll.userScrolledUp) return; + if (activeConversation()?.id !== id) return; + autoScroll.scrollToBottom(); + const height = container.scrollHeight; + stableFrames = height === lastHeight ? stableFrames + 1 : 0; + lastHeight = height; + if (stableFrames >= LANDING_STABLE_FRAMES) return; + if (performance.now() - started > LANDING_SETTLE_MAX_MS) return; + requestAnimationFrame(settle); + }; + requestAnimationFrame(settle); + } + function handleSendLikeScroll() { if (!isMobile.current) { autoScroll.enable(); @@ -246,6 +281,7 @@ {#if !isEmpty} { handleSendLikeScroll(); }} diff --git a/tools/ui/src/lib/constants/auto-scroll.ts b/tools/ui/src/lib/constants/auto-scroll.ts index c629228eb..67c5f9301 100644 --- a/tools/ui/src/lib/constants/auto-scroll.ts +++ b/tools/ui/src/lib/constants/auto-scroll.ts @@ -1,4 +1,10 @@ export const AUTO_SCROLL_INTERVAL = 100; +// Conversation landing: the page keeps growing after the first bottom pin +// without DOM mutations (content-visibility size realizations, syntax +// highlight passes), so the pin repeats every frame until the height holds +// for this many consecutive frames, bounded by the time cap below. +export const LANDING_STABLE_FRAMES = 10; +export const LANDING_SETTLE_MAX_MS = 1000; // Chat main view: tight threshold because scroll-here events come from // discrete assistant-message appends. export const AUTO_SCROLL_AT_BOTTOM_THRESHOLD = 10;