Files

67 lines
2.2 KiB
TypeScript

import { cn } from "@/lib/utils";
/** Base shimmer block. Compose larger layouts from these. */
export function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div className={cn("animate-pulse rounded-xl bg-secondary", className)} {...props} />;
}
/** A page-header placeholder (title + description). */
export function HeaderSkeleton() {
return (
<div className="mb-8 space-y-2">
<Skeleton className="h-8 w-56" />
<Skeleton className="h-4 w-80 max-w-full" />
</div>
);
}
/** A single card-shaped placeholder. */
export function CardSkeleton({ className }: { className?: string }) {
return <Skeleton className={cn("h-28 rounded-2xl", className)} />;
}
/** A responsive row of stat-card placeholders. */
export function StatRowSkeleton({ count = 3 }: { count?: number }) {
return (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{Array.from({ length: count }).map((_, i) => (
<CardSkeleton key={i} />
))}
</div>
);
}
/** A grid of square episode-card placeholders. */
export function EpisodeGridSkeleton({ count = 8 }: { count?: number }) {
return (
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
{Array.from({ length: count }).map((_, i) => (
<div key={i} className="overflow-hidden rounded-2xl border border-border bg-card">
<Skeleton className="aspect-square rounded-none" />
<div className="space-y-2 p-3">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-3 w-1/2" />
</div>
</div>
))}
</div>
);
}
/** A stacked list of row placeholders (for lists/tables). */
export function ListSkeleton({ rows = 4 }: { rows?: number }) {
return (
<div className="divide-y rounded-2xl border border-border">
{Array.from({ length: rows }).map((_, i) => (
<div key={i} className="flex items-center justify-between gap-3 p-4">
<div className="min-w-0 flex-1 space-y-2">
<Skeleton className="h-4 w-2/5" />
<Skeleton className="h-3 w-1/4" />
</div>
<Skeleton className="h-6 w-20 rounded-full" />
</div>
))}
</div>
);
}