done landing page
This commit is contained in:
157
components/ui/page-transition.tsx
Normal file
157
components/ui/page-transition.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { gsap } from "gsap";
|
||||
|
||||
interface PageTransitionProps {
|
||||
isOpen: boolean;
|
||||
onComplete?: () => void;
|
||||
direction?: "reveal" | "unreveal";
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
1. Path data – identical to the original demo
|
||||
------------------------------------------------------------------ */
|
||||
const paths = {
|
||||
step1: {
|
||||
unfilled: "M 0 100 V 100 Q 50 100 100 100 V 100 z",
|
||||
inBetween: {
|
||||
curve1: "M 0 100 V 50 Q 50 0 100 50 V 100 z",
|
||||
curve2: "M 0 100 V 50 Q 50 100 100 50 V 100 z",
|
||||
},
|
||||
filled: "M 0 100 V 0 Q 50 0 100 0 V 100 z",
|
||||
},
|
||||
step2: {
|
||||
filled: "M 0 0 V 100 Q 50 100 100 100 V 0 z",
|
||||
inBetween: {
|
||||
curve1: "M 0 0 V 50 Q 50 0 100 50 V 0 z",
|
||||
curve2: "M 0 0 V 50 Q 50 100 100 50 V 0 z",
|
||||
},
|
||||
unfilled: "M 0 0 V 0 Q 50 0 100 0 V 0 z",
|
||||
},
|
||||
};
|
||||
|
||||
export const PageTransition = ({
|
||||
isOpen,
|
||||
onComplete,
|
||||
direction = "reveal",
|
||||
}: PageTransitionProps) => {
|
||||
const pathRef = useRef<SVGPathElement>(null);
|
||||
const svgRef = useRef<SVGSVGElement>(null); // 👈 new ref for hiding
|
||||
const [animating, setAnimating] = useState(false);
|
||||
|
||||
/* --------------------------------------------------------------
|
||||
REVEAL – open second view
|
||||
-------------------------------------------------------------- */
|
||||
const reveal = () => {
|
||||
if (animating) return;
|
||||
setAnimating(true);
|
||||
|
||||
// 👇 Show overlay before animation starts
|
||||
gsap.set(svgRef.current, { display: "block" });
|
||||
|
||||
const tl = gsap.timeline({
|
||||
onComplete: () => {
|
||||
setAnimating(false);
|
||||
onComplete?.();
|
||||
// 👇 Hide overlay after animation completes
|
||||
gsap.set(svgRef.current, { display: "none" });
|
||||
},
|
||||
});
|
||||
|
||||
tl.set(pathRef.current, { attr: { d: paths.step1.unfilled } })
|
||||
.to(pathRef.current, {
|
||||
duration: 0.8,
|
||||
ease: "power4.in",
|
||||
attr: { d: paths.step1.inBetween.curve1 },
|
||||
})
|
||||
.to(pathRef.current, {
|
||||
duration: 0.2,
|
||||
ease: "power1",
|
||||
attr: { d: paths.step1.filled },
|
||||
onComplete: () => onComplete?.(),
|
||||
})
|
||||
.set(pathRef.current, { attr: { d: paths.step2.filled } })
|
||||
.to(pathRef.current, {
|
||||
duration: 0.2,
|
||||
ease: "sine.in",
|
||||
attr: { d: paths.step2.inBetween.curve1 },
|
||||
})
|
||||
.to(pathRef.current, {
|
||||
duration: 1,
|
||||
ease: "power4",
|
||||
attr: { d: paths.step2.unfilled },
|
||||
});
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------
|
||||
UNREVEAL – back to first view
|
||||
-------------------------------------------------------------- */
|
||||
const unreveal = () => {
|
||||
if (animating) return;
|
||||
setAnimating(true);
|
||||
|
||||
// 👇 Show overlay before animation starts
|
||||
gsap.set(svgRef.current, { display: "block" });
|
||||
|
||||
const tl = gsap.timeline({
|
||||
onComplete: () => {
|
||||
setAnimating(false);
|
||||
onComplete?.();
|
||||
// 👇 Hide overlay after animation completes
|
||||
gsap.set(svgRef.current, { display: "none" });
|
||||
},
|
||||
});
|
||||
|
||||
tl.set(pathRef.current, { attr: { d: paths.step2.unfilled } })
|
||||
.to(pathRef.current, {
|
||||
duration: 0.8,
|
||||
ease: "power4.in",
|
||||
attr: { d: paths.step2.inBetween.curve2 },
|
||||
})
|
||||
.to(pathRef.current, {
|
||||
duration: 0.2,
|
||||
ease: "power1",
|
||||
attr: { d: paths.step2.filled },
|
||||
onComplete: () => onComplete?.(),
|
||||
})
|
||||
.set(pathRef.current, { attr: { d: paths.step1.filled } })
|
||||
.to(pathRef.current, {
|
||||
duration: 0.2,
|
||||
ease: "sine.in",
|
||||
attr: { d: paths.step1.inBetween.curve2 },
|
||||
})
|
||||
.to(pathRef.current, {
|
||||
duration: 1,
|
||||
ease: "power4",
|
||||
attr: { d: paths.step1.unfilled },
|
||||
});
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------
|
||||
React to prop changes
|
||||
-------------------------------------------------------------- */
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
if (direction === "reveal") reveal();
|
||||
else if (direction === "unreveal") unreveal();
|
||||
}, [isOpen, direction]);
|
||||
|
||||
return (
|
||||
<svg
|
||||
ref={svgRef}
|
||||
className="pointer-events-none fixed top-0 left-0 z-[9999] h-screen w-screen"
|
||||
viewBox="0 0 100 100"
|
||||
preserveAspectRatio="none"
|
||||
style={{ display: "none" }} // 👈 hidden by default
|
||||
>
|
||||
<path
|
||||
ref={pathRef}
|
||||
className="overlay__path"
|
||||
d="M 0 100 V 100 Q 50 100 100 100 V 100 z"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
fill="#274b2d"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user