From ea137c32c38cc66d9aba24cbda3a6f18b1f10d48 Mon Sep 17 00:00:00 2001 From: Lukas Remis Date: Mon, 21 Sep 2026 21:32:15 +0200 Subject: [PATCH] Mail list: a new page starts at the top MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Paging while scrolled down kept the old scroll position, so clicking next dropped you into the middle of the following fifty with nothing to signal you had moved. The list is virtualized, so there is no natural anchor to reset — the scroll container has to be told. MessageList now takes the page number and scrolls back to the top when it changes. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018SqJYt7jD7oUEkoY68sBZo --- frontend/src/components/list/MessageList.tsx | 11 ++++++++++- frontend/src/routes/MailLayout.tsx | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/list/MessageList.tsx b/frontend/src/components/list/MessageList.tsx index cc094fe..82ede33 100644 --- a/frontend/src/components/list/MessageList.tsx +++ b/frontend/src/components/list/MessageList.tsx @@ -1,6 +1,6 @@ import { useQuery } from "@tanstack/react-query"; import { useVirtualizer } from "@tanstack/react-virtual"; -import { useRef } from "react"; +import { useEffect, useRef } from "react"; import { useT } from "../../i18n"; import { api } from "../../lib/api"; @@ -56,6 +56,7 @@ function Paperclip() { // Virtualized thread list (SPEC §2 list/MessageList.tsx). export function MessageList({ threads, + page, selectedId, folder, onSelect, @@ -69,6 +70,8 @@ export function MessageList({ onToggleCheck, }: { threads: ThreadSummary[]; + /** Which page of the list this is. Changing it scrolls back to the top. */ + page: number; selectedId?: string; folder: string; onSelect: (id: string) => void; @@ -106,6 +109,12 @@ export function MessageList({ overscan: 8, }); + // A new page starts at the top. Paging while scrolled down would otherwise + // drop you into the middle of the next fifty with no sense of having moved. + useEffect(() => { + parentRef.current?.scrollTo({ top: 0 }); + }, [page]); + if (threads.length === 0) { return
{t("mail.noConversations")}
; } diff --git a/frontend/src/routes/MailLayout.tsx b/frontend/src/routes/MailLayout.tsx index 793ebb4..05a410a 100644 --- a/frontend/src/routes/MailLayout.tsx +++ b/frontend/src/routes/MailLayout.tsx @@ -842,6 +842,7 @@ export function MailLayout() { ) : ( navigate(`/mail/t/${id}`)}