import * as React from 'react'; import { cn } from '@/lib/utils'; import { cva, type VariantProps } from 'class-variance-authority'; import { Slot as SlotPrimitive } from 'radix-ui'; export interface BadgeProps extends React.HTMLAttributes, VariantProps { asChild?: boolean; dotClassName?: string; disabled?: boolean; } export interface BadgeButtonProps extends React.ButtonHTMLAttributes, VariantProps { asChild?: boolean; } export type BadgeDotProps = React.HTMLAttributes; const badgeVariants = cva( 'inline-flex items-center whitespace-nowrap justify-center border border-transparent font-medium focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 [&_svg]:-ms-px [&_svg]:shrink-0', { variants: { variant: { default: 'bg-primary text-primary-foreground', primary: 'bg-primary text-primary-foreground', secondary: 'bg-secondary text-secondary-foreground', success: 'bg-[var(--color-success-accent,var(--color-green-500))] text-[var(--color-success-foreground,var(--color-white))]', warning: 'bg-[var(--color-warning-accent,var(--color-yellow-500))] text-[var(--color-warning-foreground,var(--color-white))]', info: 'bg-[var(--color-info-accent,var(--color-violet-500))] text-[var(--color-info-foreground,var(--color-white))]', outline: 'bg-transparent border border-border text-secondary-foreground', destructive: 'bg-destructive text-[var(--color-destructive-foreground,var(--color-white))]', }, appearance: { default: '', light: '', outline: '', ghost: 'border-transparent bg-transparent', }, disabled: { true: 'opacity-50 pointer-events-none', }, size: { lg: 'rounded-md px-[0.5rem] h-7 min-w-7 gap-1.5 text-xs [&_svg]:size-3.5', md: 'rounded-md px-[0.45rem] h-6 min-w-6 gap-1.5 text-xs [&_svg]:size-3.5 ', sm: 'rounded-sm px-[0.325rem] h-5 min-w-5 gap-1 text-[0.6875rem] leading-[0.75rem] [&_svg]:size-3', xs: 'rounded-sm px-[0.25rem] h-4 min-w-4 gap-1 text-[0.625rem] leading-[0.5rem] [&_svg]:size-3', }, shape: { default: '', circle: 'rounded-full', }, }, compoundVariants: [ /* Light */ { variant: 'default', appearance: 'light', className: 'text-[var(--color-primary-accent,var(--color-blue-700))] bg-[var(--color-primary-soft,var(--color-blue-50))] dark:bg-[var(--color-primary-soft,var(--color-blue-950))] dark:text-[var(--color-primary-soft,var(--color-blue-600))]', }, { variant: 'primary', appearance: 'light', className: 'text-[var(--color-primary-accent,var(--color-blue-700))] bg-[var(--color-primary-soft,var(--color-blue-50))] dark:bg-[var(--color-primary-soft,var(--color-blue-950))] dark:text-[var(--color-primary-soft,var(--color-blue-600))]', }, { variant: 'secondary', appearance: 'light', className: 'bg-secondary dark:bg-secondary/50 text-secondary-foreground', }, { variant: 'success', appearance: 'light', className: 'text-[var(--color-success-accent,var(--color-green-800))] bg-[var(--color-success-soft,var(--color-green-100))] dark:bg-[var(--color-success-soft,var(--color-green-950))] dark:text-[var(--color-success-soft,var(--color-green-600))]', }, { variant: 'warning', appearance: 'light', className: 'text-[var(--color-warning-accent,var(--color-yellow-700))] bg-[var(--color-warning-soft,var(--color-yellow-100))] dark:bg-[var(--color-warning-soft,var(--color-yellow-950))] dark:text-[var(--color-warning-soft,var(--color-yellow-600))]', }, { variant: 'info', appearance: 'light', className: 'text-[var(--color-info-accent,var(--color-violet-700))] bg-[var(--color-info-soft,var(--color-violet-100))] dark:bg-[var(--color-info-soft,var(--color-violet-950))] dark:text-[var(--color-info-soft,var(--color-violet-400))]', }, { variant: 'destructive', appearance: 'light', className: 'text-[var(--color-destructive-accent,var(--color-red-700))] bg-[var(--color-destructive-soft,var(--color-red-50))] dark:bg-[var(--color-destructive-soft,var(--color-red-950))] dark:text-[var(--color-destructive-soft,var(--color-red-600))]', }, /* Outline */ { variant: 'default', appearance: 'outline', className: 'text-[var(--color-primary-accent,var(--color-blue-700))] border-[var(--color-primary-soft,var(--color-blue-100))] bg-[var(--color-primary-soft,var(--color-blue-50))] dark:bg-[var(--color-primary-soft,var(--color-blue-950))] dark:border-[var(--color-primary-soft,var(--color-blue-900))] dark:text-[var(--color-primary-soft,var(--color-blue-600))]', }, { variant: 'primary', appearance: 'outline', className: 'text-[var(--color-primary-accent,var(--color-blue-700))] border-[var(--color-primary-soft,var(--color-blue-100))] bg-[var(--color-primary-soft,var(--color-blue-50))] dark:bg-[var(--color-primary-soft,var(--color-blue-950))] dark:border-[var(--color-primary-soft,var(--color-blue-900))] dark:text-[var(--color-primary-soft,var(--color-blue-600))]', }, { variant: 'success', appearance: 'outline', className: 'text-[var(--color-success-accent,var(--color-green-700))] border-[var(--color-success-soft,var(--color-green-200))] bg-[var(--color-success-soft,var(--color-green-50))] dark:bg-[var(--color-success-soft,var(--color-green-950))] dark:border-[var(--color-success-soft,var(--color-green-900))] dark:text-[var(--color-success-soft,var(--color-green-600))]', }, { variant: 'warning', appearance: 'outline', className: 'text-[var(--color-warning-accent,var(--color-yellow-700))] border-[var(--color-warning-soft,var(--color-yellow-200))] bg-[var(--color-warning-soft,var(--color-yellow-50))] dark:bg-[var(--color-warning-soft,var(--color-yellow-950))] dark:border-[var(--color-warning-soft,var(--color-yellow-900))] dark:text-[var(--color-warning-soft,var(--color-yellow-600))]', }, { variant: 'info', appearance: 'outline', className: 'text-[var(--color-info-accent,var(--color-violet-700))] border-[var(--color-info-soft,var(--color-violet-100))] bg-[var(--color-info-soft,var(--color-violet-50))] dark:bg-[var(--color-info-soft,var(--color-violet-950))] dark:border-[var(--color-info-soft,var(--color-violet-900))] dark:text-[var(--color-info-soft,var(--color-violet-400))]', }, { variant: 'destructive', appearance: 'outline', className: 'text-[var(--color-destructive-accent,var(--color-red-700))] border-[var(--color-destructive-soft,var(--color-red-100))] bg-[var(--color-destructive-soft,var(--color-red-50))] dark:bg-[var(--color-destructive-soft,var(--color-red-950))] dark:border-[var(--color-destructive-soft,var(--color-red-900))] dark:text-[var(--color-destructive-soft,var(--color-red-600))]', }, /* Ghost */ { variant: 'default', appearance: 'ghost', className: 'text-primary', }, { variant: 'primary', appearance: 'ghost', className: 'text-primary', }, { variant: 'secondary', appearance: 'ghost', className: 'text-secondary-foreground', }, { variant: 'success', appearance: 'ghost', className: 'text-[var(--color-success-accent,var(--color-green-500))]', }, { variant: 'warning', appearance: 'ghost', className: 'text-[var(--color-warning-accent,var(--color-yellow-500))]', }, { variant: 'info', appearance: 'ghost', className: 'text-[var(--color-info-accent,var(--color-violet-500))]', }, { variant: 'destructive', appearance: 'ghost', className: 'text-destructive', }, { size: 'lg', appearance: 'ghost', className: 'px-0' }, { size: 'md', appearance: 'ghost', className: 'px-0' }, { size: 'sm', appearance: 'ghost', className: 'px-0' }, { size: 'xs', appearance: 'ghost', className: 'px-0' }, ], defaultVariants: { variant: 'primary', appearance: 'default', size: 'md', }, }, ); const badgeButtonVariants = cva( 'cursor-pointer transition-all inline-flex items-center justify-center leading-none size-3.5 [&>svg]:opacity-100! [&>svg]:size-3.5! p-0 rounded-md -me-0.5 opacity-60 hover:opacity-100', { variants: { variant: { default: '', }, }, defaultVariants: { variant: 'default', }, }, ); function Badge({ className, variant, size, appearance, shape, asChild = false, disabled, ...props }: React.ComponentProps<'span'> & VariantProps & { asChild?: boolean }) { const Comp = asChild ? SlotPrimitive.Slot : 'span'; return ( ); } function BadgeButton({ className, variant, asChild = false, ...props }: React.ComponentProps<'button'> & VariantProps & { asChild?: boolean }) { const Comp = asChild ? SlotPrimitive.Slot : 'span'; return ( ); } function BadgeDot({ className, ...props }: React.ComponentProps<'span'>) { return ( ); } export { Badge, BadgeButton, BadgeDot, badgeVariants };