refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

refactor(mobile): compile semantic themes for Uniwind - #7327

Merged
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator
Aug 28, 2026
Merged

refactor(mobile): compile semantic themes for Uniwind#7327
juliusmarminge merged 1 commit into
mainfrom
try-uniwind-pro-simulator

Conversation

@juliusmarminge

@juliusmarmingejuliusmarminge commented Aug 17, 2026

Copy link
Copy Markdown
Member

Problem

Mobile theme colors were resolved through per-component CSS variable subscriptions and scattered JavaScript color props. Palette changes therefore reconciled across many React consumers, and custom registered themes could miss dark: or light: utility branches.

Solution

  • Keep T3 Code’s default palette in Uniwind’s built-in light/dark CSS variants, and compile the other five palettes in both appearances as registered Uniwind themes.
  • Delete the duplicate JavaScript default-theme object; global.css is now the sole source for T3 Code’s default color values.
  • Move ordinary React Native surfaces to semantic className, colorClassName, and tintColorClassName styling.
  • Apply the registered theme immediately, then persist preferences through React; keep one documented palette bridge only for native and third-party APIs that cannot consume classes.
  • Let a theme card select both appearances while its nested light and dark rings select one appearance.
  • Generate adaptive tokens for appearance-sensitive values and reject future dark:/light: utilities, CSS-variable subscriptions, or undocumented palette bridges.
  • Keep the normal open-source uniwind dependency and native fingerprint from main; this PR contains no Pro package, license, Nitro bump, or evaluation binary.

Verification

  • vp run --filter @t3tools/mobile generate
  • vp test run apps/mobile/scripts/generate-uniwind-themes.test.ts apps/mobile/src/lib/mobileTheme.test.ts apps/mobile/src/lib/mobileThemeRuntime.test.ts apps/mobile/src/features/review/nativeReviewDiffAdapter.test.ts apps/mobile/src/features/terminal/terminalTheme.test.ts — 35 tests passed
  • vp test run oxlint-plugin-t3code — 71 tests passed
  • vp run --filter @t3tools/mobile typecheck
  • vp run --filter oxlint-plugin-t3code typecheck
  • vp lint apps/mobile oxlint-plugin-t3code --report-unused-disable-directives
  • vp run lint:mobile — SwiftLint, ktlint, and Detekt passed
  • React Doctor changed-scope scan — no errors; four advisory warnings from existing component shapes
  • Clean iOS development-client prebuild and rebuild on iOS 26.5
  • Clean iOS Expo/Metro export — 9,399 modules bundled
  • Repeated whole-card and nested-ring selections across T3 Code, T3 Chat, Grove, and Ocean; pressed state released and semantic tokens stayed coherent

UI evidence

Before (main)After (compiled Uniwind themes)
Appearance on mainAppearance after

Split light/dark selection:

Split theme selection

Interaction demo: https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/75369d3b7dfc982f/t3code-free-uniwind-theme-demo.mp4

Built with GPT-5 Codex.


Note

Medium Risk
Wide UI refactor touching theming across most mobile screens; incorrect generated tokens or theme registration could cause subtle contrast or palette bugs, though behavior is covered by generator and theme runtime tests.

Overview
This PR replaces per-component useThemeColor subscriptions with Uniwind-driven styling so palette switches reconcile through CSS variants instead of many React color props.

A new generate-uniwind-themes script (wired via pnpm generate) emits generated-uniwind-themes.css, theme name list, and default-variable JSON. It registers five built-in palettes (T3 Chat, Grove, Ocean, Ember, Iris) as {palette}-light / {palette}-dark Uniwind variants, adds adaptive semantic tokens for values that used to rely on dark: / light: utilities, and keeps T3 Code’s default colors authored only in global.css. Metro loads extraThemes from the generated manifest and imports the generated CSS.

Across the app, surfaces move to className, tintColorClassName, and colorClassName (including withUniwind on SymbolView, glass, wordmark, and similar). useUniwindTheme remains for native/third-party APIs that need raw CSS variables (markdown, diff themes, swipe backgrounds). useMobileNavigationTheme no longer takes a theme argument; status bar background color props are dropped in favor of translucent styling.

Reviewed by Cursor Bugbot for commit c39f3e4. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Migrate mobile theming from useThemeColor to Uniwind semantic classes

  • Replaces useThemeColor hook calls with useUniwindTheme and class-based tint props (tintColorClassName, colorClassName) across nearly all mobile components, so icon, text, and surface colors resolve via CSS class tokens instead of computed runtime values
  • Deletes apps/mobile/src/lib/useThemeColor.ts and adds generated Uniwind theme assets: a build script (generate-uniwind-themes.mts), CSS variable definitions (generated-uniwind-themes.css), and JSON theme maps loaded via Metro config
  • Reworks AppearancePreferencesProvider to wrap the app in ScopedTheme, apply theme runtime operations granularly (including native Appearance.setColorScheme), and apply theme switches urgently while deferring non-theme preference saves
  • Makes useMobileNavigationTheme parameterless — it now reads appearance from the provider and derives colors from a single Uniwind palette
  • Adds oxlint rule no-mobile-uniwind-theme-escape-hatches to flag unapproved escape hatches like useCSSVariable and appearance variants in mobile source
  • Risk: getMobileThemeVariables no longer accepts the default theme id and always derives variables from the theme palette; callers of createNativeReviewDiffTheme must now pass an explicit appTheme: MobileThemeVariables. useMobileNavigationTheme signature changed to take no arguments, so existing call sites passing themeAppearance are updated in-tree

