Skip to content

fix(ui): define the orphan .mono class and restore the .nb nowrap span - #161

Merged
argszero merged 1 commit into
mainfrom
fix/ui-class-parity-mono-nb
Sep 11, 2026
Merged

argszero merged 1 commit into
mainfrom
fix/ui-class-parity-mono-nb

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

Two silent UI defects found by the class-parity audit of the prototype vs. the implementation are fixed here. Both were invisible in ordinary use because the affected elements still rendered — just without the styling rule they were asking for.

  1. .mono was referenced but defined nowhere. The sharing table's Key cell has carried class='mono' since the initial UI commit (d70e032), yet no commit ever contained a .mono rule, so the cell silently fell back to the UI font.
  2. .nb was lost together with its span. The login brand headline used to wrap token plan in <span class="nb">, and the prototype defines .nb { white-space: nowrap } (prototype line 132) so the phrase never breaks. The migration dropped both the span and the rule, and the ZH headline then broke inside the phrase.

Related Issue

None — found internally by a prototype-vs-implementation class-parity audit, not by a filed issue.

Changes

  • add the missing .mono rule (font-family: var(--mono)) so the sharing table's Key column renders monospace like it was always meant to. Alignment is deliberately left untouched: the prototype writes class="num" on that same cell, which would additionally right-align it — this change only restores the monospace face.
  • restore .nb { white-space: nowrap } in ui/css/style.css
  • re-introduce the <span class="nb">token plan</span> wrapper for both languages. applyStatic() injects i18n values via innerHTML, so the span lives in the login.brand.headline values of ui/js/i18n.js (ZH + EN); markup inside i18n values is already established for login.foot and ops.users.sub. The static ZH default in ui/index.html is kept byte-identical to the i18n value so no first-paint flash is introduced.
  • bump the asset cache-bust token ?v=20260911-5 → ?v=20260911-6 (5 refs)
  • 涉及配置/数据结构的改动已同步示例文件 — no config or data-structure change in this PR

Tests

  • cargo test 全部通过 — 148 passed / 0 failed
  • cargo fmt --check 通过
  • cargo clippy --all-targets -- -D warnings clean; node --check on api.js / data.js / i18n.js / app.js all OK
  • 新增/更新了单元测试(如适用)— not applicable: this is CSS/i18n-string markup only, and the existing Rust suite has no front-end coverage. Evidence is provided by headless computed-style probes instead (below).

Evidence (headless computed styles — not eyeballing)

A/B over two trees produced by the same harness generator (pre-fix tree exported with git archive HEAD ui, post-fix tree = the working tree), identity-keyed measurements:

Probe Before After
.mono Key-cell font-family (both langs) -apple-system, "system-ui", … (inert) ui-monospace, SFMono-Regular, Menlo, Consolas, …
Key-cell text-align start start (unchanged, intentional)
Sibling .num cell (control) right + tabular-nums right + tabular-nums (no regression)
Headline DOM span.nb absent present, computed white-space: nowrap
token vs plan line tops @1024 137 vs 185 → split 137 == 137 → same line
token vs plan line tops @1280/@1440/@1912 149 vs 203 → split 149 == 149 → same line
Reset-layer regression guard (classless native controls) 0 / 140 0 / 140
i18n parity gate ZH 762 == EN 762, 0 unresolved ZH 762 == EN 762, 0 unresolved
classparity.py bucket [1] (referenced, no rule) 4 3 — only the disproved JS toggle hooks remain
classparity.py bucket [3] (missing global rules) 0 0 — reset layer stays complete

Checklist

  • 分支命名符合约定(fix/ui-class-parity-mono-nb)
  • Commit message 使用 Conventional Commits 格式
  • 单一职责,改动最小化 — one topic (class parity from the prototype) across three files

Two class-parity defects measured by the C1986 audit (`tmp/classparity.py`,
three independent extractions) are fixed here; both were silent, because the
affected elements still rendered — just without the intended styling rule.

