58 lines
1.6 KiB
JavaScript
58 lines
1.6 KiB
JavaScript
// Generic grid + lightbox behavior shared across photoflow apps.
|
|
// Apps spread this into their own Alpine component: { ...photoGrid(), ...appLogic }
|
|
function photoGrid() {
|
|
return {
|
|
focused: null,
|
|
lightboxOpen: false,
|
|
|
|
cards() {
|
|
return [...document.querySelectorAll('.photo-card')]
|
|
.filter(c => c.style.display !== 'none');
|
|
},
|
|
|
|
select(el) {
|
|
if (this.focused) this.focused.classList.remove('ring-4', 'ring-white', 'z-10');
|
|
this.focused = el;
|
|
if (el) {
|
|
el.classList.add('ring-4', 'ring-white', 'z-10');
|
|
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
if (this.lightboxOpen) this.updateLightbox();
|
|
}
|
|
},
|
|
|
|
selectFirst() {
|
|
const cards = this.cards();
|
|
if (cards.length) this.select(cards[0]);
|
|
},
|
|
|
|
navigate(dir) {
|
|
const cards = this.cards();
|
|
if (!cards.length) return;
|
|
const idx = this.focused ? cards.indexOf(this.focused) : -1;
|
|
const next = cards[Math.max(0, Math.min(cards.length - 1, idx + dir))];
|
|
if (next) this.select(next);
|
|
},
|
|
|
|
openLightbox(el) {
|
|
this.select(el);
|
|
this.lightboxOpen = true;
|
|
document.getElementById('lb').style.display = '';
|
|
this.updateLightbox();
|
|
},
|
|
|
|
closeLightbox() {
|
|
this.lightboxOpen = false;
|
|
const lb = document.getElementById('lb');
|
|
if (lb) lb.style.display = 'none';
|
|
},
|
|
|
|
updateLightbox() {
|
|
const el = this.focused;
|
|
if (!el) return;
|
|
const img = el.querySelector('img');
|
|
const lbImg = document.getElementById('lb-img');
|
|
if (img && lbImg) lbImg.src = img.src;
|
|
},
|
|
};
|
|
}
|