Skip to content

Add dark mode support for content frame#2652

Open
shaunandrews wants to merge 26 commits intotrunkfrom
add-dark-mode-support
Open

Add dark mode support for content frame#2652
shaunandrews wants to merge 26 commits intotrunkfrom
add-dark-mode-support

Conversation

@shaunandrews
Copy link

@shaunandrews shaunandrews commented Feb 24, 2026

Summary

  • Add system-preference dark mode (prefers-color-scheme: dark) for the content frame area while keeping the sidebar chrome permanently dark
  • Define 14 CSS custom properties (--color-frame-*) with dark mode overrides, mapped to Tailwind tokens (frame-*)
  • Enable Electron nativeTheme.themeSource = 'system' so the renderer respects OS preference
  • Add dark mode CSS override block using :is() for WP component classes (inputs, buttons, tabs, modals, popovers, menus)
  • Make the Button component dark-mode-aware by replacing hardcoded text-black/bg-white with frame-* tokens
  • Migrate ~40 component files from hardcoded colors (text-gray-*, bg-white, border-gray-*, hex values) to semantic frame-* tokens
image

Test plan

  • Toggle system appearance to dark mode and verify the content frame background changes to #2F2F2F
  • Verify sidebar chrome remains unchanged in both modes
  • Check all 6 content tabs (Overview, Sync, Previews, Import/Export, Settings, Assistant)
  • Open the "Add a site" fullscreen modal and verify all text, inputs, and buttons are readable
  • Open WP modals (Connect site, Edit site) and verify dark surfaces and text
  • Check dropdown menus (preview site actions, assistant chat menu)
  • Verify primary (blue) and destructive (red) button colors are preserved
  • Test the assistant chat: messages, welcome prompts, input bar, Telex banner
  • Switch back to light mode and verify no regressions

shaunandrews and others added 6 commits February 23, 2026 23:04
…d tokens

Define 14 frame-* CSS custom properties in :root with prefers-color-scheme
dark overrides. Add matching Tailwind color tokens (frame, frame-text,
frame-border, frame-surface, etc.). Enable Electron nativeTheme.themeSource
= 'system' so the renderer respects OS dark mode. Apply bg-frame and
text-frame-text to the content frame in app.tsx. Add dark mode override
block in index.css targeting WP component classes (inputs, buttons, tabs,
modals, popovers) using :is() for scoped element cascade.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded text-black with text-frame-text in secondary and link
active states. Replace bg-gray-100 with bg-frame-surface in outlined
hover/active states. Replace hover:bg-white with hover:bg-frame-surface
in icon variant. This eliminates the root cause of most !important
overrides in consumer components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The fullscreen modal renders outside both [data-testid='site-content']
and .components-modal__frame, so dark mode overrides couldn't reach its
children. Add data-fullscreen-modal attribute as a CSS hook.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… tokens

