Files
openchamber/packages/ui/src/components/icon
Bohdan Triapitsyn d6f0f2f23c feat(settings): retire the third-party plugin integrations
Settings → Integrations offered install cards for the Claude Code and
Cursor provider plugins. They are gone: the section, its plugin catalog,
its own i18n module and tests, the settings search entries, the page
keywords, and the two sprite icons only it used. The page now holds the
built-in GitHub and Linear cards, so it is hidden in VS Code where neither
applies; its title and description live in the settings dictionaries.

Docs follow: the Integrations page in every locale now documents GitHub
(pointing at its own page) and Linear in full, the GitHub page names
Settings → Integrations as the place to connect and covers linking an
issue or PR to a message, and the Providers pages no longer promise Claude
or Cursor subscriptions.

Claude-Session: https://claude.ai/code/session_01HB9wdLQoZX2vfyDjwv6Rso
2026-09-04 23:34:15 +03:00
..

Icon System

OpenChamber uses an SVG sprite-based icon system for performance. Remixicon glyphs and explicitly registered custom glyphs are rendered via a single hidden SVG sprite injected into the DOM, referenced by <use href="#oc-icon-name"/>.

Usage

import { Icon } from "@/components/icon/Icon";

<Icon name="arrow-down-s" className="h-4 w-4" />
<Icon name="loader-4" className="size-4 animate-spin" />

Icon Names

Icons use kebab-case names based on Remixicon. To find an icon name:

  1. Start from the Remixicon component name: RiArrowDownSLine
  2. Remove Ri prefix → ArrowDownSLine
  3. Convert to kebab-case → arrow-down-s

Common suffixes:

  • Line / Fill are dropped from the sprite name
  • Numbers are preserved: RiChat4Linechat-4

Adding a New Icon

  1. Import and use it in your code: <Icon name="new-icon-name" />
  2. Run bun run icons:sprite to regenerate the sprite with the new icon
  3. The script scans packages/ui/src for all RiX usages and extracts SVG paths

If the icon doesn't exist in the sprite, the script will warn you.

Custom product glyphs are registered in scripts/generate-icon-sprite.mjs. They must use the shared 24x24 viewbox and currentColor so they match Remixicon sizing and theme behavior.

Sizing

The Icon component does not have a size prop. Use Tailwind classes instead:

<Icon name="arrow-down-s" className="h-4 w-4" />   {/* 16px */}
<Icon name="arrow-down-s" className="size-5" />      {/* 20px */}
<Icon name="arrow-down-s" className="h-6 w-6" />     {/* 24px */}

Type Safety

import type { IconName } from "@/components/icon/icons";

const icon: IconName = "arrow-down-s"; // type-checked

Architecture

  • sprite.ts — Auto-generated SVG path data (run bun run generate-icon-sprite to regenerate)
  • Icon.tsx — The <Icon> component, injects sprite on first mount
  • icons.ts — TypeScript type IconName

The sprite is injected as a hidden <svg id="openchamber-icon-sprite"> element containing <symbol> elements. Each <Icon> renders <svg><use href="#oc-{name}"/></svg>.

Migration from @remixicon/react

Old:

import { RiArrowDownSLine } from "@remixicon/react";
<RiArrowDownSLine className="h-4 w-4" />

New:

import { Icon } from "@/components/icon/Icon";
<Icon name="arrow-down-s" className="h-4 w-4" />

If an icon is used as a component reference (not JSX):

// Old: const icon = RiStackLine; return <icon />;
// New: const icon: IconName = "stack"; return <Icon name={icon} />;