104 lines
2.8 KiB
TypeScript
104 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import React, { useEffect } from "react";
|
|
import gsap from "gsap";
|
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
|
|
/**
|
|
* AnimationProvider
|
|
* Initializes GSAP + ScrollTrigger globally, refreshes on route changes,
|
|
* and provides smooth defaults.
|
|
*/
|
|
export default function AnimationProvider({ children }: { children: React.ReactNode }) {
|
|
useEffect(() => {
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
|
|
// Global GSAP defaults for buttery animations
|
|
gsap.defaults({
|
|
ease: "power3.out",
|
|
duration: 0.8,
|
|
});
|
|
|
|
const initDecorativeBlocks = () => {
|
|
// Clean up previous block triggers to avoid duplicates
|
|
ScrollTrigger.getAll().forEach((t) => {
|
|
if (t.vars && (t.vars as any).id === "block-deco") {
|
|
t.kill();
|
|
}
|
|
});
|
|
|
|
const decorativeBlocks = document.querySelectorAll(".block-decoration");
|
|
decorativeBlocks.forEach((block) => {
|
|
ScrollTrigger.create({
|
|
id: "block-deco",
|
|
trigger: block,
|
|
start: "top 92%",
|
|
onEnter: () => {
|
|
setTimeout(() => {
|
|
block.classList.add("animated");
|
|
}, 150);
|
|
},
|
|
onEnterBack: () => {
|
|
setTimeout(() => {
|
|
block.classList.add("animated");
|
|
}, 150);
|
|
},
|
|
onLeave: () => {
|
|
block.classList.remove("animated");
|
|
},
|
|
onLeaveBack: () => {
|
|
block.classList.remove("animated");
|
|
},
|
|
});
|
|
});
|
|
};
|
|
|
|
// Run initializations
|
|
initDecorativeBlocks();
|
|
|
|
// Refresh ScrollTrigger at staggered intervals to account for lazy-loaded assets/images over the network
|
|
const timeouts = [
|
|
setTimeout(() => {
|
|
initDecorativeBlocks();
|
|
ScrollTrigger.refresh(true);
|
|
}, 100),
|
|
setTimeout(() => {
|
|
initDecorativeBlocks();
|
|
ScrollTrigger.refresh(true);
|
|
}, 500),
|
|
setTimeout(() => {
|
|
initDecorativeBlocks();
|
|
ScrollTrigger.refresh(true);
|
|
}, 1500),
|
|
setTimeout(() => {
|
|
initDecorativeBlocks();
|
|
ScrollTrigger.refresh(true);
|
|
}, 3000),
|
|
];
|
|
|
|
// Refresh on full window load (when all images, styles, and fonts are in place)
|
|
const handleLoad = () => {
|
|
initDecorativeBlocks();
|
|
ScrollTrigger.refresh(true);
|
|
};
|
|
window.addEventListener("load", handleLoad);
|
|
|
|
// Also refresh on window resize
|
|
const handleResize = () => {
|
|
initDecorativeBlocks();
|
|
ScrollTrigger.refresh(true);
|
|
};
|
|
window.addEventListener("resize", handleResize);
|
|
|
|
return () => {
|
|
timeouts.forEach(clearTimeout);
|
|
window.removeEventListener("load", handleLoad);
|
|
window.removeEventListener("resize", handleResize);
|
|
ScrollTrigger.getAll().forEach((t) => t.kill());
|
|
};
|
|
}, []);
|
|
|
|
return <>{children}</>;
|
|
}
|
|
|