authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-10-11 22:31:13-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-11 22:31:13-07:00
log679b03e1c680d983cf89f5162c545342d6036ad3
treeb8ec6b8c7a7c6e995a5aea73ad69211a375a8284
parent462e7f4de4fd4ae14d2b4439fd983fa9ced2790e
signature Signed by PGP key B5690EEEBB952194

fix(mobile): preserve theme contrast across surfaces and actions (#18506)


19 files changed, 167 insertions(+), 68 deletions(-)

apps/mobile/generated-uniwind-default-theme-variables.json+4
......@@ -30,6 +30,8 @@
3030 "--color-inline-skill-border": "rgba(27, 78, 216, 0.42)",
3131 "--color-inline-skill-foreground": "#18181b",
3232 "--color-primary": "#1b4ed8",
33 "--color-prominent-action": "#27272a",
34 "--color-prominent-action-foreground": "#fcfcfc",
3335 "--color-primary-foreground": "#ffffff",
3436 "--color-primary-text": "#1b4ed8",
3537 "--color-primary-shadow": "#000000",
......@@ -119,6 +121,8 @@
119121 "--color-inline-skill-border": "rgba(52, 107, 241, 0.42)",
120122 "--color-inline-skill-foreground": "#f5f5f5",
121123 "--color-primary": "#346bf1",
124 "--color-prominent-action": "#f5f5f5",
125 "--color-prominent-action-foreground": "#0a0a0a",
122126 "--color-primary-foreground": "#ffffff",
123127 "--color-primary-text": "#4b7cf3",
124128 "--color-primary-shadow": "#000000",
apps/mobile/generated-uniwind-themes.css+52-28
......@@ -32,6 +32,8 @@
3232 --color-inline-skill-border: rgba(27, 78, 216, 0.42);
3333 --color-inline-skill-foreground: #18181b;
3434 --color-primary: #1b4ed8;
35 --color-prominent-action: #27272a;
36 --color-prominent-action-foreground: #fcfcfc;
3537 --color-primary-foreground: #ffffff;
3638 --color-primary-text: #1b4ed8;
3739 --color-primary-shadow: #000000;
......@@ -191,6 +193,8 @@
191193 --color-inline-skill-border: rgba(52, 107, 241, 0.42);
192194 --color-inline-skill-foreground: #f5f5f5;
193195 --color-primary: #346bf1;
196 --color-prominent-action: #f5f5f5;
197 --color-prominent-action-foreground: #0a0a0a;
194198 --color-primary-foreground: #ffffff;
195199 --color-primary-text: #4b7cf3;
196200 --color-primary-shadow: #000000;
......@@ -324,7 +328,7 @@
324328 --color-sheet: rgba(253, 247, 253, 0.98);
325329 --color-sheet-solid: #fdf7fd;
326330 --color-card: #faf3fb;
327 --color-grouped-card: #faf3fb;
331 --color-grouped-card: #f3e6f5;
328332 --color-card-alt: #fdfafd;
329333 --color-card-translucent: rgba(250, 243, 251, 0.8);
330334 --color-thread-canvas: #fdf7fd;
......@@ -334,8 +338,8 @@
334338 --color-thread-hover: #f8f8f7;
335339 --color-row-hover: #eccfe3;
336340 --color-composer-panel: rgba(253, 247, 253, 0.88);
337 --color-composer-surface: rgba(250, 243, 251, 0.94);
338 --color-composer-border: rgba(238, 225, 237, 0.54);
341 --color-composer-surface: rgba(243, 230, 245, 0.94);
342 --color-composer-border: rgba(238, 225, 237, 0.8);
339343 --color-foreground: #501854;
340344 --color-foreground-secondary: #ab1668;
341345 --color-foreground-muted: #8d1255;
......@@ -350,6 +354,8 @@
350354 --color-inline-skill-border: rgba(219, 39, 119, 0.42);
351355 --color-inline-skill-foreground: #454554;
352356 --color-primary: #db2777;
357 --color-prominent-action: #501854;
358 --color-prominent-action-foreground: #fdf7fd;
353359 --color-primary-foreground: #ffffff;
354360 --color-primary-text: #aa1e5d;
355361 --color-primary-shadow: #000000;
......@@ -379,7 +385,7 @@
379385 --color-header-foreground: #501854;
380386 --color-header-border: #efbdeb;
381387 --color-glass-surface: rgba(255, 255, 255, 0.74);
382 --color-glass-fallback: rgba(250, 243, 251, 0.94);
388 --color-glass-fallback: rgba(243, 230, 245, 0.94);
383389 --color-glass-tint: rgba(255, 255, 255, 0.22);
384390 --color-status-bar: #fdf7fd;
385391 --color-md-body: #501854;
......@@ -509,6 +515,8 @@
509515 --color-inline-skill-border: rgba(163, 0, 76, 0.42);
510516 --color-inline-skill-foreground: #f8f1f5;
511517 --color-primary: #a3004c;
518 --color-prominent-action: #fbd0e8;
519 --color-prominent-action-foreground: #a3004c;
512520 --color-primary-foreground: #fbd0e8;
513521 --color-primary-text: #d07ea4;
514522 --color-primary-shadow: #000000;
......@@ -642,7 +650,7 @@
642650 --color-sheet: rgba(243, 247, 244, 0.98);
643651 --color-sheet-solid: #f3f7f4;
644652 --color-card: #f3f7f4;
645 --color-grouped-card: #ecefed;
653 --color-grouped-card: #e6f0ea;
646654 --color-card-alt: #ecefed;
647655 --color-card-translucent: rgba(243, 247, 244, 0.8);
648656 --color-thread-canvas: #f3f7f4;
......@@ -652,7 +660,7 @@
652660 --color-thread-hover: #cae0d5;
653661 --color-row-hover: #d5e6dd;
654662 --color-composer-panel: rgba(243, 247, 244, 0.88);
655 --color-composer-surface: rgba(236, 239, 237, 0.94);
663 --color-composer-surface: rgba(230, 240, 234, 0.94);
656664 --color-composer-border: rgba(203, 213, 209, 0.8);
657665 --color-foreground: #241523;
658666 --color-foreground-secondary: #6f686f;
......@@ -668,6 +676,8 @@
668676 --color-inline-skill-border: rgba(27, 125, 80, 0.42);
669677 --color-inline-skill-foreground: #241523;
670678 --color-primary: #8f6410;
679 --color-prominent-action: #8f6410;
680 --color-prominent-action-foreground: #fffaff;
671681 --color-primary-foreground: #fffaff;
672682 --color-primary-text: #8d6210;
673683 --color-primary-shadow: #000000;
......@@ -697,7 +707,7 @@
697707 --color-header-foreground: #241523;
698708 --color-header-border: #d5e6dd;
699709 --color-glass-surface: rgba(231, 233, 232, 0.74);
700 --color-glass-fallback: rgba(236, 239, 237, 0.94);
710 --color-glass-fallback: rgba(230, 240, 234, 0.94);
701711 --color-glass-tint: rgba(231, 233, 232, 0.22);
702712 --color-status-bar: #f3f7f4;
703713 --color-md-body: #241523;
......@@ -801,7 +811,7 @@
801811 --color-sheet: rgba(27, 40, 33, 0.98);
802812 --color-sheet-solid: #1b2821;
803813 --color-card: #1b2821;
804 --color-grouped-card: #36413c;
814 --color-grouped-card: #253e31;
805815 --color-card-alt: #36413c;
806816 --color-card-translucent: rgba(27, 40, 33, 0.8);
807817 --color-thread-canvas: #1b2821;
......@@ -811,7 +821,7 @@
811821 --color-thread-hover: #2a4938;
812822 --color-row-hover: #325c46;
813823 --color-composer-panel: rgba(27, 40, 33, 0.92);
814 --color-composer-surface: rgba(54, 65, 60, 0.9);
824 --color-composer-surface: rgba(37, 62, 49, 0.9);
815825 --color-composer-border: rgba(65, 95, 79, 0.8);
816826 --color-foreground: #fffaff;
817827 --color-foreground-secondary: #afb1b1;
......@@ -827,6 +837,8 @@
827837 --color-inline-skill-border: rgba(105, 214, 154, 0.42);
828838 --color-inline-skill-foreground: #fffaff;
829839 --color-primary: #e3b34e;
840 --color-prominent-action: #e3b34e;
841 --color-prominent-action-foreground: #241523;
830842 --color-primary-foreground: #241523;
831843 --color-primary-text: #e3b34e;
832844 --color-primary-shadow: #000000;
......@@ -856,7 +868,7 @@
856868 --color-header-foreground: #fffaff;
857869 --color-header-border: #36654c;
858870 --color-glass-surface: rgba(68, 77, 73, 0.74);
859 --color-glass-fallback: rgba(54, 65, 60, 0.9);
871 --color-glass-fallback: rgba(37, 62, 49, 0.9);
860872 --color-glass-tint: rgba(68, 77, 73, 0.22);
861873 --color-status-bar: #1b2821;
862874 --color-md-body: #fffaff;
......@@ -960,7 +972,7 @@
960972 --color-sheet: rgba(245, 247, 248, 0.98);
961973 --color-sheet-solid: #f5f7f8;
962974 --color-card: #f5f7f8;
963 --color-grouped-card: #edeff1;
975 --color-grouped-card: #e8eff4;
964976 --color-card-alt: #edeff1;
965977 --color-card-translucent: rgba(245, 247, 248, 0.8);
966978 --color-thread-canvas: #f5f7f8;
......@@ -970,7 +982,7 @@
970982 --color-thread-hover: #cdddea;
971983 --color-row-hover: #d8e4ee;
972984 --color-composer-panel: rgba(245, 247, 248, 0.88);
973 --color-composer-surface: rgba(237, 239, 241, 0.94);
985 --color-composer-surface: rgba(232, 239, 244, 0.94);
974986 --color-composer-border: rgba(205, 212, 220, 0.8);
975987 --color-foreground: #241523;
976988 --color-foreground-secondary: #706870;
......@@ -986,6 +998,8 @@
986998 --color-inline-skill-border: rgba(38, 114, 175, 0.42);
987999 --color-inline-skill-foreground: #241523;
9881000 --color-primary: #0a6f75;
1001 --color-prominent-action: #0a6f75;
1002 --color-prominent-action-foreground: #fffaff;
9891003 --color-primary-foreground: #fffaff;
9901004 --color-primary-text: #0a6f75;
9911005 --color-primary-shadow: #000000;
......@@ -1015,7 +1029,7 @@
10151029 --color-header-foreground: #241523;
10161030 --color-header-border: #d8e4ee;
10171031 --color-glass-surface: rgba(232, 233, 235, 0.74);
1018 --color-glass-fallback: rgba(237, 239, 241, 0.94);
1032 --color-glass-fallback: rgba(232, 239, 244, 0.94);
10191033 --color-glass-tint: rgba(232, 233, 235, 0.22);
10201034 --color-status-bar: #f5f7f8;
10211035 --color-md-body: #241523;
......@@ -1119,7 +1133,7 @@
11191133 --color-sheet: rgba(23, 33, 43, 0.98);
11201134 --color-sheet-solid: #17212b;
11211135 --color-card: #17212b;
1122 --color-grouped-card: #333b45;
1136 --color-grouped-card: #233544;
11231137 --color-card-alt: #333b45;
11241138 --color-card-translucent: rgba(23, 33, 43, 0.8);
11251139 --color-thread-canvas: #17212b;
......@@ -1129,7 +1143,7 @@
11291143 --color-thread-hover: #283e50;
11301144 --color-row-hover: #324e66;
11311145 --color-composer-panel: rgba(23, 33, 43, 0.92);
1132 --color-composer-surface: rgba(51, 59, 69, 0.9);
1146 --color-composer-surface: rgba(35, 53, 68, 0.9);
11331147 --color-composer-border: rgba(64, 85, 103, 0.8);
11341148 --color-foreground: #fffaff;
11351149 --color-foreground-secondary: #a5a7ad;
......@@ -1145,6 +1159,8 @@
11451159 --color-inline-skill-border: rgba(112, 185, 238, 0.42);
11461160 --color-inline-skill-foreground: #fffaff;
11471161 --color-primary: #5bd0d6;
1162 --color-prominent-action: #5bd0d6;
1163 --color-prominent-action-foreground: #241523;
11481164 --color-primary-foreground: #241523;
11491165 --color-primary-text: #5bd0d6;
11501166 --color-primary-shadow: #000000;
......@@ -1174,7 +1190,7 @@
11741190 --color-header-foreground: #fffaff;
11751191 --color-header-border: #36566f;
11761192 --color-glass-surface: rgba(65, 72, 81, 0.74);
1177 --color-glass-fallback: rgba(51, 59, 69, 0.9);
1193 --color-glass-fallback: rgba(35, 53, 68, 0.9);
11781194 --color-glass-tint: rgba(65, 72, 81, 0.22);
11791195 --color-status-bar: #17212b;
11801196 --color-md-body: #fffaff;
......@@ -1278,7 +1294,7 @@
12781294 --color-sheet: rgba(249, 247, 245, 0.98);
12791295 --color-sheet-solid: #f9f7f5;
12801296 --color-card: #f9f7f5;
1281 --color-grouped-card: #f1efee;
1297 --color-grouped-card: #f4ede9;
12821298 --color-card-alt: #f1efee;
12831299 --color-card-translucent: rgba(249, 247, 245, 0.8);
12841300 --color-thread-canvas: #f9f7f5;
......@@ -1288,7 +1304,7 @@
12881304 --color-thread-hover: #ead8cf;
12891305 --color-row-hover: #eee0d9;
12901306 --color-composer-panel: rgba(249, 247, 245, 0.88);
1291 --color-composer-surface: rgba(241, 239, 238, 0.94);
1307 --color-composer-surface: rgba(244, 237, 233, 0.94);
12921308 --color-composer-border: rgba(221, 210, 206, 0.8);
12931309 --color-foreground: #241523;
12941310 --color-foreground-secondary: #726870;
......@@ -1304,6 +1320,8 @@
13041320 --color-inline-skill-border: rgba(174, 85, 42, 0.42);
13051321 --color-inline-skill-foreground: #241523;
13061322 --color-primary: #b23535;
1323 --color-prominent-action: #b23535;
1324 --color-prominent-action-foreground: #fffaff;
13071325 --color-primary-foreground: #fffaff;
13081326 --color-primary-text: #b23535;
13091327 --color-primary-shadow: #000000;
......@@ -1333,7 +1351,7 @@
13331351 --color-header-foreground: #241523;
13341352 --color-header-border: #eee0d9;
13351353 --color-glass-surface: rgba(236, 233, 233, 0.74);
1336 --color-glass-fallback: rgba(241, 239, 238, 0.94);
1354 --color-glass-fallback: rgba(244, 237, 233, 0.94);
13371355 --color-glass-tint: rgba(236, 233, 233, 0.22);
13381356 --color-status-bar: #f9f7f5;
13391357 --color-md-body: #241523;
......@@ -1437,7 +1455,7 @@
14371455 --color-sheet: rgba(41, 30, 26, 0.98);
14381456 --color-sheet-solid: #291e1a;
14391457 --color-card: #291e1a;
1440 --color-grouped-card: #433835;
1458 --color-grouped-card: #432e23;
14411459 --color-card-alt: #433835;
14421460 --color-card-translucent: rgba(41, 30, 26, 0.8);
14431461 --color-thread-canvas: #291e1a;
......@@ -1447,7 +1465,7 @@
14471465 --color-thread-hover: #4f3528;
14481466 --color-row-hover: #644330;
14491467 --color-composer-panel: rgba(41, 30, 26, 0.92);
1450 --color-composer-surface: rgba(67, 56, 53, 0.9);
1468 --color-composer-surface: rgba(67, 46, 35, 0.9);
14511469 --color-composer-border: rgba(102, 76, 63, 0.8);
14521470 --color-foreground: #fffaff;
14531471 --color-foreground-secondary: #aca5a6;
......@@ -1463,6 +1481,8 @@
14631481 --color-inline-skill-border: rgba(240, 154, 100, 0.42);
14641482 --color-inline-skill-foreground: #fffaff;
14651483 --color-primary: #f78a7a;
1484 --color-prominent-action: #f78a7a;
1485 --color-prominent-action-foreground: #241523;
14661486 --color-primary-foreground: #241523;
14671487 --color-primary-text: #f78a7a;
14681488 --color-primary-shadow: #000000;
......@@ -1492,7 +1512,7 @@
14921512 --color-header-foreground: #fffaff;
14931513 --color-header-border: #6e4934;
14941514 --color-glass-surface: rgba(79, 69, 67, 0.74);
1495 --color-glass-fallback: rgba(67, 56, 53, 0.9);
1515 --color-glass-fallback: rgba(67, 46, 35, 0.9);
14961516 --color-glass-tint: rgba(79, 69, 67, 0.22);
14971517 --color-status-bar: #291e1a;
14981518 --color-md-body: #fffaff;
......@@ -1596,7 +1616,7 @@
15961616 --color-sheet: rgba(248, 247, 249, 0.98);
15971617 --color-sheet-solid: #f8f7f9;
15981618 --color-card: #f8f7f9;
1599 --color-grouped-card: #f0eff2;
1619 --color-grouped-card: #f0edf6;
16001620 --color-card-alt: #f0eff2;
16011621 --color-card-translucent: rgba(248, 247, 249, 0.8);
16021622 --color-thread-canvas: #f8f7f9;
......@@ -1606,7 +1626,7 @@
16061626 --color-thread-hover: #ded8ed;
16071627 --color-row-hover: #e5e0f0;
16081628 --color-composer-panel: rgba(248, 247, 249, 0.88);
1609 --color-composer-surface: rgba(240, 239, 242, 0.94);
1629 --color-composer-surface: rgba(240, 237, 246, 0.94);
16101630 --color-composer-border: rgba(214, 209, 222, 0.8);
16111631 --color-foreground: #241523;
16121632 --color-foreground-secondary: #716871;
......@@ -1622,6 +1642,8 @@
16221642 --color-inline-skill-border: rgba(114, 83, 185, 0.42);
16231643 --color-inline-skill-foreground: #241523;
16241644 --color-primary: #a82c87;
1645 --color-prominent-action: #a82c87;
1646 --color-prominent-action-foreground: #fffaff;
16251647 --color-primary-foreground: #fffaff;
16261648 --color-primary-text: #a82c87;
16271649 --color-primary-shadow: #000000;
......@@ -1651,7 +1673,7 @@
16511673 --color-header-foreground: #241523;
16521674 --color-header-border: #e5e0f0;
16531675 --color-glass-surface: rgba(235, 233, 237, 0.74);
1654 --color-glass-fallback: rgba(240, 239, 242, 0.94);
1676 --color-glass-fallback: rgba(240, 237, 246, 0.94);
16551677 --color-glass-tint: rgba(235, 233, 237, 0.22);
16561678 --color-status-bar: #f8f7f9;
16571679 --color-md-body: #241523;
......@@ -1755,7 +1777,7 @@
17551777 --color-sheet: rgba(29, 25, 41, 0.98);
17561778 --color-sheet-solid: #1d1929;
17571779 --color-card: #1d1929;
1758 --color-grouped-card: #383443;
1780 --color-grouped-card: #2d2643;
17591781 --color-card-alt: #383443;
17601782 --color-card-translucent: rgba(29, 25, 41, 0.8);
17611783 --color-thread-canvas: #1d1929;
......@@ -1765,7 +1787,7 @@
17651787 --color-thread-hover: #352c4f;
17661788 --color-row-hover: #433765;
17671789 --color-composer-panel: rgba(29, 25, 41, 0.92);
1768 --color-composer-surface: rgba(56, 52, 67, 0.9);
1790 --color-composer-surface: rgba(45, 38, 67, 0.9);
17691791 --color-composer-border: rgba(77, 67, 102, 0.8);
17701792 --color-foreground: #fffaff;
17711793 --color-foreground-secondary: #a09da6;
......@@ -1781,6 +1803,8 @@
17811803 --color-inline-skill-border: rgba(157, 125, 242, 0.42);
17821804 --color-inline-skill-foreground: #fffaff;
17831805 --color-primary: #f099d8;
1806 --color-prominent-action: #f099d8;
1807 --color-prominent-action-foreground: #241523;
17841808 --color-primary-foreground: #241523;
17851809 --color-primary-text: #f099d8;
17861810 --color-primary-shadow: #000000;
......@@ -1810,7 +1834,7 @@
18101834 --color-header-foreground: #fffaff;
18111835 --color-header-border: #4a3c70;
18121836 --color-glass-surface: rgba(69, 66, 80, 0.74);
1813 --color-glass-fallback: rgba(56, 52, 67, 0.9);
1837 --color-glass-fallback: rgba(45, 38, 67, 0.9);
18141838 --color-glass-tint: rgba(69, 66, 80, 0.22);
18151839 --color-status-bar: #1d1929;
18161840 --color-md-body: #fffaff;
apps/mobile/src/components/ProjectCloneBanner.tsx+1-1
......@@ -73,7 +73,7 @@ function BannerAction(props: { readonly label: string; readonly onPress: () => v
7373 <Pressable
7474 accessibilityRole="button"
7575 accessibilityLabel={props.label}
76 className="rounded-full border border-border bg-background px-3 py-1.5"
76 className="rounded-full border border-border bg-card px-3 py-1.5"
7777 onPress={props.onPress}
7878 >
7979 <Text className="font-t3-medium text-xs">{props.label}</Text>
apps/mobile/src/features/browser/PreviewStreamWebView.tsx+3-1
......@@ -461,7 +461,9 @@ function PreviewStreamDocumentView({
461461 {control.dialog.type === "prompt" ? (
462462 <TextInput
463463 accessibilityLabel="Dialog response"
464 className="rounded-lg border border-secondary-border bg-background px-3 py-2 text-foreground"
464 className="rounded-lg border border-input-border bg-input px-3 py-2 text-foreground"
465 placeholderTextColorClassName="accent-placeholder"
466 selectionColorClassName="accent-focus/32"
465467 value={promptText}
466468 onChangeText={setPromptText}
467469 />
apps/mobile/src/features/files/FileTreeBrowser.tsx+3-2
......@@ -54,6 +54,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {
5454 <Pressable
5555 accessibilityRole="button"
5656 accessibilityLabel={node.path}
57 accessibilityState={{ selected: props.selected }}
5758 onPressIn={() => {
5859 if (node.kind === "file") {
5960 props.onPreviewFile?.(node.path);
......@@ -68,7 +69,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {
6869 }}
6970 className={cn(
7071 "mx-2 min-h-[42px] flex-row items-center gap-2 rounded-[12px] px-2 active:bg-subtle",
71 props.selected && "bg-subtle-strong",
72 props.selected && "bg-thread-selected",
7273 )}
7374 style={{ paddingLeft: 8 + depth * 18 }}
7475 >
......@@ -87,7 +88,7 @@ const FileTreeRow = memo(function FileTreeRow(props: {
8788 className={cn(
8889 "min-w-0 flex-1 text-sm leading-normal",
8990 props.selected
90 ? "font-t3-bold text-foreground"
91 ? "font-t3-bold text-thread-selected-foreground"
9192 : node.ignored
9293 ? "font-t3-medium text-foreground-tertiary"
9394 : "font-t3-medium text-foreground-secondary",
apps/mobile/src/features/pull-requests/PullRequestControls.tsx+3-3
......@@ -23,7 +23,7 @@ export function PullRequestCardGroup(props: { readonly children: ReactNode }) {
2323 return (
2424 <Animated.View
2525 layout={PR_ROW_LAYOUT}
26 className="overflow-hidden rounded-[22px] border-continuous bg-grouped-card"
26 className="overflow-hidden rounded-[22px] border border-composer-border border-continuous bg-grouped-card"
2727 >
2828 {props.children}
2929 </Animated.View>
......@@ -218,7 +218,7 @@ export function PullRequestActionToolbar(props: {
218218 : "bubble.left.and.bubble.right"
219219 : undefined
220220 }
221 tintColor={colors["--color-foreground"]}
221 tintColor={colors["--color-prominent-action"]}
222222 disabled={primaryDisabled}
223223 separateBackground
224224 >
......@@ -237,7 +237,7 @@ export function PullRequestActionToolbar(props: {
237237 : "bubble.left.and.bubble.right"
238238 : undefined
239239 }
240 tintColor={colors["--color-foreground"]}
240 tintColor={colors["--color-prominent-action"]}
241241 disabled={primaryDisabled}
242242 onPress={primaryPress}
243243 separateBackground
apps/mobile/src/features/pull-requests/PullRequestFiles.tsx+1-1
......@@ -125,7 +125,7 @@ export function usePullRequestFilesContent(props: {
125125 <SymbolView
126126 name="checkmark.circle.fill"
127127 size={18}
128 tintColorClassName="accent-success-foreground"
128 tintColorClassName="accent-adaptive-emerald-600-400"
129129 />
130130 ) : null}
131131 <SymbolView name="chevron.right" size={12} tintColorClassName="accent-icon-muted" />
apps/mobile/src/features/pull-requests/PullRequestMergeControls.tsx+8-4
......@@ -169,7 +169,7 @@ export function PullRequestMergeControls(props: {
169169 className={
170170 Platform.OS === "android"
171171 ? "flex-row items-center gap-2"
172 : `flex-row overflow-hidden rounded-xl border-continuous ${canMerge ? "bg-foreground" : "bg-subtle-strong"}`
172 : `flex-row overflow-hidden rounded-xl border-continuous ${canMerge ? "bg-prominent-action" : "bg-subtle-strong"}`
173173 }
174174 >
175175 {Platform.OS === "android" ? (
......@@ -200,11 +200,13 @@ export function PullRequestMergeControls(props: {
200200 <SymbolView
201201 name="arrow.triangle.merge"
202202 size={16}
203 tintColorClassName={canMerge ? "accent-screen" : "accent-icon-muted"}
203 tintColorClassName={
204 canMerge ? "accent-prominent-action-foreground" : "accent-icon-muted"
205 }
204206 />
205207 )}
206208 <Text
207 className={`shrink text-center text-sm font-t3-semibold ${canMerge ? "text-screen" : "text-foreground-muted"}`}
209 className={`shrink text-center text-sm font-t3-semibold ${canMerge ? "text-prominent-action-foreground" : "text-foreground-muted"}`}
208210 >
209211 {busy ? "Working…" : !permissions.connected ? "Reconnect to merge" : label}
210212 </Text>
......@@ -255,7 +257,9 @@ export function PullRequestMergeControls(props: {
255257 <SymbolView
256258 name="chevron.down"
257259 size={13}
258 tintColorClassName={canMerge ? "accent-screen" : "accent-icon-muted"}
260 tintColorClassName={
261 canMerge ? "accent-prominent-action-foreground" : "accent-icon-muted"
262 }
259263 />
260264 </Pressable>
261265 )}
apps/mobile/src/features/pull-requests/PullRequestStackCard.tsx+1-1
......@@ -54,7 +54,7 @@ export function PullRequestStackCard(props: {
5454 isDraft: layer.isDraft === true,
5555 });
5656 return (
57 <View key={layer.number} className={selected ? "bg-subtle-strong" : undefined}>
57 <View key={layer.number} className={selected ? "bg-thread-selected" : undefined}>
5858 <PullRequestCardRow
5959 title={layer.title ?? layer.headBranch}
6060 icon={status.icon}
apps/mobile/src/features/threads/HtmlRenderWebView.tsx+1-1
......@@ -271,7 +271,7 @@ export function ThreadHtmlRender(props: {
271271 accessibilityRole="button"
272272 accessibilityLabel={`Open ${title}`}
273273 hitSlop={8}
274 className="absolute right-1.5 top-1.5 h-7 w-7 items-center justify-center rounded-full border border-border/60 bg-surface/80"
274 className="absolute right-1.5 top-1.5 h-7 w-7 items-center justify-center rounded-full border border-border/60 bg-card/80"
275275 onPress={() =>
276276 navigation.navigate("ThreadAttachment", {
277277 environmentId: String(props.environmentId),
apps/mobile/src/features/threads/McpAppFullscreenScreen.tsx+1-1
......@@ -120,7 +120,7 @@ export function McpAppFullscreenScreen({ route }: McpAppFullscreenScreenProps) {
120120 }, [awaitingUser, exitRequested, focused, navigation]);
121121
122122 return (
123 <View className="flex-1 bg-background" style={{ paddingTop: insets.top }}>
123 <View className="flex-1 bg-screen" style={{ paddingTop: insets.top }}>
124124 <View className="h-11 flex-row items-center justify-between px-3">
125125 <Text className="text-base font-semibold text-foreground" numberOfLines={1}>
126126 {app?.server ?? "App"}
apps/mobile/src/features/threads/PendingApprovalCard.tsx+2-2
......@@ -47,7 +47,7 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) {
4747 </Text>
4848 ) : null}
4949 {!canRespond ? (
50 <Text className="font-sans text-sm leading-5 text-adaptive-neutral-600-400">
50 <Text className="font-sans text-sm leading-5 text-foreground-muted">
5151 The provider process for this request is no longer available. Interrupt or restart the run
5252 to continue.
5353 </Text>
......@@ -73,7 +73,7 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) {
7373 ))}
7474 </View>
7575 {!props.canOperateThread ? (
76 <Text className="font-sans text-xs text-adaptive-neutral-500-400">
76 <Text className="font-sans text-xs text-foreground-muted">
7777 This connection cannot respond to approvals.
7878 </Text>
7979 ) : null}
apps/mobile/src/features/threads/PendingUserInputCard.tsx+1-1
......@@ -265,7 +265,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
265265 style={{ flexShrink: 1 }}
266266 >
267267 {!canRespond ? (
268 <Text className="font-sans text-sm leading-5 text-adaptive-neutral-600-400">
268 <Text className="font-sans text-sm leading-5 text-foreground-muted">
269269 The provider process for this request is no longer available. Interrupt or restart the
270270 run to continue.
271271 </Text>
apps/mobile/src/features/threads/ThreadFeed.tsx+1-1
......@@ -2758,7 +2758,7 @@ function ThreadFeedLoadEarlierControl(props: ThreadFeedHistoryControls) {
27582758 accessibilityLabel="Load earlier activity"
27592759 disabled={props.loading}
27602760 onPress={props.onLoadEarlier}
2761 className="min-h-9 flex-row items-center justify-center gap-2 rounded-full border border-border/60 bg-surface/80 px-4 py-2 disabled:opacity-50"
2761 className="min-h-9 flex-row items-center justify-center gap-2 rounded-full border border-border/60 bg-card/80 px-4 py-2 disabled:opacity-50"
27622762 >
27632763 {props.loading ? (
27642764 <AppActivityIndicator size="small" color={accentColor} />
apps/mobile/src/features/threads/thread-context-divider.tsx+2-2
......@@ -14,7 +14,7 @@ export function ThreadContextDivider(props: {
1414}) {
1515 return (
1616 <View className="mb-3 flex-row items-center gap-3 px-1 py-1">
17 <View className="h-px min-w-2 flex-1 bg-adaptive-neutral-200-a80-white-a8" />
17 <View className="h-px min-w-2 flex-1 bg-separator" />
1818 <View className="shrink flex-row flex-wrap items-center justify-center gap-1.5">
1919 <SymbolView name={props.icon} size={12} tintColor={props.iconColor} type="monochrome" />
2020 {props.active ? (
......@@ -40,7 +40,7 @@ export function ThreadContextDivider(props: {
4040 )}
4141 {props.children}
4242 </View>
43 <View className="h-px min-w-2 flex-1 bg-adaptive-neutral-200-a80-white-a8" />
43 <View className="h-px min-w-2 flex-1 bg-separator" />
4444 </View>
4545 );
4646}
apps/mobile/src/features/threads/thread-work-log.tsx+1-1
......@@ -1535,7 +1535,7 @@ function ToolActivityImage(props: {
15351535 const [loaded, setLoaded] = useState(false);
15361536 const [failed, setFailed] = useState(false);
15371537 return (
1538 <View className="h-4 w-4 items-center justify-center overflow-hidden rounded-[3px] bg-background">
1538 <View className="h-4 w-4 items-center justify-center overflow-hidden rounded-[3px] bg-screen">
15391539 {!loaded || failed ? <WorkLogIcon icon={props.fallback} color={props.color} /> : null}
15401540 {!failed ? (
15411541 <View
apps/mobile/src/features/workspace/WorkspaceDock.tsx+2-11
......@@ -1,4 +1,4 @@
1import { Keyboard, Platform, PlatformColor, Pressable, View } from "react-native";
1import { Keyboard, Pressable, View } from "react-native";
22
33import { SymbolView } from "../../components/AppSymbol";
44import { GlassSurface } from "../../components/GlassSurface";
......@@ -43,16 +43,7 @@ export function WorkspaceDock(props: { readonly onNewTask: () => void }) {
4343 <SymbolView
4444 name={tab === "threads" ? "text.bubble" : "arrow.triangle.pull"}
4545 size={23}
46 tintColor={
47 selected && Platform.OS === "ios" ? PlatformColor("systemBlue") : undefined
48 }
49 tintColorClassName={
50 selected && Platform.OS === "ios"
51 ? undefined
52 : selected
53 ? "accent-focus"
54 : "accent-icon"
55 }
46 tintColorClassName={selected ? "accent-focus" : "accent-icon"}
5647 />
5748 </Pressable>
5849 );
apps/mobile/src/lib/mobileTheme.test.ts+60
......@@ -255,6 +255,66 @@ describe("mobile themes", () => {
255255 },
256256 );
257257
258 it("keeps T3 Chat light grouped cards distinct from the sheet", () => {
259 const variables = getMobileThemeVariables("t3-chat", "light");
260 const group = variables["--color-grouped-card"];
261 expect(contrastRatio(group, variables["--color-sheet-solid"])).toBeGreaterThanOrEqual(1.1);
262 for (const role of ["--color-foreground", "--color-foreground-muted"] as const) {
263 expect(contrastRatio(variables[role], group)).toBeGreaterThanOrEqual(4.5);
264 }
265 });
266
267 it.each(MOBILE_THEME_IDS)("keeps %s prominent actions readable and themed", (themeId) => {
268 for (const appearance of ["light", "dark"] as const) {
269 const variables = getMobileThemeVariables(themeId, appearance);
270 const fill = variables["--color-prominent-action"];
271 expect(
272 contrastRatio(variables["--color-prominent-action-foreground"], fill),
273 ).toBeGreaterThanOrEqual(4.5);
274 expect(fill).toBe(
275 variables[
276 themeId === "t3-chat" && appearance === "dark"
277 ? "--color-primary-foreground"
278 : themeId === DEFAULT_MOBILE_THEME_ID || themeId === "t3-chat"
279 ? "--color-foreground"
280 : "--color-primary"
281 ],
282 );
283 }
284 });
285
286 it.each(["grove", "ocean", "ember", "iris"] as const)(
287 "keeps %s grouped cards and floating controls visibly tinted",
288 (themeId) => {
289 const saturation = (hex: string) => {
290 const channels = hex
291 .slice(1)
292 .match(/.{2}/g)!
293 .map((value) => parseInt(value, 16));
294 return (Math.max(...channels) - Math.min(...channels)) / Math.max(...channels);
295 };
296 for (const appearance of ["light", "dark"] as const) {
297 const variables = getMobileThemeVariables(themeId, appearance);
298 const sheet = variables["--color-sheet-solid"];
299 const group = variables["--color-grouped-card"];
300 expect(contrastRatio(group, sheet)).toBeGreaterThanOrEqual(1.06);
301 for (const role of ["--color-composer-surface", "--color-glass-fallback"] as const) {
302 const surface = flattenThemeColor(variables[role], sheet);
303 expect(contrastRatio(surface, sheet)).toBeGreaterThanOrEqual(1.06);
304 expect(contrastRatio(variables["--color-placeholder"], surface)).toBeGreaterThanOrEqual(
305 4.5,
306 );
307 if (appearance === "dark") {
308 expect(saturation(surface)).toBeGreaterThanOrEqual(saturation(sheet));
309 }
310 }
311 if (appearance === "dark") {
312 expect(saturation(group)).toBeGreaterThanOrEqual(saturation(sheet));
313 }
314 }
315 },
316 );
317
258318 it.each(["light", "dark"] as const)(
259319 "slightly strengthens default %s messages and separates fallback materials",
260320 (appearance) => {
apps/mobile/src/lib/mobileTheme.ts+20-7
......@@ -247,6 +247,7 @@ export function createMobileThemeVariables(
247247 colors: ThemeColors,
248248 appearance: MobileThemeAppearance,
249249 groupedCardColor = colors.surface,
250 prominentAction: readonly [string, string] = [colors.text, colors.canvas],
250251) {
251252 const c = nativeColors(colors);
252253 const groupedCard = themeColorToNativeColor(groupedCardColor);
......@@ -299,6 +300,8 @@ export function createMobileThemeVariables(
299300 "--color-inline-skill-border": withAlpha(c.accent, 0.42),
300301 "--color-inline-skill-foreground": c.accentSurfaceForeground,
301302 "--color-primary": c.messageAction,
303 "--color-prominent-action": themeColorToNativeColor(prominentAction[0]),
304 "--color-prominent-action-foreground": themeColorToNativeColor(prominentAction[1]),
302305 "--color-primary-foreground": c.messageActionForeground,
303306 "--color-primary-text": themeColorWithContrast(c.messageAction, textSurfaces),
304307 "--color-primary-shadow": "#000000",
......@@ -386,17 +389,18 @@ export function getMobileThemeVariables(
386389 overrides: Partial<MobileThemeVariables> | null = null,
387390): MobileThemeVariables {
388391 const colors = getMobileThemeColors(themeId, appearance);
389 // Mobile settings groups and fallback materials use tonal fills where desktop
390 // uses outlined cards. Raise flat desktop surfaces above the sheet so grouped
391 // content keeps a visible boundary. Regular cards retain their desktop surface.
392 // Mobile groups and floating controls need a tonal fill, rather than the
393 // nearly neutral raised surface used by desktop outlined cards.
392394 const groupedCard =
393395 themeId === DEFAULT_MOBILE_THEME_ID
394396 ? appearance === "light"
395397 ? colors.toolbarControlHover
396398 : colors.sidebarRowActive
397 : colors.surface === colors.chrome
398 ? colors.surfaceRaised
399 : colors.surface;
399 : themeId === "t3-chat"
400 ? appearance === "light"
401 ? colors.toolbarControl
402 : colors.surface
403 : colors.muted;
400404 const mobileColors =
401405 themeId === DEFAULT_MOBILE_THEME_ID
402406 ? {
......@@ -410,7 +414,16 @@ export function getMobileThemeVariables(
410414 ),
411415 }
412416 : colors;
413 const baseVariables = createMobileThemeVariables(mobileColors, appearance, groupedCard);
417 const baseVariables = createMobileThemeVariables(
418 mobileColors,
419 appearance,
420 groupedCard,
421 themeId === "t3-chat" && appearance === "dark"
422 ? [colors.messageActionForeground, colors.messageAction]
423 : themeId !== DEFAULT_MOBILE_THEME_ID && themeId !== "t3-chat"
424 ? [colors.messageAction, colors.messageActionForeground]
425 : undefined,
426 );
414427
415428 // The complete base record guarantees that optional overrides cannot leave a token undefined.
416429 return overrides ? ({ ...baseVariables, ...overrides } as MobileThemeVariables) : baseVariables;