Spaces:
Running
Running
| import { useState } from 'react'; | |
| const colorMap = { | |
| blue: { bg: 'bg-blue-500/10', border: 'border-blue-500/30', text: 'text-blue-400', glow: 'shadow-blue-500/20' }, | |
| purple: { bg: 'bg-purple-500/10', border: 'border-purple-500/30', text: 'text-purple-400', glow: 'shadow-purple-500/20' }, | |
| indigo: { bg: 'bg-indigo-500/10', border: 'border-indigo-500/30', text: 'text-indigo-400', glow: 'shadow-indigo-500/20' }, | |
| green: { bg: 'bg-green-500/10', border: 'border-green-500/30', text: 'text-green-400', glow: 'shadow-green-500/20' }, | |
| pink: { bg: 'bg-pink-500/10', border: 'border-pink-500/30', text: 'text-pink-400', glow: 'shadow-pink-500/20' }, | |
| orange: { bg: 'bg-orange-500/10', border: 'border-orange-500/30', text: 'text-orange-400', glow: 'shadow-orange-500/20' }, | |
| yellow: { bg: 'bg-yellow-500/10', border: 'border-yellow-500/30', text: 'text-yellow-400', glow: 'shadow-yellow-500/20' }, | |
| cyan: { bg: 'bg-cyan-500/10', border: 'border-cyan-500/30', text: 'text-cyan-400', glow: 'shadow-cyan-500/20' }, | |
| red: { bg: 'bg-red-500/10', border: 'border-red-500/30', text: 'text-red-400', glow: 'shadow-red-500/20' }, | |
| teal: { bg: 'bg-teal-500/10', border: 'border-teal-500/30', text: 'text-teal-400', glow: 'shadow-teal-500/20' }, | |
| violet: { bg: 'bg-violet-500/10', border: 'border-violet-500/30', text: 'text-violet-400', glow: 'shadow-violet-500/20' }, | |
| }; | |
| const statusConfig = { | |
| idle: { label: 'Idle', dot: 'bg-gray-600', bg: 'bg-gray-500/5' }, | |
| active: { label: 'Active', dot: 'bg-yellow-500 animate-pulse', bg: '' }, | |
| done: { label: 'Done', dot: 'bg-green-500', bg: '' }, | |
| failed: { label: 'Failed', dot: 'bg-red-500', bg: '' }, | |
| }; | |
| export default function AgentGrid({ agents, statuses, currentPhase }) { | |
| const [selectedAgent, setSelectedAgent] = useState(null); | |
| const phaseNames = ['Planning', 'Execution', 'Validation', 'Documentation', 'Learning']; | |
| return ( | |
| <div className="space-y-6"> | |
| {/* Phase Indicator */} | |
| {currentPhase >= 0 && ( | |
| <div className="glass-card p-4 animate-slide-up"> | |
| <div className="flex items-center gap-3 mb-3"> | |
| <div className="w-2 h-2 rounded-full bg-indigo-500 animate-pulse" /> | |
| <span className="text-sm font-medium text-indigo-400"> | |
| Current Phase: {phaseNames[currentPhase] || 'Unknown'} | |
| </span> | |
| </div> | |
| <div className="flex gap-2"> | |
| {phaseNames.map((name, i) => ( | |
| <div | |
| key={name} | |
| className={`flex-1 h-1.5 rounded-full transition-all duration-500 ${ | |
| i < currentPhase ? 'bg-green-500' : | |
| i === currentPhase ? 'bg-indigo-500 animate-pulse' : | |
| 'bg-gray-800' | |
| }`} | |
| /> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| {/* Agent Grid */} | |
| <div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4"> | |
| {agents.map((agent, index) => { | |
| const colors = colorMap[agent.color]; | |
| const status = statuses[agent.id] || 'idle'; | |
| const statusInfo = statusConfig[status]; | |
| const isSelected = selectedAgent === agent.id; | |
| return ( | |
| <div | |
| key={agent.id} | |
| onClick={() => setSelectedAgent(isSelected ? null : agent.id)} | |
| className={`agent-card cursor-pointer animate-slide-up ${ | |
| status === 'active' ? `${colors.bg} ${colors.border} shadow-lg ${colors.glow}` : | |
| status === 'done' ? 'border-green-500/20' : | |
| '' | |
| }`} | |
| style={{ animationDelay: `${index * 50}ms` }} | |
| > | |
| <div className="flex items-start gap-3"> | |
| <div className={`w-10 h-10 rounded-xl ${colors.bg} flex items-center justify-center text-lg flex-shrink-0`}> | |
| {agent.icon} | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <div className="flex items-center justify-between gap-2"> | |
| <h3 className={`text-sm font-semibold ${colors.text} truncate`}>{agent.name}</h3> | |
| <div className="flex items-center gap-1.5 flex-shrink-0"> | |
| <div className={`status-dot ${statusInfo.dot}`} /> | |
| <span className="text-xs text-gray-500">{statusInfo.label}</span> | |
| </div> | |
| </div> | |
| <p className="text-xs text-gray-500 mt-1 line-clamp-2">{agent.description}</p> | |
| </div> | |
| </div> | |
| {isSelected && ( | |
| <div className="mt-3 pt-3 border-t border-gray-800/50 animate-slide-up"> | |
| <div className="space-y-2"> | |
| <div className="flex items-center gap-2"> | |
| <span className="text-xs text-gray-500">Agent ID:</span> | |
| <code className="text-xs text-gray-300 bg-gray-800/50 px-1.5 py-0.5 rounded">{agent.id}</code> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <span className="text-xs text-gray-500">Status:</span> | |
| <span className={`text-xs font-medium ${status === 'done' ? 'text-green-400' : status === 'active' ? 'text-yellow-400' : 'text-gray-400'}`}> | |
| {status.toUpperCase()} | |
| </span> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <span className="text-xs text-gray-500">Phase:</span> | |
| <span className="text-xs text-gray-300"> | |
| {currentPhase >= 0 ? phaseNames[currentPhase] : 'Waiting'} | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| ); | |
| } |