Fix thread scrubber anchoring

This commit is contained in:
dtonon 2026-08-27 22:50:03 +01:00
parent 7b80afbd6c
commit 997184cd66
2 changed files with 19 additions and 5 deletions

View file

@ -64,10 +64,11 @@
// The main column is its own scroll container (overflow-y-auto) and persists
// across navigations, so SvelteKit's window-only scroll restoration never
// resets it. Scroll it back to top on forward navigation; leave back/forward
// (popstate) alone so returning to a listing keeps its place.
// (popstate) alone so returning to a listing keeps its place, and hash
// targets (#post-…) alone so the page can place the anchored post itself.
let mainEl = $state<HTMLElement | null>(null);
afterNavigate((nav) => {
if (nav.type !== "popstate") mainEl?.scrollTo(0, 0);
if (nav.type !== "popstate" && !nav.to?.url.hash) mainEl?.scrollTo(0, 0);
});
// Nothing is fetched until the relay confirms it will serve this visitor:

View file

@ -390,12 +390,25 @@
await quotePost(post, text);
}
// The scrubber sticks where the OP starts. Measure independently of the
// current scroll (the page may mount already scrolled, e.g. arriving from a
// profile with a reply link) and again when the header changes height.
$effect(() => {
if (!opEl) return;
const el = opEl;
const header = threadEl?.querySelector("[data-thread-header]");
if (!el || !header) return;
const main = document.querySelector("main");
if (!main) return;
const measure = () => {
opTopOffset =
opEl.getBoundingClientRect().top - main.getBoundingClientRect().top;
el.getBoundingClientRect().top -
main.getBoundingClientRect().top +
main.scrollTop;
};
measure();
const ro = new ResizeObserver(measure);
ro.observe(header);
return () => ro.disconnect();
});
</script>