init
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
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();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { onBeforeUnmount, onMounted, unref } from "vue";
|
||||
|
||||
export function usePageShellMotion(rootRef) {
|
||||
let ctx;
|
||||
|
||||
onMounted(() => {
|
||||
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
||||
return;
|
||||
}
|
||||
|
||||
const root = unref(rootRef);
|
||||
const { $gsap } = useNuxtApp();
|
||||
|
||||
if (!root || !$gsap) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = $gsap.context(() => {
|
||||
$gsap.fromTo(
|
||||
root,
|
||||
{ autoAlpha: 0 },
|
||||
{ autoAlpha: 1, duration: 0.42, ease: "power2.out" },
|
||||
);
|
||||
|
||||
root.querySelectorAll("[data-cta-orbit]").forEach((element) => {
|
||||
$gsap.to(element, {
|
||||
scale: 1.08,
|
||||
autoAlpha: 0.72,
|
||||
duration: 2.8,
|
||||
ease: "sine.inOut",
|
||||
repeat: -1,
|
||||
yoyo: true,
|
||||
});
|
||||
});
|
||||
}, root);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
ctx?.revert();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user