feat: 业务逻辑对齐 + 首页/弹框七项减法 + 终端页四项体验修复
业务逻辑(用户定稿): - 点主机总是新建会话(会话:主机=多:1);activate 选中断线会话自动重连 - 「直接输入」凭据保存时自动落 Keychain(去重复用),主机只存引用 - 主机编辑页可就地新建 Tailscale 连接;删无人引用的旧 HostsListView 首页/弹框减法: - 删侧边栏「连接新主机」、无 tmux 横幅与安装引导、页头「新建连接」 - 搜索移到「全部主机」行;添加主机虚线卡与主机卡等高(骨架复刻) - 会话卡加 ✕ + 复用终端页同款二次确认 - 会话选择器 sheet → 项目风格居中弹框(去手柄/Header/最近) 终端页修复: - 侧边栏会话列表改创建顺序,切换不再重排抖动 - 焦点高亮上移到 pane 容器边框(四边完整,去负 padding) - 软键盘双重让位修复:画布忽略键盘 + TXKeyboardObserver 显式让位一次 - 自动聚焦:focusTick 脉冲强制翻转 FocusState + surface 就绪补聚焦; vendor 补 iPadOS 触摸板 indirectPointer 的 becomeFirstResponder Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -345,89 +345,8 @@ struct TerminalStateOverlay: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// 无 tmux 主机的行内横幅(设计稿 `2c`):说明窗口由 App 维持、mosh 兜底,但**关掉 App 不会在
|
||||
/// 服务端继续跑**;右侧给「安装并启用 tmux」次要按钮。**不弹窗、不强推**,可关闭。
|
||||
struct NoTmuxBanner: View {
|
||||
let onInstall: () -> Void
|
||||
let onDismiss: () -> Void
|
||||
@EnvironmentObject var theme: TXThemeManager
|
||||
private var p: TXPalette { theme.palette }
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: TX.Space.s) {
|
||||
Image(systemName: "info.circle")
|
||||
.font(.system(size: 12))
|
||||
.foregroundStyle(p.warning)
|
||||
Text("未检测到 tmux · 当前是客户端窗口:mosh 能兜断线,但**关掉 App 后服务端不会继续跑**")
|
||||
.font(TX.Font.mono(11.5))
|
||||
.foregroundStyle(p.text3)
|
||||
.lineLimit(1)
|
||||
Spacer(minLength: TX.Space.s)
|
||||
TXButton(title: "安装并启用 tmux", action: onInstall)
|
||||
Button(action: onDismiss) {
|
||||
Image(systemName: "xmark")
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.foregroundStyle(p.textWeak)
|
||||
.frame(width: 28, height: 28)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.txPressTight)
|
||||
}
|
||||
.padding(.horizontal, TX.Space.s)
|
||||
.frame(height: 40)
|
||||
.background(p.surfaceDark.opacity(0.92))
|
||||
.overlay(alignment: .bottom) { Rectangle().fill(p.divider).frame(height: 1) }
|
||||
}
|
||||
}
|
||||
|
||||
/// 「安装并启用 tmux」的引导(点横幅按钮后):给出各发行版命令,用户可一键塞进终端执行。
|
||||
struct TmuxInstallSheet: View {
|
||||
let onRun: (String) -> Void
|
||||
let onCancel: () -> Void
|
||||
@EnvironmentObject var theme: TXThemeManager
|
||||
private var p: TXPalette { theme.palette }
|
||||
|
||||
/// 常见包管理器。跨发行版探测一条命令搞定:有哪个用哪个。
|
||||
private let combined = "command -v apt-get >/dev/null && sudo apt-get install -y tmux || " +
|
||||
"command -v dnf >/dev/null && sudo dnf install -y tmux || " +
|
||||
"command -v pacman >/dev/null && sudo pacman -S --noconfirm tmux || " +
|
||||
"command -v apk >/dev/null && sudo apk add tmux || " +
|
||||
"command -v brew >/dev/null && brew install tmux"
|
||||
|
||||
var body: some View {
|
||||
TXModalScrim(onDismiss: onCancel) {
|
||||
VStack(alignment: .leading, spacing: TX.Space.s) {
|
||||
Text("安装 tmux")
|
||||
.font(TX.Font.mono(15, .medium))
|
||||
.foregroundStyle(p.text)
|
||||
Text("tmux 让会话留在服务端:关掉 App、换网络、睡一觉回来都能原样接回。\n下面这条会按服务器的包管理器自动选择(需要 sudo 权限)。")
|
||||
.font(TX.Font.mono(12))
|
||||
.foregroundStyle(p.text3)
|
||||
.lineSpacing(4)
|
||||
Text(combined)
|
||||
.font(TX.Font.mono(10.5))
|
||||
.foregroundStyle(p.text4)
|
||||
.padding(TX.Space.s)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(p.bgDeep, in: RoundedRectangle(cornerRadius: 8))
|
||||
HStack(spacing: TX.Space.s) {
|
||||
Spacer()
|
||||
TXButton(title: "取消", action: onCancel)
|
||||
TXButton(title: "在终端执行", emphasized: true) { onRun(combined) }
|
||||
}
|
||||
.padding(.top, TX.Space.xs)
|
||||
}
|
||||
.padding(TX.Space.l)
|
||||
.frame(width: 520)
|
||||
.background(p.surfaceDark, in: RoundedRectangle(cornerRadius: TX.Radius.dialog))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: TX.Radius.dialog)
|
||||
.strokeBorder(p.borderStrong, lineWidth: 1)
|
||||
)
|
||||
.txShadow(TX.Elevation.dialog)
|
||||
}
|
||||
}
|
||||
}
|
||||
// (「未检测到 tmux」横幅与「安装并启用 tmux」引导弹层已按用户裁决删除:无 tmux 静默走
|
||||
// 原生窗口,状态只在底部状态行一句话,不打扰。)
|
||||
|
||||
/// 舞台底部**状态行**(动作按钮已按第一版减法裁掉:window 管理交给 tmux 自己,
|
||||
/// 回首页走侧边栏 / 顶带 ⌄ 最小化)。
|
||||
|
||||
Reference in New Issue
Block a user