80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
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>
|
|
);
|
|
}
|