feat: Badge size prop (sm/md) and use Badge in ExperienceCard
This commit is contained in:
@@ -64,10 +64,10 @@ describe('ExperienceCard', () => {
|
|||||||
expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('Senior Developer');
|
expect(screen.getByRole('heading', { level: 3 })).toHaveTextContent('Senior Developer');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('period badge has brutal-border, bg-blue, text-cream, text-sm', () => {
|
it('period badge has brutal-border, bg-blue, text-cream, md size', () => {
|
||||||
render(<ExperienceCard {...DEFAULT_PROPS} />);
|
render(<ExperienceCard {...DEFAULT_PROPS} />);
|
||||||
const badge = screen.getByText('2021 – 2024');
|
const badge = screen.getByText('2021 – 2024');
|
||||||
expect(badge).toHaveClass('brutal-border', 'bg-blue', 'text-cream', 'text-sm');
|
expect(badge).toHaveClass('brutal-border', 'bg-blue', 'text-cream', 'px-4', 'py-2', 'text-sm');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('description renders via RichText with rich-text class', () => {
|
it('description renders via RichText with rich-text class', () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Card, CardSidebar, CardTitle, RichText } from '$shared/ui';
|
import { Badge, Card, CardSidebar, CardTitle, RichText } from '$shared/ui';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
/**
|
/**
|
||||||
@@ -10,7 +10,7 @@ type Props = {
|
|||||||
*/
|
*/
|
||||||
company: string;
|
company: string;
|
||||||
/**
|
/**
|
||||||
* Employment period (e.g. "2021 – 2024")
|
* Employment period (e.g. "Jan 2021 – Dec 2024")
|
||||||
*/
|
*/
|
||||||
period: string;
|
period: string;
|
||||||
/**
|
/**
|
||||||
@@ -38,17 +38,14 @@ export function ExperienceCard({ title, company, period, description, stack, cla
|
|||||||
<CardSidebar
|
<CardSidebar
|
||||||
sidebar={
|
sidebar={
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<span className="brutal-border px-4 py-2 bg-blue text-cream text-sm self-start">{period}</span>
|
<Badge size="md">{period}</Badge>
|
||||||
<p className="text-base font-medium">{company}</p>
|
<p className="text-base font-medium">{company}</p>
|
||||||
{stack.length > 0 && (
|
{stack.length > 0 && (
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{stack.map((tech) => (
|
{stack.map((tech) => (
|
||||||
<span
|
<Badge key={tech} variant="outline">
|
||||||
key={tech}
|
|
||||||
className="brutal-border px-3 py-1 bg-cream text-blue text-sm uppercase tracking-wide"
|
|
||||||
>
|
|
||||||
{tech}
|
{tech}
|
||||||
</span>
|
</Badge>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export type { BadgeVariant } from './ui/Badge';
|
export type { BadgeSize, BadgeVariant } from './ui/Badge';
|
||||||
export { Badge } from './ui/Badge';
|
export { Badge } from './ui/Badge';
|
||||||
|
|||||||
@@ -42,6 +42,23 @@ describe('Badge', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('sizes', () => {
|
||||||
|
it('defaults to sm size', () => {
|
||||||
|
render(<Badge>Tag</Badge>);
|
||||||
|
expect(screen.getByText('Tag')).toHaveClass('px-3', 'py-1', 'text-xs');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies sm size classes', () => {
|
||||||
|
render(<Badge size="sm">Tag</Badge>);
|
||||||
|
expect(screen.getByText('Tag')).toHaveClass('px-3', 'py-1', 'text-xs');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies md size classes', () => {
|
||||||
|
render(<Badge size="md">Tag</Badge>);
|
||||||
|
expect(screen.getByText('Tag')).toHaveClass('px-4', 'py-2', 'text-sm');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('className passthrough', () => {
|
describe('className passthrough', () => {
|
||||||
it('merges custom className', () => {
|
it('merges custom className', () => {
|
||||||
render(<Badge className="mt-4">Tag</Badge>);
|
render(<Badge className="mt-4">Tag</Badge>);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { ReactNode } from 'react';
|
|||||||
import { cn } from '$shared/lib';
|
import { cn } from '$shared/lib';
|
||||||
|
|
||||||
export type BadgeVariant = 'default' | 'primary' | 'secondary' | 'outline';
|
export type BadgeVariant = 'default' | 'primary' | 'secondary' | 'outline';
|
||||||
|
export type BadgeSize = 'sm' | 'md';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
@@ -13,6 +14,11 @@ interface Props {
|
|||||||
* @default 'default'
|
* @default 'default'
|
||||||
*/
|
*/
|
||||||
variant?: BadgeVariant;
|
variant?: BadgeVariant;
|
||||||
|
/**
|
||||||
|
* Size preset
|
||||||
|
* @default 'sm'
|
||||||
|
*/
|
||||||
|
size?: BadgeSize;
|
||||||
/**
|
/**
|
||||||
* Additional CSS classes
|
* Additional CSS classes
|
||||||
*/
|
*/
|
||||||
@@ -26,12 +32,17 @@ const VARIANTS: Record<BadgeVariant, string> = {
|
|||||||
outline: 'brutal-border bg-transparent text-blue',
|
outline: 'brutal-border bg-transparent text-blue',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SIZES: Record<BadgeSize, string> = {
|
||||||
|
sm: 'px-3 py-1 text-xs',
|
||||||
|
md: 'px-4 py-2 text-sm',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Small label for categorization or status.
|
* Small label for categorization or status.
|
||||||
*/
|
*/
|
||||||
export function Badge({ children, variant = 'default', className }: Props) {
|
export function Badge({ children, variant = 'default', size = 'sm', className }: Props) {
|
||||||
return (
|
return (
|
||||||
<span className={cn('inline-block px-3 py-1 text-xs uppercase tracking-wider', VARIANTS[variant], className)}>
|
<span className={cn('inline-block uppercase tracking-wider', SIZES[size], VARIANTS[variant], className)}>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export type { BadgeVariant } from './Badge';
|
export type { BadgeSize, BadgeVariant } from './Badge';
|
||||||
export { Badge } from './Badge';
|
export { Badge } from './Badge';
|
||||||
export type { ButtonSize, ButtonVariant } from './Button';
|
export type { ButtonSize, ButtonVariant } from './Button';
|
||||||
export { Button } from './Button';
|
export { Button } from './Button';
|
||||||
|
|||||||
Reference in New Issue
Block a user