Skip to content

feat(mobile): light/dark theme runtime foundation - #10423

Closed
bbingz wants to merge 5 commits into
stablyai:mainfrom
bbingz:feat/mobile-theme-runtime
Closed

bbingz wants to merge 5 commits into
stablyai:mainfrom
bbingz:feat/mobile-theme-runtime

Conversation

@bbingz

@bbingz bbingz commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Part of #9959.

Light/dark theme runtime foundation for mobile: a dual palette (darkColors / lightColors), ThemeProvider / useTheme / useThemedStyles, persisted orca:appTheme defaulting to dark, and root/host shells wired through the runtime. No visible change by itself — the app still ships dark until a later Appearance/picker PR reveals light mode.

export const colors = darkColors keeps unconverted modules compiling and painting dark. The unthemed-import ratchet lists every bare colors importer and may only shrink (currently 161 paths, regenerated from listBareColorsImporters() on this branch).

Dark palette + #11651

darkColors preserves #11651's secondary/muted tokens (textSecondary: '#a1a1a1', textMuted: '#8c8c8c'). Upstream mobile-theme-contrast.test.ts (via export const colors = darkColors) stays green: muted ≥ 4.5:1 on every standard dark surface; secondary more prominent than muted.

Contrast invariant (what the tests assert)

mobile-theme-palette.test.ts holds a dual-palette contrast ratchet (CONTRAST_PAIRS). After #11651, dark textMuted / textSecondary floors are ≥ 4.5:1 on bgBase / bgPanel / bgRaised. Light mode still has intentional sub-4.5 floors where documented (e.g. light textSecondary on bgPanel ≥ 4.34, on bgRaised ≥ 3.93; light textMuted ≥ 3.0 on those surfaces for UI chrome). Diff washes stay in the [1.09, 1.25] band on editorSurface in both modes.

Screenshots

No visual change.

Testing

  • Mobile theme suites: contrast, palette, unthemed-color-imports, theme-context, app-shell-theme, themed-style-factories, preferences — 54/54 pass (full theme set); recheck after floor/ratchet update 10/10
  • oxlint on touched theme/layout/preferences files — 0 errors
  • pnpm typecheck / full mobile suite / desktop build — not run
  • Ratchet regenerated from working-tree listBareColorsImporters() (161 entries, exact equality)

ELI5

This adds the plumbing for light mode on the phone (two color palettes and a theme provider) but still starts in dark mode so nothing looks different yet. A later PR will let you turn light mode on.

AI Review Report

Palette + runtime only; terminal-theme selection/picker files from the #10418–#10421 stack were not included (they land via #10421). Cross-platform: React Native theme tokens only; no Electron shortcuts/paths/shells. #11651 dark contrast preserved.

Security Audit

AsyncStorage app-theme preference only; persist failures swallowed (optimistic UI). No new IPC, secrets, or network.

Notes

Consolidates #10422 (light palette) into this branch. Skip of historical “defer terminal mode-mismatch” commit: it only touched terminal-theme slot files that belong to the #10421 stack, not this foundation PR.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c933f173-e861-4c37-9ad7-59b72867ee8d

📥 Commits

Reviewing files that changed from the base of the PR and between 630f13b and 7d578d9.

📒 Files selected for processing (12)
  • mobile/app/_layout.tsx
  • mobile/app/h/_layout.tsx
  • mobile/src/components/NewWorkspaceFab.tsx
  • mobile/src/storage/preferences.test.ts
  • mobile/src/storage/preferences.ts
  • mobile/src/theme/app-shell-theme.test.ts
  • mobile/src/theme/mobile-theme-palette.test.ts
  • mobile/src/theme/mobile-theme.ts
  • mobile/src/theme/theme-context.test.ts
  • mobile/src/theme/theme-context.tsx
  • mobile/src/theme/themed-style-factories.test.ts
  • mobile/src/theme/unthemed-color-imports.test.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • mobile/src/components/NewWorkspaceFab.tsx
  • mobile/src/storage/preferences.test.ts
  • mobile/src/theme/mobile-theme.ts
  • mobile/src/theme/themed-style-factories.test.ts
  • mobile/src/theme/theme-context.test.ts
  • mobile/app/h/_layout.tsx
  • mobile/src/storage/preferences.ts
  • mobile/src/theme/mobile-theme-palette.test.ts
  • mobile/src/theme/theme-context.tsx
  • mobile/app/_layout.tsx

