done landing page
This commit is contained in:
25
lib/useLenisScroll.js
Normal file
25
lib/useLenisScroll.js
Normal 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
82
lib/useSectionReveal.ts
Normal 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]);
|
||||
}
|
||||
57
lib/useTextRevealHeading.ts
Normal file
57
lib/useTextRevealHeading.ts
Normal 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
6
lib/utils.ts
Normal 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));
|
||||
}
|
||||
Reference in New Issue
Block a user