Files
terminalX/docs/design/UI-DESIGN-HANDOFF.md
kid 28e9cfc207 feat: UI 商业化改造 + 连接前 tmux 会话选择(真机验证)
按 Claude Design 定稿(归档在 docs/design/)重做 UI,并把 tmux 从
「从不自动进」修成「连接前探测 → 让用户选会话」。

设计令牌与导航地基
- Theme 拆三层:TXAccent(恒定 blurple) / TXChrome(中性阶×4 表) / TXFlavor(Catppuccin 终端)
- vendor JetBrains Mono 四权重(附 OFL 许可)
- AppRouter + SessionManager:多会话并存,路由与会话生命周期解耦
- SessionCanvas 常驻挂载会话 surface(摘除即丢内容,也是缩回动画的前提)

按设计稿落地的屏
- 沉浸轨道页:56pt 轨道 + 浮起标题/状态胶囊 + 侧边栏三态(遮罩不 resize、Pin 各一次)
- 首页:活动会话卡(readViewportText 文本镜像)+ 主机网格 + 筛选 chips
- 关闭二次确认(tmux 仅断开 / 原生窗口两套文案)、分屏菜单、pane 拖拽条
- 空状态:首次运行 / 无会话 / 搜索无命中 / 连接中·失败·已关闭

tmux 真实链路(真机查出并修掉 4 个 bug)
- 全代码库从来没人发起 attach → 连接前探测 + 会话选择器(接回 / 新建 / 原生终端)
- format 分隔符 tab 经 PTY 变成下划线 → 改用 |:|
- controller 变化不冒泡到 session → Combine 转发(否则数据解析对了 UI 不刷新)
- 当前会话名不能靠 session_attached 反推 → 改用 display-message

传输层:SSH connect 加超时(原来阻塞到系统 TCP 超时 75s+)
无头验证设施:假会话 fixture · terminalx://ui/* 驱动 · 横屏截图脚本 · 对拍走查法
TXCore 45 tests 绿(新增 5 个会话探测单测)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-25 22:59:35 +08:00

17 KiB
Raw Blame History

Handoff: terminalX — iPadOS 终端 App沉浸轨道方案

Overview

terminalX 是面向 iPadOS / iOS 的原生终端运维工具,解决 iPad 远程运维 macOS / Linux 的痛点。技术选型:libghostty(终端引擎)· mosh(抗断线传输)· Tailscale tsnet(用户态入网)· tmux control mode(会话复用)。平台优先级 iPadOS > iOS > macOS(Apple Silicon)

本包描述的是终端主界面(沉浸轨道)+ 首页(主机管理)+ 设置这一套已定稿的 UI含侧边栏三态、分屏模型、关闭/最小化语义、竖屏与 iPhone 降级规则。

About the Design Files

terminalX iPadOS.dc.html设计稿,不是生产代码。它用 HTML/CSS 表达最终视觉与交互意图1:1 像素尺寸),目的是让你在目标工程里用原生技术重建——本项目的目标环境是 SwiftUIiPadOS 26 / iOS 26,请使用工程已有的架构与组件模式实现,不要移植 HTML/CSS。

打开方式:浏览器直接打开该文件即可,画板可自由缩放平移。每块屏幕都带 data-screen-label,便于对照本文档。

Fidelity

High-fidelityhifi。颜色、字号、圆角、间距、行高均为最终值,可按本文档的精确数值实现。文案(简体中文,技术术语保留英文)也是最终稿。

唯一例外:终端内容区的命令输出是示意数据,用于验证排版密度与配色,不必照搬。


Design Tokens

颜色 — App chromeNocturne 设计系统)

用途 Hex Nocturne token
画布底 / 屏幕底 #161826 --color-bg
侧边栏 / 轨道 / 卡片底 #1b1d2b surface-dark
控件底(输入框、次要按钮、徽标) #232532 --color-surface
舞台底pane 之间的缝) #11121c bg-deep
分隔线(弱) #2c2f3d neutral-800
描边(常规) #3f424d neutral-700
描边(强调 / 对话框) #595d6c#4a4d5e neutral-600
强调色(唯一) #9184d9 --color-accent
强调 - 边框 #796cbf accent-600
强调 - 选中底 #2b2741 accent-900
强调 - 选中描边 #423a6a accent-800
强调 - 文字 #b5abfc / #d2cefd accent-400 / -300
强调 - 弱化文字 #5d5294#968ae0 accent-700 / -500
主文字 #e9e9ed --color-text
次文字 #cfd3e5 / #b2b6ca neutral-300 / -400
三级文字 #9397ab neutral-500
弱文字 / 占位 #75798c neutral-600
极弱(提示、注脚) #4a4d5e neutral-700

规则:强调色只做线、点、选中底和文字,绝不大面积铺色;不使用纯黑纯白。

颜色 — 终端内容区Catppuccin Mochalibghostty 渲染)

base #1e1e2epane 底)· mantle #181825 · surface0 #313244vim 状态栏)· text #cdd6f4 · subtext #a6adc8 · overlay #6c7086(次要输出)· surface2 #585b70(禁用/缓存态) 语义色:green #a6e3a1(成功、提示符)· red #f38ba8error· yellow #f9e2afwarning、git 标记)· blue #89b4fa(路径、字段)· mauve #cba6f7(关键字)· teal #94e2d5(勾选)· peach #fab387(重连中)· pink #f5c2e7

设置页可切换 Mocha / Macchiato / Frappé / Lattechrome 的中性阶随之推导,强调色恒为 Nocturne blurple #9184d9

macOS 窗口按钮沿用系统色:关闭 #ff5f57,最小化 #febc2e13pt 圆点,inset 0 0 0 .5px rgba(0,0,0,.25),仅悬停/触摸时显出符号)。

字体

全局 JetBrains Mono400 / 500 / 600 / 700chrome 与终端同源。中文走系统回退PingFang SC

场景 规格
屏幕主标题(首页 terminalX 500 34px, letter-spacing -.025em
页面标题(设置、总览) 500 2428px, ls -.02em
分区标题 500 22px, ls -.02em
分组小标题(活动会话 / TMUX 600 10px, ls .09em, uppercase, #75798c
列表主行 400500 13px
列表副行 / 元信息 400 10.511px, #75798c
徽标 / 胶囊 500 11.512px
终端正文(主 pane 400 13.5px / 1.55
终端正文(次 pane / 缩略) 400 1112px / 1.5
终端 pane 头 500 11px, #6c7086
底部提示条 400 11.5px, #75798c

间距 / 圆角 / 阴影

  • 间距2 / 6 / 8 / 9 / 10 / 12 / 14 / 16 / 18 / 20 / 26 / 34 / 40px
  • 圆角:徽标 57 · 控件 89 · 卡片 1113 · 对话框 1415 · 屏幕卡 18 · 手机卡 38
  • 阴影:浮起胶囊 0 10px 30px rgba(0,0,0,.55);侧边栏浮层 24px 0 60px rgba(0,0,0,.55);对话框 0 30px 80px rgba(0,0,0,.7);卡片 0 6px 18px rgba(0,0,0,.4)
  • 遮罩:rgba(10,11,18,.42.5),浮层用 backdrop-filter: blur(20px)

图标

Phosphor Iconsregular。用到magnifying-glass house plus gear-six caret-double-left caret-double-right caret-down caret-left push-pin columns terminal-window hard-drives desktop-tower cpu key shield-check lightning paint-brush text-aa keyboard export info warning x minus arrow-right arrow-left lightbulb moon check-circle wifi-high battery-high browsers rows git-branch plugs trash arrows-in-simple textbox sidebar-simple globe-hemisphere-west

SwiftUI 实现请换成等义 SF Symbols(例如 house / magnifying-glasshousemagnifyingglasscaret-double-leftchevron.compact.leftsidebar.leftpush-pinpin)。


Layout 基准

  • 画板尺寸iPad Pro 13″ 横屏 1366×1024pt;竖屏 1024×1366ptiPhone 393×852pt
  • 折叠轨道宽 56pt(竖屏 48pt元素中心线统一在 28pt竖屏 24pt
  • 展开侧边栏宽 288pt
  • pane 之间的缝 2pt(拖拽热区 12pt,把手 44×3pt 圆角 2pt
  • 触控命中区不低于 44pt(键盘附加行按键高 3840pt + 6pt 间距 = 44pt 节距)
  • 终端主 pane 顶部预留 86pt 给浮起胶囊2c 因多一条横幅为 122pt预留带用 padding-top 实现,内容容器 min-height:0; overflow:hidden 防止向上溢出
  • Home indicator 条200×4ptiPhone 140×5pt

Screens / Views

1) 终端主界面 · 沉浸轨道 — 1b 终端-沉浸轨道

Purpose:真正干活的界面,终端面积最大化。

LayoutHStack:左 56pt 轨道 + 右舞台。舞台是 VStackpane 区flex+ 硬件键盘提示条 34pt + home 区 14pt。pane 区 padding 2pt上下两个 pane 比例 1.7 : 1中间 12pt 拖拽条。

轨道自上而下Logo 方块34×34圆角 11#232532inset 描边 #3f424d,字形 700 16px #b5abfc不可点)→ 搜索图标 → 首页图标 → 1pt 分隔 → 主机头像38×38 圆角 11两字缩写选中底 #2b2741 + inset 描边 #5d5294;右上角 8pt 状态点,box-shadow: 0 0 0 2px #1b1d2b 挖底)→ 虚线 + 号 → 分隔 → TMUX 标签600 9px ls .1em+ window 数字34×30选中底 #232532 + inset 描边 #4a4d5e)→ Spacer → 连接状态点 8pt → 展开键(caret-double-right34×34 底 #232532 描边 #3f424d)→ 设置齿轮。

浮起 chromeposition: absolutebackdrop-filter: blur(20px),底 rgba(27,29,43,.86.9),描边 #3f424d,圆角 11

  • 左上标题胶囊 top 14, left 16:红/黄圆点 → 1pt 竖分隔 → 6pt 绿点 → 主机名500 12.5px)→ 「当前 window title · cwd」400 11.5px #75798c
  • 右上状态胶囊 top 14, right 16:三格分层徽标 tsnet | mosh 41ms | tmux dev,格间 1×16pt 竖线

底部提示条:接硬件键盘时只留 34pt 提示条(快捷键清单);触控时替换为键盘附加行(两行,见 iPhone / 竖屏)。

2) 侧边栏三态 — 3a 侧边栏-遮罩态3a 侧边栏-Pin 态

同一条栏的三个状态,元素不增不减,只是展示密度不同:

状态 宽度 行为
折叠 56pt 只显图标与两字缩写
遮罩(默认展开) 288pt 面板盖住轨道(left: 0,不并排,避免两套入口),右侧终端压 rgba(10,11,18,.5) 遮罩,点终端任意处收起;终端不 reflow不触发 PTY resize
Pin 288pt 点面板右上 push-pin 后钉住:遮罩消失,终端变窄,只在钉住/解除时各 resize 一次;再点解除回遮罩态

开合语义(务必唯一、不歧义) 方块是 App logo不可点。开合只有一枚按钮两态方向相反——折叠态在轨道底部 caret-double-right(展开),展开态在标题右侧 caret-double-left收起。Pin 是独立按钮,只在展开态出现。快捷键 ⌘\ 开合。

面板内容自上而下Logo + terminalX500 14px+ Pin + 收起 → 搜索框32pt 高,圆角 8首页行(house + 「首页」+ ⌘⇧H)→ 分组「活动会话 n」→ 会话行 → 1pt 渐隐分隔 → 分组「TMUX · <主机> · <会话>」→ window 行 + 「新建 window ⌘T」→ Spacer → Tailscale 状态脚(绿点 + tailnet + 设备 IP + 齿轮)。

行规格(左缘必须对齐):会话行 = 26pt 头像列 + 10pt gapwindow 行 = 26×22pt 徽标列 + 10pt gap两者标题左缘同为 x=53。选中态用 box-shadow: inset 0 0 0 1px #423a6a 而非 border,避免选中时内容位移 1pt。

3) 首页 · 主机管理(落地页)— 1e 主机-会话卡

PurposeApp 冷启动落点;「回到刚才那个会话」是首要动作。

Layout:状态栏 24pt → 页头terminalX 500 34px + 副行)+ 右侧搜索 220pt / 新建连接 / 设置 → 分组「活动会话」→ 3 列会话缩略卡flex:1 → 分组「全部主机」+ 筛选 chips → 4 列主机卡(按内容高度) → home 区。左右留白 40pt。

会话缩略卡(圆角 13选中卡描边 #423a6a + 0 6px 18px rgba(0,0,0,.4)):卡头 36pt状态点 + 主机名 + tmux 会话 + RTT→ 终端缩略(#1e1e2e11px/1.5内容底对齐,真实回滚)→ 卡脚 38pt「n windows · 上次活跃」+ ⌘1/2/3 + 主动作「回到会话 →」)。离线卡加 rgba(24,26,40,.72) + blur(1.5px) 遮罩,内含 26pt 转圈 + 两行说明;遮罩必须是 pane 的最后一个子节点pane 为 position: relative)。

最小化回来的卡:置顶并标「最小化中」,转场是从终端缩回该卡的动画。

4) 新建分屏 — 3b 新建分屏菜单

不问方向(竖分 ⌘D / 横分 ⌘⇧D 本来就是两个入口)。菜单只问「分到哪里」:

  • 分组「tmux 会话」:当前会话(带「当前」标签)、其余 detached 会话title · n windows · 上次活跃)、「新建 tmux 会话…」
  • 分隔线
  • 「原生窗口 / 不经 tmux · 关 App 即结束」

选完立即分屏。菜单 360pt 宽,圆角 14#1b1d2b + 描边 #595d6c;行高 ~40pt前导列统一 20pt状态点也要包在 20pt 居中列里,保证五行文字左缘一致 x=50

