Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pills): add scattered pills feature and resolve issue #238 #336

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
19 changes: 19 additions & 0 deletions animata/card/scattered-pills.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import ScatteredPills from "@/animata/card/scattered-pills";
import { Meta, StoryObj } from "@storybook/react";

const meta = {
title: "Card/Scattered Pills",
component: ScatteredPills,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
argTypes: {},
} satisfies Meta<typeof ScatteredPills>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Primary: Story = {
args: {},
};
69 changes: 69 additions & 0 deletions animata/card/scattered-pills.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, { useEffect, useState } from "react";

interface Pill {
id: number;
text: string;
color: string;
}

const pills: Pill[] = [
{ id: 1, text: "poor analytics", color: "bg-purple-400" },
{ id: 2, text: "no strategy", color: "bg-orange-300" },
{ id: 3, text: "running out of ideas", color: "bg-green-300" },
{ id: 4, text: "engaging content", color: "bg-blue-300" },
{ id: 5, text: "replying to mentions", color: "bg-red-300" },
];

export default function InteractivePillsPyramid() {
const [hoveredPills, setHoveredPills] = useState<Set<number>>(new Set());
const [pyramidFormed, setPyramidFormed] = useState<boolean>(false);
const [currentHover, setCurrentHover] = useState<number | null>(null);

useEffect(() => {
if (hoveredPills.size === pills.length && !pyramidFormed) {
setPyramidFormed(true);
}
}, [hoveredPills, pyramidFormed]);

const handleHover = (id: number) => {
setHoveredPills((prev) => new Set(prev).add(id));
setCurrentHover(id);
};

const handleHoverEnd = () => {
setCurrentHover(null);
};

const getPyramidPosition = (index: number): { x: number; y: number } => {
const positions = [
{ x: 30, y: 60 },
{ x: -40, y: 40 },
{ x: 40, y: 30 },
{ x: -20, y: 10 },
{ x: 20, y: 0 },
];
return positions[index] || { x: 0, y: 0 };
};

return (
<div className="flex h-fit flex-col items-center justify-start space-y-3 bg-transparent pt-24">
{pills.map((pill, index) => (
<div
key={pill.id}
className={`${pill.color} cursor-pointer rounded-full px-8 py-2 font-semibold text-gray-800 transition-all duration-300 ease-in-out`}
style={{
transform: pyramidFormed
? `translate(${getPyramidPosition(index).x}px, ${getPyramidPosition(index).y}px)`
: currentHover === pill.id
? "translateX(-10px) scale(1.1) rotate(-5deg)"
: "none",
}}
onMouseEnter={() => handleHover(pill.id)}
onMouseLeave={handleHoverEnd}
>
{pill.text}
</div>
))}
</div>
);
}
32 changes: 32 additions & 0 deletions content/docs/card/scattered-pills.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: Scattered Pills
description: This Components renders a set of interactive pills, which display different messages. Each pill reacts to user with a slight movement animation
author: raghav_dadhich
---

<ComponentPreview name="card-scattered-pills--docs" />

## Installation

<Steps>
<Step>Run the following command</Step>

It will create a new file `scattered-pills.tsx` inside the `components/animata/card` directory.

```bash
mkdir -p components/animata/card && touch components/animata/card/scattered-pills.tsx
```

<Step>Paste the code</Step>{" "}

Open the newly created file and paste the following code:

```jsx file=<rootDir>/animata/card/scattered-pills.tsx

```

</Steps>

## Credits

Built by [Raghav Dadhich](https://github.com/raghav3615/)
Loading