70 lines
2.1 KiB
TypeScript
70 lines
2.1 KiB
TypeScript
"use client";
|
|
import React from "react";
|
|
import Image from "next/image";
|
|
import { Sparkles } from "lucide-react";
|
|
import { cn } from "../lib/utils";
|
|
|
|
interface SafeImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, 'src'> {
|
|
src?: string;
|
|
alt?: string;
|
|
className?: string;
|
|
imgClassName?: string;
|
|
fallbackText?: string;
|
|
}
|
|
|
|
export default function SafeImage({
|
|
src,
|
|
alt = "تصویر مکمل کنینا",
|
|
className,
|
|
imgClassName,
|
|
fallbackText = "در حال بروزرسانی تصویر..."
|
|
}: SafeImageProps) {
|
|
const [error, setError] = React.useState(false);
|
|
const [loading, setLoading] = React.useState(true);
|
|
|
|
if (!src || error) {
|
|
return (
|
|
<div className={cn(
|
|
"flex flex-col items-center justify-center bg-medical-gray-50/90 border border-medical-gray-100 p-2 text-center w-full h-full rounded-2xl relative overflow-hidden select-none",
|
|
className
|
|
)}>
|
|
<Image
|
|
src="/assets/images/canina-product-placeholder.png"
|
|
alt={alt}
|
|
width={240}
|
|
height={240}
|
|
className="max-h-[85%] w-auto object-contain opacity-70"
|
|
unoptimized
|
|
/>
|
|
<span className="text-[9px] font-black text-canina-blue/80 font-vazir leading-tight mt-1 line-clamp-1 bg-white/80 px-2 py-0.5 rounded-md shadow-xs">
|
|
{fallbackText}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={cn("relative overflow-hidden group flex items-center justify-center", className)}>
|
|
{loading && (
|
|
<div className="absolute inset-0 bg-medical-gray-50 animate-pulse flex items-center justify-center z-10">
|
|
<Sparkles className="w-6 h-6 text-canina-blue/20" />
|
|
</div>
|
|
)}
|
|
<Image
|
|
src={src}
|
|
alt={alt}
|
|
width={500}
|
|
height={500}
|
|
unoptimized
|
|
className={cn(
|
|
"transition-all duration-700 w-full h-full",
|
|
imgClassName,
|
|
loading ? "opacity-0 scale-110" : "opacity-100 scale-100"
|
|
)}
|
|
onLoad={() => setLoading(false)}
|
|
onError={() => setError(true)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|