Update image logic

This commit is contained in:
2026-07-31 11:11:19 +10:00
parent 5e289c29ba
commit 3c752b399c
+90 -4
View File
@@ -466,6 +466,33 @@
.fan-lightbox-close:hover, .fan-lightbox-close:focus-visible { background: rgba(255, 255, 255, 0.28); }
.fan-lightbox-close svg { width: 1.2rem; height: 1.2rem; }
/* ---------- Fan lightbox: prev / next navigation ---------- */
.fan-lightbox-nav {
position: absolute; top: 50%; transform: translateY(-50%);
width: 3rem; height: 3rem; border-radius: 50%; border: none;
display: flex; align-items: center; justify-content: center;
background: rgba(255, 255, 255, 0.14); color: #fff; cursor: pointer;
transition: background 0.2s ease, opacity 0.2s ease;
-webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.fan-lightbox-nav:hover, .fan-lightbox-nav:focus-visible { background: rgba(255, 255, 255, 0.28); }
.fan-lightbox-nav svg { width: 1.6rem; height: 1.6rem; }
.fan-lightbox-nav.prev { left: 1.1rem; }
.fan-lightbox-nav.next { right: 1.1rem; }
.fan-lightbox-counter {
position: absolute; bottom: 1.3rem; left: 50%; transform: translateX(-50%);
padding: 0.35rem 1rem; border-radius: 980px;
background: rgba(255, 255, 255, 0.14); color: #fff;
font-size: 0.85rem; font-weight: 500; letter-spacing: 0.01em;
-webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
pointer-events: none;
}
@media (max-width: 640px) {
.fan-lightbox-nav { width: 2.6rem; height: 2.6rem; }
.fan-lightbox-nav.prev { left: 0.6rem; }
.fan-lightbox-nav.next { right: 0.6rem; }
}
/* ---------- Accessibility: visible keyboard focus ---------- */
a:focus-visible, button:focus-visible {
outline: 2px solid var(--apple-blue);
@@ -729,6 +756,17 @@
</svg>
</button>
<img id="fan-lightbox-img" class="fan-lightbox-img" src="" alt="{% trans 'Random Image' %}">
<button type="button" class="fan-lightbox-nav prev" id="fan-lightbox-prev" aria-label="{% trans 'Previous image' %}">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/>
</svg>
</button>
<button type="button" class="fan-lightbox-nav next" id="fan-lightbox-next" aria-label="{% trans 'Next image' %}">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
</svg>
</button>
<span class="fan-lightbox-counter" id="fan-lightbox-counter" aria-hidden="true"></span>
</div>
<!-- ============ Link Library ============ -->
@@ -871,11 +909,41 @@
const fanLightbox = document.getElementById('fan-lightbox');
const fanLightboxImg = document.getElementById('fan-lightbox-img');
const fanLightboxClose = document.getElementById('fan-lightbox-close');
const fanLightboxPrev = document.getElementById('fan-lightbox-prev');
const fanLightboxNext = document.getElementById('fan-lightbox-next');
const fanLightboxCounter = document.getElementById('fan-lightbox-counter');
// Snapshot of the five fan-card images, captured once so navigation works
// even if the DOM shuffles later. We store the live <img> elements and
// read their current src each time, so refreshed (re-shuffled) images are
// reflected without rebuilding this list.
const fanImages = Array.from(document.querySelectorAll('.fan-card img'));
let fanIndex = -1;
function showFanImage(index) {
if (!fanImages.length || !fanLightboxImg) return;
// Wrap around the ends so left/right never dead-end.
fanIndex = ((index % fanImages.length) + fanImages.length) % fanImages.length;
const src = fanImages[fanIndex].currentSrc || fanImages[fanIndex].src;
// Preserve any inline opacity transition state from the source image.
fanLightboxImg.src = src;
fanLightboxImg.alt = fanImages[fanIndex].alt;
if (fanLightboxCounter) {
fanLightboxCounter.textContent = (fanIndex + 1) + ' / ' + fanImages.length;
}
}
window.openFanLightbox = function (img) {
if (!img || !fanLightbox || !fanLightboxImg) return;
fanLightboxImg.src = img.currentSrc || img.src;
fanLightboxImg.alt = img.alt;
// Track which of the five images was clicked so navigation starts there.
fanIndex = fanImages.indexOf(img);
if (fanIndex < 0) {
// Fallback: match by current src if the element reference was replaced.
const src = img.currentSrc || img.src;
fanIndex = fanImages.findIndex(i => (i.currentSrc || i.src) === src);
if (fanIndex < 0) fanIndex = 0;
}
showFanImage(fanIndex);
fanLightbox.hidden = false;
document.body.style.overflow = 'hidden';
fanLightboxClose.focus();
@@ -885,17 +953,35 @@
if (!fanLightbox) return;
fanLightbox.hidden = true;
fanLightboxImg.src = '';
fanIndex = -1;
document.body.style.overflow = '';
}
if (fanLightbox) {
fanLightboxClose.addEventListener('click', closeFanLightbox);
// Click the dimmed backdrop (not the image itself) to dismiss.
if (fanLightboxPrev) {
fanLightboxPrev.addEventListener('click', function (event) {
event.stopPropagation();
showFanImage(fanIndex - 1);
fanLightboxPrev.focus();
});
}
if (fanLightboxNext) {
fanLightboxNext.addEventListener('click', function (event) {
event.stopPropagation();
showFanImage(fanIndex + 1);
fanLightboxNext.focus();
});
}
// Click the dimmed backdrop (not the image or nav buttons) to dismiss.
fanLightbox.addEventListener('click', function (event) {
if (event.target === fanLightbox) closeFanLightbox();
});
document.addEventListener('keydown', function (event) {
if (event.key === 'Escape' && !fanLightbox.hidden) closeFanLightbox();
if (fanLightbox.hidden) return;
if (event.key === 'Escape') closeFanLightbox();
else if (event.key === 'ArrowLeft') { event.preventDefault(); showFanImage(fanIndex - 1); }
else if (event.key === 'ArrowRight') { event.preventDefault(); showFanImage(fanIndex + 1); }
});
}