diff --git a/animata/list/list-stack.stories.tsx b/animata/list/list-stack.stories.tsx new file mode 100644 index 00000000..5b19cee8 --- /dev/null +++ b/animata/list/list-stack.stories.tsx @@ -0,0 +1,45 @@ +import { HandPlatter, Sailboat, Tent } from "lucide-react"; + +import { ListStack } from "@/animata/list/list-stack"; +import { Meta, StoryObj } from "@storybook/react"; + +const meta = { + title: "List/List Stack", + component: ListStack, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], + argTypes: {}, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + cards: [ + { + id: 0, + icon: , + title: "Camping", + location: "Yosemite Park", + date: "5 August", + }, + { + id: 1, + icon: , + title: "Boating", + location: "Lake Tahoe Park", + date: "2 August", + }, + { + id: 2, + icon: , + title: "Barbecue", + location: "Greenfield Shores", + date: "28 July", + }, + ], + }, +}; diff --git a/animata/list/list-stack.tsx b/animata/list/list-stack.tsx new file mode 100644 index 00000000..7b579797 --- /dev/null +++ b/animata/list/list-stack.tsx @@ -0,0 +1,167 @@ +import React, { ReactElement, useState } from "react"; +import { AnimatePresence, motion } from "framer-motion"; +import { ChevronDown } from "lucide-react"; + +interface CardProps { + id: number; + icon: ReactElement | string; + title: string; + location: string; + date: string; +} + +interface ListStackProps { + cards: CardProps[]; + offset?: number; + scaleFactor?: number; +} + +export const CardStack = ({ icon, title, location, date }: CardProps) => { + return ( + +
{icon}
+
+

{title}

+
+
{location}
+
{date}
+
+
+
+ ); +}; + +export const ListStack = ({ cards, offset, scaleFactor }: ListStackProps) => { + const CARD_OFFSET = offset || 9; + const SCALE_FACTOR = scaleFactor || 0.03; + const [showAll, setShowAll] = useState(false); + + const toggleShow = () => setShowAll(!showAll); + const middleIndex = Math.floor(cards.length / 2); + + const revealAnimation = { + hidden: { opacity: 0, scale: 1 }, + visible: { + opacity: 1, + transition: { + duration: 0.5, + ease: [0, 0.71, 0.2, 1.01], + scale: { + type: "spring", + damping: 5, + stiffness: 100, + restDelta: 0.001, + }, + }, + }, + }; + + const stackAnimation = { + hidden: { opacity: 0, scale: 1 }, + visible: (i: number) => ({ + opacity: 1, + y: (i - middleIndex) * CARD_OFFSET, + scale: 1 - i * SCALE_FACTOR, + zIndex: cards.length - i, + }), + }; + + return ( +
+
+
+
+ + {showAll + ? cards.map((card, index) => ( + + + + )) + : cards.map((card, index) => ( + + + + ))} + +
+
+
+ + {showAll ? ( + <> +
+

Hide

+ + + +
+ + ) : ( + <> +
+

Show All

+ + + +
+ + )} +
+
+ ); +}; diff --git a/content/docs/list/list-stack.mdx b/content/docs/list/list-stack.mdx new file mode 100644 index 00000000..209a5767 --- /dev/null +++ b/content/docs/list/list-stack.mdx @@ -0,0 +1,39 @@ +--- +title: List Stack +description: A stack of bouncy revealing cards +author: mansidhamne +--- + + + +## Installation + + +Install dependencies + +```bash +npm install framer-motion lucide-react +``` + +Run the following command + +It will create a new file `list-stack.tsx` inside the `components/animata/list` directory. + +```bash +mkdir -p components/animata/list && touch components/animata/list/list-stack.tsx +``` + +Paste the code{" "} + +Open the newly created file and paste the following code: + +```jsx file=/animata/list/list-stack.tsx + +``` + + + +## Credits + +Built by [Mansi Dhamne](https://github.com/mansidhamne) +Interaction by [Nitish Khagwal](https://x.com/nitishkmrk)