1/** 2 * lightbox.js â Click-to-expand image modal for feature cards 3 * âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4 * Opens a fullscreen lightbox modal when clicking on cards with 5 * data-image attributes. Shows the screenshot without cluttering 6 * the main layout. 7 */ 8 9(function() { 10 'use strict'; 11 12 // Wait for DOM to be ready 13 if (document.readyState === 'loading') { 14 document.addEventListener('DOMContentLoaded', init); 15 } else { 16 init(); 17 } 18 19 function init() { 20 const lightbox = document.getElementById('lightbox'); 21 const lightboxImage = document.getElementById('lightboxImage'); 22 const lightboxBackdrop = document.getElementById('lightboxBackdrop'); 23 const lightboxClose = document.getElementById('lightboxClose'); 24 25 if (!lightbox || !lightboxImage || !lightboxBackdrop || !lightboxClose) { 26 return; 27 } 28 29 // Find all cards with data-image attribute 30 const cards = document.querySelectorAll('[data-image]'); 31 32 cards.forEach(card => { 33 card.addEventListener('click', function() { 34 const imageSrc = this.getAttribute('data-image'); 35 if (imageSrc) { 36 openLightbox(imageSrc); 37 } 38 }); 39 }); 40 41 // Close lightbox handlers 42 lightboxBackdrop.addEventListener('click', closeLightbox); 43 lightboxClose.addEventListener('click', closeLightbox); 44 45 // Close on Escape key 46 document.addEventListener('keydown', function(e) { 47 if (e.key === 'Escape' && lightbox.classList.contains('active')) { 48 closeLightbox(); 49 } 50 }); 51 52 function openLightbox(imageSrc) { 53 lightboxImage.src = imageSrc; 54 // Show lightbox with display: flex first 55 lightbox.style.display = 'flex'; 56 document.body.style.overflow = 'hidden'; // Prevent background scroll 57 58 // Force reflow to ensure display change is applied 59 lightbox.offsetHeight; 60 61 // Then add active class to trigger animation 62 requestAnimationFrame(() => { 63 lightbox.classList.add('active'); 64 }); 65 } 66 67 function closeLightbox() { 68 lightbox.classList.remove('active'); 69 document.body.style.overflow = ''; // Restore scroll 70 71 // Wait for animation to finish before hiding 72 setTimeout(() => { 73 lightbox.style.display = 'none'; 74 lightboxImage.src = ''; 75 }, 400); 76 } 77 } 78})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.