Skip to content

Add an "Increase contrast" accessibility setting to Appearance #66

Description

@DragonnZhang

Problem or Motivation

OpenWork's Settings → Appearance → Interface section already offers one
accessibility affordance — the Reduce motion toggle (shipped in #51). But it
has no way to increase visual contrast. Today the app's borders, dividers,
input outlines and secondary/"muted" text are intentionally low-contrast
(derived from --foreground at very low alpha, e.g. --border is
oklch(from var(--foreground) l c h / 0.05) and --muted-foreground is only a
50% mix in apps/electron/src/renderer/index.css). That looks clean but is hard
to read for low-vision users and in bright environments.

Increasing contrast is a standard desktop-app accessibility control that
OpenWork's peers expose and OpenWork lacks:

  • macOS — System Settings → Accessibility → Display → Increase contrast.
  • WindowsContrast themes.
  • VS Code (which Claude Code / Codex desktop build on) — dedicated
    High Contrast themes.
  • Claude Desktop / ChatGPT desktop — standing accessibility asks for a
    higher-contrast reading mode.

Reduce motion is already here; Increase contrast is its natural companion in
the same Interface section.

Proposed Solution

Add an "Increase contrast" toggle to Settings → Appearance → Interface,
directly below the existing Reduce motion toggle. It is a renderer-only,
frontend preference — no backend involvement:

  • Persist it in localStorage (new key craft-high-contrast), mirroring
    Reduce motion's craft-reduce-motion and the other lightweight prefs in
    apps/electron/src/renderer/lib/local-storage.ts.
  • Provide it app-wide via a small HighContrastProvider context (mirroring
    ReduceMotionContext), wired in main.tsx.
  • When enabled, set data-high-contrast="true" on <html>. A global CSS block
    in index.css gated on :root[data-high-contrast='true'] then raises the
    contrast of theme tokens
    — strengthening --border, --input,
    --muted-foreground, --foreground-dimmed and the focus --ring, and adding
    a visible focus outline. Because every theme derives these tokens from
    --foreground (which flips per light/dark), the alpha-based overrides work in
    both light and dark and across preset themes.
  • Add two i18n keys (settings.appearance.increaseContrast /
    ...Desc) across all 7 locales, matching how reduceMotion is localized.

Off by default, so existing users see no change.

Feasibility

Frontend-only — confirmed feasible. This is the exact mechanism the merged
Reduce motion feature uses (localStorage pref → React context → <html> data
attribute → CSS guard). No qwen-code backend change is required. Theme variables
are injected as a :root { … } stylesheet rule
(ThemeContext.tsx), so a higher-specificity :root[data-high-contrast='true']
selector overrides them cleanly without !important.

Acceptance Criteria (what the CDP assertion will check)

Driven over CDP in the draft/no-session state (no backend), mirroring the
reduce-motion assertion:

  1. Open Settings → Appearance; the Increase contrast toggle renders and
    is off initially, with no data-high-contrast attribute on <html>.
  2. Enabling it: the switch reads aria-checked="true", <html> gains
    data-high-contrast="true", localStorage['craft-high-contrast'] === "true",
    and the high-contrast CSS actually applies (a dedicated
    --hc-enabled custom property computes to 1 on :root).
  3. Disabling it reverts all four: switch off, attribute removed,
    localStorage "false", and --hc-enabled no longer 1 — proving it both
    applies and reverts, not merely renders.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions