diff --git a/web/src/App.tsx b/web/src/App.tsx index 059b5eb..83418e6 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -320,12 +320,14 @@ export default function App() { return stored.openai ?? PROVIDER_FALLBACK_MODELS.openai[0]; }); const [error, setError] = useState(null); + const transcriptContainerRef = useRef(null); const transcriptEndRef = useRef(null); const contextMenuRef = useRef(null); const selectedItemRef = useRef(null); const pendingTitleGenerationRef = useRef>(new Set()); const searchRunAbortRef = useRef(null); const searchRunCounterRef = useRef(0); + const shouldAutoScrollRef = useRef(true); const wasSendingRef = useRef(false); const [contextMenu, setContextMenu] = useState(null); const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false); @@ -506,6 +508,10 @@ export default function App() { const selectedKey = selectedItem ? `${selectedItem.kind}:${selectedItem.id}` : null; + useEffect(() => { + shouldAutoScrollRef.current = true; + }, [draftKind, selectedItem?.kind, selectedKey]); + useEffect(() => { selectedItemRef.current = selectedItem; }, [selectedItem]); @@ -534,6 +540,7 @@ export default function App() { const wasSending = wasSendingRef.current; wasSendingRef.current = isSending; if (wasSending && !isSending) return; + if (!shouldAutoScrollRef.current) return; transcriptEndRef.current?.scrollIntoView({ behavior: isSending ? "smooth" : "auto", block: "end" }); }, [draftKind, selectedChat?.messages.length, isSending, selectedItem?.kind, selectedKey]); @@ -1174,7 +1181,16 @@ export default function App() { -
+
{ + const container = transcriptContainerRef.current; + if (!container) return; + const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight; + shouldAutoScrollRef.current = distanceFromBottom < 96; + }} + > {!isSearchMode ? ( ) : (