video discover: cascade rail cards in instead of one block flash

Each rail showed a shimmer skeleton then revealed the whole row in a single fade — on a
big library with hide-owned on (which pages deep server-side) that reads as a long blank then
a pop. Cards now stagger in left-to-right via a per-card --i index (capped) + a 'backwards'
fill-mode keyframe (so the entrance animation releases and :hover transforms still work).
Applies to lazy rails (fillShelf) and the prepended personalized rows (staggerWithin).
This commit is contained in:
BoulderBadgeDad 2026-06-23 09:32:18 -07:00
parent 73395b9668
commit 1feb34621e
2 changed files with 29 additions and 6 deletions

View file

@ -402,6 +402,7 @@
'</section>';
}).join('');
host.insertAdjacentHTML('afterbegin', html);
staggerWithin(host);
hydrateGet(host);
})
.catch(function () { /* personalization is best-effort */ });
@ -429,6 +430,7 @@
'</section>';
}).join('');
host.insertAdjacentHTML('afterbegin', html);
staggerWithin(host);
hydrateGet(host);
})
.catch(function () { /* gaps are best-effort */ });
@ -453,6 +455,7 @@
'<div class="vdsc-rail" data-vdsc-rail>' + items.map(card).join('') + '</div>' +
'</section>';
host.insertAdjacentHTML('afterbegin', html);
staggerWithin(host);
hydrateGet(host);
})
.catch(function () { /* best-effort */ });
@ -504,6 +507,22 @@
var h = $('[data-vdsc-hideowned]');
return !!(h && h.checked);
}
// Tag each card with its index so the CSS cascade reveals them one-by-one (not all at once).
// Capped so a long rail's tail doesn't lag too far behind the head.
function stagger(rail) {
if (!rail) return;
var c = rail.children;
for (var i = 0; i < c.length; i++) c[i].style.setProperty('--i', i < 14 ? i : 14);
}
// Stagger every not-yet-tagged filled rail under a host (used by the prepended
// personalized rows, which render their cards inline rather than via fillShelf).
function staggerWithin(host) {
if (!host) return;
var rails = host.querySelectorAll('.vdsc-shelf--in .vdsc-rail');
for (var i = 0; i < rails.length; i++) {
if (!rails[i].getAttribute('data-stg')) { rails[i].setAttribute('data-stg', '1'); stagger(rails[i]); }
}
}
function fillShelf(shelf) {
if (!shelf || shelf.getAttribute('data-vdsc-loaded')) return;
shelf.setAttribute('data-vdsc-loaded', '1');
@ -515,8 +534,8 @@
.then(function (d) {
var items = (d && d.items) || [];
if (!items.length) { shelf.remove(); return; } // drop empty shelves
if (rail) { rail.innerHTML = items.map(card).join(''); hydrateGet(rail); }
shelf.classList.add('vdsc-shelf--in'); // reveal
if (rail) { rail.innerHTML = items.map(card).join(''); stagger(rail); hydrateGet(rail); }
shelf.classList.add('vdsc-shelf--in'); // reveal (cards cascade via --i)
})
.catch(function () { shelf.remove(); });
}

View file

@ -2449,15 +2449,19 @@ body[data-side="video"] #soulsync-toggle { display: none; }
.vdsc-ig-empty-ic { font-size: 40px; margin-bottom: 10px; }
.vdsc-ig-empty-sub { font-size: 12.5px; color: rgba(255, 255, 255, 0.38); margin-top: 6px; }
/* rails: a gentle fade-in when filled + per-title hue on hover */
.vdsc-shelf--in .vdsc-rail { animation: vdscFade 0.45s ease both; }
@keyframes vdscFade { from { opacity: 0.35; } to { opacity: 1; } }
/* rails: cards cascade in (staggered by --i) when the row fills, instead of one block flash.
`backwards` fill holds the hidden start-state during the delay, then releases so :hover works. */
.vdsc-shelf--in .vdsc-rail .vsr-card {
animation: vdscCardIn 0.42s cubic-bezier(0.22, 0.61, 0.36, 1) backwards;
animation-delay: calc(var(--i, 0) * 40ms);
}
@keyframes vdscCardIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.vdsc-rail .vsr-card, .vdsc-grid .vsr-card { transition: transform 0.2s ease, box-shadow 0.2s ease; }
.vdsc-rail .vsr-card:hover, .vdsc-grid .vsr-card:hover {
box-shadow: 0 14px 36px rgba(0, 0, 0, 0.5), 0 0 26px -6px hsla(var(--vgm-h, 230), 80%, 58%, 0.5); }
@media (prefers-reduced-motion: reduce) {
.vdsc-shelf--in .vdsc-rail { animation: none; }
.vdsc-shelf--in .vdsc-rail .vsr-card { animation: none; }
.vdsc-amb { transition: none; }
}