gallery fix

This commit is contained in:
2026-02-21 21:39:23 +01:00
parent e4e0bdf8f1
commit 48e2055b6a
20 changed files with 1064 additions and 481 deletions

View File

@@ -6,6 +6,14 @@
(function () {
'use strict';
var GRID_V2_ENABLED = (function () {
try {
return new URLSearchParams(window.location.search).get('grid') === 'v2';
} catch (e) {
return false;
}
})();
var MAX_DOM_CARDS_FOR_VIRTUAL_HINT = 220;
var LOAD_TRIGGER_MARGIN = '900px';
@@ -28,11 +36,16 @@
box.classList.remove('is-loading');
return;
}
var templateHost = root.querySelector('[data-gallery-skeleton-template]');
var templateNode = templateHost ? templateHost.firstElementChild : null;
box.classList.add('is-loading');
var total = Math.max(4, count || 8);
for (var i = 0; i < total; i += 1) {
var sk = document.createElement('div');
sk.className = 'nova-skeleton-card';
var sk = templateNode ? templateNode.cloneNode(true) : document.createElement('div');
if (!templateNode) {
sk.className = 'nova-skeleton-card';
sk.innerHTML = '<div class="nova-skeleton-media"></div><div class="nova-skeleton-body"><div class="nova-skeleton-line"></div><div class="nova-skeleton-line"></div><div class="nova-skeleton-pill"></div></div>';
}
box.appendChild(sk);
}
}
@@ -131,25 +144,6 @@
var grid = root.querySelector('[data-gallery-grid]');
if (!grid) return;
// loader overlay element (created lazily)
var loader = null;
function ensureLoader() {
if (loader) return loader;
loader = document.createElement('div');
loader.className = 'nova-loader-overlay';
var inner = document.createElement('div');
inner.className = 'nova-loader-spinner';
loader.appendChild(inner);
// place loader as child of root so it overlays grid area
loader.style.display = 'none';
root.style.position = root.style.position || '';
root.appendChild(loader);
return loader;
}
function showLoader() { var l = ensureLoader(); l.style.display = 'flex'; }
function hideLoader() { if (loader) loader.style.display = 'none'; }
root.classList.add('is-enhanced');
var state = {
@@ -159,8 +153,20 @@
};
function relayout() {
waitForImages(grid).then(function () {
// Apply masonry synchronously first — the card already has inline aspect-ratio
// set from image dimensions, so getBoundingClientRect() returns the correct
// reserved height immediately at DOMContentLoaded without waiting for decode.
// This collapses both the is-enhanced class change and span assignment into one
// paint frame, eliminating the visible layout jump (CLS).
if (!GRID_V2_ENABLED) {
applyMasonry(root);
}
// Secondary pass after images finish decoding — corrects any lazy-loaded or
// dynamically-appended cards whose heights weren't yet known.
waitForImages(grid).then(function () {
if (!GRID_V2_ENABLED) {
applyMasonry(root);
}
applyVirtualizationHints(root);
});
}
@@ -178,8 +184,6 @@
if (state.loading || state.done || !state.nextUrl) return;
state.loading = true;
showLoader();
var sampleCards = toArray(grid.querySelectorAll('.nova-card'));
var skeletonCount = Math.min(12, Math.max(4, sampleCards.length ? sampleCards.slice(-4).length * 2 : 8));
setSkeleton(root, true, skeletonCount);
@@ -215,7 +219,6 @@
} finally {
state.loading = false;
setSkeleton(root, false);
hideLoader();
}
}