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 || (

{error}

) ); } return <>{children}; } // Default export for convenience export default LoadingSpinner;