Skip to content

style: typography pass — drop hardcoded sizes + NSColor.white onto the design scale#18

Merged
DaxxSec merged 1 commit into
mainfrom
feat/typography-pass
May 13, 2026
Merged

style: typography pass — drop hardcoded sizes + NSColor.white onto the design scale#18
DaxxSec merged 1 commit into
mainfrom
feat/typography-pass

Conversation

@DaxxSec
Copy link
Copy Markdown
Owner

@DaxxSec DaxxSec commented May 13, 2026

Why

User feedback after the merged redesign:

The font is off as well as button look + styles everywhere in the app

Targeted sweep at the specific offenders rather than a wholesale rewrite.

NSColor.white → AppColors.textPrimary

Three callsites total — all on dark-themed checkboxes / labels:

  • `PacketAnalysisWindowController`: `autoScrollCheckbox` tint, `filterLabel`
  • `VMLibraryWindowController`: `arpCheckbox` tint

NSColor.white is the maximum-contrast value (1.0/1.0/1.0). Against the tactical dark grey palette that reads as visually too hot — like a headlight. AppColors.textPrimary (0.910 / 0.922 / 0.941) is slightly-off-white, calibrated to look like text, not glare, and it's the value every other label in the dark UI already uses.

Hardcoded font sizes → LayoutConstants scale

Five offenders pulled onto the existing scale:

Where Was Now (LayoutConstants)
VM library sidebar brand wordmark 16 fontSizeHeader (15)
VM library info labels (bold/regular) 13 / 11 fontSizeSubtitle / fontSizeBody
VM library log section buttons 13 fontSizeSubtitle
VM library ARP filter checkbox 11 fontSizeBody
Switch Statistics text view 12 fontSizeBody
ISO Cache Manager toolbar button 12 fontSizeBody

Chosen mappings are the closest scale value in each case — no semantic shifts. Body text doesn't get promoted to subtitle just because it was 12pt before.

Out of scope

Sizes 9 / 10 / 11 that already match fontSizeCaption / fontSizeSmall / fontSizeBody numerically aren't the user's complaint — they look right, they're just spelled with raw integers instead of symbolic names. A separate mechanical refactor can pull those onto symbols if it matters later.

Test plan

  • `xcodebuild build` succeeds
  • Launch app, open Packet Analysis: checkbox + filter label tint reads as the same off-white as the table body text, not glaring white
  • Library window: ARP filter checkbox tint matches the rest of the dark UI
  • Sidebar brand block: "SecVF" wordmark is one notch smaller (15pt vs 16pt), reads as proportional to the small tag underneath instead of slightly overpowering it
  • Switch Statistics + ISO Cache windows: monospaced body text is 11pt (was 12pt), matches the body-text size elsewhere

🤖 Generated with Claude Code

…e design scale

User feedback: "the font is off as well as button look + styles
everywhere in the app". A targeted sweep here, focused on the
specific offenders rather than a wholesale rewrite:

NSColor.white → AppColors.textPrimary
=====================================
Three callsites total in the app, all on dark-themed checkboxes /
labels:
- PacketAnalysisWindowController: autoScrollCheckbox tint, filterLabel
- VMLibraryWindowController:       arpCheckbox tint

`NSColor.white` is the maximum-contrast value (pure 1.0,1.0,1.0)
which against the tactical dark grey reads as visually too hot.
`AppColors.textPrimary` is the same color the rest of the dark UI
uses (RGB 0.910 / 0.922 / 0.941) — slightly off-white, calibrated
to look like text, not headlight.

Font sizes onto the LayoutConstants scale
=========================================
Five hardcoded sizes pulled onto the existing type scale:

- VMLibraryWindowController sidebar brand wordmark: 16 → fontSizeHeader (15)
- VMLibraryWindowController info labels: 13/11 → fontSizeSubtitle/Body
- VMLibraryWindowController log section buttons: 13 → fontSizeSubtitle
- VMLibraryWindowController ARP filter checkbox: 11 → fontSizeBody
- SwitchStatisticsWindowController text view: 12 → fontSizeBody
- ISOCacheManagerWindow toolbar button: 12 → fontSizeBody

