feat: 侧边栏两态重构(统一视图身份)+ 第四轮触控化走查
侧边栏(真机验证): - 砍掉悬浮态,只留收起⇄固定展开;TerminalSidebar 单一视图身份, 内容恒按 288pt 排版、收起=左侧裁切(clipped 宽度动画), 图标列两态同尺寸同位置,明细淡入淡出,终端随宽度盖上/让开 - 开合入口收敛:Logo 位(收起态=»展开键/展开态=Logo)+ 头部«; 删底部开合键与 Pin;LeadingHitShape 修 clipped 不裁触摸 - 修 GridBox 从不通知 UI:onGridChange→objectWillChange, 标题胶囊格子数随开合实时刷新 触控化走查(上一轮,真机部署验证): - 窗口按钮 13pt 色点→22pt 圆角方块常显字形;动作条改可点按钮 - TXTech 拼写/配色规范(SSH/mosh/tmux 官方写法+品牌色映射) - 首页会话卡固定 3 列 4:3;去掉未实现的 ⌘K 提示 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,21 +14,19 @@ enum AppRoute: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
/// 侧边栏三态。同一条栏,元素不增不减,只是展示密度不同。
|
||||
/// 侧边栏两态(用户裁决砍掉悬浮态:展开即固定)。同一条栏,元素不增不减,只是展示密度不同。
|
||||
enum SidebarState: Equatable {
|
||||
/// 56pt 轨道:只显图标与两字缩写
|
||||
case collapsed
|
||||
/// 288pt 面板**盖住**轨道,右侧终端压遮罩;点终端任意处收起。终端不 reflow、不触发 PTY resize。
|
||||
case overlay
|
||||
/// 288pt 钉在左侧:遮罩消失,终端变窄。**只在钉住/解除时各 resize 一次**。
|
||||
/// 288pt 固定在左侧:终端变窄。开合各触发一次 resize。
|
||||
case pinned
|
||||
|
||||
var isExpanded: Bool { self != .collapsed }
|
||||
var isExpanded: Bool { self == .pinned }
|
||||
|
||||
/// 该状态下侧边栏占据的布局宽度(overlay 是浮层,不占位)。
|
||||
/// 该状态下侧边栏占据的布局宽度。
|
||||
var layoutWidth: CGFloat {
|
||||
switch self {
|
||||
case .collapsed, .overlay: TX.Layout.railWidth
|
||||
case .collapsed: TX.Layout.railWidth
|
||||
case .pinned: TX.Layout.sidebarWidth
|
||||
}
|
||||
}
|
||||
@@ -51,47 +49,34 @@ final class AppRouter: ObservableObject {
|
||||
/// 当前模态浮层(关闭确认 / 分屏菜单)。
|
||||
@Published var modal: AppModal?
|
||||
|
||||
/// 状态切换动效:设计定稿 200–260ms easeOut(侧边栏浮层从左滑入 + 遮罩淡入)。
|
||||
/// 所有侧边栏状态变更都经这里,键盘快捷键与点击拿到同一条曲线。
|
||||
static let sidebarAnimation = Animation.easeOut(duration: 0.24)
|
||||
|
||||
private func animateSidebar(_ change: () -> Void) {
|
||||
withAnimation(Self.sidebarAnimation, change)
|
||||
/// 状态切换动效统一走 `TX.Motion.standard`(设计定稿 200–260ms easeOut,响应「减弱动态」)。
|
||||
///
|
||||
/// **路由 / 侧边栏 / 浮层的每一次变更都必须包在这条曲线里**,否则视图上的 `transition`
|
||||
/// 拿不到动画事务就退化成硬切 —— 首页 ⇄ 终端、关闭确认、分屏菜单曾都是这么"啪"地跳出来的。
|
||||
/// 收在 router 里的另一个好处:点击、⌘ 快捷键、无头 URL 三条入口天然同一手感。
|
||||
private func animated(_ change: () -> Void) {
|
||||
withAnimation(TX.Motion.standard, change)
|
||||
}
|
||||
|
||||
/// 进入某会话(点会话卡 / 侧边栏会话行 / 新建连接后)。恢复焦点由会话自身持有。
|
||||
func enter(_ sessionID: UUID) {
|
||||
route = .terminal(sessionID)
|
||||
animated { route = .terminal(sessionID) }
|
||||
}
|
||||
|
||||
/// 回首页:会话完全不动(⌘⇧H / 侧边栏首页行)。
|
||||
/// 回首页:会话完全不动(⌘⇧H / 侧边栏首页行)。展开态跨导航保留。
|
||||
func goHome() {
|
||||
modal = nil
|
||||
route = .home
|
||||
if sidebar == .overlay { animateSidebar { sidebar = .collapsed } }
|
||||
}
|
||||
|
||||
/// 开合侧边栏(⌘\ / 开合键)。折叠 ⇄ 遮罩;Pin 态视作展开,收起回折叠。
|
||||
func toggleSidebar() {
|
||||
animateSidebar {
|
||||
switch sidebar {
|
||||
case .collapsed: sidebar = .overlay
|
||||
case .overlay, .pinned: sidebar = .collapsed
|
||||
}
|
||||
animated {
|
||||
modal = nil
|
||||
route = .home
|
||||
}
|
||||
}
|
||||
|
||||
/// Pin 切换(只在展开态出现)。钉住/解除各触发一次终端 resize。
|
||||
func togglePin() {
|
||||
animateSidebar { sidebar = sidebar == .pinned ? .overlay : .pinned }
|
||||
/// 开合侧边栏(⌘\ / Logo 位展开键 / 头部收起键)。收起 ⇄ 固定展开。
|
||||
func toggleSidebar() {
|
||||
animated { sidebar = sidebar == .collapsed ? .pinned : .collapsed }
|
||||
}
|
||||
|
||||
/// 打开/关闭模态浮层(红点、⌘W、⌘D、⌘⇧D 与无头 URL 共用同一入口)。
|
||||
func present(_ modal: AppModal) { self.modal = modal }
|
||||
func dismissModal() { modal = nil }
|
||||
|
||||
/// 点终端任意处:遮罩态收起(Pin 态不受影响)。
|
||||
func dismissOverlaySidebar() {
|
||||
if sidebar == .overlay { animateSidebar { sidebar = .collapsed } }
|
||||
}
|
||||
func present(_ modal: AppModal) { animated { self.modal = modal } }
|
||||
func dismissModal() { animated { modal = nil } }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user