48 lines
1.6 KiB
JavaScript
48 lines
1.6 KiB
JavaScript
import { useState } from 'react';
|
|
import { MediaItemSkeleton } from './media-item-skeleton';
|
|
|
|
const MediaItem = ({ src, alt, onClick, isSelected, className = "" }) => {
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [hasError, setHasError] = useState(false);
|
|
|
|
const handleImageLoad = () => {
|
|
setIsLoading(false);
|
|
};
|
|
|
|
const handleImageError = () => {
|
|
setIsLoading(false);
|
|
setHasError(true);
|
|
};
|
|
|
|
return (
|
|
<div className={`relative aspect-[9/16] w-full overflow-hidden rounded-lg bg-muted ${className}`}>
|
|
{isLoading && (
|
|
<div className="absolute inset-0 z-10">
|
|
<MediaItemSkeleton />
|
|
</div>
|
|
)}
|
|
|
|
{hasError ? (
|
|
<div className="flex h-full w-full items-center justify-center bg-muted text-muted-foreground text-xs p-2 text-center">
|
|
Failed to load
|
|
</div>
|
|
) : (
|
|
<img
|
|
src={src}
|
|
alt={alt}
|
|
className={`h-full w-full object-cover cursor-pointer transition-opacity duration-300 ${isLoading ? 'opacity-0' : 'opacity-100'}`}
|
|
onLoad={handleImageLoad}
|
|
onError={handleImageError}
|
|
onClick={onClick}
|
|
/>
|
|
)}
|
|
|
|
{/* Selection border overlay */}
|
|
{isSelected && !isLoading && (
|
|
<div className="absolute inset-0 rounded-lg ring-2 ring-blue-500 pointer-events-none" />
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export { MediaItem }; |