diff --git a/web/src/App.tsx b/web/src/App.tsx
index 6b3ad5a..5606df4 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import { Zap, ArrowLeft, Bot, Clock, Sun, Moon, PanelRightOpen, X, Brain, Settings as SettingsIcon, ChevronRight } from 'lucide-react'
+import { Zap, ArrowLeft, Bot, Clock, Sun, Moon, PanelRightOpen, PanelLeftClose, PanelLeftOpen, X, Brain, Settings as SettingsIcon, ChevronRight } from 'lucide-react'
import { ChatContainer } from './components/Chat/ChatContainer'
import { TopicList } from './components/Sidebar/TopicList'
import { SchedulerJobList } from './components/Sidebar/SchedulerJobList'
@@ -120,6 +120,22 @@ function App() {
const [rightPanelTab, setRightPanelTab] = useState<'memory' | 'skill'>('memory')
+ const [sidebarCollapsed, setSidebarCollapsed] = useState(() => {
+ try {
+ return localStorage.getItem('picobot-sidebar-collapsed') === 'true'
+ } catch {
+ return false
+ }
+ })
+
+ const toggleSidebar = useCallback(() => {
+ setSidebarCollapsed(prev => {
+ const next = !prev
+ localStorage.setItem('picobot-sidebar-collapsed', String(next))
+ return next
+ })
+ }, [])
+
const [theme, setTheme] = useState<'dark' | 'light'>(() => {
const saved = localStorage.getItem('picobot-theme')
return saved === 'light' ? 'light' : 'dark'
@@ -562,34 +578,83 @@ function App() {
{/* Main Content */}
- {/* Left Sidebar */}
-
- {/* Tab 栏 */}
-
-
-
+ {/* Left Sidebar — smooth width animation via will-change + overflow-hidden */}
+
+ {/* Tab 栏 + collapse toggle */}
+
+ {sidebarCollapsed ? (
+ /* 收起态:紧凑竖排 tab 按钮 */
+
+
+
+ {/* 展开按钮 */}
+
+
+ ) : (
+ <>
+
+
+ {/* 收起按钮 */}
+
+ >
+ )}
-
- {sidebarTab === 'topics' ? (
+
+ {sidebarCollapsed ? null : sidebarTab === 'topics' ? (