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