From d1d28d6bb4ba5db4633849f83c276a1fa6250117 Mon Sep 17 00:00:00 2001 From: Amos Date: Sat, 22 Aug 2026 06:45:32 +0300 Subject: [PATCH] Session switch: land at the bottom instantly with the question dock open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Chat now remounts per session (key={chat.id}): fresh StickToBottom, fresh DockOverlay (no cross-session morph from the previous shell height), fresh useChat. - Conversation initial="instant" (was "smooth"): the mount scroll to bottom is a jump, not a slide. - DockOverlay skips the pending-question scroll/expand effect for the session's INITIAL pending question (dock starts expanded; the initial scroll positions us) — previously it fired a second smooth scrollToBottom right after the library's initial scroll (the visible 'pause, then the quiz pops and pushes everything up'). - The dock-variant fade/rise no longer plays for the session's opening variant; reserved for mid-session transitions. Verified live: client-side switch settles at d=1px from the bottom within one frame of content swap, dock open from the first frame, both directions (quiz session, plain session). --- app/chat/[id]/page.tsx | 1 + components/chat.tsx | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/chat/[id]/page.tsx b/app/chat/[id]/page.tsx index e463947..f91f1c3 100644 --- a/app/chat/[id]/page.tsx +++ b/app/chat/[id]/page.tsx @@ -17,6 +17,7 @@ export default async function ChatPage({ if (!chat) notFound(); return (
- +
{messages.length === 0 && !busy && ( @@ -208,14 +208,16 @@ function DockOverlay({ const [expanded, setExpanded] = useState(true); const pendingId = pending?.toolCallId ?? null; + const initialPendingRef = useRef(pendingId); - // New question: open expanded if the learner is following at the bottom - // (scroll to reveal it); if they're reading history, arrive as the slim bar. + // New question MID-SESSION: open expanded if the learner is following at + // the bottom (scroll to reveal it); reading history → arrive as the bar. + // On session mount the dock simply starts expanded at the bottom (the + // library's instant initial scroll positions us) — no scroll, no morph. useEffect(() => { - if (pendingId) { - setExpanded(isAtBottom); - if (isAtBottom) void scrollToBottom(); - } + if (!pendingId || pendingId === initialPendingRef.current) return; + setExpanded(isAtBottom); + if (isAtBottom) void scrollToBottom(); // eslint-disable-next-line react-hooks/exhaustive-deps -- fire only when a NEW question lands }, [pendingId]); @@ -258,6 +260,9 @@ function DockOverlay({ }; const mode = pending ? `question:${pending.toolCallId}` : "chat"; + // The opening variant of a session appears instantly — the fade/rise is + // reserved for mid-session transitions. + const initialModeRef = useRef(mode); // Height morph: animate the shell from its previous height to its new one // whenever the variant (chat ↔ question ↔ collapsed bar) changes. Typing @@ -298,7 +303,7 @@ function DockOverlay({
-
+
{pending ? (