Skip to content

refactor(ui): overhaul icon system and migrate Avatar to shadcn/radix#12858

Merged
kangfenmao merged 32 commits intov2from
feat/v2/mono-icons
Mar 16, 2026
Merged

refactor(ui): overhaul icon system and migrate Avatar to shadcn/radix#12858
kangfenmao merged 32 commits intov2from
feat/v2/mono-icons

Conversation

@DeJeune
Copy link
Copy Markdown
Collaborator

@DeJeune DeJeune commented Feb 10, 2026

What this PR does

Before this PR:

  • Provider/model icons were scattered image imports (PNG/WebP) with no unified API
  • Avatar primitive was based on HeroUI with hardcoded shadow-lg and border-[0.5px]
  • Full-bleed and padded avatar variants used different rendering approaches
  • Multiple files duplicated IIFE patterns for rendering CompoundIcon vs string logos
  • No type-safe icon catalogs

After this PR:

  • Compound Icon API: Each icon exposes .Color, .Mono, and .Avatar sub-components via a unified CompoundIcon interface
  • Auto-generated catalogs: PROVIDER_ICON_CATALOG and MODEL_ICON_CATALOG with resolveProviderIcon / resolveModelIcon helpers
  • SVG pipeline: Codegen processes SVGs → generates Color/Mono/Avatar components
  • Avatar migrated to shadcn/radix: Replaced HeroUI Avatar with Avatar + AvatarFallback pattern, removed hardcoded shadow/border
  • EmojiAvatar moved: From primitives/Avatar/ to composites/EmojiAvatar/
  • LogoAvatar component: Reusable component replacing repeated IIFE patterns across 5+ files
  • getMCPProviderLogo helper: Centralized MCP provider icon mapping
  • 80+ monochrome icon components, stroke attribute support, deprecated logos cleanup
image image

Why we need it and why it was done in this way

The v2 refactoring requires moving away from HeroUI toward shadcn/radix primitives, and needs a scalable, type-safe icon system to replace scattered image imports. The compound icon pattern (Icon.Color, Icon.Mono, Icon.Avatar) provides a consistent API while enabling tree-shaking. The Avatar primitive now uses radix-based Avatar + AvatarFallback, aligning with the project's shadcn migration.

The following tradeoffs were made:

  • Each icon is a separate TSX file for tree-shaking and lazy loading support
  • Avatar components use AvatarFallback to render icons — no image loading overhead

The following alternatives were considered:

  • Runtime SVG color manipulation — rejected for better performance and consistency
  • Keeping HeroUI Avatar — rejected as it conflicts with v2 shadcn migration goals

Breaking changes

  • Avatar primitive API changed: HeroUI Avatar → shadcn Avatar + AvatarFallback + AvatarImage
  • EmojiAvatar moved from primitives/Avatar to composites/EmojiAvatar
  • shadow-lg and border-[0.5px] removed from generated avatars — now opt-in via className

Special notes for your reviewer

  • ~214 files changed, but the bulk are auto-generated avatar/icon components under packages/ui/src/components/icons/
  • Key files to review:
    • packages/ui/src/components/primitives/avatar.tsx — new shadcn Avatar primitive
    • packages/ui/scripts/codegen.ts — avatar generation using AvatarFallback
    • src/renderer/src/components/Icons/LogoAvatar.tsx — reusable logo renderer
    • Renderer files using the new Avatar API (Sidebar, UserPopup, ModelAvatar, etc.)

Checklist

  • PR: The PR description is expressive enough and will help future contributors
  • Code: Write code that humans can understand and Keep it simple
  • Refactor: You have left the code cleaner than you found it (Boy Scout Rule)
  • Upgrade: Impact of this change on upgrade flows was considered and addressed if required
  • Documentation: N/A - internal component changes

Release note

NONE

🤖 Generated with Claude Code

