diff --git a/src/shared/ui/badge/index.ts b/src/shared/ui/badge/index.ts new file mode 100644 index 0000000..0e1d9b6 --- /dev/null +++ b/src/shared/ui/badge/index.ts @@ -0,0 +1 @@ +export { Badge } from './ui/Badge' diff --git a/src/shared/ui/badge/ui/Badge.test.tsx b/src/shared/ui/badge/ui/Badge.test.tsx new file mode 100644 index 0000000..67f130c --- /dev/null +++ b/src/shared/ui/badge/ui/Badge.test.tsx @@ -0,0 +1,52 @@ +import { describe, it, expect } from 'vitest' +import { render, screen } from '@testing-library/react' +import { Badge } from './Badge' + +describe('Badge', () => { + describe('rendering', () => { + it('renders children', () => { + render(React) + expect(screen.getByText('React')).toBeInTheDocument() + }) + + it('renders as inline span', () => { + render(Tag) + expect(screen.getByText('Tag').tagName).toBe('SPAN') + }) + }) + + describe('variants', () => { + it('applies default variant classes', () => { + render(Tag) + const el = screen.getByText('Tag') + expect(el).toHaveClass('bg-carbon-black', 'text-ochre-clay') + }) + + it('applies primary variant classes', () => { + render(Tag) + expect(screen.getByText('Tag')).toHaveClass('bg-burnt-oxide') + }) + + it('applies secondary variant classes', () => { + render(Tag) + expect(screen.getByText('Tag')).toHaveClass('bg-slate-indigo') + }) + + it('applies outline variant classes', () => { + render(Tag) + expect(screen.getByText('Tag')).toHaveClass('bg-transparent') + }) + + it('defaults to default variant when unspecified', () => { + render(Tag) + expect(screen.getByText('Tag')).toHaveClass('bg-carbon-black') + }) + }) + + describe('className passthrough', () => { + it('merges custom className', () => { + render(Tag) + expect(screen.getByText('Tag')).toHaveClass('mt-4') + }) + }) +}) diff --git a/src/shared/ui/badge/ui/Badge.tsx b/src/shared/ui/badge/ui/Badge.tsx new file mode 100644 index 0000000..bea718c --- /dev/null +++ b/src/shared/ui/badge/ui/Badge.tsx @@ -0,0 +1,38 @@ +import type { ReactNode } from 'react' +import { cn } from '$shared/lib' + +type BadgeVariant = 'default' | 'primary' | 'secondary' | 'outline' + +interface Props { + /** + * Badge content + */ + children: ReactNode + /** + * Visual variant + * @default 'default' + */ + variant?: BadgeVariant + /** + * Additional CSS classes + */ + className?: string +} + +const VARIANTS: Record = { + default: 'brutal-border bg-carbon-black text-ochre-clay', + primary: 'brutal-border bg-burnt-oxide text-ochre-clay', + secondary: 'brutal-border bg-slate-indigo text-ochre-clay', + outline: 'brutal-border bg-transparent text-carbon-black', +} + +/** + * Small label for categorization or status. + */ +export function Badge({ children, variant = 'default', className }: Props) { + return ( + + {children} + + ) +}