From 428caab6fd65a112d46d1bd93fdf3797c1a53aa8 Mon Sep 17 00:00:00 2001 From: iamtoruk Date: Sun, 12 Jul 2026 13:00:43 -0700 Subject: [PATCH] feat(app): real provider logos in the picker and Settings - add Claude/OpenAI/Cursor/Grok brand SVGs under app/renderer/assets/providers - ProviderLogo component: brand-orange Claude in both themes; light/dark monochrome variants for OpenAI/Cursor/Grok swapped per active theme - show the logo in the provider dropdown (trigger + menu items) and in Settings > Providers, left of each provider name typecheck clean; 128/128 tests pass. --- app/renderer/assets/providers/claude.svg | 1 + app/renderer/assets/providers/cursor-dark.svg | 12 +++++++++ .../assets/providers/cursor-light.svg | 12 +++++++++ app/renderer/assets/providers/grok-dark.svg | 4 +++ app/renderer/assets/providers/grok-light.svg | 4 +++ app/renderer/assets/providers/openai-dark.svg | 1 + .../assets/providers/openai-light.svg | 1 + app/renderer/components/ProviderLogo.tsx | 27 +++++++++++++++++++ app/renderer/components/ProviderPop.tsx | 6 +++-- app/renderer/sections/Settings.tsx | 3 ++- app/renderer/styles/plain.css | 11 +++++++- 11 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 app/renderer/assets/providers/claude.svg create mode 100644 app/renderer/assets/providers/cursor-dark.svg create mode 100644 app/renderer/assets/providers/cursor-light.svg create mode 100644 app/renderer/assets/providers/grok-dark.svg create mode 100644 app/renderer/assets/providers/grok-light.svg create mode 100644 app/renderer/assets/providers/openai-dark.svg create mode 100644 app/renderer/assets/providers/openai-light.svg create mode 100644 app/renderer/components/ProviderLogo.tsx diff --git a/app/renderer/assets/providers/claude.svg b/app/renderer/assets/providers/claude.svg new file mode 100644 index 0000000..d300701 --- /dev/null +++ b/app/renderer/assets/providers/claude.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/renderer/assets/providers/cursor-dark.svg b/app/renderer/assets/providers/cursor-dark.svg new file mode 100644 index 0000000..10d50ca --- /dev/null +++ b/app/renderer/assets/providers/cursor-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/renderer/assets/providers/cursor-light.svg b/app/renderer/assets/providers/cursor-light.svg new file mode 100644 index 0000000..635d3cc --- /dev/null +++ b/app/renderer/assets/providers/cursor-light.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/renderer/assets/providers/grok-dark.svg b/app/renderer/assets/providers/grok-dark.svg new file mode 100644 index 0000000..7057a3b --- /dev/null +++ b/app/renderer/assets/providers/grok-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/renderer/assets/providers/grok-light.svg b/app/renderer/assets/providers/grok-light.svg new file mode 100644 index 0000000..642d7b6 --- /dev/null +++ b/app/renderer/assets/providers/grok-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/renderer/assets/providers/openai-dark.svg b/app/renderer/assets/providers/openai-dark.svg new file mode 100644 index 0000000..b6d542d --- /dev/null +++ b/app/renderer/assets/providers/openai-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/renderer/assets/providers/openai-light.svg b/app/renderer/assets/providers/openai-light.svg new file mode 100644 index 0000000..2ebab67 --- /dev/null +++ b/app/renderer/assets/providers/openai-light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/renderer/components/ProviderLogo.tsx b/app/renderer/components/ProviderLogo.tsx new file mode 100644 index 0000000..c5898f1 --- /dev/null +++ b/app/renderer/components/ProviderLogo.tsx @@ -0,0 +1,27 @@ +import claude from '../assets/providers/claude.svg' +import cursorDark from '../assets/providers/cursor-dark.svg' +import cursorLight from '../assets/providers/cursor-light.svg' +import grokDark from '../assets/providers/grok-dark.svg' +import grokLight from '../assets/providers/grok-light.svg' +import openaiDark from '../assets/providers/openai-dark.svg' +import openaiLight from '../assets/providers/openai-light.svg' + +const THEMED_LOGOS: Record = { + codex: { light: openaiLight, dark: openaiDark }, + cursor: { light: cursorLight, dark: cursorDark }, + grok: { light: grokLight, dark: grokDark }, +} + +export function ProviderLogo({ provider, size = 16 }: { provider: string; size?: number }) { + if (provider === 'claude') { + return + } + + const logos = THEMED_LOGOS[provider] + if (!logos) return null + + return <> + + + +} diff --git a/app/renderer/components/ProviderPop.tsx b/app/renderer/components/ProviderPop.tsx index 7b376cc..8a50127 100644 --- a/app/renderer/components/ProviderPop.tsx +++ b/app/renderer/components/ProviderPop.tsx @@ -1,5 +1,7 @@ import { useEffect, useRef, useState } from 'react' +import { ProviderLogo } from './ProviderLogo' + export type ProviderOption = { value: string; label: string } /** Provider selector populated from providers detected in the CLI payload. */ @@ -49,7 +51,7 @@ export function ProviderPop({ } }} > - {label} + {label} {open && (
@@ -72,7 +74,7 @@ export function ProviderPop({ } }} > - {option.label} + {option.label}
))} diff --git a/app/renderer/sections/Settings.tsx b/app/renderer/sections/Settings.tsx index ddf4115..e4f03b7 100644 --- a/app/renderer/sections/Settings.tsx +++ b/app/renderer/sections/Settings.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react' import { Hint } from '../components/Hint' import { CliErrorText, cliErrorDisplay } from '../components/CliErrorPanel' import { Panel } from '../components/Panel' +import { ProviderLogo } from '../components/ProviderLogo' import type { Section } from '../components/Sidebar' import { usePolled } from '../hooks/usePolled' import { formatUsd } from '../lib/format' @@ -142,7 +143,7 @@ function ProvidersPane({ period, refreshToken }: { period: Period; refreshToken: const providers = Object.entries(overview.data?.current.providers ?? {}) return

