mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
Added filter chips
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { FilterChips } from "./FilterChips";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "AGPTUI/FilterChips",
|
||||
component: FilterChips,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
argTypes: {
|
||||
badges: { control: "object" },
|
||||
onFilterChange: { action: "onFilterChange" },
|
||||
multiSelect: { control: "boolean" },
|
||||
},
|
||||
} satisfies Meta<typeof FilterChips>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
const defaultBadges = [
|
||||
"Marketing",
|
||||
"Sales",
|
||||
"Content creation",
|
||||
"Lorem ipsum",
|
||||
"Lorem ipsum",
|
||||
];
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
badges: defaultBadges,
|
||||
multiSelect: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const SingleSelect: Story = {
|
||||
args: {
|
||||
badges: defaultBadges,
|
||||
multiSelect: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithSelectedFilters: Story = {
|
||||
args: {
|
||||
badges: defaultBadges,
|
||||
multiSelect: true,
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const marketingChip = canvas.getByText("Marketing").parentElement;
|
||||
const salesChip = canvas.getByText("Sales").parentElement;
|
||||
if (!marketingChip || !salesChip) {
|
||||
throw new Error("Marketing or Sales chip not found");
|
||||
}
|
||||
|
||||
await userEvent.click(marketingChip);
|
||||
await userEvent.click(salesChip);
|
||||
|
||||
expect(marketingChip).toHaveClass("bg-neutral-100");
|
||||
expect(salesChip).toHaveClass("bg-neutral-100");
|
||||
},
|
||||
};
|
||||
|
||||
export const WithFilterChangeCallback: Story = {
|
||||
args: {
|
||||
badges: defaultBadges,
|
||||
multiSelect: true,
|
||||
onFilterChange: (selectedFilters: string[]) => {
|
||||
console.log("Selected filters:", selectedFilters);
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const salesChip = canvas.getByText("Sales");
|
||||
const marketingChip = canvas.getByText("Marketing");
|
||||
|
||||
await userEvent.click(salesChip);
|
||||
await userEvent.click(marketingChip);
|
||||
},
|
||||
};
|
||||
|
||||
export const EmptyBadges: Story = {
|
||||
args: {
|
||||
badges: [],
|
||||
multiSelect: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const LongBadgeNames: Story = {
|
||||
args: {
|
||||
badges: [
|
||||
"Machine Learning",
|
||||
"Natural Language Processing",
|
||||
"Computer Vision",
|
||||
"Data Science",
|
||||
],
|
||||
multiSelect: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const SingleSelectBehavior: Story = {
|
||||
args: {
|
||||
badges: defaultBadges,
|
||||
multiSelect: false,
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const salesChip = canvas.getByText("Sales").parentElement;
|
||||
const marketingChip = canvas.getByText("Marketing").parentElement;
|
||||
|
||||
if (!salesChip || !marketingChip) {
|
||||
throw new Error("Sales or Marketing chip not found");
|
||||
}
|
||||
|
||||
await userEvent.click(salesChip);
|
||||
expect(salesChip).toHaveClass("bg-neutral-100");
|
||||
|
||||
await userEvent.click(marketingChip);
|
||||
expect(marketingChip).toHaveClass("bg-neutral-100");
|
||||
expect(salesChip).not.toHaveClass("bg-neutral-100");
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import * as React from "react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
interface FilterChipsProps {
|
||||
badges: string[];
|
||||
onFilterChange?: (selectedFilters: string[]) => void;
|
||||
multiSelect?: boolean;
|
||||
}
|
||||
/** FilterChips is a component that allows the user to select filters from a list of badges. It is used on the Agent Store home page */
|
||||
export const FilterChips: React.FC<FilterChipsProps> = ({
|
||||
badges,
|
||||
onFilterChange,
|
||||
multiSelect = true,
|
||||
}) => {
|
||||
const [selectedFilters, setSelectedFilters] = React.useState<string[]>([]);
|
||||
|
||||
const handleBadgeClick = (badge: string) => {
|
||||
setSelectedFilters((prevFilters) => {
|
||||
let newFilters;
|
||||
if (multiSelect) {
|
||||
newFilters = prevFilters.includes(badge)
|
||||
? prevFilters.filter((filter) => filter !== badge)
|
||||
: [...prevFilters, badge];
|
||||
} else {
|
||||
newFilters = prevFilters.includes(badge) ? [] : [badge];
|
||||
}
|
||||
|
||||
if (onFilterChange) {
|
||||
onFilterChange(newFilters);
|
||||
}
|
||||
|
||||
return newFilters;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="inline-flex h-14 items-center justify-start gap-5">
|
||||
{badges.map((badge) => (
|
||||
<Badge
|
||||
key={badge}
|
||||
variant={selectedFilters.includes(badge) ? "secondary" : "outline"}
|
||||
className="h-1] flex cursor-pointer items-center justify-center gap-2.5 rounded-full border border-black/50 px-6 py-2"
|
||||
onClick={() => handleBadgeClick(badge)}
|
||||
>
|
||||
<div className="font-neue text-xl font-medium leading-9 tracking-tight text-[#474747]">
|
||||
{badge}
|
||||
</div>
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user