2026-05-02 08:26:18 +12:00
|
|
|
type RevealOptions = {
|
|
|
|
|
delay?: number;
|
|
|
|
|
distance?: number;
|
|
|
|
|
threshold?: number;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const defaultOptions: Required<RevealOptions> = {
|
|
|
|
|
delay: 0,
|
|
|
|
|
distance: 24,
|
|
|
|
|
threshold: 0.18
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function reveal(node: HTMLElement, options: RevealOptions = {}) {
|
|
|
|
|
const settings = { ...defaultOptions, ...options };
|
|
|
|
|
const media = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
|
|
|
|
|
|
|
|
if (media.matches) {
|
|
|
|
|
node.classList.add('reveal-visible');
|
|
|
|
|
return {
|
|
|
|
|
destroy() {}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node.style.setProperty('--reveal-delay', `${settings.delay}ms`);
|
|
|
|
|
node.style.setProperty('--reveal-distance', `${settings.distance}px`);
|
|
|
|
|
node.classList.add('reveal-ready');
|
|
|
|
|
|
2026-05-05 20:54:56 +12:00
|
|
|
// If the element is already visible at all in the initial viewport,
|
|
|
|
|
// reveal it immediately so the first section below the hero doesn't
|
|
|
|
|
// appear blank on page load.
|
|
|
|
|
const initialCheck = () => {
|
|
|
|
|
const rect = node.getBoundingClientRect();
|
|
|
|
|
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
|
|
|
if (rect.top < viewportHeight && rect.bottom > 0) {
|
|
|
|
|
node.classList.add('reveal-visible');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (initialCheck()) {
|
|
|
|
|
return {
|
|
|
|
|
destroy() {}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 08:26:18 +12:00
|
|
|
const observer = new IntersectionObserver(
|
|
|
|
|
(entries) => {
|
|
|
|
|
for (const entry of entries) {
|
|
|
|
|
if (!entry.isIntersecting) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node.classList.add('reveal-visible');
|
|
|
|
|
observer.disconnect();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
threshold: settings.threshold,
|
|
|
|
|
rootMargin: '0px 0px -8% 0px'
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
observer.observe(node);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
destroy() {
|
|
|
|
|
observer.disconnect();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|