Recycle grid cards instead of rebuilding them
Scrolling the grid did nothing but destroy cards and build near-identical ones back: a template string parsed as innerHTML, ten querySelectors, and a listener per interactive element, every time a card entered the window. The virtualizer now keeps a pool and rebinds a card it already has -- 18us against 136us to build one, and 74-83% of mounts are served from it. Two things had to change first. Nothing on a card may close over the video it is showing, because the card outlives the video, so every interaction moved to one delegated listener per event type on the grid. And every card now has the same shape whatever it shows: the optional parts are always present and hidden when unused, so any pooled card fits any video. That needed a global [hidden] rule, since .live-badge and .video-tags carry their own display. The rest is the release path, which is where this design lives or dies. A thumbnail carries a generation, so a race or a proxy fallback settling after the card moved on cannot paint over the video now showing. The player stamps the card it was opened from, so a recycled element stops answering for it. The reveal handler, the entrance-animation listener and the hover preview are all taken back off. Anything missed here surfaces as one video's title, thumbnail or heart on another video's card, which is what the smoke suite scrolls back and forth to catch. Two incidental fixes found while measuring: bindCard no longer writes a data-tag per tag button (dataset is a proxy, and that alone cost more than the rest of a rebind put together -- the handler reads the label off the button), and favorites.has no longer parses a URL for every card that isn't a favorite by key. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QBDkEXP4htyXTCZUwMLphd
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
/* A card keeps its optional parts (live badge, uploader, duration, tags) at all
|
||||
times and hides the ones this video doesn't need, so any pooled card fits any
|
||||
video -- see bindCard. Several of those carry their own `display`, which beats
|
||||
the UA rule for [hidden], so say it once and mean it. */
|
||||
[hidden] { display: none !important; }
|
||||
|
||||
:root {
|
||||
/* Warm "classic" dark: deep charcoal with a hint of brown, never pure black. */
|
||||
--bg-primary: #14110d;
|
||||
|
||||
Reference in New Issue
Block a user