67 lines
2.2 KiB
TypeScript
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>
|
|
);
|
|
}
|