perf(ui): migrate icons to SVG sprite system
Replace @remixicon/react with a shared Icon component that renders via <use href> references to a single hidden SVG sprite. This reduces DOM node count by replacing inline SVGs with lightweight references. - Create Icon component with sprite injection (packages/ui/src/components/icon/) - Migrate all 164 files from @remixicon/react to Icon component - Auto-generate sprite data from remixicon bundle (scripts/generate-icon-sprite.mjs) - Add bun run icons:generate to package.json - Move @remixicon/react to devDependencies - Add icon usage instructions to theme-system skill
This commit is contained in:
@@ -1,24 +1,3 @@
|
||||
import {
|
||||
RiBrainAi3Line,
|
||||
RiCheckboxCircleLine,
|
||||
RiBugLine,
|
||||
RiCodeLine,
|
||||
RiCommandLine,
|
||||
RiFileTextLine,
|
||||
RiFlaskLine,
|
||||
RiGitBranchLine,
|
||||
RiHammerLine,
|
||||
RiPlayLine,
|
||||
RiRocketLine,
|
||||
RiRobot2Line,
|
||||
RiSearchLine,
|
||||
RiServerLine,
|
||||
RiSettings3Line,
|
||||
RiStackLine,
|
||||
RiTerminalBoxLine,
|
||||
RiToolsLine,
|
||||
} from '@remixicon/react';
|
||||
import type { ComponentType } from 'react';
|
||||
import type {
|
||||
OpenChamberProjectAction,
|
||||
OpenChamberProjectActionPlatform,
|
||||
@@ -27,6 +6,7 @@ import type {
|
||||
DesktopSshInstance,
|
||||
DesktopSshPortForward,
|
||||
} from '@/lib/desktopSsh';
|
||||
import type { IconName } from "@/components/icon/icons";
|
||||
|
||||
export type ProjectActionIconKey =
|
||||
| 'play'
|
||||
@@ -51,31 +31,31 @@ export type ProjectActionIconKey =
|
||||
export const PROJECT_ACTION_ICONS: Array<{
|
||||
key: ProjectActionIconKey;
|
||||
label: string;
|
||||
Icon: ComponentType<{ className?: string }>;
|
||||
Icon: IconName;
|
||||
}> = [
|
||||
{ key: 'play', label: 'Play', Icon: RiPlayLine },
|
||||
{ key: 'build', label: 'Build', Icon: RiHammerLine },
|
||||
{ key: 'lint', label: 'Lint', Icon: RiCheckboxCircleLine },
|
||||
{ key: 'terminal', label: 'Terminal', Icon: RiTerminalBoxLine },
|
||||
{ key: 'tools', label: 'Tools', Icon: RiToolsLine },
|
||||
{ key: 'bug', label: 'Bug', Icon: RiBugLine },
|
||||
{ key: 'flask', label: 'Flask', Icon: RiFlaskLine },
|
||||
{ key: 'rocket', label: 'Rocket', Icon: RiRocketLine },
|
||||
{ key: 'code', label: 'Code', Icon: RiCodeLine },
|
||||
{ key: 'server', label: 'Server', Icon: RiServerLine },
|
||||
{ key: 'branch', label: 'Branch', Icon: RiGitBranchLine },
|
||||
{ key: 'search', label: 'Search', Icon: RiSearchLine },
|
||||
{ key: 'settings', label: 'Settings', Icon: RiSettings3Line },
|
||||
{ key: 'brain', label: 'Brain', Icon: RiBrainAi3Line },
|
||||
{ key: 'stack', label: 'Stack', Icon: RiStackLine },
|
||||
{ key: 'robot', label: 'Robot', Icon: RiRobot2Line },
|
||||
{ key: 'command', label: 'Command', Icon: RiCommandLine },
|
||||
{ key: 'file', label: 'File', Icon: RiFileTextLine },
|
||||
{ key: 'play', label: 'Play', Icon: 'play' },
|
||||
{ key: 'build', label: 'Build', Icon: 'hammer' },
|
||||
{ key: 'lint', label: 'Lint', Icon: 'checkbox-circle' },
|
||||
{ key: 'terminal', label: 'Terminal', Icon: 'terminal-box' },
|
||||
{ key: 'tools', label: 'Tools', Icon: 'tools' },
|
||||
{ key: 'bug', label: 'Bug', Icon: 'bug' },
|
||||
{ key: 'flask', label: 'Flask', Icon: 'flask' },
|
||||
{ key: 'rocket', label: 'Rocket', Icon: 'rocket' },
|
||||
{ key: 'code', label: 'Code', Icon: 'code' },
|
||||
{ key: 'server', label: 'Server', Icon: 'server' },
|
||||
{ key: 'branch', label: 'Branch', Icon: 'git-branch' },
|
||||
{ key: 'search', label: 'Search', Icon: 'search' },
|
||||
{ key: 'settings', label: 'Settings', Icon: 'settings-3' },
|
||||
{ key: 'brain', label: 'Brain', Icon: 'brain-ai-3' },
|
||||
{ key: 'stack', label: 'Stack', Icon: 'stack' },
|
||||
{ key: 'robot', label: 'Robot', Icon: 'robot-2' },
|
||||
{ key: 'command', label: 'Command', Icon: 'command' },
|
||||
{ key: 'file', label: 'File', Icon: 'file-text' },
|
||||
];
|
||||
|
||||
export const PROJECT_ACTION_ICON_MAP = Object.fromEntries(
|
||||
PROJECT_ACTION_ICONS.map((entry) => [entry.key, entry.Icon])
|
||||
) as Record<ProjectActionIconKey, ComponentType<{ className?: string }>>;
|
||||
) as Record<ProjectActionIconKey, IconName>;
|
||||
|
||||
export const PROJECT_ACTIONS_UPDATED_EVENT = 'openchamber:project-actions-updated';
|
||||
|
||||
|
||||
@@ -1,52 +1,31 @@
|
||||
import {
|
||||
RiCodeBoxLine,
|
||||
RiTerminalBoxLine,
|
||||
RiRocketLine,
|
||||
RiFlaskLine,
|
||||
RiGamepadLine,
|
||||
RiBriefcaseLine,
|
||||
RiHomeLine,
|
||||
RiGlobalLine,
|
||||
RiLeafLine,
|
||||
RiShieldLine,
|
||||
RiPaletteLine,
|
||||
RiServerLine,
|
||||
RiSmartphoneLine,
|
||||
RiDatabase2Line,
|
||||
RiLightbulbLine,
|
||||
RiMusicLine,
|
||||
RiCameraLine,
|
||||
RiBookOpenLine,
|
||||
RiHeartLine,
|
||||
type RemixiconComponentType,
|
||||
} from '@remixicon/react';
|
||||
import type { ProjectEntry } from '@/lib/api/types';
|
||||
import type { IconName } from "@/components/icon/icons";
|
||||
|
||||
type ThemeVariant = 'light' | 'dark';
|
||||
|
||||
export const PROJECT_ICONS: Array<{ key: string; Icon: RemixiconComponentType; label: string }> = [
|
||||
{ key: 'code', Icon: RiCodeBoxLine, label: 'Code' },
|
||||
{ key: 'terminal', Icon: RiTerminalBoxLine, label: 'Terminal' },
|
||||
{ key: 'rocket', Icon: RiRocketLine, label: 'Rocket' },
|
||||
{ key: 'flask', Icon: RiFlaskLine, label: 'Lab' },
|
||||
{ key: 'gamepad', Icon: RiGamepadLine, label: 'Game' },
|
||||
{ key: 'briefcase', Icon: RiBriefcaseLine, label: 'Work' },
|
||||
{ key: 'home', Icon: RiHomeLine, label: 'Home' },
|
||||
{ key: 'globe', Icon: RiGlobalLine, label: 'Web' },
|
||||
{ key: 'leaf', Icon: RiLeafLine, label: 'Nature' },
|
||||
{ key: 'shield', Icon: RiShieldLine, label: 'Security' },
|
||||
{ key: 'palette', Icon: RiPaletteLine, label: 'Design' },
|
||||
{ key: 'server', Icon: RiServerLine, label: 'Server' },
|
||||
{ key: 'phone', Icon: RiSmartphoneLine, label: 'Mobile' },
|
||||
{ key: 'database', Icon: RiDatabase2Line, label: 'Data' },
|
||||
{ key: 'lightbulb', Icon: RiLightbulbLine, label: 'Idea' },
|
||||
{ key: 'music', Icon: RiMusicLine, label: 'Music' },
|
||||
{ key: 'camera', Icon: RiCameraLine, label: 'Media' },
|
||||
{ key: 'book', Icon: RiBookOpenLine, label: 'Docs' },
|
||||
{ key: 'heart', Icon: RiHeartLine, label: 'Favorite' },
|
||||
export const PROJECT_ICONS: Array<{ key: string; Icon: IconName; label: string }> = [
|
||||
{ key: 'code', Icon: 'code-box', label: 'Code' },
|
||||
{ key: 'terminal', Icon: 'terminal-box', label: 'Terminal' },
|
||||
{ key: 'rocket', Icon: 'rocket', label: 'Rocket' },
|
||||
{ key: 'flask', Icon: 'flask', label: 'Lab' },
|
||||
{ key: 'gamepad', Icon: 'gamepad', label: 'Game' },
|
||||
{ key: 'briefcase', Icon: 'briefcase', label: 'Work' },
|
||||
{ key: 'home', Icon: 'home', label: 'Home' },
|
||||
{ key: 'globe', Icon: 'global', label: 'Web' },
|
||||
{ key: 'leaf', Icon: 'leaf', label: 'Nature' },
|
||||
{ key: 'shield', Icon: 'shield', label: 'Security' },
|
||||
{ key: 'palette', Icon: 'palette', label: 'Design' },
|
||||
{ key: 'server', Icon: 'server', label: 'Server' },
|
||||
{ key: 'phone', Icon: 'smartphone', label: 'Mobile' },
|
||||
{ key: 'database', Icon: 'database-2', label: 'Data' },
|
||||
{ key: 'lightbulb', Icon: 'lightbulb', label: 'Idea' },
|
||||
{ key: 'music', Icon: 'music', label: 'Music' },
|
||||
{ key: 'camera', Icon: 'camera', label: 'Media' },
|
||||
{ key: 'book', Icon: 'book-open', label: 'Docs' },
|
||||
{ key: 'heart', Icon: 'heart', label: 'Favorite' },
|
||||
];
|
||||
|
||||
export const PROJECT_ICON_MAP: Record<string, RemixiconComponentType> = Object.fromEntries(
|
||||
export const PROJECT_ICON_MAP: Record<string, IconName> = Object.fromEntries(
|
||||
PROJECT_ICONS.map((i) => [i.key, i.Icon])
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user