first commit

This commit is contained in:
2026-05-27 15:11:56 +05:30
commit d2e47805c8
44 changed files with 11390 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
'use client'
import { useLenis } from './useLenis'
export function LenisProvider({ children }: { children: React.ReactNode }) {
useLenis()
return <>{children}</>
}

51
src/lib/animations.ts Normal file
View File

@@ -0,0 +1,51 @@
import type { Variants } from 'framer-motion'
export const fadeUp: Variants = {
hidden: { opacity: 0, y: 28 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] },
},
}
export const fadeIn: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1, transition: { duration: 0.5 } },
}
export const staggerContainer: Variants = {
hidden: {},
visible: {
transition: { staggerChildren: 0.08, delayChildren: 0.1 },
},
}
export const scaleUp: Variants = {
hidden: { opacity: 0, scale: 0.92 },
visible: {
opacity: 1,
scale: 1,
transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] },
},
}
export const slideLeft: Variants = {
hidden: { opacity: 0, x: 40 },
visible: {
opacity: 1,
x: 0,
transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] },
},
}
export const slideRight: Variants = {
hidden: { opacity: 0, x: -40 },
visible: {
opacity: 1,
x: 0,
transition: { duration: 0.6, ease: [0.25, 0.46, 0.45, 0.94] },
},
}
export const viewportConfig = { once: true, margin: '-80px' } as const

27
src/lib/useLenis.ts Normal file
View File

@@ -0,0 +1,27 @@
'use client'
import { useEffect } from 'react'
import Lenis from 'lenis'
export function useLenis() {
useEffect(() => {
const lenis = new Lenis({
duration: 1.2,
easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
orientation: 'vertical',
smoothWheel: true,
})
let rafId = 0
function raf(time: number) {
lenis.raf(time)
rafId = requestAnimationFrame(raf)
}
rafId = requestAnimationFrame(raf)
return () => {
cancelAnimationFrame(rafId)
lenis.destroy()
}
}, [])
}

30
src/lib/useScrollSpy.ts Normal file
View File

@@ -0,0 +1,30 @@
'use client'
import { useEffect, useState } from 'react'
export function useScrollSpy(sectionIds: string[], rootMargin = '-40% 0px -55% 0px') {
const [activeId, setActiveId] = useState<string | null>(null)
useEffect(() => {
if (typeof window === 'undefined') return
const elements = sectionIds
.map((id) => document.getElementById(id))
.filter((el): el is HTMLElement => !!el)
if (elements.length === 0) return
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) setActiveId(entry.target.id)
})
},
{ rootMargin, threshold: 0 }
)
elements.forEach((el) => observer.observe(el))
return () => observer.disconnect()
}, [sectionIds, rootMargin])
return activeId
}