Library: infinite-scroll the results grid (refs #1) #8
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/library-infinite-scroll"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #1. See description in the commits.
Replaces the fixed 50-item pagination on the Library page with IntersectionObserver-driven infinite scroll so every matching item is reachable without manual paging. * New JSON endpoint `GET /items/page` returns `{items, total, has_more, offset, limit}` for the same filter / sort combination the SSR page already uses; `limit` is capped at `MAX_PAGE_LIMIT = 100`. * SSR library page keeps server-rendering the first slice (so no-JS still works), drops the `page` query param, removes the numeric pagination `<nav>`, and exposes the active filter set to JS via a `data-filters` attribute on the sentinel. * New `initInfiniteScroll` module in `app/static/app.js` handles IntersectionObserver fetch, dedupe by `data-item-id`, end-of-results marker, error + retry, and auto-refresh pause while a fetch is pending. * Selection toolbar re-queries checkboxes on update so streamed-in cards participate in bulk selection. * Tests cover slice, has_more boundary, limit cap, filter and sort round-trip, and a regression that the SSR page no longer exposes the numeric pagination block. Refs #1The first round of the infinite-scroll feature dropped a raw JSON string into the data-filters attribute via Jinja's |tojson filter. The filter marks its output as MarkupSafe so the quotes inside the payload were not escaped; the browser then closed the attribute at the first inner quote ({) and initInfiniteScroll ended up with a payload it could not parse, so no follow-up /items/page fetch ever fired. The three skeleton blocks next to the sentinel were also laid out as a 3-column grid that read as three empty boxes. * Serialise the filter payload in app/main.py and pass the escaped JSON string to the template (filters_payload); Jinja still escapes it on output so the browser sees {"q": ...}. * Render the loading skeleton as a single contained card-shaped block (flex column, max-width, surface card background) instead of three loose skeletons in a grid. Refs #1