feat(ios): adopt ScarfDesign across the iOS app

AccentColor.colorset repointed to BrandRust hex (light + dark) so the
tab bar, every .tint, every default button, and every navigation
accent across all 5 tabs read rust automatically. Single-line fix,
biggest visible change.

ScarfDesign now imported across all 27 iOS view files. Color sweep
applies the same patterns as the Mac side, with two iOS-specific
deviations documented in CLAUDE.md:

- ScarfPageHeader is NOT retrofitted onto iOS tab roots. iOS uses
  .navigationTitle(...) + .navigationBarTitleDisplayMode(.large) as
  its native page-header pattern; stacking ScarfPageHeader on top
  creates double titles. ScarfPageHeader is reserved for sub-views
  without a native large-title bar.

- Only .borderedProminent → ScarfPrimaryButton. .bordered and .plain
  stay native because .bordered is the iOS convention for non-primary
  buttons and inherits rust through AccentColor automatically.

Dynamic Type policy (locked + documented in CLAUDE.md): preserve
.font(.headline)/.body/.caption semantic tokens for body copy, list
rows, error messages, and chat content (anything read for content).
Use ScarfFont only for status badges, chip labels, intentional fixed-
size display elements. Mass-swapping ScarfFont on iOS would regress
accessibility for users on .accessibility2 / .xSmall.

Files touched (27 view files + AccentColor + CLAUDE.md):

- Color sweep: .foregroundStyle(.secondary) → ScarfColor.foregroundMuted,
  Color(.secondarySystemBackground) → ScarfColor.backgroundSecondary,
  status colors (.orange/.green/.red) → ScarfColor.warning/success/danger
  in: Dashboard, Skills (root + Installed + Hub + Updates + Detail),
  Projects (root + Detail + Sessions + Site + 8 widgets), Memory
  (List + Editor), Cron, Settings (root + Editor), Servers, Chat
  (root + Picker + Slash browser), Onboarding.

- Primary button swap (5 files): Chat, Projects/Sessions, Skills/
  Updates, Skills/Hub, Onboarding.

- CLAUDE.md: appended "iOS Dynamic Type policy" + "iOS page chrome"
  guidance under the existing Design System section.

Both Mac (scarf) and iOS (scarf mobile) schemes build green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alan Wizemann
2026-04-25 15:08:46 +02:00
parent 23dd8becb9
commit de611c5343
30 changed files with 141 additions and 96 deletions
+17
View File
@@ -34,6 +34,23 @@ All app UI uses the typed token bundle in [scarf/Packages/ScarfDesign/](scarf/Pa
- **Reference**: full screen mockups live at `design/static-site/ui-kit/*.jsx` (open `design/static-site/index.html` in a browser). The `ScarfChatView.ChatRootView` reference component in the package is a 3-pane chat redesign target — usable for previews but not yet swapped into the live chat (the existing `RichChatView` machinery still owns the real ACP pipeline).
- **Don't**: introduce purple/violet tones (we shifted to rust); use yellow `#F0AD4E` for success (that's `.warning``.success` is green); bypass the type scale with `.font(.system(size: 13.5))`; ship terminal/syntax-highlight palettes through ScarfColor (those are content semantics, keep them inline).
### iOS Dynamic Type policy
iOS users can scale text via Settings → Accessibility → Display & Text Size. ScarfFont uses fixed point sizes; adopting it blanket on iOS would regress accessibility on `.accessibility2` / `.xSmall` users. iOS-specific rule:
- **Use `ScarfFont` only for**: status badges, chip labels, intentional-display elements (e.g., onboarding step titles, header chrome that's meant to be a fixed visual size).
- **Keep `.font(.headline)` / `.body` / `.caption` semantic tokens for**: list-row primary + secondary text, body copy, error messages, chat content — anything the user reads.
Decision tree per text element: "is this read for content?" → semantic token. "Is this chrome / a label / a badge?" → ScarfFont.
Mac doesn't have this constraint and adopts ScarfFont everywhere. The iOS app already clamps Dynamic Type at the scene root (`ScarfIOSApp.swift`: `.dynamicTypeSize(.xSmall ... .accessibility2)`) — keep that.
### iOS page chrome
Don't retrofit `ScarfPageHeader` over iOS tab roots. iOS uses `.navigationTitle(...)` + `.navigationBarTitleDisplayMode(.large)` as its native page-header pattern; stacking ScarfPageHeader on top creates double titles. Use ScarfPageHeader only on iOS sub-views without a native large-title bar (rare).
iOS button styling: only swap `.borderedProminent``ScarfPrimaryButton`. **Leave `.bordered` native** — it's the iOS convention and inherits rust through `AccentColor.colorset` automatically. Same for `.plain` (used as compact tap targets in lists).
## Key Paths
- Hermes home: `~/.hermes/`