|
@@ -2,27 +2,70 @@ import { NavLink, useNavigate } from 'react-router-dom'
|
|
|
import { LayoutDashboard, Bot, Cpu, LogOut, Zap, LibraryBig } from 'lucide-react'
|
|
import { LayoutDashboard, Bot, Cpu, LogOut, Zap, LibraryBig } from 'lucide-react'
|
|
|
import { useAppStore } from '../store/app'
|
|
import { useAppStore } from '../store/app'
|
|
|
import { clsx } from '../lib/clsx'
|
|
import { clsx } from '../lib/clsx'
|
|
|
|
|
+import { useMode, MODE_META, type DeploymentMode } from '../api/mode'
|
|
|
|
|
|
|
|
-const nav = [
|
|
|
|
|
- { to: '/dashboard', label: '仪表盘', icon: LayoutDashboard },
|
|
|
|
|
- { to: '/agents', label: '智能体', icon: Bot },
|
|
|
|
|
- { to: '/knowledge', label: '知识体', icon: LibraryBig },
|
|
|
|
|
- { to: '/settings/providers', label: '模型提供商', icon: Cpu },
|
|
|
|
|
-]
|
|
|
|
|
|
|
+// Nav labels are mode-aware (CR-20260607-001 rev.2 §10.3): desktop users
|
|
|
|
|
+// are scientists, not platform operators, so the wording leans toward
|
|
|
|
|
+// "research workspace" instead of "platform admin". lab/paas keep the
|
|
|
|
|
+// platform vocabulary.
|
|
|
|
|
+function navItems(mode: DeploymentMode) {
|
|
|
|
|
+ const desktop = mode === 'desktop'
|
|
|
|
|
+ return [
|
|
|
|
|
+ { to: '/dashboard', label: desktop ? '今日工作' : '仪表盘', icon: LayoutDashboard },
|
|
|
|
|
+ { to: '/agents', label: '智能体', icon: Bot },
|
|
|
|
|
+ { to: '/knowledge', label: desktop ? '资料库' : '知识体', icon: LibraryBig },
|
|
|
|
|
+ { to: '/settings/providers', label: desktop ? '模型与隐私' : '模型提供商', icon: Cpu },
|
|
|
|
|
+ ]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function ModeChip() {
|
|
|
|
|
+ const { data } = useMode()
|
|
|
|
|
+ const mode = (data?.mode ?? 'desktop') as DeploymentMode
|
|
|
|
|
+ const meta = MODE_META[mode]
|
|
|
|
|
+ const alias = data?.tenant_alias ?? ''
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={clsx(
|
|
|
|
|
+ 'flex items-center gap-1.5 px-2 py-1 rounded-md border text-[11px] font-medium',
|
|
|
|
|
+ meta.chipClass,
|
|
|
|
|
+ )}
|
|
|
|
|
+ title={
|
|
|
|
|
+ mode === 'desktop'
|
|
|
|
|
+ ? '单机模式 — 数据全部保存在本机'
|
|
|
|
|
+ : `${meta.label} 模式${alias ? ` · ${alias}` : ''}`
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ <span>{meta.icon}</span>
|
|
|
|
|
+ <span>{meta.label}</span>
|
|
|
|
|
+ {mode !== 'desktop' && alias && (
|
|
|
|
|
+ <span className="opacity-60 truncate max-w-[90px]">· {alias}</span>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
export default function Sidebar() {
|
|
export default function Sidebar() {
|
|
|
const { clearApiKey } = useAppStore()
|
|
const { clearApiKey } = useAppStore()
|
|
|
const navigate = useNavigate()
|
|
const navigate = useNavigate()
|
|
|
|
|
+ const { data } = useMode()
|
|
|
|
|
+ const mode = (data?.mode ?? 'desktop') as DeploymentMode
|
|
|
|
|
+ const meta = MODE_META[mode]
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<aside className="w-56 bg-gray-900 text-gray-100 flex flex-col shrink-0">
|
|
<aside className="w-56 bg-gray-900 text-gray-100 flex flex-col shrink-0">
|
|
|
- <div className="px-4 py-5 flex items-center gap-2 border-b border-gray-800">
|
|
|
|
|
- <Zap size={18} className="text-indigo-400" />
|
|
|
|
|
- <span className="font-semibold text-sm tracking-tight">LambdAgent PaaS</span>
|
|
|
|
|
|
|
+ <div className="px-4 py-4 border-b border-gray-800 space-y-2.5">
|
|
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
|
|
+ <Zap size={18} className="text-indigo-400 shrink-0" />
|
|
|
|
|
+ <span className="font-semibold text-sm tracking-tight truncate">
|
|
|
|
|
+ {meta.brand}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <ModeChip />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<nav className="flex-1 px-2 py-4 space-y-0.5">
|
|
<nav className="flex-1 px-2 py-4 space-y-0.5">
|
|
|
- {nav.map(({ to, label, icon: Icon }) => (
|
|
|
|
|
|
|
+ {navItems(mode).map(({ to, label, icon: Icon }) => (
|
|
|
<NavLink
|
|
<NavLink
|
|
|
key={to}
|
|
key={to}
|
|
|
to={to}
|
|
to={to}
|
|
@@ -50,7 +93,7 @@ export default function Sidebar() {
|
|
|
className="flex items-center gap-3 px-3 py-2 w-full rounded-lg text-sm text-gray-500 hover:bg-gray-800 hover:text-gray-300 transition-colors"
|
|
className="flex items-center gap-3 px-3 py-2 w-full rounded-lg text-sm text-gray-500 hover:bg-gray-800 hover:text-gray-300 transition-colors"
|
|
|
>
|
|
>
|
|
|
<LogOut size={16} />
|
|
<LogOut size={16} />
|
|
|
- 重新配置
|
|
|
|
|
|
|
+ {mode === 'desktop' ? '切换数据 / 重新配置' : '重新配置'}
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
</aside>
|
|
</aside>
|