Why this set: anything ≥ 12 and ≤ 17 that wasn't already routed
through `LayoutConstants.fontSize*` was off-scale. The chosen
mapping is the closest scale value in each case — no semantic
shifts (e.g. body text isn't promoted to subtitle just because
it was 12pt before).

Out of scope
============
Sizes 9, 10, and 11 that match `fontSizeCaption` / `fontSizeSmall` /
`fontSizeBody` exactly are not the user's complaint — those are
already on-scale numerically, just not symbolically. Pulling them
onto symbolic names is mechanical busywork that doesn't change
how anything looks. A separate refactor can do that pass if it
matters later.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@DaxxSec DaxxSec force-pushed the feat/typography-pass branch from 62db98f to cafb0f8 Compare May 13, 2026 16:48
@DaxxSec DaxxSec merged commit e06a3f6 into main May 13, 2026
1 check passed
DaxxSec added a commit that referenced this pull request May 14, 2026
* fix(ui): three layout regressions from the typography pass merge

Three visible regressions that the user reported after #15+#18 landed:

1. Sidebar section titles truncating ("ERATING SYSTEM", "TWORK", "GS")
==================================================================
`TacticalSidebarSection.rebuild()` runs inside `init` before the
caller has set the section's frame. It read `bounds.width` (=0 at
that moment) and gave the title label / row views
`width: bounds.width - inset * 2` = **-24pt**. The autoresizing mask
(`.width`) compensates when the parent's bounds change, but it adds
delta only — a section that grows from `bounds.width = 0` to `220`
produces a title width of `-24 + 220 = 196`. That should be visible
end-to-end, but NSTextField that's first sized with a negative-width
frame caches its rendering metrics and the title gets visually
left-truncated by ~inset pixels on every paint after.

Fix: defer layout. `rebuild` now adds the subviews without sizing
them; a new `relayoutContents()` runs from both `rebuild` (so the
initial paint has a valid frame once the caller assigns one) AND
from `layout()` (Cocoa hook fired whenever the section's bounds
resolve). Layout constants moved to type-level statics so the two
call sites share them.

2. VM table rows squished to ~20pt — multi-line card not showing
================================================================
The XIB hardcodes `tableView rowHeight="20"`. `switchTableToCardMode`
sets `tableView.rowHeight = 62`, which SHOULD be authoritative — but
when the XIB latches the lower value before the awakeFromNib call
that runs the swap, NSTableView's first layout pass uses the latched
20pt and the card cell renders as a single squished line with
row-3 chips spilling into row-1's name area.

Fix: implement `tableView(_:heightOfRow:)` returning
`VMCardCellView.rowHeight`. The delegate is queried on every row
draw, so the value can't be stale or pre-empted by the XIB.

3. Detail-card status pill drifts off-center inside its 80pt bounds
====================================================================
The pill is an NSTextField with `alignment = .center`,
`isBordered = false`, layer-backed background. On some macOS
revisions the plain `alignment` property doesn't fully center
text inside a borderless layer-backed label — the text drifts
leftward, producing the dead-space halo on the right that
appears as "the pill is spaced wrong".

Fix: use `attributedStringValue` with an explicit centered
NSMutableParagraphStyle. The paragraph-style centering bypasses
NSTextField's plain alignment quirk and works deterministically.

No behavior changes — these are all visual/positioning fixes.
Full test suite still 292/292 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ui): the VM-card row pill (the one user actually meant)

User clarified the "pill is spaced wrong" report — they meant the
status pill inside the VM-card row (e.g. "● RUNNING" / "○ STOPPED"
on the right edge of row 1), not the detail card pill at the bottom
of the window. My previous commit on this PR fixed the wrong pill.

Same root cause + fix: NSTextField's plain `alignment = .center`
drifts leftward on layer-backed borderless labels. Apply explicit
centered NSMutableParagraphStyle via attributedStringValue on the
VMCardCellView statusPill (running-state path) and the AI Sandbox
TEMPLATE/SESSION pill (sandbox-bundle path).

The previous fix to the detail card's makeStatusPill stays — same
class of bug, two separate widgets, both needed the treatment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: DaxxSec <dax@example.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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