📝 Walkthrough

Walkthrough

The mobile app now supports persisted system, dark, and light theme preferences. It defines typed dark and light palettes, resolves system mode, and caches themed styles. Root and host layouts consume the theme context, update shell colors, and flip StatusBar content style. The workspace FAB uses a dedicated pressed-surface token. Tests cover preference persistence, palette contrast, theme resolution, style caching, shell wiring, and remaining static color imports.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.87% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the mobile light/dark theme runtime foundation, which is the primary change.
Description check ✅ Passed The description covers the required sections, user-visible impact, testing status, review scope, security audit, and platform notes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e59fdcad-5aee-4f2e-9a7f-11e9c08cee62

📥 Commits

Reviewing files that changed from the base of the PR and between 17959a2 and ad6dcecba768a1b8e1ba15ec371416acfb9f56d3.

📒 Files selected for processing (37)
  • mobile/app/_layout.tsx
  • mobile/app/h/_layout.tsx
  • mobile/src/components/NewWorkspaceFab.tsx
  • mobile/src/session/TerminalPaneView.test.ts
  • mobile/src/session/TerminalPaneView.tsx
  • mobile/src/storage/preferences.test.ts
  • mobile/src/storage/preferences.ts
  • mobile/src/storage/terminal-theme-preference.test.ts
  • mobile/src/storage/terminal-theme-preference.ts
  • mobile/src/terminal/TerminalWebView.test.ts
  • mobile/src/terminal/TerminalWebView.tsx
  • mobile/src/terminal/terminal-theme-slot-selection.test.ts
  • mobile/src/terminal/terminal-theme-slot-selection.ts
  • mobile/src/terminal/terminal-webview-html.ts
  • mobile/src/terminal/use-mobile-terminal-theme.test.ts
  • mobile/src/terminal/use-mobile-terminal-theme.ts
  • mobile/src/theme/app-shell-theme.test.ts
  • mobile/src/theme/mobile-theme-palette.test.ts
  • mobile/src/theme/mobile-theme.ts
  • mobile/src/theme/theme-context.test.ts
  • mobile/src/theme/theme-context.tsx
  • mobile/src/theme/themed-style-factories.test.ts
  • mobile/src/theme/unthemed-color-imports.test.ts
  • src/renderer/src/lib/terminal-contrast-correction.test.ts
  • src/renderer/src/lib/terminal-theme.ts
  • src/renderer/src/lib/terminal-themes-data.ts
  • src/renderer/src/lib/terminal-themes/types.ts
  • src/shared/terminal-themes/catalog-merge.ts
  • src/shared/terminal-themes/classic.ts
  • src/shared/terminal-themes/defaults.ts
  • src/shared/terminal-themes/index.ts
  • src/shared/terminal-themes/popular-dark-core.ts
  • src/shared/terminal-themes/popular-dark-extended.ts
  • src/shared/terminal-themes/popular-dark.ts
  • src/shared/terminal-themes/popular-light.ts
  • src/shared/terminal-themes/terminal-theme-catalog.test.ts
  • src/shared/terminal-themes/types.ts
💤 Files with no reviewable changes (2)
  • src/renderer/src/lib/terminal-themes/types.ts
  • src/renderer/src/lib/terminal-themes-data.ts

Comment thread mobile/src/storage/preferences.ts Resolved
Comment thread src/shared/terminal-themes/index.ts Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
mobile/src/theme/mobile-theme-palette.test.ts (1)

15-60: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting shared WCAG contrast utilities.

The mobile and renderer terminal contrast logic repeat the same sRGB linearization/relative-luminance and contrast-ratio formula. If these continue to be test utility helpers, a small shared contrast module can keep the implementations in sync.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5f37993d-9e82-4158-adcd-b7559f9b49a9

📥 Commits

Reviewing files that changed from the base of the PR and between ad6dcecba768a1b8e1ba15ec371416acfb9f56d3 and b595052d41b63af2243fe06dc3db96d7c352277d.

