113 lines
3.3 KiB
JavaScript
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();
|
|
}
|