| import { useState, useMemo } from "react"; |
| import { |
| type LucideIcon, |
| } from "lucide-react"; |
| import { AGENT_ICON_NAMES, type AgentIconName } from "@paperclipai/shared"; |
| import { |
| Popover, |
| PopoverContent, |
| PopoverTrigger, |
| } from "@/components/ui/popover"; |
| import { Input } from "@/components/ui/input"; |
| import { cn } from "@/lib/utils"; |
| import { AGENT_ICONS, getAgentIcon } from "../lib/agent-icons"; |
|
|
| const DEFAULT_ICON: AgentIconName = "bot"; |
|
|
| interface AgentIconProps { |
| icon: string | null | undefined; |
| className?: string; |
| } |
|
|
| export function AgentIcon({ icon, className }: AgentIconProps) { |
| const Icon = getAgentIcon(icon); |
| return <Icon className={className} />; |
| } |
|
|
| interface AgentIconPickerProps { |
| value: string | null | undefined; |
| onChange: (icon: string) => void; |
| children: React.ReactNode; |
| } |
|
|
| export function AgentIconPicker({ value, onChange, children }: AgentIconPickerProps) { |
| const [open, setOpen] = useState(false); |
| const [search, setSearch] = useState(""); |
|
|
| const filtered = useMemo(() => { |
| const entries = AGENT_ICON_NAMES.map((name) => [name, AGENT_ICONS[name]] as const); |
| if (!search) return entries; |
| const q = search.toLowerCase(); |
| return entries.filter(([name]) => name.includes(q)); |
| }, [search]); |
|
|
| return ( |
| <Popover open={open} onOpenChange={setOpen}> |
| <PopoverTrigger asChild>{children}</PopoverTrigger> |
| <PopoverContent className="w-72 p-3" align="start"> |
| <Input |
| placeholder="Search icons..." |
| value={search} |
| onChange={(e) => setSearch(e.target.value)} |
| className="mb-2 h-8 text-sm" |
| autoFocus |
| /> |
| <div className="grid grid-cols-7 gap-1 max-h-48 overflow-y-auto"> |
| {filtered.map(([name, Icon]) => ( |
| <button |
| key={name} |
| onClick={() => { |
| onChange(name); |
| setOpen(false); |
| setSearch(""); |
| }} |
| className={cn( |
| "flex items-center justify-center h-8 w-8 rounded hover:bg-accent transition-colors", |
| (value ?? DEFAULT_ICON) === name && "bg-accent ring-1 ring-primary" |
| )} |
| title={name} |
| > |
| <Icon className="h-4 w-4" /> |
| </button> |
| ))} |
| {filtered.length === 0 && ( |
| <p className="col-span-7 text-xs text-muted-foreground text-center py-2">No icons match</p> |
| )} |
| </div> |
| </PopoverContent> |
| </Popover> |
| ); |
| } |
|
|