mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-10 11:51:29 +00:00
Co-authored-by: Alan Buscaglia <alanbuscaglia@MacBook-Pro.local> Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com> Co-authored-by: César Arroba <cesar@prowler.com> Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
121 lines
3.0 KiB
TypeScript
121 lines
3.0 KiB
TypeScript
import { cn } from "@/lib/utils";
|
|
|
|
interface SkeletonProps {
|
|
className?: string;
|
|
variant?: "default" | "card" | "table" | "text" | "circle" | "rectangular";
|
|
width?: string | number;
|
|
height?: string | number;
|
|
animate?: boolean;
|
|
}
|
|
|
|
export function Skeleton({
|
|
className,
|
|
variant = "default",
|
|
width,
|
|
height,
|
|
animate = true,
|
|
}: SkeletonProps) {
|
|
const variantClasses = {
|
|
default: "w-full h-4 rounded-lg",
|
|
card: "w-full h-40 rounded-xl",
|
|
table: "w-full h-60 rounded-lg",
|
|
text: "w-24 h-4 rounded-full",
|
|
circle: "rounded-full w-8 h-8",
|
|
rectangular: "rounded-md",
|
|
};
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
width: width
|
|
? typeof width === "number"
|
|
? `${width}px`
|
|
: width
|
|
: undefined,
|
|
height: height
|
|
? typeof height === "number"
|
|
? `${height}px`
|
|
: height
|
|
: undefined,
|
|
}}
|
|
className={cn(
|
|
"dark:bg-prowler-blue-800 animate-pulse bg-gray-200",
|
|
variantClasses[variant],
|
|
!animate && "animate-none",
|
|
className,
|
|
)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function SkeletonTable({
|
|
rows = 5,
|
|
columns = 4,
|
|
className,
|
|
roundedCells = true,
|
|
}: {
|
|
rows?: number;
|
|
columns?: number;
|
|
className?: string;
|
|
roundedCells?: boolean;
|
|
}) {
|
|
return (
|
|
<div className={cn("flex w-full flex-col gap-4", className)}>
|
|
{/* Header */}
|
|
<div className="flex items-center gap-4 pb-4">
|
|
{Array.from({ length: columns }).map((_, index) => (
|
|
<Skeleton
|
|
key={`header-${index}`}
|
|
className={cn("h-8", roundedCells && "rounded-lg")}
|
|
width={`${100 / columns}%`}
|
|
variant={roundedCells ? "default" : "rectangular"}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{/* Rows */}
|
|
{Array.from({ length: rows }).map((_, rowIndex) => (
|
|
<div key={`row-${rowIndex}`} className="flex items-center gap-4 py-3">
|
|
{Array.from({ length: columns }).map((_, colIndex) => (
|
|
<Skeleton
|
|
key={`cell-${rowIndex}-${colIndex}`}
|
|
className={cn("h-6", roundedCells && "rounded-lg")}
|
|
width={`${100 / columns}%`}
|
|
variant={roundedCells ? "default" : "rectangular"}
|
|
/>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function SkeletonCard({ className }: { className?: string }) {
|
|
return (
|
|
<div className={cn("flex flex-col gap-3", className)}>
|
|
<Skeleton variant="card" />
|
|
<Skeleton className="h-4 w-2/3" />
|
|
<Skeleton className="h-4 w-1/2" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function SkeletonText({
|
|
lines = 3,
|
|
className,
|
|
lastLineWidth = "w-1/2",
|
|
}: {
|
|
lines?: number;
|
|
className?: string;
|
|
lastLineWidth?: string;
|
|
}) {
|
|
return (
|
|
<div className={cn("flex flex-col gap-2", className)}>
|
|
{Array.from({ length: lines - 1 }).map((_, index) => (
|
|
<Skeleton key={index} className="h-4 w-full" variant="text" />
|
|
))}
|
|
<Skeleton className={cn("h-4", lastLineWidth)} variant="text" />
|
|
</div>
|
|
);
|
|
}
|