Macroscope summarized c39f3e4.

@juliusmarmingejuliusmarminge changed the title Migrate mobile theming to Uniwind Pro[DO NOT MERGE] Try out Uniwind ProAug 17, 2026
@juliusmarminge
juliusmarminge marked this pull request as draft August 17, 2026 13:48
@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.8%)15.1 KiB
CodexThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+26.0%)7.3 KiB
CodexLive turn WebSocket wire5.9 KiB6.4 KiB+603 B (+10.1%)7.8 KiB
CodexLive turn WebSocket decoded49.7 KiB55.6 KiB+5.9 KiB (+11.8%)66.4 KiB
CodexLive turn messages1611−5 (−31.3%)21
ClaudeTotal thread wire11.3 KiB13.3 KiB+2.0 KiB (+17.7%)15.1 KiB
ClaudeThread snapshot wire5.5 KiB6.9 KiB+1.4 KiB (+25.8%)7.3 KiB
ClaudeLive turn WebSocket wire5.9 KiB6.5 KiB+610 B (+10.2%)7.8 KiB
ClaudeLive turn WebSocket decoded50.6 KiB56.4 KiB+5.9 KiB (+11.6%)66.4 KiB
ClaudeLive turn messages1611−5 (−31.3%)21

Baseline: 83d769f · PR result: c39f3e4 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dad7e213-30a7-4234-b7f8-5e3d10f4c17e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@juliusmarmingejuliusmarminge added the DO NOT MERGE Experimental pull request. Do not merge. label Aug 17, 2026
@t3-code

ghost commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

closing because this is explicitly marked DO NOT MERGE and is an evaluation-only Uniwind Pro experiment containing a local binary package.

@t3-codet3-codeBot closed this Aug 20, 2026
@juliusmarmingejuliusmarminge changed the title [DO NOT MERGE] Try out Uniwind Prorefactor(mobile): compile semantic themes for UniwindAug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 24177f7 to 9904182CompareAugust 28, 2026 03:08
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review August 28, 2026 03:09
@juliusmarmingejuliusmarminge removed DO NOT MERGE Experimental pull request. Do not merge. 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. labels Aug 28, 2026
Comment threadapps/mobile/src/components/GlassSurface.tsx
@macroscopeapp

ghost commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This is a broad 110-file mobile theming migration that changes shared runtime theme selection, native appearance synchronization, compiled theme registration, and rendering across most screens. The generated assets and tests help constrain the change, but its production blast radius and new theming infrastructure are too substantial for an automated approval recommendation.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9904182 to 7655a9dCompareAugust 28, 2026 03:31
@github-actionsgithub-actionsBot added the 📱 Native Change Changes the native fingerprint; merging blocks production OTAs until a new store build ships. label Aug 28, 2026
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 7655a9d to 9a2f759CompareAugust 28, 2026 03:40
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 9a2f759 to 5c2519aCompareAugust 28, 2026 03:47
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 5c2519a to 113da07CompareAugust 28, 2026 03:53
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 3 times, most recently from 8620732 to 7f68a2aCompareAugust 28, 2026 04:19
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from f8b0097 to fe12832CompareAugust 28, 2026 04:28
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadapps/mobile/src/components/ComposerToolbar.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from f4f7bb6 to 222deb2CompareAugust 28, 2026 04:40
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
Comment threadoxlint-plugin-t3code/rules/no-mobile-uniwind-theme-escape-hatches.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 2 times, most recently from 5e55533 to 47ff252CompareAugust 28, 2026 04:53
Comment threadapps/mobile/src/features/threads/ThreadComposer.tsx
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch 4 times, most recently from 8aa218f to a77ec4cCompareAugust 28, 2026 05:21

ghost 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit a77ec4c59bf2939d6c255e8f28d4d60ba34670e2. Configure here.

Comment threadapps/mobile/src/components/ComposerToolbar.tsx Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from a77ec4c to 3aca002CompareAugust 28, 2026 06:05
Comment threadapps/mobile/src/lib/useUniwindTheme.ts Outdated
@juliusmarminge
juliusmarmingeforce-pushed the try-uniwind-pro-simulator branch from 3aca002 to 2d94231CompareAugust 28, 2026 06:12
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📱 Native ChangeChanges the native fingerprint; merging blocks production OTAs until a new store build ships.size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@juliusmarminge