Browse Source

docs: Document our Icon and PlatformIcons inside a story file (#56433)

This implements, in a very manual way a story for our icons. It's
patterned after the old/original icons story that existed at
https://storybook.sentry.dev/?path=/story/assets-icons--page

New icons, if they are not categorized, will appear at the top of the
page so editors will know to step in.

| New | Original |
| --- | --- |
| <img width="1241" alt="SCR-20230918-mneh"
src="https://github.com/getsentry/sentry/assets/187460/0bf98f9e-124c-4239-ac6c-01875bdf7255">
| <img width="1074" alt="SCR-20230918-nhvf"
src="https://github.com/getsentry/sentry/assets/187460/f36e6c5c-497b-49cb-83ff-fb81947e594a">
|
Ryan Albrecht 1 year ago
parent
commit
dc2972d268
1 changed files with 1454 additions and 0 deletions
  1. 1454 0
      static/app/icons/icons.stories.tsx

+ 1454 - 0
static/app/icons/icons.stories.tsx

@@ -0,0 +1,1454 @@
+import {Fragment, useState} from 'react';
+import styled from '@emotion/styled';
+import {PlatformIcon} from 'platformicons';
+
+import Input from 'sentry/components/input';
+import {Sticky} from 'sentry/components/sticky';
+import {Tooltip} from 'sentry/components/tooltip';
+import * as Icons from 'sentry/icons';
+import {space} from 'sentry/styles/space';
+
+type TIcon = {
+  id: string;
+  name: string;
+  additionalProps?: string[];
+  defaultProps?: Record<string, unknown>;
+  groups?: string[];
+  keywords?: string[];
+};
+type TSection = {
+  icons: TIcon[];
+  id: string;
+  label: string;
+};
+
+// TODO: Let the platformicons package could export this object instead.
+const platformToIcon = {
+  android: 'android',
+  apple: 'apple',
+  bun: 'bun',
+  capacitor: 'capacitor',
+  clojure: 'clojure',
+  cocoa: 'apple',
+  'cocoa-objc': 'apple',
+  'cocoa-swift': 'swift',
+  cordova: 'cordova',
+  cpp: 'cpp',
+  cryengine: 'cryengine',
+  csharp: 'csharp',
+  'csharp-aspnetcore': 'csharp',
+  dart: 'dart',
+  default: 'default',
+  dotnet: 'dotnet',
+  'dotnet-aspnetcore': 'dotnet',
+  'dotnet-aspnet': 'dotnet',
+  'dotnet-awslambda': 'aws',
+  'dotnet-blazor': 'blazor',
+  'dotnet-csharp': 'csharp',
+  'dotnet-gcpfunctions': 'gcp',
+  'dotnet-maui': 'maui',
+  'dotnet-uno': 'uno',
+  'dotnet-xamarin': 'xamarin',
+  dotnetcore: 'dotnetcore',
+  dotnetfx: 'dotnetfx',
+  electron: 'electron',
+  elixir: 'elixir',
+  flutter: 'flutter',
+  fsharp: 'fsharp',
+  git: 'git',
+  go: 'go',
+  'go-echo': 'echo',
+  godot: 'godot',
+  java: 'java',
+  'java-appengine': 'app-engine',
+  'java-android': 'android',
+  'java-log4j': 'java',
+  'java-log4j2': 'java',
+  'java-logback': 'logback',
+  'java-logging': 'java',
+  'java-spring': 'spring',
+  'java-spring-boot': 'springboot',
+  javascript: 'javascript',
+  'javascript-angular': 'angularjs',
+  'javascript-angularjs': 'angularjs',
+  'javascript-backbone': 'backbone',
+  'javascript-browser': 'javascript',
+  'javascript-capacitor': 'capacitor',
+  'javascript-cordova': 'cordova',
+  'javascript-electron': 'electron',
+  'javascript-ember': 'ember',
+  'javascript-gatsby': 'gatsby',
+  'javascript-ionic': 'ionic',
+  'javascript-nextjs': 'nextjs',
+  'javascript-react': 'react',
+  'javascript-remix': 'remix',
+  'javascript-svelte': 'svelte',
+  'javascript-sveltekit': 'svelte',
+  'javascript-vue': 'vue',
+  'javascript-wasm': 'wasm',
+  ionic: 'ionic',
+  kotlin: 'kotlin',
+  'kotlin-android': 'android',
+  linux: 'linux',
+  native: 'nativec',
+  'native-qt': 'qt',
+  node: 'nodejs',
+  'node-awslambda': 'aws',
+  'node-azurefunctions': 'azure',
+  'node-connect': 'nodejs',
+  'node-express': 'express',
+  'node-gcpfunctions': 'gcp',
+  'node-koa': 'koa',
+  'node-serverlesscloud': 'serverless',
+  perl: 'perl',
+  php: 'php',
+  'php-laravel': 'laravel',
+  'php-monolog': 'php',
+  'php-symfony2': 'symfony',
+  'php-symfony': 'symfony',
+  python: 'python',
+  'python-aiohttp': 'aiohttp',
+  'python-awslambda': 'aws',
+  'python-azurefunctions': 'azure',
+  'python-bottle': 'bottle',
+  'python-celery': 'celery',
+  'python-chalice': 'chalice',
+  'python-django': 'django',
+  'python-falcon': 'falcon',
+  'python-fastapi': 'fastapi',
+  'python-flask': 'flask',
+  'python-gcpfunctions': 'gcp',
+  'python-pylons': 'python',
+  'python-pyramid': 'pyramid',
+  'python-pythonawslambda': 'aws',
+  'python-rq': 'redis',
+  'python-sanic': 'python',
+  'python-serverless': 'serverless',
+  'python-starlette': 'starlette',
+  'python-tornado': 'tornado',
+  'python-tryton': 'tryton',
+  qt: 'qt',
+  'react-native': 'react-native',
+  ruby: 'ruby',
+  'ruby-rack': 'ruby',
+  'ruby-rails': 'rails',
+  'ruby-sinatra': 'sinatra',
+  rust: 'rust',
+  'rust-actix': 'actix',
+  scala: 'scala',
+  stride3d: 'stride3d',
+  swift: 'swift',
+  unity: 'unity',
+  // This will be deprecated in favor of 'unrealengine'
+  ue4: 'unreal',
+  unreal: 'unreal',
+  unrealengine: 'unreal',
+  visualbasic: 'visual-basic',
+  windows: 'windows',
+};
+
+const SECTIONS: TSection[] = [
+  {
+    id: 'product',
+    label: 'Product',
+    icons: [
+      {
+        id: 'dashboard',
+        groups: ['product'],
+        keywords: ['overview', 'group', 'organize', 'widgets'],
+        name: 'Dashboard',
+        defaultProps: {},
+      },
+      {
+        id: 'stats',
+        groups: ['product'],
+        keywords: ['bar', 'graph'],
+        name: 'Stats',
+        defaultProps: {},
+      },
+      {
+        id: 'project',
+        groups: ['product'],
+        keywords: [],
+        name: 'Project',
+        defaultProps: {},
+      },
+      {
+        id: 'issues',
+        groups: ['product'],
+        keywords: ['stack'],
+        name: 'Issues',
+        defaultProps: {},
+      },
+      {
+        id: 'releases',
+        groups: ['product'],
+        keywords: ['stack', 'versions'],
+        name: 'Releases',
+        defaultProps: {},
+      },
+      {
+        id: 'archive',
+        groups: ['product'],
+        keywords: [],
+        name: 'Archive',
+        defaultProps: {},
+      },
+      {
+        id: 'support',
+        groups: ['product'],
+        keywords: ['microphone', 'help'],
+        name: 'Support',
+        defaultProps: {},
+      },
+      {
+        id: 'settings',
+        groups: ['product'],
+        keywords: ['preference'],
+        name: 'Settings',
+        defaultProps: {},
+      },
+      {
+        id: 'lab',
+        groups: ['product'],
+        keywords: ['experiment', 'test'],
+        name: 'Lab',
+        defaultProps: {},
+      },
+      {
+        id: 'broadcast',
+        groups: ['product'],
+        keywords: ['stream'],
+        name: 'Broadcast',
+        defaultProps: {},
+      },
+      {
+        id: 'telescope',
+        groups: ['product'],
+        keywords: [],
+        name: 'Telescope',
+        defaultProps: {},
+      },
+      {
+        id: 'lightning',
+        groups: ['product'],
+        keywords: ['feature', 'new', 'fresh'],
+        name: 'Lightning',
+        defaultProps: {},
+      },
+      {
+        id: 'business',
+        groups: ['product'],
+        keywords: ['feature', 'promotion', 'fresh', 'new'],
+        name: 'Business',
+        defaultProps: {},
+      },
+      {
+        id: 'siren',
+        groups: ['product'],
+        keywords: ['alert', 'important', 'warning'],
+        name: 'Siren',
+        defaultProps: {},
+      },
+      {
+        id: 'profiling',
+        groups: ['product', 'chart'],
+        keywords: ['performance', 'span', 'flame', 'icicle'],
+        name: 'Profiling',
+        defaultProps: {},
+      },
+      {
+        id: 'timer',
+        groups: ['product', 'action'],
+        keywords: ['cron', 'monitors', 'clock', 'cycle'],
+        name: 'Timer',
+        defaultProps: {},
+      },
+    ],
+  },
+  {
+    id: 'logo',
+    label: 'Logos',
+    icons: [
+      {
+        id: 'sentry',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Sentry',
+        defaultProps: {},
+      },
+      {
+        id: 'codecov',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Codecov',
+        defaultProps: {},
+      },
+      {
+        id: 'bitbucket',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Bitbucket',
+        defaultProps: {},
+      },
+      {
+        id: 'github',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Github',
+        defaultProps: {},
+      },
+      {
+        id: 'gitlab',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Gitlab',
+        defaultProps: {},
+      },
+      {
+        id: 'google',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Google',
+        defaultProps: {},
+      },
+      {
+        id: 'jira',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Jira',
+        defaultProps: {},
+      },
+      {
+        id: 'trello',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Trello',
+        defaultProps: {},
+      },
+      {
+        id: 'vsts',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Vsts',
+        defaultProps: {},
+      },
+      {
+        id: 'generic',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Generic',
+        defaultProps: {},
+      },
+      {
+        id: 'asana',
+        groups: ['logo'],
+        keywords: [''],
+        name: 'Asana',
+        defaultProps: {},
+      },
+      {
+        id: 'vercel',
+        groups: ['logo'],
+        keywords: [''],
+        name: 'Vercel',
+        defaultProps: {},
+      },
+      {
+        id: 'teamwork',
+        groups: ['logo'],
+        keywords: [],
+        name: 'Teamwork',
+        defaultProps: {},
+      },
+    ],
+  },
+  {
+    id: 'navigation',
+    label: 'Navigation',
+    icons: [
+      {
+        id: 'chevron-direction-left',
+        groups: ['navigation'],
+        keywords: [
+          'up',
+          'down',
+          'left',
+          'right',
+          'point',
+          'direct',
+          'move',
+          'expand',
+          'collapse',
+          'arrow',
+        ],
+        additionalProps: ['isCircled', 'direction'],
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: false,
+          direction: 'left',
+        },
+      },
+      {
+        id: 'chevron-direction-right',
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: false,
+          direction: 'right',
+        },
+      },
+      {
+        id: 'chevron-direction-up',
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: false,
+          direction: 'up',
+        },
+      },
+      {
+        id: 'chevron-direction-down',
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: false,
+          direction: 'down',
+        },
+      },
+      {
+        id: 'chevron-isCircled-direction-left',
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: true,
+          direction: 'left',
+        },
+      },
+      {
+        id: 'chevron-isCircled-direction-right',
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: true,
+          direction: 'right',
+        },
+      },
+      {
+        id: 'chevron-isCircled-direction-up',
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: true,
+          direction: 'up',
+        },
+      },
+      {
+        id: 'chevron-isCircled-direction-down',
+        name: 'Chevron',
+        defaultProps: {
+          isCircled: true,
+          direction: 'down',
+        },
+      },
+      {
+        id: 'arrow-direction-left',
+        groups: ['navigation'],
+        keywords: ['up', 'down', 'left', 'right', 'point', 'direct', 'move'],
+        additionalProps: ['direction'],
+        name: 'Arrow',
+        defaultProps: {
+          direction: 'left',
+        },
+      },
+      {
+        id: 'arrow-direction-right',
+        name: 'Arrow',
+        defaultProps: {
+          direction: 'right',
+        },
+      },
+      {
+        id: 'arrow-direction-up',
+        name: 'Arrow',
+        defaultProps: {
+          direction: 'up',
+        },
+      },
+      {
+        id: 'arrow-direction-down',
+        name: 'Arrow',
+        defaultProps: {
+          direction: 'down',
+        },
+      },
+      {
+        id: 'panel-direction-left',
+        groups: ['navigation'],
+        keywords: ['sidebar', 'footer', 'header'],
+        additionalProps: ['direction'],
+        name: 'Panel',
+        defaultProps: {
+          direction: 'left',
+        },
+      },
+      {
+        id: 'panel-direction-right',
+        name: 'Panel',
+        defaultProps: {
+          direction: 'right',
+        },
+      },
+      {
+        id: 'panel-direction-up',
+        name: 'Panel',
+        defaultProps: {
+          direction: 'up',
+        },
+      },
+      {
+        id: 'panel-direction-down',
+        name: 'Panel',
+        defaultProps: {
+          direction: 'down',
+        },
+      },
+    ],
+  },
+  {
+    id: 'status',
+    label: 'Status',
+    icons: [
+      {
+        id: 'lock',
+        groups: ['action', 'status'],
+        keywords: ['secure'],
+        additionalProps: ['isSolid'],
+        name: 'Lock',
+        defaultProps: {
+          isSolid: false,
+        },
+      },
+      {
+        id: 'lock-isSolid',
+        name: 'Lock',
+        defaultProps: {
+          isSolid: true,
+        },
+      },
+      {
+        id: 'fire',
+        groups: ['status'],
+        keywords: ['danger', 'severe', 'critical'],
+        name: 'Fire',
+        defaultProps: {},
+      },
+      {
+        id: 'fatal',
+        groups: ['status'],
+        keywords: ['skull'],
+        name: 'Fatal',
+        defaultProps: {},
+      },
+      {
+        id: 'warning',
+        groups: ['status'],
+        keywords: ['alert', 'notification'],
+        name: 'Warning',
+        defaultProps: {},
+      },
+      {
+        id: 'exclamation',
+        groups: ['status'],
+        keywords: ['alert', 'warning'],
+        name: 'Exclamation',
+        defaultProps: {},
+      },
+      {
+        id: 'not',
+        groups: ['status'],
+        keywords: ['invalid', 'no', 'forbidden'],
+        name: 'Not',
+        defaultProps: {},
+      },
+      {
+        id: 'circle',
+        groups: ['status'],
+        keywords: ['shape', 'round'],
+        name: 'Circle',
+        defaultProps: {},
+      },
+      {
+        id: 'circleFill',
+        groups: ['status'],
+        keywords: ['shape', 'round'],
+        name: 'CircleFill',
+        defaultProps: {},
+      },
+      {
+        id: 'diamond',
+        groups: ['status'],
+        keywords: ['shape', 'alert', 'diamond'],
+        name: 'Diamond',
+        defaultProps: {},
+      },
+      {
+        id: 'flag',
+        groups: ['status'],
+        keywords: ['bookmark', 'mark', 'save', 'warning', 'message'],
+        name: 'Flag',
+        defaultProps: {},
+      },
+      {
+        id: 'happy',
+        groups: ['status'],
+        keywords: ['good'],
+        name: 'Happy',
+        defaultProps: {},
+      },
+      {
+        id: 'meh',
+        groups: ['status'],
+        keywords: ['meh'],
+        name: 'Meh',
+        defaultProps: {},
+      },
+      {
+        id: 'sad',
+        groups: ['status'],
+        keywords: ['poor'],
+        name: 'Sad',
+        defaultProps: {},
+      },
+      {
+        id: 'frozen',
+        groups: ['status'],
+        keywords: ['frame', 'mobile'],
+        name: 'Frozen',
+        defaultProps: {},
+      },
+      {
+        id: 'slow',
+        groups: ['status'],
+        keywords: ['frame', 'mobile'],
+        name: 'Slow',
+        defaultProps: {},
+      },
+    ],
+  },
+  {
+    id: 'action',
+    label: 'Action',
+    icons: [
+      {
+        id: 'add',
+        groups: ['action'],
+        keywords: ['plus'],
+        additionalProps: ['isCircled'],
+        name: 'Add',
+        defaultProps: {
+          isCircled: false,
+        },
+      },
+      {
+        id: 'add-isCircled',
+        name: 'Add',
+        defaultProps: {
+          isCircled: true,
+        },
+      },
+      {
+        id: 'subtract',
+        groups: ['action'],
+        keywords: ['minus'],
+        additionalProps: ['isCircled'],
+        name: 'Subtract',
+        defaultProps: {
+          isCircled: false,
+        },
+      },
+      {
+        id: 'subtract-isCircled',
+        name: 'Subtract',
+        defaultProps: {
+          isCircled: true,
+        },
+      },
+      {
+        id: 'checkmark',
+        groups: ['action'],
+        keywords: ['done', 'finish', 'success', 'confirm', 'resolve'],
+        additionalProps: ['isCircled'],
+        name: 'Checkmark',
+        defaultProps: {
+          isCircled: false,
+        },
+      },
+      {
+        id: 'checkmark-isCircled',
+        name: 'Checkmark',
+        defaultProps: {
+          isCircled: true,
+        },
+      },
+      {
+        id: 'close',
+        groups: ['action'],
+        keywords: ['cross', 'deny', 'terminate'],
+        additionalProps: ['isCircled'],
+        name: 'Close',
+        defaultProps: {
+          isCircled: false,
+        },
+      },
+      {
+        id: 'close-isCircled',
+        name: 'Close',
+        defaultProps: {
+          isCircled: true,
+        },
+      },
+      {
+        id: 'upload',
+        groups: ['action'],
+        keywords: ['file', 'image', 'up'],
+        name: 'Upload',
+        defaultProps: {},
+      },
+      {
+        id: 'download',
+        groups: ['action'],
+        keywords: ['file', 'image', 'down'],
+        name: 'Download',
+        defaultProps: {},
+      },
+      {
+        id: 'sync',
+        groups: ['action'],
+        keywords: ['swap'],
+        name: 'Sync',
+        defaultProps: {},
+      },
+      {
+        id: 'menu',
+        groups: ['action'],
+        keywords: ['navigate'],
+        name: 'Menu',
+        defaultProps: {},
+      },
+      {
+        id: 'list',
+        groups: ['action'],
+        keywords: ['item'],
+        name: 'List',
+        defaultProps: {},
+      },
+      {
+        id: 'upgrade',
+        groups: ['action'],
+        keywords: ['up'],
+        name: 'Upgrade',
+        defaultProps: {},
+      },
+      {
+        id: 'open',
+        groups: ['action'],
+        keywords: ['link', 'hyperlink', 'external'],
+        name: 'Open',
+        defaultProps: {},
+      },
+      {
+        id: 'refresh',
+        groups: ['action'],
+        keywords: ['reload', 'restart', 'repeat'],
+        name: 'Refresh',
+        defaultProps: {},
+      },
+      {
+        id: 'bookmark',
+        groups: ['action'],
+        keywords: ['favorite', 'star', 'mark'],
+        additionalProps: ['isSolid'],
+        name: 'Bookmark',
+        defaultProps: {
+          isSolid: false,
+        },
+      },
+      {
+        id: 'bookmark-isSolid',
+        name: 'Bookmark',
+        defaultProps: {
+          isSolid: true,
+        },
+      },
+      {
+        id: 'pin',
+        groups: ['action'],
+        keywords: ['stick'],
+        additionalProps: ['isSolid'],
+        name: 'Pin',
+        defaultProps: {
+          isSolid: false,
+        },
+      },
+      {
+        id: 'pin-isSolid',
+        name: 'Pin',
+        defaultProps: {
+          isSolid: true,
+        },
+      },
+      {
+        id: 'star',
+        groups: ['action'],
+        keywords: ['favorite', 'star', 'bookmark'],
+        additionalProps: ['isSolid'],
+        name: 'Star',
+        defaultProps: {
+          isSolid: false,
+        },
+      },
+      {
+        id: 'star-isSolid',
+        name: 'Star',
+        defaultProps: {
+          isSolid: true,
+        },
+      },
+      {
+        id: 'archive',
+        groups: ['product'],
+        keywords: [],
+        name: 'Archive',
+        defaultProps: {},
+      },
+      {
+        id: 'play',
+        groups: ['action'],
+        keywords: ['video', 'audio', 'unpause'],
+        name: 'Play',
+        defaultProps: {},
+      },
+      {
+        id: 'pause',
+        groups: ['action'],
+        keywords: ['video', 'audio', 'stop'],
+        name: 'Pause',
+        defaultProps: {},
+      },
+      {
+        id: 'previous',
+        groups: ['action'],
+        keywords: ['video', 'audio', 'back', 'return', 'rewind'],
+        name: 'Previous',
+        defaultProps: {},
+      },
+      {
+        id: 'next',
+        groups: ['action'],
+        keywords: ['video', 'audio', 'skip', 'forward'],
+        name: 'Next',
+        defaultProps: {},
+      },
+      {
+        id: 'search',
+        groups: ['action'],
+        keywords: ['find', 'look', 'query'],
+        name: 'Search',
+        defaultProps: {},
+      },
+      {
+        id: 'copy',
+        groups: ['action'],
+        keywords: ['duplicate'],
+        name: 'Copy',
+        defaultProps: {},
+      },
+      {
+        id: 'delete',
+        groups: ['action'],
+        keywords: ['trash', 'can', 'dumpster', 'remove', 'erase', 'clear'],
+        name: 'Delete',
+        defaultProps: {},
+      },
+      {
+        id: 'docs',
+        groups: ['action'],
+        keywords: ['document'],
+        name: 'Docs',
+        defaultProps: {},
+      },
+      {
+        id: 'link',
+        groups: ['action'],
+        keywords: ['hyperlink'],
+        name: 'Link',
+        defaultProps: {},
+      },
+      {
+        id: 'attachment',
+        groups: ['action'],
+        keywords: ['include', 'clip'],
+        name: 'Attachment',
+        defaultProps: {},
+      },
+      {
+        id: 'location',
+        groups: ['action'],
+        keywords: ['pin', 'position', 'map'],
+        name: 'Location',
+        defaultProps: {},
+      },
+      {
+        id: 'edit',
+        groups: ['action'],
+        keywords: ['pencil'],
+        name: 'Edit',
+        defaultProps: {},
+      },
+      {
+        id: 'filter',
+        groups: ['action'],
+        keywords: [],
+        name: 'Filter',
+        defaultProps: {},
+      },
+      {
+        id: 'sort',
+        groups: ['action'],
+        keywords: [],
+        name: 'Sort',
+        defaultProps: {},
+      },
+      {
+        id: 'show',
+        groups: ['action'],
+        keywords: ['visible'],
+        name: 'Show',
+        defaultProps: {},
+      },
+      {
+        id: 'lock',
+        name: 'Lock',
+        defaultProps: {
+          isSolid: false,
+        },
+      },
+      {
+        id: 'lock-isSolid',
+        name: 'Lock',
+        defaultProps: {
+          isSolid: true,
+        },
+      },
+      {
+        id: 'grabbable',
+        groups: ['action'],
+        keywords: ['move', 'arrange', 'organize', 'rank', 'switch'],
+        name: 'Grabbable',
+        defaultProps: {},
+      },
+      {
+        id: 'ellipsis',
+        groups: ['action'],
+        keywords: ['expand', 'open', 'more', 'hidden'],
+        name: 'Ellipsis',
+        defaultProps: {},
+      },
+      {
+        id: 'megaphone',
+        groups: ['action'],
+        keywords: ['speaker', 'announce'],
+        name: 'Megaphone',
+        defaultProps: {},
+      },
+      {
+        id: 'question',
+        groups: ['action'],
+        keywords: ['info', 'about', 'information', 'ask', 'faq', 'q&a'],
+        name: 'Question',
+        defaultProps: {},
+      },
+      {
+        id: 'info',
+        groups: ['action'],
+        keywords: ['more', 'about', 'information', 'ask', 'faq', 'q&a'],
+        name: 'Info',
+        defaultProps: {},
+      },
+      {
+        id: 'user',
+        groups: ['action'],
+        keywords: ['person', 'portrait'],
+        name: 'User',
+        defaultProps: {},
+      },
+      {
+        id: 'chat',
+        groups: ['action', 'action'],
+        keywords: ['message', 'bubble'],
+        name: 'Chat',
+        defaultProps: {},
+      },
+      {
+        id: 'clock',
+        groups: ['action'],
+        keywords: ['time', 'watch'],
+        name: 'Clock',
+        defaultProps: {},
+      },
+      {
+        id: 'sliders-direction-left',
+        groups: ['action'],
+        keywords: ['settings', 'slide', 'adjust'],
+        additionalProps: ['direction'],
+        name: 'Sliders',
+        defaultProps: {
+          direction: 'left',
+        },
+      },
+      {
+        id: 'sliders-direction-up',
+        name: 'Sliders',
+        defaultProps: {
+          direction: 'up',
+        },
+      },
+      {
+        id: 'toggle',
+        groups: ['action'],
+        keywords: ['switch', 'form', 'disable', 'enable'],
+        name: 'Toggle',
+        defaultProps: {},
+      },
+      {
+        id: 'fix',
+        groups: ['action'],
+        keywords: ['wrench', 'resolve'],
+        name: 'Fix',
+        defaultProps: {},
+      },
+      {
+        id: 'tag',
+        groups: ['action'],
+        keywords: ['price', 'category', 'group'],
+        name: 'Tag',
+        defaultProps: {},
+      },
+      {
+        id: 'moon',
+        groups: ['action'],
+        keywords: ['dark', 'night'],
+        name: 'Moon',
+        defaultProps: {},
+      },
+      {
+        id: 'subscribed',
+        groups: ['action'],
+        keywords: ['alert', 'notification', 'subscribe', 'bell', 'ring'],
+        name: 'Subscribed',
+        defaultProps: {},
+      },
+      {
+        id: 'unsubscribed',
+        groups: ['action'],
+        keywords: ['alert', 'notification', 'subscribe', 'bell', 'ring'],
+        name: 'Unsubscribed',
+        defaultProps: {},
+      },
+      {
+        id: 'sound',
+        groups: ['action'],
+        keywords: ['audio'],
+        name: 'Sound',
+        defaultProps: {},
+      },
+      {
+        id: 'mute',
+        groups: ['action'],
+        keywords: ['audio'],
+        name: 'Mute',
+        defaultProps: {},
+      },
+      {
+        id: 'resize',
+        groups: ['action'],
+        keywords: ['scale', 'stretch'],
+        name: 'Resize',
+        defaultProps: {},
+      },
+      {
+        id: 'expand',
+        groups: ['action'],
+        keywords: ['open'],
+        name: 'Expand',
+        defaultProps: {},
+      },
+      {
+        id: 'contract',
+        groups: ['action'],
+        keywords: ['close'],
+        name: 'Contract',
+        defaultProps: {},
+      },
+      {
+        id: 'group',
+        groups: ['action'],
+        keywords: ['users', 'person', 'people'],
+        name: 'Group',
+        defaultProps: {},
+      },
+      {
+        id: 'rewind10',
+        groups: ['action'],
+        keywords: ['rewind'],
+        name: 'Rewind10',
+        defaultProps: {},
+      },
+      {
+        id: 'timer',
+        name: 'Timer',
+        defaultProps: {},
+      },
+      {
+        id: 'cursorArrow',
+        keywords: ['pointer', 'mouse'],
+        name: 'CursorArrow',
+        defaultProps: {},
+      },
+      {
+        id: 'keyDown',
+        keywords: ['keyboard', 'press', 'click', 'tap'],
+        name: 'KeyDown',
+        defaultProps: {},
+      },
+    ],
+  },
+  {
+    id: 'chart',
+    label: 'Chart',
+    icons: [
+      {
+        id: 'graph-type-line',
+        groups: ['chart'],
+        keywords: ['line', 'plot'],
+        additionalProps: ['type'],
+        name: 'Graph',
+        defaultProps: {
+          type: 'line',
+        },
+      },
+      {
+        id: 'graph-type-circle',
+        name: 'Graph',
+        defaultProps: {
+          type: 'circle',
+        },
+      },
+      {
+        id: 'graph-type-bar',
+        name: 'Graph',
+        defaultProps: {
+          type: 'bar',
+        },
+      },
+      {
+        id: 'graph-type-area',
+        name: 'Graph',
+        defaultProps: {
+          type: 'area',
+        },
+      },
+      {
+        id: 'stack',
+        groups: ['chart'],
+        keywords: ['group', 'combine', 'view'],
+        name: 'Stack',
+        defaultProps: {},
+      },
+      {
+        id: 'span',
+        groups: ['chart'],
+        keywords: ['performance', 'transaction'],
+        name: 'Span',
+        defaultProps: {},
+      },
+      {
+        id: 'number',
+        groups: ['chart'],
+        keywords: ['value'],
+        name: 'Number',
+        defaultProps: {},
+      },
+      {
+        id: 'profiling',
+        name: 'Profiling',
+        defaultProps: {},
+      },
+    ],
+  },
+  {
+    id: 'device',
+    label: 'Device',
+    icons: [
+      {
+        id: 'return',
+        groups: ['device'],
+        keywords: ['enter'],
+        name: 'Return',
+        defaultProps: {},
+      },
+      {
+        id: 'file',
+        groups: ['device'],
+        keywords: ['document'],
+        name: 'File',
+        defaultProps: {},
+      },
+      {
+        id: 'print',
+        groups: ['device'],
+        keywords: [],
+        name: 'Print',
+        defaultProps: {},
+      },
+      {
+        id: 'code',
+        groups: ['device'],
+        keywords: ['snippet', 'javascript', 'json', 'curly', 'source'],
+        name: 'Code',
+        defaultProps: {},
+      },
+      {
+        id: 'json',
+        groups: ['device'],
+        keywords: ['snippet', 'code', 'javascript', 'source'],
+        name: 'Json',
+        defaultProps: {},
+      },
+      {
+        id: 'markdown',
+        groups: ['device'],
+        keywords: ['code'],
+        name: 'Markdown',
+        defaultProps: {},
+      },
+      {
+        id: 'terminal',
+        groups: ['device', 'device'],
+        keywords: ['code', 'bash', 'command'],
+        name: 'Terminal',
+        defaultProps: {},
+      },
+      {
+        id: 'commit',
+        groups: ['device'],
+        keywords: ['git', 'github'],
+        name: 'Commit',
+        defaultProps: {},
+      },
+      {
+        id: 'laptop',
+        groups: ['device'],
+        keywords: ['computer', 'macbook'],
+        name: 'Laptop',
+        defaultProps: {},
+      },
+      {
+        id: 'mobile',
+        groups: ['device'],
+        keywords: ['phone', 'iphone'],
+        name: 'Mobile',
+        defaultProps: {},
+      },
+      {
+        id: 'window',
+        groups: ['device'],
+        keywords: ['application'],
+        name: 'Window',
+        defaultProps: {},
+      },
+      {
+        id: 'calendar',
+        groups: ['device'],
+        keywords: ['time', 'date'],
+        name: 'Calendar',
+        defaultProps: {},
+      },
+      {
+        id: 'mail',
+        groups: ['device'],
+        keywords: ['email'],
+        name: 'Mail',
+        defaultProps: {},
+      },
+      {
+        id: 'input',
+        groups: ['device'],
+        keywords: ['text'],
+        name: 'Input',
+        defaultProps: {},
+      },
+      {
+        id: 'option',
+        groups: ['device'],
+        keywords: [''],
+        name: 'Option',
+        defaultProps: {},
+      },
+      {
+        id: 'fileBroken',
+        groups: ['device'],
+        keywords: ['file', 'missing', 'error'],
+        name: 'FileBroken',
+        defaultProps: {},
+      },
+    ],
+  },
+];
+
+export default function IconsStories() {
+  const [searchTerm, setSearchTerm] = useState('');
+
+  const definedWithPrefix = new Set<string>();
+  SECTIONS.forEach(section =>
+    section.icons.forEach(icon => definedWithPrefix.add(`Icon${icon.name}`))
+  );
+  const unclassifiedSection = {
+    id: 'other',
+    label: 'Unclassified',
+    icons: Object.keys(Icons)
+      .filter(name => !definedWithPrefix.has(name))
+      .map((name): TIcon => ({id: name, name})),
+  };
+
+  const filteredSections = searchTerm
+    ? SECTIONS.map(section => ({
+        ...section,
+        icons: section.icons.filter(
+          icon =>
+            icon.name.toLowerCase().includes(searchTerm) ||
+            icon.keywords?.some(keyword => keyword.toLowerCase().includes(searchTerm))
+        ),
+      }))
+    : SECTIONS;
+
+  return (
+    <Fragment>
+      <StyledSticky>
+        <p>
+          In addition to icon name, you can also search by keyword. For example, typing
+          either <kbd>checkmark</kbd> or <kbd>success</kbd> will return{' '}
+          <samp>IconCheckmark</samp>.
+        </p>
+        <Input
+          placeholder="Search icons by name or keyword"
+          onChange={e => setSearchTerm(e.target.value.toLowerCase())}
+        />
+      </StyledSticky>
+
+      <Section section={unclassifiedSection} />
+
+      {filteredSections.map(section => (
+        <Section key={section.id} section={section} />
+      ))}
+
+      <PlatformIconsSection searchTerm={searchTerm} />
+    </Fragment>
+  );
+}
+
+function Section({section}: {section: TSection}) {
+  if (section.icons.length === 0) {
+    return null;
+  }
+
+  return (
+    <section>
+      <SectionHeader>{section.label}</SectionHeader>
+      <Grid style={{gridTemplateColumns: 'repeat(4, 1fr)'}}>
+        {section.icons.map(icon => {
+          const name = icon.name.startsWith('Icon') ? icon.name : `Icon${icon.name}`;
+          const Component = Icons[name];
+
+          const props = {color: 'gray500', size: 'sm', ...icon.defaultProps};
+          return (
+            <Tooltip
+              key={icon.id}
+              title={formatObjAsReactStatement(name, props)}
+              isHoverable
+            >
+              <Cell>
+                <Component {...props} />
+                {name}
+              </Cell>
+            </Tooltip>
+          );
+        })}
+      </Grid>
+    </section>
+  );
+}
+
+function PlatformIconsSection({searchTerm}: {searchTerm: string}) {
+  const platforms = Object.keys(platformToIcon).filter(platform =>
+    platform.includes(searchTerm)
+  );
+
+  return (
+    <section>
+      <SectionHeader>PlatformIcons</SectionHeader>
+      <Grid
+        style={{
+          gridAutoFlow: 'column',
+          gridTemplateRows: `repeat(${Math.ceil(platforms.length / 4)}, 1fr)`,
+        }}
+      >
+        {platforms.map(platform => (
+          <Tooltip
+            key={platform}
+            title={formatObjAsReactStatement('PlatformIcon', {platform})}
+            isHoverable
+          >
+            <Cell>
+              <PlatformIcon platform={platform} /> {platform}
+            </Cell>
+          </Tooltip>
+        ))}
+      </Grid>
+    </section>
+  );
+}
+
+function formatObjAsReactStatement(name, props: Record<string, unknown>) {
+  const keyValues = Object.entries(props)
+    .map(([prop, val]) => (val === true ? prop : `${prop}=${JSON.stringify(val)}`))
+    .join(' ');
+  return `<${name} ${keyValues} />`;
+}
+
+const StyledSticky = styled(Sticky)`
+  background: ${p => p.theme.background};
+  z-index: ${p => p.theme.zIndex.initial};
+  &[data-stuck='true'] {
+    box-shadow: 0px 10px 20px -8px rgba(128, 128, 128, 0.89);
+  }
+`;
+
+const SectionHeader = styled('h5')`
+  margin-block: ${space(2)};
+`;
+
+const Grid = styled('div')`
+  display: grid;
+  gap: ${space(1)};
+  align-items: center;
+`;
+
+const Cell = styled('div')`
+  display: flex;
+  gap: ${space(1)};
+  align-items: center;
+  border: 1px solid transparent;
+  border-radius: ${p => p.theme.borderRadius};
+  padding: ${space(1)};
+  cursor: pointer;
+
+  &:hover {
+    border-color: ${p => p.theme.border};
+  }
+`;