Files
Unlucky-Launcher/crates/app-iced
AskaEth cb580a257e feat(layout): M301 页面宽度跟随活轨宽(折叠 −64 / 展开 −88 / 动效插值)
用户口径「折叠腾出空间」只完成一半:M300 落了折叠态(ui.nav.collapsed + 一条并列宽度轨)
与折叠档令牌 nav_collapsed_width = 64,但 `pages/layout.rs` 的 `rail_width()` 仍是
`const fn` 恒返回 88 ⇒ 折叠后页面照旧按 88 扣宽,内容区右侧留一条 24px 空白带。

## 轨宽从常量改成**当帧活值**(不存第二份状态)
- 新增 `pages/layout/rail.rs`:thread-local `Option<f32>` 采样槽,`rail_width()` 读它,
  未采样回落展开档令牌 88(不 panic、不 unwrap;NaN/inf/负数不写入)。
- 写入口**只有一个**:`app/view/rail.rs` 的 `rail_account()` —— M300 自己点名的「折叠档与
  过渡进度的唯一构造点」,一次 `App::view()` 调用恰好一次,且排在页面树之前
  (`app/view.rs` 的 `let account = self.rail_account();`),所以页面扣的宽度与外壳画的轨
  是同一帧同一个数。折叠的**决定**仍在 presenter `prefs.nav_collapsed`,进度仍在 motion 轨。
- `rail_width()` 签名不变 ⇒ `pages/mod.rs`、`pages/agent/**`、20 个页面/测试文件的调用面
  **零改动**(`git diff --stat` 里那两处都没有出现)。
- 动效期间自动插值:采样值就是 `RailAccount::nav_width` 的 64⇄88 插值结果。
- 门槛跟着动(公式里本来就是 `+ rail`):720/816 → 折叠 696/792。

## 测试
- `pages/tests/rail_width.rs`(新):折叠=窗口−64、展开=窗口−88、差正好 24、块右缘贴死窗口;
  无外壳通道回落 88;采样不粘滞;门槛跟活值;**唯一写入口**(扫 `src/**` 源码);
  **先写后读**(扫 `app/view.rs` 语句顺序)。期望值全从令牌取,不再写 88.0 / 64.0。
- `app/view/rail.rs` 新增接线用例:折叠→采样→展开→再采样必须回到 88(不粘滞)、
  动效中间帧页面可用宽跟着插值(首尾逐位落在端值)。
- 原有钉 88 的三条改为「跟随模型」并逐条给了新算式(标题左缘 1180−88−48、块宽、
  主列 pane);`pages/tests.rs` 400 行门禁前先拆出 `tests/demo_model.rs`。

## 判据
- app-iced:1064 passed(M300 基线 1053 + 11 条新用例);no_hardcoded_tokens 6 passed。
- `clippy --workspace --all-targets -- -D warnings` / `fmt --all -- --check` 均 0。
- 变异:`rail_width()` 改回常量 88 ⇒ 2 条几何判据 + 门槛判据红(1068 vs 1044);
  删掉外壳那一行写入 ⇒ 2 条接线用例红(折叠仍按 88 扣宽)。
- 像素(DevDocs/artifacts/m301/,本地不进仓):日志页折叠态内容右缘 1107 = 展开态 1107
  (24px 全进内容),变异版折叠态 1083(那条 24px 空白带);`instances` 页因详情列被 424
  封顶、列表列固定 336,改前改后**逐像素相同**,所以举证必须用单列页。
2026-11-13 17:06:12 +08:00
..