Skip to content

Add interface zoom (⌘+ / ⌘- / ⌘0) to scale the whole app#69

Open
DragonnZhang wants to merge 2 commits into
mainfrom
loop/interface-zoom
Open

Add interface zoom (⌘+ / ⌘- / ⌘0) to scale the whole app#69
DragonnZhang wants to merge 2 commits into
mainfrom
loop/interface-zoom

Conversation

@DragonnZhang

Copy link
Copy Markdown
Collaborator

Closes #68

What & why

Every desktop app OpenWork is benchmarked against — Claude Desktop, VS Code, Codex/ChatGPT desktop, Slack, Discord — exposes an interface zoom that scales the whole UI up or down via the platform-standard ⌘+ / ⌘- / ⌘0 (Ctrl on Windows/Linux). OpenWork had none: grep -rn "setZoomLevel\|zoomFactor\|webFrame\|zoom" apps/electron/src found nothing, and there was no such binding in the action registry. Users on high-DPI displays (or who want to fit more on screen) had no way to resize the whole app.

This adds an app-wide interface-zoom preference — frontend-only, no backend / qwen-code change.

Distinct from any per-surface "chat text size" / "conversation width" work: interface zoom scales the entire renderer (sidebar, navigator, chat, settings, dialogs, composer), not just message text.

How

  • context/ZoomContext.tsx (new) — ZoomProvider, mirroring the merged ReduceMotionProvider. Owns a discrete zoom factor from a Chrome-like step ladder (50%–200%), applies it by setting document.documentElement.style.zoom (a Chromium-native property that scales the whole tree, including portalled dialogs), and clears the inline style at 100%. Persists in localStorage (craft-zoom-level) via the existing lib/local-storage.ts helper — no IPC, no config.json.
  • actions/definitions.ts — three new View actions: view.zoomIn (mod+=), view.zoomOut (mod+-), view.zoomReset (mod+0). Registering them means they appear automatically in the Command Palette (⌘K) and the Settings → Keyboard Shortcuts reference.
  • components/ZoomHotkeys.tsx (new) — a render-null bridge mounted inside ActionRegistryProvider that wires those actions to the provider via useAction.
  • main.tsx — mounts ZoomProvider at the renderer root (inside ReduceMotionProvider).
  • pages/settings/AppearanceSettingsPage.tsx — a Zoom stepper ( / percentage / + with reset) in Appearance → Interface, for discoverability and mouse-only users.
  • lib/local-storage.ts — new zoomLevel key.
  • actions/action-i18n.ts + locales/*.json — 5 new i18n keys across all 7 locales.
  • e2e/assertions/zoom.assert.ts (new) — CDP assertion (below).

Verification (DoD)

Run in this PR's sandbox; all checks that don't require launching Electron pass with zero delta vs main:

  • bun run typecheck:all — no new errors. apps/electron reports exactly the 11 pre-existing errors (auto-update.ts owner/repo, a settings-default-thinking test tuple, two test files importing vitest) — none in files this PR touches; all other packages clean.
  • bun test — the failing-test set is byte-for-byte identical to a clean main run in the same environment: 56 failing tests on both, diff empty. This change adds zero new failures. (The raw N fail line is order-dependent when the whole suite runs unisolated; the deterministic signal is the failing-test set.)
  • bun run lint:i18n:parity — OK (1549 keys per locale, 7 locales). The 5 new keys are in every locale.
  • eslint on all changed files — 0 errors. The new files add no warnings; the pre-existing no-localstorage / exhaustive-deps warnings are unchanged.
  • Renderer build (bun run build:renderer, where this change lives) — ✅ built cleanly.
  • CDP assertion transpiles (bun build e2e/assertions/zoom.assert.ts) — ✅.

CDP e2e assertion (zoom.assert.ts)

Drives the real built app over CDP entirely in the draft/no-session state (Settings only, no backend):

  1. Open Settings → Appearance → Interface; the Zoom control renders at 100%, with no inline zoom style on <html>.
  2. Click Zoom in → the display reads 110%, document.documentElement.style.zoom === '1.1', and localStorage["craft-zoom-level"] is 1.1 — proving it applies and persists, not merely renders.
  3. Click Reset → back to 100%, the inline zoom style is cleared, and the persisted value returns to 1.

⚠️ Local CDP run was blocked by this sandbox's egress policy, not by the feature. The Electron binary download (GitHub release host) returns 403 from the org egress proxy — its allowlist covers npm/pypi/crates but not GitHub release hosts — so Electron can't be launched here (xvfb is present; only the binary fetch fails; the proxy README says to report such policy denials, not route around them). The assertion transpiles and is included so CI / a reviewer can run bun run e2e in an environment with normal network access. Everything that doesn't require launching Electron (typecheck, unit tests, i18n parity, lint, renderer build) passes with zero delta vs main. This is the same documented environment limitation as the merged reduce-motion PR (#51).

Part of the autonomous desktop-feature loop (loop-bot).

🤖 Generated with Claude Code


Generated by Claude Code

Adds an app-wide interface-zoom preference that scales the entire renderer
(sidebar, navigator, chat, settings, dialogs) up or down, matching the
standard desktop zoom in Claude Desktop, VS Code, and other apps.

- ZoomProvider (renderer context, mirrors ReduceMotionProvider): owns a
  discrete zoom factor from a Chrome-like step ladder (50%-200%), applies it
  via document.documentElement.style.zoom, and persists it in localStorage
  (craft-zoom-level). Frontend-only; no IPC, no backend, no config.json.
- Three action-registry entries under View - view.zoomIn (mod+=),
  view.zoomOut (mod+-), view.zoomReset (mod+0) - so the shortcuts appear in
  the Command Palette and Keyboard Shortcuts reference for free. Wired to the
  provider via a ZoomHotkeys bridge component.
- A Zoom stepper (-/percentage/+ with reset) in Settings > Appearance >
  Interface for discoverability and mouse-only users.
- i18n keys added to all 7 locales.
- CDP e2e assertion (zoom.assert.ts) drives the stepper and asserts the
  percentage, the inline zoom on <html>, and the persisted value.

Closes #68
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add interface zoom (⌘+ / ⌘- / ⌘0) to scale the whole app up or down

2 participants