@@ -5,8 +5,8 @@ import Image from 'next/image';
55import { Container } from '@/components/ui/container' ;
66import Link from 'next/link' ;
77import { CarouselDots , type CarouselApi } from '@/components/ui/carousel' ;
8- // import { useState } from 'react';
9- // import { useEffect } from 'react';
8+ import { useState } from 'react' ;
9+ import { useEffect } from 'react' ;
1010import YellowStar from '@/public/assets/testimonials/yellow-star.svg'
1111import WhiteStar from '@/public/assets/testimonials/white-star.svg'
1212import ChatBubble from '@/public/assets/testimonials/chat-bubble.svg'
@@ -26,6 +26,7 @@ import {
2626type TestimonialProps = {
2727 text : string
2828 rate : number
29+ active : boolean
2930}
3031
3132export function Testimonials ( ) {
@@ -69,29 +70,28 @@ export function Testimonials() {
6970 } ,
7071 ] ;
7172
72- // const [api, setApi] = useState<CarouselApi>();
73- // const [current, setCurrent] = useState(0);
74- // const [isInteracting, setIsInteracting] = useState(false);
75- //
76- // useEffect(() => {
77- // if (!api) {
78- // return;
79- // }
80- //
81- // setCurrent(api.selectedScrollSnap());
82- //
83- // api.on('select', () => {
84- // setCurrent(api.selectedScrollSnap());
85- // });
86- // }, [api]);
73+ const [ api , setApi ] = useState < CarouselApi > ( ) ;
74+ const [ current , setCurrent ] = useState ( 0 ) ;
75+ const [ isInteracting , setIsInteracting ] = useState ( false ) ;
76+
77+ useEffect ( ( ) => {
78+ if ( ! api ) {
79+ return ;
80+ }
81+ setCurrent ( api . selectedScrollSnap ( ) ) ;
82+
83+ api . on ( 'select' , ( ) => {
84+ setCurrent ( api . selectedScrollSnap ( ) ) ;
85+ } ) ;
86+ } , [ api ] ) ;
8787
8888 return (
89- < section className = "relative z-10 text-white py-12 sm:py-16 -ms-4" >
90- < Container className = 'space-y-6 xl:space-x-0 mx-auto' >
89+ < section className = "relative z-10 text-white py-12 sm:py-16 -ms-4 lg:-ms-0 " >
90+ < Container className = 'space-y-6 xl:space-x-0 mx-auto lg:space-y-3 ' >
9191 { /* Combined container: Ratings + Button */ }
92- < div className = "flex flex-col space-y-5 xl:flex-row xl:items-center xl: justify-between px-[1%] 2xl:px-0 sm:pb-4" >
92+ < div className = "flex flex-col space-y-5 xl:flex-row xl:justify-between px-[1%] 2xl:px-0 sm:pb-4 lg:flex-row lg:px-14 " >
9393 { /* Logo & Ratings */ }
94- < div className = "flex flex-col items-center xl:items-start xl:text-left w-full" >
94+ < div className = "flex flex-col items-center xl:items-start xl:text-left w-full lg:items-start " >
9595 < div className = '-space-y-4' >
9696 < div className = "flex items-center gap-x-2" >
9797 < Image
@@ -126,7 +126,7 @@ export function Testimonials() {
126126 < Link href = "https://www.meetup.com/durianpy/" target = "_blank" >
127127 < Button
128128 variant = "footer"
129- className = "py-1 px-4 text-xs sm:py-1.5 sm:px-6 text-black sm:text-lg sm:font-normal"
129+ className = "py-1 px-4 text-xs sm:py-1.5 sm:px-6 text-black sm:text-lg sm:font-normal lg:mt-3 "
130130 >
131131 Write a Review
132132 </ Button >
@@ -137,14 +137,21 @@ export function Testimonials() {
137137 { /* CAROUSEL */ }
138138 < div >
139139 < Carousel
140+ setApi = { setApi }
140141 opts = { { loop : true } }
141- className = 'max-w-96 sm:w-96 mx-auto'
142+ autoplay = { ! isInteracting }
143+ autoplayInterval = { 5000 }
144+ onClick = { ( ) => setIsInteracting ( true ) }
145+ onMouseLeave = { ( ) => setIsInteracting ( false ) }
146+ className = 'max-w-96 sm:w-96 lg:max-w-full lg:w-full lg:px-5 mx-auto bg-red-300'
142147 >
143- < CarouselContent className = 'flex mx-auto sm:-ms-4' >
148+ < CarouselContent className = 'flex mx-auto sm:-ms-4 lg:-ms-0 lg:py-8 ' >
144149 { dummyData . map ( ( data , index ) => (
145- < CarouselItem className = "flex-col justify-center lg:basis-1/3" key = { index } >
146- < TestimonialCard text = { data . comment } rate = { data . rate } />
147- < div className = 'flex justify-center items-center space-x-3 mt-4 sm:mt-2 sm:-ms-16' >
150+ < CarouselItem className = "flex-col justify-center lg:basis-1/3 lg:px-11" key = { index } >
151+ < TestimonialCard text = { data . comment } rate = { data . rate } active = { current === index ? true : false } />
152+ < div
153+ className = { current === index ? "flex justify-center items-center space-x-3 mt-4 sm:mt-2 sm:-ms-16 lg:-ms-5 lg:scale-125 lg:mt-12 transition-all duration-300 ease-in-out" : "flex justify-center items-center space-x-3 mt-4 sm:mt-2 sm:-ms-16 lg:-ms-0 lg:mb-12 transition-all duration-300 ease-in-out" }
154+ >
148155 < Avatar className = 'h-16 w-16' >
149156 < AvatarImage src = { data . profilePic } />
150157 < AvatarFallback className = 'text-2xl text-[#B3B3B3]' > { data . name . split ( ' ' ) . map ( word => word [ 0 ] ) . join ( '' ) . toUpperCase ( ) } </ AvatarFallback >
@@ -157,29 +164,29 @@ export function Testimonials() {
157164 </ CarouselItem >
158165 ) ) }
159166 </ CarouselContent >
160- < CarouselPrevious className = 'hidden sm:block absolute -left-24 h-20 w-20 -mt-4' />
161- < CarouselNext className = 'hidden sm:block absolute -right-24 h-20 w-20 -mt-4' />
167+ < CarouselPrevious className = 'hidden sm:block absolute -left-24 h-20 w-20 -mt-[5%] lg:-left-6 lg:h-20 lg:w-20' onClick = { ( ) => api ?. scrollTo ( current - 1 ) } />
168+ < CarouselNext className = 'hidden sm:block absolute -right-24 h-20 w-20 -mt-[5%] lg:-right-6 lg:h-20 lg:w-20' onClick = { ( ) => api ?. scrollTo ( current + 1 ) } />
162169 < CarouselDots className = 'pt-5' />
163170 </ Carousel >
164171 </ div >
165172 </ Container >
166- </ section >
173+ </ section >
167174 ) ;
168175}
169176
170- export function TestimonialCard ( { text, rate } : TestimonialProps ) {
177+ export function TestimonialCard ( { text, rate, active } : TestimonialProps ) {
171178 const starRate = [ ] ;
172179
173180 // Append stars
174181 for ( let i = 0 ; i < 5 ; i ++ ) {
175182 // If index is greater than the rating, append white star, else yellow star.
176183 if ( i >= rate ) {
177184 starRate . push (
178- < Image src = { WhiteStar } alt = "yellow star" key = { i } className = "" />
185+ < Image src = { WhiteStar } alt = "yellow star" key = { i } className = "lg:p-1 " />
179186 ) ;
180187 } else {
181188 starRate . push (
182- < Image src = { YellowStar } alt = "yellow star" key = { i } className = "" />
189+ < Image src = { YellowStar } alt = "yellow star" key = { i } className = "lg:p-1 " />
183190 ) ;
184191 }
185192 }
@@ -196,12 +203,12 @@ export function TestimonialCard({ text, rate }: TestimonialProps) {
196203
197204
198205 { /* Tablet & Laptop View Display */ }
199- < div className = ' hidden sm:block relative' >
206+ < div className = { active === true ? " hidden sm:block relative transition-all duration-300 ease-in-out lg:scale-125" : "hidden sm:block relative transition-all duration-300 ease-in-out" } >
200207 < Image src = { ChatBubble } alt = 'chat-bubble' />
201- < div className = 'flex absolute top-5 inset-x-0 justify-center space-x-2.5' > { starRate } </ div >
202- < div className = 'absolute top-16 mt-1 h-44 px-9 text-lg text-clip overflow-hidden' > { text } </ div >
203- < div className = 'absolute bottom-14 pb-2 pt-28 bg-gradient-to-t from-medium-dark-green from-25% inset-x-9' >
204- < a href = '' target = '_blank' className = 'text-[#B3B3B3] underline' > Read more</ a >
208+ < div className = 'flex absolute top-5 inset-x-0 justify-center space-x-2.5 lg:space-x-0.5 ' > { starRate } </ div >
209+ < div className = 'absolute top-16 mt-1 h-44 px-9 text-lg text-clip overflow-hidden lg:text-base lg:px-7 lg:h-1/3 xl:h-1/2 ' > { text } </ div >
210+ < div className = 'absolute bottom-14 pb-2 pt-28 bg-gradient-to-t from-medium-dark-green from-25% inset-x-9 lg:inset-x-7 lg:bottom-10 ' >
211+ < a href = '' target = '_blank' className = 'text-[#B3B3B3] underline lg:text-xs ' > Read more</ a >
205212 </ div >
206213 </ div >
207214 </ >
0 commit comments