Skip to content
162 linesCodeBlameRaw
1/**
2 * Connectors' brand marks, from Simple Icons, by connector id
3 * (@g1t/contracts/connectors). A connector without one here keeps its
4 * letters. Named imports, so only these icons are bundled.
5 */
6import {
7 type SimpleIcon,
8 si1password,
9 siAnthropic,
10 siAsana,
11 siAtlassian,
12 siBetterstack,
13 siBitbucket,
14 siBox,
15 siBuildkite,
16 siCircleci,
17 siClickup,
18 siCloudflare,
19 siCoda,
20 siDatadog,
21 siDeepseek,
22 siDiscord,
23 siDocker,
24 siDropbox,
25 siFigma,
26 siFlydotio,
27 siGithub,
28 siGitlab,
29 siGmail,
30 siGooglebigquery,
31 siGooglecalendar,
32 siGooglecloud,
33 siGoogledocs,
34 siGoogledrive,
35 siGooglegemini,
36 siGooglemeet,
37 siGrafana,
38 siHubspot,
39 siHuggingface,
40 siIntercom,
41 siJira,
42 siKubernetes,
43 siLinear,
44 siMiro,
45 siMistralai,
46 siModelcontextprotocol,
47 siNeon,
48 siNetlify,
49 siNewrelic,
50 siNotion,
51 siOkta,
52 siOpenrouter,
53 siOpsgenie,
54 siPagerduty,
55 siPaypal,
56 siPostgresql,
57 siPosthog,
58 siSentry,
59 siShortcut,
60 siSnowflake,
61 siSnyk,
62 siStorybook,
63 siStripe,
64 siSupabase,
65 siTrello,
66 siVercel,
67 siZapier,
68 siZendesk,
69 siZoom,
70} from "simple-icons";
71
72const BRAND_ICONS: Record<string, SimpleIcon> = {
73 github: siGithub,
74 "github-mcp": siGithub,
75 gitlab: siGitlab,
76 bitbucket: siBitbucket,
77 circleci: siCircleci,
78 buildkite: siBuildkite,
79 "docker-hub": siDocker,
80 linear: siLinear,
81 "linear-mcp": siLinear,
82 jira: siJira,
83 asana: siAsana,
84 shortcut: siShortcut,
85 clickup: siClickup,
86 trello: siTrello,
87 discord: siDiscord,
88 zoom: siZoom,
89 "google-meet": siGooglemeet,
90 "google-calendar": siGooglecalendar,
91 gmail: siGmail,
92 notion: siNotion,
93 atlassian: siAtlassian,
94 "google-docs": siGoogledocs,
95 zapier: siZapier,
96 coda: siCoda,
97 sentry: siSentry,
98 "sentry-mcp": siSentry,
99 datadog: siDatadog,
100 pagerduty: siPagerduty,
101 opsgenie: siOpsgenie,
102 grafana: siGrafana,
103 "new-relic": siNewrelic,
104 "better-stack": siBetterstack,
105 cloudflare: siCloudflare,
106 "cloudflare-docs": siCloudflare,
107 "google-cloud": siGooglecloud,
108 vercel: siVercel,
109 netlify: siNetlify,
110 "fly-io": siFlydotio,
111 kubernetes: siKubernetes,
112 anthropic: siAnthropic,
113 gemini: siGooglegemini,
114 mistral: siMistralai,
115 deepseek: siDeepseek,
116 openrouter: siOpenrouter,
117 mcp: siModelcontextprotocol,
118 "hugging-face": siHuggingface,
119 postgresql: siPostgresql,
120 snowflake: siSnowflake,
121 bigquery: siGooglebigquery,
122 posthog: siPosthog,
123 supabase: siSupabase,
124 neon: siNeon,
125 zendesk: siZendesk,
126 intercom: siIntercom,
127 hubspot: siHubspot,
128 stripe: siStripe,
129 paypal: siPaypal,
130 figma: siFigma,
131 miro: siMiro,
132 storybook: siStorybook,
133 okta: siOkta,
134 "1password": si1password,
135 snyk: siSnyk,
136 "google-drive": siGoogledrive,
137 dropbox: siDropbox,
138 box: siBox,
139};
140
141/** A connector's brand mark: its SVG path, and the colour to draw it in. */
142export type BrandIcon = { path: string; title: string; color: string | null };
143
144/** Relative luminance of a `RRGGBB` colour, 0 (black) to 1 (white). */
145function luminance(hex: string): number {
146 const [r, g, b] = [0, 2, 4].map((at) => {
147 const channel = parseInt(hex.slice(at, at + 2), 16) / 255;
148 return channel <= 0.03928 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
149 });
150 return 0.2126 * r! + 0.7152 * g! + 0.0722 * b!;
151}
152
153/**
154 * The brand mark for connector `id`, or null. `color` is the brand's own,
155 * or null when it is black or nearly (GitHub, Notion, Vercel): those are
156 * drawn in the text colour, so they read on the dark theme as on the light.
157 */
158export function brandIcon(id: string): BrandIcon | null {
159 const icon = BRAND_ICONS[id];
160 if (!icon) return null;
161 return { path: icon.path, title: icon.title, color: luminance(icon.hex) < 0.04 ? null : `#${icon.hex}` };
162}