Files
portifolio-evandrodevbr/app/components/animations/LazyRevealImage.tsx
T
Evandro Fonseca Junior 08dd046887 feat: add animated components for enhanced UI/UX
- Introduced DrawLine component for drawing animations.
- Added LazyRevealImage component for lazy loading images with reveal animations.
- Implemented TextDiffuseReveal for animated text reveals with staggered effects.
- Created TopProgressBar for a dynamic loading indicator.
- Added PointCloud mock for testing animations.
- Developed useReducedMotion hook to handle user preferences for reduced motion.
- Centralized animation configurations in config.ts for easier management.
- Defined animation variants in variants.ts for consistent animation effects.
- Established AnimationProvider to supply global animation settings.
- Created tests for AnimationProvider and useReducedMotion hook.
- Added SVG assets for branding and UI elements.
- Documented frontend review plan and hero circuit board animation plan.
2026-03-15 21:06:43 -03:00

71 lines
1.8 KiB
TypeScript

"use client";
import { useState } from "react";
import Image, { type StaticImageData } from "next/image";
import { motion, useReducedMotion } from "framer-motion";
interface LazyRevealImageProps {
src: string | StaticImageData;
alt: string;
className?: string;
imageClassName?: string;
sizes?: string;
}
export function LazyRevealImage({
src,
alt,
className = "",
imageClassName = "object-cover",
sizes = "(max-width: 1024px) 100vw, 50vw",
}: Readonly<LazyRevealImageProps>) {
const shouldReduceMotion = useReducedMotion();
const [loaded, setLoaded] = useState(false);
const [animating, setAnimating] = useState(!shouldReduceMotion);
return (
<motion.div
className={`relative ${className}`.trim()}
initial={
shouldReduceMotion
? { opacity: 0 }
: { opacity: 0, filter: "blur(20px)", scale: 1.05 }
}
animate={
loaded
? shouldReduceMotion
? { opacity: 1 }
: { opacity: 1, filter: "blur(0px)", scale: 1 }
: shouldReduceMotion
? { opacity: 0 }
: { opacity: 0, filter: "blur(20px)", scale: 1.05 }
}
transition={{
duration: shouldReduceMotion ? 0.25 : 0.75,
ease: [0.16, 1, 0.3, 1],
}}
style={{
willChange:
animating && !shouldReduceMotion
? "filter, transform, opacity"
: undefined,
}}
onAnimationComplete={() => setAnimating(false)}
>
<Image
src={src}
alt={alt}
fill
loading="lazy"
sizes={sizes}
placeholder={typeof src === "string" ? "empty" : "blur"}
onLoad={() => {
setAnimating(true);
setLoaded(true);
}}
className={imageClassName}
/>
</motion.div>
);
}