📒 Files selected for processing (37)
  • mobile/app/_layout.tsx
  • mobile/app/h/_layout.tsx
  • mobile/src/components/NewWorkspaceFab.tsx
  • mobile/src/session/TerminalPaneView.test.ts
  • mobile/src/session/TerminalPaneView.tsx
  • mobile/src/storage/preferences.test.ts
  • mobile/src/storage/preferences.ts
  • mobile/src/storage/terminal-theme-preference.test.ts
  • mobile/src/storage/terminal-theme-preference.ts
  • mobile/src/terminal/TerminalWebView.test.ts
  • mobile/src/terminal/TerminalWebView.tsx
  • mobile/src/terminal/terminal-theme-slot-selection.test.ts
  • mobile/src/terminal/terminal-theme-slot-selection.ts
  • mobile/src/terminal/terminal-webview-html.ts
  • mobile/src/terminal/use-mobile-terminal-theme.test.ts
  • mobile/src/terminal/use-mobile-terminal-theme.ts
  • mobile/src/theme/app-shell-theme.test.ts
  • mobile/src/theme/mobile-theme-palette.test.ts
  • mobile/src/theme/mobile-theme.ts
  • mobile/src/theme/theme-context.test.ts
  • mobile/src/theme/theme-context.tsx
  • mobile/src/theme/themed-style-factories.test.ts
  • mobile/src/theme/unthemed-color-imports.test.ts
  • src/renderer/src/lib/terminal-contrast-correction.test.ts
  • src/renderer/src/lib/terminal-theme.ts
  • src/renderer/src/lib/terminal-themes-data.ts
  • src/renderer/src/lib/terminal-themes/types.ts
  • src/shared/terminal-themes/catalog-merge.ts
  • src/shared/terminal-themes/classic.ts
  • src/shared/terminal-themes/defaults.ts
  • src/shared/terminal-themes/index.ts
  • src/shared/terminal-themes/popular-dark-core.ts
  • src/shared/terminal-themes/popular-dark-extended.ts
  • src/shared/terminal-themes/popular-dark.ts
  • src/shared/terminal-themes/popular-light.ts
  • src/shared/terminal-themes/terminal-theme-catalog.test.ts
  • src/shared/terminal-themes/types.ts
💤 Files with no reviewable changes (2)
  • src/renderer/src/lib/terminal-themes-data.ts
  • src/renderer/src/lib/terminal-themes/types.ts
🚧 Files skipped from review as they are similar to previous changes (30)
  • src/shared/terminal-themes/types.ts
  • src/shared/terminal-themes/classic.ts
  • mobile/src/terminal/terminal-webview-html.ts
  • mobile/src/components/NewWorkspaceFab.tsx
  • src/shared/terminal-themes/defaults.ts
  • src/shared/terminal-themes/catalog-merge.ts
  • src/shared/terminal-themes/popular-dark.ts
  • mobile/src/theme/theme-context.test.ts
  • mobile/src/terminal/use-mobile-terminal-theme.ts
  • mobile/src/terminal/terminal-theme-slot-selection.ts
  • src/shared/terminal-themes/popular-dark-core.ts
  • src/shared/terminal-themes/popular-dark-extended.ts
  • mobile/src/storage/preferences.test.ts
  • mobile/src/session/TerminalPaneView.tsx
  • src/shared/terminal-themes/popular-light.ts
  • src/shared/terminal-themes/index.ts
  • mobile/src/storage/preferences.ts
  • mobile/src/theme/themed-style-factories.test.ts
  • src/shared/terminal-themes/terminal-theme-catalog.test.ts
  • mobile/src/terminal/TerminalWebView.tsx
  • mobile/src/storage/terminal-theme-preference.test.ts
  • mobile/src/terminal/terminal-theme-slot-selection.test.ts
  • mobile/src/terminal/TerminalWebView.test.ts
  • src/renderer/src/lib/terminal-contrast-correction.test.ts
  • mobile/app/_layout.tsx
  • mobile/src/terminal/use-mobile-terminal-theme.test.ts
  • src/renderer/src/lib/terminal-theme.ts
  • mobile/src/theme/theme-context.tsx
  • mobile/src/storage/terminal-theme-preference.ts
  • mobile/app/h/_layout.tsx

