Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/desktop-tauri/src/components/MenuCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { localizeWindowLabel } from "../lib/windowLabels";
import { inlineDashboardModel } from "../lib/inlineDashboard";
import { useMonthlyLimitBlockNow } from "../hooks/useMonthlyLimitBlockNow";
import type { UsageThresholdSettings } from "../lib/metricRowModel";
import { getProviderIcon } from "./providers/providerIcons";
import { providerBarAccent } from "./providers/providerIcons";
import CardHeader, { displayPlanName } from "./card/CardHeader";
import CardMetricRow, { type MetricEntry } from "./card/CardMetricRow";
import DetailSections from "./card/DetailSections";
Expand Down Expand Up @@ -232,7 +232,7 @@ export default function MenuCard({
]
.filter(Boolean)
.join(" ");
const accent = accentColor ?? getProviderIcon(provider.providerId).brandColor;
const accent = providerBarAccent(provider.providerId, accentColor);

return (
<article
Expand Down
9 changes: 9 additions & 0 deletions apps/desktop-tauri/src/components/charts/chartPalette.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ describe("chartPalette.providerColor", () => {
);
});

it("gives xAI its own token now that Grok uses the Mac green", () => {
expect(providerCostColor("xai")).toBe(
"var(--chart-xai, var(--provider-accent, var(--chart-cost)))",
);
expect(providerCostColor("grok")).toBe(
"var(--chart-grok, var(--provider-accent, var(--chart-cost)))",
);
});

it("falls back to the generic cost/credits token for unknown providers", () => {
expect(providerCostColor("unknown-provider-xyz")).toBe(
"var(--provider-accent, var(--chart-cost))",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop-tauri/src/components/charts/chartPalette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const PROVIDER_TOKEN: Record<string, string> = {
"eleven labs": "--chart-elevenlabs",
deepgram: "--chart-deepgram",
grok: "--chart-grok",
xai: "--chart-grok",
xai: "--chart-xai",
supergrok: "--chart-grok",
groq: "--chart-groq",
groqcloud: "--chart-groq",
Expand Down
13 changes: 10 additions & 3 deletions apps/desktop-tauri/src/components/providers/ProviderIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProviderIcon } from "./providerIcons";
import { brandColorOnDark, getProviderIcon } from "./providerIcons";

interface Props {
providerId: string;
Expand All @@ -19,6 +19,13 @@ export function ProviderIcon({
title,
}: Props) {
const entry = getProviderIcon(providerId);
const onDark = brandColorOnDark(entry.brandColor);
const tint = {
["--provider-brand" as string]: entry.brandColor,
// Only near-black brands get a dark-surface tint; CSS picks it on dark
// surfaces and keeps the brand color on light ones.
...(onDark ? { ["--provider-brand-dark" as string]: onDark } : {}),
};
const dims = { width: size, height: size };

if (entry.svgPath) {
Expand All @@ -27,7 +34,7 @@ export function ProviderIcon({
className={`provider-icon provider-icon--svg${className ? " " + className : ""}`}
style={{
...dims,
["--provider-brand" as string]: entry.brandColor,
...tint,
}}
title={title}
aria-hidden={title ? undefined : true}
Expand All @@ -42,7 +49,7 @@ export function ProviderIcon({
className={`provider-icon provider-icon--letter${className ? " " + className : ""}`}
style={{
...dims,
["--provider-brand" as string]: entry.brandColor,
...tint,
}}
title={title}
aria-hidden={title ? undefined : true}
Expand Down
134 changes: 126 additions & 8 deletions apps/desktop-tauri/src/components/providers/providerIcons.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import { TEST_PROVIDER_CATALOG } from "../../test/providerCatalog";
import { loadStyles } from "../../test/styles";
import { PROVIDER_ICON_REGISTRY } from "./providerIcons";
import { loadStyles, loadStylesheet, ruleBlock } from "../../test/styles";
import { PROVIDER_ICON_REGISTRY, brandColorOnDark, providerBarAccent } from "./providerIcons";

// Repository root, from apps/desktop-tauri/src/components/providers.
const REPO_ROOT = import.meta.dirname + "/../../../../../";
Expand Down Expand Up @@ -64,6 +64,35 @@ const ADOPTED_ACCENTS: Array<[string, string]> = [
["venice", "#3c8fdd"],
];

// Mac CodexBar 0.70.0 brand colors adopted for parity (card PR 4,
// tray-card-spec section 4). Vercel is the one deliberate exception.
const MAC_PARITY_ACCENTS: Array<[string, string]> = [
["chutes", "#3184ff"],
["deepgram", "#6467f2"],
["doubao", "#3370ff"],
["grok", "#10a37f"],
["groq", "#f56844"],
["helmcode", "#4934e1"],
["kilo", "#f27027"],
["litellm", "#4c89f0"],
["llmproxy", "#24b47e"],
["ollama", "#888888"],
["openaiapi", "#0f826e"],
["openrouter", "#6467f2"],
["perplexity", "#20b2aa"],
["poe", "#5d5cde"],
["qoder", "#10b981"],
["sakana", "#2975db"],
["stepfun", "#2196f2"],
["t3chat", "#f56647"],
["typesafe", "#111111"],
["v0", "#111111"],
["warp", "#938bb4"],
["wayfinder", "#10a37f"],
["windsurf", "#34e8bb"],
["zed", "#084eff"],
];

describe("provider icon registry", () => {
it("has explicit icon metadata for every provider in the catalog", () => {
for (const [id] of TEST_PROVIDER_CATALOG) {
Expand All @@ -88,6 +117,85 @@ describe("provider icon registry", () => {
}
});

it("uses the Mac 0.70.0 brand colors", () => {
for (const [id, color] of MAC_PARITY_ACCENTS) {
expect(PROVIDER_ICON_REGISTRY[id]?.brandColor.toLowerCase(), id).toBe(color);
}
});

it("keeps Vercel on a mid neutral instead of Mac white", () => {
// User decision 2026-10-10: Mac #FFFFFF is invisible on the light track.
expect(PROVIDER_ICON_REGISTRY.vercel.brandColor.toLowerCase()).toBe("#737373");
});

it("paints ElevenLabs bars in the label color, as Mac does", () => {
expect(providerBarAccent("elevenlabs")).toBe("var(--mac-text, rgba(0, 0, 0, 0.85))");
expect(providerBarAccent("ElevenLabs", null)).toBe("var(--mac-text, rgba(0, 0, 0, 0.85))");
// The icon keeps its brand color.
expect(PROVIDER_ICON_REGISTRY.elevenlabs.brandColor.toLowerCase()).toBe("#111827");
});

it("uses the user's override, else the brand color, for card bars", () => {
expect(providerBarAccent("claude")).toBe("#cc7c5e");
expect(providerBarAccent("claude", "#123456")).toBe("#123456");
expect(providerBarAccent("elevenlabs", "#ff0000")).toBe("#ff0000");
});

it("lifts only near-black brand colors on dark surfaces", () => {
// Literal values: #111111 is 1.19:1 on #222222, #707070 is the first
// 10% white mix that reaches 3:1.
expect(brandColorOnDark("#111111")).toBe("#707070");
expect(brandColorOnDark("#000000")).toBe("#808080");
expect(brandColorOnDark("#111827")).toBe("#70747d");
// Colors that already read on dark keep their exact value.
expect(brandColorOnDark("#10a37f")).toBeNull();
expect(brandColorOnDark("#2563eb")).toBeNull();
expect(brandColorOnDark("#737373")).toBeNull();
expect(brandColorOnDark("#4c00ff")).toBeNull();
expect(brandColorOnDark("var(--mac-text)")).toBeNull();

const lifted = Object.entries(PROVIDER_ICON_REGISTRY)
.filter(([, icon]) => brandColorOnDark(icon.brandColor) !== null)
.map(([id]) => id)
.sort();
expect(lifted).toEqual([
"aixy",
"deepinfra",
"elevenlabs",
"manus",
"replicate",
"typesafe",
"v0",
]);
});

it("keeps the brand color in light scopes and the lifted tint in dark ones", () => {
const css = loadStyles();
const dark = css.indexOf('[data-theme="dark"] .provider-icon {');
const light = css.indexOf('[data-theme="light"] .provider-icon {');
expect(dark).toBeGreaterThan(-1);
// The tray panel nests data-theme="light" inside a dark document, so the
// light rule must come later to win at equal specificity.
expect(light).toBeGreaterThan(dark);
expect(ruleBlock(css, '[data-theme="dark"] .provider-icon')).toContain(
"var(--provider-brand-dark, var(--provider-brand",
);
expect(ruleBlock(css, '[data-theme="light"] .provider-icon')).not.toContain(
"--provider-brand-dark",
);

const floatbar = loadStylesheet("floatbar/FloatBar.css");
expect(ruleBlock(floatbar, ".floatbar .floatbar__provider-icon .provider-icon")).not.toContain(
"--provider-brand-dark",
);
expect(
ruleBlock(
floatbar,
".floatbar--floating:not(.floatbar--light-bg) .floatbar__provider-icon .provider-icon",
),
).toContain("var(--provider-brand-dark, var(--provider-brand");
});

it("matches the Rust brand_color table for every provider", () => {
const rust = rustBrandColors();
expect(rust.size).toBeGreaterThan(0);
Expand All @@ -98,13 +206,23 @@ describe("provider icon registry", () => {
});

it("keeps provider chart tokens on the brand color", () => {
// Grok's chart token has been pure black since before the registry
// existed (xAI shares it), so it is the one intentional exception.
const checked = chartTokens().filter(
([id]) => id !== "grok" && PROVIDER_ICON_REGISTRY[id] !== undefined,
);
const checked = chartTokens().filter(([id]) => PROVIDER_ICON_REGISTRY[id] !== undefined);
expect(checked.map(([id]) => id)).toEqual(
expect.arrayContaining(["amp", "augment", "codebuff", "cursor", "deepseek", "kiro", "mistral"]),
expect.arrayContaining([
"amp",
"augment",
"codebuff",
"cursor",
"deepgram",
"deepseek",
"grok",
"groq",
"kiro",
"llmproxy",
"mistral",
"windsurf",
"xai",
]),
);
for (const [id, color] of checked) {
expect(color, `--chart-${id}`).toBe(PROVIDER_ICON_REGISTRY[id].brandColor.toLowerCase());
Expand Down
Loading