Spaces:
Running
Running
import { useEffect } from 'react'; | |
import { Fancybox } from "@fancyapps/ui"; | |
import "@fancyapps/ui/dist/fancybox/fancybox.css"; | |
interface Image { | |
url: string; | |
} | |
interface ImageCardProps { | |
image: Image; | |
batchImages: Image[]; | |
batchId: number; | |
status?: 'pending' | 'error' | 'completed'; | |
width: number; | |
height: number; | |
elapsedTime: number; | |
} | |
export default function ImageCard({ image, batchImages, batchId, status, width, height, elapsedTime }: ImageCardProps) { | |
useEffect(() => { | |
Fancybox.bind(`[data-fancybox="gallery-${batchId}"]`, { | |
contentClick: "iterateZoom", | |
Images: { | |
Panzoom: { | |
maxScale: 8, | |
}, | |
}, | |
Toolbar: { | |
display: { | |
left: ["infobar"], | |
middle: [], | |
right: ["iterateZoom", "fullscreen", "download", "thumbs", "close"], | |
} | |
}, | |
Thumbs: { | |
type: "classic", | |
}, | |
}); | |
return () => { | |
Fancybox.destroy(); | |
}; | |
}, [batchId]); | |
const aspectRatio = `${width} / ${height}`; | |
return ( | |
<a | |
href={image.url} | |
data-fancybox={`gallery-${batchId}`} | |
data-src={image.url} | |
className="block relative" | |
style={{ aspectRatio }} | |
> | |
<div | |
className={`w-full h-full bg-center bg-no-repeat bg-cover rounded-xl cursor-pointer overflow-hidden ${ | |
status === 'pending' ? 'animate-pulse bg-gray-300 dark:bg-gray-700' : '' | |
}`} | |
style={status !== 'pending' ? {backgroundImage: `url("${image.url}")`} : {}} | |
> | |
{status === 'pending' && ( | |
<div className="absolute inset-0 flex items-center justify-center"> | |
<div className="relative w-16 h-16"> | |
<svg className="animate-spin h-16 w-16 text-primary" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> | |
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> | |
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> | |
</svg> | |
<div className="absolute inset-0 flex items-center justify-center"> | |
<span className="text-primary font-bold">{elapsedTime.toFixed(1)}s</span> | |
</div> | |
</div> | |
</div> | |
)} | |
{status === 'error' && ( | |
<div className="flex items-center justify-center h-full bg-red-200 dark:bg-red-900 rounded-xl"> | |
<span className="text-red-500 dark:text-red-300">Error</span> | |
</div> | |
)} | |
</div> | |
</a> | |
); | |
} | |