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 = `
${alt} ${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); } }); }); }