87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
import React from 'react';
|
|
import { Image as ImageIcon, AlertCircle, Loader2 } from 'lucide-react';
|
|
import { Box } from './primitives/Box';
|
|
import { Icon } from './Icon';
|
|
import { Text } from './Text';
|
|
|
|
export interface ImagePlaceholderProps {
|
|
size?: number | string;
|
|
aspectRatio?: string;
|
|
variant?: 'default' | 'error' | 'loading';
|
|
message?: string;
|
|
className?: string;
|
|
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';
|
|
}
|
|
|
|
export function ImagePlaceholder({
|
|
size = 'full',
|
|
aspectRatio = '1/1',
|
|
variant = 'default',
|
|
message,
|
|
className = '',
|
|
rounded = 'md',
|
|
}: ImagePlaceholderProps) {
|
|
const config = {
|
|
default: {
|
|
icon: ImageIcon,
|
|
color: 'text-gray-500',
|
|
bg: 'bg-charcoal-outline/20',
|
|
borderColor: 'border-charcoal-outline/50',
|
|
animate: undefined as 'spin' | 'pulse' | 'bounce' | 'fade-in' | 'none' | undefined,
|
|
},
|
|
error: {
|
|
icon: AlertCircle,
|
|
color: 'text-amber-500',
|
|
bg: 'bg-amber-500/5',
|
|
borderColor: 'border-amber-500/20',
|
|
animate: undefined as 'spin' | 'pulse' | 'bounce' | 'fade-in' | 'none' | undefined,
|
|
},
|
|
loading: {
|
|
icon: Loader2,
|
|
color: 'text-blue-500',
|
|
bg: 'bg-blue-500/5',
|
|
borderColor: 'border-blue-500/20',
|
|
animate: 'spin' as const,
|
|
},
|
|
};
|
|
|
|
const { icon, color, bg, borderColor, animate } = config[variant];
|
|
|
|
return (
|
|
<Box
|
|
display="flex"
|
|
flexDirection="col"
|
|
alignItems="center"
|
|
justifyContent="center"
|
|
w={typeof size === 'string' ? size : undefined}
|
|
h={typeof size === 'string' ? size : undefined}
|
|
style={typeof size === 'number' ? { width: size, height: size } : { aspectRatio }}
|
|
bg={bg}
|
|
border
|
|
borderColor={borderColor}
|
|
rounded={rounded}
|
|
className={`overflow-hidden ${className}`}
|
|
gap={2}
|
|
p={4}
|
|
>
|
|
<Icon
|
|
icon={icon}
|
|
size={6}
|
|
color={color}
|
|
animate={animate}
|
|
/>
|
|
{message && (
|
|
<Text
|
|
size="xs"
|
|
color={color}
|
|
weight="medium"
|
|
align="center"
|
|
className="max-w-[80%]"
|
|
>
|
|
{message}
|
|
</Text>
|
|
)}
|
|
</Box>
|
|
);
|
|
}
|