File size: 5,220 Bytes
55847d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import {
  FolderOpen, BookOpen, Users,
  Home, Zap, ScrollText, Cpu,
} from 'lucide-react'
import { useLayoutStore, type SidebarView, type BottomTab } from '../../stores/layout-store'
import { useWorkflowStore } from '../../stores/workflow-store'
import { useTranslation } from 'react-i18next'

/** 左侧侧边栏视图按钮配置(不含 Home,它单独渲染) */
// Note: These arrays are now inside the component to support i18n

/**
 * 左侧工具窗口栏(LeftToolWindowBar)
 * JetBrains 风格:36px 宽,全高
 */
export default function LeftToolWindowBar() {
  const { t } = useTranslation('layout')
  const sidebarView = useLayoutStore(s => s.sidebarView)
  const sidebarOpen = useLayoutStore(s => s.sidebarOpen)
  const setSidebarView = useLayoutStore(s => s.setSidebarView)
  const bottomTab = useLayoutStore(s => s.bottomTab)
  const bottomPanelOpen = useLayoutStore(s => s.bottomPanelOpen)
  const setBottomTab = useLayoutStore(s => s.setBottomTab)
  const currentRun = useWorkflowStore(s => s.currentRun)

  // Side bar activities (Home excluded - rendered separately)
  const sidebarActivities: Array<{ id: SidebarView; icon: typeof FolderOpen; label: string }> = [
    { id: 'project', icon: FolderOpen, label: t('activityBar.project') },
    { id: 'knowledge', icon: BookOpen, label: t('activityBar.knowledge') },
    { id: 'characters', icon: Users, label: t('activityBar.characters') },
  ]

  // Bottom panel tabs
  const bottomTabs: Array<{ id: BottomTab; icon: typeof Zap; label: string }> = [
    { id: 'tasks', icon: Zap, label: t('statusBar.tasksLabel') },
    { id: 'log', icon: ScrollText, label: t('bottomPanel.tabs.log') },
    { id: 'models', icon: Cpu, label: t('bottomPanel.tabs.models') },
  ]

  /** Home 按钮是否激活 */
  const homeActive = sidebarOpen && sidebarView === 'home'

  return (
    <div
      className="no-select flex flex-col h-full"
      style={{
        width: 'var(--width-left-bar)',  /* 36px */
        backgroundColor: 'var(--color-activity-bar)',
        borderRight: '1px solid var(--color-border)',
        flexShrink: 0,
      }}
    >
      {/* ===== 顶部:Home + 侧边栏视图切换 ===== */}
      <div className="flex flex-col items-center w-full pt-0.5">

        {/* Home 按钮 — 点击切换到主页视图 */}
        <button
          onClick={() => setSidebarView('home')}
          title={t('activityBar.home')}
          className="tool-btn"
          style={{
            height: 30,
            boxShadow: homeActive ? 'inset 2px 0 0 var(--color-activity-indicator)' : 'none',
            color: homeActive ? 'var(--color-activity-icon-active)' : undefined,
          }}
        >
          <Home size={16} strokeWidth={homeActive ? 2 : 1.5} />
        </button>

        {/* 分割线 */}
        <div className="w-4 my-0.5" style={{ height: 1, backgroundColor: 'var(--color-border)' }} />

        {/* 侧边栏视图按钮 */}
        {sidebarActivities.map(({ id, icon: Icon, label }) => {
          const isActive = sidebarOpen && sidebarView === id
          return (
            <button
              key={id}
              onClick={() => setSidebarView(id)}
              title={label}
              className="tool-btn"
              style={{
                boxShadow: isActive ? 'inset 2px 0 0 var(--color-activity-indicator)' : 'none',
                color: isActive ? 'var(--color-activity-icon-active)' : 'var(--color-activity-icon)',
              }}
            >
              <Icon size={17} strokeWidth={isActive ? 2 : 1.5} />
            </button>
          )
        })}
      </div>

      {/* 弹性间隔 */}
      <div className="flex-1" />

      {/* ===== 底部:底部面板 Tab 控制 ===== */}
      <div className="flex flex-col items-center w-full pb-1">
        <div className="w-4 mb-0.5" style={{ height: 1, backgroundColor: 'var(--color-border)' }} />

        {bottomTabs.map(({ id, icon: Icon, label }) => {
          const isActive = bottomPanelOpen && bottomTab === id
          const showPulse = id === 'tasks' && currentRun &&
            (currentRun.status === 'running' || currentRun.status === 'waiting')

          return (
            <div key={id} className="relative w-full">
              <button
                onClick={() => setBottomTab(id)}
                title={label}
                className="tool-btn"
                style={{
                  boxShadow: isActive ? 'inset 2px 0 0 var(--color-activity-indicator)' : 'none',
                  color: isActive ? 'var(--color-activity-icon-active)' : 'var(--color-activity-icon)',
                }}
              >
                <Icon size={15} strokeWidth={isActive ? 2 : 1.5} />
              </button>
              {showPulse && (
                <span
                  className="absolute top-[4px] right-[4px] w-[5px] h-[5px] rounded-full animate-pulse pointer-events-none"
                  style={{
                    backgroundColor: currentRun.status === 'waiting'
                      ? 'var(--color-warning)'
                      : 'var(--color-accent)',
                  }}
                />
              )}
            </div>
          )
        })}
      </div>
    </div>
  )
}