diff options
Diffstat (limited to 'public/js/album.js')
| -rw-r--r-- | public/js/album.js | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/public/js/album.js b/public/js/album.js new file mode 100644 index 0000000..74d524c --- /dev/null +++ b/public/js/album.js @@ -0,0 +1,111 @@ +'use strict'; + +let lbIndex = 0; + +function openLightbox(i) { + lbIndex = i; + renderLightbox(); + document.getElementById('lightbox').classList.remove('hidden'); + document.body.style.overflow = 'hidden'; + document.addEventListener('keydown', lbKey); +} + +function closeLightbox() { + document.getElementById('lightbox').classList.add('hidden'); + document.body.style.overflow = ''; + document.removeEventListener('keydown', lbKey); + ['lb-video', 'lb-audio'].forEach(id => { + const el = document.getElementById(id); + el.pause && el.pause(); + }); + history.replaceState(null, '', location.pathname + location.search); +} + +function lbNav(delta) { + let next = lbIndex + delta; + while (next >= 0 && next < ENTRIES.length && !ENTRIES[next].type) next += delta; + if (next >= 0 && next < ENTRIES.length) { + lbIndex = next; + renderLightbox(); + } +} + +function renderLightbox() { + const e = ENTRIES[lbIndex]; + const img = document.getElementById('lb-img'); + const vid = document.getElementById('lb-video'); + const aud = document.getElementById('lb-audio'); + + [img, vid, aud].forEach(el => { el.classList.add('hidden'); el.pause && el.pause(); }); + + if (e.type === 'image') { + img.src = e.src; img.alt = e.title; + img.classList.remove('hidden'); + } else if (e.type === 'video') { + vid.src = e.src; + vid.classList.remove('hidden'); + vid.play().catch(() => {}); + } else if (e.type === 'audio') { + aud.src = e.src; + aud.classList.remove('hidden'); + aud.play().catch(() => {}); + } + + document.getElementById('lb-title').textContent = e.title !== e.name ? e.title : ''; + document.getElementById('lb-caption').textContent = e.caption || ''; + document.getElementById('lb-counter').textContent = `${lbIndex + 1} / ${ENTRIES.length}`; + + const dl = document.getElementById('lb-download'); + dl.href = e.src; + dl.download = e.name; + + // Update URL hash so the address bar is the shareable link + history.replaceState(null, '', location.pathname + location.search + '#photo=' + encodeURIComponent(e.name)); +} + +function lbCopyLink() { + navigator.clipboard.writeText(location.href).then(() => { + const btn = document.getElementById('lb-copylink'); + const orig = btn.textContent; + btn.textContent = '✓ Copied!'; + setTimeout(() => { btn.textContent = orig; }, 1800); + }).catch(() => { + // Fallback: select a temporary input + const tmp = document.createElement('input'); + tmp.value = location.href; + document.body.appendChild(tmp); + tmp.select(); + document.execCommand('copy'); + document.body.removeChild(tmp); + }); +} + +function lbKey(ev) { + if (ev.key === 'Escape') closeLightbox(); + else if (ev.key === 'ArrowLeft') lbNav(-1); + else if (ev.key === 'ArrowRight') lbNav(1); +} + +// Restore lightbox from URL hash on page load +window.addEventListener('DOMContentLoaded', () => { + const m = location.hash.match(/^#photo=(.+)$/); + if (m) { + const name = decodeURIComponent(m[1]); + const idx = ENTRIES.findIndex(e => e.name === name); + if (idx >= 0) openLightbox(idx); + } +}); + +// Touch swipe +(function () { + let startX = null; + const lb = document.getElementById('lightbox'); + if (!lb) return; + lb.addEventListener('touchstart', e => { startX = e.changedTouches[0].clientX; }, { passive: true }); + lb.addEventListener('touchend', e => { + if (startX === null) return; + const dx = e.changedTouches[0].clientX - startX; + if (Math.abs(dx) > 50) lbNav(dx < 0 ? 1 : -1); + startX = null; + }, { passive: true }); +})(); |
