@@ -4,6 +4,7 @@ import "@copilotkit/react-ui/styles.css";
4
4
import "./style.css" ;
5
5
import { CopilotKit , useCoAgentStateRender } from "@copilotkit/react-core" ;
6
6
import { CopilotChat } from "@copilotkit/react-ui" ;
7
+ import { useTheme } from "next-themes" ;
7
8
8
9
interface AgenticGenerativeUIProps {
9
10
params : Promise < {
@@ -33,42 +34,146 @@ interface AgentState {
33
34
}
34
35
35
36
const Chat = ( ) => {
37
+ const { theme } = useTheme ( ) ;
36
38
useCoAgentStateRender < AgentState > ( {
37
39
name : "agentic_generative_ui" ,
38
40
render : ( { state } ) => {
39
41
if ( ! state . steps || state . steps . length === 0 ) {
40
42
return null ;
41
43
}
42
44
45
+ const completedCount = state . steps . filter ( step => step . status === "completed" ) . length ;
46
+ const progressPercentage = ( completedCount / state . steps . length ) * 100 ;
47
+
43
48
return (
44
49
< div className = "flex" >
45
- < div className = "bg-gray-100 rounded-lg w-[800px] p-4 text-black space-y-2" >
46
- { state . steps . map ( ( step , index ) => {
47
- if ( step . status === "completed" ) {
48
- return (
49
- < div key = { index } className = "text-sm" >
50
- ✓ { step . description }
51
- </ div >
52
- ) ;
53
- } else if (
54
- step . status === "pending" &&
55
- index === state . steps . findIndex ( ( s ) => s . status === "pending" )
56
- ) {
57
- return (
58
- < div key = { index } className = "text-2xl font-bold text-slate-700" >
59
- < Spinner />
60
- { step . description }
61
- </ div >
62
- ) ;
63
- } else {
50
+ < div className = { `relative rounded-xl w-[700px] p-6 shadow-lg backdrop-blur-sm ${
51
+ theme === "dark"
52
+ ? "bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 text-white border border-slate-700/50 shadow-2xl"
53
+ : "bg-gradient-to-br from-white via-gray-50 to-white text-gray-800 border border-gray-200/80"
54
+ } `} >
55
+ { /* Header */ }
56
+ < div className = "mb-5" >
57
+ < div className = "flex items-center justify-between mb-3" >
58
+ < h3 className = "text-xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent" >
59
+ Task Progress
60
+ </ h3 >
61
+ < div className = { `text-sm ${ theme === "dark" ? "text-slate-400" : "text-gray-500" } ` } >
62
+ { completedCount } /{ state . steps . length } Complete
63
+ </ div >
64
+ </ div >
65
+
66
+ { /* Progress Bar */ }
67
+ < div className = { `relative h-2 rounded-full overflow-hidden ${ theme === "dark" ? "bg-slate-700" : "bg-gray-200" } ` } >
68
+ < div
69
+ className = "absolute top-0 left-0 h-full bg-gradient-to-r from-blue-500 to-purple-500 rounded-full transition-all duration-1000 ease-out"
70
+ style = { { width : `${ progressPercentage } %` } }
71
+ />
72
+ < div className = { `absolute top-0 left-0 h-full w-full bg-gradient-to-r from-transparent to-transparent animate-pulse ${
73
+ theme === "dark" ? "via-white/20" : "via-white/40"
74
+ } `} />
75
+ </ div >
76
+ </ div >
77
+
78
+ { /* Steps */ }
79
+ < div className = "space-y-2" >
80
+ { state . steps . map ( ( step , index ) => {
81
+ const isCompleted = step . status === "completed" ;
82
+ const isCurrentPending = step . status === "pending" &&
83
+ index === state . steps . findIndex ( ( s ) => s . status === "pending" ) ;
84
+ const isFuturePending = step . status === "pending" && ! isCurrentPending ;
85
+
64
86
return (
65
- < div key = { index } className = "text-sm" >
66
- < Spinner />
67
- { step . description }
87
+ < div
88
+ key = { index }
89
+ className = { `relative flex items-center p-2.5 rounded-lg transition-all duration-500 ${
90
+ isCompleted
91
+ ? theme === "dark"
92
+ ? "bg-gradient-to-r from-green-900/30 to-emerald-900/20 border border-green-500/30"
93
+ : "bg-gradient-to-r from-green-50 to-emerald-50 border border-green-200/60"
94
+ : isCurrentPending
95
+ ? theme === "dark"
96
+ ? "bg-gradient-to-r from-blue-900/40 to-purple-900/30 border border-blue-500/50 shadow-lg shadow-blue-500/20"
97
+ : "bg-gradient-to-r from-blue-50 to-purple-50 border border-blue-200/60 shadow-md shadow-blue-200/50"
98
+ : theme === "dark"
99
+ ? "bg-slate-800/50 border border-slate-600/30"
100
+ : "bg-gray-50/50 border border-gray-200/60"
101
+ } `}
102
+ >
103
+ { /* Connector Line */ }
104
+ { index < state . steps . length - 1 && (
105
+ < div className = { `absolute left-5 top-full w-0.5 h-2 bg-gradient-to-b ${
106
+ theme === "dark" ? "from-slate-500 to-slate-600" : "from-gray-300 to-gray-400"
107
+ } `} />
108
+ ) }
109
+
110
+ { /* Status Icon */ }
111
+ < div className = { `flex-shrink-0 w-6 h-6 rounded-full flex items-center justify-center mr-2 ${
112
+ isCompleted
113
+ ? theme === "dark"
114
+ ? "bg-gradient-to-br from-green-500 to-emerald-600 shadow-lg shadow-green-500/30"
115
+ : "bg-gradient-to-br from-green-500 to-emerald-600 shadow-md shadow-green-200"
116
+ : isCurrentPending
117
+ ? theme === "dark"
118
+ ? "bg-gradient-to-br from-blue-500 to-purple-600 shadow-lg shadow-blue-500/30"
119
+ : "bg-gradient-to-br from-blue-500 to-purple-600 shadow-md shadow-blue-200"
120
+ : theme === "dark"
121
+ ? "bg-slate-700 border border-slate-600"
122
+ : "bg-gray-300 border border-gray-400"
123
+ } `} >
124
+ { isCompleted ? (
125
+ < CheckIcon />
126
+ ) : isCurrentPending ? (
127
+ < SpinnerIcon />
128
+ ) : (
129
+ < ClockIcon theme = { theme } />
130
+ ) }
131
+ </ div >
132
+
133
+ { /* Step Content */ }
134
+ < div className = "flex-1 min-w-0" >
135
+ < div className = { `font-semibold transition-all duration-300 text-sm ${
136
+ isCompleted
137
+ ? theme === "dark" ? "text-green-300" : "text-green-700"
138
+ : isCurrentPending
139
+ ? theme === "dark" ? "text-blue-300 text-base" : "text-blue-700 text-base"
140
+ : theme === "dark" ? "text-slate-400" : "text-gray-500"
141
+ } `} >
142
+ { step . description }
143
+ </ div >
144
+ { isCurrentPending && (
145
+ < div className = { `text-sm mt-1 animate-pulse ${
146
+ theme === "dark" ? "text-blue-400" : "text-blue-600"
147
+ } `} >
148
+ Processing...
149
+ </ div >
150
+ ) }
151
+ </ div >
152
+
153
+ { /* Animated Background for Current Step */ }
154
+ { isCurrentPending && (
155
+ < div className = { `absolute inset-0 rounded-lg bg-gradient-to-r animate-pulse ${
156
+ theme === "dark"
157
+ ? "from-blue-500/10 to-purple-500/10"
158
+ : "from-blue-100/50 to-purple-100/50"
159
+ } `} />
160
+ ) }
68
161
</ div >
69
162
) ;
70
- }
71
- } ) }
163
+ } ) }
164
+ </ div >
165
+
166
+ { /* Decorative Elements */ }
167
+ < div className = { `absolute top-3 right-3 w-16 h-16 rounded-full blur-xl ${
168
+ theme === "dark"
169
+ ? "bg-gradient-to-br from-blue-500/10 to-purple-500/10"
170
+ : "bg-gradient-to-br from-blue-200/30 to-purple-200/30"
171
+ } `} />
172
+ < div className = { `absolute bottom-3 left-3 w-12 h-12 rounded-full blur-xl ${
173
+ theme === "dark"
174
+ ? "bg-gradient-to-br from-green-500/10 to-emerald-500/10"
175
+ : "bg-gradient-to-br from-green-200/30 to-emerald-200/30"
176
+ } `} />
72
177
</ div >
73
178
</ div >
74
179
) ;
@@ -90,10 +195,19 @@ const Chat = () => {
90
195
) ;
91
196
} ;
92
197
93
- function Spinner ( ) {
198
+ // Enhanced Icons
199
+ function CheckIcon ( ) {
200
+ return (
201
+ < svg className = "w-4 h-4 text-white" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
202
+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 3 } d = "M5 13l4 4L19 7" />
203
+ </ svg >
204
+ ) ;
205
+ }
206
+
207
+ function SpinnerIcon ( ) {
94
208
return (
95
209
< svg
96
- className = "mr-2 size-3 animate-spin text-slate-500 "
210
+ className = "w-4 h-4 animate-spin text-white "
97
211
xmlns = "http://www.w3.org/2000/svg"
98
212
fill = "none"
99
213
viewBox = "0 0 24 24"
@@ -105,12 +219,21 @@ function Spinner() {
105
219
r = "10"
106
220
stroke = "currentColor"
107
221
strokeWidth = "4"
108
- > </ circle >
222
+ / >
109
223
< path
110
224
className = "opacity-75"
111
225
fill = "currentColor"
112
226
d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
113
- > </ path >
227
+ />
228
+ </ svg >
229
+ ) ;
230
+ }
231
+
232
+ function ClockIcon ( { theme } : { theme ?: string } ) {
233
+ return (
234
+ < svg className = { `w-3 h-3 ${ theme === "dark" ? "text-slate-400" : "text-gray-600" } ` } fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
235
+ < circle cx = "12" cy = "12" r = "10" strokeWidth = "2" />
236
+ < polyline points = "12,6 12,12 16,14" strokeWidth = "2" />
114
237
</ svg >
115
238
) ;
116
239
}
0 commit comments