Files
klz-cables.com/components/blog/AnimatedImage.tsx
2026-01-17 01:22:01 +01:00

72 lines
1.6 KiB
TypeScript

'use client';
import React, { useState, useEffect, useRef } from 'react';
import Image from 'next/image';
interface AnimatedImageProps {
src: string;
alt: string;
width?: number;
height?: number;
className?: string;
priority?: boolean;
}
export default function AnimatedImage({
src,
alt,
width = 800,
height = 600,
className = '',
priority = false,
}: AnimatedImageProps) {
const [isLoaded, setIsLoaded] = useState(false);
const [isInView, setIsInView] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setIsInView(true);
observer.disconnect();
}
});
},
{ threshold: 0.1 }
);
if (containerRef.current) {
observer.observe(containerRef.current);
}
return () => observer.disconnect();
}, []);
return (
<div
ref={containerRef}
className={`relative overflow-hidden rounded-xl shadow-lg my-12 ${className}`}
>
<Image
src={src}
alt={alt}
width={width}
height={height}
className={`
duration-1000 ease-out w-full h-auto
${isLoaded && isInView ? 'scale-100 blur-0 opacity-100' : 'scale-110 blur-xl opacity-0'}
`}
onLoad={() => setIsLoaded(true)}
priority={priority}
/>
{alt && (
<p className="text-sm text-text-secondary text-center mt-3 italic px-4 pb-4">
{alt}
</p>
)}
</div>
);
}