Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions components/app/chat-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -445,12 +445,38 @@ export function ChatView({

// Opening a chat lands on its latest message; only new messages in the open chat glide in.
const shownChat = useRef<string | null>(null);
// Whether the reader is at the latest message, so the chat follows it.
const follow = useRef(true);
useLayoutEffect(() => {
const el = scroller.current;
if (!el) return;
follow.current = true;
el.scrollTo({ top: el.scrollHeight, behavior: shownChat.current === c.id && !matchMedia("(prefers-reduced-motion: reduce)").matches ? "smooth" : "instant" });
shownChat.current = c.id;
}, [messages.length, c.typing.length, c.id]);
// A reader at the bottom stays there when the column changes size (the side panel opening makes every bubble
// taller): they never land on old messages. One who scrolled up keeps their place. The chat only ever scrolls
// itself down, so moving up away from the bottom is always the reader's own.
useEffect(() => {
const el = scroller.current;
if (!el || typeof ResizeObserver !== "function") return;
let top = el.scrollTop;
const onScroll = () => {
if (el.scrollHeight - el.scrollTop - el.clientHeight < 40) follow.current = true;
else if (el.scrollTop < top) follow.current = false;
top = el.scrollTop;
};
const ro = new ResizeObserver(() => {
if (follow.current) el.scrollTop = el.scrollHeight;
});
ro.observe(el);
for (const child of Array.from(el.children)) ro.observe(child);
el.addEventListener("scroll", onScroll, { passive: true });
return () => {
ro.disconnect();
el.removeEventListener("scroll", onScroll);
};
}, [c.id]);

// Marked read only when there's something unread: each mark is a state change every open page reloads.
const lastAt = messages.at(-1)?.at ?? 0;
Expand Down
Loading