Skip to content

Commit de43054

Browse files
committed
Animation in Faq's
1 parent 63d4857 commit de43054

File tree

2 files changed

+267
-32
lines changed

2 files changed

+267
-32
lines changed

src/pages/About/FAQs.tsx

Lines changed: 118 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ import { useState } from 'react';
44
import { stats } from '@/constants/Stats';
55
import faqs from '@/constants/aboutUs/faqs.ts';
66
import { quickAnswers } from '@/constants/aboutUs/quickanswers';
7+
import { motion } from 'framer-motion';
8+
import {
9+
fadeIn,
10+
slideInLeft,
11+
slideInRight,
12+
subtleRise,
13+
headerReveal,
14+
faqPageAnimations,
15+
} from '@/styles/Animations';
716

817
const FAQs = () => {
918
const [openIndex, setOpenIndex] = useState<number | null>(null);
@@ -17,72 +26,149 @@ const FAQs = () => {
1726
<Header />
1827
<main className="container mx-auto p-4">
1928
{/* Top FAQs Section */}
20-
<section className="my-8 flex justify-center">
29+
<motion.section
30+
className="my-8 flex justify-center"
31+
initial="hidden"
32+
whileInView="visible"
33+
viewport={{ once: true, amount: 0.3 }}
34+
variants={faqPageAnimations.pageSection}
35+
>
2136
<div className="max-w-4xl w-4/5 flex flex-col md:flex-row justify-between items-center">
2237
{/* Left Side - Text */}
23-
<div className="md:w-1/2 text-left md:pr-8">
24-
<h1 className="text-4xl font-bold">FAQs</h1>
25-
<p className="text-gray-600 mt-2 text-lg">
26-
Have questions? Here you’ll find the answers most valued by our
38+
<motion.div
39+
className="md:w-1/2 text-left md:pr-8"
40+
variants={slideInLeft}
41+
>
42+
<motion.h1
43+
className="text-4xl font-bold"
44+
variants={faqPageAnimations.headingText}
45+
>
46+
FAQs
47+
</motion.h1>
48+
<motion.p
49+
className="text-gray-600 mt-2 text-lg"
50+
variants={faqPageAnimations.paragraphText}
51+
>
52+
Have questions? Here you'll find the answers most valued by our
2753
partners, along with access to step-by-step instructions and
2854
support.
29-
</p>
30-
</div>
55+
</motion.p>
56+
</motion.div>
3157

3258
{/* Right Side - Enlarged Image */}
33-
<div className="md:w-1/2 flex justify-end">
34-
<img
59+
<motion.div
60+
className="md:w-1/2 flex justify-end"
61+
variants={slideInRight}
62+
>
63+
<motion.img
3564
src={stats.faq}
3665
alt="FAQs Illustration"
3766
className="w-80 md:w-[400px] lg:w-[500px]"
67+
variants={faqPageAnimations.heroImage}
68+
whileHover="hover"
3869
/>
39-
</div>
70+
</motion.div>
4071
</div>
41-
</section>
72+
</motion.section>
4273

4374
{/* FAQ Sections Container */}
4475
<div className="w-4/5 max-w-5xl mx-auto">
4576
{/* Quick Answers */}
46-
<section className="my-10">
47-
<h2 className="text-3xl font-bold mb-6">Quick Answers</h2>
48-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-6">
77+
<motion.section
78+
className="my-10"
79+
initial="hidden"
80+
whileInView="visible"
81+
viewport={{ once: true, amount: 0.2 }}
82+
variants={fadeIn}
83+
>
84+
<motion.h2
85+
className="text-3xl font-bold mb-6"
86+
variants={headerReveal}
87+
>
88+
Quick Answers
89+
</motion.h2>
90+
<motion.div
91+
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-6"
92+
variants={faqPageAnimations.quickAnswersContainer}
93+
>
4994
{quickAnswers.map((qa, index) => (
50-
<div
95+
<motion.div
5196
key={index}
5297
className="bg-white shadow-lg rounded-2xl p-6 flex flex-col items-center border border-gray-200"
98+
variants={faqPageAnimations.quickAnswerCard}
99+
whileHover="hover"
100+
whileTap="tap"
53101
>
54-
<div className="w-12 h-12 bg-white flex items-center justify-center rounded-lg mb-4">
102+
<motion.div
103+
className="w-12 h-12 bg-white flex items-center justify-center rounded-lg mb-4"
104+
variants={faqPageAnimations.quickAnswerIcon}
105+
custom={index}
106+
>
55107
<img src={qa.image} alt={qa.question} className="w-6 h-6" />
56-
</div>
108+
</motion.div>
57109
<h3 className="font-semibold text-center">{qa.question}</h3>
58110
<p className="text-gray-600 text-sm text-center mt-2">
59111
{qa.answer}
60112
</p>
61-
</div>
113+
</motion.div>
62114
))}
63-
</div>
64-
</section>
115+
</motion.div>
116+
</motion.section>
65117

66118
{/* General FAQs */}
67-
<section className="my-10">
68-
<h2 className="text-3xl font-bold mb-6">General FAQs</h2>
69-
<div className="bg-white shadow-lg rounded-lg p-6">
119+
<motion.section
120+
className="my-10"
121+
initial="hidden"
122+
whileInView="visible"
123+
viewport={{ once: true, amount: 0.2 }}
124+
variants={faqPageAnimations.faqContainer}
125+
>
126+
<motion.h2
127+
className="text-3xl font-bold mb-6"
128+
variants={headerReveal}
129+
>
130+
General FAQs
131+
</motion.h2>
132+
<motion.div
133+
className="bg-white shadow-lg rounded-lg p-6"
134+
variants={subtleRise}
135+
>
70136
{faqs.map((faq, index) => (
71-
<div key={index} className="border-b">
72-
<button
137+
<motion.div
138+
key={index}
139+
className="border-b"
140+
variants={faqPageAnimations.faqItem}
141+
custom={index}
142+
>
143+
<motion.button
73144
className="w-full text-left py-4 text-lg font-medium flex justify-between items-center"
74145
onClick={() => toggleFAQ(index)}
146+
whileHover="hover"
147+
variants={faqPageAnimations.faqQuestionButton}
75148
>
76149
{faq.question}
77-
<span>{openIndex === index ? '-' : '+'}</span>
78-
</button>
79-
{openIndex === index && (
150+
<motion.span
151+
variants={faqPageAnimations.faqToggleIcon(
152+
openIndex === index,
153+
)}
154+
initial="initial"
155+
animate="animate"
156+
>
157+
{openIndex === index ? '-' : '+'}
158+
</motion.span>
159+
</motion.button>
160+
<motion.div
161+
variants={faqPageAnimations.faqAnswer(openIndex === index)}
162+
initial="initial"
163+
animate="animate"
164+
style={{ overflow: 'hidden' }}
165+
>
80166
<p className="p-4 text-gray-700">{faq.answer}</p>
81-
)}
82-
</div>
167+
</motion.div>
168+
</motion.div>
83169
))}
84-
</div>
85-
</section>
170+
</motion.div>
171+
</motion.section>
86172
</div>
87173
</main>
88174
<Footer />

src/styles/Animations.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,3 +688,152 @@ export const dividerVariants = {
688688
},
689689
},
690690
};
691+
692+
export const faqPageAnimations = {
693+
// Page section animations
694+
pageSection: {
695+
hidden: { opacity: 0 },
696+
visible: {
697+
opacity: 1,
698+
transition: { duration: 0.6, ease: 'easeOut' },
699+
},
700+
},
701+
702+
// Text content animations
703+
headingText: {
704+
hidden: { opacity: 0, y: 20 },
705+
visible: {
706+
opacity: 1,
707+
y: 0,
708+
transition: { duration: 0.7, ease: 'easeOut' },
709+
},
710+
},
711+
712+
paragraphText: {
713+
hidden: { opacity: 0, y: 20 },
714+
visible: {
715+
opacity: 1,
716+
y: 0,
717+
transition: { duration: 0.7, ease: 'easeOut', delay: 0.2 },
718+
},
719+
},
720+
721+
// Hero image animation
722+
heroImage: {
723+
hidden: { opacity: 0, x: 100 },
724+
visible: {
725+
opacity: 1,
726+
x: 0,
727+
transition: { duration: 0.6, ease: 'easeOut' },
728+
},
729+
hover: {
730+
scale: 1.03,
731+
transition: { duration: 0.3 },
732+
},
733+
},
734+
735+
// Quick answers grid container
736+
quickAnswersContainer: {
737+
hidden: { opacity: 0 },
738+
visible: {
739+
opacity: 1,
740+
transition: {
741+
staggerChildren: 0.15,
742+
delayChildren: 0.1,
743+
},
744+
},
745+
},
746+
747+
// Quick answer card animation
748+
quickAnswerCard: {
749+
hidden: { scale: 0.9, opacity: 0 },
750+
visible: {
751+
scale: 1,
752+
opacity: 1,
753+
transition: {
754+
type: 'spring',
755+
stiffness: 400,
756+
damping: 10,
757+
},
758+
},
759+
hover: {
760+
scale: 1.05,
761+
transition: {
762+
type: 'spring',
763+
stiffness: 400,
764+
damping: 10,
765+
},
766+
},
767+
tap: { scale: 0.95 },
768+
},
769+
770+
// Icon in quick answer cards
771+
quickAnswerIcon: {
772+
hidden: { rotate: -10, scale: 0.9 },
773+
visible: (index: number) => ({
774+
rotate: 0,
775+
scale: 1,
776+
transition: {
777+
duration: 0.5,
778+
delay: index * 0.1,
779+
},
780+
}),
781+
},
782+
783+
// FAQ container
784+
faqContainer: {
785+
hidden: { opacity: 0 },
786+
visible: {
787+
opacity: 1,
788+
transition: {
789+
staggerChildren: 0.2,
790+
delayChildren: 0.3,
791+
},
792+
},
793+
},
794+
795+
// FAQ item animation
796+
faqItem: {
797+
hidden: { y: 20, opacity: 0 },
798+
visible: (index: number) => ({
799+
y: 0,
800+
opacity: 1,
801+
transition: {
802+
duration: 0.8,
803+
delay: index * 0.1,
804+
ease: [0.22, 1, 0.36, 1],
805+
},
806+
}),
807+
},
808+
809+
// FAQ question button hover
810+
faqQuestionButton: {
811+
initial: {},
812+
hover: {
813+
x: 5,
814+
transition: {
815+
type: 'spring',
816+
stiffness: 300,
817+
},
818+
},
819+
},
820+
821+
// FAQ toggle icon animation
822+
faqToggleIcon: (isOpen: boolean): Variants => ({
823+
initial: { rotate: 0 },
824+
animate: {
825+
rotate: isOpen ? 180 : 0,
826+
transition: { duration: 0.3 },
827+
},
828+
}),
829+
830+
// FAQ answer animation
831+
faqAnswer: (isOpen: boolean): Variants => ({
832+
initial: { height: 0, opacity: 0 },
833+
animate: {
834+
height: isOpen ? 'auto' : 0,
835+
opacity: isOpen ? 1 : 0,
836+
transition: { duration: 0.3 },
837+
},
838+
}),
839+
};

0 commit comments

Comments
 (0)