From b438447f67b6b61bbe6f564d8b78fd90702117c5 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sat, 5 Sep 2026 19:22:39 -0700 Subject: [PATCH] fix(mobile): use selected theme across input forms and controls (#10239) --- ...rated-uniwind-default-theme-variables.json | 6 +++ apps/mobile/generated-uniwind-themes.css | 30 +++++++++++++ apps/mobile/global.css | 10 +++++ apps/mobile/src/components/AppText.tsx | 2 + .../components/ComposerAttachmentStrip.tsx | 2 +- apps/mobile/src/components/ErrorBanner.tsx | 4 +- .../connection/CloudEnvironmentRows.tsx | 2 +- .../connection/ConnectionEnvironmentRow.tsx | 2 +- .../src/features/connection/connectionTone.ts | 20 ++++----- .../features/files/ThreadFilesRouteScreen.tsx | 6 +-- .../features/home/thread-swipe-actions.tsx | 33 ++++++++++---- .../src/features/review/ReviewSheet.tsx | 8 ++-- .../components/FontSizeSliderRow.tsx | 3 +- .../threads/GitActionProgressOverlay.tsx | 8 ++-- .../features/threads/PendingApprovalCard.tsx | 24 +++++------ .../features/threads/PendingUserInputCard.tsx | 43 ++++++++++--------- .../src/features/threads/ThreadFeed.tsx | 19 +++++--- .../features/threads/git/GitCommitSheet.tsx | 2 +- .../features/threads/thread-list-items.tsx | 4 +- .../features/threads/thread-list-v2-items.tsx | 23 ++++------ .../features/threads/thread-search-match.tsx | 2 +- .../src/features/threads/thread-work-log.tsx | 6 +-- .../features/threads/threadPresentation.ts | 24 +++++------ apps/mobile/src/lib/mobileTheme.test.ts | 8 +++- apps/mobile/src/lib/mobileTheme.ts | 3 ++ .../src/state/thread-pr-presentation.ts | 4 +- apps/mobile/src/state/use-thread-pr.test.ts | 2 +- 27 files changed, 184 insertions(+), 116 deletions(-) diff --git a/apps/mobile/generated-uniwind-default-theme-variables.json b/apps/mobile/generated-uniwind-default-theme-variables.json index 427d370acb573bbdae2a2a26cd510c477f1e2aaa..1953880fa946858fb9d85f64621104ce7856f8ab 100644 --- a/apps/mobile/generated-uniwind-default-theme-variables.json +++ b/apps/mobile/generated-uniwind-default-theme-variables.json @@ -28,6 +28,9 @@ "--color-switch-active-thumb": "#ffffff", "--color-switch-inactive-track": "rgba(0, 0, 0, 0.08)", "--color-switch-inactive-thumb": "#8e8e93", + "--color-warning": "#fffbeb", + "--color-warning-border": "#fde68a", + "--color-warning-foreground": "#b45309", "--color-danger": "#fef2f2", "--color-danger-border": "rgba(239, 68, 68, 0.12)", "--color-danger-foreground": "#dc2626", @@ -95,6 +98,9 @@ "--color-switch-active-thumb": "#ffffff", "--color-switch-inactive-track": "rgba(255, 255, 255, 0.06)", "--color-switch-inactive-thumb": "#8e8e93", + "--color-warning": "rgba(69, 26, 3, 0.4)", + "--color-warning-border": "rgba(120, 53, 15, 0.6)", + "--color-warning-foreground": "#fcd34d", "--color-danger": "rgba(239, 68, 68, 0.14)", "--color-danger-border": "rgba(248, 113, 113, 0.18)", "--color-danger-foreground": "#fca5a5", diff --git a/apps/mobile/generated-uniwind-themes.css b/apps/mobile/generated-uniwind-themes.css index 8ba542165f18c6dccf08504a82875feed9306fb2..e9352e1b38b90232aa983759b4c36d2faf1b1113 100644 --- a/apps/mobile/generated-uniwind-themes.css +++ b/apps/mobile/generated-uniwind-themes.css @@ -150,6 +150,9 @@ --color-switch-active-thumb: #ffffff; --color-switch-inactive-track: #f1c4e6; --color-switch-inactive-thumb: #8d1255; + --color-warning: #fcf0ea; + --color-warning-border: rgba(245, 158, 11, 0.32); + --color-warning-foreground: #b05109; --color-danger: #fde4f1; --color-danger-border: rgba(247, 8, 108, 0.32); --color-danger-foreground: #9d174d; @@ -275,6 +278,9 @@ --color-switch-active-thumb: #fbd0e8; --color-switch-inactive-track: #362d3d; --color-switch-inactive-thumb: #e7d0dd; + --color-warning: #412f20; + --color-warning-border: rgba(245, 158, 11, 0.32); + --color-warning-foreground: #fbbf24; --color-danger: #331a2b; --color-danger-border: rgba(157, 23, 77, 0.32); --color-danger-foreground: #fbd0e8; @@ -400,6 +406,9 @@ --color-switch-active-thumb: #fffaff; --color-switch-inactive-track: #e2ede7; --color-switch-inactive-thumb: #6e696f; + --color-warning: #f4f0e1; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #b64a00; --color-danger: #f4e7e5; --color-danger-border: rgba(251, 44, 54, 0.32); --color-danger-foreground: #c10007; @@ -525,6 +534,9 @@ --color-switch-active-thumb: #241523; --color-switch-inactive-track: #2a4b39; --color-switch-inactive-thumb: #9da5a2; + --color-warning: #3f3a1c; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #ffb900; --color-danger: #3f2c28; --color-danger-border: rgba(251, 65, 74, 0.32); --color-danger-foreground: #ff6668; @@ -650,6 +662,9 @@ --color-switch-active-thumb: #fffaff; --color-switch-inactive-track: #e4ecf2; --color-switch-inactive-thumb: #6f6873; + --color-warning: #f6efe4; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #b74b00; --color-danger: #f5e6e9; --color-danger-border: rgba(251, 44, 54, 0.32); --color-danger-foreground: #c10007; @@ -775,6 +790,9 @@ --color-switch-active-thumb: #241523; --color-switch-inactive-track: #293f52; --color-switch-inactive-thumb: #969ca6; + --color-warning: #3c3424; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #ffb900; --color-danger: #3c2630; --color-danger-border: rgba(251, 65, 74, 0.32); --color-danger-foreground: #ff6467; @@ -900,6 +918,9 @@ --color-switch-active-thumb: #fffaff; --color-switch-inactive-track: #f3eae5; --color-switch-inactive-thumb: #74686f; + --color-warning: #f9efe2; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #b84b00; --color-danger: #f9e7e6; --color-danger-border: rgba(251, 44, 54, 0.32); --color-danger-foreground: #c10007; @@ -1025,6 +1046,9 @@ --color-switch-active-thumb: #241523; --color-switch-inactive-track: #513728; --color-switch-inactive-thumb: #a59996; + --color-warning: #4b3215; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #ffb900; --color-danger: #4a2321; --color-danger-border: rgba(251, 65, 74, 0.32); --color-danger-foreground: #ff6467; @@ -1150,6 +1174,9 @@ --color-switch-active-thumb: #fffaff; --color-switch-inactive-track: #edeaf4; --color-switch-inactive-thumb: #726874; + --color-warning: #f8efe5; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #b84b00; --color-danger: #f8e6ea; --color-danger-border: rgba(251, 44, 54, 0.32); --color-danger-foreground: #c10007; @@ -1275,6 +1302,9 @@ --color-switch-active-thumb: #241523; --color-switch-inactive-track: #362d51; --color-switch-inactive-thumb: #9690a1; + --color-warning: #412e23; + --color-warning-border: rgba(254, 154, 0, 0.32); + --color-warning-foreground: #ffb900; --color-danger: #40202e; --color-danger-border: rgba(251, 65, 74, 0.32); --color-danger-foreground: #ff6467; diff --git a/apps/mobile/global.css b/apps/mobile/global.css index e6961eac4eea72c82900b83959addcc7c3f552ad..e153107b181104b92009a71ca897c64f97ae067b 100644 --- a/apps/mobile/global.css +++ b/apps/mobile/global.css @@ -52,6 +52,11 @@ --color-switch-inactive-track: rgba(0, 0, 0, 0.08); --color-switch-inactive-thumb: #8e8e93; + /* Warning */ + --color-warning: #fffbeb; + --color-warning-border: #fde68a; + --color-warning-foreground: #b45309; + /* Danger */ --color-danger: #fef2f2; --color-danger-border: rgba(239, 68, 68, 0.12); @@ -151,6 +156,11 @@ --color-switch-inactive-track: rgba(255, 255, 255, 0.06); --color-switch-inactive-thumb: #8e8e93; + /* Warning */ + --color-warning: rgba(69, 26, 3, 0.4); + --color-warning-border: rgba(120, 53, 15, 0.6); + --color-warning-foreground: #fcd34d; + /* Danger */ --color-danger: rgba(239, 68, 68, 0.14); --color-danger-border: rgba(248, 113, 113, 0.18); diff --git a/apps/mobile/src/components/AppText.tsx b/apps/mobile/src/components/AppText.tsx index 39517f0e62ee78bd35bef79143082a69d18066b0..6501d2044083dfbbe1987163b600b9bb884c9b15 100644 --- a/apps/mobile/src/components/AppText.tsx +++ b/apps/mobile/src/components/AppText.tsx @@ -35,6 +35,8 @@ export function AppTextInput({ className, ref, ...props }: AppTextInputProps) { className, )} placeholderTextColorClassName="accent-placeholder" + selectionColorClassName="accent-foreground-secondary" + cursorColorClassName="accent-foreground-secondary" {...props} /> ); diff --git a/apps/mobile/src/components/ComposerAttachmentStrip.tsx b/apps/mobile/src/components/ComposerAttachmentStrip.tsx index 40465012e5da3bfc02e3ec66294087a1496f4110..8c86fcc38e69cf39b86af101d3d680679d770d17 100644 --- a/apps/mobile/src/components/ComposerAttachmentStrip.tsx +++ b/apps/mobile/src/components/ComposerAttachmentStrip.tsx @@ -195,7 +195,7 @@ function ComposerAttachmentContent(props: ComposerAttachmentThumbnailProps) { {!props.compact ? ( diff --git a/apps/mobile/src/components/ErrorBanner.tsx b/apps/mobile/src/components/ErrorBanner.tsx index 6c12c9bdd8235a7d55ed12f6a14ab2f386ff3f16..38f85de195b519100272e39fab03fd4ee70fa8d4 100644 --- a/apps/mobile/src/components/ErrorBanner.tsx +++ b/apps/mobile/src/components/ErrorBanner.tsx @@ -3,8 +3,8 @@ import { View } from "react-native"; import { AppText as Text } from "./AppText"; export function ErrorBanner(props: { readonly message: string }) { return ( - - {props.message} + + {props.message} ); } diff --git a/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx b/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx index 448889549016236b297093b0c851f0d21fb98f39..806499c2273b8b2d897c5a2328911d49fda4d412 100644 --- a/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx +++ b/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx @@ -299,7 +299,7 @@ function CloudEnvironmentRowShell(props: { traceId: props.connectionErrorTraceId, }); const statusClassName = props.connectionError - ? "text-adaptive-rose-500-400" + ? "text-danger-foreground" : "text-foreground-muted"; const [errorMeasurement, setErrorMeasurement] = useState<{ readonly text: string; diff --git a/apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx b/apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx index 75d3e8ce7a343941e5d8e95541f97ff13d7b100d..5555548ff799ac6fd1c7e7d1345a981e03600cee 100644 --- a/apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx +++ b/apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx @@ -96,7 +96,7 @@ export function ConnectionEnvironmentRow(props: { {props.truncated ? ( - - + + Partial file - + Preview limited to the first 1 MB of a truncated file. diff --git a/apps/mobile/src/features/home/thread-swipe-actions.tsx b/apps/mobile/src/features/home/thread-swipe-actions.tsx index 052ac969c10f59242f8aac01bdc218c95bcc17d9..c5f6768c55d0c76bb5f107d88a1776918c10a336 100644 --- a/apps/mobile/src/features/home/thread-swipe-actions.tsx +++ b/apps/mobile/src/features/home/thread-swipe-actions.tsx @@ -62,7 +62,7 @@ interface ThreadSwipeAction { } interface ThreadSwipeSecondaryAction extends ThreadSwipeAction { - readonly backgroundColor: string; + readonly tone: "primary" | "secondary" | "danger"; } function swipeActionsWidth(hasSecondaryAction: boolean) { @@ -80,7 +80,7 @@ function resolveSecondaryAction(input: { if (input.secondaryAction === undefined) { return { accessibilityLabel: `Delete ${input.threadTitle}`, - backgroundColor: "#ff2d55", + tone: "danger", icon: "trash", label: "Delete", onPress: () => { @@ -92,7 +92,7 @@ function resolveSecondaryAction(input: { const action = input.secondaryAction; return { ...action, - backgroundColor: "#5856d6", + tone: "secondary", menu: action.menu === undefined ? undefined @@ -359,7 +359,7 @@ export function ThreadSwipeable(props: { function SwipeActionButton(props: { readonly accessibilityLabel: string; readonly actionsWidth: number; - readonly backgroundColor: string; + readonly tone: "primary" | "secondary" | "danger"; readonly compact: boolean; readonly entryRange: readonly [number, number]; readonly fullSwipeThreshold: number; @@ -462,9 +462,15 @@ function SwipeActionButton(props: { > - + - - Partial diff - - {props.notice} + + Partial diff + {props.notice} ); }); diff --git a/apps/mobile/src/features/settings/appearance/components/FontSizeSliderRow.tsx b/apps/mobile/src/features/settings/appearance/components/FontSizeSliderRow.tsx index 9b5d8e113f85775676df007b7b38be40f25b3657..bc8ddfc84ba5df4741731a2aa347b99783efdcbb 100644 --- a/apps/mobile/src/features/settings/appearance/components/FontSizeSliderRow.tsx +++ b/apps/mobile/src/features/settings/appearance/components/FontSizeSliderRow.tsx @@ -176,10 +176,9 @@ export function FontSizeSliderRow(props: { /> + diff --git a/apps/mobile/src/features/threads/PendingApprovalCard.tsx b/apps/mobile/src/features/threads/PendingApprovalCard.tsx index a94f321a4ad815cbe4e42a41991fa45e69829a1b..4be6ff611842fdf7419150480f8425877c1d697f 100644 --- a/apps/mobile/src/features/threads/PendingApprovalCard.tsx +++ b/apps/mobile/src/features/threads/PendingApprovalCard.tsx @@ -30,22 +30,20 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) { // Opaque for the same reason as PendingUserInputCard: nothing blurs the feed // behind this card, so a translucent surface bleeds messages through it. return ( - - + + Approval needed - + {props.approval.appName ?? props.approval.requestKind} {props.approval.detail ? ( - + {props.approval.detail} ) : null} {warning ? ( - - {warning} - + {warning} ) : null} {options.map((option) => ( @@ -53,10 +51,10 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) { key={option.decision} className={`items-center justify-center rounded-[14px] px-3.5 py-3 ${ option.decision === "accept" - ? "bg-blue-500" + ? "bg-primary" : option.decision === "decline" - ? "bg-adaptive-rose-100-500-a18" - : "bg-adaptive-neutral-200-800" + ? "bg-danger" + : "bg-subtle-strong" }`} disabled={props.respondingApprovalId === props.approval.requestId} onPress={() => void props.onRespond(props.approval.requestId, option.decision)} @@ -64,10 +62,10 @@ export function PendingApprovalCard(props: PendingApprovalCardProps) { {option.label} diff --git a/apps/mobile/src/features/threads/PendingUserInputCard.tsx b/apps/mobile/src/features/threads/PendingUserInputCard.tsx index f821c5714950cceaff2c5809341a269e3a49cafe..8fe7fc186adb09bf75c0dda0706ece198c787854 100644 --- a/apps/mobile/src/features/threads/PendingUserInputCard.tsx +++ b/apps/mobile/src/features/threads/PendingUserInputCard.tsx @@ -161,7 +161,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) { pointerEvents={props.collapsed ? "auto" : "none"} accessibilityElementsHidden={!props.collapsed} importantForAccessibility={props.collapsed ? "auto" : "no-hide-descendants"} - 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" + className="flex-row items-center gap-2 rounded-full border border-border bg-card-alt py-1.5 pl-4 pr-1.5" > - + User input needed - + {questionCount} question{questionCount === 1 ? "" : "s"} @@ -216,7 +216,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) { : FadeOutDown.duration(USER_INPUT_TOGGLE_DURATION_MS).easing(Easing.out(Easing.cubic)) } layout={CARD_LAYOUT_TRANSITION} - className="overflow-hidden gap-2.5 rounded-[20px] border border-adaptive-neutral-200-white-a6 bg-adaptive-neutral-100-900 p-4" + className="overflow-hidden gap-2.5 rounded-[20px] border border-border bg-card-alt p-4" style={ EXPANDED_CARD_IS_OVERLAY ? [{ maxHeight: props.maxHeight }, cardAnimatedStyle] @@ -230,14 +230,12 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) { className="flex-row items-start gap-2" > - + User input needed - - Fill in the pending answers - + Fill in the pending answers - + - + {question.header} - + {question.question} @@ -276,9 +274,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) { key={optionValue} className={cn( "min-h-12 w-full rounded-2xl border px-3.5 py-3", - selected - ? "border-adaptive-blue-300-a50-blue-400-a28 bg-adaptive-blue-50-blue-400-a14" - : "border-adaptive-neutral-200-white-a6 bg-adaptive-white-neutral-950-a70", + selected ? "border-primary bg-primary/10" : "border-border bg-input", )} onPress={() => props.onSelectOption( @@ -292,15 +288,13 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) { {option.label} {description ? ( - + {description} ) : null} @@ -318,7 +312,7 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) { onFocus={() => props.onInputFocusChange?.(true)} onBlur={() => props.onInputFocusChange?.(false)} placeholder="Or type a custom answer" - 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" + className="min-h-[54px] rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-base text-foreground" /> ) : null} @@ -328,14 +322,21 @@ export function PendingUserInputCard(props: PendingUserInputCardProps) { void props.onSubmit()} > - Submit answers + + Submit answers + ) : null; diff --git a/apps/mobile/src/features/threads/ThreadFeed.tsx b/apps/mobile/src/features/threads/ThreadFeed.tsx index d53ae65be062f15a3f6d9e193869e0eb0addf855..b57758b50c12be5b3102d23ae81cabbf9440d67a 100644 --- a/apps/mobile/src/features/threads/ThreadFeed.tsx +++ b/apps/mobile/src/features/threads/ThreadFeed.tsx @@ -504,7 +504,12 @@ function MessageAttachmentFile(props: { function MessageAttachmentUnknown(props: { readonly name: string }) { return ( - + {props.name} @@ -1352,7 +1357,7 @@ function renderFeedEntry( accessibilityState={{ expanded: entry.expanded }} onPress={() => props.onToggleTurnFold(entry.turnId)} hitSlop={4} - className="mb-1 min-h-11 flex-row items-center gap-2 border-b border-adaptive-neutral-200-a80-white-a8 px-2" + className="mb-1 min-h-11 flex-row items-center gap-2 border-b border-border px-2" style={{ minHeight: Math.max(TURN_FOLD_HEIGHT - 3.5, props.workRowSizing.estimatedRowHeight), }} @@ -1406,7 +1411,7 @@ function renderFeedEntry( accessibilityLabel={label} className="mb-3 flex-row items-center gap-3 px-1 py-1" > - + {label} - + ); } @@ -1503,7 +1508,7 @@ function renderFeedEntry( })} - + {timestampLabel} {message.text.trim().length > 0 ? ( @@ -1552,7 +1557,7 @@ function renderFeedEntry( attachmentId={attachment.id} name={attachment.name} mimeType={attachment.mimeType} - className="mt-1.5 aspect-[1.3] w-full rounded-[18px] bg-adaptive-neutral-200-800" + className="mt-1.5 aspect-[1.3] w-full rounded-[18px] bg-subtle-strong" onPressPreview={props.onPressPreview} /> ) : isFileAttachment(attachment) ? ( @@ -1576,7 +1581,7 @@ function renderFeedEntry( buttonSize={28} iconSize={13} /> - + {timestampLabel} diff --git a/apps/mobile/src/features/threads/git/GitCommitSheet.tsx b/apps/mobile/src/features/threads/git/GitCommitSheet.tsx index f263372bad22bda16dfa56a9d48cc3ac4fdf3cff..e76672de20f11db3ae411a8be05fbcedb5d6f77a 100644 --- a/apps/mobile/src/features/threads/git/GitCommitSheet.tsx +++ b/apps/mobile/src/features/threads/git/GitCommitSheet.tsx @@ -85,7 +85,7 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { {isDefaultRef ? ( - + Warning: this is the default branch. ) : null} diff --git a/apps/mobile/src/features/threads/thread-list-items.tsx b/apps/mobile/src/features/threads/thread-list-items.tsx index fcba4626be2d9e050ffb351e912d2ac812811ca0..fc3898279e3e7e692d9cb881bc7c0ac41c97c04b 100644 --- a/apps/mobile/src/features/threads/thread-list-items.tsx +++ b/apps/mobile/src/features/threads/thread-list-items.tsx @@ -297,8 +297,8 @@ export const PendingTaskListRow = memo(function PendingTaskListRow(props: { ); const statusPill = ( - - Pending + + Pending ); diff --git a/apps/mobile/src/features/threads/thread-list-v2-items.tsx b/apps/mobile/src/features/threads/thread-list-v2-items.tsx index 97c13de56aab13e61aa42f61e6881dc7e479af33..e34dce0590141a1ec4ef58348c371fb995d117c6 100644 --- a/apps/mobile/src/features/threads/thread-list-v2-items.tsx +++ b/apps/mobile/src/features/threads/thread-list-v2-items.tsx @@ -23,7 +23,6 @@ import { useUniwindTheme } from "../../lib/useUniwindTheme"; import type { PendingNewTask } from "../../state/use-pending-new-tasks"; import { useThreadPr } from "../../state/use-thread-pr"; import { ThreadSwipeable } from "../home/thread-swipe-actions"; -import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider"; import { buildThreadTitleRegenerationMenuItems } from "./thread-title-regeneration-menu"; import { resolveThreadListV2SnoozeMenuSelection, @@ -53,10 +52,10 @@ const MONO_FONT = Platform.select({ const STATUS_LABEL_BY_STATUS: Partial< Record > = { - approval: { label: "Approval", className: "text-adaptive-amber-700-300" }, - input: { label: "Input", className: "text-adaptive-indigo-600-300" }, - working: { label: "Working", className: "text-adaptive-sky-600-400" }, - failed: { label: "Failed", className: "text-adaptive-red-700-300" }, + approval: { label: "Approval", className: "text-warning-foreground" }, + input: { label: "Input", className: "text-foreground-secondary" }, + working: { label: "Working", className: "text-foreground-secondary" }, + failed: { label: "Failed", className: "text-danger-foreground" }, }; function threadTimeLabel(thread: EnvironmentThreadShell): string { @@ -107,9 +106,6 @@ export const ThreadListV2SectionDivider = memo(function ThreadListV2SectionDivid ); }); -const SNOOZE_ACCENT_LIGHT = "#2563eb"; -const SNOOZE_ACCENT_DARK = "#60a5fa"; - export const ThreadListV2SnoozedShelfHeader = memo(function ThreadListV2SnoozedShelfHeader(props: { readonly count: number; readonly disabled?: boolean; @@ -117,7 +113,6 @@ export const ThreadListV2SnoozedShelfHeader = memo(function ThreadListV2SnoozedS readonly onToggle: () => void; readonly pane?: "screen" | "sidebar"; }) { - const { themeAppearance: colorScheme } = useAppearancePreferences(); return ( ({ opacity: pressed ? 0.6 : 1 })} > - + {props.expanded ? "Snoozed" : `Snoozed (${props.count})`} - + @@ -737,7 +732,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { @@ -919,7 +914,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { selected ? "text-user-bubble-foreground-muted" : snoozedRow - ? "text-adaptive-blue-600-400" + ? "text-foreground-secondary" : "text-foreground-tertiary", )} style={{ fontFamily: MONO_FONT }} diff --git a/apps/mobile/src/features/threads/thread-search-match.tsx b/apps/mobile/src/features/threads/thread-search-match.tsx index 48aaf80249d54bbba5e43f81e0b077c0c5442caf..9c478f3c4504d8639a660ff39c1a15de177554c6 100644 --- a/apps/mobile/src/features/threads/thread-search-match.tsx +++ b/apps/mobile/src/features/threads/thread-search-match.tsx @@ -65,7 +65,7 @@ export function ThreadSearchMatchExcerpt(props: { props.selected ? "text-user-bubble-foreground" : isUser - ? "text-adaptive-blue-500-400" + ? "text-foreground-secondary" : "text-adaptive-emerald-600-400", )} > diff --git a/apps/mobile/src/features/threads/thread-work-log.tsx b/apps/mobile/src/features/threads/thread-work-log.tsx index 13a78b8f1454d1735800a357bbdaabc1313d501c..9d5b40fce6dc3b7a3651aac82620eff05fe3566e 100644 --- a/apps/mobile/src/features/threads/thread-work-log.tsx +++ b/apps/mobile/src/features/threads/thread-work-log.tsx @@ -773,7 +773,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow( color={props.iconSubtleColor} colorClassName={ iconIsDestructive - ? "accent-adaptive-rose-600-400" + ? "accent-danger-foreground" : failed ? "accent-danger-foreground/40" : undefined @@ -784,7 +784,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow( @@ -832,7 +832,7 @@ const ThreadWorkLogRow = memo(function ThreadWorkLogRow( entering={WORK_LOG_DETAIL_ENTER_TRANSITION} exiting={WORK_LOG_DETAIL_EXIT_TRANSITION} layout={WORK_LOG_LAYOUT_TRANSITION} - className="ml-7 border-l border-adaptive-neutral-300-a60-white-a12 pb-1 pl-3 pt-0.5" + className="ml-7 border-l border-border pb-1 pl-3 pt-0.5" > {viewedImagePath ? ( diff --git a/apps/mobile/src/features/threads/threadPresentation.ts b/apps/mobile/src/features/threads/threadPresentation.ts index 59cf108a01dd248aacc2d213d87a395f5dbc1e3d..bfc72d2ac9b85f899598df2b687d182323f76184 100644 --- a/apps/mobile/src/features/threads/threadPresentation.ts +++ b/apps/mobile/src/features/threads/threadPresentation.ts @@ -42,8 +42,8 @@ export function resolveThreadStatus( return { kind: "pending-approval", label: "Needs Approval", - pillClassName: "bg-adaptive-amber-500-a12-a16", - textClassName: "text-adaptive-amber-700-300", + pillClassName: "bg-warning", + textClassName: "text-warning-foreground", iconColor: "#ff9f0a", iconBackground: "rgba(255,159,10,0.22)", pulse: false, @@ -54,8 +54,8 @@ export function resolveThreadStatus( return { kind: "awaiting-input", label: "Awaiting Input", - pillClassName: "bg-adaptive-indigo-500-a12-a16", - textClassName: "text-adaptive-indigo-700-300", + pillClassName: "bg-primary/10", + textClassName: "text-foreground-secondary", iconColor: "#5e5ce6", iconBackground: "rgba(94,92,230,0.22)", pulse: false, @@ -66,8 +66,8 @@ export function resolveThreadStatus( return { kind: "working", label: "Working", - pillClassName: "bg-adaptive-sky-500-a12-a16", - textClassName: "text-adaptive-sky-700-300", + pillClassName: "bg-primary/10", + textClassName: "text-foreground-secondary", iconColor: "#0a84ff", iconBackground: "rgba(10,132,255,0.22)", pulse: true, @@ -78,8 +78,8 @@ export function resolveThreadStatus( return { kind: "connecting", label: "Connecting", - pillClassName: "bg-adaptive-sky-500-a12-a16", - textClassName: "text-adaptive-sky-700-300", + pillClassName: "bg-primary/10", + textClassName: "text-foreground-secondary", iconColor: "#0a84ff", iconBackground: "rgba(10,132,255,0.22)", pulse: true, @@ -90,8 +90,8 @@ export function resolveThreadStatus( return { kind: "error", label: "Error", - pillClassName: "bg-adaptive-rose-500-a12-a16", - textClassName: "text-adaptive-rose-700-300", + pillClassName: "bg-danger", + textClassName: "text-danger-foreground", iconColor: "#ff453a", iconBackground: "rgba(255,69,58,0.22)", pulse: false, @@ -106,8 +106,8 @@ export function resolveThreadStatus( return { kind: "plan-ready", label: "Plan Ready", - pillClassName: "bg-adaptive-violet-500-a12-a16", - textClassName: "text-adaptive-violet-700-300", + pillClassName: "bg-primary/10", + textClassName: "text-foreground-secondary", iconColor: "#bf5af2", iconBackground: "rgba(191,90,242,0.22)", pulse: false, diff --git a/apps/mobile/src/lib/mobileTheme.test.ts b/apps/mobile/src/lib/mobileTheme.test.ts index a3c6712abae832dcd85bf239e63f01d1ec366554..652de9296f1f66de501d94c91c7991a39c3a5bd6 100644 --- a/apps/mobile/src/lib/mobileTheme.test.ts +++ b/apps/mobile/src/lib/mobileTheme.test.ts @@ -153,10 +153,16 @@ describe("mobile themes", () => { it("maps semantic palette roles onto every mobile color variable", () => { const variables = createMobileThemeVariables(BUILT_IN_THEMES[0].colors, "light"); - expect(Object.keys(variables)).toHaveLength(65); + expect(Object.keys(variables)).toHaveLength(68); expect(variables["--color-sheet-solid"]).toBe( themeColorToNativeColor(BUILT_IN_THEMES[0].colors.chrome), ); + expect(variables["--color-warning"]).toBe( + themeColorToNativeColor(BUILT_IN_THEMES[0].colors.warningSurface), + ); + expect(variables["--color-warning-foreground"]).toBe( + themeColorToNativeColor(BUILT_IN_THEMES[0].colors.warningForeground), + ); expect(variables["--color-primary"]).not.toBe(variables["--color-screen"]); expect(variables["--color-primary-shadow"]).toBe("#000000"); expect(variables["--color-backdrop"]).toBe("rgba(0, 0, 0, 0.22)"); diff --git a/apps/mobile/src/lib/mobileTheme.ts b/apps/mobile/src/lib/mobileTheme.ts index 23034511287e31f00355e8bb23f9c995597770f8..10ef1b58edeccd25be9407ebc7b1535f098d7d36 100644 --- a/apps/mobile/src/lib/mobileTheme.ts +++ b/apps/mobile/src/lib/mobileTheme.ts @@ -239,6 +239,9 @@ export function createMobileThemeVariables( "--color-switch-active-thumb": c.accentForeground, "--color-switch-inactive-track": c.secondary, "--color-switch-inactive-thumb": c.mutedForeground, + "--color-warning": c.warningSurface, + "--color-warning-border": withAlpha(c.warning, 0.32), + "--color-warning-foreground": c.warningForeground, "--color-danger": c.errorSurface, "--color-danger-border": withAlpha(c.error, 0.32), "--color-danger-foreground": c.errorForeground, diff --git a/apps/mobile/src/state/thread-pr-presentation.ts b/apps/mobile/src/state/thread-pr-presentation.ts index 53d19abd95a41c07cddff2c1d66826a234041461..fd7a171810ee6c181ef5e97c6c5fa30ba6b36ee7 100644 --- a/apps/mobile/src/state/thread-pr-presentation.ts +++ b/apps/mobile/src/state/thread-pr-presentation.ts @@ -20,7 +20,7 @@ export interface ThreadPrPresentation { const PR_STATE_TEXT_CLASS: Record = { open: "text-adaptive-emerald-600-400", merged: "text-adaptive-violet-600-400", - closed: "text-adaptive-zinc-500-400", + closed: "text-foreground-muted", }; export function presentThreadPr( @@ -37,6 +37,6 @@ export function presentThreadPr( url: pr.url, label: String(pr.number), accessibilityLabel: `#${pr.number} ${presentation.longName} ${isDraft ? "draft" : pr.state}`, - textClassName: isDraft ? "text-adaptive-zinc-500-400" : PR_STATE_TEXT_CLASS[pr.state], + textClassName: isDraft ? "text-foreground-muted" : PR_STATE_TEXT_CLASS[pr.state], }; } diff --git a/apps/mobile/src/state/use-thread-pr.test.ts b/apps/mobile/src/state/use-thread-pr.test.ts index ddda3b1acd9648fb79d2f9c265eb4ca5d2b1261c..f6fddfdc55786526905c0e0d20d1d584c7e8772f 100644 --- a/apps/mobile/src/state/use-thread-pr.test.ts +++ b/apps/mobile/src/state/use-thread-pr.test.ts @@ -39,7 +39,7 @@ describe("presentThreadPr", () => { presentThreadPr({ ...pullRequest, state: "open", isDraft: true }, undefined), ).toMatchObject({ accessibilityLabel: "#3774 pull request draft", - textClassName: "text-adaptive-zinc-500-400", + textClassName: "text-foreground-muted", }); }); }); -- 2.54.0