feat(ui): add collapsible persistent sidebar

This commit is contained in:
Logan.Li committed 2026-08-06 17:56:55 +08:00
1 parent 9ce71795b8
commit 101d2164b4
13 files changed
+153 -29

No files matched your search

+31 -8
View File
@@ -4,7 +4,7 @@
*/
import { useState, useEffect, useRef, useCallback } from 'react'
import { Plus, Zap, Server, Settings, ListChecks, Terminal, FolderSync, X, TerminalSquare } from 'lucide-react'
import { Plus, Zap, Settings, ListChecks, Terminal, FolderSync, X, TerminalSquare, PanelLeftClose } from 'lucide-react'
import { useSessionStore, Session } from '../../stores'
import { useSettingsStore } from '../../stores/settingsStore'
import { useTabStore } from '../../stores/tabStore'
@@ -12,6 +12,7 @@ import { SessionTree } from './sidebar/SessionTree'
import { SearchBox } from './sidebar/SearchBox'
import { useConfirmDialog } from '../common/ConfirmDialog'
import BatchCommandDialog from '../sessions/BatchCommandDialog'
import appIconUrl from '../../assets/opsxshell-app-icon.png'
const MIN_SIDEBAR_WIDTH = 180
const MAX_SIDEBAR_WIDTH = 400
@@ -20,9 +21,10 @@ interface SidebarProps {
onNewSession: () => void
onQuickConnect: () => void
onEditSession: (session: Session) => void
onCollapse?: () => void
}
export default function Sidebar({ onNewSession, onQuickConnect, onEditSession }: SidebarProps) {
export default function Sidebar({ onNewSession, onQuickConnect, onEditSession, onCollapse }: SidebarProps) {
const { sessions, setSessions, addSession, removeSession } = useSessionStore()
const { settings, setSetting } = useSettingsStore()
const { addTab } = useTabStore()
@@ -259,15 +261,31 @@ export default function Sidebar({ onNewSession, onQuickConnect, onEditSession }:
{/* Header */}
<div className="p-3.5 border-b border-dark-700/30">
<div className="flex items-center gap-2.5 mb-3.5 px-0.5">
<div className="w-8 h-8 bg-gradient-to-br from-accent-blue to-accent-blue/70 rounded-lg flex items-center justify-center shadow-sm shadow-accent-blue/25">
<Server className="w-4 h-4 text-white" />
</div>
<div className="min-w-0">
<img
src={appIconUrl}
alt="OpsXShell"
width={32}
height={32}
className="h-8 w-8 flex-shrink-0 rounded-[9px] object-cover"
draggable={false}
/>
<div className="min-w-0 flex-1">
<div className="font-semibold text-sm text-content-primary tracking-tight leading-none">
OpsXShell
</div>
<div className="text-[10px] text-txt-faint mt-1">远程运维工作台</div>
<div className="text-[10px] text-txt-faint mt-1">SSH / SFTP 终端</div>
</div>
{onCollapse && (
<button
type="button"
onClick={onCollapse}
title="折叠侧栏 (Ctrl/Cmd+B)"
aria-label="折叠侧栏"
className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg text-txt-muted transition-colors hover:bg-dark-700 hover:text-content-primary"
>
<PanelLeftClose className="h-4 w-4" />
</button>
)}
</div>
<div className="flex gap-1.5">
@@ -414,9 +432,14 @@ export default function Sidebar({ onNewSession, onQuickConnect, onEditSession }:
)}
</div>
{/* Resize Handle */}
{/* Resize Handle — 双击也可折叠 */}
<div
onMouseDown={handleResizeStart}
onDoubleClick={(e) => {
e.preventDefault()
onCollapse?.()
}}
title="拖拽调整宽度,双击折叠"
className={`
absolute top-0 right-0 bottom-0 w-1 cursor-col-resize
hover:bg-accent-blue/50 active:bg-accent-blue/70