const IMAGE_DIR = 'images/'; const MANIFEST = IMAGE_DIR + 'manifest.json'; function parseIndexHtmlList(text) { // crude parser to extract hrefs from an autoindex HTML listing const hrefs = []; const re = /href="([^"]+)"/g; let m; while ((m = re.exec(text)) !== null) { const name = m[1]; if (name.match(/\.(jpe?g|png|webp|gif)$/i)) hrefs.push(name); } return hrefs; } async function loadImageList() { // Try manifest first try { const r = await fetch(MANIFEST, {cache: 'no-cache'}); if (r.ok) return await r.json(); } catch (e) { // continue to directory probe } try { const r = await fetch(IMAGE_DIR, {cache: 'no-cache'}); if (r.ok) { const text = await r.text(); return parseIndexHtmlList(text); } } catch (e) { console.warn('Could not read image directory listing', e); } return []; } function createThumb(src, idx) { const img = document.createElement('img'); img.src = src; img.loading = 'lazy'; img.dataset.index = idx; img.alt = `Photo ${idx+1}`; img.addEventListener('click', () => openModal(idx)); return img; } let images = []; let currentIndex = 0; function openModal(idx) { currentIndex = idx; const modal = document.getElementById('gallery-modal'); const mimg = document.getElementById('modal-image'); mimg.src = IMAGE_DIR + images[idx]; modal.classList.remove('hidden'); modal.setAttribute('aria-hidden', 'false'); } function closeModal() { const modal = document.getElementById('gallery-modal'); modal.classList.add('hidden'); modal.setAttribute('aria-hidden', 'true'); document.getElementById('modal-image').src = ''; } function showNext(delta=1) { if (!images.length) return; currentIndex = (currentIndex + delta + images.length) % images.length; document.getElementById('modal-image').src = IMAGE_DIR + images[currentIndex]; } function setupModalControls() { document.getElementById('modal-close').addEventListener('click', closeModal); document.getElementById('modal-prev').addEventListener('click', () => showNext(-1)); document.getElementById('modal-next').addEventListener('click', () => showNext(1)); document.addEventListener('keydown', (e) => { if (document.getElementById('gallery-modal').classList.contains('hidden')) return; if (e.key === 'Escape') closeModal(); if (e.key === 'ArrowRight') showNext(1); if (e.key === 'ArrowLeft') showNext(-1); }); document.getElementById('gallery-modal').addEventListener('click', (e)=>{ if (e.target.id === 'gallery-modal') closeModal(); }); } async function initGallery() { const list = await loadImageList(); images = list; const container = document.getElementById('gallery-thumbs'); container.innerHTML = ''; if (!images.length) { container.textContent = 'No images found. Create images/manifest.json or enable directory listing.'; return; } images.forEach((name, idx) => { const thumb = createThumb(IMAGE_DIR + name, idx); container.appendChild(thumb); }); setupModalControls(); } document.addEventListener('DOMContentLoaded', initGallery);