Skip to content

Commit f74de40

Browse files
feat: add music stack interaction widget (codse#314)
1 parent 20b049d commit f74de40

File tree

4 files changed

+223
-4
lines changed

4 files changed

+223
-4
lines changed

.github/ISSUE_TEMPLATE/new-component-ticket.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@ name: New Component Ticket [HACKTOBERFEST]
33
about: Create a new animated component task for Hacktoberfest
44
title: Component Name
55
labels: hacktoberfest
6-
assignees: ''
7-
6+
assignees: ""
87
---
98

109
### Description
10+
1111
Create the component as shown in the video attached below.
1212

1313
### Animation Preview
14+
1415
- Screenshot/Video:
1516

1617
[Upload file here]
1718

18-
1919
> [!NOTE]
2020
> Please refer to the **Animata contributing guidelines** available [here](https://www.animata.design/docs/contributing) for rules on how to contribute to the project. Let us know in the comments if you’re working on this issue, and feel free to ask any questions!
2121
2222
### Requirements
23+
2324
1. Create a new animated component that matches the provided design.
2425
2. Add example usage of the component in the documentation or storybook.
2526
3. **Add credits** for any resources, references, or assets used, as specified in the **Additional Resources** section.
2627

27-
2828
<details>
2929
<summary>
3030
<h3> Guidelines & Best Practices</h3>
@@ -38,12 +38,14 @@ Create the component as shown in the video attached below.
3838

3939
> [!IMPORTANT]
4040
> To ensure more contributors have the opportunity to participate, we kindly request that:
41+
>
4142
> - Each contributor submits only **one pull request** related to this issue.
4243
> - If you're interested in working on this issue, please comment below. We will assign the issue on a **first-come, first-served basis**.
4344
4445
---
4546

4647
### Additional Resources
48+
4749
<!-- Add references and credits here -->
4850

4951
---
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import MusicStackInteraction from "@/animata/widget/music-stack-interaction";
2+
import { Meta, StoryObj } from "@storybook/react";
3+
4+
const meta = {
5+
title: "Widget/Music Stack Interaction",
6+
component: MusicStackInteraction,
7+
parameters: {
8+
layout: "centered",
9+
},
10+
tags: ["autodocs"],
11+
argTypes: {},
12+
} satisfies Meta<typeof MusicStackInteraction>;
13+
14+
export default meta;
15+
type Story = StoryObj<typeof meta>;
16+
17+
export const Primary: Story = {
18+
args: {
19+
albums: [
20+
{
21+
id: 1,
22+
title: "The Dark Side of the Moon",
23+
artist: "Pink Floyd",
24+
cover: "https://images.unsplash.com/photo-1569424758782-cba94e6165fd",
25+
},
26+
{
27+
id: 2,
28+
title: "Abbey Road",
29+
artist: "The Beatles",
30+
cover: "https://images.unsplash.com/photo-1516410529446-2c777cb7366d",
31+
},
32+
{
33+
id: 3,
34+
title: "Thriller",
35+
artist: "Michael Jackson",
36+
cover: "https://images.unsplash.com/photo-1559406041-c7d2b2e98690",
37+
},
38+
{
39+
id: 4,
40+
title: "The Wall",
41+
artist: "Pink Floyd",
42+
cover: "https://images.unsplash.com/photo-1528822234686-beae35cab346",
43+
},
44+
],
45+
},
46+
render: (args) => {
47+
return (
48+
<div className="flex w-auto items-center justify-center rounded-xl border bg-gray-900 p-4 text-white shadow-2xl">
49+
<MusicStackInteraction {...args} />
50+
</div>
51+
);
52+
},
53+
};
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import React, { useState } from "react";
2+
import { motion } from "framer-motion";
3+
import { Layers, LayoutGrid } from "lucide-react";
4+
5+
import { cn } from "@/lib/utils";
6+
7+
const carouselStyles = {
8+
perspective: "1000px",
9+
overflow: "hidden",
10+
};
11+
12+
const carouselInnerStyles: React.CSSProperties = {
13+
display: "flex",
14+
transformStyle: "preserve-3d",
15+
transition: "transform 2s",
16+
justifyContent: "center",
17+
alignItems: "center",
18+
height: "100%",
19+
};
20+
21+
const carouselItemStyles: React.CSSProperties = {
22+
minWidth: "200px",
23+
marginLeft: "-180px",
24+
transform: "rotateY(15deg) translateZ(300px) translateX(-50px)",
25+
backfaceVisibility: "hidden",
26+
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.2)",
27+
transition: "transform 2s, box-shadow 2s",
28+
};
29+
30+
const carouselItemFirstChildStyles: React.CSSProperties = {
31+
minWidth: "200px",
32+
marginLeft: "20px",
33+
transform: "rotateY(5deg) translateZ(300px) translateX(0)",
34+
backfaceVisibility: "hidden",
35+
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.2)",
36+
transition: "transform 2s, box-shadow 2s",
37+
};
38+
39+
interface albumsProps {
40+
/*
41+
* Array of album objects
42+
*/
43+
albums: {
44+
id: number;
45+
title: string;
46+
artist: string;
47+
cover: string;
48+
}[];
49+
}
50+
51+
export default function MusicStackInteraction({ albums }: albumsProps) {
52+
const [isGridView, setIsGridView] = useState(true);
53+
54+
const handleToggleView = () => {
55+
setIsGridView(!isGridView);
56+
};
57+
58+
return (
59+
<div className="relative mx-auto h-[33rem] w-80 rounded bg-gray-900 p-2 text-white">
60+
<motion.div
61+
className={cn("h-96 w-full", { "mt-24": !isGridView })}
62+
style={isGridView ? undefined : carouselStyles}
63+
layout
64+
>
65+
<motion.div
66+
className={cn("", { "mb-4 grid grid-cols-2 gap-6": isGridView })}
67+
style={isGridView ? undefined : carouselInnerStyles}
68+
layout
69+
>
70+
{albums.map((album, index) => (
71+
<div
72+
key={album.id}
73+
className={cn("relative w-full shadow-lg")}
74+
style={
75+
isGridView
76+
? undefined
77+
: index === 0
78+
? carouselItemFirstChildStyles
79+
: carouselItemStyles
80+
}
81+
>
82+
<motion.img
83+
layout
84+
src={album.cover + "?w=200&h=200"}
85+
alt={album.title}
86+
className="h-auto rounded-xl shadow-md"
87+
/>
88+
<motion.div
89+
layout
90+
className="absolute bottom-0 left-0 w-full bg-opacity-50 bg-gradient-to-b from-transparent to-gray-800 px-4 py-2 text-white"
91+
>
92+
<motion.h3 layout className="font-semibold leading-tight">
93+
{album.title}
94+
</motion.h3>
95+
<motion.p layout className="text-sm leading-snug">
96+
{album.artist}
97+
</motion.p>
98+
</motion.div>
99+
</div>
100+
))}
101+
</motion.div>
102+
</motion.div>
103+
104+
<motion.div className="duration-2000 absolute bottom-4 left-0 right-0 -mb-4 flex w-auto items-center justify-center rounded-xl bg-gray-800 p-4 text-white shadow-2xl transition-all">
105+
<div className="flex w-32 items-center space-x-2 rounded-full bg-gray-900 p-2">
106+
<div
107+
className={cn("flex h-8 w-16 cursor-pointer items-center justify-center rounded-full", {
108+
"bg-gray-700": isGridView,
109+
})}
110+
onClick={handleToggleView}
111+
>
112+
<LayoutGrid />
113+
</div>
114+
<div
115+
className={cn("flex h-8 w-16 cursor-pointer items-center justify-center rounded-full", {
116+
"bg-gray-700": !isGridView,
117+
})}
118+
onClick={handleToggleView}
119+
>
120+
<Layers />
121+
</div>
122+
</div>
123+
</motion.div>
124+
</div>
125+
);
126+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: Music Stack Interaction
3+
description: widget for Music stack and unstacking
4+
author: Mahlawat2001
5+
---
6+
7+
<ComponentPreview name="widget-music-stack-interaction--docs" />
8+
9+
## Installation
10+
11+
<Steps>
12+
<Step>Install dependencies</Step>
13+
14+
```bash
15+
npm install lucide-react framer-motion
16+
```
17+
18+
<Step>Run the following command</Step>
19+
20+
It will create a new file `music-stack-interaction.tsx` inside the `components/animata/widget` directory.
21+
22+
```bash
23+
mkdir -p components/animata/widget && touch components/animata/widget/music-stack-interaction.tsx
24+
```
25+
26+
<Step>Paste the code</Step>{" "}
27+
28+
Open the newly created file and paste the following code:
29+
30+
```jsx file=<rootDir>/animata/widget/music-stack-interaction.tsx
31+
32+
```
33+
34+
</Steps>
35+
36+
## Credits
37+
38+
Built by [Mohit Ahlawat](https://github.com/mohitahlawat2001)

0 commit comments

Comments
 (0)