In-post event gallery block + lightbox; mobile polish
- Reusable "Photos from the event" grid (shows 5 thumbnails + "+N more") that opens a full-screen lightbox (arrows / keyboard / swipe / Esc); added to the Meet Student Slovenia 2024 post as the pattern - New css/components/_lightbox.css + setupLightbox() in main.js (injects one shared overlay, wires any .js-lightbox grid) - Mobile polish: gallery albums go single-column on phones, two on tablets; event-gallery grid 3-up on mobile; lightbox sizing/controls tuned for small screens Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
24c77e6171
commit
1f5e031be9
5 files changed
+183
-6
No files matched your search
@@ -833,6 +833,81 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ===================================================================
|
||||
* REUSABLE LIGHTBOX (for .event-gallery-grid.js-lightbox blocks)
|
||||
* ===================================================================
|
||||
*/
|
||||
function setupLightbox() {
|
||||
var grids = document.querySelectorAll('.js-lightbox');
|
||||
if (!grids.length) return;
|
||||
|
||||
var lb = document.createElement('div');
|
||||
lb.className = 'lightbox';
|
||||
lb.setAttribute('role', 'dialog');
|
||||
lb.setAttribute('aria-label', 'Photo viewer');
|
||||
lb.setAttribute('aria-hidden', 'true');
|
||||
lb.innerHTML =
|
||||
'<button type="button" class="lightbox-close" aria-label="Close">×</button>' +
|
||||
'<button type="button" class="lightbox-prev" aria-label="Previous">❮</button>' +
|
||||
'<img class="lightbox-img" src="" alt="">' +
|
||||
'<button type="button" class="lightbox-next" aria-label="Next">❯</button>' +
|
||||
'<div class="lightbox-caption"></div>';
|
||||
document.body.appendChild(lb);
|
||||
|
||||
var img = lb.querySelector('.lightbox-img');
|
||||
var cap = lb.querySelector('.lightbox-caption');
|
||||
var group = [];
|
||||
var idx = 0;
|
||||
|
||||
function render() {
|
||||
var it = group[idx];
|
||||
img.setAttribute('src', it.full);
|
||||
img.setAttribute('alt', it.caption || '');
|
||||
cap.textContent = (it.caption || '') + (group.length > 1 ? ' (' + (idx + 1) + '/' + group.length + ')' : '');
|
||||
}
|
||||
function open(grid, start) {
|
||||
group = Array.prototype.map.call(grid.querySelectorAll('.eg-thumb'), function (b) {
|
||||
return { full: b.getAttribute('data-full'), caption: b.getAttribute('data-caption') || '' };
|
||||
});
|
||||
idx = start;
|
||||
render();
|
||||
lb.classList.add('is-open');
|
||||
lb.setAttribute('aria-hidden', 'false');
|
||||
document.documentElement.style.overflow = 'hidden';
|
||||
}
|
||||
function close() {
|
||||
lb.classList.remove('is-open');
|
||||
lb.setAttribute('aria-hidden', 'true');
|
||||
document.documentElement.style.overflow = '';
|
||||
img.setAttribute('src', '');
|
||||
}
|
||||
function step(d) { idx = (idx + d + group.length) % group.length; render(); }
|
||||
|
||||
grids.forEach(function (grid) {
|
||||
grid.querySelectorAll('.eg-thumb').forEach(function (b, i) {
|
||||
b.addEventListener('click', function () { open(grid, i); });
|
||||
});
|
||||
});
|
||||
lb.querySelector('.lightbox-close').addEventListener('click', close);
|
||||
lb.querySelector('.lightbox-prev').addEventListener('click', function () { step(-1); });
|
||||
lb.querySelector('.lightbox-next').addEventListener('click', function () { step(1); });
|
||||
lb.addEventListener('click', function (e) { if (e.target === lb) close(); });
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (!lb.classList.contains('is-open')) return;
|
||||
if (e.key === 'Escape') close();
|
||||
else if (e.key === 'ArrowLeft') step(-1);
|
||||
else if (e.key === 'ArrowRight') step(1);
|
||||
});
|
||||
// Swipe on touch devices
|
||||
var sx = 0;
|
||||
lb.addEventListener('touchstart', function (e) { sx = e.changedTouches[0].clientX; }, { passive: true });
|
||||
lb.addEventListener('touchend', function (e) {
|
||||
var dx = e.changedTouches[0].clientX - sx;
|
||||
if (Math.abs(dx) > 40) step(dx < 0 ? 1 : -1);
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* ===================================================================
|
||||
* HUB USE-CASE CAROUSEL (auto-scrolling)
|
||||
@@ -863,5 +938,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
setupLanguageSuggestion();
|
||||
setupNewsletter();
|
||||
setupHubCarousel();
|
||||
setupLightbox();
|
||||
|
||||
});
|
||||
Reference in new issue
Block a user