| 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 | */ |
| 6 | import { |
| 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 | |
| 72 | const 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. */ |
| 142 | export type BrandIcon = { path: string; title: string; color: string | null }; |
| 143 | |
| 144 | /** Relative luminance of a `RRGGBB` colour, 0 (black) to 1 (white). */ |
| 145 | function 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 | */ |
| 158 | export 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 | } |