Files

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));
}