@bbingz
bbingz force-pushed the feat/mobile-theme-runtime branch from b595052 to 9e35852 Compare July 25, 2026 04:49
@bbingz

bbingz commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

Rebuilt onto current main via refreshed #10420 + #10422 tips (no merge commit).

Stack base now includes:

Reviewable surface remains the theme runtime commits (provider / shells / defer mode-mismatch).

CodeRabbit:

Verified: theme-context/app-shell/palette/factories/unthemed + preferences/slots/use-theme (80) + catalog (5); oxlint clean.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
mobile/src/theme/theme-context.test.ts (1)

23-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated console-suppression helper into a shared test utility. Both files define an identical suppressReactTestRendererDeprecationWarning function; as more react-test-renderer-based mobile tests are added in this stack, this duplication will keep growing.

  • mobile/src/theme/theme-context.test.ts#L23-L33: move this implementation into a new module (e.g. mobile/src/test-support/suppress-react-test-renderer-deprecation-warning.ts) and import it here.
  • mobile/src/session/TerminalPaneView.test.ts#L29-L39: remove the duplicate and import the same shared implementation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fbfedc29-c6b4-4331-9d61-50aeba6e5cab

📥 Commits

Reviewing files that changed from the base of the PR and between b595052d41b63af2243fe06dc3db96d7c352277d and 076c65e.

📒 Files selected for processing (38)
  • mobile/app/_layout.tsx
  • mobile/app/h/_layout.tsx
  • mobile/src/components/NewWorkspaceFab.tsx
  • mobile/src/session/TerminalPaneView.test.ts
  • mobile/src/session/TerminalPaneView.tsx
  • mobile/src/storage/preferences.test.ts
  • mobile/src/storage/preferences.ts
  • mobile/src/storage/terminal-theme-preference.test.ts
  • mobile/src/storage/terminal-theme-preference.ts
  • mobile/src/terminal/TerminalWebView.test.ts
  • mobile/src/terminal/TerminalWebView.tsx
  • mobile/src/terminal/terminal-theme-slot-selection.test.ts
  • mobile/src/terminal/terminal-theme-slot-selection.ts
  • mobile/src/terminal/terminal-webview-html.ts
  • mobile/src/terminal/use-mobile-terminal-theme.test.ts
  • mobile/src/terminal/use-mobile-terminal-theme.ts
  • mobile/src/theme/app-shell-theme.test.ts
  • mobile/src/theme/mobile-theme-palette.test.ts
  • mobile/src/theme/mobile-theme.ts
  • mobile/src/theme/theme-context.test.ts
  • mobile/src/theme/theme-context.tsx
  • mobile/src/theme/themed-style-factories.test.ts
  • mobile/src/theme/unthemed-color-imports.test.ts
  • src/renderer/src/lib/terminal-contrast-correction.test.ts
  • src/renderer/src/lib/terminal-theme.ts
  • src/renderer/src/lib/terminal-themes-data.ts
  • src/renderer/src/lib/terminal-themes/index.ts
  • src/renderer/src/lib/terminal-themes/types.ts
  • src/shared/terminal-themes/catalog-merge.ts
  • src/shared/terminal-themes/classic.ts
  • src/shared/terminal-themes/defaults.ts
  • src/shared/terminal-themes/index.ts
  • src/shared/terminal-themes/popular-dark-core.ts
  • src/shared/terminal-themes/popular-dark-extended.ts
  • src/shared/terminal-themes/popular-dark.ts
  • src/shared/terminal-themes/popular-light.ts
  • src/shared/terminal-themes/terminal-theme-catalog.test.ts
  • src/shared/terminal-themes/types.ts
💤 Files with no reviewable changes (3)
  • src/renderer/src/lib/terminal-themes-data.ts
  • src/renderer/src/lib/terminal-themes/index.ts
  • src/renderer/src/lib/terminal-themes/types.ts
