Adds consultation leads, section editors, and the one-time content reset for this release. Co-authored-by: Cursor <cursoragent@cursor.com>
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import type { Ref } from "vue";
|
|
|
|
/**
|
|
* Scroll-scrubbed hero device parallax. GSAP is imported only on the client after mount,
|
|
* keeping it off the critical rendering path; the context is reverted on unmount.
|
|
*/
|
|
export function useHeroScrollParallax(sectionEl: Ref<HTMLElement | null>) {
|
|
let revert: (() => void) | null = null;
|
|
let disposed = false;
|
|
|
|
onMounted(async () => {
|
|
const [{ gsap }, { ScrollTrigger }] = await Promise.all([import("gsap"), import("gsap/ScrollTrigger")]);
|
|
const root = sectionEl.value;
|
|
if (disposed || !root) return;
|
|
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
const laptop = root.querySelector<HTMLElement>("#hero-laptop");
|
|
const mobile = root.querySelector<HTMLElement>("#hero-mobile");
|
|
if (!laptop || !mobile) return;
|
|
|
|
const ctx = gsap.context(() => {
|
|
gsap.to(laptop, {
|
|
scrollTrigger: { trigger: root, start: "top top", end: "bottom top", scrub: 1.2 },
|
|
y: -40,
|
|
rotateY: -25,
|
|
rotateX: 13,
|
|
scale: 0.98,
|
|
ease: "none",
|
|
});
|
|
gsap.to(mobile, {
|
|
scrollTrigger: { trigger: root, start: "top top", end: "bottom top", scrub: 1.5 },
|
|
y: -85,
|
|
rotateY: -6,
|
|
rotateX: 4,
|
|
scale: 1.03,
|
|
ease: "none",
|
|
});
|
|
}, root);
|
|
revert = () => ctx.revert();
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
disposed = true;
|
|
revert?.();
|
|
});
|
|
}
|