Skip to content

Add dark mode support for content frame - #2652

Merged
sejas merged 38 commits into
trunkfrom
add-dark-mode-support
Mar 19, 2026
Merged

Add dark mode support for content frame#2652
sejas merged 38 commits into
trunkfrom
add-dark-mode-support

Conversation

@shaunandrews

@shaunandrews shaunandrews commented Feb 24, 2026

Copy link
Copy Markdown
Contributor

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
  • Remove two "What's New" pages (selective sync, Pressable sync)
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

wojtekn commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

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
Copy Markdown
Contributor 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
Copy Markdown
Contributor Author

I also added to the What's new modal:

image
@shaunandrews
shaunandrews requested a review from sejas February 25, 2026 21:56
@wpmobilebot

wpmobilebot commented Feb 25, 2026

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing f723f91 vs trunk

app-size

Metric trunk f723f91 Diff Change
App Size (Mac) 1236.42 MB 1236.49 MB +0.07 MB ⚪ 0.0%

site-editor

Metric trunk f723f91 Diff Change
load 1925 ms 1648 ms 277 ms 🟢 -14.4%

site-startup

Metric trunk f723f91 Diff Change
siteCreation 7095 ms 7099 ms +4 ms ⚪ 0.0%
siteStartup 3923 ms 3918 ms 5 ms ⚪ 0.0%

Results are median values from multiple test runs.

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

@wojtekn

wojtekn commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

@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

shaunandrews commented Feb 26, 2026

Copy link
Copy Markdown
Contributor Author

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
shaunandrews and others added 4 commits February 26, 2026 14:53
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	apps/studio/e2e/page-objects/user-settings-modal.ts
#	apps/studio/src/components/content-tab-overview.tsx
#	apps/studio/src/modules/sync/components/sync-connected-sites.tsx
#	apps/studio/src/modules/sync/components/sync-sites-modal-selector.tsx
#	apps/studio/src/modules/user-settings/components/preferences-tab.tsx

@sejas sejas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@shaunandrews, thanks for creating this PR. I tested the app holistically and only found a few places where we could improve the colors for accessibility reasons. There were some conflicts, and I pushed a commit to fix them and pull the latest changes from trunk 1d084ed

I suggest collaborating next week to bring this PR over the finish line. Thank you!

Here are the components that I identified as needing improvement:

Push warning

Image

Site title to connect sites

Image

AI animated icon and maybe arrows links
Some links are difficult for me to identify; they are clickable.

Image

File icons on selective push

Image

Password input in site settings

I think it's too bright-white.

Image

Here is a video with all my testing:

light-dark-mode-web.mp4
sejas and others added 2 commits March 13, 2026 14:46
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add allowDefaultProject for tailwind.config.js in eslint config and fix
import order.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sejas and others added 8 commits March 18, 2026 09:24
Override Emotion-generated styles for modals, input controls, primary
buttons, link button hover, notices, and the span text cascade to
properly support dark mode without breaking light mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace text-a8c-gray-50/70/700/30, fill-a8c-gray-*, border-gray-*,
and bg-gray-* with semantic frame-text-secondary, frame-border, and
frame-surface tokens across all content frame components.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use frame-surface for hover, white text for selected rows, and white
badge on selected. Environment badges use fixed colors that work on
both light and dark backgrounds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use frame-border, frame-surface, and frame-text tokens. Replace
hardcoded disabled grays with opacity approach for consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add fill-frame-text to tree view file/folder icons. Add select-minimal
class to sync dialog select to preserve borderless style in dark mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…/studio into add-dark-mode-support

# Conflicts:
#	apps/studio/src/components/ai-settings-modal.tsx
@shaunandrews

shaunandrews commented Mar 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review! I've got through and fixed a bunch! I wasn't able to change the Rive animation for the Assistant tab input, but I don't think that's a blocker. (I honestly kind of hate it, and would rather just remove it than generate a dark-mode variant.)

WP component overrides (index.css)

  • Modals: Override Emotion's background: white on modal frames so they render with the dark frame background. Fixed header border that was always visible (now only shows when content scrolls). Replaced light box-shadow with a darker one appropriate for dark backgrounds.
  • Input controls: Override Emotion's white container backgrounds on input/search controls. Fixed the search icon prefix area that showed a lighter background behind the magnifying glass.
  • Primary buttons: Force dark mode theme blue (#6b8aff) with proper hover (#8da6ff) instead of WP's default calculated hover.
  • Link buttons: Hover now turns blue (frame-theme) instead of light gray.
  • Notices: Added dark mode surface/text overrides for WP Notice component.
  • Span cascade: Split the blanket span color override to exclude spans inside buttons, fixing arrows and link text that were forced white regardless of their parent's color.
  • Minimal selects: Preserved the borderless/transparent style for variant="minimal" selects in dark mode.
  • Skeleton loading: Gradient now uses frame tokens instead of hardcoded light grays.

Component token migration (~30 files)

Replaced hardcoded text-a8c-gray-50/70/700/30, fill-a8c-gray-*, border-gray-*, and bg-gray-* with semantic frame-text-secondary, frame-border, and frame-surface tokens across all content frame components — including settings, assistant, sync, previews, import/export, onboarding, add-site, and user settings.

Site selector & badges

  • Hover state: Changed from bg-a8c-blue-5 (invisible on dark) to bg-frame-surface.
  • Selected state: Site name now uses !text-white to override the .a8c-body dark mode cascade. WordPress logo icon uses frame token for disabled state.
  • Environment badges: Production/staging use fixed colors that pass WCAG contrast on both backgrounds. Selected badge is white fill with theme-blue text.

Input controls

  • Password control: Replaced hardcoded border-[#949494], bg-gray-100, text-gray-500 with frame tokens. Eye icon uses fill-frame-text-secondary.
  • Text control: Replaced hardcoded disabled grays with opacity approach.

Tree view & sync dialog

  • File/folder icons: Added fill-frame-text so WP icons are visible on dark backgrounds.
  • Minimal select: Added select-minimal class to preserve the borderless style in the sync file picker.
@sejas

sejas commented Mar 19, 2026

Copy link
Copy Markdown
Member

I'll make one last review and push some small fixes if I find anything.

@sejas sejas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for adjusting the PR. I just pushed a fix for notices. f723f91

Light Dark
Image Image

I also confirm that the rest of the improvements were fixed. The only exception would the Rive AI animation.

Passowrd input

Screenshot 2026-03-19 at 17 23 15

Files icons

Screenshot 2026-03-19 at 17 23 00

Learn more and arrow icons

Screenshot 2026-03-19 at 17 13 22

Site selection

Screenshot 2026-03-19 at 17 03 39
@shaunandrews

Copy link
Copy Markdown
Contributor Author

doh, i missed the notice! thanks for the fix

@sejas
sejas merged commit 1aadaeb into trunk Mar 19, 2026
11 checks passed
@sejas
sejas deleted the add-dark-mode-support branch March 19, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants