Download src/components/states/LoadingState.tsx from asnannp/DocDoeAI: direct link, hf CLI and curl.
- Browser
- Download file 3.91 kB
-
https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/components/states/LoadingState.tsx
- Command line
-
hf download hf://spaces/asnannp/DocDoeAI/src/components/states/LoadingState.tsx
-
curl -L -o LoadingState.tsx https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/components/states/LoadingState.tsx
3.91 kB
| "use client"; | |
| import { cn } from "@/lib/utils"; | |
| type LoadingStateProps = { | |
| message?: string; | |
| size?: "sm" | "md" | "lg"; | |
| className?: string; | |
| }; | |
| export function LoadingState({ | |
| message = "Loading...", | |
| size = "md", | |
| className, | |
| }: LoadingStateProps) { | |
| const sizeClasses = { | |
| sm: "h-6 w-6 border-2", | |
| md: "h-8 w-8 border-2", | |
| lg: "h-12 w-12 border-3", | |
| }; | |
| return ( | |
| <div | |
| className={cn( | |
| "flex flex-col items-center justify-center gap-4 p-8", | |
| className, | |
| )} | |
| aria-live="polite" | |
| aria-busy="true" | |
| > | |
| <div | |
| className={cn( | |
| "animate-spin rounded-full border-current border-t-transparent", | |
| sizeClasses[size], | |
| )} | |
| role="status" | |
| aria-label="Loading" | |
| /> | |
| {message && ( | |
| <p className="text-[14px] text-[var(--text-secondary)] loading-message"> | |
| {message} | |
| </p> | |
| )} | |
| </div> | |
| ); | |
| } | |
| type SkeletonProps = { | |
| variant?: "text" | "card" | "circle" | "rect"; | |
| width?: string | number; | |
| height?: string | number; | |
| lines?: number; | |
| className?: string; | |
| }; | |
| export function Skeleton({ | |
| variant = "rect", | |
| width, | |
| height, | |
| lines = 1, | |
| className, | |
| }: SkeletonProps) { | |
| const baseClasses = "skeleton"; | |
| const variantClasses = { | |
| text: "rounded-md", | |
| card: "rounded-lg", | |
| circle: "rounded-full", | |
| rect: "rounded-sm", | |
| }; | |
| const style = { | |
| width: width || (variant === "text" ? "100%" : "120px"), | |
| height: height || (variant === "text" ? "1em" : variant === "circle" ? width || "40px" : "80px"), | |
| }; | |
| if (variant === "text" && lines > 1) { | |
| return ( | |
| <div className={cn("flex flex-col gap-2", className)}> | |
| {Array.from({ length: lines }).map((_, i) => ( | |
| <div | |
| key={i} | |
| className={cn(baseClasses, variantClasses[variant])} | |
| style={{ | |
| width: width || (i === lines - 1 ? "70%" : "100%"), | |
| height: height || "1em", | |
| }} | |
| /> | |
| ))} | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div | |
| className={cn(baseClasses, variantClasses[variant], className)} | |
| style={style} | |
| aria-hidden="true" | |
| /> | |
| ); | |
| } | |
| type PageLoadingProps = { | |
| message?: string; | |
| subtitle?: string; | |
| }; | |
| export function PageLoading({ message, subtitle }: PageLoadingProps) { | |
| return ( | |
| <div className="flex min-h-[400px] flex-1 items-center justify-center"> | |
| <LoadingState message={message || "Loading..."} size="lg" /> | |
| {subtitle && ( | |
| <p className="mt-2 text-center text-[13px] text-[var(--text-muted)]"> | |
| {subtitle} | |
| </p> | |
| )} | |
| </div> | |
| ); | |
| } | |
| type InlineLoadingProps = { | |
| text?: string; | |
| size?: "sm" | "md" | "lg"; | |
| className?: string; | |
| }; | |
| export function InlineLoading({ | |
| text = "Loading...", | |
| size = "sm", | |
| className, | |
| }: InlineLoadingProps) { | |
| return ( | |
| <div | |
| className={cn( | |
| "flex items-center gap-2 text-[var(--text-secondary)]", | |
| className, | |
| )} | |
| > | |
| <span | |
| className={cn( | |
| "animate-spin rounded-full border-current border-t-transparent", | |
| size === "sm" && "h-3 w-3 border-2", | |
| size === "md" && "h-4 w-4 border-2", | |
| size === "lg" && "h-5 w-5 border-2", | |
| )} | |
| /> | |
| <span className="text-[12px] sm:text-[13px]">{text}</span> | |
| </div> | |
| ); | |
| } | |
| type CardSkeletonProps = { | |
| lines?: number; | |
| withImage?: boolean; | |
| className?: string; | |
| }; | |
| export function CardSkeleton({ | |
| lines = 3, | |
| withImage = false, | |
| className, | |
| }: CardSkeletonProps) { | |
| return ( | |
| <div | |
| className={cn( | |
| "workspace-card overflow-hidden p-4", | |
| className, | |
| )} | |
| > | |
| {withImage && ( | |
| <Skeleton variant="rect" width="100%" height={120} className="mb-4" /> | |
| )} | |
| <Skeleton variant="text" width="60%" className="mb-2" /> | |
| <Skeleton variant="text" width="100%" lines={lines} /> | |
| </div> | |
| ); | |
| } | |