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:
kid
2026-07-26 00:55:53 +08:00
parent 28e9cfc207
commit 5707d70dff
15 changed files with 1086 additions and 675 deletions

View File

@@ -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?
/// 稿 200260ms easeOut +
/// 线
static let sidebarAnimation = Animation.easeOut(duration: 0.24)
private func animateSidebar(_ change: () -> Void) {
withAnimation(Self.sidebarAnimation, change)
/// `TX.Motion.standard`稿 200260ms 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 }
}
/// /WDD 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 } }
}