import Swiper from 'https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.mjs';
const DESKTOP = window.matchMedia('(min-width: 1080px)');
// Inline du close.svg (assets/icons/close.svg)
const CLOSE_SVG = ``;
let lightboxEl = null;
let lightboxSwiper = null;
function createLightboxDOM() {
const el = document.createElement('div');
el.id = 'lightbox';
el.setAttribute('aria-modal', 'true');
el.setAttribute('role', 'dialog');
el.setAttribute('aria-label', 'Image agrandie');
el.setAttribute('inert', '');
el.innerHTML = `
`;
document.body.appendChild(el);
el.querySelector('#lightbox-close').addEventListener('click', closeLightbox);
// Fermeture au clic sur le fond (pas sur le swiper)
el.addEventListener('click', (e) => {
if (e.target === el) closeLightbox();
});
return el;
}
function ensureLightboxDOM() {
if (!lightboxEl) {
lightboxEl = createLightboxDOM();
}
}
function getImageData(figure) {
const img = figure.querySelector('img');
// 1. figcaption dans la figure
// 2. p.caption dans la figure (horizontal-gallery)
// 3. p.caption sibling de la figure (covers : resource, news-item, impact…)
const captionEl =
figure.querySelector('figcaption') ||
figure.querySelector('p.caption') ||
(figure.nextElementSibling?.matches('p.caption') ? figure.nextElementSibling : null);
return {
src: img?.src || '',
alt: img?.alt || '',
caption: captionEl?.innerHTML || '',
};
}
function buildSlides(images) {
const wrapper = lightboxEl.querySelector('.swiper-wrapper');
wrapper.innerHTML = '';
images.forEach(({ src, alt, caption }) => {
const slide = document.createElement('div');
slide.className = 'swiper-slide';
slide.innerHTML = `
${caption ? `${caption}` : ''}
`;
wrapper.appendChild(slide);
});
}
function openLightbox(images, startIndex = 0) {
ensureLightboxDOM();
buildSlides(images);
const swiperEl = lightboxEl.querySelector('#lightbox-swiper');
// Détruire l'instance précédente si elle existe
if (swiperEl.swiper) {
swiperEl.swiper.destroy(true, true);
}
lightboxSwiper = new Swiper(swiperEl, {
slidesPerView: 1,
initialSlide: startIndex,
speed: 400,
watchOverflow: true,
keyboard: { enabled: true },
navigation: {
nextEl: swiperEl.querySelector('.swiper-button-next'),
prevEl: swiperEl.querySelector('.swiper-button-prev'),
},
pagination: {
el: swiperEl.querySelector('.swiper-pagination'),
clickable: true,
},
a11y: {
prevSlideMessage: 'Image précédente',
nextSlideMessage: 'Image suivante',
},
});
lightboxEl.removeAttribute('inert');
document.body.classList.add('lightbox-open');
lightboxEl.querySelector('#lightbox-close').focus();
}
function closeLightbox() {
document.body.classList.remove('lightbox-open');
lightboxEl.setAttribute('inert', '');
}
function isEligible(figure) {
// Exclure les figures dans un
if (figure.closest('a')) return false;
// Exclure si le parent direct contient un .link-block (card navigable)
if (figure.parentElement.querySelector(':scope > .link-block')) return false;
return true;
}
export function initLightbox() {
// Fermeture à la touche Echap
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && document.body.classList.contains('lightbox-open')) {
closeLightbox();
}
});
document.querySelectorAll('figure').forEach((figure) => {
if (!isEligible(figure)) return;
// Marquer les figures éligibles (pour le cursor CSS)
figure.setAttribute('data-lightbox', '');
figure.addEventListener('click', () => {
if (!DESKTOP.matches) return;
const slide = figure.closest('.swiper-slide');
if (slide) {
// Galerie : ouvrir toutes les images du swiper parent
const swiperEl = slide.closest('.swiper');
const allFigures = [...swiperEl.querySelectorAll('.swiper-slide > figure')];
const startIndex = allFigures.indexOf(figure);
openLightbox(allFigures.map(getImageData), startIndex);
} else {
// Image standalone
openLightbox([getImageData(figure)], 0);
}
});
});
}