feat: 添加侧边栏收起/展开功能并优化样式

This commit is contained in:
oudecheng 2026-06-26 11:34:39 +08:00
parent a40f57fb22
commit 63714b6c6e

View File

@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react' 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 { ChatContainer } from './components/Chat/ChatContainer'
import { TopicList } from './components/Sidebar/TopicList' import { TopicList } from './components/Sidebar/TopicList'
import { SchedulerJobList } from './components/Sidebar/SchedulerJobList' import { SchedulerJobList } from './components/Sidebar/SchedulerJobList'
@ -120,6 +120,22 @@ function App() {
const [rightPanelTab, setRightPanelTab] = useState<'memory' | 'skill'>('memory') 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 [theme, setTheme] = useState<'dark' | 'light'>(() => {
const saved = localStorage.getItem('picobot-theme') const saved = localStorage.getItem('picobot-theme')
return saved === 'light' ? 'light' : 'dark' return saved === 'light' ? 'light' : 'dark'
@ -562,34 +578,83 @@ function App() {
{/* Main Content */} {/* Main Content */}
<div className="flex flex-1 overflow-hidden relative"> <div className="flex flex-1 overflow-hidden relative">
{/* Left Sidebar */} {/* Left Sidebar — smooth width animation via will-change + overflow-hidden */}
<div className={`w-72 shrink-0 border-r border-[var(--border-color)] bg-[var(--bg-secondary)]/50 flex flex-col ${subAgentView || schedulerView ? 'opacity-50 pointer-events-none' : ''}`}> <div
{/* Tab 栏 */} className={`shrink-0 border-r border-[var(--border-color)] bg-[var(--bg-secondary)]/50 flex flex-col overflow-hidden ${sidebarCollapsed ? 'w-11' : 'w-72'} ${subAgentView || schedulerView ? 'opacity-50 pointer-events-none' : ''}`}
<div className="flex border-b border-[var(--border-color)]"> style={{ transition: 'width 200ms ease-out', willChange: 'width' }}
<button >
onClick={() => setSidebarTab('topics')} {/* Tab 栏 + collapse toggle */}
className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors ${ <div className="flex border-b border-[var(--border-color)]" style={{ minWidth: sidebarCollapsed ? 0 : '288px' }}>
sidebarTab === 'topics' {sidebarCollapsed ? (
? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]' /* 收起态:紧凑竖排 tab 按钮 */
: 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]' <div className="flex flex-col w-full">
}`} <button
> onClick={() => { setSidebarTab('topics'); setSidebarCollapsed(false); localStorage.setItem('picobot-sidebar-collapsed', 'false'); }}
className={`py-2 text-xs font-medium text-center transition-colors ${
</button> sidebarTab === 'topics'
<button ? 'text-[var(--accent-cyan)] bg-[var(--accent-cyan)]/10'
onClick={() => setSidebarTab('scheduler')} : 'text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:bg-[var(--overlay-hover)]'
className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors ${ }`}
sidebarTab === 'scheduler' title="话题"
? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]' >
: 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]' <br/>
}`} </button>
> <button
onClick={() => { setSidebarTab('scheduler'); setSidebarCollapsed(false); localStorage.setItem('picobot-sidebar-collapsed', 'false'); }}
</button> className={`py-2 text-xs font-medium text-center transition-colors ${
sidebarTab === 'scheduler'
? 'text-[var(--accent-cyan)] bg-[var(--accent-cyan)]/10'
: 'text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:bg-[var(--overlay-hover)]'
}`}
title="定时任务"
>
<br/>
</button>
{/* 展开按钮 */}
<button
onClick={toggleSidebar}
className="flex items-center justify-center py-2 text-[var(--text-muted)] hover:text-[var(--accent-cyan)] hover:bg-[var(--overlay-hover)] transition-colors"
title="展开侧栏"
>
<PanelLeftOpen className="h-3.5 w-3.5" />
</button>
</div>
) : (
<>
<button
onClick={() => setSidebarTab('topics')}
className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors whitespace-nowrap ${
sidebarTab === 'topics'
? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]'
: 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]'
}`}
>
</button>
<button
onClick={() => setSidebarTab('scheduler')}
className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors whitespace-nowrap ${
sidebarTab === 'scheduler'
? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]'
: 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]'
}`}
>
</button>
{/* 收起按钮 */}
<button
onClick={toggleSidebar}
className="flex items-center justify-center px-2 text-[var(--text-muted)] hover:text-[var(--accent-cyan)] hover:bg-[var(--overlay-hover)] transition-colors shrink-0"
title="收起侧栏"
>
<PanelLeftClose className="h-4 w-4" />
</button>
</>
)}
</div> </div>
<div className="flex-1 overflow-hidden"> <div className="flex-1 overflow-hidden" style={{ minWidth: sidebarCollapsed ? 0 : '288px' }}>
{sidebarTab === 'topics' ? ( {sidebarCollapsed ? null : sidebarTab === 'topics' ? (
<TopicList <TopicList
sessionId={sessionId} sessionId={sessionId}
topics={topics} topics={topics}