Re-anchor the room feed on the present when jumping to newest

This commit is contained in:
Coracle-Bot 2026-09-10 00:45:54 +00:00 committed by hodlbod
parent 528a04de38
commit 7e3a0c9741
2 changed files with 18 additions and 11 deletions

View file

@ -404,8 +404,8 @@ Acceptance:
- Clicking a result closes search and scrolls the timeline to the message, - Clicking a result closes search and scrolls the timeline to the message,
highlighted in view. highlighted in view.
- Opening a permalink url for a specific message lands on that message directly, - Opening a permalink url for a specific message lands on that message directly,
with a "jump to newest" control shown since the view is no longer at the newest and in a room short enough that the window opening with it reaches the present,
message. Using it returns to the live end and the control goes away. there is nothing left to jump back to and no control.
### US-027a — Follow a link to a recent message ### US-027a — Follow a link to a recent message

View file

@ -128,7 +128,7 @@
pushToast({theme: "error", message}) pushToast({theme: "error", message})
} else { } else {
// Restart the feed now that we're a member // Restart the feed now that we're a member
start() start(at || now())
} }
} finally { } finally {
joining = false joining = false
@ -339,12 +339,19 @@
const scrollToNewMessages = () => scrollToRow("new-messages", {behavior: "smooth"}) const scrollToNewMessages = () => scrollToRow("new-messages", {behavior: "smooth"})
const scrollToBottom = () => { // While the window stops short, dropping the anchor only takes the button away: where the reader
if (!isNaN(at)) { // lands is then whatever the list settles on as it re-windows and the forward walk catches up,
navigate($page.url.pathname, {replaceState: true}) // which is not reliably the live end. Anchoring a fresh feed on the present puts it there.
} else { const scrollToBottom = async () => {
element?.scrollTo({top: 0, behavior: "smooth"}) const anchored = !isNaN(at)
if (anchored) {
release()
await navigate($page.url.pathname, {replaceState: true})
start(now())
} }
element?.scrollTo({top: 0, behavior: anchored ? "auto" : "smooth"})
} }
// A tab can be `visible` but unfocused (user alt-tabbed to another app), so we // A tab can be `visible` but unfocused (user alt-tabbed to another app), so we
@ -474,12 +481,12 @@
} }
}) })
const start = () => { const start = (anchor: number) => {
cleanup?.() cleanup?.()
const feed = makeFeed({ const feed = makeFeed({
relays: [url], relays: [url],
at: at || now(), at: anchor,
filters: [ filters: [
h ? {kinds: [MESSAGE, addMemberKind], "#h": [h]} : {kinds: [MESSAGE, addMemberKind]}, h ? {kinds: [MESSAGE, addMemberKind], "#h": [h]} : {kinds: [MESSAGE, addMemberKind]},
], ],
@ -519,7 +526,7 @@
onMount(() => { onMount(() => {
// Defer rendering until navigation finishes // Defer rendering until navigation finishes
let frame = requestAnimationFrame(() => { let frame = requestAnimationFrame(() => {
frame = requestAnimationFrame(start) frame = requestAnimationFrame(() => start(at || now()))
}) })
const unsubscribeActive = documentActive.subscribe(onActiveChange) const unsubscribeActive = documentActive.subscribe(onActiveChange)