123 lines
5.0 KiB
JavaScript
123 lines
5.0 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
const toastElement = document.getElementById('pageToast');
|
|
const toastBody = document.getElementById('pageToastBody');
|
|
const pageToast = toastElement ? new bootstrap.Toast(toastElement, { delay: 2200 }) : null;
|
|
|
|
const showToast = (message) => {
|
|
if (!pageToast || !toastBody || !message) return;
|
|
toastBody.textContent = message;
|
|
pageToast.show();
|
|
};
|
|
|
|
document.querySelectorAll('[data-toast-message]').forEach((link) => {
|
|
link.addEventListener('click', () => showToast(link.getAttribute('data-toast-message')));
|
|
});
|
|
|
|
const revealItems = document.querySelectorAll('.reveal');
|
|
if ('IntersectionObserver' in window && revealItems.length) {
|
|
const revealObserver = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add('is-visible');
|
|
revealObserver.unobserve(entry.target);
|
|
}
|
|
});
|
|
}, { threshold: 0.16 });
|
|
|
|
revealItems.forEach((item) => revealObserver.observe(item));
|
|
} else {
|
|
revealItems.forEach((item) => item.classList.add('is-visible'));
|
|
}
|
|
|
|
const filterButtons = document.querySelectorAll('.btn-filter');
|
|
const galleryItems = document.querySelectorAll('.gallery-item');
|
|
const filterStatus = document.getElementById('filterStatus');
|
|
|
|
filterButtons.forEach((button) => {
|
|
button.addEventListener('click', () => {
|
|
const filter = button.dataset.filter || 'all';
|
|
filterButtons.forEach((btn) => btn.classList.remove('active'));
|
|
button.classList.add('active');
|
|
|
|
let visibleCount = 0;
|
|
galleryItems.forEach((item) => {
|
|
const matches = filter === 'all' || item.dataset.era === filter;
|
|
item.classList.toggle('is-hidden', !matches);
|
|
if (matches) visibleCount += 1;
|
|
});
|
|
|
|
const statusText = filter === 'all'
|
|
? `Showing all ${visibleCount} images.`
|
|
: `Showing ${visibleCount} ${filter} image${visibleCount === 1 ? '' : 's'}.`;
|
|
|
|
if (filterStatus) filterStatus.textContent = statusText;
|
|
showToast(statusText);
|
|
});
|
|
});
|
|
|
|
const galleryModal = document.getElementById('galleryModal');
|
|
if (galleryModal) {
|
|
const modalLabel = document.getElementById('galleryModalLabel');
|
|
const modalMeta = document.getElementById('galleryModalMeta');
|
|
const modalImage = document.getElementById('galleryModalImage');
|
|
const modalCaption = document.getElementById('galleryModalCaption');
|
|
|
|
galleryModal.addEventListener('show.bs.modal', (event) => {
|
|
const trigger = event.relatedTarget;
|
|
if (!trigger) return;
|
|
|
|
const title = trigger.getAttribute('data-title') || 'Gallery image';
|
|
const eraLabel = trigger.getAttribute('data-era-label') || 'Archive';
|
|
const year = trigger.getAttribute('data-year') || '';
|
|
const caption = trigger.getAttribute('data-caption') || '';
|
|
const image = trigger.getAttribute('data-image') || '';
|
|
const alt = trigger.getAttribute('data-alt') || title;
|
|
|
|
if (modalLabel) modalLabel.textContent = title;
|
|
if (modalMeta) modalMeta.textContent = `${eraLabel} · ${year}`;
|
|
if (modalCaption) modalCaption.textContent = caption;
|
|
if (modalImage) {
|
|
modalImage.src = image;
|
|
modalImage.alt = alt;
|
|
}
|
|
});
|
|
}
|
|
|
|
const sections = document.querySelectorAll('main section[id]');
|
|
const navLinks = document.querySelectorAll('#mainNav .nav-link');
|
|
const setActiveLink = () => {
|
|
let currentId = '';
|
|
sections.forEach((section) => {
|
|
const top = section.getBoundingClientRect().top;
|
|
if (top <= 140) currentId = section.id;
|
|
});
|
|
|
|
navLinks.forEach((link) => {
|
|
const href = link.getAttribute('href');
|
|
link.classList.toggle('active', href === `#${currentId}`);
|
|
});
|
|
};
|
|
|
|
setActiveLink();
|
|
document.addEventListener('scroll', setActiveLink, { passive: true });
|
|
|
|
|
|
const parallaxItems = document.querySelectorAll('[data-parallax]');
|
|
if (parallaxItems.length && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
const updateParallax = () => {
|
|
parallaxItems.forEach((item) => {
|
|
const rect = item.getBoundingClientRect();
|
|
const centerOffset = (window.innerHeight * 0.5 - rect.top) / window.innerHeight;
|
|
const depth = item.dataset.parallax === 'media' ? 16 : 10;
|
|
const translateY = Math.max(-depth, Math.min(depth, centerOffset * depth));
|
|
item.style.transform = `translate3d(0, ${translateY}px, 0)`;
|
|
});
|
|
};
|
|
|
|
updateParallax();
|
|
window.addEventListener('scroll', updateParallax, { passive: true });
|
|
window.addEventListener('resize', updateParallax);
|
|
}
|
|
|
|
});
|