1
+ import { useEffect , useState } from 'react' ;
2
+ import { CheckCircle , Circle , Loader2 } from 'lucide-react' ;
1
3
import { Tabs , TabsContent , TabsList , TabsTrigger } from "@/components/ui/tabs" ;
4
+ import { Card , CardContent , CardHeader , CardTitle } from '@/components/ui/card' ;
2
5
import { benchifyFileSchema } from "@/lib/schemas" ;
3
6
import { z } from "zod" ;
4
7
import { CodeEditor } from "./code-editor" ;
5
8
9
+ interface Step {
10
+ id : string ;
11
+ label : string ;
12
+ description : string ;
13
+ }
14
+
15
+ const GENERATION_STEPS : Step [ ] = [
16
+ {
17
+ id : 'analyzing' ,
18
+ label : 'Analyzing Request' ,
19
+ description : 'Understanding your requirements and design specifications' ,
20
+ } ,
21
+ {
22
+ id : 'generating' ,
23
+ label : 'Generating Code' ,
24
+ description : 'Creating UI components with AI assistance' ,
25
+ } ,
26
+ {
27
+ id : 'building' ,
28
+ label : 'Building Project' ,
29
+ description : 'Setting up development environment and dependencies' ,
30
+ } ,
31
+ {
32
+ id : 'deploying' ,
33
+ label : 'Creating Preview' ,
34
+ description : 'Deploying your project for live preview' ,
35
+ } ,
36
+ ] ;
37
+
6
38
interface PreviewCardProps {
7
- previewUrl : string ;
39
+ previewUrl ? : string ;
8
40
code : z . infer < typeof benchifyFileSchema > ;
41
+ isGenerating ?: boolean ;
42
+ prompt ?: string ;
9
43
}
10
44
11
- export function PreviewCard ( { previewUrl, code } : PreviewCardProps ) {
45
+ export function PreviewCard ( { previewUrl, code, isGenerating = false , prompt } : PreviewCardProps ) {
12
46
const files = code || [ ] ;
47
+ const [ currentStep , setCurrentStep ] = useState ( 0 ) ;
48
+
49
+ useEffect ( ( ) => {
50
+ if ( isGenerating ) {
51
+ // Reset to first step when generation starts
52
+ setCurrentStep ( 0 ) ;
53
+
54
+ // Automatically advance through steps for visual feedback
55
+ const stepTimer = setInterval ( ( ) => {
56
+ setCurrentStep ( prev => {
57
+ // Cycle through steps, but don't go past the last one
58
+ if ( prev < GENERATION_STEPS . length - 1 ) {
59
+ return prev + 1 ;
60
+ }
61
+ return prev ;
62
+ } ) ;
63
+ } , 2000 ) ; // Advance every 2 seconds
64
+
65
+ return ( ) => clearInterval ( stepTimer ) ;
66
+ }
67
+ } , [ isGenerating ] ) ;
13
68
14
69
return (
15
70
< div className = "h-full" >
@@ -20,14 +75,69 @@ export function PreviewCard({ previewUrl, code }: PreviewCardProps) {
20
75
</ TabsList >
21
76
22
77
< TabsContent value = "preview" className = "flex-1 m-0" >
23
- < div className = "w-full h-full overflow-hidden rounded-md border bg-background" >
24
- < iframe
25
- title = "Preview"
26
- src = { previewUrl }
27
- className = "w-full h-full"
28
- sandbox = "allow-scripts allow-same-origin"
29
- />
30
- </ div >
78
+ { isGenerating && prompt ? (
79
+ // Show loading progress inside the preview tab
80
+ < div className = "w-full h-full flex items-center justify-center rounded-md border bg-background" >
81
+ < Card className = "w-full max-w-md mx-auto" >
82
+ < CardHeader >
83
+ < CardTitle > Building Your UI</ CardTitle >
84
+ < p className = "text-sm text-muted-foreground mt-2" >
85
+ "{ prompt . substring ( 0 , 100 ) } { prompt . length > 100 ? '...' : '' } "
86
+ </ p >
87
+ </ CardHeader >
88
+ < CardContent className = "space-y-4" >
89
+ { GENERATION_STEPS . map ( ( step , index ) => {
90
+ const isCompleted = index < currentStep ;
91
+ const isCurrent = index === currentStep ;
92
+
93
+ return (
94
+ < div key = { step . id } className = "flex items-start space-x-3" >
95
+ < div className = "flex-shrink-0 mt-1" >
96
+ { isCompleted ? (
97
+ < CheckCircle className = "h-5 w-5 text-green-500" />
98
+ ) : isCurrent ? (
99
+ < Loader2 className = "h-5 w-5 text-primary animate-spin" />
100
+ ) : (
101
+ < Circle className = "h-5 w-5 text-muted-foreground" />
102
+ ) }
103
+ </ div >
104
+ < div className = "flex-1 min-w-0" >
105
+ < p className = { `text-sm font-medium ${ isCompleted ? 'text-green-700 dark:text-green-400' :
106
+ isCurrent ? 'text-primary' :
107
+ 'text-muted-foreground'
108
+ } `} >
109
+ { step . label }
110
+ </ p >
111
+ < p className = { `text-xs ${ isCompleted || isCurrent ? 'text-muted-foreground' : 'text-muted-foreground/60'
112
+ } `} >
113
+ { step . description }
114
+ </ p >
115
+ </ div >
116
+ </ div >
117
+ ) ;
118
+ } ) }
119
+ </ CardContent >
120
+ </ Card >
121
+ </ div >
122
+ ) : previewUrl ? (
123
+ // Show the actual preview iframe when ready
124
+ < div className = "w-full h-full overflow-hidden rounded-md border bg-background" >
125
+ < iframe
126
+ title = "Preview"
127
+ src = { previewUrl }
128
+ className = "w-full h-full"
129
+ sandbox = "allow-scripts allow-same-origin"
130
+ />
131
+ </ div >
132
+ ) : (
133
+ // Show loading spinner if no preview URL yet
134
+ < div className = "w-full h-full flex items-center justify-center rounded-md border bg-background" >
135
+ < div className = "text-center" >
136
+ < div className = "animate-spin rounded-full h-32 w-32 border-b-2 border-primary mx-auto mb-4" > </ div >
137
+ < p className = "text-muted-foreground" > Loading your project...</ p >
138
+ </ div >
139
+ </ div >
140
+ ) }
31
141
</ TabsContent >
32
142
33
143
< TabsContent value = "code" className = "flex-1 m-0" >
0 commit comments