mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
feat(frontend): add Badge component (#10244)
## Changes 🏗️ <img width="800" alt="Screenshot 2025-06-25 at 20 34 38" src="https://github.com/user-attachments/assets/bfc90504-85b6-4178-9ace-2aa4d14f16b0" /> <br /><br /> - To match what is on the AutoGPT design system - Unit tests commented because they depend on: https://github.com/Significant-Gravitas/AutoGPT/pull/10243 ## Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Run Storybook locally, Badge stories look good
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { Badge } from "./Badge";
|
||||
|
||||
const meta: Meta<typeof Badge> = {
|
||||
title: "Atoms/Badge",
|
||||
tags: ["autodocs"],
|
||||
component: Badge,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Badge component for displaying status information with different variants for success, error, and info states.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: "select",
|
||||
options: ["success", "error", "info"],
|
||||
description: "Badge variant that determines color scheme",
|
||||
},
|
||||
children: {
|
||||
control: "text",
|
||||
description: "Badge content",
|
||||
},
|
||||
className: {
|
||||
control: "text",
|
||||
description: "Additional CSS classes",
|
||||
},
|
||||
},
|
||||
args: {
|
||||
variant: "success",
|
||||
children: "Success",
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Success: Story = {
|
||||
args: {
|
||||
variant: "success",
|
||||
children: "Success",
|
||||
},
|
||||
};
|
||||
|
||||
export const Error: Story = {
|
||||
args: {
|
||||
variant: "error",
|
||||
children: "Failed",
|
||||
},
|
||||
};
|
||||
|
||||
export const Info: Story = {
|
||||
args: {
|
||||
variant: "info",
|
||||
children: "Stopped",
|
||||
},
|
||||
};
|
||||
|
||||
export const AllVariants: Story = {
|
||||
render: renderAllVariants,
|
||||
};
|
||||
|
||||
function renderAllVariants() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<Badge variant="success">Success</Badge>
|
||||
<Badge variant="error">Failed</Badge>
|
||||
<Badge variant="info">Stopped</Badge>
|
||||
<Badge variant="info">Running</Badge>
|
||||
<Badge variant="success">Completed</Badge>
|
||||
<Badge variant="error">Error</Badge>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// import { render, screen } from "@testing-library/react";
|
||||
// import { describe, expect, it } from "vitest";
|
||||
// import { Badge } from "./Badge";
|
||||
|
||||
// describe("Badge Component", () => {
|
||||
// it("renders badge with content", () => {
|
||||
// render(<Badge variant="success">Success</Badge>);
|
||||
|
||||
// expect(screen.getByText("Success")).toBeInTheDocument();
|
||||
// });
|
||||
|
||||
// it("applies correct variant styles", () => {
|
||||
// const { rerender } = render(<Badge variant="success">Success</Badge>);
|
||||
// let badge = screen.getByText("Success");
|
||||
// expect(badge).toHaveClass("bg-green-100", "text-green-800");
|
||||
|
||||
// rerender(<Badge variant="error">Error</Badge>);
|
||||
// badge = screen.getByText("Error");
|
||||
// expect(badge).toHaveClass("bg-red-100", "text-red-800");
|
||||
|
||||
// rerender(<Badge variant="info">Info</Badge>);
|
||||
// badge = screen.getByText("Info");
|
||||
// expect(badge).toHaveClass("bg-slate-100", "text-slate-800");
|
||||
// });
|
||||
|
||||
// it("applies custom className", () => {
|
||||
// render(
|
||||
// <Badge variant="success" className="custom-class">
|
||||
// Success
|
||||
// </Badge>,
|
||||
// );
|
||||
|
||||
// const badge = screen.getByText("Success");
|
||||
// expect(badge).toHaveClass("custom-class");
|
||||
// });
|
||||
|
||||
// it("renders as span element", () => {
|
||||
// render(<Badge variant="success">Success</Badge>);
|
||||
|
||||
// const badge = screen.getByText("Success");
|
||||
// expect(badge.tagName).toBe("SPAN");
|
||||
// });
|
||||
|
||||
// it("renders children correctly", () => {
|
||||
// render(
|
||||
// <Badge variant="success">
|
||||
// <span>Custom</span> Content
|
||||
// </Badge>,
|
||||
// );
|
||||
|
||||
// expect(screen.getByText("Custom")).toBeInTheDocument();
|
||||
// expect(screen.getByText("Content")).toBeInTheDocument();
|
||||
// });
|
||||
|
||||
// it("supports all badge variants", () => {
|
||||
// const variants = ["success", "error", "info"] as const;
|
||||
|
||||
// variants.forEach((variant) => {
|
||||
// const { unmount } = render(
|
||||
// <Badge variant={variant} data-testid={`badge-${variant}`}>
|
||||
// {variant}
|
||||
// </Badge>,
|
||||
// );
|
||||
|
||||
// expect(screen.getByTestId(`badge-${variant}`)).toBeInTheDocument();
|
||||
// unmount();
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("handles long text content", () => {
|
||||
// render(
|
||||
// <Badge variant="info">
|
||||
// Very long text that should be handled properly by the component
|
||||
// </Badge>,
|
||||
// );
|
||||
|
||||
// const badge = screen.getByText(/Very long text/);
|
||||
// expect(badge).toBeInTheDocument();
|
||||
// expect(badge).toHaveClass("overflow-hidden", "text-ellipsis");
|
||||
// });
|
||||
// });
|
||||
@@ -0,0 +1,35 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type BadgeVariant = "success" | "error" | "info";
|
||||
|
||||
interface BadgeProps {
|
||||
variant: BadgeVariant;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const badgeVariants: Record<BadgeVariant, string> = {
|
||||
success: "bg-green-100 text-green-800",
|
||||
error: "bg-red-100 text-red-800",
|
||||
info: "bg-slate-100 text-slate-800",
|
||||
};
|
||||
|
||||
export function Badge({ variant, children, className }: BadgeProps) {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
// Base styles from Figma
|
||||
"inline-flex items-center gap-2 rounded-[45px] px-[9px] py-[3px]",
|
||||
// Text styles
|
||||
"font-['Geist'] text-xs font-medium leading-5",
|
||||
// Text overflow handling
|
||||
"overflow-hidden text-ellipsis",
|
||||
// Variant styles
|
||||
badgeVariants[variant],
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user