Skip to content
This repository was archived by the owner on Jul 20, 2025. It is now read-only.

Commit 636c00a

Browse files
feat: add badge (#130)
* feat: add badge * fix: resolve comments
1 parent a2c9ef6 commit 636c00a

File tree

5 files changed

+143
-0
lines changed

5 files changed

+143
-0
lines changed

src/components/Badge/Badge.css

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
.bbn-badge {
2+
@apply relative inline-flex;
3+
4+
&-indicator {
5+
@apply absolute z-10 flex items-center justify-center;
6+
@apply min-w-5 h-5 px-1 rounded-full;
7+
@apply text-xs font-medium leading-none text-white;
8+
9+
/* Position variants */
10+
&.bbn-badge-top-right {
11+
@apply top-0 right-0 translate-x-1/4 -translate-y-1/4;
12+
}
13+
14+
&.bbn-badge-top-left {
15+
@apply top-0 left-0 -translate-x-1/4 -translate-y-1/4;
16+
}
17+
18+
&.bbn-badge-bottom-right {
19+
@apply bottom-0 right-0 translate-x-1/4 translate-y-1/4;
20+
}
21+
22+
&.bbn-badge-bottom-left {
23+
@apply bottom-0 left-0 -translate-x-1/4 translate-y-1/4;
24+
}
25+
26+
/* Color variants */
27+
&.bbn-badge-primary {
28+
@apply bg-primary-main;
29+
}
30+
31+
&.bbn-badge-secondary {
32+
@apply bg-secondary-main;
33+
}
34+
35+
&.bbn-badge-error {
36+
@apply bg-error-main;
37+
}
38+
39+
&.bbn-badge-warning {
40+
@apply bg-warning-main;
41+
}
42+
43+
&.bbn-badge-info {
44+
@apply bg-info-main;
45+
}
46+
47+
&.bbn-badge-success {
48+
@apply bg-success-main;
49+
}
50+
}
51+
52+
&-content {
53+
@apply flex items-center justify-center;
54+
}
55+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { Badge } from "./Badge";
3+
import { Avatar } from "../Avatar/Avatar";
4+
5+
const meta: Meta<typeof Badge> = {
6+
component: Badge,
7+
tags: ["autodocs"],
8+
parameters: {
9+
layout: "centered",
10+
},
11+
};
12+
13+
export default meta;
14+
type Story = StoryObj<typeof meta>;
15+
16+
export const WithWhiteBorder: Story = {
17+
render: () => (
18+
<div className="rounded bg-gray-200 p-8">
19+
<Badge count={1} position="bottom-right" color="secondary" badgeClassName="border-2 border-white">
20+
<Avatar url="/images/fps/lombard.jpeg" alt="Lombard" size="large" />
21+
</Badge>
22+
</div>
23+
),
24+
};

src/components/Badge/Badge.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import type { PropsWithChildren, ReactNode } from "react";
2+
import { twJoin } from "tailwind-merge";
3+
import "./Badge.css";
4+
5+
export interface BadgeProps extends PropsWithChildren {
6+
/**
7+
* The number or content to display in the badge
8+
*/
9+
count?: number | ReactNode;
10+
/**
11+
* Max count to show. If count is greater than max, show max+
12+
*/
13+
max?: number;
14+
/**
15+
* The position of the badge
16+
*/
17+
position?: "top-right" | "top-left" | "bottom-right" | "bottom-left";
18+
/**
19+
* The color of the badge
20+
*/
21+
color?: "primary" | "secondary" | "error" | "warning" | "info" | "success";
22+
/**
23+
* Additional CSS class for the badge wrapper
24+
*/
25+
className?: string;
26+
/**
27+
* Additional CSS class for the badge indicator
28+
*/
29+
badgeClassName?: string;
30+
/**
31+
* Additional CSS class for the badge content
32+
*/
33+
contentClassName?: string;
34+
}
35+
36+
export function Badge({
37+
children,
38+
count = 0,
39+
max = 99,
40+
position = "bottom-right",
41+
color = "error",
42+
className,
43+
badgeClassName,
44+
contentClassName,
45+
}: BadgeProps) {
46+
const shouldShow = typeof count === "number" ? count > 0 : count != null;
47+
const displayValue = typeof count === "number" && count > max ? `${max}+` : count;
48+
49+
const positionClass = `bbn-badge-${position}`;
50+
const colorClass = `bbn-badge-${color}`;
51+
52+
return (
53+
<div className={twJoin("bbn-badge", className)}>
54+
{children}
55+
{shouldShow && (
56+
<span className={twJoin("bbn-badge-indicator", positionClass, colorClass, badgeClassName)}>
57+
<span className={twJoin("bbn-badge-content", contentClassName)}>{displayValue}</span>
58+
</span>
59+
)}
60+
</div>
61+
);
62+
}

src/components/Badge/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./Badge";

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export * from "./components/Popover";
1515
export * from "./components/Card";
1616
export * from "./components/Toggle";
1717
export * from "./components/List";
18+
export * from "./components/Badge";
1819

1920
export * from "./widgets/form/Form";
2021
export * from "./widgets/form/NumberField";

0 commit comments

Comments
 (0)