模型约束:分屏只发生在同一台主机内。卡片内部的分割 = 真 tmux panesplit-window,服务端持有,断线原样恢复);跨主机分屏已取消(层级过深),要同时看两台机器就切会话或 Pin 侧边栏。

5) 关闭 / 最小化 — 3c 关闭确认

标题胶囊左侧 macOS 红黄圆点:

  • 黄点(最小化)不确认,直接回首页,会话继续跑;卡片置顶标「最小化中」。手势:终端下滑。快捷键 ⌘M
  • 红点(关闭)弹一次确认,按主机能力分两套文案:
    • tmux 会话 → 主按钮「仅断开 ⏎」(detach,服务端继续跑);左侧次要文字按钮「结束会话」(kill-session,需再确认)
    • 原生窗口 → 琥珀警告「没有 tmux 兜底,前台进程会随之结束」;推荐「取消」,危险按钮「关闭窗口」(描边 #8d5560,底 rgba(92,58,63,.35),字 #f5a0ac
    • 快捷键 ⌘Wesc 取消; 选推荐项

对话框 436pt / 404pt 宽,圆角 15。

6) 首页 ⇄ 终端 跳转关系 — 3d 页面跳转关系

进入终端2 条):点活动会话卡 / 会话行 → 恢复到上一个焦点 pane;新建连接或主机 + → 建好即进终端,侧边栏同步出现该会话。 离开终端3 条):侧边栏首页行(⌘⇧H,会话完全不动)· 黄点最小化(同上但语义是"待会儿还回来")· 红点关闭二次确认tmux detach / 原生窗口结束)。 换会话不必回首页——侧边栏直接切;回首页表示"换任务"。会话总览层(原 ⌘O 缩放)已取消

7) 无 tmux 主机 — 2c 无 tmux 主机

轨道下半段的 TMUX 段换成「窗口」段(客户端窗口,每个 = 一条独立 SSH channel / mosh 会话,可随意新建)。状态胶囊第三格写「无 tmux · 客户端窗口」而非报错。终端顶部一条可关闭的行内横幅:说明窗口由 App 维持、mosh 兜底,但关掉 App 不会在服务端继续跑,右侧给「安装并启用 tmux」次要按钮。不弹窗、不强推。

8) 竖屏与 iPhone — 2d iPad 竖屏2d iPhone 竖屏1h iPhone-终端1h iPhone-主机

  • iPad 竖屏1024×1366:轨道降到 48pt元素中心 24pt同样含搜索/首页/展开键pane 由左右平铺改为上下堆叠,最多两层,多余 pane 折成顶部段控;状态胶囊压缩为「主机名 + RTT」两枚底部常驻单行键盘附加行。
  • iPhone393×852:轨道下沉为底部主机条ms / u2 / nh 胶囊);单 pane 全屏,顶部 3 段进度式 pane 指示 +「左右轻扫切 pane」下拉标题打开会话列表键盘附加行两行esc/ctrl/tab/~///| 与 ↑↓←→/⌘K主机页用底部 tab主机 / 会话 / 密钥 / 设置)。

