Files
klz-cables.com/components/blog/AnimatedImage.tsx
2026-01-19 02:05:30 +01:00

84 lines
2.3 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-2xl shadow-2xl my-16 group ${className}`}
>
<div className={`
absolute inset-0 bg-primary/10 z-10 pointer-events-none transition-opacity duration-1000
${isLoaded && isInView ? 'opacity-0' : 'opacity-100'}
`} />
<Image
src={src}
alt={alt}
width={width}
height={height}
className={`
duration-[1.5s] ease-out w-full h-auto transition-all
${isLoaded && isInView ? 'scale-100 blur-0 opacity-100' : 'scale-110 blur-2xl opacity-0'}
group-hover:scale-105
`}
onLoad={() => setIsLoaded(true)}
priority={priority}
/>
{/* Subtle reflection overlay */}
<div className="absolute inset-0 bg-gradient-to-tr from-white/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700 pointer-events-none" />
{alt && (
<div className="absolute bottom-0 left-0 right-0 p-6 bg-gradient-to-t from-black/60 to-transparent translate-y-full group-hover:translate-y-0 transition-transform duration-500">
<p className="text-sm text-white font-medium italic">
{alt}
</p>
</div>
)}
</div>
);
}