Add MonoIcon component and generate-mono-icons script for creating
monochrome versions of provider logos. Update existing SVG logos
(DMXAPI, aiOnly, cephalon, cherryin, lanyun, ph8, tokenflux) and
add tng.svg.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@DeJeune DeJeune requested a review from a team February 10, 2026 11:31
@DeJeune DeJeune added the v2 label Feb 10, 2026
@DeJeune DeJeune marked this pull request as draft February 10, 2026 11:33
@MyPrototypeWhat
Copy link
Copy Markdown
Collaborator

MyPrototypeWhat commented Feb 10, 2026

Note

This comment was translated by Claude.

Were the tsx files generated by executing the icon generation command?


Original Content

是通过执行icon生成的命令生成的tsx吗

Refactor logo icon exports to use compound component pattern:
  <Anthropic />        — Color (default)
  <Anthropic.Color />  — Color (explicit)
  <Anthropic.Mono />   — Mono (currentColor)

- Update logos/index.ts to export compound components via Object.assign
- Add #__PURE__ annotations for proper tree-shaking
- Remove logos-mono/index.ts barrel (mono accessed via .Mono)
- Remove LogosMono namespace export from icons/index.ts
- Update generate-mono-icons.ts to produce compound barrel

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@DeJeune
Copy link
Copy Markdown
Collaborator Author

DeJeune commented Feb 10, 2026

Note

This comment was translated by Claude.

Were the tsx files generated by executing the icon generation command?

Original Content

MyPrototypeWhat

This comment was marked as resolved.

DeJeune and others added 13 commits February 16, 2026 19:29
Replace @svgr/core ConfigPlugin with proper svgo types, add local svgo
AST type definitions, and consolidate duplicated helper functions
(toCamelCase, ensureViewBox, isImageBased, etc.) into svg-utils.ts.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…enerated catalogs

Implement a centralized icon resolution system in packages/ui that replaces
the old PNG/WebP-based logo imports with CompoundIcon components. Adds
MODEL_ICON_PATTERNS, MODEL_TO_PROVIDER_PATTERNS, and PROVIDER_ID_ALIASES
for regex-based model-to-icon matching with three-tier fallback chain.

Integrates catalog.ts auto-generation into the icon pipeline so new icons
are automatically included. Migrates all renderer consumers (ModelAvatar,
ProviderAvatar, painting pages, mention panel, etc.) from <Avatar src={url}>
to <Icon.Avatar />.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…and replace MCP market logos

- Use `as const satisfies` for PROVIDER_ICON_CATALOG and MODEL_ICON_CATALOG
  to enable compile-time key validation and export ProviderIconKey/ModelIconKey types
- Update codegen script to generate type-safe catalogs automatically
- Extract shared getWebSearchProviderLogo() to eliminate 4 duplicate icon mappings
- Replace URL-based logos in McpMarketList with PROVIDER_ICON_CATALOG entries
- Add new provider icons and remove deprecated image assets

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Replace shadow-lg with shadow-none in Avatar primitive
- Remove hardcoded border-[0.5px] from generated avatars
- Unify full-bleed variant to use Avatar primitive instead of raw div
- Regenerate all 187 provider and model avatar components

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@DeJeune DeJeune marked this pull request as ready for review February 19, 2026 08:50
DeJeune and others added 3 commits February 19, 2026 16:59
Use execSync to run biome format on all ts-morph generated files
(index.ts, meta.ts, barrel index, catalog) to remove semicolons and
match project formatting conventions.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace repeated IIFE patterns for CompoundIcon vs string logo rendering
with a reusable LogoAvatar component. Extract MCP provider icon mapping
into a dedicated getMCPProviderLogo helper function.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@DeJeune DeJeune changed the title feat(ui): add mono icon components and update provider logos refactor(ui): overhaul icon system with compound icons, catalogs, and unified avatar rendering Feb 19, 2026
DeJeune and others added 5 commits February 19, 2026 17:24
…egen

