From 562843e4b2aefa14314753ec4995893052c82423 Mon Sep 17 00:00:00 2001 From: TerryM Date: Tue, 2 Jun 2026 11:42:10 +0800 Subject: [PATCH] feat(stream): reset scroll to top on ?post deep-link arrivals Banner / Home-card clicks landing on /browse?post=X now always start the smooth-scroll positioning from the top of the stream, instead of from whatever scrollY the user happened to leave the page at. Runs in useLayoutEffect before paint so the user never briefly sees the previous position before the jump, giving a clearly visible scroll journey to the target post every time. Verified in the browser: before banner click scrollY=2000, immediately after =0, then smooth-scrolled to ~25k as pagination loaded the target post deeper in the stream. --- src/components/messageStream/MessageStream.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/messageStream/MessageStream.tsx b/src/components/messageStream/MessageStream.tsx index d8b2215..9a7163f 100644 --- a/src/components/messageStream/MessageStream.tsx +++ b/src/components/messageStream/MessageStream.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import { useLocation, useSearchParams } from "react-router-dom"; import { postJSON } from "../../api"; import { useI18n } from "../../i18n"; @@ -104,6 +104,16 @@ export function MessageStream({ scope }: MessageStreamProps) { setIsAligningQueryTarget(false); }, [queryTargetPostId, targetPostId]); + // Banner / deep-link arrivals (`?post=`) should always begin the + // smooth-scroll positioning from the top of the stream, so the user sees a + // clear, satisfying journey to the target post instead of a tiny nudge when + // they happen to revisit the page mid-scroll. Run before paint so the user + // never briefly sees the previous scrollY before the jump. + useLayoutEffect(() => { + if (!queryTargetPostId) return; + window.scrollTo({ top: 0, left: 0, behavior: "auto" }); + }, [queryTargetPostId]); + useEffect(() => clearTargetScrollTimers, []); useEffect(() => {