/**
* Skeleton - Loading skeleton components for web
*
* Components:
* - Skeleton: Basic skeleton element
* - SkeletonCard: Card-style skeleton
* - SkeletonList: List of skeleton items
* - SkeletonText: Text skeleton with multiple lines
* - SkeletonAvatar: Avatar/profile picture skeleton
*
* Features:
* - Animated shimmer effect
* - Multiple variants and sizes
* - Composable building blocks
* - Tailwind CSS styling
*
* @example
* ```tsx
* if (isLoading) {
* return ;
* }
* ```
*/
import { cn } from '@/lib/utils';
/**
* Skeleton - Base skeleton component with shimmer animation
*/
interface SkeletonProps {
className?: string;
variant?: 'rectangular' | 'circular' | 'text';
}
export function Skeleton({
className,
variant = 'rectangular',
}: SkeletonProps) {
const variantClasses = {
rectangular: 'rounded',
circular: 'rounded-full',
text: 'rounded h-4',
};
return (
);
}
/**
* SkeletonAvatar - Avatar skeleton with circular shape
*
* @example
* ```tsx
*
* ```
*/
interface SkeletonAvatarProps {
size?: 'sm' | 'md' | 'lg' | 'xl';
className?: string;
}
const avatarSizes = {
sm: 'h-8 w-8',
md: 'h-10 w-10',
lg: 'h-12 w-12',
xl: 'h-16 w-16',
};
export function SkeletonAvatar({
size = 'md',
className,
}: SkeletonAvatarProps) {
return (
);
}
/**
* SkeletonText - Multi-line text skeleton
*
* @example
* ```tsx
*
* ```
*/
interface SkeletonTextProps {
lines?: number;
className?: string;
}
export function SkeletonText({ lines = 3, className }: SkeletonTextProps) {
return (
{Array.from({ length: lines }).map((_, i) => (
))}
);
}
/**
* SkeletonCard - Card-style skeleton with header and content
*
* @example
* ```tsx
* {isLoading ? (
*
* ) : (
*
* )}
* ```
*/
interface SkeletonCardProps {
showAvatar?: boolean;
lines?: number;
className?: string;
}
export function SkeletonCard({
showAvatar = true,
lines = 3,
className,
}: SkeletonCardProps) {
return (
);
}
/**
* SkeletonList - List of skeleton cards
*
* @example
* ```tsx
* {isLoading ? (
*
* ) : (
* items.map(item => )
* )}
* ```
*/
interface SkeletonListProps {
count?: number;
showAvatar?: boolean;
className?: string;
}
export function SkeletonList({
count = 3,
showAvatar = true,
className,
}: SkeletonListProps) {
return (
{Array.from({ length: count }).map((_, i) => (
))}
);
}
/**
* SkeletonTable - Table skeleton with rows and columns
*
* @example
* ```tsx
* {isLoading ? (
*
* ) : (
*
* )}
* ```
*/
interface SkeletonTableProps {
rows?: number;
columns?: number;
showHeader?: boolean;
className?: string;
}
export function SkeletonTable({
rows = 5,
columns = 4,
showHeader = true,
className,
}: SkeletonTableProps) {
return (
{/* Header */}
{showHeader && (
{Array.from({ length: columns }).map((_, i) => (
))}
)}
{/* Rows */}
{Array.from({ length: rows }).map((_, rowIndex) => (
{Array.from({ length: columns }).map((_, colIndex) => (
))}
))}
);
}
/**
* SkeletonDashboard - Dashboard-style skeleton with multiple sections
*
* @example
* ```tsx
* {isLoading ? (
*
* ) : (
*
* )}
* ```
*/
export function SkeletonDashboard() {
return (
{/* Header */}
{/* Stats grid */}
{Array.from({ length: 4 }).map((_, i) => (
))}
{/* Content */}
);
}
/**
* SkeletonForm - Form skeleton with fields and button
*
* @example
* ```tsx
* {isLoading ? (
*
* ) : (
*
* )}
* ```
*/
interface SkeletonFormProps {
fields?: number;
className?: string;
}
export function SkeletonForm({ fields = 3, className }: SkeletonFormProps) {
return (
{Array.from({ length: fields }).map((_, i) => (
))}
);
}