first commit
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
'use client';
|
||||
import { useEffect } from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
const targets = '.reference-service-card, .reference-about-intro, .reference-about-values, .reference-faq, .reference-contact > div, .section-heading, .service-row, .service-detail, .about-band-grid, .contact-cta, .about-intro, .values-grid > div, .faq-section, .contact-info > div, .offices-grid > article, .contact-form, .portfolio-grid > article, .portfolio-detail';
|
||||
export default function PageMotion() {
|
||||
const pathname = usePathname();
|
||||
useEffect(() => {
|
||||
const main = document.getElementById('main');
|
||||
if (!main || !('IntersectionObserver' in window)) return;
|
||||
const preference = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
const seen = new WeakSet();
|
||||
const prepared = new Set();
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
for (const entry of entries) {
|
||||
if (!entry.isIntersecting) continue;
|
||||
observer.unobserve(entry.target);
|
||||
entry.target.dataset.scrollReveal = 'visible';
|
||||
}
|
||||
}, { threshold: 0, rootMargin: '0px 0px 48px 0px' });
|
||||
const prepare = element => {
|
||||
if (seen.has(element)) return;
|
||||
seen.add(element);
|
||||
// Never hide already-visible content, restored scroll positions, or filtered cards.
|
||||
if (preference.matches || element.getBoundingClientRect().top < window.innerHeight) return;
|
||||
element.dataset.scrollReveal = 'pending';
|
||||
prepared.add(element);
|
||||
observer.observe(element);
|
||||
};
|
||||
main.querySelectorAll(targets).forEach(prepare);
|
||||
// Inspect added subtrees only; do not rescan the page on every Swiper update.
|
||||
const mutations = new MutationObserver(records => {
|
||||
for (const record of records) {
|
||||
for (const node of record.addedNodes) {
|
||||
if (!(node instanceof Element)) continue;
|
||||
if (node.matches(targets)) prepare(node);
|
||||
node.querySelectorAll(targets).forEach(prepare);
|
||||
}
|
||||
}
|
||||
for (const element of prepared) {
|
||||
if (!element.isConnected) {
|
||||
observer.unobserve(element);
|
||||
prepared.delete(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
mutations.observe(main, { childList: true, subtree: true });
|
||||
const revealAll = () => {
|
||||
observer.disconnect();
|
||||
prepared.forEach(element => element.removeAttribute('data-scroll-reveal'));
|
||||
prepared.clear();
|
||||
};
|
||||
const onPreferenceChange = () => { if (preference.matches) revealAll(); };
|
||||
preference.addEventListener('change', onPreferenceChange);
|
||||
return () => {
|
||||
mutations.disconnect();
|
||||
revealAll();
|
||||
preference.removeEventListener('change', onPreferenceChange);
|
||||
};
|
||||
}, [pathname]);
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user