authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-05 19:22:39-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-05 19:22:39-07:00
logb438447f67b6b61bbe6f564d8b78fd90702117c5
tree452b22de63e9976c1d13ce3f3bd8732c870fe16b
parenteee05575ebd514db36f61d7eb05d2258a10c96bd
signature Signed by PGP key B5690EEEBB952194

fix(mobile): use selected theme across input forms and controls (#10239)


27 files changed, 184 insertions(+), 116 deletions(-)

apps/mobile/generated-uniwind-default-theme-variables.json+6
......@@ -28,6 +28,9 @@
2828 "--color-switch-active-thumb": "#ffffff",
2929 "--color-switch-inactive-track": "rgba(0, 0, 0, 0.08)",
3030 "--color-switch-inactive-thumb": "#8e8e93",
31 "--color-warning": "#fffbeb",
32 "--color-warning-border": "#fde68a",
33 "--color-warning-foreground": "#b45309",
3134 "--color-danger": "#fef2f2",
3235 "--color-danger-border": "rgba(239, 68, 68, 0.12)",
3336 "--color-danger-foreground": "#dc2626",
......@@ -95,6 +98,9 @@
9598 "--color-switch-active-thumb": "#ffffff",
9699 "--color-switch-inactive-track": "rgba(255, 255, 255, 0.06)",
97100 "--color-switch-inactive-thumb": "#8e8e93",
101 "--color-warning": "rgba(69, 26, 3, 0.4)",
102 "--color-warning-border": "rgba(120, 53, 15, 0.6)",
103 "--color-warning-foreground": "#fcd34d",
98104 "--color-danger": "rgba(239, 68, 68, 0.14)",
99105 "--color-danger-border": "rgba(248, 113, 113, 0.18)",
100106 "--color-danger-foreground": "#fca5a5",
apps/mobile/generated-uniwind-themes.css+30
......@@ -150,6 +150,9 @@
150150 --color-switch-active-thumb: #ffffff;
151151 --color-switch-inactive-track: #f1c4e6;
152152 --color-switch-inactive-thumb: #8d1255;
153 --color-warning: #fcf0ea;
154 --color-warning-border: rgba(245, 158, 11, 0.32);
155 --color-warning-foreground: #b05109;
153156 --color-danger: #fde4f1;
154157 --color-danger-border: rgba(247, 8, 108, 0.32);
155158 --color-danger-foreground: #9d174d;
......@@ -275,6 +278,9 @@
275278 --color-switch-active-thumb: #fbd0e8;
276279 --color-switch-inactive-track: #362d3d;
277280 --color-switch-inactive-thumb: #e7d0dd;
281 --color-warning: #412f20;
282 --color-warning-border: rgba(245, 158, 11, 0.32);
283 --color-warning-foreground: #fbbf24;
278284 --color-danger: #331a2b;
279285 --color-danger-border: rgba(157, 23, 77, 0.32);
280286 --color-danger-foreground: #fbd0e8;
......@@ -400,6 +406,9 @@
400406 --color-switch-active-thumb: #fffaff;
401407 --color-switch-inactive-track: #e2ede7;
402408 --color-switch-inactive-thumb: #6e696f;
409 --color-warning: #f4f0e1;
410 --color-warning-border: rgba(254, 154, 0, 0.32);
411 --color-warning-foreground: #b64a00;
403412 --color-danger: #f4e7e5;
404413 --color-danger-border: rgba(251, 44, 54, 0.32);
405414 --color-danger-foreground: #c10007;
......@@ -525,6 +534,9 @@
525534 --color-switch-active-thumb: #241523;
526535 --color-switch-inactive-track: #2a4b39;
527536 --color-switch-inactive-thumb: #9da5a2;
537 --color-warning: #3f3a1c;
538 --color-warning-border: rgba(254, 154, 0, 0.32);
539 --color-warning-foreground: #ffb900;
528540 --color-danger: #3f2c28;
529541 --color-danger-border: rgba(251, 65, 74, 0.32);
530542 --color-danger-foreground: #ff6668;
......@@ -650,6 +662,9 @@
650662 --color-switch-active-thumb: #fffaff;
651663 --color-switch-inactive-track: #e4ecf2;
652664 --color-switch-inactive-thumb: #6f6873;
665 --color-warning: #f6efe4;
666 --color-warning-border: rgba(254, 154, 0, 0.32);
667 --color-warning-foreground: #b74b00;
653668 --color-danger: #f5e6e9;
654669 --color-danger-border: rgba(251, 44, 54, 0.32);
655670 --color-danger-foreground: #c10007;
......@@ -775,6 +790,9 @@
775790 --color-switch-active-thumb: #241523;
776791 --color-switch-inactive-track: #293f52;
777792 --color-switch-inactive-thumb: #969ca6;
793 --color-warning: #3c3424;
794 --color-warning-border: rgba(254, 154, 0, 0.32);
795 --color-warning-foreground: #ffb900;
778796 --color-danger: #3c2630;
779797 --color-danger-border: rgba(251, 65, 74, 0.32);
780798 --color-danger-foreground: #ff6467;
......@@ -900,6 +918,9 @@
900918 --color-switch-active-thumb: #fffaff;
901919 --color-switch-inactive-track: #f3eae5;
902920 --color-switch-inactive-thumb: #74686f;
921 --color-warning: #f9efe2;
922 --color-warning-border: rgba(254, 154, 0, 0.32);
923 --color-warning-foreground: #b84b00;
903924 --color-danger: #f9e7e6;
904925 --color-danger-border: rgba(251, 44, 54, 0.32);
905926 --color-danger-foreground: #c10007;
......@@ -1025,6 +1046,9 @@
10251046 --color-switch-active-thumb: #241523;
10261047 --color-switch-inactive-track: #513728;
10271048 --color-switch-inactive-thumb: #a59996;
1049 --color-warning: #4b3215;
1050 --color-warning-border: rgba(254, 154, 0, 0.32);
1051 --color-warning-foreground: #ffb900;
10281052 --color-danger: #4a2321;
10291053 --color-danger-border: rgba(251, 65, 74, 0.32);
10301054 --color-danger-foreground: #ff6467;
......@@ -1150,6 +1174,9 @@
11501174 --color-switch-active-thumb: #fffaff;
11511175 --color-switch-inactive-track: #edeaf4;
11521176 --color-switch-inactive-thumb: #726874;
1177 --color-warning: #f8efe5;
1178 --color-warning-border: rgba(254, 154, 0, 0.32);
1179 --color-warning-foreground: #b84b00;
11531180 --color-danger: #f8e6ea;
11541181 --color-danger-border: rgba(251, 44, 54, 0.32);
11551182 --color-danger-foreground: #c10007;
......@@ -1275,6 +1302,9 @@
12751302 --color-switch-active-thumb: #241523;
12761303 --color-switch-inactive-track: #362d51;
12771304 --color-switch-inactive-thumb: #9690a1;
1305 --color-warning: #412e23;
1306 --color-warning-border: rgba(254, 154, 0, 0.32);
1307 --color-warning-foreground: #ffb900;
12781308 --color-danger: #40202e;
12791309 --color-danger-border: rgba(251, 65, 74, 0.32);
12801310 --color-danger-foreground: #ff6467;
apps/mobile/global.css+10
......@@ -52,6 +52,11 @@
5252 --color-switch-inactive-track: rgba(0, 0, 0, 0.08);
5353 --color-switch-inactive-thumb: #8e8e93;
5454
55 /* Warning */
56 --color-warning: #fffbeb;
57 --color-warning-border: #fde68a;
58 --color-warning-foreground: #b45309;
59
5560 /* Danger */
5661 --color-danger: #fef2f2;
5762 --color-danger-border: rgba(239, 68, 68, 0.12);
......@@ -151,6 +156,11 @@
151156 --color-switch-inactive-track: rgba(255, 255, 255, 0.06);
152157 --color-switch-inactive-thumb: #8e8e93;
153158
159 /* Warning */
160 --color-warning: rgba(69, 26, 3, 0.4);
161 --color-warning-border: rgba(120, 53, 15, 0.6);
162 --color-warning-foreground: #fcd34d;
163
154164 /* Danger */
155165 --color-danger: rgba(239, 68, 68, 0.14);
156166 --color-danger-border: rgba(248, 113, 113, 0.18);
apps/mobile/src/components/AppText.tsx+2
......@@ -35,6 +35,8 @@ export function AppTextInput({ className, ref, ...props }: AppTextInputProps) {
3535 className,
3636 )}
3737 placeholderTextColorClassName="accent-placeholder"
38 selectionColorClassName="accent-foreground-secondary"
39 cursorColorClassName="accent-foreground-secondary"
3840 {...props}
3941 />
4042 );
apps/mobile/src/components/ComposerAttachmentStrip.tsx+1-1
......@@ -195,7 +195,7 @@ function ComposerAttachmentContent(props: ComposerAttachmentThumbnailProps) {
195195 <SymbolView
196196 name="doc.text"
197197 size={props.compact ? 15 : 22}
198 tintColor="#a3a3a3"
198 tintColorClassName="accent-icon-subtle"
199199 type="monochrome"
200200 />
201201 {!props.compact ? (
apps/mobile/src/components/ErrorBanner.tsx+2-2
......@@ -3,8 +3,8 @@ import { View } from "react-native";
33import { AppText as Text } from "./AppText";
44export function ErrorBanner(props: { readonly message: string }) {
55 return (
6 <View className="rounded-2xl border border-adaptive-rose-300-a70-400-a28 bg-adaptive-rose-100-a80-500-a12 px-3.5 py-3">
7 <Text className="font-t3-medium text-sm text-adaptive-rose-700-300">{props.message}</Text>
6 <View className="rounded-2xl border border-danger-border bg-danger px-3.5 py-3">
7 <Text className="font-t3-medium text-sm text-danger-foreground">{props.message}</Text>
88 </View>
99 );
1010}
apps/mobile/src/features/connection/CloudEnvironmentRows.tsx+1-1
......@@ -299,7 +299,7 @@ function CloudEnvironmentRowShell(props: {
299299 traceId: props.connectionErrorTraceId,
300300 });
301301 const statusClassName = props.connectionError
302 ? "text-adaptive-rose-500-400"
302 ? "text-danger-foreground"
303303 : "text-foreground-muted";
304304 const [errorMeasurement, setErrorMeasurement] = useState<{
305305 readonly text: string;
apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx+1-1
......@@ -96,7 +96,7 @@ export function ConnectionEnvironmentRow(props: {
9696 <Text
9797 className={cn(
9898 "text-xs",
99 hasConnectionFailure ? "text-adaptive-rose-500-400" : "text-foreground-muted",
99 hasConnectionFailure ? "text-danger-foreground" : "text-foreground-muted",
100100 )}
101101 numberOfLines={props.expanded ? undefined : 1}
102102 selectable={props.expanded}
apps/mobile/src/features/connection/connectionTone.ts+10-10
......@@ -12,32 +12,32 @@ export function connectionTone(state: RemoteClientConnectionState): StatusTone {
1212 case "reconnecting":
1313 return {
1414 label: "Reconnecting",
15 pillClassName: "bg-adaptive-amber-500-a12-a16",
16 textClassName: "text-adaptive-amber-700-300",
15 pillClassName: "bg-warning",
16 textClassName: "text-warning-foreground",
1717 };
1818 case "connecting":
1919 return {
2020 label: "Connecting",
21 pillClassName: "bg-adaptive-sky-500-a12-a16",
22 textClassName: "text-adaptive-sky-700-300",
21 pillClassName: "bg-primary/10",
22 textClassName: "text-foreground-secondary",
2323 };
2424 case "error":
2525 return {
2626 label: "Connection failed",
27 pillClassName: "bg-adaptive-rose-500-a12-a16",
28 textClassName: "text-adaptive-rose-700-300",
27 pillClassName: "bg-danger",
28 textClassName: "text-danger-foreground",
2929 };
3030 case "offline":
3131 return {
3232 label: "Offline",
33 pillClassName: "bg-adaptive-rose-500-a12-a16",
34 textClassName: "text-adaptive-rose-700-300",
33 pillClassName: "bg-danger",
34 textClassName: "text-danger-foreground",
3535 };
3636 case "available":
3737 return {
3838 label: "Available",
39 pillClassName: "bg-adaptive-neutral-500-a10-a16",
40 textClassName: "text-adaptive-neutral-600-300",
39 pillClassName: "bg-subtle",
40 textClassName: "text-foreground-secondary",
4141 };
4242 }
4343}
apps/mobile/src/features/files/ThreadFilesRouteScreen.tsx+3-3
......@@ -190,11 +190,11 @@ function FileContent(props: {
190190 return (
191191 <View className="flex-1 bg-sheet">
192192 {props.truncated ? (
193 <View className="border-b border-adaptive-amber-200-900-a60 bg-adaptive-amber-50-950-a40 px-4 py-2">
194 <Text className="text-2xs font-t3-bold uppercase text-adaptive-amber-700-300">
193 <View className="border-b border-warning-border bg-warning px-4 py-2">
194 <Text className="text-2xs font-t3-bold uppercase text-warning-foreground">
195195 Partial file
196196 </Text>
197 <Text className="text-xs leading-snug text-adaptive-amber-800-200">
197 <Text className="text-xs leading-snug text-warning-foreground">
198198 Preview limited to the first 1 MB of a truncated file.
199199 </Text>
200200 </View>
apps/mobile/src/features/home/thread-swipe-actions.tsx+25-8
......@@ -62,7 +62,7 @@ interface ThreadSwipeAction {
6262}
6363
6464interface ThreadSwipeSecondaryAction extends ThreadSwipeAction {
65 readonly backgroundColor: string;
65 readonly tone: "primary" | "secondary" | "danger";
6666}
6767
6868function swipeActionsWidth(hasSecondaryAction: boolean) {
......@@ -80,7 +80,7 @@ function resolveSecondaryAction(input: {
8080 if (input.secondaryAction === undefined) {
8181 return {
8282 accessibilityLabel: `Delete ${input.threadTitle}`,
83 backgroundColor: "#ff2d55",
83 tone: "danger",
8484 icon: "trash",
8585 label: "Delete",
8686 onPress: () => {
......@@ -92,7 +92,7 @@ function resolveSecondaryAction(input: {
9292 const action = input.secondaryAction;
9393 return {
9494 ...action,
95 backgroundColor: "#5856d6",
95 tone: "secondary",
9696 menu:
9797 action.menu === undefined
9898 ? undefined
......@@ -359,7 +359,7 @@ export function ThreadSwipeable(props: {
359359function SwipeActionButton(props: {
360360 readonly accessibilityLabel: string;
361361 readonly actionsWidth: number;
362 readonly backgroundColor: string;
362 readonly tone: "primary" | "secondary" | "danger";
363363 readonly compact: boolean;
364364 readonly entryRange: readonly [number, number];
365365 readonly fullSwipeThreshold: number;
......@@ -462,9 +462,15 @@ function SwipeActionButton(props: {
462462 >
463463 <View style={{ height: circleSize, width: circleSize }}>
464464 <Animated.View
465 className={
466 props.tone === "danger"
467 ? "bg-danger"
468 : props.tone === "secondary"
469 ? "bg-secondary"
470 : "bg-primary"
471 }
465472 style={[
466473 {
467 backgroundColor: props.backgroundColor,
468474 borderRadius: 999,
469475 height: circleSize,
470476 left: 0,
......@@ -488,7 +494,18 @@ function SwipeActionButton(props: {
488494 iconStyle,
489495 ]}
490496 >
491 <SymbolView name={props.icon} size={iconSize} tintColor="#ffffff" type="monochrome" />
497 <SymbolView
498 name={props.icon}
499 size={iconSize}
500 tintColorClassName={
501 props.tone === "danger"
502 ? "accent-danger-foreground"
503 : props.tone === "secondary"
504 ? "accent-secondary-foreground"
505 : "accent-primary-foreground"
506 }
507 type="monochrome"
508 />
492509 </Animated.View>
493510 </View>
494511 <Animated.View
......@@ -568,7 +585,7 @@ export function ThreadSwipeActions(props: {
568585 <SwipeActionButton
569586 accessibilityLabel={props.primaryAction.accessibilityLabel}
570587 actionsWidth={actionsWidth}
571 backgroundColor="#007aff"
588 tone="primary"
572589 compact={props.compact}
573590 entryRange={
574591 secondaryAction === null
......@@ -586,7 +603,7 @@ export function ThreadSwipeActions(props: {
586603 <SwipeActionButton
587604 accessibilityLabel={secondaryAction.accessibilityLabel}
588605 actionsWidth={actionsWidth}
589 backgroundColor={secondaryAction.backgroundColor}
606 tone={secondaryAction.tone}
590607 compact={props.compact}
591608 entryRange={[8, ACTION_ITEM_WIDTH * 0.72]}
592609 fullSwipeThreshold={props.fullSwipeThreshold}
apps/mobile/src/features/review/ReviewSheet.tsx+3-5
......@@ -80,11 +80,9 @@ const SHOWCASE_ENABLED = process.env.EXPO_PUBLIC_SHOWCASE === "1";
8080
8181const ReviewNotice = memo(function ReviewNotice(props: { readonly notice: string }) {
8282 return (
83 <View className="border-b border-adaptive-amber-200-900-a60 bg-adaptive-amber-50-950-a40 px-4 py-3">
84 <Text className="text-xs font-t3-bold uppercase text-adaptive-amber-700-300">
85 Partial diff
86 </Text>
87 <Text className="text-xs leading-normal text-adaptive-amber-800-200">{props.notice}</Text>
83 <View className="border-b border-warning-border bg-warning px-4 py-3">
84 <Text className="text-xs font-t3-bold uppercase text-warning-foreground">Partial diff</Text>
85 <Text className="text-xs leading-normal text-warning-foreground">{props.notice}</Text>
8886 </View>
8987 );
9088});
apps/mobile/src/features/settings/appearance/components/FontSizeSliderRow.tsx+1-2
......@@ -176,10 +176,9 @@ export function FontSizeSliderRow(props: {
176176 />
177177 </View>
178178 <Animated.View
179 className="absolute left-0 rounded-full bg-white"
179 className="absolute left-0 rounded-full border-border bg-primary-foreground"
180180 style={[
181181 {
182 borderColor: "rgba(0, 0, 0, 0.06)",
183182 borderWidth: 1,
184183 height: THUMB_SIZE,
185184 marginTop: -THUMB_SIZE / 2,
apps/mobile/src/features/threads/GitActionProgressOverlay.tsx+3-5
......@@ -143,9 +143,7 @@ function OverlayContent(props: { readonly progress: GitActionProgress }) {
143143 }
144144
145145 const bgClass =
146 progress.phase === "error"
147 ? "border-adaptive-red-200-800 bg-adaptive-red-50-950-a80"
148 : "bg-card border-border";
146 progress.phase === "error" ? "border-danger-border bg-danger" : "bg-card border-border";
149147
150148 return (
151149 <Animated.View
......@@ -169,11 +167,11 @@ function OverlayIcon(props: { readonly phase: GitActionProgress["phase"] }) {
169167 );
170168 case "error":
171169 return (
172 <View className="h-6 w-6 items-center justify-center rounded-full bg-red-500">
170 <View className="h-6 w-6 items-center justify-center rounded-full bg-danger">
173171 <SymbolView
174172 name="exclamationmark.triangle"
175173 size={12}
176 tintColor="white"
174 tintColorClassName="accent-danger-foreground"
177175 type="monochrome"
178176 />
179177 </View>
apps/mobile/src/features/threads/PendingApprovalCard.tsx+11-13
......@@ -30,22 +30,20 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) {
3030 // Opaque for the same reason as PendingUserInputCard: nothing blurs the feed
3131 // behind this card, so a translucent surface bleeds messages through it.
3232 return (
33 <View className="gap-2.5 rounded-[20px] border border-adaptive-neutral-200-white-a6 bg-adaptive-neutral-100-900 p-4">
34 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-adaptive-sky-700-300">
33 <View className="gap-2.5 rounded-[20px] border border-border bg-card-alt p-4">
34 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-foreground-secondary">
3535 Approval needed
3636 </Text>
37 <Text className="font-t3-bold text-lg text-adaptive-neutral-950-50">
37 <Text className="font-t3-bold text-lg text-foreground">
3838 {props.approval.appName ?? props.approval.requestKind}
3939 </Text>
4040 {props.approval.detail ? (
41 <Text className="font-sans text-sm leading-normal text-adaptive-neutral-600-400">
41 <Text className="font-sans text-sm leading-normal text-foreground-secondary">
4242 {props.approval.detail}
4343 </Text>
4444 ) : null}
4545 {warning ? (
46 <Text className="font-sans text-xs leading-normal text-adaptive-amber-700-300">
47 {warning}
48 </Text>
46 <Text className="font-sans text-xs leading-normal text-warning-foreground">{warning}</Text>
4947 ) : null}
5048 <View className="flex-row flex-wrap gap-2.5">
5149 {options.map((option) => (
......@@ -53,10 +51,10 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) {
5351 key={option.decision}
5452 className={`items-center justify-center rounded-[14px] px-3.5 py-3 ${
5553 option.decision === "accept"
56 ? "bg-blue-500"
54 ? "bg-primary"
5755 : option.decision === "decline"
58 ? "bg-adaptive-rose-100-500-a18"
59 : "bg-adaptive-neutral-200-800"
56 ? "bg-danger"
57 : "bg-subtle-strong"
6058 }`}
6159 disabled={props.respondingApprovalId === props.approval.requestId}
6260 onPress={() => void props.onRespond(props.approval.requestId, option.decision)}
......@@ -64,10 +62,10 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) {
6462 <Text
6563 className={`text-sm ${
6664 option.decision === "accept"
67 ? "font-t3-extrabold text-white"
65 ? "font-t3-extrabold text-primary-foreground"
6866 : option.decision === "decline"
69 ? "font-t3-bold text-adaptive-rose-700-300"
70 : "font-t3-bold text-adaptive-neutral-950-50"
67 ? "font-t3-bold text-danger-foreground"
68 : "font-t3-bold text-foreground"
7169 }`}
7270 >
7371 {option.label}
apps/mobile/src/features/threads/PendingUserInputCard.tsx+22-21
......@@ -161,7 +161,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
161161 pointerEvents={props.collapsed ? "auto" : "none"}
162162 accessibilityElementsHidden={!props.collapsed}
163163 importantForAccessibility={props.collapsed ? "auto" : "no-hide-descendants"}
164 className="flex-row items-center gap-2 rounded-full border border-adaptive-neutral-200-white-a6 bg-adaptive-neutral-100-900 py-1.5 pl-4 pr-1.5"
164 className="flex-row items-center gap-2 rounded-full border border-border bg-card-alt py-1.5 pl-4 pr-1.5"
165165 >
166166 <Pressable
167167 accessibilityRole="button"
......@@ -171,10 +171,10 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
171171 onPress={props.onToggleCollapsed}
172172 className="min-h-10 flex-1 flex-row items-center gap-2 active:opacity-70"
173173 >
174 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-adaptive-sky-700-300">
174 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-foreground-secondary">
175175 User input needed
176176 </Text>
177 <Text className="font-sans text-xs text-adaptive-neutral-500-400">
177 <Text className="font-sans text-xs text-foreground-muted">
178178 {questionCount} question{questionCount === 1 ? "" : "s"}
179179 </Text>
180180 <View className="flex-1" />
......@@ -216,7 +216,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
216216 : FadeOutDown.duration(USER_INPUT_TOGGLE_DURATION_MS).easing(Easing.out(Easing.cubic))
217217 }
218218 layout={CARD_LAYOUT_TRANSITION}
219 className="overflow-hidden gap-2.5 rounded-[20px] border border-adaptive-neutral-200-white-a6 bg-adaptive-neutral-100-900 p-4"
219 className="overflow-hidden gap-2.5 rounded-[20px] border border-border bg-card-alt p-4"
220220 style={
221221 EXPANDED_CARD_IS_OVERLAY
222222 ? [{ maxHeight: props.maxHeight }, cardAnimatedStyle]
......@@ -230,14 +230,12 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
230230 className="flex-row items-start gap-2"
231231 >
232232 <View className="flex-1 gap-2.5">
233 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-adaptive-sky-700-300">
233 <Text className="font-t3-bold text-2xs uppercase tracking-[1.1px] text-foreground-secondary">
234234 User input needed
235235 </Text>
236 <Text className="font-t3-bold text-lg text-adaptive-neutral-950-50">
237 Fill in the pending answers
238 </Text>
236 <Text className="font-t3-bold text-lg text-foreground">Fill in the pending answers</Text>
239237 </View>
240 <View className="h-8 w-8 items-center justify-center rounded-full bg-adaptive-neutral-200-a70-white-a8">
238 <View className="h-8 w-8 items-center justify-center rounded-full bg-subtle-strong">
241239 <SymbolView
242240 name="chevron.down"
243241 size={13}
......@@ -259,10 +257,10 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
259257 const draft = props.drafts[question.id];
260258 return (
261259 <View key={question.id} className="gap-2 pt-1">
262 <Text className="font-t3-bold text-xs uppercase tracking-[1px] text-neutral-500">
260 <Text className="font-t3-bold text-xs uppercase tracking-[1px] text-foreground-muted">
263261 {question.header}
264262 </Text>
265 <Text className="font-sans text-base leading-snug text-adaptive-neutral-950-50">
263 <Text className="font-sans text-base leading-snug text-foreground">
266264 {question.question}
267265 </Text>
268266 <View className="gap-2">
......@@ -276,9 +274,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
276274 key={optionValue}
277275 className={cn(
278276 "min-h-12 w-full rounded-2xl border px-3.5 py-3",
279 selected
280 ? "border-adaptive-blue-300-a50-blue-400-a28 bg-adaptive-blue-50-blue-400-a14"
281 : "border-adaptive-neutral-200-white-a6 bg-adaptive-white-neutral-950-a70",
277 selected ? "border-primary bg-primary/10" : "border-border bg-input",
282278 )}
283279 onPress={() =>
284280 props.onSelectOption(
......@@ -292,15 +288,13 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
292288 <Text
293289 className={cn(
294290 "font-t3-bold text-sm",
295 selected
296 ? "text-adaptive-sky-700-300"
297 : "text-adaptive-neutral-600-300",
291 selected ? "text-foreground" : "text-foreground-secondary",
298292 )}
299293 >
300294 {option.label}
301295 </Text>
302296 {description ? (
303 <Text className="font-sans text-sm leading-5 text-adaptive-neutral-500-400">
297 <Text className="font-sans text-sm leading-5 text-foreground-muted">
304298 {description}
305299 </Text>
306300 ) : null}
......@@ -318,7 +312,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
318312 onFocus={() => props.onInputFocusChange?.(true)}
319313 onBlur={() => props.onInputFocusChange?.(false)}
320314 placeholder="Or type a custom answer"
321 className="min-h-[54px] rounded-2xl border border-adaptive-neutral-200-white-a8 bg-adaptive-white-neutral-950-a70 px-3.5 py-3 font-sans text-base text-adaptive-neutral-950-50"
315 className="min-h-[54px] rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-base text-foreground"
322316 />
323317 ) : null}
324318 </View>
......@@ -328,14 +322,21 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) {
328322 <Pressable
329323 className={cn(
330324 "items-center justify-center rounded-2xl px-4 py-3.5",
331 props.answers ? "bg-blue-500" : "bg-adaptive-neutral-200-700-a60",
325 props.answers ? "bg-primary" : "bg-subtle-strong",
332326 )}
333327 disabled={
334328 props.answers === null || props.respondingUserInputId === props.pendingUserInput.requestId
335329 }
336330 onPress={() => void props.onSubmit()}
337331 >
338 <Text className="font-t3-extrabold text-sm text-white">Submit answers</Text>
332 <Text
333 className={cn(
334 "font-t3-extrabold text-sm",
335 props.answers ? "text-primary-foreground" : "text-foreground-muted",
336 )}
337 >
338 Submit answers
339 </Text>
339340 </Pressable>
340341 </Animated.View>
341342 ) : null;
apps/mobile/src/features/threads/ThreadFeed.tsx+12-7
......@@ -504,7 +504,12 @@ function MessageAttachmentFile(props: {
504504function MessageAttachmentUnknown(props: { readonly name: string }) {
505505 return (
506506 <View className="flex-row items-center gap-2 py-1">
507 <SymbolView name="doc.text" size={16} tintColor="#a3a3a3" type="monochrome" />
507 <SymbolView
508 name="doc.text"
509 size={16}
510 tintColorClassName="accent-icon-subtle"
511 type="monochrome"
512 />
508513 <Text className="min-w-0 flex-1 text-sm text-foreground" numberOfLines={1}>
509514 {props.name}
510515 </Text>
......@@ -1352,7 +1357,7 @@ function renderFeedEntry(
13521357 accessibilityState={{ expanded: entry.expanded }}
13531358 onPress={() => props.onToggleTurnFold(entry.turnId)}
13541359 hitSlop={4}
1355 className="mb-1 min-h-11 flex-row items-center gap-2 border-b border-adaptive-neutral-200-a80-white-a8 px-2"
1360 className="mb-1 min-h-11 flex-row items-center gap-2 border-b border-border px-2"
13561361 style={{
13571362 minHeight: Math.max(TURN_FOLD_HEIGHT - 3.5, props.workRowSizing.estimatedRowHeight),
13581363 }}
......@@ -1406,7 +1411,7 @@ function renderFeedEntry(
14061411 accessibilityLabel={label}
14071412 className="mb-3 flex-row items-center gap-3 px-1 py-1"
14081413 >
1409 <View className="h-px flex-1 bg-adaptive-neutral-200-a80-white-a8" />
1414 <View className="h-px flex-1 bg-border" />
14101415 <View className="shrink-0 flex-row items-center gap-1.5">
14111416 <SymbolView
14121417 name="arrow.down.right.and.arrow.up.left"
......@@ -1416,7 +1421,7 @@ function renderFeedEntry(
14161421 />
14171422 <Text className="font-t3-medium text-xs text-foreground-muted">{label}</Text>
14181423 </View>
1419 <View className="h-px flex-1 bg-adaptive-neutral-200-a80-white-a8" />
1424 <View className="h-px flex-1 bg-border" />
14201425 </View>
14211426 );
14221427 }
......@@ -1503,7 +1508,7 @@ function renderFeedEntry(
15031508 })}
15041509 </View>
15051510 <View className="mt-1 flex-row items-center justify-end gap-1 pr-0.5">
1506 <Text className="font-t3-medium text-xs tabular-nums text-adaptive-neutral-600-400">
1511 <Text className="font-t3-medium text-xs tabular-nums text-foreground-secondary">
15071512 {timestampLabel}
15081513 </Text>
15091514 {message.text.trim().length > 0 ? (
......@@ -1552,7 +1557,7 @@ function renderFeedEntry(
15521557 attachmentId={attachment.id}
15531558 name={attachment.name}
15541559 mimeType={attachment.mimeType}
1555 className="mt-1.5 aspect-[1.3] w-full rounded-[18px] bg-adaptive-neutral-200-800"
1560 className="mt-1.5 aspect-[1.3] w-full rounded-[18px] bg-subtle-strong"
15561561 onPressPreview={props.onPressPreview}
15571562 />
15581563 ) : isFileAttachment(attachment) ? (
......@@ -1576,7 +1581,7 @@ function renderFeedEntry(
15761581 buttonSize={28}
15771582 iconSize={13}
15781583 />
1579 <Text className="font-t3-medium text-xs tabular-nums text-adaptive-neutral-600-400">
1584 <Text className="font-t3-medium text-xs tabular-nums text-foreground-secondary">
15801585 {timestampLabel}
15811586 </Text>
15821587 </View>
apps/mobile/src/features/threads/git/GitCommitSheet.tsx+1-1
......@@ -85,7 +85,7 @@ export function GitCommitSheet(_props: GitCommitSheetProps) {
8585 </Text>
8686 </View>
8787 {isDefaultRef ? (
88 <Text className="text-xs leading-normal text-adaptive-amber-700-400">
88 <Text className="text-xs leading-normal text-warning-foreground">
8989 Warning: this is the default branch.
9090 </Text>
9191 ) : null}
apps/mobile/src/features/threads/thread-list-items.tsx+2-2
......@@ -297,8 +297,8 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: {
297297 );
298298
299299 const statusPill = (
300 <View className="rounded-full bg-adaptive-zinc-500-a12-a16 px-1.5 py-0.5">
301 <Text className="text-3xs font-t3-bold text-adaptive-zinc-600-300">Pending</Text>
300 <View className="rounded-full bg-subtle px-1.5 py-0.5">
301 <Text className="text-3xs font-t3-bold text-foreground-muted">Pending</Text>
302302 </View>
303303 );
304304
apps/mobile/src/features/threads/thread-list-v2-items.tsx+9-14
......@@ -23,7 +23,6 @@ import { useUniwindTheme } from "../../lib/useUniwindTheme";
2323import type { PendingNewTask } from "../../state/use-pending-new-tasks";
2424import { useThreadPr } from "../../state/use-thread-pr";
2525import { ThreadSwipeable } from "../home/thread-swipe-actions";
26import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider";
2726import { buildThreadTitleRegenerationMenuItems } from "./thread-title-regeneration-menu";
2827import {
2928 resolveThreadListV2SnoozeMenuSelection,
......@@ -53,10 +52,10 @@ const MONO_FONT = Platform.select({
5352const STATUS_LABEL_BY_STATUS: Partial<
5453 Record<ThreadListV2Status, { label: string; className: string }>
5554> = {
56 approval: { label: "Approval", className: "text-adaptive-amber-700-300" },
57 input: { label: "Input", className: "text-adaptive-indigo-600-300" },
58 working: { label: "Working", className: "text-adaptive-sky-600-400" },
59 failed: { label: "Failed", className: "text-adaptive-red-700-300" },
55 approval: { label: "Approval", className: "text-warning-foreground" },
56 input: { label: "Input", className: "text-foreground-secondary" },
57 working: { label: "Working", className: "text-foreground-secondary" },
58 failed: { label: "Failed", className: "text-danger-foreground" },
6059};
6160
6261function threadTimeLabel(thread: EnvironmentThreadShell): string {
......@@ -107,9 +106,6 @@ export const ThreadListV2SectionDivider = memo(function ThreadListV2SectionDivid
107106 );
108107});
109108
110const SNOOZE_ACCENT_LIGHT = "#2563eb";
111const SNOOZE_ACCENT_DARK = "#60a5fa";
112
113109export const ThreadListV2SnoozedShelfHeader = memo(function ThreadListV2SnoozedShelfHeader(props: {
114110 readonly count: number;
115111 readonly disabled?: boolean;
......@@ -117,7 +113,6 @@ export const ThreadListV2SnoozedShelfHeader = memo(function ThreadListV2SnoozedS
117113 readonly onToggle: () => void;
118114 readonly pane?: "screen" | "sidebar";
119115}) {
120 const { themeAppearance: colorScheme } = useAppearancePreferences();
121116 return (
122117 <Pressable
123118 accessibilityHint={
......@@ -134,14 +129,14 @@ export const ThreadListV2SnoozedShelfHeader = memo(function ThreadListV2SnoozedS
134129 onPress={props.onToggle}
135130 style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })}
136131 >
137 <Text className="text-xs font-t3-medium text-adaptive-blue-600-400">
132 <Text className="text-xs font-t3-medium text-foreground-secondary">
138133 {props.expanded ? "Snoozed" : `Snoozed (${props.count})`}
139134 </Text>
140 <View className="h-px flex-1 bg-adaptive-blue-500-a20-blue-400-a15" />
135 <View className="h-px flex-1 bg-primary/20" />
141136 <SymbolView
142137 name="chevron.down"
143138 size={10}
144 tintColor={colorScheme === "dark" ? SNOOZE_ACCENT_DARK : SNOOZE_ACCENT_LIGHT}
139 tintColorClassName="accent-icon-muted"
145140 type="monochrome"
146141 style={{ transform: [{ rotate: props.expanded ? "180deg" : "0deg" }] }}
147142 />
......@@ -737,7 +732,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: {
737732 <Text
738733 className={cn(
739734 "flex-1 text-xs",
740 selected ? "text-user-bubble-foreground-muted" : "text-adaptive-red-600-a80-400-a80",
735 selected ? "text-user-bubble-foreground-muted" : "text-danger-foreground",
741736 )}
742737 numberOfLines={1}
743738 >
......@@ -919,7 +914,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: {
919914 selected
920915 ? "text-user-bubble-foreground-muted"
921916 : snoozedRow
922 ? "text-adaptive-blue-600-400"
917 ? "text-foreground-secondary"
923918 : "text-foreground-tertiary",
924919 )}
925920 style={{ fontFamily: MONO_FONT }}
apps/mobile/src/features/threads/thread-search-match.tsx+1-1
......@@ -65,7 +65,7 @@ export function ThreadSearchMatchExcerpt(props: {
6565 props.selected
6666 ? "text-user-bubble-foreground"
6767 : isUser
68 ? "text-adaptive-blue-500-400"
68 ? "text-foreground-secondary"
6969 : "text-adaptive-emerald-600-400",
7070 )}
7171 >
apps/mobile/src/features/threads/thread-work-log.tsx+3-3
......@@ -773,7 +773,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow(
773773 color={props.iconSubtleColor}
774774 colorClassName={
775775 iconIsDestructive
776 ? "accent-adaptive-rose-600-400"
776 ? "accent-danger-foreground"
777777 : failed
778778 ? "accent-danger-foreground/40"
779779 : undefined
......@@ -784,7 +784,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow(
784784 <Text
785785 className={cn(
786786 "min-w-0 flex-1 text-sm text-foreground-muted",
787 iconIsDestructive && "font-t3-medium text-adaptive-rose-600-400",
787 iconIsDestructive && "font-t3-medium text-danger-foreground",
788788 )}
789789 numberOfLines={1}
790790 >
......@@ -832,7 +832,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow(
832832 entering={WORK_LOG_DETAIL_ENTER_TRANSITION}
833833 exiting={WORK_LOG_DETAIL_EXIT_TRANSITION}
834834 layout={WORK_LOG_LAYOUT_TRANSITION}
835 className="ml-7 border-l border-adaptive-neutral-300-a60-white-a12 pb-1 pl-3 pt-0.5"
835 className="ml-7 border-l border-border pb-1 pl-3 pt-0.5"
836836 >
837837 {viewedImagePath ? (
838838 <View className="pb-1.5">
apps/mobile/src/features/threads/threadPresentation.ts+12-12
......@@ -42,8 +42,8 @@ export function resolveThreadStatus(
4242 return {
4343 kind: "pending-approval",
4444 label: "Needs Approval",
45 pillClassName: "bg-adaptive-amber-500-a12-a16",
46 textClassName: "text-adaptive-amber-700-300",
45 pillClassName: "bg-warning",
46 textClassName: "text-warning-foreground",
4747 iconColor: "#ff9f0a",
4848 iconBackground: "rgba(255,159,10,0.22)",
4949 pulse: false,
......@@ -54,8 +54,8 @@ export function resolveThreadStatus(
5454 return {
5555 kind: "awaiting-input",
5656 label: "Awaiting Input",
57 pillClassName: "bg-adaptive-indigo-500-a12-a16",
58 textClassName: "text-adaptive-indigo-700-300",
57 pillClassName: "bg-primary/10",
58 textClassName: "text-foreground-secondary",
5959 iconColor: "#5e5ce6",
6060 iconBackground: "rgba(94,92,230,0.22)",
6161 pulse: false,
......@@ -66,8 +66,8 @@ export function resolveThreadStatus(
6666 return {
6767 kind: "working",
6868 label: "Working",
69 pillClassName: "bg-adaptive-sky-500-a12-a16",
70 textClassName: "text-adaptive-sky-700-300",
69 pillClassName: "bg-primary/10",
70 textClassName: "text-foreground-secondary",
7171 iconColor: "#0a84ff",
7272 iconBackground: "rgba(10,132,255,0.22)",
7373 pulse: true,
......@@ -78,8 +78,8 @@ export function resolveThreadStatus(
7878 return {
7979 kind: "connecting",
8080 label: "Connecting",
81 pillClassName: "bg-adaptive-sky-500-a12-a16",
82 textClassName: "text-adaptive-sky-700-300",
81 pillClassName: "bg-primary/10",
82 textClassName: "text-foreground-secondary",
8383 iconColor: "#0a84ff",
8484 iconBackground: "rgba(10,132,255,0.22)",
8585 pulse: true,
......@@ -90,8 +90,8 @@ export function resolveThreadStatus(
9090 return {
9191 kind: "error",
9292 label: "Error",
93 pillClassName: "bg-adaptive-rose-500-a12-a16",
94 textClassName: "text-adaptive-rose-700-300",
93 pillClassName: "bg-danger",
94 textClassName: "text-danger-foreground",
9595 iconColor: "#ff453a",
9696 iconBackground: "rgba(255,69,58,0.22)",
9797 pulse: false,
......@@ -106,8 +106,8 @@ export function resolveThreadStatus(
106106 return {
107107 kind: "plan-ready",
108108 label: "Plan Ready",
109 pillClassName: "bg-adaptive-violet-500-a12-a16",
110 textClassName: "text-adaptive-violet-700-300",
109 pillClassName: "bg-primary/10",
110 textClassName: "text-foreground-secondary",
111111 iconColor: "#bf5af2",
112112 iconBackground: "rgba(191,90,242,0.22)",
113113 pulse: false,
apps/mobile/src/lib/mobileTheme.test.ts+7-1
......@@ -153,10 +153,16 @@ describe("mobile themes", () => {
153153
154154 it("maps semantic palette roles onto every mobile color variable", () => {
155155 const variables = createMobileThemeVariables(BUILT_IN_THEMES[0].colors, "light");
156 expect(Object.keys(variables)).toHaveLength(65);
156 expect(Object.keys(variables)).toHaveLength(68);
157157 expect(variables["--color-sheet-solid"]).toBe(
158158 themeColorToNativeColor(BUILT_IN_THEMES[0].colors.chrome),
159159 );
160 expect(variables["--color-warning"]).toBe(
161 themeColorToNativeColor(BUILT_IN_THEMES[0].colors.warningSurface),
162 );
163 expect(variables["--color-warning-foreground"]).toBe(
164 themeColorToNativeColor(BUILT_IN_THEMES[0].colors.warningForeground),
165 );
160166 expect(variables["--color-primary"]).not.toBe(variables["--color-screen"]);
161167 expect(variables["--color-primary-shadow"]).toBe("#000000");
162168 expect(variables["--color-backdrop"]).toBe("rgba(0, 0, 0, 0.22)");
apps/mobile/src/lib/mobileTheme.ts+3
......@@ -239,6 +239,9 @@ export function createMobileThemeVariables(
239239 "--color-switch-active-thumb": c.accentForeground,
240240 "--color-switch-inactive-track": c.secondary,
241241 "--color-switch-inactive-thumb": c.mutedForeground,
242 "--color-warning": c.warningSurface,
243 "--color-warning-border": withAlpha(c.warning, 0.32),
244 "--color-warning-foreground": c.warningForeground,
242245 "--color-danger": c.errorSurface,
243246 "--color-danger-border": withAlpha(c.error, 0.32),
244247 "--color-danger-foreground": c.errorForeground,
apps/mobile/src/state/thread-pr-presentation.ts+2-2
......@@ -20,7 +20,7 @@ export interface ThreadPrPresentation {
2020const PR_STATE_TEXT_CLASS: Record<ThreadPr["state"], string> = {
2121 open: "text-adaptive-emerald-600-400",
2222 merged: "text-adaptive-violet-600-400",
23 closed: "text-adaptive-zinc-500-400",
23 closed: "text-foreground-muted",
2424};
2525
2626export function presentThreadPr(
......@@ -37,6 +37,6 @@ export function presentThreadPr(
3737 url: pr.url,
3838 label: String(pr.number),
3939 accessibilityLabel: `#${pr.number} ${presentation.longName} ${isDraft ? "draft" : pr.state}`,
40 textClassName: isDraft ? "text-adaptive-zinc-500-400" : PR_STATE_TEXT_CLASS[pr.state],
40 textClassName: isDraft ? "text-foreground-muted" : PR_STATE_TEXT_CLASS[pr.state],
4141 };
4242}
apps/mobile/src/state/use-thread-pr.test.ts+1-1
......@@ -39,7 +39,7 @@ describe("presentThreadPr", () => {
3939 presentThreadPr({ ...pullRequest, state: "open", isDraft: true }, undefined),
4040 ).toMatchObject({
4141 accessibilityLabel: "#3774 pull request draft",
42 textClassName: "text-adaptive-zinc-500-400",
42 textClassName: "text-foreground-muted",
4343 });
4444 });
4545});