diff --git a/apps/desktop/src/lib/brand-icon.test.ts b/apps/desktop/src/lib/brand-icon.test.ts
new file mode 100644
index 000000000000..1b23ec458587
--- /dev/null
+++ b/apps/desktop/src/lib/brand-icon.test.ts
@@ -0,0 +1,43 @@
+import { describe, expect, it } from 'vitest'
+
+import { resolveBrandIcon } from './brand-icon'
+
+describe('resolveBrandIcon', () => {
+ it('resolves a registrable domain to a brand glyph', () => {
+ expect(resolveBrandIcon('github.com')).toBeTruthy()
+ expect(resolveBrandIcon('gitlab.com')).toBeTruthy()
+ })
+
+ it('ignores case and a leading www.', () => {
+ const github = resolveBrandIcon('github.com')
+
+ expect(resolveBrandIcon('WWW.GitHub.com')).toBe(github)
+ })
+
+ it('inherits the parent brand on subdomains', () => {
+ const github = resolveBrandIcon('github.com')
+
+ expect(resolveBrandIcon('gist.github.com')).toBe(github)
+ expect(resolveBrandIcon('api.github.com')).toBe(github)
+ })
+
+ it('prefers the longest matching suffix over its parent', () => {
+ const google = resolveBrandIcon('google.com')
+ const docs = resolveBrandIcon('docs.google.com')
+
+ expect(docs).toBeTruthy()
+ expect(docs).not.toBe(google)
+ })
+
+ it('returns null for unknown hosts and bare labels', () => {
+ expect(resolveBrandIcon('example.com')).toBeNull()
+ expect(resolveBrandIcon('localhost')).toBeNull()
+ expect(resolveBrandIcon('')).toBeNull()
+ })
+
+ it('never matches on a bare public suffix', () => {
+ // `github.io` is a real entry; a lone `io` must not inherit it.
+ expect(resolveBrandIcon('io')).toBeNull()
+ expect(resolveBrandIcon('com')).toBeNull()
+ })
+})
diff --git a/apps/desktop/src/lib/brand-icon.ts b/apps/desktop/src/lib/brand-icon.ts
new file mode 100644
index 000000000000..000a066d858f
--- /dev/null
+++ b/apps/desktop/src/lib/brand-icon.ts
@@ -0,0 +1,426 @@
+import {
+ SiAnthropic,
+ SiArchlinux,
+ SiArxiv,
+ SiAsana,
+ SiAtlassian,
+ SiBehance,
+ SiBitbucket,
+ SiBlender,
+ SiBluesky,
+ SiBun,
+ SiBuymeacoffee,
+ SiCircleci,
+ SiClaude,
+ SiCloudflare,
+ SiCodeberg,
+ SiCodecov,
+ SiCodesandbox,
+ SiConfluence,
+ SiCoursera,
+ SiCrunchbase,
+ SiCursor,
+ SiDatadog,
+ SiDebian,
+ SiDeno,
+ SiDevdotto,
+ SiDigitalocean,
+ SiDiscord,
+ SiDjango,
+ SiDocker,
+ SiDropbox,
+ SiElectron,
+ SiEslint,
+ SiExcalidraw,
+ SiFacebook,
+ SiFastapi,
+ SiFigma,
+ SiFirebase,
+ SiFlask,
+ SiForgejo,
+ SiGhost,
+ SiGitea,
+ SiGithub,
+ SiGitlab,
+ SiGmail,
+ SiGo,
+ SiGodotengine,
+ SiGoodreads,
+ SiGoogle,
+ SiGoogledocs,
+ SiGoogledrive,
+ SiGooglegemini,
+ SiGooglemaps,
+ SiGooglescholar,
+ SiGrafana,
+ SiGraphql,
+ SiHashnode,
+ SiHomebrew,
+ SiHuggingface,
+ SiImdb,
+ SiInstagram,
+ SiInternetarchive,
+ SiItchdotio,
+ SiJenkins,
+ SiJira,
+ SiJupyter,
+ SiKaggle,
+ SiKofi,
+ SiKotlin,
+ SiKubernetes,
+ SiLaravel,
+ SiLeetcode,
+ SiLinear,
+ SiMastodon,
+ SiMdnwebdocs,
+ SiMedium,
+ SiMiro,
+ SiMistralai,
+ SiMongodb,
+ SiNetflix,
+ SiNetlify,
+ SiNodedotjs,
+ SiNotion,
+ SiNpm,
+ SiNvidia,
+ SiObsidian,
+ SiOllama,
+ SiOpenrouter,
+ SiOpenstreetmap,
+ SiOverleaf,
+ SiPatreon,
+ SiPaypal,
+ SiPerplexity,
+ SiPhp,
+ SiPinterest,
+ SiPnpm,
+ SiPostgresql,
+ SiPostman,
+ SiPrisma,
+ SiProducthunt,
+ SiPypi,
+ SiPython,
+ SiPytorch,
+ SiQuora,
+ SiRailway,
+ SiRaspberrypi,
+ SiRaycast,
+ SiReact,
+ SiReadthedocs,
+ SiReddit,
+ SiRedis,
+ SiRender,
+ SiReplicate,
+ SiReplit,
+ SiResearchgate,
+ SiRuby,
+ SiRubyonrails,
+ SiRust,
+ SiScikitlearn,
+ SiSemanticscholar,
+ SiSentry,
+ SiServerfault,
+ SiShopify,
+ SiSnyk,
+ SiSoundcloud,
+ SiSourcehut,
+ SiSpotify,
+ SiStackblitz,
+ SiStackexchange,
+ SiStackoverflow,
+ SiSteam,
+ SiStorybook,
+ SiStripe,
+ SiSubstack,
+ SiSupabase,
+ SiSuperuser,
+ SiSwift,
+ SiTailwindcss,
+ SiTauri,
+ SiTelegram,
+ SiTensorflow,
+ SiThreedotjs,
+ SiTiktok,
+ SiTldraw,
+ SiTrello,
+ SiTurborepo,
+ SiTwitch,
+ SiTypescript,
+ SiUbuntu,
+ SiUdemy,
+ SiUnity,
+ SiUnsplash,
+ SiVercel,
+ SiVimeo,
+ SiVite,
+ SiWarp,
+ SiWebflow,
+ SiWeightsandbiases,
+ SiWikipedia,
+ SiWindsurf,
+ SiWordpress,
+ SiX,
+ SiYcombinator,
+ SiYelp,
+ SiYoutube,
+ SiZedindustries,
+ SiZoom,
+ SiZotero
+} from '@icons-pack/react-simple-icons'
+import type { ComponentType, SVGProps } from 'react'
+
+// Simple Icons components accept a `title` prop on top of the usual SVG props.
+// It matters: they always render a
element, defaulting to the brand
+// name, so callers need to be able to blank it out (see `LinkBrandIcon`).
+export type BrandIcon = ComponentType & { title?: string }>
+
+// simpleicons.org brand marks keyed by registrable domain. Lookup walks the
+// host's suffixes (see `resolveBrandIcon`), so one `github.com` entry also
+// covers `gist.github.com` and `api.github.com` — only list a subdomain when it
+// belongs to a *different* brand than its parent.
+//
+// Some brands are absent on purpose: Simple Icons has removed Slack, LinkedIn,
+// OpenAI, Amazon, and CodePen at their owners' request, so those hosts fall
+// through to no glyph rather than a lookalike.
+const BRAND_ICONS: Record = {
+ // Code hosting & package registries
+ 'github.com': SiGithub,
+ 'github.io': SiGithub,
+ 'githubusercontent.com': SiGithub,
+ 'gitlab.com': SiGitlab,
+ 'gitlab.io': SiGitlab,
+ 'bitbucket.org': SiBitbucket,
+ 'codeberg.org': SiCodeberg,
+ 'gitea.com': SiGitea,
+ 'gitea.io': SiGitea,
+ 'forgejo.org': SiForgejo,
+ 'sr.ht': SiSourcehut,
+ 'npmjs.com': SiNpm,
+ 'pypi.org': SiPypi,
+ 'crates.io': SiRust,
+ 'huggingface.co': SiHuggingface,
+ 'hf.co': SiHuggingface,
+
+ // Q&A, docs & reference
+ 'stackoverflow.com': SiStackoverflow,
+ 'stackexchange.com': SiStackexchange,
+ 'serverfault.com': SiServerfault,
+ 'superuser.com': SiSuperuser,
+ 'developer.mozilla.org': SiMdnwebdocs,
+ 'readthedocs.io': SiReadthedocs,
+ 'readthedocs.org': SiReadthedocs,
+ 'wikipedia.org': SiWikipedia,
+ 'archive.org': SiInternetarchive,
+
+ // Research
+ 'arxiv.org': SiArxiv,
+ 'semanticscholar.org': SiSemanticscholar,
+ 'scholar.google.com': SiGooglescholar,
+ 'researchgate.net': SiResearchgate,
+ 'zotero.org': SiZotero,
+ 'overleaf.com': SiOverleaf,
+
+ // AI
+ 'anthropic.com': SiAnthropic,
+ 'claude.ai': SiClaude,
+ 'gemini.google.com': SiGooglegemini,
+ 'perplexity.ai': SiPerplexity,
+ 'openrouter.ai': SiOpenrouter,
+ 'mistral.ai': SiMistralai,
+ 'ollama.com': SiOllama,
+ 'replicate.com': SiReplicate,
+ 'wandb.ai': SiWeightsandbiases,
+ 'kaggle.com': SiKaggle,
+
+ // Social
+ 'x.com': SiX,
+ 'twitter.com': SiX,
+ 't.co': SiX,
+ 'reddit.com': SiReddit,
+ 'redd.it': SiReddit,
+ 'news.ycombinator.com': SiYcombinator,
+ 'bsky.app': SiBluesky,
+ 'mastodon.social': SiMastodon,
+ 'joinmastodon.org': SiMastodon,
+ 'facebook.com': SiFacebook,
+ 'instagram.com': SiInstagram,
+ 'tiktok.com': SiTiktok,
+ 'pinterest.com': SiPinterest,
+ 'discord.com': SiDiscord,
+ 'discord.gg': SiDiscord,
+ 't.me': SiTelegram,
+ 'telegram.org': SiTelegram,
+ 'producthunt.com': SiProducthunt,
+ 'crunchbase.com': SiCrunchbase,
+ 'quora.com': SiQuora,
+
+ // Writing & blogs
+ 'medium.com': SiMedium,
+ 'substack.com': SiSubstack,
+ 'dev.to': SiDevdotto,
+ 'hashnode.dev': SiHashnode,
+ 'hashnode.com': SiHashnode,
+ 'wordpress.com': SiWordpress,
+ 'wordpress.org': SiWordpress,
+ 'ghost.org': SiGhost,
+
+ // Media
+ 'youtube.com': SiYoutube,
+ 'youtu.be': SiYoutube,
+ 'vimeo.com': SiVimeo,
+ 'twitch.tv': SiTwitch,
+ 'soundcloud.com': SiSoundcloud,
+ 'spotify.com': SiSpotify,
+ 'netflix.com': SiNetflix,
+ 'imdb.com': SiImdb,
+ 'goodreads.com': SiGoodreads,
+ 'unsplash.com': SiUnsplash,
+ 'behance.net': SiBehance,
+ 'store.steampowered.com': SiSteam,
+ 'itch.io': SiItchdotio,
+
+ // Product & project tools
+ 'linear.app': SiLinear,
+ 'notion.so': SiNotion,
+ 'notion.site': SiNotion,
+ 'figma.com': SiFigma,
+ 'atlassian.net': SiAtlassian,
+ 'atlassian.com': SiJira,
+ 'confluence.com': SiConfluence,
+ 'asana.com': SiAsana,
+ 'trello.com': SiTrello,
+ 'obsidian.md': SiObsidian,
+ 'miro.com': SiMiro,
+ 'excalidraw.com': SiExcalidraw,
+ 'tldraw.com': SiTldraw,
+ 'zoom.us': SiZoom,
+
+ // Google
+ 'google.com': SiGoogle,
+ 'goo.gl': SiGoogle,
+ 'docs.google.com': SiGoogledocs,
+ 'drive.google.com': SiGoogledrive,
+ 'mail.google.com': SiGmail,
+ 'maps.google.com': SiGooglemaps,
+ 'openstreetmap.org': SiOpenstreetmap,
+
+ // Hosting & infra
+ 'vercel.com': SiVercel,
+ 'vercel.app': SiVercel,
+ 'netlify.com': SiNetlify,
+ 'netlify.app': SiNetlify,
+ 'cloudflare.com': SiCloudflare,
+ 'pages.dev': SiCloudflare,
+ 'workers.dev': SiCloudflare,
+ 'railway.app': SiRailway,
+ 'render.com': SiRender,
+ 'digitalocean.com': SiDigitalocean,
+ 'firebase.google.com': SiFirebase,
+ 'supabase.com': SiSupabase,
+ 'docker.com': SiDocker,
+ 'kubernetes.io': SiKubernetes,
+ 'grafana.com': SiGrafana,
+ 'datadoghq.com': SiDatadog,
+ 'sentry.io': SiSentry,
+ 'snyk.io': SiSnyk,
+ 'codecov.io': SiCodecov,
+ 'circleci.com': SiCircleci,
+ 'jenkins.io': SiJenkins,
+
+ // Languages, frameworks & tooling
+ 'python.org': SiPython,
+ 'nodejs.org': SiNodedotjs,
+ 'react.dev': SiReact,
+ 'typescriptlang.org': SiTypescript,
+ 'tailwindcss.com': SiTailwindcss,
+ 'vite.dev': SiVite,
+ 'vitejs.dev': SiVite,
+ 'rust-lang.org': SiRust,
+ 'go.dev': SiGo,
+ 'golang.org': SiGo,
+ 'ruby-lang.org': SiRuby,
+ 'rubyonrails.org': SiRubyonrails,
+ 'php.net': SiPhp,
+ 'laravel.com': SiLaravel,
+ 'djangoproject.com': SiDjango,
+ 'flask.palletsprojects.com': SiFlask,
+ 'fastapi.tiangolo.com': SiFastapi,
+ 'swift.org': SiSwift,
+ 'kotlinlang.org': SiKotlin,
+ 'deno.com': SiDeno,
+ 'bun.sh': SiBun,
+ 'pnpm.io': SiPnpm,
+ 'turborepo.com': SiTurborepo,
+ 'eslint.org': SiEslint,
+ 'storybook.js.org': SiStorybook,
+ 'graphql.org': SiGraphql,
+ 'prisma.io': SiPrisma,
+ 'postgresql.org': SiPostgresql,
+ 'redis.io': SiRedis,
+ 'mongodb.com': SiMongodb,
+ 'pytorch.org': SiPytorch,
+ 'tensorflow.org': SiTensorflow,
+ 'scikit-learn.org': SiScikitlearn,
+ 'jupyter.org': SiJupyter,
+ 'threejs.org': SiThreedotjs,
+ 'blender.org': SiBlender,
+ 'godotengine.org': SiGodotengine,
+ 'unity.com': SiUnity,
+ 'electronjs.org': SiElectron,
+ 'tauri.app': SiTauri,
+ 'brew.sh': SiHomebrew,
+ 'archlinux.org': SiArchlinux,
+ 'debian.org': SiDebian,
+ 'ubuntu.com': SiUbuntu,
+ 'raspberrypi.com': SiRaspberrypi,
+ 'nvidia.com': SiNvidia,
+
+ // Dev environments & editors
+ 'codesandbox.io': SiCodesandbox,
+ 'stackblitz.com': SiStackblitz,
+ 'replit.com': SiReplit,
+ 'cursor.com': SiCursor,
+ 'windsurf.com': SiWindsurf,
+ 'zed.dev': SiZedindustries,
+ 'warp.dev': SiWarp,
+ 'raycast.com': SiRaycast,
+ 'postman.com': SiPostman,
+
+ // Commerce, learning & the rest
+ 'stripe.com': SiStripe,
+ 'paypal.com': SiPaypal,
+ 'patreon.com': SiPatreon,
+ 'ko-fi.com': SiKofi,
+ 'buymeacoffee.com': SiBuymeacoffee,
+ 'shopify.com': SiShopify,
+ 'webflow.com': SiWebflow,
+ 'dropbox.com': SiDropbox,
+ 'leetcode.com': SiLeetcode,
+ 'coursera.org': SiCoursera,
+ 'udemy.com': SiUdemy,
+ 'yelp.com': SiYelp
+}
+
+// Resolve a hostname to its brand glyph, walking suffixes so subdomains inherit
+// their parent's mark (`api.github.com` → `github.com`). Longest match wins, so
+// a subdomain entry like `docs.google.com` beats the `google.com` fallback. The
+// bare TLD is never tested.
+export function resolveBrandIcon(hostname: string): BrandIcon | null {
+ const host = hostname.trim().toLowerCase().replace(/^www\./, '')
+
+ if (!host.includes('.')) {
+ return null
+ }
+
+ const parts = host.split('.')
+
+ for (let i = 0; i < parts.length - 1; i += 1) {
+ const icon = BRAND_ICONS[parts.slice(i).join('.')]
+
+ if (icon) {
+ return icon
+ }
+ }
+
+ return null
+}