Add full-image zoom overlay to single post pages

A "View full image" button appears in the single-post hero alongside
the return link. Clicking the lightbox main image also opens the same
overlay from any page. The overlay is pure image on a near-black
backdrop; click backdrop, close button, or Escape to dismiss.

Escape is layered: closes zoom first, then lightbox if zoom is not open.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 14:46:24 +02:00
parent 81e7417a1d
commit 3b359d2b37
4 changed files with 95 additions and 3 deletions
+44 -1
View File
@@ -211,6 +211,7 @@
let lbIdx = -1; // index into lbList
let lbBuilt = false;
let lbReferrer = null; // URL to return to on close
let imgZoomOpen = false;
function lbOpen(slug, scopedList) {
lbList = scopedList || POSTS;
@@ -348,7 +349,7 @@
});
document.addEventListener('keydown', e => {
if (lb.dataset.open !== 'true') return;
if (e.key === 'Escape') { lbClose(); }
if (e.key === 'Escape') { if (imgZoomOpen) closeImgZoom(); else lbClose(); }
if (e.key === 'ArrowLeft') { e.preventDefault(); goToSlide(lbIdx - 1); }
if (e.key === 'ArrowRight') { e.preventDefault(); goToSlide(lbIdx + 1); }
});
@@ -469,4 +470,46 @@
lbOpen(window.__ROUX_OPEN_SLUG, scoped.length ? scoped : POSTS);
}
// ── Full-image zoom overlay
const imgZoom = document.getElementById('imgZoom');
const imgZoomImg = document.getElementById('imgZoomImg');
function openImgZoom(src) {
if (!imgZoom || !imgZoomImg || !src) return;
imgZoomImg.src = src;
imgZoom.dataset.open = 'true';
imgZoomOpen = true;
document.body.style.overflow = 'hidden';
}
function closeImgZoom() {
if (!imgZoom) return;
imgZoom.dataset.open = 'false';
imgZoomOpen = false;
if (!lb || lb.dataset.open !== 'true') document.body.style.overflow = '';
}
// Hero "View full image" button
const viewFullBtn = document.getElementById('viewFull');
if (viewFullBtn) {
viewFullBtn.addEventListener('click', () => openImgZoom(viewFullBtn.dataset.src));
}
// Click on the lightbox main image → zoom
document.addEventListener('click', e => {
const img = e.target.closest('.lb-img');
if (img) openImgZoom(img.src);
});
// Close on backdrop click or close button
if (imgZoom) {
imgZoom.addEventListener('click', e => { if (e.target === imgZoom) closeImgZoom(); });
document.getElementById('imgZoomClose')?.addEventListener('click', closeImgZoom);
}
// Escape when lightbox is NOT open (standalone zoom)
document.addEventListener('keydown', e => {
if (e.key === 'Escape' && imgZoomOpen && (!lb || lb.dataset.open !== 'true')) closeImgZoom();
});
})();