the home site for me: also iteration 3 or 4 of my site
at main 152 lines 4.3 kB view raw
1class ImageLightbox extends HTMLElement { 2 constructor() { 3 super(); 4 this.currentImages = []; 5 this.currentIndex = 0; 6 this.handleImageClick = this.handleImageClick.bind(this); 7 this.handleKeyPress = this.handleKeyPress.bind(this); 8 } 9 10 connectedCallback() { 11 this.render(); 12 this.setupEventListeners(); 13 } 14 15 disconnectedCallback() { 16 this.cleanup(); 17 } 18 19 render() { 20 this.id = 'lightbox'; 21 this.style.display = 'none'; 22 this.innerHTML = ` 23 <div class="lightbox-content"> 24 <button class="lightbox-close" aria-label="Close lightbox">&times;</button> 25 <img id="lightbox-img" src="" alt="" /> 26 <div class="lightbox-controls"> 27 <button class="lightbox-prev" aria-label="Previous image">←</button> 28 <button class="lightbox-next" aria-label="Next image">→</button> 29 </div> 30 </div> 31 `; 32 } 33 34 setupEventListeners() { 35 // Delegate clicks on images with data-lightbox attribute 36 document.addEventListener('click', this.handleImageClick); 37 38 // Lightbox controls 39 this.querySelector('.lightbox-close').addEventListener('click', () => this.close()); 40 this.querySelector('.lightbox-prev').addEventListener('click', () => this.prev()); 41 this.querySelector('.lightbox-next').addEventListener('click', () => this.next()); 42 43 // Click backdrop to close 44 this.addEventListener('click', (e) => { 45 if (e.target === this) this.close(); 46 }); 47 48 // Keyboard navigation 49 document.addEventListener('keydown', this.handleKeyPress); 50 } 51 52 handleImageClick(e) { 53 // Check if clicked element or its parent has data-lightbox 54 const target = e.target.closest('[data-lightbox]'); 55 if (!target) return; 56 57 e.preventDefault(); 58 59 const group = target.dataset.lightboxGroup; 60 61 if (group) { 62 // Find all images in the same group 63 const groupElements = Array.from( 64 document.querySelectorAll(`[data-lightbox-group="${group}"]`) 65 ); 66 67 // Extract image sources 68 this.currentImages = groupElements.map(el => { 69 const img = el.tagName === 'IMG' ? el : el.querySelector('img'); 70 return img ? img.src : null; 71 }).filter(Boolean); 72 73 // Find the index of the clicked image 74 this.currentIndex = groupElements.indexOf(target); 75 } else { 76 // Single image 77 const img = target.tagName === 'IMG' ? target : target.querySelector('img'); 78 this.currentImages = img ? [img.src] : []; 79 this.currentIndex = 0; 80 } 81 82 if (this.currentImages.length > 0) { 83 this.open(); 84 } 85 } 86 87 handleKeyPress(e) { 88 if (this.style.display !== 'flex') return; 89 90 if (e.key === 'Escape') { 91 this.close(); 92 } else if (e.key === 'ArrowLeft') { 93 this.prev(); 94 } else if (e.key === 'ArrowRight') { 95 this.next(); 96 } 97 } 98 99 open() { 100 this.style.display = 'flex'; 101 const controls = this.querySelector('.lightbox-controls'); 102 if (this.currentImages.length > 1) { 103 controls.style.display = 'flex'; 104 } else { 105 controls.style.display = 'none'; 106 } 107 document.body.style.overflow = 'hidden'; 108 this.updateImage(); 109 } 110 111 close() { 112 this.style.display = 'none'; 113 document.body.style.overflow = ''; 114 } 115 116 updateImage() { 117 const img = this.querySelector('#lightbox-img'); 118 img.src = this.currentImages[this.currentIndex]; 119 } 120 121 prev() { 122 this.currentIndex = (this.currentIndex - 1 + this.currentImages.length) % this.currentImages.length; 123 this.updateImage(); 124 } 125 126 next() { 127 this.currentIndex = (this.currentIndex + 1) % this.currentImages.length; 128 this.updateImage(); 129 } 130 131 cleanup() { 132 document.removeEventListener('click', this.handleImageClick); 133 document.removeEventListener('keydown', this.handleKeyPress); 134 document.body.style.overflow = ''; 135 } 136} 137 138customElements.define('image-lightbox', ImageLightbox); 139 140// Auto-initialize: add lightbox to page if not already present 141if (document.readyState === 'loading') { 142 document.addEventListener('DOMContentLoaded', initLightbox); 143} else { 144 initLightbox(); 145} 146 147function initLightbox() { 148 if (!document.querySelector('image-lightbox')) { 149 const lightbox = document.createElement('image-lightbox'); 150 document.body.appendChild(lightbox); 151 } 152}