Skip to content

UI refactor P0: design-token foundation + full hex/font sweep behind a permanent gate#97

Merged
dovvnloading merged 1 commit into
mainfrom
refactor/ui-p0-design-tokens
Jul 22, 2026
Merged

UI refactor P0: design-token foundation + full hex/font sweep behind a permanent gate#97
dovvnloading merged 1 commit into
mainfrom
refactor/ui-p0-design-tokens

Conversation

@dovvnloading

Copy link
Copy Markdown
Owner

Summary

Phase P0 of the UI refactor plan (from the QA audit): one design-token source feeding both rendering stacks, and the elimination of scattered hardcoded styling.

Recorded decision: rather than introducing a parallel JSON token file, P0 extends the codebase's existing single source — graphlink_styles.py — whose THEME_TOKENS already feed runtime island injection and the generated Tailwind theme. A second source would have forked truth.

Foundation

  • STRUCTURE_TOKENS — theme-independent scales: spacing (4px grid), radius (sm/md/lg), type ramp (12/13/14/16/20 — nothing under 12px), 3 elevation shadow levels, motion (150/200ms + easing). Exported to every island as --gl-* vars, registered under Tailwind v4's proper namespaces (--spacing-*/--radius-*/--text-*/--font-weight-*/--shadow-*/--duration-*/--ease-*), mirrored as Qt-side ints (SPACE_PX/RADIUS_PX/TEXT_PX/ELEVATION_PARAMS) parsed from the same dict so the representations cannot drift.
  • surface group (per-theme) — the clean neutral role vocabulary native painting/stylesheet code migrated onto. Dark values equal the exact hexes being replaced → essentially byte-neutral migration; mono/muted derived coherently.
  • syntax group (per-theme) — the code highlighter's palette, relocated from graphlink_pycoder.py.
  • FONT_FAMILY_NAME + get_surface_color()/get_syntax_color() lookups.

Sweep

~500 hex literals + ~40 "Segoe UI" strings across ~35 UI files replaced with token lookups (4 parallel sweep passes + centrally-adjudicated finalization). Module-level scrollbar-style constants became functions so stylesheets resolve the live theme instead of freezing at import. Persisted scene-data defaults deduped onto documented constants.

The gate

tests/test_ui_token_acceptance.py makes the acceptance criterion permanent: no hex literal and no "Segoe UI" outside graphlink_styles.py, minus a small reasoned allowlist (export CSS, user-pickable presets, persisted data defaults, the per-theme QMenu table that P8 retires) — plus structure-scale conformance tests.

Test plan

  • Full pytest: 1742 passed (gate green; export round-trip/count/shape tests updated for the new groups)
  • vitest: 533 passed
  • All 19 islands rebuilt against the extended token sheet
  • Real app launch: window up, zero log errors (dark-theme visuals byte-neutral by construction)

Phase P0 of the audit's refactor plan; P1 (overlay/dialog manager) follows.

…a permanent gate

First phase of the UI refactor plan (doc/UI_QA_AUDIT.md section 7).

Foundation - graphlink_styles.py is THE token source (recorded decision:
extending the existing THEME_TOKENS/runtime-injection pipeline instead of
introducing a parallel JSON file that would fork truth):
- STRUCTURE_TOKENS: theme-independent scales - spacing on a 4px grid
  (--gl-space-1..8), radius sm/md/lg, type ramp 12/13/14/16/20 (nothing
  under 12px - audit finding D2), three elevation shadow levels (finding
  B9), motion 150/200ms + easing (finding F4). Exported to every island
  and registered under Tailwind v4's PROPER namespaces (spacing/radius/
  text/font-weight/shadow/duration/ease - not bogus color utilities), with
  Qt-side integer mirrors (SPACE_PX/RADIUS_PX/TEXT_PX/ELEVATION_PARAMS)
  parsed from the same dict so the two representations cannot drift.
- New per-theme "surface" group: the clean neutral role vocabulary
  (window/node_body/inset/inset_deep/field/border/border_strong/divider/
  handle/handle_hover/chrome_inactive + a 6-tier text ramp). Dark values
  equal the exact hexes that dominated the swept files, so the migration
  is essentially byte-neutral in the default theme; mono/muted derive
  from each theme's existing neutrals.
- New per-theme "syntax" group: PythonHighlighter's palette relocated
  from graphlink_pycoder.py so code-node colors theme with everything else.
- FONT_FAMILY_NAME (bare name for QFont) beside the existing QSS stack;
  get_surface_color()/get_syntax_color() lookups in graphlink_config.

Sweep - ~500 hardcoded hex literals and ~40 string-pasted "Segoe UI"
occurrences across ~35 UI files replaced with token lookups (4 parallel
sweep passes + a centrally-adjudicated finalization: near-role neutrals
deduped onto the role scale within a sanctioned sub-perceptual tolerance;
semantic/data colors either matched byte-exact to existing semantic roles,
promoted into the new groups, or explicitly allowlisted). Module-level
scrollbar style constants became functions so stylesheets resolve the
LIVE theme instead of freezing at import. Persisted scene-data defaults
(container color) deduped onto one documented constant.

Gate - tests/test_ui_token_acceptance.py codifies the P0 acceptance
criterion permanently: no hex literal and no "Segoe UI" outside
graphlink_styles.py, excepting a small reasoned allowlist (export CSS,
user-pickable presets, persisted data defaults, the per-theme QMenu table
that phase P8 retires); plus structure-scale conformance (4px grid, 12px
type floor, 3 elevation levels).

Verified: full pytest 1742 passed (acceptance gate green, export
round-trip/count/shape tests updated for the new groups); vitest 533
passed; all 19 islands rebuilt against the extended token sheet; real app
launch clean (window up, zero log errors).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dovvnloading
dovvnloading merged commit 3d1bd5f into main Jul 22, 2026
2 checks passed
@dovvnloading
dovvnloading deleted the refactor/ui-p0-design-tokens branch July 22, 2026 12:49
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