veza/apps/web/desy/components/ui/badge.tsx
2026-01-22 17:23:11 +01:00

112 lines
2.9 KiB
TypeScript

import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const badgeVariants = cva(
'inline-flex items-center justify-center rounded-sm border px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1.5 [&>svg]:pointer-events-none transition-all overflow-hidden font-mono',
{
variants: {
variant: {
// Default: Primary cyan
default:
'border-transparent bg-primary/15 text-primary',
// Secondary: Magenta
secondary:
'border-transparent bg-secondary/15 text-secondary',
// Success: Lime green
success:
'border-transparent bg-success/15 text-success',
// Warning: Amber
warning:
'border-transparent bg-warning/15 text-warning',
// Destructive: Error red
destructive:
'border-transparent bg-destructive/15 text-destructive',
// Info: Sky blue
info:
'border-transparent bg-info/15 text-info',
// Outline: Bordered
outline:
'border-border text-muted-foreground bg-transparent',
// Muted: Subtle
muted:
'border-transparent bg-muted text-muted-foreground',
// Gaming: XP Gold style
gaming:
'border-[oklch(0.88_0.16_85)] bg-[oklch(0.88_0.16_85_/_0.1)] text-[oklch(0.88_0.16_85)] shadow-[0_0_5px_oklch(0.88_0.16_85_/_0.3)]',
// Nature: Organic green
nature:
'border-[oklch(0.55_0.12_145)] bg-[oklch(0.55_0.12_145_/_0.1)] text-[oklch(0.55_0.12_145)]',
// Live: Pulsing indicator
live:
'border-destructive bg-destructive/15 text-destructive animate-pulse',
// Premium: Gradient
premium:
'border-transparent bg-gradient-to-r from-primary/20 to-secondary/20 text-foreground',
},
size: {
default: 'h-5 text-[10px]',
sm: 'h-4 text-[9px] px-1.5',
lg: 'h-6 text-xs px-2.5',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
},
)
interface BadgeProps
extends React.ComponentProps<'span'>,
VariantProps<typeof badgeVariants> {
asChild?: boolean
dot?: boolean
pulse?: boolean
}
function Badge({
className,
variant,
size,
asChild = false,
dot = false,
pulse = false,
children,
...props
}: BadgeProps) {
const Comp = asChild ? Slot : 'span'
return (
<Comp
data-slot="badge"
className={cn(badgeVariants({ variant, size }), className)}
{...props}
>
{dot && (
<span
className={cn(
'size-1.5 rounded-full bg-current',
pulse && 'animate-pulse'
)}
/>
)}
{children}
</Comp>
)
}
export { Badge, badgeVariants }