Files
PaperClipAI/ui/src/lib/project-icons.ts
T
scotttongandClaude Opus 4.8 ee196badee PAP-70: project icon infra + ProjectTile renderer + picker (PAP-68 part 3)
Adds the project icon system mirroring the agent icon pattern:

- shared: PROJECT_ICON_NAMES + ProjectIconName (default "folder", curated
  Lucide set), exported from index; tighten project validator icon field
  from loose string to z.enum(PROJECT_ICON_NAMES).
- ui: project-icons.ts (PROJECT_ICONS map + getProjectIcon defaulting to
  folder) and ProjectIconPicker (Popover + search + grid), mirroring the
  agent equivalents.
- ProjectTile gains an optional `icon` prop, rendering getProjectIcon(icon)
  instead of a hard-coded Folder (default unchanged). Color behavior intact.
- Pass icon={project.icon ?? null} at all three tile sites: Projects list,
  SidebarProjects, and the detail header (threaded through ColorPicker).
- Tests: ProjectTile renders chosen icon / falls back to folder for unknown.
- Backfill required Project.icon on test/storybook fixtures left un-updated
  by part 1, restoring a green UI typecheck.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 15:18:54 -07:00

95 lines
1.6 KiB
TypeScript

import {
Atom,
Box,
Boxes,
Brain,
Briefcase,
Bug,
Code,
Cog,
Compass,
Cpu,
Crown,
Database,
FileCode,
Flame,
Folder,
Gem,
GitBranch,
Globe,
Hammer,
Heart,
Hexagon,
Layers,
Lightbulb,
Lock,
Mail,
MessageSquare,
Package,
Puzzle,
Radar,
Rocket,
Search,
Shield,
Sparkles,
Star,
Target,
Telescope,
Terminal,
Wrench,
Zap,
type LucideIcon,
} from "lucide-react";
import { PROJECT_ICON_NAMES, type ProjectIconName } from "@paperclipai/shared";
export const PROJECT_ICONS: Record<ProjectIconName, LucideIcon> = {
folder: Folder,
rocket: Rocket,
code: Code,
terminal: Terminal,
database: Database,
globe: Globe,
package: Package,
boxes: Boxes,
box: Box,
layers: Layers,
briefcase: Briefcase,
compass: Compass,
target: Target,
flame: Flame,
zap: Zap,
star: Star,
bug: Bug,
wrench: Wrench,
hammer: Hammer,
lightbulb: Lightbulb,
sparkles: Sparkles,
shield: Shield,
lock: Lock,
search: Search,
cog: Cog,
brain: Brain,
cpu: Cpu,
"git-branch": GitBranch,
"file-code": FileCode,
puzzle: Puzzle,
gem: Gem,
atom: Atom,
heart: Heart,
mail: Mail,
"message-square": MessageSquare,
crown: Crown,
radar: Radar,
telescope: Telescope,
hexagon: Hexagon,
};
const DEFAULT_ICON: ProjectIconName = "folder";
export function getProjectIcon(iconName: string | null | undefined): LucideIcon {
if (iconName && PROJECT_ICON_NAMES.includes(iconName as ProjectIconName)) {
return PROJECT_ICONS[iconName as ProjectIconName];
}
return PROJECT_ICONS[DEFAULT_ICON];
}