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(() => {