77 lines
1.6 KiB
JavaScript
77 lines
1.6 KiB
JavaScript
"use client";
|
|
|
|
import { cn } from "@/shared/utils/cn";
|
|
|
|
// Spinner loading
|
|
export function Spinner({ size = "md", className }) {
|
|
const sizes = {
|
|
sm: "size-4",
|
|
md: "size-6",
|
|
lg: "size-8",
|
|
xl: "size-12",
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={cn(
|
|
"material-symbols-outlined animate-spin text-primary",
|
|
sizes[size],
|
|
className
|
|
)}
|
|
>
|
|
progress_activity
|
|
</span>
|
|
);
|
|
}
|
|
|
|
// Full page loading
|
|
export function PageLoading({ message = "Loading..." }) {
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex flex-col items-center justify-center bg-bg">
|
|
<Spinner size="xl" />
|
|
<p className="mt-4 text-text-muted">{message}</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Skeleton loading
|
|
export function Skeleton({ className, ...props }) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"animate-pulse rounded-lg bg-border",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
// Card skeleton
|
|
export function CardSkeleton() {
|
|
return (
|
|
<div className="p-6 rounded-xl border border-border bg-surface">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<Skeleton className="h-4 w-24" />
|
|
<Skeleton className="size-10 rounded-lg" />
|
|
</div>
|
|
<Skeleton className="h-8 w-16 mb-2" />
|
|
<Skeleton className="h-3 w-20" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Default export
|
|
export default function Loading({ type = "spinner", ...props }) {
|
|
switch (type) {
|
|
case "page":
|
|
return <PageLoading {...props} />;
|
|
case "skeleton":
|
|
return <Skeleton {...props} />;
|
|
case "card":
|
|
return <CardSkeleton {...props} />;
|
|
default:
|
|
return <Spinner {...props} />;
|
|
}
|
|
}
|
|
|