84 lines
2.3 KiB
TypeScript
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>
|
|
);
|
|
}
|