Files
amare/resources/js/motion.js

113 lines
3.3 KiB
JavaScript

const MOTION_QUERY = '(prefers-reduced-motion: reduce)';
function prefersReducedMotion() {
return window.matchMedia(MOTION_QUERY).matches;
}
function enableEnhancement() {
if (prefersReducedMotion() || typeof IntersectionObserver !== 'function') {
document.documentElement.removeAttribute('data-motion');
return false;
}
document.documentElement.dataset.motion = 'enhance';
return true;
}
function activatePageOpen(enhance) {
document.querySelectorAll('[data-motion="page-open"]').forEach((node) => {
if (!enhance) {
node.classList.add('is-active');
return;
}
requestAnimationFrame(() => {
requestAnimationFrame(() => node.classList.add('is-active'));
});
});
}
function initializeMotionDelays() {
const beatOrder = new Map([
['seal', 0],
['heading', 0],
['title', 1],
['media', 2],
['cta', 3],
]);
document.querySelectorAll('[data-motion="page-open"]').forEach((page) => {
page.querySelectorAll('[data-motion-beat]').forEach((beat, index) => {
const namedIndex = beatOrder.get(beat.dataset.motionBeat);
beat.style.setProperty('--motion-index', String(Math.min(namedIndex ?? index, 3)));
});
});
document.querySelectorAll('[data-reveal-group]').forEach((group) => {
const nodes = Array.from(group.querySelectorAll('[data-reveal]'))
.filter((node) => node.closest('[data-reveal-group]') === group);
nodes.forEach((node, index) => {
node.style.setProperty('--motion-index', String(Math.min(index, 3)));
});
});
}
function observeReveals(enhance) {
const nodes = Array.from(document.querySelectorAll('[data-reveal]'));
if (nodes.length === 0) {
return;
}
if (!enhance || typeof IntersectionObserver !== 'function') {
nodes.forEach((node) => node.classList.add('is-revealed'));
return;
}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) {
return;
}
entry.target.classList.add('is-revealed');
observer.unobserve(entry.target);
});
},
{
rootMargin: '0px 0px -12% 0px',
threshold: 0.2,
},
);
nodes.forEach((node) => observer.observe(node));
}
function bootMotion() {
initializeMotionDelays();
const enhance = enableEnhancement();
activatePageOpen(enhance);
observeReveals(enhance);
window.matchMedia(MOTION_QUERY).addEventListener('change', (event) => {
if (event.matches) {
document.documentElement.removeAttribute('data-motion');
document.querySelectorAll('[data-motion="page-open"]').forEach((node) => {
node.classList.add('is-active');
});
document.querySelectorAll('[data-reveal]').forEach((node) => {
node.classList.add('is-revealed');
});
return;
}
document.documentElement.dataset.motion = 'enhance';
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bootMotion, { once: true });
} else {
bootMotion();
}