authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-02-13 18:46:10-08:00
committergravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-02-13 18:46:10-08:00
logfa3cccc3f9ec880d0054f1f4f14f0fe7880185d3
tree26af15fcfab64eb1eb374d4f72eb62b84bb641f9
parent54e7dd96f73163a46f5ee6d0db652a7c55ee1d41
signature Commit is signed but in an unrecognized format.

fix message scrolling and update todo


2 files changed, 11 insertions(+), 3 deletions(-)

TODO.md+2-2
...@@ -12,5 +12,5 @@...@@ -12,5 +12,5 @@
12- [x] Reduce noise of tool calls (combine "command run" and "command completed", make tool calls a "box" with limited # of calls shown at a time, etc)12- [x] Reduce noise of tool calls (combine "command run" and "command completed", make tool calls a "box" with limited # of calls shown at a time, etc)
13- [ ] Insta focus input on new thread creation13- [ ] Insta focus input on new thread creation
14- [ ] Disable "streaming" (wait until whole paragraph/step finishes before showing it14- [ ] Disable "streaming" (wait until whole paragraph/step finishes before showing it
15- [ ] Making new thread should auto-focus input box15- [x] Making new thread should auto-focus input box
16- [ ] Threads should be scrolled to bottom on open (they currently start near top and "scroll down" after rendering, it's jank)16- [x] Threads should be scrolled to bottom on open (they currently start near top and "scroll down" after rendering, it's jank)
apps/web/src/components/ChatView.tsx+9-1
...@@ -13,6 +13,7 @@ import {...@@ -13,6 +13,7 @@ import {
13 type KeyboardEvent,13 type KeyboardEvent,
14 useCallback,14 useCallback,
15 useEffect,15 useEffect,
16 useLayoutEffect,
16 useMemo,17 useMemo,
17 useRef,18 useRef,
18 useState,19 useState,
...@@ -131,6 +132,7 @@ export default function ChatView() {...@@ -131,6 +132,7 @@ export default function ChatView() {
131 const [expandedWorkGroups, setExpandedWorkGroups] = useState<Record<string, boolean>>({});132 const [expandedWorkGroups, setExpandedWorkGroups] = useState<Record<string, boolean>>({});
132 const [nowTick, setNowTick] = useState(() => Date.now());133 const [nowTick, setNowTick] = useState(() => Date.now());
133 const [terminalFocusRequestId, setTerminalFocusRequestId] = useState(0);134 const [terminalFocusRequestId, setTerminalFocusRequestId] = useState(0);
135 const messagesScrollRef = useRef<HTMLDivElement>(null);
134 const messagesEndRef = useRef<HTMLDivElement>(null);136 const messagesEndRef = useRef<HTMLDivElement>(null);
135 const textareaRef = useRef<HTMLTextAreaElement>(null);137 const textareaRef = useRef<HTMLTextAreaElement>(null);
136 const composerImagesRef = useRef<ComposerImageAttachment[]>([]);138 const composerImagesRef = useRef<ComposerImageAttachment[]>([]);
...@@ -345,6 +347,12 @@ export default function ChatView() {...@@ -345,6 +347,12 @@ export default function ChatView() {
345 // Auto-scroll on new messages347 // Auto-scroll on new messages
346 const messageCount = activeThread?.messages.length ?? 0;348 const messageCount = activeThread?.messages.length ?? 0;
347 const workLogCount = workLogEntries.length;349 const workLogCount = workLogEntries.length;
350 useLayoutEffect(() => {
351 if (!activeThread?.id) return;
352 const scrollContainer = messagesScrollRef.current;
353 if (!scrollContainer) return;
354 scrollContainer.scrollTop = scrollContainer.scrollHeight;
355 }, [activeThread?.id]);
348 useEffect(() => {356 useEffect(() => {
349 messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });357 messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
350 }, [messageCount]);358 }, [messageCount]);
...@@ -1014,7 +1022,7 @@ export default function ChatView() {...@@ -1014,7 +1022,7 @@ export default function ChatView() {
1014 )}1022 )}
10151023
1016 {/* Messages */}1024 {/* Messages */}
1017 <div className="min-h-0 flex-1 overflow-y-auto px-5 py-4">1025 <div ref={messagesScrollRef} className="min-h-0 flex-1 overflow-y-auto px-5 py-4">
1018 {activeThread.messages.length === 0 && !isWorking ? (1026 {activeThread.messages.length === 0 && !isWorking ? (
1019 <div className="flex h-full items-center justify-center">1027 <div className="flex h-full items-center justify-center">
1020 <p className="text-sm text-muted-foreground/30">1028 <p className="text-sm text-muted-foreground/30">