99 lines
3.2 KiB
JavaScript
99 lines
3.2 KiB
JavaScript
const paths = {
|
|
close: 'M6 6l12 12M18 6 6 18',
|
|
prev: 'M15 5l-7 7 7 7',
|
|
next: 'M9 5l7 7-7 7',
|
|
};
|
|
|
|
function button(className, name, label) {
|
|
const element = document.createElement('button');
|
|
element.type = 'button';
|
|
element.className = `lightbox__btn ${className}`;
|
|
element.setAttribute('aria-label', label);
|
|
element.innerHTML = `<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><path d="${paths[name]}"/></svg>`;
|
|
return element;
|
|
}
|
|
|
|
export function initLightbox(gallery) {
|
|
const links = [...gallery.querySelectorAll('.gallery__link')];
|
|
if (!links.length || typeof HTMLDialogElement !== 'function') return;
|
|
const { labelPrev, labelNext, labelClose } = gallery.dataset;
|
|
|
|
const dialog = document.createElement('dialog');
|
|
dialog.className = 'lightbox';
|
|
const figure = document.createElement('figure');
|
|
figure.className = 'lightbox__figure';
|
|
const image = document.createElement('img');
|
|
image.className = 'lightbox__img';
|
|
image.decoding = 'async';
|
|
figure.append(image);
|
|
const count = document.createElement('p');
|
|
count.className = 'lightbox__count';
|
|
const close = button('lightbox__close', 'close', labelClose);
|
|
const prev = button('lightbox__prev', 'prev', labelPrev);
|
|
const next = button('lightbox__next', 'next', labelNext);
|
|
dialog.append(figure, count, close, prev, next);
|
|
document.body.append(dialog);
|
|
|
|
if (links.length < 2) {
|
|
prev.hidden = true;
|
|
next.hidden = true;
|
|
count.hidden = true;
|
|
}
|
|
|
|
let current = 0;
|
|
|
|
function show(index) {
|
|
current = (index + links.length) % links.length;
|
|
const link = links[current];
|
|
image.src = link.dataset.full || link.href;
|
|
image.width = Number(link.dataset.width) || 0;
|
|
image.height = Number(link.dataset.height) || 0;
|
|
image.alt = link.querySelector('img')?.alt ?? '';
|
|
count.textContent = `${current + 1} / ${links.length}`;
|
|
}
|
|
|
|
function open(index) {
|
|
show(index);
|
|
dialog.showModal();
|
|
document.documentElement.classList.add('lightbox-open');
|
|
}
|
|
|
|
links.forEach((link, index) => {
|
|
link.addEventListener('click', (event) => {
|
|
if (event.metaKey || event.ctrlKey || event.shiftKey) return;
|
|
event.preventDefault();
|
|
open(index);
|
|
});
|
|
});
|
|
|
|
dialog.addEventListener('close', () => {
|
|
document.documentElement.classList.remove('lightbox-open');
|
|
links[current].focus();
|
|
});
|
|
close.addEventListener('click', () => dialog.close());
|
|
prev.addEventListener('click', () => show(current - 1));
|
|
next.addEventListener('click', () => show(current + 1));
|
|
|
|
// a click on the dark area around the image closes it
|
|
figure.addEventListener('click', (event) => {
|
|
if (event.target === figure) dialog.close();
|
|
});
|
|
|
|
dialog.addEventListener('keydown', (event) => {
|
|
if (event.key === 'ArrowLeft') show(current - 1);
|
|
if (event.key === 'ArrowRight') show(current + 1);
|
|
});
|
|
|
|
let startX = null;
|
|
figure.addEventListener('pointerdown', (event) => {
|
|
if (event.pointerType !== 'mouse') startX = event.clientX;
|
|
});
|
|
figure.addEventListener('pointerup', (event) => {
|
|
if (startX === null) return;
|
|
const distance = event.clientX - startX;
|
|
startX = null;
|
|
if (Math.abs(distance) > 50 && links.length > 1) show(current + (distance < 0 ? 1 : -1));
|
|
});
|
|
figure.addEventListener('pointercancel', () => (startX = null));
|
|
}
|