{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "points-badge",
  "title": "Points Badge",
  "description": "Compact React points badge for totals and currency-style scores in gamification UIs. Fits XP-style displays alongside charts and lists. Built on shadcn/ui + Tailwind. Open source.",
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/trophy/ui/points-badge.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Sparkle } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst pointsBadgeVariants = cva(\n  \"flex items-center gap-3 rounded-lg transition-colors\",\n  {\n    variants: {\n      size: {\n        sm: \"text-sm gap-2\",\n        default: \"\",\n        lg: \"text-lg gap-4\",\n      },\n    },\n    defaultVariants: {\n      size: \"default\",\n    },\n  }\n)\n\ninterface PointsBadgeProps\n  extends\n    React.HTMLAttributes<HTMLDivElement>,\n    VariantProps<typeof pointsBadgeVariants> {\n  name: string\n  total: number\n  /** When omitted or `null`, the default icon is shown instead of an image. */\n  badgeUrl?: string | null\n  icon?: React.ComponentType<{ className?: string }>\n  formatValue?: (value: number) => string\n}\n\nconst PointsBadge = React.forwardRef<HTMLDivElement, PointsBadgeProps>(\n  (\n    {\n      className,\n      size,\n      name,\n      badgeUrl,\n      total,\n      icon: CustomIcon,\n      formatValue,\n      ...props\n    },\n    ref\n  ) => {\n    const Icon = CustomIcon ?? Sparkle\n    const displayValue = formatValue\n      ? formatValue(total)\n      : total.toLocaleString()\n\n    const iconSize = {\n      sm: \"h-4 w-4\",\n      default: \"h-5 w-5\",\n      lg: \"h-6 w-6\",\n    }[size ?? \"default\"]\n\n    const badgeSize = {\n      sm: \"h-6 w-6\",\n      default: \"h-8 w-8\",\n      lg: \"h-10 w-10\",\n    }[size ?? \"default\"]\n    const statusLabel = `${displayValue} ${name}`\n\n    return (\n      <div\n        ref={ref}\n        role=\"status\"\n        aria-label={statusLabel}\n        className={cn(\n          pointsBadgeVariants({ size }),\n          \"bg-card border p-4\",\n          className\n        )}\n        {...props}\n      >\n        <div className=\"flex items-center gap-2\">\n          {badgeUrl ? (\n            <div>\n              <img\n                src={badgeUrl}\n                alt=\"\"\n                aria-hidden=\"true\"\n                className={cn(\"shrink-0 rounded object-contain\", badgeSize)}\n              />\n            </div>\n          ) : (\n            <div\n              aria-hidden=\"true\"\n              className={cn(\n                \"bg-primary/10 flex shrink-0 items-center justify-center rounded-full\",\n                badgeSize\n              )}\n            >\n              <Icon className={cn(iconSize, \"text-primary\")} />\n            </div>\n          )}\n\n          <div>\n            <span\n              className={cn(\n                \"font-bold tabular-nums\",\n                size === \"lg\" && \"text-2xl\",\n                size === \"sm\" && \"text-base\",\n                size === \"default\" && \"text-xl\"\n              )}\n            >\n              {displayValue}\n            </span>\n          </div>\n        </div>\n\n        <div>\n          <span className=\"text-muted-foreground truncate\">{name}</span>\n        </div>\n      </div>\n    )\n  }\n)\nPointsBadge.displayName = \"PointsBadge\"\n\nexport { PointsBadge, pointsBadgeVariants }\nexport type { PointsBadgeProps }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}