Build / Build (push) Successful in 33s
decePub no longer looks at the system's "reduce motion" setting, so everything moves the same way whatever it says: - a GIF video in a post plays by itself, muted and looping, instead of waiting for a tap; it now also starts on a page just opened, before the first tap, where the browser used to hold it still; - animated custom emoji move in the emoji picker instead of showing a still picture; - the globe turns by itself while no located post is in view, flies to the posts, and its pulses, arcs and Sun move; - going back to the top of a feed scrolls smoothly; - tooltips, dropdowns, menus, folding sections, toasts, loading spinners, placeholders, progress bars, radio buttons and ratings keep their animations: the build now takes daisyUI's reduce-motion rules out of the stylesheet (tools/css/motion.py, run after every Tailwind build, in watch mode too). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W4YtEKqxKjKyHkFzuRVMNA
62 lines
1.7 KiB
JavaScript
62 lines
1.7 KiB
JavaScript
// The feed page's scrolling (Pages/Index.razor): tells .NET when the end of the list comes near, so the next page loads
|
|
// before the reader gets there, and whether the page is visible, so polling for new posts stops in a hidden tab.
|
|
|
|
let observer = null
|
|
let sentinel = null
|
|
let reference = null
|
|
|
|
export function observeEnd(dotNetReference, sentinelId, rootId) {
|
|
dispose()
|
|
reference = dotNetReference
|
|
sentinel = document.getElementById(sentinelId)
|
|
const root = document.getElementById(rootId)
|
|
if (!sentinel || !root)
|
|
return
|
|
observer = new IntersectionObserver(entries => {
|
|
if (entries.some(entry => entry.isIntersecting))
|
|
nearEnd()
|
|
}, { root, rootMargin: "0px 0px 800px 0px" })
|
|
observer.observe(sentinel)
|
|
}
|
|
|
|
// After a page is added: if the end is still in sight (a short page), ask for the next one too.
|
|
export function checkEnd() {
|
|
if (!sentinel || !observer)
|
|
return
|
|
const root = observer.root
|
|
const end = sentinel.getBoundingClientRect().top
|
|
const bottom = root.getBoundingClientRect().bottom
|
|
if (end < bottom + 800)
|
|
nearEnd()
|
|
}
|
|
|
|
export function isVisible() {
|
|
return document.visibilityState === "visible"
|
|
}
|
|
|
|
// The scroll a feed was left at, and the way back to it (Services/FeedMemory.cs).
|
|
export function scrollOffset(rootId) {
|
|
return document.getElementById(rootId)?.scrollTop ?? 0
|
|
}
|
|
|
|
export function scrollToOffset(rootId, top) {
|
|
const root = document.getElementById(rootId)
|
|
if (root)
|
|
root.scrollTop = top
|
|
}
|
|
|
|
export function scrollToTop(rootId) {
|
|
document.getElementById(rootId)?.scrollTo({ top: 0, behavior: "smooth" })
|
|
}
|
|
|
|
export function dispose() {
|
|
observer?.disconnect()
|
|
observer = null
|
|
sentinel = null
|
|
reference = null
|
|
}
|
|
|
|
function nearEnd() {
|
|
reference?.invokeMethodAsync("NearEnd").catch(e => console.error(e))
|
|
}
|