Fix typo in Stability AI icon name across SVG, generated components,
catalog, barrel index, and registry. Remove per-file biome formatting
from codegen to avoid slow generation — format externally instead.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace HeroUI Avatar with shadcn-style Avatar + AvatarFallback.
Move EmojiAvatar from primitives to composites. Regenerate all
avatar components to use the new AvatarFallback pattern. Update
renderer components to use the new Avatar API.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@DeJeune DeJeune changed the title refactor(ui): overhaul icon system with compound icons, catalogs, and unified avatar rendering refactor(ui): overhaul icon system and migrate Avatar to shadcn/radix Feb 19, 2026
DeJeune and others added 8 commits February 19, 2026 20:18
Prevents unwanted gray background on icons with transparent SVGs.
Background is now opt-in via className (e.g. bg-background for padded).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The radix-ui meta-package was removed but avatar.tsx still imported from
it, breaking typecheck. Add the specific @radix-ui/react-avatar package
and update the import.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Remove `export * from './icons'` from components/index.ts, replacing it
with type-only exports. All icon imports now go through the dedicated
`@cherrystudio/ui/icons` subpath. For 7 consumer files that only used
static PROVIDER_ICON_CATALOG access, replace with direct named icon
imports to enable per-icon tree-shaking.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- package.json: keep both test:pkg:ui and test:shared scripts
- minapps.ts: use icon catalog functions (PR) with supportedRegions/bodered/style (v2)
- logo.ts: keep simplified getModelLogoById using resolveModelIcon (PR)
- CodeToolsPage.tsx: use AnthropicProviderListPopover component (v2)
- PpioPage.tsx: use simplified navigation without useLocation (v2)
- types/index.ts: keep supportedRegions (v2) with logo type supporting objects (PR)
- pnpm-lock.yaml: regenerated from merged package.json

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: suyao <[email protected]>
Copy link
Copy Markdown
Contributor

@cherry-ai-bot cherry-ai-bot bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the icon-system overhaul and the Avatar migration paths. I focused on the higher-risk areas first: generated logo exports, provider/model logo mapping, and the renderer-side Avatar consumers. I didn't find a concrete blocking regression in the current revision, and the remaining comments I saw were mostly about style/story completeness rather than functional breakage. LGTM.

Copy link
Copy Markdown
Collaborator

@GeorgeDong32 GeorgeDong32 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This review was translated by Claude.

Review by kimi-k2.5

Overall Assessment

This is a high-quality large-scale refactoring PR that implements a comprehensive overhaul of the icon system and migrates the Avatar component to shadcn/radix. The code design is excellent, with thorough test coverage and full compliance with project standards.

Recommended Status: Approve

Review Summary

Category Rating Description
Code Quality ⭐⭐⭐⭐⭐ Excellent type safety, clear API design
Architecture Design ⭐⭐⭐⭐⭐ Elegant Compound Icon pattern, tree-shaking friendly
Test Coverage ⭐⭐⭐⭐⭐ SVG utility functions have complete unit tests
Documentation ⭐⭐⭐⭐ Comprehensive README, though some internal implementations lack JSDoc
Security ⭐⭐⭐⭐⭐ No security issues
Performance ⭐⭐⭐⭐⭐ Supports tree-shaking, AvatarFallback prevents unnecessary image loading

Key Highlights

  1. Excellent Compound Icon API Design - .Color, .Mono, .Avatar sub-components are uniformly exposed with type safety
  2. Reasonable Icon Resolution Strategy - Three-level fallback mechanism (Model → Provider → Provider ID) provides comprehensive coverage
  3. High-Quality Code Generation - Uses ts-morph for AST-level generation, ensuring code consistency
  4. Complete Avatar Migration - Correctly migrated to @radix-ui/react-avatar with size/shape variant support
  5. Adequate Test Coverage - SVG utility functions handle edge cases appropriately

Minor Suggestions (Non-Blocking)

src/renderer/src/components/Icons/LogoAvatar.tsx:19

// Current
const Icon = logo as CompoundIcon

// Suggestion: use type guard for safer approach
if (typeof logo !== 'string' && 'Avatar' in logo) {
  return <logo.Avatar size={size} shape={shape} className={className} />
}

Verification Checklist

  • ✅ Code logic is correct
  • ✅ Good type safety
  • ✅ Adequate test coverage
  • ✅ No security vulnerabilities
  • ✅ Supports tree-shaking
  • ✅ Follows project coding standards
  • ✅ Breaking changes are clearly documented
  • ⚠️ Minor type assertions can be optimized later

This is a high-quality PR with reasonable refactoring design and complete implementation. It can be merged with confidence. The icon system refactoring will significantly improve project maintainability and performance.


Original Content

Review by kimi-k2.5

总体评价

这是一个高质量的大型重构 PR,实现了图标系统的全面改造和 Avatar 组件的 shadcn/radix 迁移。代码设计良好,测试覆盖充分,符合项目规范。

建议状态: Approve

审查摘要

类别 评分 说明
代码质量 ⭐⭐⭐⭐⭐ 良好的类型安全、清晰的 API 设计
架构设计 ⭐⭐⭐⭐⭐ Compound Icon 模式优雅,tree-shaking 友好
测试覆盖 ⭐⭐⭐⭐⭐ SVG 处理工具函数有完整单元测试
文档 ⭐⭐⭐⭐ README 详尽,但部分内部实现缺少 JSDoc
安全性 ⭐⭐⭐⭐⭐ 无安全问题
性能 ⭐⭐⭐⭐⭐ 支持 tree-shaking,AvatarFallback 避免图片加载

主要亮点

  1. Compound Icon API 设计优秀 - .Color.Mono.Avatar 子组件统一暴露,类型安全
  2. 图标解析策略合理 - 三级回退机制(Model → Provider → Provider ID)覆盖全面
  3. 代码生成质量高 - 使用 ts-morph 进行 AST 级别生成,保证代码一致性
  4. Avatar 迁移完整 - 正确迁移到 @radix-ui/react-avatar,支持 size/shape 变体
  5. 测试覆盖充分 - SVG 工具函数边界情况处理得当

轻微建议(非阻塞)

src/renderer/src/components/Icons/LogoAvatar.tsx:19

// 当前
const Icon = logo as CompoundIcon

// 建议:使用类型守卫更安全
if (typeof logo !== 'string' && 'Avatar' in logo) {
  return <logo.Avatar size={size} shape={shape} className={className} />
}

验证检查清单

  • ✅ 代码逻辑正确
  • ✅ 类型安全良好
  • ✅ 测试覆盖充分
  • ✅ 无安全漏洞
  • ✅ 支持 tree-shaking
  • ✅ 符合项目代码规范
  • ✅ Breaking changes 已明确记录
  • ⚠️ 轻微类型断言可后续优化

这是一个高质量的 PR,重构设计合理,实现完整,可以放心合并。图标系统的重构将大大改善项目的可维护性和性能。

@kangfenmao kangfenmao merged commit 43f2a6b into v2 Mar 16, 2026
12 checks passed
@kangfenmao kangfenmao deleted the feat/v2/mono-icons branch March 16, 2026 09:13
0xfullex added a commit that referenced this pull request Mar 17, 2026
… package

