first commit
This commit is contained in:
8
src/lib/LenisProvider.tsx
Normal file
8
src/lib/LenisProvider.tsx
Normal 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
51
src/lib/animations.ts
Normal 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
27
src/lib/useLenis.ts
Normal 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
30
src/lib/useScrollSpy.ts
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user