import { onBeforeUnmount, onMounted, unref } from "vue"; export function useGsapReveal(rootRef) { let ctx; const cleanup = []; onMounted(() => { if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) { return; } const root = unref(rootRef); const { $gsap } = useNuxtApp(); if (!root || !$gsap) { return; } ctx = $gsap.context(() => { const isTouch = window.matchMedia("(hover: none), (pointer: coarse)").matches; const heroItems = root.querySelectorAll("[data-hero-reveal]"); if (heroItems.length) { $gsap.fromTo( heroItems, { autoAlpha: 0, y: 34, filter: "blur(10px)", }, { autoAlpha: 1, y: 0, filter: "blur(0px)", duration: 0.95, stagger: 0.12, ease: "power3.out", }, ); } root.querySelectorAll("[data-reveal]").forEach((element, index) => { $gsap.fromTo( element, { autoAlpha: 0, y: 26, }, { autoAlpha: 1, y: 0, duration: 0.72, delay: index * 0.025, ease: "power2.out", scrollTrigger: { trigger: element, start: "top 85%", once: true, }, }, ); }); root.querySelectorAll("[data-stagger]").forEach((element) => { const children = element.querySelectorAll("[data-stagger-item]"); if (!children.length) { return; } $gsap.fromTo( children, { autoAlpha: 0, y: 22, }, { autoAlpha: 1, y: 0, duration: 0.64, stagger: 0.09, ease: "power2.out", scrollTrigger: { trigger: element, start: "top 82%", once: true, }, }, ); }); root.querySelectorAll("[data-parallax]").forEach((element) => { const distance = Number(element.dataset.parallax) || 42; $gsap.fromTo( element, { y: distance * -0.35 }, { y: distance, ease: "none", scrollTrigger: { trigger: element, start: "top bottom", end: "bottom top", scrub: 0.8, }, }, ); }); root.querySelectorAll("[data-geo-loop]").forEach((element) => { const nodes = element.querySelectorAll("[data-geo-node]"); if (!nodes.length) { return; } $gsap.fromTo( nodes, { autoAlpha: 0.48, x: -10 }, { autoAlpha: 1, x: 0, duration: 0.45, stagger: 0.11, ease: "power2.out", scrollTrigger: { trigger: element, start: "top 75%", once: true, }, }, ); }); root.querySelectorAll("[data-flow-line]").forEach((element) => { $gsap.fromTo( element, { width: "0%" }, { width: "100%", duration: 1, ease: "power2.out", scrollTrigger: { trigger: element, start: "top 82%", once: true, }, }, ); }); if (isTouch) { return; } root.querySelectorAll("[data-hover-card]").forEach((element) => { const onMove = (event) => { const rect = element.getBoundingClientRect(); const x = ((event.clientX - rect.left) / rect.width - 0.5) * 10; const y = ((event.clientY - rect.top) / rect.height - 0.5) * -10; $gsap.to(element, { rotateX: y, rotateY: x, y: -6, duration: 0.35, ease: "power2.out", transformPerspective: 900, }); }; const onLeave = () => { $gsap.to(element, { rotateX: 0, rotateY: 0, y: 0, duration: 0.42, ease: "power2.out", }); }; element.addEventListener("mousemove", onMove); element.addEventListener("mouseleave", onLeave); cleanup.push(() => { element.removeEventListener("mousemove", onMove); element.removeEventListener("mouseleave", onLeave); }); }); }, root); }); onBeforeUnmount(() => { cleanup.forEach((dispose) => dispose()); ctx?.revert(); }); }