feat: 侧边栏双面板 — 右上角按钮簇、底部面板(首展自动终端/关闭按钮)、跨面板拖 Tab、拖动性能优化

- 右上角持久按钮簇:横向排列、独立 glyph(底栏/侧拉)、始终钉在视口右上角(侧边栏展开时位于其标签条右端,真实挤占 Tab 空间)
- 底部面板:独立工作台,只挤占中间 Agent 输出区(不覆盖左右侧边栏),右缘分割线、关闭 x、首展自动开终端(二级设置开关,默认开)
- 两面板拐角双向拖动调节尺寸;拖动改为 rAF 节流直写 DOM,消除卡顿;面板尺寸互钳制防丢失
- 跨面板拖 Tab(合并/拆分落点),moveTab/moveTabToEdge 支持跨树移动
- 欢迎卡片改响应式网格;布局/几何全部按会话持久化,旧状态平滑迁移
This commit is contained in:
Menghuan1918
2026-08-12 16:43:24 +08:00
parent 7eccc49f6e
commit c7af7dccdb
19 changed files with 1033 additions and 170 deletions
+7 -3
View File
@@ -262,20 +262,24 @@ function NodeView(props: {
)
}
/** The workbench: the split tree filling the sidebar body. */
/** The workbench: the split tree filling the sidebar body. `tree` selects
* which tree renders (the right panel's by default; the bottom panel passes
* `state.bottomSplits` — the actions route by pane id, so one action set
* serves both). */
export function Workbench(props: {
state: SidebarState
tree?: SplitNode
newTabOptions: NewTabOption[]
actions: WorkbenchActions
onNewTab: (optionId: string) => void
renderTab: (tab: SidebarTab, active: boolean, paneId: string) => ReactNode
getTabIcon?: (tab: SidebarTab) => ReactNode
}) {
const { state, newTabOptions, actions, onNewTab, renderTab, getTabIcon } = props
const { state, tree, newTabOptions, actions, onNewTab, renderTab, getTabIcon } = props
return (
<div className={css.workbench}>
<NodeView
node={state.splits}
node={tree ?? state.splits}
state={state}
newTabOptions={newTabOptions}
actions={actions}