Skip to content

Commit a1d8297

Browse files
anshuman008anshuman
andauthored
feat: add faq in accordion (codse#348)
Co-authored-by: anshuman <[email protected]>
1 parent 2a15612 commit a1d8297

File tree

4 files changed

+221
-0
lines changed

4 files changed

+221
-0
lines changed

animata/accordion/faq.stories.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import Faq from "@/animata/accordion/faq";
2+
import { Meta, StoryObj } from "@storybook/react";
3+
4+
const faqData = [
5+
{
6+
id: 1,
7+
question: "How late does the internet close?",
8+
answer: "The internet doesn't close. It's available 24/7.",
9+
icon: "❤️",
10+
iconPosition: "right",
11+
},
12+
{
13+
id: 2,
14+
question: "Do I need a license to browse this website?",
15+
answer: "No, you don't need a license to browse this website.",
16+
},
17+
{
18+
id: 3,
19+
question: "What flavour are the cookies?",
20+
answer: "Our cookies are digital, not edible. They're used for website functionality.",
21+
},
22+
{
23+
id: 4,
24+
question: "Can I get lost here?",
25+
answer: "Yes, but we do have a return policy",
26+
icon: "⭐",
27+
iconPostion: "left",
28+
},
29+
{
30+
id: 5,
31+
question: "What if I click the wrong button?",
32+
answer: "Don't worry, you can always go back or refresh the page.",
33+
},
34+
];
35+
36+
const meta = {
37+
title: "Accordion/Faq",
38+
component: Faq,
39+
parameters: {
40+
layout: "centered",
41+
},
42+
tags: ["autodocs"],
43+
argTypes: {},
44+
} satisfies Meta<typeof Faq>;
45+
46+
export default meta;
47+
type Story = StoryObj<typeof meta>;
48+
49+
export const Primary: Story = {
50+
args: {
51+
data: faqData,
52+
},
53+
};

animata/accordion/faq.tsx

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
"use client";
2+
3+
import React, { useState } from "react";
4+
import { motion } from "framer-motion";
5+
6+
import * as Accordion from "@radix-ui/react-accordion";
7+
8+
interface FAQItem {
9+
id: number;
10+
question: string;
11+
answer: string;
12+
icon?: string;
13+
iconPosition?: string;
14+
}
15+
16+
interface FaqSectionProps {
17+
data: FAQItem[];
18+
}
19+
20+
export default function FaqSection({ data }: FaqSectionProps) {
21+
const [openItem, setOpenItem] = useState<string | null>(null);
22+
23+
return (
24+
<div
25+
className="mx-auto max-w-md rounded-lg bg-white p-4"
26+
style={{ maxWidth: "700px", minWidth: "700px" }}
27+
>
28+
<div className="mb-4 text-sm text-gray-500">Every day, 9:01 AM</div>
29+
30+
<Accordion.Root
31+
type="single"
32+
collapsible
33+
value={openItem || ""}
34+
onValueChange={(value) => setOpenItem(value)}
35+
>
36+
{data.map((item) => (
37+
<Accordion.Item value={item.id.toString()} key={item.id} className="mb-2">
38+
<Accordion.Header>
39+
<Accordion.Trigger
40+
className="flex w-full items-center justify-start gap-x-4"
41+
style={{ width: "100%" }}
42+
>
43+
<div
44+
className="relative flex items-center space-x-2 rounded-xl bg-gray-100 p-2 hover:bg-[#E0F7FA]"
45+
style={{
46+
backgroundColor: openItem === item.id.toString() ? "#E0F7FA" : "",
47+
}}
48+
>
49+
{item.icon && (
50+
<span
51+
className={`absolute bottom-6 ${
52+
item.iconPosition === "right" ? "right-0" : "left-0"
53+
}`}
54+
style={{
55+
transform: item.iconPosition === "right" ? "rotate(7deg)" : "rotate(-4deg)",
56+
}}
57+
>
58+
{item.icon}
59+
</span>
60+
)}
61+
<span className="font-medium text-gray-700">{item.question}</span>
62+
</div>
63+
64+
<span className="cursor-pointer text-lg font-bold text-gray-400">
65+
{openItem === item.id.toString() ? (
66+
<svg
67+
xmlns="http://www.w3.org/2000/svg"
68+
viewBox="0 0 24 24"
69+
fill="#7CB9E8"
70+
className="size-6"
71+
>
72+
<path
73+
fillRule="evenodd"
74+
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm3 10.5a.75.75 0 0 0 0-1.5H9a.75.75 0 0 0 0 1.5h6Z"
75+
clipRule="evenodd"
76+
/>
77+
</svg>
78+
) : (
79+
<svg
80+
xmlns="http://www.w3.org/2000/svg"
81+
viewBox="0 0 24 24"
82+
fill="currentColor"
83+
className="size-6"
84+
>
85+
<path
86+
fillRule="evenodd"
87+
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25ZM12.75 9a.75.75 0 0 0-1.5 0v2.25H9a.75.75 0 0 0 0 1.5h2.25V15a.75.75 0 0 0 1.5 0v-2.25H15a.75.75 0 0 0 0-1.5h-2.25V9Z"
88+
clipRule="evenodd"
89+
/>
90+
</svg>
91+
)}
92+
</span>
93+
</Accordion.Trigger>
94+
</Accordion.Header>
95+
<Accordion.Content asChild forceMount style={{ display: "block" }}>
96+
<motion.div
97+
initial="collapsed"
98+
animate={openItem === item.id.toString() ? "open" : "collapsed"}
99+
variants={{
100+
open: { opacity: 1, height: "auto" },
101+
collapsed: { opacity: 0, height: 0 },
102+
}}
103+
transition={{ duration: 0.4 }}
104+
style={{ width: "100%", overflow: "hidden" }}
105+
>
106+
<div
107+
className="ml-7 mt-1 rounded-lg p-3 text-white md:ml-16"
108+
style={{
109+
borderRadius: "12px",
110+
textAlign: "left",
111+
width: "100%",
112+
}}
113+
>
114+
<div className="relative max-w-xs rounded-2xl bg-blue-500 px-4 py-2 text-white">
115+
{item.answer}
116+
<div className="absolute bottom-0 right-0 h-0 w-0 border-l-[10px] border-t-[10px] border-l-transparent border-t-blue-500"></div>
117+
</div>
118+
</div>
119+
</motion.div>
120+
</Accordion.Content>
121+
</Accordion.Item>
122+
))}
123+
</Accordion.Root>
124+
</div>
125+
);
126+
}

config/docs.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ const sidebarNav: SidebarNavItem[] = [
105105
title: "Container",
106106
items: createLinks("container"),
107107
},
108+
{
109+
title: "Accordion",
110+
items: createLinks("accordion"),
111+
},
108112
{
109113
title: "Card",
110114
items: createLinks("card"),

content/docs/accordion/faq.mdx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: Faq
3+
description: its an faq accordion that looks like an chating interface with smooth animations
4+
author: anshu_code
5+
---
6+
7+
<ComponentPreview name="accordion-faq--docs" />
8+
9+
## Installation
10+
11+
<Steps>
12+
<Step>Install dependencies</Step>
13+
14+
```bash
15+
npm install framer-motion lucide-react
16+
```
17+
18+
<Step>Run the following command</Step>
19+
20+
It will create a new file `faq.tsx` inside the `components/animata/accordion` directory.
21+
22+
```bash
23+
mkdir -p components/animata/accordion && touch components/animata/accordion/faq.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/accordion/faq.tsx
31+
32+
```
33+
34+
</Steps>
35+
36+
## Credits
37+
38+
Built by [Anshuman](https://github.com/anshuman008)

0 commit comments

Comments
 (0)