Skip to content

[Refactor] Complete UI contract: density tokens, layout tokens, persistence, and dead code cleanup#165

Merged
samzong merged 2 commits intomainfrom
ui-contract-refactor
Mar 25, 2026
Merged

[Refactor] Complete UI contract: density tokens, layout tokens, persistence, and dead code cleanup#165
samzong merged 2 commits intomainfrom
ui-contract-refactor

Conversation

@samzong
Copy link
Copy Markdown
Collaborator

@samzong samzong commented Mar 25, 2026

Summary

Complete the UI contract system by wiring density tokens end-to-end, adding layout tokens, building the density settings UI, and cleaning up dead code. This closes the gap where density switching had no effect on buttons, inputs, or avatars, and where max-w-3xl was duplicated across 5 files with no single source of truth.

Type of change

  • [Refactor] internal cleanup
  • [UI] UI or UX change

Why is this needed?

The ui-contract-refactor branch established the theme token system and CI checker, but left density tokens unconnected: buttons, search inputs, form inputs, and chat avatars all used hardcoded Tailwind classes (h-9, h-10, w-8 h-8, max-w-3xl). Switching density mode (compact/comfortable/spacious) had no visible effect on these elements. There was also no user-facing UI to change density, and the setting wasn't persisted across restarts.

What changed?

  • New density tokens in theme.css: --density-control-height (3 tiers), --density-avatar-size — each with compact/comfortable/spacious values
  • New layout token: --content-max-width in @theme block (replaces 5× max-w-3xl)
  • Density persistence: Added density field to AppConfig (main) and AppSettings (preload); ThemeProvider now loads and persists density via independent effects
  • Consumer migration (~12 files): button.tsx size variants, search inputs, form inputs, chat avatars, content max-width all use tokens
  • Density settings UI: New SegmentedControl in GeneralSection (compact/comfortable/spacious) with i18n (en + zh)
  • Checker: +1 rule hardcoded-content-width to prevent max-w-3xl regression
  • Dead code removed: AppPanel.tsx, DataList.tsx (0 imports), Settings/components/SettingRow.tsx (unnecessary re-export shim); 3 unused CSS vars (--radius, --shadow-color, --state-disabled-opacity)
  • Stagger delay: Extracted STAGGER_STEP constant in design-tokens.ts

Architecture impact

  • Owning layer: renderer (tokens, components, layouts), main (config type), preload (type bridge)
  • Cross-layer impact: yes — density field added to AppConfig (main/workspace/config.ts) and AppSettings (preload/clawwork.d.ts). IPC handlers are generic Partial<AppConfig> so no handler changes needed.
  • Invariants touched from docs/architecture-invariants.md: none — density follows the same persistence pattern as theme (ThemeProvider effect → updateSettings → IPC → config file)
  • Why those invariants remain protected: single-writer pattern preserved; ThemeProvider is sole owner of density persistence; GeneralSection only calls setDensity(), never updateSettings directly

Linked issues

Part of the ui-contract-refactor branch work.

Validation

  • pnpm lint
  • pnpm test
  • pnpm check:ui-contract
  • pnpm check (full pipeline: lint + architecture + ui-contract + renderer-copy + format + typecheck + test)
  • Manual smoke test
  • pnpm build

Commands, screenshots, or notes:

```text
pnpm check — all green (89/89 tests pass, 0 UI contract violations)
Test fix: settings-ui-regressions expects 2 updateSettings calls (theme + density)
```

Screenshots or recordings

No screenshots — density UI is a standard SegmentedControl matching existing theme toggle pattern. Comfortable mode values match previous hardcoded values (zero visual regression).

Token changes: --density-control-height (32/36/40px), --density-control-height-sm (28/32/36px), --density-control-height-lg (36/40/44px), --density-avatar-size (28/32/36px), --content-max-width (48rem). New checker rule hardcoded-content-width prevents max-w-3xl regression.

Release note

  • User-facing change. Release note is included below.

```release-note
Add display density setting (compact/comfortable/spacious) that adjusts button heights, input sizes, and chat avatar dimensions across the app. Setting persists across restarts.
```

Checklist

  • The PR title uses at least one approved prefix: [Feat], [Fix], [UI], [Docs], [Refactor], [Build], or [Chore]
  • The summary explains both what changed and why
  • Validation reflects the commands actually run for this PR
  • Architecture impact is described and references any touched invariants
  • Cross-layer changes are explicitly justified
  • The release note block is accurate

Signed-off-by: samzong <samzong.lu@gmail.com>
@github-actions
Copy link
Copy Markdown
Contributor

Hi @samzong,
Thanks for your pull request!
If the PR is ready, use the /auto-cc command to assign Reviewer to Review.
We will review it shortly.

Details

Instructions for interacting with me using comments are available here.
If you have questions or suggestions related to my behavior, please file an issue against the gh-ci-bot repository.

@samzong
Copy link
Copy Markdown
Collaborator Author

samzong commented Mar 25, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5dc15b64f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/desktop/src/renderer/App.tsx Outdated
/>
<Toaster
theme={theme === 'auto' ? 'system' : theme}
theme={resolvedTheme}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Toaster in system mode for auto theme

Passing resolvedTheme here hard-codes Sonner to 'light'/'dark' even when the user selected auto theme. In this commit, ThemeProvider handles OS theme changes by mutating document.documentElement directly, not by updating React state, so useResolvedTheme() does not necessarily update when the system theme flips at runtime; both toasters can remain on the old palette until an unrelated rerender. Keep using 'system' for auto mode (or make resolved theme stateful on media-query changes) so toast styling tracks OS theme changes immediately.

Useful? React with 👍 / 👎.

Signed-off-by: samzong <samzong.lu@gmail.com>
@samzong samzong force-pushed the ui-contract-refactor branch from 876b43e to d13067d Compare March 25, 2026 11:15
@samzong samzong merged commit 8fe1e28 into main Mar 25, 2026
6 checks passed
@samzong samzong deleted the ui-contract-refactor branch March 29, 2026 14:11
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