9) 设置 · 外观 — 1g 设置-外观

左 280pt 类别栏(外观与主题 / 终端与字体 / Tailscale / 密钥与安全 / mosh 与重连 / tmux 集成 / 键盘与手势 / 诊断日志,脚注版本行),右内容区 padding 28/40。内容标题 + 说明 → 4 张 Catppuccin 主题卡88pt 预览 + 5 色点 + 名称,选中描边 #796cbf + check-circle)→ 两栏(左「实时预览」终端框,右「排版」面板:字体、字号 13.5pt、行高 1.50、连字、CJK 等宽补偿、跟随系统深浅色)。


Interactions & Behavior

交互 行为
侧边栏开合 ⌘\ 或开合键遮罩态点终端收起Pin 切换推挤/浮层
切会话 轨道主机头像 / 侧边栏会话行 / ⌘1…9;恢复到该会话上一个焦点 pane
切 window 轨道数字 / 侧边栏 window 行 / ⌃⇥
分屏 ⌘D 竖分、⌘⇧D 横分 → 弹会话选择菜单 → 立即分屏
新建 ⌘T 新 tmux window⌘⌥T 原生窗口
调整 pane 比例 拖 12pt 分隔条(把手 44×3pt松手才向 tmux 发 resize-pane
回首页 ⌘⇧H / 侧边栏首页行
最小化 黄点 / ⌘M / 终端下滑;无确认
关闭 红点 / ⌘W;二次确认, = 推荐项,esc 取消
命令面板 ⌘K(模糊匹配主机、会话、动作)
硬件键盘 检测到即收起附加行,只留 34pt 提示条;拔掉恢复附加行
长按 显示全部快捷键面板iPadOS 系统行为)

动效:状态切换 200260ms easeOut;侧边栏浮层从左滑入 + 遮罩淡入;最小化 = 终端缩回首页卡片matched geometry重连转圈 1s 线性循环。

状态徽标规则(分层,只染出问题的那层)

  1. tsnet — 网络可达;断则本格转灰/琥珀
  2. mosh <RTT> — 数字实时跳动;≤120ms 绿 #a6e3a1120200ms 中性,>200ms 琥珀 #fab387
  3. tmux <会话名> / 「无 tmux · 客户端窗口」

重连:指数退避,上限 30s卡片/胶囊显示「重连中 · 第 n 次 · ms 后」;屏幕内容本地缓存,恢复后原样接回(目标 <3s

安全host key TOFU 固定在钥匙串;不匹配时拦截连接并告警;私钥存 Secure Enclave不可导出密码回退默认关闭。

State Management

AppRoute          = .home | .terminal(sessionID)
SidebarState      = .collapsed | .overlay | .pinned
Session           { id, host, kind: .tmux(name) | .nativeWindow, windows[], focusedPaneID,
                    transport: .ssh | .sshOverTsnet | .mosh | .moshOverTsnet,
                    link: .direct(rtt) | .relay(derp, rtt) | .reconnecting(attempt, nextIn) | .offline,
                    lastActiveAt, isMinimized }
TmuxWindow        { index, title, cwd, panes[] }        // title 为 shell 默认值时 UI 回退显示 cwd
Host              { id, name, group, user, addr, port, os, tsnetIP, hasTmux, hostKeyPinnedAt }

关键转换:选择会话 → .terminal首页/最小化 → .home(会话保留);关闭 → detach 或 kill → .homePin → .pinned(触发一次 PTY resize

Files

  • terminalX iPadOS.dc.html — 全部 13 块屏幕的设计稿(画板,可缩放平移)
  • CLAUDE.md / README.md(源项目文档,若已在仓库中则以仓库版本为准)

Assets

无位图资产。图标全部来自 Phosphor实现时换 SF Symbols字体 JetBrains MonoGoogle Fonts终端配色 Catppuccin。