Replace bg-white, bg-gray-*, text-gray-*, text-black, border-gray-*,
and hardcoded hex colors with frame-* Tailwind tokens across all content
tab components, assistant chat UI, welcome prompts, and shared components.
Key changes: assistant tab bg-gray-50 -> bg-frame-surface, chat input
bg-frame (solid, since opacity modifiers fail on hex custom properties),
chat message borders, skeleton loaders, error states, and SVG fills.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace text-gray-900, bg-gray-50, bg-[#FAFAFA], border-gray-200,
fill='#949494', and other hardcoded colors with frame-* tokens across
all add-site components: options, create-site form, blueprints,
blueprint details/deeplinks, import backup, pull remote, and stepper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace text-gray-*, text-[#3C434A], bg-white, border-a8c-gray-0, and
other hardcoded colors with frame-* tokens in sync module (connected
sites, dialog, modal selector, environment badge, site name box), preview
site rows/headers, onboarding, and What's New modal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wojtekn wojtekn marked this pull request as draft February 24, 2026 07:56
shaunandrews and others added 7 commits February 24, 2026 11:37
…f filter invert

The invert(1) filter turned the blue hover color (#3858E9) into yellow (#C7A716).
Replace with a white-fill SVG so hover stays blue in both color schemes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… accent

Rename --color-frame-link/--color-frame-link-hover CSS custom properties
to --color-frame-theme/--color-frame-theme-hover to better reflect their
role as the app-wide accent color, not just link styling.

Also sets --wp-admin-theme-color to var(--color-frame-theme) so WordPress
component hover/focus styles (box-shadow, background) adapt to dark mode
instead of using hardcoded #3858e9.

Adds dark mode override for the assistant tab hover icon SVG data URI
(#6b8aff instead of light-mode #3858E9).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all text-a8c-blue-50, bg-a8c-blue-50, fill-a8c-blue-50,
border-a8c-blue-50, shadow-a8c-blue-50, ring-a8c-blue-50, and
outline-a8c-blue-50 class references with their frame-theme equivalents
across ~30 component and module files.

These classes now resolve through CSS custom properties, enabling
automatic dark mode color adaptation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert SVG components and inline styles from hardcoded #3858E9:
- wordpress-short-logo, blueprint-icon: use currentColor + style prop
- sync-tab-image, screenshot-demo-site: use var(--color-frame-theme)
- wordpress-logo-circle: default prop to var(--color-frame-theme)
- options.tsx: Icon fill props to var(--color-frame-theme)
- onboarding gradient: from-[var(--color-frame-theme)]
- about-menu.html: inline CSS vars with dark mode media query

SVG asset files in whats-new/assets/ left unchanged (loaded as <img>).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Unify link/copy-button hover to frame-theme (not frame-theme-hover)
  so all interactive text uses the same blue on hover
- Add fill-frame-theme on hover for secondary button SVG icons so
  shortcut button icons (Site Editor, Styles, etc.) turn blue on hover
- Fix icon-variant hover: use bg-white/10 instead of bg-frame-surface
  with bg-opacity-10, which didn't compose (CSS vars ignore bg-opacity)
  and showed a solid light grey square in the dark titlebar chrome

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set --wp-components-color-foreground/background so Emotion-styled WP
components (ProgressBar, etc.) adapt to dark mode. Override the
ProgressBar indicator to use frame-theme blue instead of the default
foreground color-mix. Update TwoColorProgressBar track default to
frame-text-secondary for dark mode visibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add --color-frame-running token (green-50 light, green-20 dark) so the
action button adapts to both modes. Replace hardcoded hex greens in the
sidebar dot with a8c-green-20 palette classes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wojtekn
Copy link
Contributor

wojtekn commented Feb 25, 2026

Hey @shaunandrews ! Thanks for working on that - it looks like an interesting addition. I think it would make sense to do the following before we pass it for review:

  • Adding a setting allowing the user to choose between light mode, dark mode, and “follow system default” modes
  • Adding e2e tests for new changes
  • Fixing all failing builds

You could also consider adding it to the What's New dialog.

shaunandrews and others added 5 commits February 25, 2026 12:01
Adds an Appearance picker to Preferences with three options that control
Electron's nativeTheme.themeSource, so existing CSS dark mode rules work
as-is. Preference persists to appdata and restores on startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace dropdown with three illustrated cards (System/Light/Dark) that
save immediately on click. Update SVG assets and reduce Settings modal
max-height override so content isn't clipped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded a8c-gray classes with frame-text and
frame-text-secondary tokens so the error screen respects the
user's color scheme preference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@shaunandrews
Copy link
Author

I've updated the settings screen:

  • I've added a new appearance setting for system, light, and dark modes. This setting is changes immediately, without having to click the save button.
  • The new appearance setting has a tendency to cause the settings modal to scroll vertically, hiding the save button. To avoid this, I've removed some of the size restrictions around the modal height, and put the editor and terminal settings on the same row.
  • I visually aligned the CLI switch with the first row of text.
image

shaunandrews and others added 4 commits February 25, 2026 14:54
…e assertion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	apps/studio/src/components/link-button.tsx
#	apps/studio/src/modules/add-site/components/blueprint-deeplink.tsx
#	apps/studio/src/modules/sync/components/sync-sites-modal-selector.tsx
@shaunandrews shaunandrews marked this pull request as ready for review February 25, 2026 20:29
@shaunandrews
Copy link
Author

I also added to the What's new modal:

image

@shaunandrews shaunandrews requested a review from sejas February 25, 2026 21:56
@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Feb 25, 2026

📊 Performance Test Results

Comparing 3a5fcc5 vs trunk

site-editor

Metric trunk 3a5fcc5 Diff Change
load 1480.00 ms 1459.00 ms -21.00 ms ⚪ 0.0%

site-startup

Metric trunk 3a5fcc5 Diff Change
siteCreation 7138.00 ms 8077.00 ms +939.00 ms 🔴 13.2%
siteStartup 4948.00 ms 4960.00 ms +12.00 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@wojtekn
Copy link
Contributor

wojtekn commented Feb 26, 2026

@shaunandrews, thanks for adding settings UI. Some notes regarding UX:

  • Currently, settings are not saved until the user presses Save, and it's different for dark mode. I think the new way is okay too, but it would be better to stick to one of those ways and use the same approach for all options.
  • The buttons look a bit too expressive - do they add any value? What if we just used buttons with small icons inside?

@shaunandrews
Copy link
Author

shaunandrews commented Feb 26, 2026

I made the appearance setting save immediately because it helps the user understand what the setting does as they can see the UI of the main window change immediately. I'm not opposed to changing the rest of the settings to work similarly, but this PR is already huge; would be a good follow up.

As for the buttons, I did try other options but felt the illustrations looked much better and helped convey the settings effects better than an icon. It's also a fairly standard pattern.

image

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants