import React from "react";
import { cn } from "~/lib/utils";
import { Loader2 } from "lucide-react";
interface LoadingSpinnerProps {
size?: "xs" | "sm" | "md" | "lg" | "xl";
variant?: "primary" | "secondary" | "muted" | "white";
className?: string;
}
export function LoadingSpinner({
size = "md",
variant = "primary",
className,
}: LoadingSpinnerProps) {
const sizes = {
xs: "w-3 h-3",
sm: "w-4 h-4",
md: "w-6 h-6",
lg: "w-8 h-8",
xl: "w-12 h-12",
};
const variants = {
primary: "text-primary",
secondary: "text-secondary",
muted: "text-muted-foreground",
white: "text-white",
};
return (
);
}
interface LoadingDotsProps {
size?: "sm" | "md" | "lg";
variant?: "primary" | "secondary" | "muted" | "white";
className?: string;
}
export function LoadingDots({
size = "md",
variant = "primary",
className,
}: LoadingDotsProps) {
const sizes = {
sm: "w-1 h-1",
md: "w-2 h-2",
lg: "w-3 h-3",
};
const variants = {
primary: "bg-primary",
secondary: "bg-secondary",
muted: "bg-muted-foreground",
white: "bg-white",
};
const dotClass = cn(
"rounded-full animate-pulse",
sizes[size],
variants[variant],
);
return (
);
}
interface LoadingBarProps {
progress?: number;
variant?: "primary" | "secondary" | "success" | "warning" | "error";
size?: "sm" | "md" | "lg";
className?: string;
showPercentage?: boolean;
}
export function LoadingBar({
progress,
variant = "primary",
size = "md",
className,
showPercentage = false,
}: LoadingBarProps) {
const variants = {
primary: "bg-primary",
secondary: "bg-secondary",
success: "bg-green-500",
warning: "bg-yellow-500",
error: "bg-red-500",
};
const sizes = {
sm: "h-1",
md: "h-2",
lg: "h-3",
};
return (
{showPercentage && progress !== undefined && (
در حال بارگذاری...
{Math.round(progress)}%
)}
);
}
interface LoadingPageProps {
title?: string;
description?: string;
variant?: "primary" | "white";
className?: string;
}
export function LoadingPage({
title = "در حال بارگذاری...",
description,
variant = "primary",
className,
}: LoadingPageProps) {
const isWhite = variant === "white";
return (
{title}
{description && (
{description}
)}
);
}
interface LoadingOverlayProps {
visible: boolean;
title?: string;
description?: string;
className?: string;
}
export function LoadingOverlay({
visible,
title = "در حال پردازش...",
description,
className,
}: LoadingOverlayProps) {
if (!visible) return null;
return (
{title}
{description && (
{description}
)}
);
}
interface LoadingButtonProps {
loading: boolean;
children: React.ReactNode;
className?: string;
}
export function LoadingButton({
loading,
children,
className,
...props
}: LoadingButtonProps & React.ButtonHTMLAttributes) {
return (
);
}
interface LoadingCardProps {
title?: string;
lines?: number;
showAvatar?: boolean;
className?: string;
}
export function LoadingCard({
title,
lines = 3,
showAvatar = false,
className,
}: LoadingCardProps) {
return (
{title &&
}
{showAvatar &&
}
{Array.from({ length: lines }).map((_, index) => (
))}
);
}
interface LoadingSkeletonProps {
className?: string;
variant?: "text" | "circular" | "rectangular";
width?: string | number;
height?: string | number;
}
export function LoadingSkeleton({
className,
variant = "rectangular",
width,
height,
}: LoadingSkeletonProps) {
const variants = {
text: "h-4 w-full",
circular: "rounded-full",
rectangular: "rounded",
};
const style: React.CSSProperties = {};
if (width) style.width = typeof width === "number" ? `${width}px` : width;
if (height)
style.height = typeof height === "number" ? `${height}px` : height;
return (
);
}
// Utility component for loading states
interface LoadingStateProps {
loading: boolean;
error?: string | null;
children: React.ReactNode;
loadingComponent?: React.ReactNode;
errorComponent?: React.ReactNode;
}
export function LoadingState({
loading,
error,
children,
loadingComponent,
errorComponent,
}: LoadingStateProps) {
if (loading) {
return loadingComponent || ;
}
if (error) {
return (
errorComponent || (
)
);
}
return <>{children}>;
}
// Default export for convenience
export default LoadingSpinner;