45 lines
1.1 KiB
TypeScript
45 lines
1.1 KiB
TypeScript
interface SkeletonProps {
|
|
className?: string
|
|
variant?: 'text' | 'circular' | 'rectangular'
|
|
width?: string | number
|
|
height?: string | number
|
|
}
|
|
|
|
function getVariantClasses(variant: SkeletonProps['variant']): string {
|
|
switch (variant) {
|
|
case 'circular':
|
|
return 'rounded-full'
|
|
case 'rectangular':
|
|
return 'rounded-lg'
|
|
case 'text':
|
|
default:
|
|
return 'rounded'
|
|
}
|
|
}
|
|
|
|
export function Skeleton({
|
|
className = '',
|
|
variant = 'text',
|
|
width,
|
|
height,
|
|
}: SkeletonProps): React.ReactElement {
|
|
const variantClasses = getVariantClasses(variant)
|
|
const baseClasses = 'bg-cyber-light animate-pulse'
|
|
const style: React.CSSProperties = {}
|
|
|
|
if (width) {
|
|
style.width = typeof width === 'number' ? `${width}px` : width
|
|
}
|
|
if (height) {
|
|
style.height = typeof height === 'number' ? `${height}px` : height
|
|
}
|
|
|
|
const combinedClasses = `${baseClasses} ${variantClasses} ${className}`.trim()
|
|
|
|
return (
|
|
<div className={combinedClasses} style={style} aria-busy="true" aria-label="Loading">
|
|
<span className="sr-only">Loading...</span>
|
|
</div>
|
|
)
|
|
}
|