🚧 Files skipped from review as they are similar to previous changes (30)
  • mobile/src/components/NewWorkspaceFab.tsx
  • src/shared/terminal-themes/popular-dark.ts
  • src/shared/terminal-themes/catalog-merge.ts
  • src/shared/terminal-themes/defaults.ts
  • src/shared/terminal-themes/classic.ts
  • mobile/src/theme/themed-style-factories.test.ts
  • src/shared/terminal-themes/types.ts
  • mobile/src/session/TerminalPaneView.tsx
  • mobile/src/storage/preferences.test.ts
  • src/shared/terminal-themes/popular-dark-core.ts
  • src/shared/terminal-themes/popular-dark-extended.ts
  • mobile/src/terminal/TerminalWebView.tsx
  • mobile/src/storage/preferences.ts
  • src/shared/terminal-themes/terminal-theme-catalog.test.ts
  • mobile/src/theme/mobile-theme.ts
  • src/renderer/src/lib/terminal-contrast-correction.test.ts
  • mobile/src/terminal/terminal-webview-html.ts
  • src/shared/terminal-themes/index.ts
  • mobile/app/h/_layout.tsx
  • src/shared/terminal-themes/popular-light.ts
  • mobile/src/theme/theme-context.tsx
  • mobile/src/theme/mobile-theme-palette.test.ts
  • mobile/src/terminal/use-mobile-terminal-theme.test.ts
  • mobile/src/terminal/terminal-theme-slot-selection.ts
  • mobile/src/terminal/terminal-theme-slot-selection.test.ts
  • mobile/src/terminal/TerminalWebView.test.ts
  • src/renderer/src/lib/terminal-theme.ts
  • mobile/app/_layout.tsx
  • mobile/src/storage/terminal-theme-preference.ts
  • mobile/src/storage/terminal-theme-preference.test.ts

bbingz added 5 commits August 6, 2026 09:55
Rename the existing tokens to darkColors, add lightColors (31 keys)
derived from the desktop light tokens, and keep `export const colors =
darkColors` so unconverted modules keep compiling and rendering dark.
Pin the NewWorkspaceFab pressed state to surfaceBrightPressed (byte-
identical in dark). Seed the unthemed-import ratchet and an empty
themed-style-factories suite for the migration batches.
Catch unparenthesized useThemedStyles arrow factories in the ratchet, and
assert the themed-style factory registry starts empty so later conversion
batches must register deliberately rather than leaving a vacuous suite.
Add ThemeProvider / useTheme / useThemedStyles with an explicit resolved
mode, persist orca:appTheme defaulting to dark (no visible change), and
wire the root + host shells through the runtime. Terminal slot selection
falls back to the desktop default for the app mode when the host palette
mode mismatches. Drop the two converted layout paths from the unthemed
import ratchet.
setAppTheme already updates preference optimistically and fire-and-forgets
saveAppTheme; a rejected AsyncStorage write must not become an unhandled
rejection (loadAppTheme already falls back on read errors).
Regenerate unthemed-color-imports from listBareColorsImporters on the
consolidated tree (161 bare importers). Raise dark textMuted/secondary
contrast floors to match stablyai#11651's readable dark tokens.
@bbingz bbingz changed the title feat(mobile): mobile theme runtime and themed app shell feat(mobile): light/dark theme runtime foundation Aug 6, 2026
@bbingz
bbingz force-pushed the feat/mobile-theme-runtime branch from 076c65e to 7d578d9 Compare August 6, 2026 01:57
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@bbingz
bbingz marked this pull request as draft August 11, 2026 07:49
@bbingz

bbingz commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Queue hygiene (contributor): converting this PR to draft.

It is not superseded by main — still a valid product stack — but at +hundreds–thousands of lines it sits behind a large campaign backlog and is unlikely to get review soon. Draft reduces noise for maintainers.

If product wants this stack prioritized, say so and we will mark ready again / rebase.

@bbingz

bbingz commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Closing: the ratchet this PR depends on can no longer hold.

Its gate pins 161 bare-colors importers as a may-only-shrink list. On main today git grep -l theme/mobile-theme -- mobile returns 173 importers, with 293 mobile files added since the branch date — so the list is already red, and every future mobile merge re-reds it.

By its own description the PR ships no visible change on its own, and the follow-on stack that would give it a payoff doesn't exist. Light mode (#9959) is still worth doing; it needs a plan that doesn't depend on a tree-wide pinned list.

Closing to keep my open-PR queue honest. If this turns out to be wrong I'll reopen — please just say so, or reopen it yourself, within the next 7 days.

@bbingz bbingz closed this Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants