Skip to content

Commit e9080b2

Browse files
samejrclaude
andcommitted
fix(webapp): give loading spinners a color that suits the theme
A Button's loading spinner was always white, so on the neutral variants it was white-on-near-white once the theme was light. It now takes the variant's text color: still white on primary and danger, dark ink on secondary, tertiary and minimal when the theme is light. The muted spinner was a fixed dark navy for the same reason and now comes from theme tokens, so it stays muted against a light surface too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 9cb6fc1 commit e9080b2

3 files changed

Lines changed: 23 additions & 8 deletions

File tree

apps/webapp/app/components/primitives/Buttons.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,13 @@ export function ButtonContent(props: ButtonContentPropsType) {
351351
renderShortcutKey()}
352352
</div>
353353
{showSpinner && (
354-
<span className="absolute inset-0 flex items-center justify-center">
355-
<Spinner className="size-3.5" color="white" />
354+
// Wears the variant's text color so the spinner tracks the button it's
355+
// on: white on primary and danger, and dark ink on the neutral
356+
// variants once the theme is light rather than white on near-white.
357+
<span
358+
className={cn("absolute inset-0 flex items-center justify-center", textColorClassName)}
359+
>
360+
<Spinner className="size-3.5" color="inherit" />
356361
</span>
357362
)}
358363
</div>

apps/webapp/app/components/primitives/Spinner.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export function Spinner({
1111
color = "blue",
1212
}: {
1313
className?: string;
14-
color?: "blue" | "white" | "muted" | "dark" | CustomColor;
14+
color?: "blue" | "white" | "muted" | "dark" | "inherit" | CustomColor;
1515
}) {
1616
const colors = {
1717
blue: {
@@ -22,13 +22,22 @@ export function Spinner({
2222
background: "rgba(255, 255, 255, 0.4)",
2323
foreground: "rgba(255, 255, 255)",
2424
},
25+
/* Theme tokens rather than fixed values, so a muted spinner stays muted
26+
against a light surface instead of staying dark-theme navy. */
2527
muted: {
26-
background: "#1C2433",
27-
foreground: "#3C4B62",
28+
background: "var(--color-grid-bright)",
29+
foreground: "var(--color-text-dimmed)",
2830
},
2931
dark: {
30-
background: "rgba(18, 19, 23, 0.35)",
31-
foreground: "#1A1B1F",
32+
background: "color-mix(in srgb, var(--color-charcoal-900) 35%, transparent)",
33+
foreground: "var(--color-charcoal-900)",
34+
},
35+
/* Takes the surrounding text color, so it follows both the theme and
36+
whatever it sits on - white on a primary button, dark ink on a
37+
secondary one once the theme is light. */
38+
inherit: {
39+
background: "color-mix(in srgb, currentColor 40%, transparent)",
40+
foreground: "currentColor",
3241
},
3342
};
3443

apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ export function TierHobby({
527527
<Button
528528
variant="secondary/medium"
529529
disabled={isLoading}
530-
LeadingIcon={isLoading ? () => <Spinner color="white" /> : undefined}
530+
// A white spinner would vanish on this button's light surface
531+
LeadingIcon={isLoading ? () => <Spinner color="inherit" /> : undefined}
531532
form="subscribe-hobby"
532533
>
533534
{`Downgrade to ${plan.title}`}

0 commit comments

Comments
 (0)