feat: use official SVG brand icons for model providers

Replace colored letter badges with official SVG icons sourced from
Simple Icons (Anthropic, Google Gemini) and Wikimedia Commons (OpenAI).

- Create shared ProviderIcons.tsx with OpenAI, Anthropic, and Gemini
  SVG icon components using the official brand marks
- Update PatternEditor ModelSelect dropdown to use real provider icons
- Update ActivityPanel model badges to use real provider icons
- Remove duplicated providerStyles objects from both files

Icons are inline SVG using currentColor for theme-aware coloring.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-21 20:58:38 +01:00
co-authored by Copilot
parent d155085d0c
commit 8f668da7f8
3 changed files with 67 additions and 30 deletions
+3 -13
View File
@@ -8,15 +8,10 @@ import {
isAgentActivityCompleted,
type SessionActivityState,
} from '@renderer/lib/sessionActivity';
import { inferProvider, type ModelProvider } from '@shared/domain/models';
import { inferProvider } from '@shared/domain/models';
import type { PatternDefinition } from '@shared/domain/pattern';
import type { SessionRecord } from '@shared/domain/session';
const providerStyles: Record<ModelProvider, { bg: string; text: string; label: string }> = {
openai: { bg: 'bg-emerald-500/15', text: 'text-emerald-400', label: 'AI' },
anthropic: { bg: 'bg-orange-500/15', text: 'text-orange-400', label: 'A' },
google: { bg: 'bg-blue-500/15', text: 'text-blue-400', label: 'G' },
};
import { ProviderIcon } from './ProviderIcons';
function formatModel(model: string): string {
return model.replace(/-/g, '\u2011');
@@ -102,12 +97,7 @@ export function ActivityPanel({ activity, pattern, session }: ActivityPanelProps
{(() => {
const prov = inferProvider(agent.model);
if (prov) {
const s = providerStyles[prov];
return (
<span className={`flex size-3.5 items-center justify-center rounded text-[7px] font-bold ${s.bg} ${s.text}`}>
{s.label}
</span>
);
return <ProviderIcon provider={prov} className="size-3" />;
}
return null;
})()}
+1 -17
View File
@@ -27,7 +27,6 @@ import {
providerMeta,
findModel,
inferProvider,
type ModelProvider,
type ModelDefinition,
} from '@shared/domain/models';
@@ -203,22 +202,7 @@ function InputField({
);
}
const providerStyles: Record<ModelProvider, { bg: string; text: string; label: string }> = {
openai: { bg: 'bg-emerald-500/15', text: 'text-emerald-400', label: 'AI' },
anthropic: { bg: 'bg-orange-500/15', text: 'text-orange-400', label: 'A' },
google: { bg: 'bg-blue-500/15', text: 'text-blue-400', label: 'G' },
};
function ProviderIcon({ provider }: { provider: ModelProvider }) {
const s = providerStyles[provider];
return (
<span
className={`flex size-5 shrink-0 items-center justify-center rounded text-[8px] font-bold ${s.bg} ${s.text}`}
>
{s.label}
</span>
);
}
import { ProviderIcon } from './ProviderIcons';
function TierBadge({ tier }: { tier: ModelDefinition['tier'] }) {
const styles = {
+63
View File
@@ -0,0 +1,63 @@
import type { ModelProvider } from '@shared/domain/models';
interface ProviderIconProps {
provider: ModelProvider;
className?: string;
}
function OpenAIIcon({ className }: { className?: string }) {
return (
<svg
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" />
</svg>
);
}
function AnthropicIcon({ className }: { className?: string }) {
return (
<svg
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z" />
</svg>
);
}
function GeminiIcon({ className }: { className?: string }) {
return (
<svg
className={className}
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81" />
</svg>
);
}
const iconComponents: Record<ModelProvider, React.FC<{ className?: string }>> = {
openai: OpenAIIcon,
anthropic: AnthropicIcon,
google: GeminiIcon,
};
export const providerColors: Record<ModelProvider, string> = {
openai: 'text-emerald-400',
anthropic: 'text-orange-400',
google: 'text-blue-400',
};
export function ProviderIcon({ provider, className }: ProviderIconProps) {
const Icon = iconComponents[provider];
const color = providerColors[provider];
return <Icon className={`${color} ${className ?? 'size-4'}`} />;
}