1. `.mono` was referenced but never defined anywhere
   The sharing table's Key cell has been written as `<td class='mono'>` since the
   initial UI commit (d70e032) while no commit ever contained a `.mono` rule, so
   the cell fell back to the UI font. Measured (headless computed styles, both
   themes/languages): before `font-family: -apple-system, "system-ui", …` and
   `font-variant-numeric: normal`, while the `.num` cells in the same row got
   `ui-monospace, …` + `tabular-nums`. After: `ui-monospace, …`. Alignment is
   deliberately left alone (the prototype writes `class="num"` on that cell,
   which would also right-align it); this only restores the monospace face.

2. `.nb` (white-space: nowrap) lost together with its span
   The login brand headline used to wrap "token plan" in `<span class="nb">`, and
   the prototype defines `.nb { white-space: nowrap }` (line 132) so the phrase
   never breaks. Both the span and the rule were dropped in the migration, and
   the ZH headline then broke inside the phrase. Measured at 1024/1280/1440/1912:
   before, `token` and `plan` sat on different lines (top 137 vs 185, 149 vs 203)
   in all four widths; after, both on the same line (137==137, 149==149), with a
   real `<span class="nb">` in the DOM whose computed white-space is `nowrap`.
   Since `applyStatic()` injects i18n values via `innerHTML`, the span lives in
   the `login.brand.headline` values for both ZH and EN (markup inside i18n
   values already exists for `login.foot` / `ops.users.sub`); the static ZH
   default in index.html is kept identical to the i18n value.

Also bumps the asset cache-bust token `?v=20260911-5` -> `?v=20260911-6` (5 refs)
so the CSS/JS changes are picked up.

Verification
- `cargo test`: 148 passed / 0 failed
- `cargo fmt --check` clean, `cargo clippy --all-targets -- -D warnings` clean
- `node --check` on api.js / data.js / i18n.js / app.js: all OK
- i18n parity gate: ZH 762 == EN 762, 0 unresolved
- `classparity.py`: bucket [1] 4 -> 3 (only the disproved JS toggle hooks
  `admin-pane` / `ops-pane` and the globally-covered `tx-count` remain), bucket
  [2] 17 -> 16 (`.cap` resolved as a deliberate rename to `.recent-label`),
  bucket [3] still 0 -> the global reset layer stays complete.
- A/B acceptance probe over both trees built by the same generator
  (`git archive HEAD ui` vs the working tree): `.mono` monospace false -> true in
  both languages; `.nb` phrase split true -> false at every measured width.
- Reset-layer regression guard re-run: native control count still 0 / 140.
@argszero
argszero merged commit b4b3fbd into main Sep 11, 2026
1 check passed
argszero added a commit that referenced this pull request Sep 14, 2026
Ships the 76 PRs merged since v0.7.22 (#161-#237), the largest release so far.
Database schema moves 12 -> 14:

- v13 (#217): `keys.used` changes unit from tokens to points, and the live
  values are healed from the ledger (`used = SUM(transactions.pts WHERE
  type='consume')`), gated on schema_version < 13.
- v14 (#234): four indexes for the monthly aggregates —
  `transactions(user_id, time, type, pts)`, `transactions(time, type, pts)`,
  `usage_records(time)`, `usage_records(user_id, time)`.

Deployments must apply the DeepSeek flash rename (#233) to their own
config.toml: `seed_models` is a full sync, so a model absent from the config is
deleted at startup; the retired names are gone from config.example.toml.

- Cargo.toml / Cargo.lock: 0.7.22 -> 0.7.23.
- ui/index.html: asset cache-bust 20260912-4 / 20260912-5 / 20260914-1 /
  20260914-4 / 20260914-9 -> 20260914-10 (all five refs).
- CHANGELOG.md: v0.7.23 entry, grouped by area with the PR and hash of each fix.

Gates: `cargo test` 249 passed / 0 failed, `cargo fmt --check` clean,
`node --check` on the four ui/js files OK.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant