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:
parent
73395b9668
commit
1feb34621e
2 changed files with 29 additions and 6 deletions
|
|
@ -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(); });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue