update about page
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import gsap from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
|
||||
@@ -10,6 +11,51 @@ import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
* and provides smooth defaults.
|
||||
*/
|
||||
export default function AnimationProvider({ children }: { children: React.ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
|
||||
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 vh = window.innerHeight || document.documentElement.clientHeight;
|
||||
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");
|
||||
},
|
||||
});
|
||||
|
||||
// ScrollTrigger does not fire onEnter for blocks already in view at
|
||||
// creation — on larger / taller screens those stayed un-animated.
|
||||
// Reveal any block already intersecting the viewport.
|
||||
const r = block.getBoundingClientRect();
|
||||
if (r.top < vh && r.bottom > 0) {
|
||||
block.classList.add("animated");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
@@ -24,72 +70,9 @@ export default function AnimationProvider({ children }: { children: React.ReactN
|
||||
// re-hidden animations on phones. Ignore those spurious resizes.
|
||||
ScrollTrigger.config({ ignoreMobileResize: true });
|
||||
|
||||
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 vh = window.innerHeight || document.documentElement.clientHeight;
|
||||
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");
|
||||
},
|
||||
});
|
||||
|
||||
// ScrollTrigger does not fire onEnter for blocks already in view at
|
||||
// creation — on larger / taller screens those stayed un-animated.
|
||||
// Reveal any block already intersecting the viewport.
|
||||
const r = block.getBoundingClientRect();
|
||||
if (r.top < vh && r.bottom > 0) {
|
||||
block.classList.add("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();
|
||||
@@ -111,7 +94,6 @@ export default function AnimationProvider({ children }: { children: React.ReactN
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
return () => {
|
||||
timeouts.forEach(clearTimeout);
|
||||
clearTimeout(resizeTimer);
|
||||
window.removeEventListener("load", handleLoad);
|
||||
window.removeEventListener("resize", handleResize);
|
||||
@@ -119,6 +101,29 @@ export default function AnimationProvider({ children }: { children: React.ReactN
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Listen for route changes and refresh ScrollTriggers so newly rendered content animates in correctly
|
||||
useEffect(() => {
|
||||
const refreshAnimations = () => {
|
||||
initDecorativeBlocks();
|
||||
ScrollTrigger.refresh(true);
|
||||
};
|
||||
|
||||
// Run route change handler immediately on navigation
|
||||
refreshAnimations();
|
||||
|
||||
// Staggered refreshes to accommodate page layout calculations and paint frames
|
||||
const timers = [
|
||||
setTimeout(refreshAnimations, 100),
|
||||
setTimeout(refreshAnimations, 400),
|
||||
setTimeout(refreshAnimations, 800),
|
||||
setTimeout(refreshAnimations, 1500),
|
||||
];
|
||||
|
||||
return () => {
|
||||
timers.forEach(clearTimeout);
|
||||
};
|
||||
}, [pathname]);
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user