Files
homepage/components/animations/animate.tsx
2025-05-14 14:35:15 +02:00

111 lines
2.5 KiB
TypeScript

"use client"
import type React from "react"
import { useEffect, useRef, useState } from "react"
import { motion, useAnimation, useInView } from "framer-motion"
type AnimateProps = {
children: React.ReactNode
animation?: "fadeIn" | "fadeInUp" | "fadeInDown" | "fadeInLeft" | "fadeInRight" | "zoom" | "bounce"
delay?: number
duration?: number
className?: string
once?: boolean
threshold?: number
}
const animations = {
fadeIn: {
hidden: { opacity: 0 },
visible: { opacity: 1 },
},
fadeInUp: {
hidden: { opacity: 0, y: 50 },
visible: { opacity: 1, y: 0 },
},
fadeInDown: {
hidden: { opacity: 0, y: -50 },
visible: { opacity: 1, y: 0 },
},
fadeInLeft: {
hidden: { opacity: 0, x: -50 },
visible: { opacity: 1, x: 0 },
},
fadeInRight: {
hidden: { opacity: 0, x: 50 },
visible: { opacity: 1, x: 0 },
},
zoom: {
hidden: { opacity: 0, scale: 0.8 },
visible: { opacity: 1, scale: 1 },
},
bounce: {
hidden: { opacity: 0, y: 50 },
visible: {
opacity: 1,
y: 0,
transition: {
type: "spring",
bounce: 0.4,
},
},
},
}
export function Animate({
children,
animation = "fadeIn",
delay = 0,
duration = 0.5,
className = "",
once = true,
threshold = 0.1,
}: AnimateProps) {
const controls = useAnimation()
const ref = useRef(null)
const isInView = useInView(ref, { once, threshold })
const [shouldReduceMotion, setShouldReduceMotion] = useState(false)
// Check for prefers-reduced-motion
useEffect(() => {
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)")
setShouldReduceMotion(mediaQuery.matches)
const handleChange = () => setShouldReduceMotion(mediaQuery.matches)
mediaQuery.addEventListener("change", handleChange)
return () => mediaQuery.removeEventListener("change", handleChange)
}, [])
useEffect(() => {
if (isInView) {
controls.start("visible")
} else if (!once) {
controls.start("hidden")
}
}, [isInView, controls, once])
const selectedAnimation = animations[animation]
// If user prefers reduced motion, use a simpler animation
const variants = shouldReduceMotion
? {
hidden: { opacity: 0 },
visible: { opacity: 1 },
}
: selectedAnimation
return (
<motion.div
ref={ref}
initial="hidden"
animate={controls}
variants={variants}
transition={{ duration, delay, ease: "easeOut" }}
className={className}
>
{children}
</motion.div>
)
}