(feat): improve chat ui
All checks were successful
/ build-web (push) Successful in 7m57s
/ build-desktop (linux) (push) Successful in 12m32s
/ build-mobile (push) Successful in 20m14s
/ release (push) Successful in 3m38s

This commit is contained in:
Alois 2026-08-05 00:30:11 +02:00
commit 4cb38264d0
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24

View file

@ -146,6 +146,7 @@ export default function Screen() {
setComposerValue, setComposerValue,
} = useChat(); } = useChat();
const scrollRef = useRef<HTMLDivElement | null>(null); const scrollRef = useRef<HTMLDivElement | null>(null);
const composerRef = useRef<HTMLDivElement | null>(null);
const topSentinelRef = useRef<HTMLDivElement | null>(null); const topSentinelRef = useRef<HTMLDivElement | null>(null);
const didInitialScrollRef = useRef(false); const didInitialScrollRef = useRef(false);
const userScrolledUpRef = useRef(false); const userScrolledUpRef = useRef(false);
@ -159,6 +160,7 @@ export default function Screen() {
const [lastLiveMessageCount, setLastLiveMessageCount] = useState(0); const [lastLiveMessageCount, setLastLiveMessageCount] = useState(0);
const [didInitialScroll, setDidInitialScroll] = useState(false); const [didInitialScroll, setDidInitialScroll] = useState(false);
const [viewportHeight, setViewportHeight] = useState(0); const [viewportHeight, setViewportHeight] = useState(0);
const [composerHeight, setComposerHeight] = useState(0);
const [editingMessageId, setEditingMessageId] = useState<number | null>(null); const [editingMessageId, setEditingMessageId] = useState<number | null>(null);
const previousEditingMessageIdRef = useRef<number | null>(null); const previousEditingMessageIdRef = useRef<number | null>(null);
@ -280,6 +282,7 @@ export default function Screen() {
getItemKey, getItemKey,
estimateSize, estimateSize,
overscan: 2, overscan: 2,
paddingStart: composerHeight + 8,
}); });
const totalSize = virtualizer.getTotalSize(); const totalSize = virtualizer.getTotalSize();
const contentHeight = Math.max(totalSize, viewportHeight); const contentHeight = Math.max(totalSize, viewportHeight);
@ -333,6 +336,26 @@ export default function Screen() {
}; };
}, []); }, []);
useLayoutEffect(() => {
const element = composerRef.current;
if (!element || typeof ResizeObserver === "undefined") {
return;
}
const updateComposerHeight = () => {
setComposerHeight(element.getBoundingClientRect().height);
};
updateComposerHeight();
const observer = new ResizeObserver(updateComposerHeight);
observer.observe(element);
return () => {
observer.disconnect();
};
}, []);
useLayoutEffect(() => { useLayoutEffect(() => {
if (didInitialScrollRef.current || virtualRowCount === 0) { if (didInitialScrollRef.current || virtualRowCount === 0) {
return; return;
@ -382,22 +405,6 @@ export default function Screen() {
void messagesQuery.fetchNextPage(); void messagesQuery.fetchNextPage();
}, [didInitialScroll, messagesQuery, totalSize, viewportHeight]); }, [didInitialScroll, messagesQuery, totalSize, viewportHeight]);
useLayoutEffect(() => {
if (
!didInitialScroll ||
userScrolledUpRef.current ||
virtualRowCount === 0
) {
return;
}
requestAnimationFrame(() => {
if (scrollRef.current) {
scrollRef.current.scrollTop = 0;
}
});
}, [didInitialScroll, virtualRowCount]);
useEffect(() => { useEffect(() => {
const root = scrollRef.current; const root = scrollRef.current;
const sentinel = topSentinelRef.current; const sentinel = topSentinelRef.current;
@ -623,7 +630,7 @@ export default function Screen() {
})} })}
</div> </div>
</div> </div>
<div className="z-10 shrink-0"> <div ref={composerRef} className="absolute inset-x-0 bottom-0 z-10">
<InputComponent <InputComponent
onEditLastMessage={editLastMessage} onEditLastMessage={editLastMessage}
setValue={setComposerValue} setValue={setComposerValue}