File size: 7,163 Bytes
666aab6 a20767f 5d62489 666aab6 a20767f 666aab6 5d62489 a20767f 5d62489 a20767f 660d02b a20767f 666aab6 5d62489 a20767f 5d62489 666aab6 a20767f 666aab6 a20767f 666aab6 a20767f 666aab6 a20767f 666aab6 a20767f 5d62489 a20767f 5d62489 a20767f 5d62489 a20767f 666aab6 a20767f 666aab6 a20767f 5d62489 a20767f 5d62489 a20767f 5d62489 666aab6 a20767f 5d62489 a20767f 5d62489 a20767f 5d62489 a20767f 5d62489 a20767f 666aab6 a20767f 660d02b a20767f 666aab6 a20767f 666aab6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 'use client'
import { useAgentStore } from '@/hooks/useAgentStore'
import {
MessageSquare, ListTodo, Brain, Clock, Plug, Terminal,
Plus, Zap, Code2, Bug, Cpu,
GitBranch, Workflow, Rocket, Palette, Bot, Globe, Folder,
FlaskConical, Eye, Cpu as CpuIcon
} from 'lucide-react'
import type { ActivePanel, AgentName } from '@/hooks/useAgentStore'
const PANELS: { id: ActivePanel; icon: React.ElementType; labelEn: string; labelMy: string; badge?: string }[] = [
{ id: 'timeline', icon: Clock, labelEn: 'Timeline', labelMy: 'α‘αα»αααΊααα¬αΈ' },
{ id: 'tasks', icon: ListTodo, labelEn: 'Tasks', labelMy: 'αα―ααΊαααΊαΈαα»α¬αΈ' },
{ id: 'sandbox', icon: Terminal, labelEn: 'Terminal', labelMy: 'Terminal' },
{ id: 'files', icon: Folder, labelEn: 'Files', labelMy: 'ααα―ααΊαα»α¬αΈ', badge: 'v7' },
{ id: 'browser', icon: Globe, labelEn: 'Browser', labelMy: 'ααα±α¬ααΊαα¬', badge: 'v7' },
{ id: 'memory', icon: Brain, labelEn: 'Memory', labelMy: 'ααΎααΊαα¬ααΊ' },
{ id: 'connectors', icon: Plug, labelEn: 'Connectors', labelMy: 'αα»αααΊαααΊααΎα―' },
{ id: 'ai_router', icon: Cpu, labelEn: 'AI Router', labelMy: 'AI Router', badge: 'v8' },
]
const AGENT_META: Record<string, { icon: React.ElementType; color: string; label: string; isNew?: boolean }> = {
chat: { icon: MessageSquare, color: '#22d3ee', label: 'Chat' },
planner: { icon: Zap, color: '#a78bfa', label: 'Planner' },
coding: { icon: Code2, color: '#34d399', label: 'Coding' },
debug: { icon: Bug, color: '#f87171', label: 'Debug' },
memory: { icon: Brain, color: '#fbbf24', label: 'Memory' },
connector: { icon: Plug, color: '#60a5fa', label: 'Connector' },
deploy: { icon: Rocket, color: '#f472b6', label: 'Deploy' },
workflow: { icon: Workflow, color: '#fb923c', label: 'Workflow' },
sandbox: { icon: Terminal, color: '#4ade80', label: 'Sandbox' },
ui: { icon: Palette, color: '#e879f9', label: 'UI' },
browser: { icon: Globe, color: '#38bdf8', label: 'Browser', isNew: true },
file: { icon: Folder, color: '#fcd34d', label: 'File', isNew: true },
git: { icon: GitBranch, color: '#f97316', label: 'Git', isNew: true },
test: { icon: FlaskConical, color: '#a3e635', label: 'Test', isNew: true },
vision: { icon: Eye, color: '#c084fc', label: 'Vision', isNew: true },
}
export default function Sidebar() {
const { sidebarOpen, activePanel, setActivePanel, locale, messages, clearMessages, agents } = useAgentStore()
if (!sidebarOpen) return null
return (
<aside className="w-52 flex-shrink-0 flex flex-col border-r hidden md:flex"
style={{ background: 'var(--bg-2)', borderColor: 'var(--border)' }}>
{/* New Chat */}
<div className="p-3 border-b" style={{ borderColor: 'var(--border)' }}>
<button onClick={clearMessages}
className="w-full flex items-center gap-2 px-3 py-2 rounded-xl text-sm font-medium transition-all hover:opacity-90 active:scale-95"
style={{ background: 'var(--brand)', color: '#fff' }}>
<Plus size={14} />
{locale === 'my' ? 'α
αα¬αΈααΌα±α¬αα
αΊ' : 'New Chat'}
</button>
</div>
{/* Navigation */}
<nav className="p-2 border-b" style={{ borderColor: 'var(--border)' }}>
<p className="text-[10px] uppercase tracking-wider px-2 mb-1.5"
style={{ color: 'var(--text-muted)' }}>Views</p>
{PANELS.map(({ id, icon: Icon, labelEn, labelMy, badge }) => (
<button key={id} onClick={() => setActivePanel(id)}
className={`w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-lg text-xs font-medium transition-all mb-0.5`}
style={{
background: activePanel === id ? 'var(--brand)' : 'transparent',
color: activePanel === id ? '#fff' : 'var(--text-secondary)',
}}>
<Icon size={13} />
<span className="flex-1 text-left">{locale === 'my' ? labelMy : labelEn}</span>
{badge && (
<span className="text-[8px] px-1 py-0.5 rounded font-bold"
style={{
background: activePanel === id ? 'rgba(255,255,255,0.2)' : 'rgba(99,102,241,0.2)',
color: activePanel === id ? '#fff' : '#a5b4fc',
}}>
{badge}
</span>
)}
</button>
))}
</nav>
{/* Agent Status */}
<div className="p-2 flex-1 overflow-y-auto">
<p className="text-[10px] uppercase tracking-wider px-2 mb-1.5"
style={{ color: 'var(--text-muted)' }}>
Agents ({Object.keys(AGENT_META).length})
</p>
{Object.entries(AGENT_META).map(([name, meta]) => {
const agent = (agents as any)[name]
const Icon = meta.icon
const isActive = agent?.status === 'executing' || agent?.status === 'thinking'
const isComplete = agent?.status === 'complete'
const isError = agent?.status === 'error'
return (
<div key={name}
className="flex items-center gap-2 px-2 py-1 rounded-lg mb-0.5 transition-all"
style={{
background: isActive ? `${meta.color}10` : 'transparent',
border: isActive ? `1px solid ${meta.color}30` : '1px solid transparent',
}}>
<Icon size={11} style={{ color: meta.color, flexShrink: 0 }} />
<span className="text-[11px] flex-1 truncate capitalize"
style={{ color: isActive ? 'var(--text-primary)' : 'var(--text-muted)' }}>
{meta.label}
</span>
{meta.isNew && !isActive && (
<span className="text-[8px] px-1 rounded" style={{ background: 'rgba(99,102,241,0.15)', color: '#a5b4fc' }}>
new
</span>
)}
<div className={`w-1.5 h-1.5 rounded-full flex-shrink-0 ${isActive ? 'animate-pulse' : ''}`}
style={{
background: isActive ? meta.color : isComplete ? '#22c55e' : isError ? '#ef4444' : 'var(--border)',
boxShadow: isActive ? `0 0 6px ${meta.color}` : 'none',
}}
/>
</div>
)
})}
</div>
{/* Footer */}
<div className="p-3 border-t" style={{ borderColor: 'var(--border)' }}>
<div className="flex items-center gap-2 px-2 py-1.5 rounded-lg text-[10px]"
style={{ background: 'rgba(99,102,241,0.08)', border: '1px solid rgba(99,102,241,0.2)' }}>
<Bot size={10} className="text-indigo-400" />
<span style={{ color: 'var(--text-muted)' }}>God Agent OS v8.0</span>
<div className="ml-auto w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse" />
</div>
</div>
</aside>
)
}
|