feat(11-04): create GroupBadge component
- Built-in variant: Badge secondary, no dismiss, hover:bg-accent/30 - Custom variant: Badge outline, X dismiss button with spinner, hover:bg-accent/50 - Tooltip on both variants showing name · built-in · N skills or name · N skills - text-sm font-semibold typography per UI-SPEC (no font-bold or font-medium)
This commit is contained in:
parent
37476870a2
commit
609c5b30b7
1 changed files with 82 additions and 0 deletions
82
ui/src/components/GroupBadge.tsx
Normal file
82
ui/src/components/GroupBadge.tsx
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { X, Loader2 } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type GroupBadgeProps = {
|
||||
name: string;
|
||||
isBuiltin: boolean;
|
||||
skillCount?: number;
|
||||
description?: string | null;
|
||||
onRemove?: () => void;
|
||||
removing?: boolean;
|
||||
};
|
||||
|
||||
export function GroupBadge({
|
||||
name,
|
||||
isBuiltin,
|
||||
skillCount,
|
||||
description: _description,
|
||||
onRemove,
|
||||
removing = false,
|
||||
}: GroupBadgeProps) {
|
||||
const tooltipText = isBuiltin
|
||||
? `${name} · built-in${skillCount != null ? ` · ${skillCount} skills` : ""}`
|
||||
: `${name}${skillCount != null ? ` · ${skillCount} skills` : ""}`;
|
||||
|
||||
if (isBuiltin) {
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className={cn(
|
||||
"cursor-default select-none text-sm font-semibold",
|
||||
"hover:bg-accent/30",
|
||||
"focus-visible:ring-ring focus-visible:ring-[3px]",
|
||||
)}
|
||||
>
|
||||
{name}
|
||||
</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top">{tooltipText}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"cursor-default select-none gap-1 text-sm font-semibold",
|
||||
"hover:bg-accent/50",
|
||||
"focus-visible:ring-ring focus-visible:ring-[3px]",
|
||||
)}
|
||||
>
|
||||
{name}
|
||||
{onRemove && (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`Remove ${name}`}
|
||||
disabled={removing}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onRemove();
|
||||
}}
|
||||
className="ml-0.5 rounded-full p-0.5 transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{removing ? (
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
) : (
|
||||
<X className="h-3 w-3" />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top">{tooltipText}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue