| import React, { useState, useEffect } from 'react'; |
| import { Loader2, LucideIcon } from 'lucide-react'; |
| import { cn } from '@/lib/utils'; |
| import { Progress } from '@/components/ui/progress'; |
|
|
| interface LoadingStateProps { |
| icon?: LucideIcon; |
| iconColor?: string; |
| bgColor?: string; |
| title: string; |
| subtitle?: string; |
| filePath?: string | null; |
| showProgress?: boolean; |
| progressText?: string; |
| autoProgress?: boolean; |
| initialProgress?: number; |
| } |
|
|
| export function LoadingState({ |
| icon: Icon = Loader2, |
| iconColor = 'text-purple-500 dark:text-purple-400', |
| bgColor = 'bg-gradient-to-b from-purple-100 to-purple-50 shadow-inner dark:from-purple-800/40 dark:to-purple-900/60 dark:shadow-purple-950/20', |
| title, |
| subtitle, |
| filePath, |
| showProgress = true, |
| progressText, |
| autoProgress = true, |
| initialProgress = 0, |
| }: LoadingStateProps): JSX.Element { |
| const [progress, setProgress] = useState(initialProgress); |
|
|
| useEffect(() => { |
| if (showProgress && autoProgress) { |
| setProgress(0); |
| const timer = setInterval(() => { |
| setProgress((prevProgress) => { |
| if (prevProgress >= 95) { |
| clearInterval(timer); |
| return prevProgress; |
| } |
| return prevProgress + Math.random() * 10 + 5; |
| }); |
| }, 500); |
| return () => clearInterval(timer); |
| } |
| }, [showProgress, autoProgress]); |
| return ( |
| <div className="flex flex-col items-center justify-center h-[calc(100vh-15rem)] overflow-hidden scrollbar-hide py-12 px-6"> |
| <div className="text-center w-full max-w-sm"> |
| <div className={cn("w-16 h-16 rounded-full mx-auto mb-6 flex items-center justify-center", bgColor)}> |
| <Icon className={cn("h-8 w-8", iconColor, Icon === Loader2 && "animate-spin")} /> |
| </div> |
| |
| <h3 className="text-xl font-semibold mb-4 text-zinc-900 dark:text-zinc-100"> |
| {title} |
| </h3> |
| |
| {filePath && ( |
| <div className="bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-4 w-full text-center mb-6 shadow-sm"> |
| <code className="text-sm font-mono text-zinc-700 dark:text-zinc-300 break-all"> |
| {filePath} |
| </code> |
| </div> |
| )} |
| |
| {showProgress && ( |
| <div className="space-y-3"> |
| <Progress value={Math.min(progress, 100)} className="w-full h-1" /> |
| <div className="flex justify-between items-center text-xs text-zinc-500 dark:text-zinc-400"> |
| <span>{progressText || 'Processing...'}</span> |
| <span className="font-mono">{Math.round(Math.min(progress, 100))}%</span> |
| </div> |
| </div> |
| )} |
| |
| {subtitle && ( |
| <p className="text-sm text-zinc-500 dark:text-zinc-400 mt-4"> |
| {subtitle} |
| </p> |
| )} |
| </div> |
| </div> |
| ); |
| } |