perf(photos): virtualize the timeline to bound DOM node count

The photos timeline rendered every tile into the DOM and grew it
unbounded on infinite scroll, degrading on large libraries. Each
date-group is now a <section> whose grid is materialized (tiles
inserted) only while near the viewport and dematerialized (emptied,
height frozen as a spacer) once it scrolls away, driven by an
IntersectionObserver rooted on the scroll container. DOM nodes stay
bounded by a few screens regardless of library size.

- Grouping (day/month/year), infinite scroll, multi-select, video
  thumbnails and fade-in are all preserved.
- Selection state and the video-thumbnail cache survive the
  materialize/dematerialize cycle.
- Falls back to full rendering when IntersectionObserver is unavailable.
- Spacer heights are estimated from grid geometry and re-estimated on
  resize.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JW6ghFMDtnRYuYNzZhb47M
This commit is contained in:
Claude
2026-06-19 09:30:41 +00:00
parent 293986d1f6
commit 081b2b68d8
2 changed files with 273 additions and 92 deletions
+6
View File
@@ -8,6 +8,12 @@
display: block;
}
/* Virtualized timeline: each date-group is a <section>; its grid is
materialized (tiles inserted) only while near the viewport — see photos.js. */
.photos-group {
display: block;
}
/* Toolbar with group mode toggle */
.photos-toolbar {
display: flex;