Providers

codeburn auto-detects coding tools from local session files — no setup needed.

- {overview.error ? : !overview.data ?

Loading detected providers…

: providers.length === 0 ?

No providers detected.

: providers.map(([name, cost]) =>
{name.charAt(0).toUpperCase() + name.slice(1)}Detected · {formatUsd(cost)}
)} + {overview.error ? : !overview.data ?

Loading detected providers…

: providers.length === 0 ?

No providers detected.

: providers.map(([name, cost]) =>
{name.charAt(0).toUpperCase() + name.slice(1)}Detected · {formatUsd(cost)}
)}
} diff --git a/app/renderer/styles/plain.css b/app/renderer/styles/plain.css index 3615112..ba39833 100644 --- a/app/renderer/styles/plain.css +++ b/app/renderer/styles/plain.css @@ -48,6 +48,9 @@ --hair2: var(--line2); } +.provider-logo { display: inline-flex; object-fit: contain; flex: 0 0 auto; border-radius: 4px; } +.pl-dark { display: none; } + @media (prefers-color-scheme: dark) { :root { --canvas: #0e1013; @@ -90,6 +93,8 @@ --tip-bg: #eef0f3; --tip-ink: #15181d; } + .pl-light { display: none; } + .pl-dark { display: inline-flex; } } :root[data-theme='dark'] { @@ -106,6 +111,8 @@ --fill: #20242b; --hover: #20242b; --tip-bg: #eef0f3; --tip-ink: #15181d; } +:root[data-theme='dark'] .pl-light { display: none; } +:root[data-theme='dark'] .pl-dark { display: inline-flex; } :root[data-theme='light'] { color-scheme: light; @@ -121,6 +128,8 @@ --fill: #f1f2f4; --hover: #f2f3f5; --tip-bg: #1a1d23; --tip-ink: #ffffff; } +:root[data-theme='light'] .pl-light { display: inline-flex; } +:root[data-theme='light'] .pl-dark { display: none; } html, body, #root { height: 100%; margin: 0; } body { overflow: hidden; background: var(--bg); color: var(--ink); } @@ -174,7 +183,7 @@ body { overflow: hidden; background: var(--bg); color: var(--ink); } background: var(--panel); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.14); z-index: 20; } -.pop-item { padding: 6px 11px; font-size: 12px; border-radius: 6px; cursor: pointer; color: var(--t1); white-space: nowrap; } +.pop-item { display: flex; align-items: center; gap: 6px; padding: 6px 11px; font-size: 12px; border-radius: 6px; cursor: pointer; color: var(--t1); white-space: nowrap; } .pop-item:hover, .pop-item:focus-visible { background: var(--hover); outline: none; } .pop-item.on { color: var(--accent); font-weight: 560; } .calendar-trigger {