- Create ChatMentionPopover (200px, opens upward, agent icon + name + role label) - Agents filtered by query, max 5 visible, No agents found empty state - 3 skeleton rows loading state, onOpenAutoFocus prevented for textarea focus - Include agent-role-colors dependency for worktree build
73 lines
2.5 KiB
TypeScript
73 lines
2.5 KiB
TypeScript
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
import { AgentIcon } from "./AgentIconPicker";
|
|
import { agentRoleColors, agentRoleColorDefault } from "../lib/agent-role-colors";
|
|
import type { Agent, AgentRole } from "@paperclipai/shared";
|
|
|
|
interface ChatMentionPopoverProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
onSelect: (agentName: string) => void;
|
|
query: string;
|
|
agents: Agent[];
|
|
isLoading?: boolean;
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export function ChatMentionPopover({
|
|
open,
|
|
onOpenChange,
|
|
onSelect,
|
|
query,
|
|
agents,
|
|
isLoading,
|
|
children,
|
|
}: ChatMentionPopoverProps) {
|
|
const filtered = agents.filter((a) =>
|
|
a.name.toLowerCase().includes(query.toLowerCase()),
|
|
);
|
|
|
|
return (
|
|
<Popover open={open} onOpenChange={onOpenChange}>
|
|
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
|
<PopoverContent
|
|
className="w-[200px] p-1"
|
|
align="start"
|
|
side="top"
|
|
onOpenAutoFocus={(e) => e.preventDefault()}
|
|
>
|
|
{isLoading ? (
|
|
<div className="space-y-1 p-1">
|
|
<Skeleton className="h-7 w-full" />
|
|
<Skeleton className="h-7 w-full" />
|
|
<Skeleton className="h-7 w-full" />
|
|
</div>
|
|
) : filtered.length === 0 ? (
|
|
<p className="text-sm text-muted-foreground text-center py-2">No agents found</p>
|
|
) : (
|
|
<div className="max-h-[180px] overflow-auto">
|
|
{filtered.slice(0, 5).map((agent) => {
|
|
const colorClass = agent.role
|
|
? (agentRoleColors[agent.role as AgentRole] ?? agentRoleColorDefault)
|
|
: agentRoleColorDefault;
|
|
return (
|
|
<button
|
|
key={agent.id}
|
|
className="flex items-center gap-2 w-full rounded-sm px-2 py-1.5 text-left text-sm hover:bg-accent hover:text-accent-foreground cursor-pointer"
|
|
onClick={() => {
|
|
onSelect(agent.name);
|
|
onOpenChange(false);
|
|
}}
|
|
>
|
|
<AgentIcon icon={agent.icon} className={`h-3.5 w-3.5 ${colorClass}`} />
|
|
<span className="truncate">{agent.name}</span>
|
|
<span className="ml-auto text-[11px] text-muted-foreground">{agent.role}</span>
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
}
|