From 3b359d2b3733c1c0c0516a3729f114c66a00a2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Sun, 7 Jun 2026 14:46:24 +0200 Subject: [PATCH] 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 --- assets/css/main.css | 10 ++++++++ layouts/_default/single.html | 26 +++++++++++++++++++-- layouts/baseof.html | 17 ++++++++++++++ static/js/app.js | 45 +++++++++++++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/assets/css/main.css b/assets/css/main.css index 8e564b7..970ee2d 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -198,6 +198,16 @@ input[type="search"]::-webkit-search-cancel-button { opacity: 1; } +/* ── full-image zoom overlay ── */ +.img-zoom { + position: fixed; inset: 0; z-index: 400; + background: rgba(8,6,4,.97); + display: none; place-items: center; + cursor: zoom-out; +} +.img-zoom[data-open="true"] { display: grid; } +.lb-img { cursor: zoom-in; } + /* ── scrollbar ── */ ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 0; } diff --git a/layouts/_default/single.html b/layouts/_default/single.html index 7d20e86..f62e835 100644 --- a/layouts/_default/single.html +++ b/layouts/_default/single.html @@ -1,15 +1,37 @@ {{ define "main" }} {{- $issue := index (.Params.issues | default (slice "01")) 0 }} {{- $issueURL := printf "/issues/%s/" $issue }} +{{- $img := .Resources.GetMatch "*.png" }} +{{- $cardSrc := "" }} +{{- if $img }}{{- $c := $img.Resize "900x1350 webp" }}{{- $cardSrc = $c.RelPermalink }}{{- end }} +
№ {{ $issue }} · {{ index (.Params.categories | default (slice "Plate")) 0 }}

{{ .Title }}

-

+

{{ .Params.description }} - Return to issue →

+
+ + ← Return to issue + + {{- if $cardSrc }} + + {{- end }} +
+ {{/* Pure image zoom — opened by hero button or clicking the lightbox main image */}} + + diff --git a/static/js/app.js b/static/js/app.js index 7c2ca60..4b0e154 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -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(); + }); + })();