AgentSelector.tsx
1 import React, { useState, KeyboardEvent } from 'react'; 2 import { useApp } from '../contexts/AppContext'; 3 import { mockAgents } from '../data/mockData'; 4 import type { Agent } from '../types'; 5 import './AgentSelector.css'; 6 7 const getLevelColor = (level: string): string => { 8 const colors: Record<string, string> = { 9 'Master': '#E6E6FA', 10 'Expert': '#FF6B6B', 11 'Advanced': '#7B68EE', 12 'Autonomous': '#FFD700', 13 'Intermediate': '#888888', 14 'Basic': '#888888' 15 }; 16 return colors[level] || '#888888'; 17 }; 18 19 export const AgentSelector: React.FC = () => { 20 const { agentSelectorVisible, hideAgentSelector, selectAgent, addMessage } = useApp(); 21 const [selectedIndex, setSelectedIndex] = useState(0); 22 23 const handleKeyDown = (e: KeyboardEvent) => { 24 switch (e.key) { 25 case 'Escape': 26 hideAgentSelector(); 27 break; 28 case 'ArrowUp': 29 case 'k': 30 e.preventDefault(); 31 setSelectedIndex(prev => Math.max(0, prev - 1)); 32 break; 33 case 'ArrowDown': 34 case 'j': 35 e.preventDefault(); 36 setSelectedIndex(prev => Math.min(mockAgents.length - 1, prev + 1)); 37 break; 38 case 'Enter': 39 e.preventDefault(); 40 handleSelect(mockAgents[selectedIndex]); 41 break; 42 } 43 }; 44 45 const handleSelect = (agent: Agent) => { 46 selectAgent(agent); 47 addMessage({ 48 role: 'system', 49 content: `Switched to ${agent.name} - ${agent.personality.name}`, 50 timestamp: new Date() 51 }); 52 hideAgentSelector(); 53 }; 54 55 if (!agentSelectorVisible) return null; 56 57 return ( 58 <div 59 className="agent-selector-overlay" 60 onClick={hideAgentSelector} 61 onKeyDown={handleKeyDown} 62 tabIndex={0} 63 > 64 <div className="agent-selector" onClick={(e) => e.stopPropagation()}> 65 <div className="selector-header"> 66 <h2>🤖 Select Spirit Agent</h2> 67 <p className="selector-subtitle"> 68 Choose your specialized agent for the task 69 </p> 70 </div> 71 72 <div className="agent-cards"> 73 {mockAgents.map((agent, idx) => ( 74 <div 75 key={agent.id} 76 className={`agent-card ${idx === selectedIndex ? 'selected' : ''}`} 77 onClick={() => handleSelect(agent)} 78 > 79 <div className="card-header"> 80 <span className="card-icon">{agent.icon}</span> 81 <span className="card-name">{agent.name}</span> 82 <span 83 className="card-level" 84 style={{ background: getLevelColor(agent.level) }} 85 > 86 {agent.level} 87 </span> 88 </div> 89 90 <div className="card-info"> 91 <div className="card-row"> 92 <span className="info-label">ID:</span> 93 <span className="info-value">{agent.id}</span> 94 <span className="info-separator">•</span> 95 <span className="info-label">Type:</span> 96 <span className="info-value">{agent.type}</span> 97 </div> 98 </div> 99 100 <div className="card-personality"> 101 <span className="personality-icon">ðŸ’</span> 102 <span className="personality-text"> 103 "{agent.personality.name}" - {agent.personality.approach} 104 </span> 105 </div> 106 107 <div className="card-traits"> 108 <span className="trait-icon">✨</span> 109 {agent.personality.traits.slice(0, 3).map((trait, i) => ( 110 <span key={i} className="trait-badge">{trait}</span> 111 ))} 112 </div> 113 114 <div className="card-specialties"> 115 <span className="specialty-icon">🎯</span> 116 <span className="specialty-text"> 117 {agent.personality.specialties.slice(0, 2).join(', ')} 118 </span> 119 </div> 120 121 <div className="card-capabilities"> 122 <span className="capability-icon">🔧</span> 123 <span className="capability-text"> 124 {agent.capabilities.length} capabilities 125 </span> 126 </div> 127 </div> 128 ))} 129 </div> 130 131 <div className="selector-footer"> 132 ↑↓/j/k Navigate • ENTER Select • ESC Cancel 133 </div> 134 </div> 135 </div> 136 ); 137 };