claude-team-dashboard 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-team-dashboard might be problematic. Click here for more details.
- package/CHANGELOG.md +76 -0
- package/LICENSE +21 -0
- package/README.md +722 -0
- package/cleanup.js +73 -0
- package/config.js +50 -0
- package/dist/assets/icons-Ijf8rQIc.js +1 -0
- package/dist/assets/index-Cqc1m1x_.css +1 -0
- package/dist/assets/index-jGy3ms0W.js +9 -0
- package/dist/assets/react-vendor-DbmSkCAF.js +1 -0
- package/dist/index.html +16 -0
- package/index.html +13 -0
- package/package.json +93 -0
- package/server.js +953 -0
- package/src/App.jsx +372 -0
- package/src/animations-enhanced.css +929 -0
- package/src/animations.css +783 -0
- package/src/components/ActivityFeed.jsx +289 -0
- package/src/components/AgentActivity.jsx +104 -0
- package/src/components/AgentCard.jsx +163 -0
- package/src/components/AgentOutputViewer.jsx +334 -0
- package/src/components/ArchiveViewer.jsx +283 -0
- package/src/components/ConnectionStatus.jsx +124 -0
- package/src/components/DetailedTaskProgress.jsx +126 -0
- package/src/components/ErrorBoundary.jsx +132 -0
- package/src/components/Header.jsx +154 -0
- package/src/components/LiveAgentStream.jsx +176 -0
- package/src/components/LiveCommunication.jsx +326 -0
- package/src/components/LiveMetrics.jsx +100 -0
- package/src/components/RealTimeMessages.jsx +298 -0
- package/src/components/SkeletonLoader.jsx +384 -0
- package/src/components/StatsOverview.jsx +209 -0
- package/src/components/SystemStatus.jsx +57 -0
- package/src/components/TaskList.jsx +306 -0
- package/src/components/TeamCard.jsx +126 -0
- package/src/components/TeamHistory.jsx +204 -0
- package/src/components/__tests__/ConnectionStatus.test.jsx +54 -0
- package/src/components/__tests__/StatsOverview.test.jsx +66 -0
- package/src/config/constants.js +59 -0
- package/src/hooks/useCounterAnimation.js +219 -0
- package/src/hooks/useWebSocket.js +76 -0
- package/src/index.css +1818 -0
- package/src/main.jsx +17 -0
- package/src/polish-enhancements.css +303 -0
- package/src/premium-visual-polish.css +830 -0
- package/src/responsive-enhancements.css +666 -0
- package/src/styles/theme.css +395 -0
- package/src/test/setup.js +19 -0
- package/start.js +36 -0
- package/vite.config.js +37 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Activity, Circle, Users, ListTodo, CheckCircle2 } from 'lucide-react';
|
|
4
|
+
import dayjs from 'dayjs';
|
|
5
|
+
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
6
|
+
dayjs.extend(relativeTime);
|
|
7
|
+
|
|
8
|
+
export function ActivityFeed({ updates }) {
|
|
9
|
+
const [activities, setActivities] = useState([]);
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (updates) {
|
|
13
|
+
const newActivity = {
|
|
14
|
+
id: Date.now(),
|
|
15
|
+
type: updates.type,
|
|
16
|
+
timestamp: new Date().toISOString(),
|
|
17
|
+
message: getActivityMessage(updates)
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
setActivities(prev => [newActivity, ...prev].slice(0, 50));
|
|
21
|
+
}
|
|
22
|
+
}, [updates]);
|
|
23
|
+
|
|
24
|
+
const getActivityMessage = (update) => {
|
|
25
|
+
switch (update.type) {
|
|
26
|
+
case 'initial_data':
|
|
27
|
+
return `Connected to dashboard - ${update.data?.length || 0} teams loaded`;
|
|
28
|
+
case 'teams_update':
|
|
29
|
+
return 'Team configuration updated';
|
|
30
|
+
case 'task_update':
|
|
31
|
+
return 'Task status changed';
|
|
32
|
+
default:
|
|
33
|
+
return 'System event';
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getActivityConfig = (type) => {
|
|
38
|
+
switch (type) {
|
|
39
|
+
case 'initial_data':
|
|
40
|
+
return {
|
|
41
|
+
icon: CheckCircle2,
|
|
42
|
+
color: '#4ade80',
|
|
43
|
+
bgGradient: 'linear-gradient(135deg, rgba(34, 197, 94, 0.25) 0%, rgba(21, 128, 61, 0.15) 100%)',
|
|
44
|
+
glowColor: 'rgba(34, 197, 94, 0.4)',
|
|
45
|
+
borderColor: 'rgba(34, 197, 94, 0.3)'
|
|
46
|
+
};
|
|
47
|
+
case 'teams_update':
|
|
48
|
+
return {
|
|
49
|
+
icon: Users,
|
|
50
|
+
color: '#60a5fa',
|
|
51
|
+
bgGradient: 'linear-gradient(135deg, rgba(59, 130, 246, 0.25) 0%, rgba(37, 99, 235, 0.15) 100%)',
|
|
52
|
+
glowColor: 'rgba(59, 130, 246, 0.4)',
|
|
53
|
+
borderColor: 'rgba(59, 130, 246, 0.3)'
|
|
54
|
+
};
|
|
55
|
+
case 'task_update':
|
|
56
|
+
return {
|
|
57
|
+
icon: ListTodo,
|
|
58
|
+
color: '#c084fc',
|
|
59
|
+
bgGradient: 'linear-gradient(135deg, rgba(168, 85, 247, 0.25) 0%, rgba(147, 51, 234, 0.15) 100%)',
|
|
60
|
+
glowColor: 'rgba(168, 85, 247, 0.4)',
|
|
61
|
+
borderColor: 'rgba(168, 85, 247, 0.3)'
|
|
62
|
+
};
|
|
63
|
+
default:
|
|
64
|
+
return {
|
|
65
|
+
icon: Activity,
|
|
66
|
+
color: '#9ca3af',
|
|
67
|
+
bgGradient: 'rgba(55, 65, 81, 0.3)',
|
|
68
|
+
glowColor: 'rgba(75, 85, 99, 0.3)',
|
|
69
|
+
borderColor: 'rgba(75, 85, 99, 0.3)'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
className="rounded-2xl p-6"
|
|
77
|
+
style={{
|
|
78
|
+
background: 'linear-gradient(135deg, rgba(30, 41, 59, 0.95) 0%, rgba(15, 23, 42, 0.9) 100%)',
|
|
79
|
+
border: '1px solid rgba(249, 115, 22, 0.15)',
|
|
80
|
+
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.05)',
|
|
81
|
+
backdropFilter: 'blur(16px)'
|
|
82
|
+
}}
|
|
83
|
+
>
|
|
84
|
+
{/* Header */}
|
|
85
|
+
<div className="flex items-center justify-between mb-6">
|
|
86
|
+
<div className="flex items-center gap-3">
|
|
87
|
+
<div
|
|
88
|
+
className="p-2.5 rounded-xl"
|
|
89
|
+
style={{
|
|
90
|
+
background: 'linear-gradient(135deg, rgba(249, 115, 22, 0.25) 0%, rgba(251, 146, 60, 0.15) 100%)',
|
|
91
|
+
boxShadow: '0 4px 12px rgba(249, 115, 22, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1)',
|
|
92
|
+
border: '1px solid rgba(249, 115, 22, 0.3)'
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<Activity
|
|
96
|
+
className="h-5 w-5"
|
|
97
|
+
style={{
|
|
98
|
+
color: '#fb923c',
|
|
99
|
+
filter: 'drop-shadow(0 0 8px rgba(249, 115, 22, 0.5))'
|
|
100
|
+
}}
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
<h3
|
|
104
|
+
className="text-lg font-bold"
|
|
105
|
+
style={{
|
|
106
|
+
color: '#ffffff',
|
|
107
|
+
letterSpacing: '-0.01em',
|
|
108
|
+
textShadow: '0 1px 2px rgba(0, 0, 0, 0.3)'
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
Activity Feed
|
|
112
|
+
</h3>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
{/* Event Counter */}
|
|
116
|
+
<span
|
|
117
|
+
className="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold"
|
|
118
|
+
style={{
|
|
119
|
+
background: 'rgba(59, 130, 246, 0.15)',
|
|
120
|
+
color: '#93c5fd',
|
|
121
|
+
border: '1px solid rgba(59, 130, 246, 0.3)'
|
|
122
|
+
}}
|
|
123
|
+
>
|
|
124
|
+
{activities.length} events
|
|
125
|
+
</span>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
{/* Timeline Container */}
|
|
129
|
+
<div
|
|
130
|
+
className="max-h-96 overflow-y-auto pr-2"
|
|
131
|
+
style={{
|
|
132
|
+
scrollbarWidth: 'thin'
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
{activities.length === 0 ? (
|
|
136
|
+
<div
|
|
137
|
+
className="text-center py-12 rounded-xl"
|
|
138
|
+
style={{
|
|
139
|
+
background: 'rgba(30, 41, 59, 0.5)',
|
|
140
|
+
border: '1px dashed rgba(156, 163, 175, 0.2)'
|
|
141
|
+
}}
|
|
142
|
+
>
|
|
143
|
+
<Activity className="h-12 w-12 text-gray-600 mx-auto mb-3 opacity-50" />
|
|
144
|
+
<p className="text-gray-400 text-sm">No activity yet</p>
|
|
145
|
+
<p className="text-gray-500 text-xs mt-1">Events will appear here in real-time</p>
|
|
146
|
+
</div>
|
|
147
|
+
) : (
|
|
148
|
+
<div className="relative">
|
|
149
|
+
{/* Timeline Line */}
|
|
150
|
+
<div
|
|
151
|
+
className="absolute left-5 top-0 bottom-0 w-0.5"
|
|
152
|
+
style={{
|
|
153
|
+
background: 'linear-gradient(180deg, rgba(249, 115, 22, 0.3) 0%, rgba(249, 115, 22, 0.1) 100%)'
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
|
|
157
|
+
<div className="space-y-4">
|
|
158
|
+
{activities.map((activity, index) => {
|
|
159
|
+
const config = getActivityConfig(activity.type);
|
|
160
|
+
const Icon = config.icon;
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<div
|
|
164
|
+
key={activity.id}
|
|
165
|
+
className="relative pl-14 group"
|
|
166
|
+
style={{
|
|
167
|
+
animation: 'slideInRight 0.4s cubic-bezier(0.4, 0.0, 0.2, 1)',
|
|
168
|
+
animationDelay: `${index * 60}ms`,
|
|
169
|
+
animationFillMode: 'both'
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
172
|
+
{/* Timeline Node */}
|
|
173
|
+
<div
|
|
174
|
+
className="absolute left-0 top-1 p-2 rounded-xl transition-all duration-300"
|
|
175
|
+
style={{
|
|
176
|
+
background: config.bgGradient,
|
|
177
|
+
border: `2px solid ${config.borderColor}`,
|
|
178
|
+
boxShadow: `0 4px 12px ${config.glowColor}, inset 0 1px 0 rgba(255, 255, 255, 0.1)`,
|
|
179
|
+
zIndex: 10
|
|
180
|
+
}}
|
|
181
|
+
>
|
|
182
|
+
<Icon
|
|
183
|
+
className="h-5 w-5"
|
|
184
|
+
style={{
|
|
185
|
+
color: config.color,
|
|
186
|
+
filter: `drop-shadow(0 0 6px ${config.glowColor})`
|
|
187
|
+
}}
|
|
188
|
+
/>
|
|
189
|
+
|
|
190
|
+
{/* Pulsing Ring */}
|
|
191
|
+
{index === 0 && (
|
|
192
|
+
<div
|
|
193
|
+
className="absolute inset-0 rounded-xl animate-ping"
|
|
194
|
+
style={{
|
|
195
|
+
background: config.bgGradient,
|
|
196
|
+
opacity: 0.4
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
)}
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
{/* Activity Card */}
|
|
203
|
+
<div
|
|
204
|
+
className="rounded-xl p-4 transition-all duration-300"
|
|
205
|
+
style={{
|
|
206
|
+
background: 'linear-gradient(135deg, rgba(30, 41, 59, 0.6) 0%, rgba(15, 23, 42, 0.5) 100%)',
|
|
207
|
+
border: '1px solid rgba(75, 85, 99, 0.3)',
|
|
208
|
+
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05)'
|
|
209
|
+
}}
|
|
210
|
+
onMouseEnter={(e) => {
|
|
211
|
+
e.currentTarget.style.borderColor = config.borderColor;
|
|
212
|
+
e.currentTarget.style.boxShadow = `0 4px 16px ${config.glowColor}, inset 0 1px 0 rgba(255, 255, 255, 0.08)`;
|
|
213
|
+
e.currentTarget.style.transform = 'translateY(-2px)';
|
|
214
|
+
}}
|
|
215
|
+
onMouseLeave={(e) => {
|
|
216
|
+
e.currentTarget.style.borderColor = 'rgba(75, 85, 99, 0.3)';
|
|
217
|
+
e.currentTarget.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05)';
|
|
218
|
+
e.currentTarget.style.transform = 'translateY(0)';
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
<p
|
|
222
|
+
className="text-sm font-medium mb-1.5"
|
|
223
|
+
style={{
|
|
224
|
+
color: 'rgba(255, 255, 255, 0.95)',
|
|
225
|
+
letterSpacing: '-0.01em'
|
|
226
|
+
}}
|
|
227
|
+
>
|
|
228
|
+
{activity.message}
|
|
229
|
+
</p>
|
|
230
|
+
|
|
231
|
+
<div className="flex items-center gap-2">
|
|
232
|
+
<Circle
|
|
233
|
+
className="h-1.5 w-1.5"
|
|
234
|
+
style={{
|
|
235
|
+
color: config.color,
|
|
236
|
+
fill: config.color
|
|
237
|
+
}}
|
|
238
|
+
/>
|
|
239
|
+
<p
|
|
240
|
+
className="text-xs"
|
|
241
|
+
style={{
|
|
242
|
+
color: 'rgba(156, 163, 175, 0.8)'
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
{dayjs(activity.timestamp).fromNow()}
|
|
246
|
+
</p>
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
{/* Live indicator for latest activity */}
|
|
250
|
+
{index === 0 && (
|
|
251
|
+
<div className="absolute top-4 right-4">
|
|
252
|
+
<span
|
|
253
|
+
className="inline-flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-semibold"
|
|
254
|
+
style={{
|
|
255
|
+
background: 'rgba(34, 197, 94, 0.15)',
|
|
256
|
+
color: '#4ade80',
|
|
257
|
+
border: '1px solid rgba(34, 197, 94, 0.3)'
|
|
258
|
+
}}
|
|
259
|
+
>
|
|
260
|
+
<span
|
|
261
|
+
className="h-1.5 w-1.5 rounded-full animate-pulse"
|
|
262
|
+
style={{
|
|
263
|
+
background: '#4ade80',
|
|
264
|
+
boxShadow: '0 0 8px rgba(34, 197, 94, 0.6)'
|
|
265
|
+
}}
|
|
266
|
+
/>
|
|
267
|
+
LIVE
|
|
268
|
+
</span>
|
|
269
|
+
</div>
|
|
270
|
+
)}
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
);
|
|
274
|
+
})}
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
)}
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
ActivityFeed.propTypes = {
|
|
284
|
+
updates: PropTypes.shape({
|
|
285
|
+
type: PropTypes.string,
|
|
286
|
+
data: PropTypes.array,
|
|
287
|
+
stats: PropTypes.object
|
|
288
|
+
})
|
|
289
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { Users, Zap, Brain, CheckSquare } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
export function AgentActivity({ teams }) {
|
|
5
|
+
const [activeAgents, setActiveAgents] = useState([]);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (teams && teams.length > 0) {
|
|
9
|
+
const agents = [];
|
|
10
|
+
teams.forEach(team => {
|
|
11
|
+
if (team.config && team.config.members) {
|
|
12
|
+
team.config.members.forEach(member => {
|
|
13
|
+
const agentTasks = team.tasks?.filter(t =>
|
|
14
|
+
t.owner === member.name && t.status === 'in_progress'
|
|
15
|
+
) || [];
|
|
16
|
+
|
|
17
|
+
agents.push({
|
|
18
|
+
name: member.name,
|
|
19
|
+
team: team.name,
|
|
20
|
+
agentType: member.agentType,
|
|
21
|
+
activeTasks: agentTasks.length,
|
|
22
|
+
currentTask: agentTasks[0]?.subject || 'Idle',
|
|
23
|
+
color: getAgentColor(member.name)
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
setActiveAgents(agents.slice(0, 10)); // Show top 10
|
|
29
|
+
}
|
|
30
|
+
}, [teams]);
|
|
31
|
+
|
|
32
|
+
const getAgentColor = (name) => {
|
|
33
|
+
const colors = [
|
|
34
|
+
'#60a5fa', '#34d399', '#fbbf24', '#f87171',
|
|
35
|
+
'#c084fc', '#22d3ee', '#fb923c', '#a78bfa'
|
|
36
|
+
];
|
|
37
|
+
const hash = name.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
38
|
+
return colors[hash % colors.length];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div className="card">
|
|
43
|
+
<div className="flex items-center justify-between mb-4">
|
|
44
|
+
<div className="flex items-center gap-2">
|
|
45
|
+
<Users className="h-5 w-5 text-claude-orange" />
|
|
46
|
+
<h3 className="text-lg font-semibold text-white">Agent Activity</h3>
|
|
47
|
+
</div>
|
|
48
|
+
<span className="text-sm text-gray-400">{activeAgents.length} agents</span>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div className="space-y-2 max-h-96 overflow-y-auto">
|
|
52
|
+
{activeAgents.length === 0 ? (
|
|
53
|
+
<div className="text-center py-8 text-gray-400">
|
|
54
|
+
<Users className="h-12 w-12 mx-auto mb-2 opacity-50" />
|
|
55
|
+
<p className="text-sm">No active agents</p>
|
|
56
|
+
</div>
|
|
57
|
+
) : (
|
|
58
|
+
activeAgents.map((agent, index) => (
|
|
59
|
+
<div
|
|
60
|
+
key={`${agent.team}-${agent.name}-${index}`}
|
|
61
|
+
className="p-3 rounded-lg bg-gray-700/50 border border-gray-600 hover:border-claude-orange transition-all"
|
|
62
|
+
>
|
|
63
|
+
<div className="flex items-start gap-3">
|
|
64
|
+
<div
|
|
65
|
+
className="p-2 rounded-lg"
|
|
66
|
+
style={{ backgroundColor: `${agent.color}20` }}
|
|
67
|
+
>
|
|
68
|
+
<Brain className="h-4 w-4" style={{ color: agent.color }} />
|
|
69
|
+
</div>
|
|
70
|
+
<div className="flex-1 min-w-0">
|
|
71
|
+
<div className="flex items-center justify-between mb-1">
|
|
72
|
+
<span className="text-sm font-semibold text-white truncate">
|
|
73
|
+
{agent.name}
|
|
74
|
+
</span>
|
|
75
|
+
{agent.activeTasks > 0 && (
|
|
76
|
+
<span className="flex items-center gap-1 text-xs text-green-400">
|
|
77
|
+
<Zap className="h-3 w-3" />
|
|
78
|
+
Active
|
|
79
|
+
</span>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
82
|
+
<div className="text-xs text-gray-400 mb-1">{agent.agentType}</div>
|
|
83
|
+
<div className="flex items-center gap-1 text-xs text-gray-500">
|
|
84
|
+
<CheckSquare className="h-3 w-3" />
|
|
85
|
+
<span className="truncate">{agent.currentTask}</span>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
<div className="text-right">
|
|
89
|
+
<div
|
|
90
|
+
className="text-lg font-bold"
|
|
91
|
+
style={{ color: agent.color }}
|
|
92
|
+
>
|
|
93
|
+
{agent.activeTasks}
|
|
94
|
+
</div>
|
|
95
|
+
<div className="text-xs text-gray-400">tasks</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
))
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Bot, Crown, Cpu, Zap } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
export function AgentCard({ agent, isLead }) {
|
|
6
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
className="relative group rounded-2xl p-5 transition-all duration-300"
|
|
11
|
+
style={{
|
|
12
|
+
background: isLead
|
|
13
|
+
? 'linear-gradient(135deg, rgba(234, 179, 8, 0.12) 0%, rgba(202, 138, 4, 0.08) 100%)'
|
|
14
|
+
: 'linear-gradient(135deg, rgba(59, 130, 246, 0.12) 0%, rgba(37, 99, 235, 0.08) 100%)',
|
|
15
|
+
border: `2px solid ${isLead ? 'rgba(234, 179, 8, 0.3)' : 'rgba(59, 130, 246, 0.25)'}`,
|
|
16
|
+
boxShadow: isHovered
|
|
17
|
+
? `0 8px 24px ${isLead ? 'rgba(234, 179, 8, 0.25)' : 'rgba(59, 130, 246, 0.2)'}, inset 0 1px 0 rgba(255, 255, 255, 0.1)`
|
|
18
|
+
: '0 4px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.05)',
|
|
19
|
+
transform: isHovered ? 'translateY(-4px) scale(1.02)' : 'translateY(0) scale(1)',
|
|
20
|
+
}}
|
|
21
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
22
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
23
|
+
>
|
|
24
|
+
{/* Gradient Border Animation */}
|
|
25
|
+
<div
|
|
26
|
+
className="absolute inset-0 rounded-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-500"
|
|
27
|
+
style={{
|
|
28
|
+
background: isLead
|
|
29
|
+
? 'linear-gradient(135deg, rgba(234, 179, 8, 0.2), transparent 50%, rgba(234, 179, 8, 0.1))'
|
|
30
|
+
: 'linear-gradient(135deg, rgba(59, 130, 246, 0.2), transparent 50%, rgba(59, 130, 246, 0.1))',
|
|
31
|
+
pointerEvents: 'none'
|
|
32
|
+
}}
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
<div className="flex items-start justify-between relative z-10">
|
|
36
|
+
<div className="flex items-start gap-4 flex-1">
|
|
37
|
+
{/* Icon Container with Glow */}
|
|
38
|
+
<div
|
|
39
|
+
className="relative p-3 rounded-xl transition-all duration-300"
|
|
40
|
+
style={{
|
|
41
|
+
background: isLead
|
|
42
|
+
? 'linear-gradient(135deg, rgba(234, 179, 8, 0.25) 0%, rgba(202, 138, 4, 0.15) 100%)'
|
|
43
|
+
: 'linear-gradient(135deg, rgba(59, 130, 246, 0.25) 0%, rgba(37, 99, 235, 0.15) 100%)',
|
|
44
|
+
boxShadow: isHovered
|
|
45
|
+
? `0 4px 16px ${isLead ? 'rgba(234, 179, 8, 0.4)' : 'rgba(59, 130, 246, 0.35)'}, inset 0 1px 0 rgba(255, 255, 255, 0.15)`
|
|
46
|
+
: `0 2px 8px ${isLead ? 'rgba(234, 179, 8, 0.3)' : 'rgba(59, 130, 246, 0.25)'}, inset 0 1px 0 rgba(255, 255, 255, 0.1)`,
|
|
47
|
+
border: `1px solid ${isLead ? 'rgba(234, 179, 8, 0.4)' : 'rgba(59, 130, 246, 0.35)'}`,
|
|
48
|
+
transform: isHovered ? 'scale(1.1) rotate(-5deg)' : 'scale(1) rotate(0deg)'
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
{isLead ? (
|
|
52
|
+
<Crown
|
|
53
|
+
className="h-6 w-6"
|
|
54
|
+
style={{
|
|
55
|
+
color: '#facc15',
|
|
56
|
+
filter: 'drop-shadow(0 0 8px rgba(234, 179, 8, 0.6))'
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
) : (
|
|
60
|
+
<Bot
|
|
61
|
+
className="h-6 w-6"
|
|
62
|
+
style={{
|
|
63
|
+
color: '#60a5fa',
|
|
64
|
+
filter: 'drop-shadow(0 0 8px rgba(59, 130, 246, 0.5))'
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
)}
|
|
68
|
+
|
|
69
|
+
{/* Pulsing Glow Effect */}
|
|
70
|
+
{isHovered && (
|
|
71
|
+
<div
|
|
72
|
+
className="absolute inset-0 rounded-xl animate-pulse"
|
|
73
|
+
style={{
|
|
74
|
+
background: isLead
|
|
75
|
+
? 'radial-gradient(circle, rgba(234, 179, 8, 0.3), transparent 70%)'
|
|
76
|
+
: 'radial-gradient(circle, rgba(59, 130, 246, 0.3), transparent 70%)',
|
|
77
|
+
zIndex: -1
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{/* Agent Details */}
|
|
84
|
+
<div className="flex-1 min-w-0">
|
|
85
|
+
<div className="flex items-center gap-2 mb-2">
|
|
86
|
+
<h5
|
|
87
|
+
className="text-white font-bold text-lg truncate"
|
|
88
|
+
style={{
|
|
89
|
+
letterSpacing: '-0.01em',
|
|
90
|
+
textShadow: '0 1px 2px rgba(0, 0, 0, 0.3)'
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
{agent.name}
|
|
94
|
+
</h5>
|
|
95
|
+
|
|
96
|
+
{isLead && (
|
|
97
|
+
<span
|
|
98
|
+
className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-semibold uppercase tracking-wider"
|
|
99
|
+
style={{
|
|
100
|
+
background: 'linear-gradient(135deg, rgba(234, 179, 8, 0.3) 0%, rgba(202, 138, 4, 0.2) 100%)',
|
|
101
|
+
color: '#facc15',
|
|
102
|
+
border: '1px solid rgba(234, 179, 8, 0.5)',
|
|
103
|
+
boxShadow: '0 2px 8px rgba(234, 179, 8, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.15)',
|
|
104
|
+
textShadow: '0 0 10px rgba(234, 179, 8, 0.4)'
|
|
105
|
+
}}
|
|
106
|
+
>
|
|
107
|
+
<Zap className="h-3 w-3" />
|
|
108
|
+
Lead
|
|
109
|
+
</span>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
{agent.agentType && (
|
|
114
|
+
<div
|
|
115
|
+
className="flex items-center gap-2 mb-2 px-2.5 py-1 rounded-lg inline-flex"
|
|
116
|
+
style={{
|
|
117
|
+
background: 'rgba(55, 65, 81, 0.4)',
|
|
118
|
+
border: '1px solid rgba(75, 85, 99, 0.3)'
|
|
119
|
+
}}
|
|
120
|
+
>
|
|
121
|
+
<Cpu className="h-4 w-4 text-gray-400" />
|
|
122
|
+
<span className="text-sm text-gray-300 truncate font-medium">
|
|
123
|
+
{agent.agentType}
|
|
124
|
+
</span>
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
127
|
+
|
|
128
|
+
<p
|
|
129
|
+
className="text-xs font-mono truncate"
|
|
130
|
+
style={{
|
|
131
|
+
color: 'rgba(156, 163, 175, 0.8)'
|
|
132
|
+
}}
|
|
133
|
+
title={agent.agentId}
|
|
134
|
+
>
|
|
135
|
+
ID: {agent.agentId?.substring(0, 12)}...
|
|
136
|
+
</p>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
{/* Shine Effect on Hover */}
|
|
142
|
+
{isHovered && (
|
|
143
|
+
<div
|
|
144
|
+
className="absolute inset-0 rounded-2xl pointer-events-none"
|
|
145
|
+
style={{
|
|
146
|
+
background: 'linear-gradient(135deg, transparent 0%, rgba(255, 255, 255, 0.05) 50%, transparent 100%)',
|
|
147
|
+
animation: 'shimmer 2s ease-in-out infinite'
|
|
148
|
+
}}
|
|
149
|
+
/>
|
|
150
|
+
)}
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
AgentCard.propTypes = {
|
|
156
|
+
agent: PropTypes.shape({
|
|
157
|
+
name: PropTypes.string.isRequired,
|
|
158
|
+
agentId: PropTypes.string.isRequired,
|
|
159
|
+
agentType: PropTypes.string,
|
|
160
|
+
model: PropTypes.string
|
|
161
|
+
}).isRequired,
|
|
162
|
+
isLead: PropTypes.bool
|
|
163
|
+
};
|