The icon-system overhaul (#12858) removed legacy PNG/WebP/SVG logos from
assets/images/apps|models|providers, breaking 20 renderer tests that
transitively imported minapps.ts. Replace all 57 dead image imports with
CompoundIcon references from @cherrystudio/ui/icons, keeping only
application.png (custom-app fallback) and ima.svg (no catalog entry yet).

Signed-off-by: fullex <[email protected]>
MyPrototypeWhat pushed a commit that referenced this pull request Mar 30, 2026
…#12858)

### What this PR does

Before this PR:
- Provider/model icons were scattered image imports (PNG/WebP) with no
unified API
- Avatar primitive was based on HeroUI with hardcoded `shadow-lg` and
`border-[0.5px]`
- Full-bleed and padded avatar variants used different rendering
approaches
- Multiple files duplicated IIFE patterns for rendering CompoundIcon vs
string logos
- No type-safe icon catalogs

After this PR:
- **Compound Icon API**: Each icon exposes `.Color`, `.Mono`, and
`.Avatar` sub-components via a unified `CompoundIcon` interface
- **Auto-generated catalogs**: `PROVIDER_ICON_CATALOG` and
`MODEL_ICON_CATALOG` with `resolveProviderIcon` / `resolveModelIcon`
helpers
- **SVG pipeline**: Codegen processes SVGs → generates Color/Mono/Avatar
components
- **Avatar migrated to shadcn/radix**: Replaced HeroUI Avatar with
`Avatar` + `AvatarFallback` pattern, removed hardcoded shadow/border
- **EmojiAvatar moved**: From `primitives/Avatar/` to
`composites/EmojiAvatar/`
- **LogoAvatar component**: Reusable component replacing repeated IIFE
patterns across 5+ files
- **getMCPProviderLogo helper**: Centralized MCP provider icon mapping
- 80+ monochrome icon components, stroke attribute support, deprecated
logos cleanup

<img width="714" height="820" alt="image"
src="https://github.com/user-attachments/assets/a3f14348-5781-494a-8c3b-1f40391e2ec0"
/>

<img width="1008" height="593" alt="image"
src="https://github.com/user-attachments/assets/8ba7fa42-fa33-4e49-ba76-647ba1438e0c"
/>

### Why we need it and why it was done in this way

The v2 refactoring requires moving away from HeroUI toward shadcn/radix
primitives, and needs a scalable, type-safe icon system to replace
scattered image imports. The compound icon pattern (`Icon.Color`,
`Icon.Mono`, `Icon.Avatar`) provides a consistent API while enabling
tree-shaking. The Avatar primitive now uses radix-based `Avatar` +
`AvatarFallback`, aligning with the project's shadcn migration.

The following tradeoffs were made:
- Each icon is a separate TSX file for tree-shaking and lazy loading
support
- Avatar components use `AvatarFallback` to render icons — no image
loading overhead

The following alternatives were considered:
- Runtime SVG color manipulation — rejected for better performance and
consistency
- Keeping HeroUI Avatar — rejected as it conflicts with v2 shadcn
migration goals

### Breaking changes

- Avatar primitive API changed: `HeroUI Avatar` → shadcn `Avatar` +
`AvatarFallback` + `AvatarImage`
- `EmojiAvatar` moved from `primitives/Avatar` to
`composites/EmojiAvatar`
- `shadow-lg` and `border-[0.5px]` removed from generated avatars — now
opt-in via `className`

### Special notes for your reviewer

- ~214 files changed, but the bulk are auto-generated avatar/icon
components under `packages/ui/src/components/icons/`
- Key files to review:
- `packages/ui/src/components/primitives/avatar.tsx` — new shadcn Avatar
primitive
- `packages/ui/scripts/codegen.ts` — avatar generation using
AvatarFallback
- `src/renderer/src/components/Icons/LogoAvatar.tsx` — reusable logo
renderer
- Renderer files using the new Avatar API (Sidebar, UserPopup,
ModelAvatar, etc.)

### Checklist

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: Write code that humans can understand and Keep it simple
- [x] Refactor: You have left the code cleaner than you found it (Boy
Scout Rule)
- [ ] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: N/A - internal component changes

### Release note

```release-note
NONE
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: suyao <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: icarus <[email protected]>
MyPrototypeWhat pushed a commit that referenced this pull request Mar 30, 2026
… package

The icon-system overhaul (#12858) removed legacy PNG/WebP/SVG logos from
assets/images/apps|models|providers, breaking 20 renderer tests that
transitively imported minapps.ts. Replace all 57 dead image imports with
CompoundIcon references from @cherrystudio/ui/icons, keeping only
application.png (custom-app fallback) and ima.svg (no catalog entry yet).

Signed-off-by: fullex <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants