done landing page

This commit is contained in:
2025-11-10 17:10:34 +05:30
parent 3852d46661
commit 483515e163
105 changed files with 3529 additions and 104 deletions

25
lib/useLenisScroll.js Normal file
View File

@@ -0,0 +1,25 @@
"use client";
import { useEffect } from "react";
import Lenis from "@studio-freight/lenis";
export default function SmoothScrollProvider({ children }) {
useEffect(() => {
const lenis = new Lenis({
smooth: true,
duration: 1.2, // Adjust the scroll speed
});
function raf(time) {
lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
return () => {
lenis.destroy();
};
}, []);
return <>{children}</>;
}

82
lib/useSectionReveal.ts Normal file
View File

@@ -0,0 +1,82 @@
import { useEffect } from "react";
import gsap from "gsap";
import SplitText from "gsap/SplitText";
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(SplitText, ScrollTrigger);
type UseSplitTextAnimationProps<T extends HTMLElement = HTMLElement> = {
headingRef: React.RefObject<T | null>;
paraRef: React.RefObject<T | null>;
shinyRef?: React.RefObject<T | null>;
triggerId: string;
};
export function useSplitTextAnimation<T extends HTMLElement = HTMLElement>({
headingRef,
paraRef,
shinyRef,
triggerId,
}: UseSplitTextAnimationProps<T>) {
useEffect(() => {
const ctx = gsap.context(() => {
const tl = gsap.timeline({
scrollTrigger: {
trigger: `#${triggerId}`,
start: "top 70%",
},
});
const headingSplit = new SplitText(headingRef.current, {
type: "lines, words",
linesClass: "line",
});
const paraSplit = new SplitText(paraRef.current, {
type: "lines, words",
linesClass: "line",
});
const headingWords = headingSplit.words;
const paraWords = paraSplit.words;
if (shinyRef?.current) {
tl.from(shinyRef.current, {
opacity: 0,
y: 20,
duration: 0.6,
ease: "power",
});
}
tl.from(
headingWords,
{
duration: 0.8,
opacity: 0,
yPercent: 120,
ease: "power",
stagger: 0.015,
},
"-=0.2"
);
tl.from(
paraWords,
{
duration: 0.7,
opacity: 0,
yPercent: 120,
ease: "power",
stagger: 0.01,
},
"-=0.5"
);
});
return () => {
ctx.revert();
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
};
}, [headingRef, paraRef, shinyRef, triggerId]);
}

View File

@@ -0,0 +1,57 @@
"use client";
import { useEffect } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
gsap.registerPlugin(ScrollTrigger, SplitText);
export const useSplitHeading = (
headingRef: React.RefObject<HTMLElement | null>,
subHeadingRef?: React.RefObject<HTMLElement | null>
) => {
useEffect(() => {
if (!headingRef.current) return;
const headingSplit = new SplitText(headingRef.current, { type: "words" });
const subSplit =
subHeadingRef?.current &&
new SplitText(subHeadingRef.current, { type: "words" });
// heading animation
gsap.from(headingSplit.words, {
yPercent: 100,
opacity: 0,
duration: 1,
ease: "expo.out",
stagger: 0.07,
scrollTrigger: {
trigger: headingRef.current,
start: "top 85%",
toggleActions: "play none none none",
},
});
// subheading animation
if (subSplit) {
gsap.from(subSplit.words, {
yPercent: 100,
opacity: 0,
duration: 1,
ease: "expo.out",
stagger: 0.04,
scrollTrigger: {
trigger: subHeadingRef?.current,
start: "top 85%",
toggleActions: "play none none none",
},
});
}
return () => {
headingSplit.revert();
subSplit?.revert();
ScrollTrigger.getAll().forEach((st) => st.kill());
};
}, [headingRef, subHeadingRef]);
};

6
lib/utils.ts Normal file
View File

@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}