tags and place at * the bottom of your Gallery page in the Block Editor. * * METHOD C — WPCode / Insert Headers and Footers plugin * Paste as a JavaScript snippet, set location to "Footer". */ (function () { 'use strict'; /* ── Wait for DOM ── */ document.addEventListener('DOMContentLoaded', function () { /* ════════════════════════════════════ SCROLL PROGRESS BAR ════════════════════════════════════ */ var scrollBar = document.getElementById('msf-scroll-bar'); var backTop = document.getElementById('msf-back-top'); if (scrollBar || backTop) { window.addEventListener('scroll', function () { var max = document.documentElement.scrollHeight - window.innerHeight; if (scrollBar) scrollBar.style.width = (window.scrollY / max * 100) + '%'; if (backTop) backTop.classList.toggle('msf-show', window.scrollY > 400); }, { passive: true }); } if (backTop) { backTop.addEventListener('click', function () { window.scrollTo({ top: 0, behavior: 'smooth' }); }); } /* ════════════════════════════════════ SCROLL REVEAL ════════════════════════════════════ */ var srElements = document.querySelectorAll('.msf-sr'); if (srElements.length) { var srObs = new IntersectionObserver(function (entries) { entries.forEach(function (e) { if (e.isIntersecting) { e.target.classList.add('msf-visible'); srObs.unobserve(e.target); } }); }, { threshold: 0.08, rootMargin: '0px 0px -32px 0px' }); srElements.forEach(function (el) { srObs.observe(el); }); } /* ════════════════════════════════════ FILTER BUTTONS ════════════════════════════════════ */ var filterBtns = document.querySelectorAll('.msf-filter-btn'); var cards = document.querySelectorAll('.msf-g-card:not(.msf-empty-state)'); var countEl = document.getElementById('msf-filterCount'); var emptyState = document.getElementById('msf-emptyState'); if (filterBtns.length) { filterBtns.forEach(function (btn) { btn.addEventListener('click', function () { filterBtns.forEach(function (b) { b.classList.remove('msf-active'); }); btn.classList.add('msf-active'); var filter = btn.dataset.filter; var visible = 0; cards.forEach(function (card) { var match = filter === 'all' || card.dataset.category === filter; card.style.display = match ? 'block' : 'none'; if (match) visible++; }); if (emptyState) emptyState.style.display = visible === 0 ? 'block' : 'none'; if (countEl) countEl.innerHTML = 'Showing ' + visible + ' photo' + (visible !== 1 ? 's' : ''); }); }); } /* ════════════════════════════════════ GRID / LIST VIEW TOGGLE ════════════════════════════════════ */ var gridViewBtn = document.getElementById('msf-gridViewBtn'); var listViewBtn = document.getElementById('msf-listViewBtn'); var galleryGrid = document.getElementById('msf-galleryGrid'); if (gridViewBtn && listViewBtn && galleryGrid) { gridViewBtn.addEventListener('click', function () { galleryGrid.classList.remove('msf-list-view'); gridViewBtn.classList.add('msf-active'); listViewBtn.classList.remove('msf-active'); }); listViewBtn.addEventListener('click', function () { galleryGrid.classList.add('msf-list-view'); listViewBtn.classList.add('msf-active'); gridViewBtn.classList.remove('msf-active'); }); } /* ════════════════════════════════════ LIGHTBOX ════════════════════════════════════ */ var lightbox = document.getElementById('msf-lightbox'); var lbImg = document.getElementById('msf-lbImg'); var lbTag = document.getElementById('msf-lbTag'); var lbTitle = document.getElementById('msf-lbTitle'); var lbDesc = document.getElementById('msf-lbDesc'); var lbClose = document.getElementById('msf-lbClose'); var lbPrev = document.getElementById('msf-lbPrev'); var lbNext = document.getElementById('msf-lbNext'); var currentIdx = 0; var visibleCards = []; function openLightbox(card, idx) { var img = card.querySelector('.msf-g-card-img img'); var tag = card.querySelector('.msf-g-tag'); var title = card.querySelector('.msf-g-card-title'); if (lbImg) { lbImg.src = img ? img.src : ''; lbImg.alt = title ? title.textContent : ''; } if (lbTag) lbTag.textContent = tag ? tag.textContent : ''; if (lbTitle) lbTitle.textContent = title ? title.textContent : ''; if (lbDesc) lbDesc.textContent = card.dataset.desc || ''; currentIdx = idx; if (lightbox) { lightbox.classList.add('msf-open'); document.body.style.overflow = 'hidden'; } } function closeLightbox() { if (lightbox) { lightbox.classList.remove('msf-open'); document.body.style.overflow = ''; } } function navigate(dir) { visibleCards = Array.from(cards).filter(function (c) { return c.style.display !== 'none'; }); currentIdx = (currentIdx + dir + visibleCards.length) % visibleCards.length; openLightbox(visibleCards[currentIdx], currentIdx); } if (lightbox) { cards.forEach(function (card) { card.addEventListener('click', function (e) { if (e.target.closest('.msf-g-card-link')) return; visibleCards = Array.from(cards).filter(function (c) { return c.style.display !== 'none'; }); var idx = visibleCards.indexOf(card); openLightbox(card, idx); }); }); if (lbClose) lbClose.addEventListener('click', closeLightbox); if (lbPrev) lbPrev.addEventListener('click', function (e) { e.stopPropagation(); navigate(-1); }); if (lbNext) lbNext.addEventListener('click', function (e) { e.stopPropagation(); navigate(1); }); lightbox.addEventListener('click', function (e) { if (e.target === lightbox) closeLightbox(); }); document.addEventListener('keydown', function (e) { if (!lightbox.classList.contains('msf-open')) return; if (e.key === 'Escape') closeLightbox(); if (e.key === 'ArrowLeft') navigate(-1); if (e.key === 'ArrowRight') navigate(1); }); } /* ════════════════════════════════════ 3D CARD TILT ════════════════════════════════════ */ document.querySelectorAll('.msf-g-card').forEach(function (card) { card.addEventListener('mousemove', function (e) { var r = card.getBoundingClientRect(); var x = ((e.clientX - r.left) / r.width - 0.5) * 7; var y = ((e.clientY - r.top) / r.height - 0.5) * 7; card.style.transform = 'translateY(-8px) scale(1.01) rotateX(' + (-y) + 'deg) rotateY(' + x + 'deg)'; card.style.transition = 'none'; }); card.addEventListener('mouseleave', function () { card.style.transform = ''; card.style.transition = ''; }); }); }); // end DOMContentLoaded })();