Spaces:
Sleeping
Sleeping
| import { useEffect, useRef, useState } from 'react'; | |
| import { useInView } from 'framer-motion'; | |
| interface UseScrollAnimationOptions { | |
| threshold?: number; | |
| rootMargin?: string; | |
| triggerOnce?: boolean; | |
| delay?: number; | |
| } | |
| export const useScrollAnimation = (options: UseScrollAnimationOptions = {}) => { | |
| const ref = useRef(null); | |
| const isInView = useInView(ref, { | |
| threshold: options.threshold || 0.1, | |
| margin: options.rootMargin || '-100px 0px', | |
| once: options.triggerOnce !== false, | |
| }); | |
| const [hasAnimated, setHasAnimated] = useState(false); | |
| useEffect(() => { | |
| if (isInView && !hasAnimated) { | |
| if (options.delay) { | |
| setTimeout(() => setHasAnimated(true), options.delay); | |
| } else { | |
| setHasAnimated(true); | |
| } | |
| } | |
| }, [isInView, hasAnimated, options.delay]); | |
| return { | |
| ref, | |
| inView: isInView, | |
| hasAnimated: hasAnimated || isInView, | |
| }; | |
| }; | |
| export const useStaggeredAnimation = (itemCount: number, delay: number = 100) => { | |
| const [visibleItems, setVisibleItems] = useState<number[]>([]); | |
| const { ref, inView } = useScrollAnimation(); | |
| useEffect(() => { | |
| if (inView) { | |
| const timeouts: NodeJS.Timeout[] = []; | |
| for (let i = 0; i < itemCount; i++) { | |
| const timeout = setTimeout(() => { | |
| setVisibleItems(prev => [...prev, i]); | |
| }, i * delay); | |
| timeouts.push(timeout); | |
| } | |
| return () => { | |
| timeouts.forEach(timeout => clearTimeout(timeout)); | |
| }; | |
| } | |
| }, [inView, itemCount, delay]); | |
| return { | |
| ref, | |
| visibleItems, | |
| inView, | |
| }; | |
| }; | |
| // Hook for parallax effects | |
| export const useParallax = (speed: number = 0.5) => { | |
| const [offset, setOffset] = useState(0); | |
| const ref = useRef<HTMLDivElement>(null); | |
| useEffect(() => { | |
| const handleScroll = () => { | |
| if (ref.current) { | |
| const rect = ref.current.getBoundingClientRect(); | |
| const scrolled = window.pageYOffset; | |
| const rate = scrolled * speed; | |
| setOffset(rate); | |
| } | |
| }; | |
| window.addEventListener('scroll', handleScroll); | |
| return () => window.removeEventListener('scroll', handleScroll); | |
| }, [speed]); | |
| return { | |
| ref, | |
| offset, | |
| }; | |
| }; |