Add map image lightbox overlay with zoom animation on click
This commit is contained in:
parent
5a81f48be0
commit
a52e0a8bb3
4 changed files with 147 additions and 12 deletions
|
|
@ -291,5 +291,6 @@ if ($titleExact && ($filters['f_title'] ?? '') !== '') $baseParams['f_exact'] =
|
|||
});
|
||||
})();
|
||||
</script>
|
||||
<script src="js/map_lightbox.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
75
js/map_lightbox.js
Normal file
75
js/map_lightbox.js
Normal file
|
|
@ -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');
|
||||
});
|
||||
})();
|
||||
5
new.php
5
new.php
|
|
@ -1098,8 +1098,5 @@ function applySwitchPayload(payload){
|
|||
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="js/map_lightbox.js" defer></script>
|
||||
</body></html>
|
||||
78
style.css
78
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue