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
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');
|
||||
});
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue