From a52e0a8bb3ed5a98f4701b262d7e4dc7040ae3ff Mon Sep 17 00:00:00 2001 From: hbrain Date: Sun, 31 May 2026 14:55:56 +0200 Subject: [PATCH] Add map image lightbox overlay with zoom animation on click --- index.php | 1 + js/map_lightbox.js | 75 ++++++++++++++++++++++++++++++++++++++++++++ new.php | 5 +-- style.css | 78 +++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 js/map_lightbox.js diff --git a/index.php b/index.php index 283824b..a23358f 100644 --- a/index.php +++ b/index.php @@ -291,5 +291,6 @@ if ($titleExact && ($filters['f_title'] ?? '') !== '') $baseParams['f_exact'] = }); })(); + diff --git a/js/map_lightbox.js b/js/map_lightbox.js new file mode 100644 index 0000000..094d5c3 --- /dev/null +++ b/js/map_lightbox.js @@ -0,0 +1,75 @@ +(() => { + const SELECTOR = 'img.map-image'; + let lightbox = null; + let lightboxImg = null; + + function ensureLightbox() { + if (lightbox) return lightbox; + + lightbox = document.createElement('div'); + lightbox.className = 'map-lightbox'; + lightbox.setAttribute('aria-hidden', 'true'); + + const closeBtn = document.createElement('button'); + closeBtn.type = 'button'; + closeBtn.className = 'map-lightbox__close'; + closeBtn.setAttribute('aria-label', 'Close map preview'); + closeBtn.textContent = '×'; + + lightboxImg = document.createElement('img'); + lightboxImg.className = 'map-lightbox__img'; + lightboxImg.alt = 'Map preview'; + + const hint = document.createElement('div'); + hint.className = 'map-lightbox__hint'; + hint.textContent = 'Esc or click outside to close'; + + lightbox.appendChild(closeBtn); + lightbox.appendChild(lightboxImg); + lightbox.appendChild(hint); + document.body.appendChild(lightbox); + + closeBtn.addEventListener('click', closeLightbox); + + lightbox.addEventListener('click', (ev) => { + if (ev.target === lightbox) closeLightbox(); + }); + + document.addEventListener('keydown', (ev) => { + if (ev.key === 'Escape' && lightbox.classList.contains('is-open')) { + closeLightbox(); + } + }); + + return lightbox; + } + + function openLightbox(src, alt) { + ensureLightbox(); + lightboxImg.src = src; + lightboxImg.alt = alt || 'Map preview'; + lightbox.classList.add('is-open'); + lightbox.setAttribute('aria-hidden', 'false'); + document.body.classList.add('map-lightbox-open'); + } + + function closeLightbox() { + if (!lightbox) return; + lightbox.classList.remove('is-open'); + lightbox.setAttribute('aria-hidden', 'true'); + document.body.classList.remove('map-lightbox-open'); + setTimeout(() => { + if (!lightbox.classList.contains('is-open')) { + lightboxImg.removeAttribute('src'); + } + }, 260); + } + + document.addEventListener('click', (ev) => { + const target = ev.target instanceof Element ? ev.target.closest(SELECTOR) : null; + if (!target) return; + ev.preventDefault(); + ev.stopPropagation(); + openLightbox(target.currentSrc || target.src, target.alt || 'Map preview'); + }); +})(); diff --git a/new.php b/new.php index 59cd94d..e578508 100644 --- a/new.php +++ b/new.php @@ -1098,8 +1098,5 @@ function applySwitchPayload(payload){ })(); - - - - + \ No newline at end of file diff --git a/style.css b/style.css index b9fbbb8..832238a 100644 --- a/style.css +++ b/style.css @@ -45,14 +45,6 @@ } .describe-button{display:inline-block;margin-right:.6rem} -.map-image{ - width: 100%; - aspect-ratio: 16/9; - background: #111315; - border-radius: .5rem; - margin-top: 1rem; -} - .map-image { width: 100%; aspect-ratio: 16 / 9; @@ -60,8 +52,78 @@ background: #111315; border-radius: .5rem; margin-top: 1rem; + cursor: zoom-in; + transition: transform .22s ease, box-shadow .22s ease; +} +.map-image:hover { + transform: translateY(-1px); + box-shadow: 0 8px 22px rgba(0,0,0,.35); } .video-wrapper { display: flex; flex-direction: column; } + +body.map-lightbox-open { overflow: hidden; } +.map-lightbox { + position: fixed; + inset: 0; + z-index: 99999; + display: grid; + place-items: center; + background: rgba(11, 13, 15, .86); + backdrop-filter: blur(4px); + opacity: 0; + pointer-events: none; + transition: opacity .22s ease; + padding: 2.2rem; + box-sizing: border-box; +} +.map-lightbox.is-open { + opacity: 1; + pointer-events: auto; +} +.map-lightbox__img { + max-width: min(96vw, 2300px); + max-height: 92vh; + width: auto; + height: auto; + object-fit: contain; + border-radius: .65rem; + box-shadow: 0 20px 70px rgba(0,0,0,.65); + transform: scale(.9); + opacity: 0; + transition: transform .24s cubic-bezier(.2,.75,.15,1), opacity .24s ease; +} +.map-lightbox.is-open .map-lightbox__img { + transform: scale(1); + opacity: 1; +} +.map-lightbox__close { + position: fixed; + top: 1.1rem; + right: 1.1rem; + width: 2.2rem; + height: 2.2rem; + border-radius: 50%; + border: 1px solid #C46A3A; + background: #C46A3A; + color: #111315; + font-size: 1.15rem; + line-height: 1; + font-weight: 700; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + box-shadow: 0 3px 12px rgba(0,0,0,.45); +} +.map-lightbox__close:hover { background: #d97b48; border-color: #d97b48; } +.map-lightbox__hint { + position: fixed; + bottom: .9rem; + left: 50%; + transform: translateX(-50%); + color: #A0A4AB; + font-size: .82rem; +}