Pin scroll position to at'd event until user scrolls

This commit is contained in:
Jon Staab
2026-02-16 14:58:21 -08:00
parent c8eb4ac31a
commit 69f6abf4b6
3 changed files with 55 additions and 8 deletions
+1 -2
View File
@@ -13,7 +13,6 @@ import {
isDefined,
filterVals,
fromPairs,
HOUR,
} from "@welshman/lib"
import {
EVENT_TIME,
@@ -48,7 +47,7 @@ export const makeFeed = ({
onForwardExhausted?: () => void
at?: number
}) => {
const interval = int(12, HOUR)
const interval = int(DAY)
const controller = new AbortController()
const events = writable<TrustedEvent[]>([])
+27 -3
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import {onMount} from "svelte"
import {onMount, tick} from "svelte"
import {readable} from "svelte/store"
import {page} from "$app/stores"
import type {Readable} from "svelte/store"
@@ -165,7 +165,7 @@
}
}
const onScroll = () => {
const manageScrollPosition = () => {
showScrollButton = Math.abs(element?.scrollTop || 0) > 1500
const newMessages = document.getElementById("new-messages")
@@ -181,6 +181,28 @@
showFixedNewMessages = y < 0
}
}
if (!userHasScrolled && $page.url.searchParams.get("at")) {
const targetEvent = $events.find(event => event.created_at >= at)
if (targetEvent) {
const target = element?.querySelector(`[data-event="${targetEvent.id}"]`)
if (target instanceof HTMLElement) {
isProgrammaticScroll = true
target.scrollIntoView({block: "center"})
}
}
}
}
const onScroll = () => {
if (!isProgrammaticScroll) {
userHasScrolled = true
manageScrollPosition()
}
isProgrammaticScroll = false
}
const scrollToNewMessages = () =>
@@ -197,6 +219,8 @@
let joining = $state(false)
let leaving = $state(false)
let userHasScrolled = $state(false)
let isProgrammaticScroll = $state(false)
let loadingBackward = $state(true)
let loadingForward = $state(true)
let at = $state(parseInt($page.url.searchParams.get("at") || String(now())))
@@ -272,7 +296,7 @@
elements.reverse()
setTimeout(onScroll, 100)
tick().then(manageScrollPosition)
return elements
})
+27 -3
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import {onMount} from "svelte"
import {onMount, tick} from "svelte"
import {page} from "$app/stores"
import type {Readable} from "svelte/store"
import {readable} from "svelte/store"
@@ -103,7 +103,7 @@
}
}
const onScroll = () => {
const manageScrollPosition = () => {
showScrollButton = Math.abs(element?.scrollTop || 0) > 1500
const newMessages = document.getElementById("new-messages")
@@ -119,6 +119,28 @@
showFixedNewMessages = y < 0
}
}
if (!userHasScrolled && $page.url.searchParams.get("at")) {
const targetEvent = $events.find(event => event.created_at >= at)
if (targetEvent) {
const target = element?.querySelector(`[data-event="${targetEvent.id}"]`)
if (target instanceof HTMLElement) {
isProgrammaticScroll = true
target.scrollIntoView({block: "center"})
}
}
}
}
const onScroll = () => {
if (!isProgrammaticScroll) {
userHasScrolled = true
manageScrollPosition()
}
isProgrammaticScroll = false
}
const scrollToNewMessages = () =>
@@ -135,6 +157,8 @@
let loadingBackward = $state(true)
let loadingForward = $state(true)
let userHasScrolled = $state(false)
let isProgrammaticScroll = $state(false)
let at = $state(parseInt($page.url.searchParams.get("at") || String(now())))
let share = $state(popKey<TrustedEvent | undefined>("share"))
let parent: TrustedEvent | undefined = $state()
@@ -208,7 +232,7 @@
elements.reverse()
setTimeout(onScroll, 100)
tick().then(manageScrollPosition)
return elements
})