Add store cards

This commit is contained in:
SwiftyOS
2024-10-11 10:00:40 +02:00
parent 3ce7cf2713
commit 00d5d843a2
2 changed files with 139 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
import type { Meta, StoryObj } from "@storybook/react";
import { StoreCard } from "./StoreCard";
import { userEvent, within } from "@storybook/test";
const meta = {
title: "AGPTUI/StoreCard",
component: StoreCard,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
argTypes: {
agentName: { control: "text" },
description: { control: "text" },
runs: { control: "number" },
rating: { control: "number", min: 0, max: 5, step: 0.1 },
onClick: { action: "clicked" },
},
} satisfies Meta<typeof StoreCard>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
agentName: "SEO Optimizer",
description: "Optimize your website's SEO with AI-powered suggestions",
runs: 10000,
rating: 4.5,
onClick: () => console.log("Default StoreCard clicked"),
},
};
export const LowRating: Story = {
args: {
agentName: "Data Analyzer",
description: "Analyze complex datasets with machine learning algorithms",
runs: 5000,
rating: 2.7,
onClick: () => console.log("LowRating StoreCard clicked"),
},
};
export const HighRuns: Story = {
args: {
agentName: "Code Assistant",
description: "Get AI-powered coding help for various programming languages",
runs: 1000000,
rating: 4.8,
onClick: () => console.log("HighRuns StoreCard clicked"),
},
};
export const WithInteraction: Story = {
args: {
agentName: "Task Planner",
description: "Plan and organize your tasks efficiently with AI",
runs: 50000,
rating: 4.2,
onClick: () => console.log("WithInteraction StoreCard clicked"),
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const storeCard = canvas.getByText("Task Planner");
await userEvent.hover(storeCard);
await userEvent.click(storeCard);
},
};

View File

@@ -0,0 +1,70 @@
import * as React from "react";
import { StarIcon, StarFilledIcon } from "@radix-ui/react-icons";
interface StoreCardProps {
agentName: string;
description: string;
runs: number;
rating: number;
onClick: () => void;
}
export const StoreCard: React.FC<StoreCardProps> = ({
agentName,
description,
runs,
rating,
onClick,
}) => {
const [isHovered, setIsHovered] = React.useState(false);
const handleMouseEnter = () => setIsHovered(true);
const handleMouseLeave = () => setIsHovered(false);
const renderStars = () => {
const fullStars = Math.floor(rating);
const hasHalfStar = rating % 1 !== 0;
const stars = [];
for (let i = 0; i < 5; i++) {
if (i < fullStars) {
stars.push(<StarFilledIcon key={i} className="text-black" />);
} else if (i === fullStars && hasHalfStar) {
stars.push(<StarIcon key={i} className="text-black" />);
} else {
stars.push(<StarIcon key={i} className="text-black" />);
}
}
return stars;
};
return (
<div
className={`relative h-96 w-[440px] ${isHovered ? "shadow-lg" : ""} rounded-xl transition-shadow duration-300`}
onClick={onClick}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className="absolute left-0 top-0 h-[238px] w-[440px] rounded-xl bg-[#d9d9d9]" />
<div className="absolute left-[16px] top-[158px] h-16 w-16 rounded-full bg-[#7e7e7e]" />
<div className="font-['PP Neue Montreal TT'] absolute left-0 top-[254px] text-xl font-bold tracking-tight text-[#272727]">
{agentName}
</div>
<div className="font-['PP Neue Montreal TT'] absolute left-0 top-[284px] w-[440px] text-base font-normal leading-[21px] tracking-tight text-[#282828]">
{description}
</div>
<div className="font-['PP Neue Montreal TT'] absolute left-0 top-[360px] text-base font-medium tracking-tight text-[#272727]">
{runs.toLocaleString()}+ runs
</div>
<div className="absolute left-[297px] top-[360px] pb-2">
<div className="font-['PP Neue Montreal TT'] absolute left-0 top-0 text-base font-medium tracking-tight text-[#272727]">
{rating.toFixed(1)}
</div>
<div className="absolute left-[34px] top-0 inline-flex h-[19px] items-center justify-start gap-px">
{renderStars()}
</div>
</div>
</div>
);
};