61 lines
1.2 KiB
TypeScript
61 lines
1.2 KiB
TypeScript
'use client'
|
|
import { useEffect, useRef } from 'react'
|
|
import { gsap } from 'gsap'
|
|
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
|
|
|
if (typeof window !== 'undefined') {
|
|
gsap.registerPlugin(ScrollTrigger)
|
|
}
|
|
|
|
interface ParallaxLayerProps {
|
|
depth?: number
|
|
children: React.ReactNode
|
|
className?: string
|
|
speed?: number
|
|
}
|
|
|
|
export default function ParallaxLayer({
|
|
depth = 1,
|
|
children,
|
|
className = '',
|
|
speed = 0.5
|
|
}: ParallaxLayerProps) {
|
|
const ref = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
const element = ref.current
|
|
if (!element) return
|
|
|
|
// Check for reduced motion
|
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
if (prefersReducedMotion) return
|
|
|
|
const yMovement = -100 * depth * speed
|
|
|
|
const tl = gsap.to(element, {
|
|
yPercent: yMovement,
|
|
ease: 'none',
|
|
scrollTrigger: {
|
|
trigger: element,
|
|
start: 'top bottom',
|
|
end: 'bottom top',
|
|
scrub: true,
|
|
invalidateOnRefresh: true
|
|
}
|
|
})
|
|
|
|
return () => {
|
|
tl.kill()
|
|
}
|
|
}, [depth, speed])
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={`will-change-transform ${className}`}
|
|
style={{ willChange: 'transform' }}
|
|
>
|
|
{children}
|
|
</div>
|
|
)
|
|
} |