1- " use client"
1+ ' use client' ;
22
33import { type CarouselApi } from '@/components/ui/carousel' ;
44
@@ -9,134 +9,206 @@ import {
99 CarouselDots ,
1010} from '@/components/ui/carousel' ;
1111import Image from 'next/image' ;
12- import testimonialCard from '@/public/assets/testimonials/testimonial-card.svg'
13- import yellowStarIcon from '@/public/assets/testimonials/yellow-star.svg'
14- import whiteStarIcon from '@/public/assets/testimonials/white-star.svg'
15- import nextArrowIcon from '@/public/assets/testimonials/next-arrow.svg'
16- import prevArrowIcon from '@/public/assets/testimonials/previous-arrow.svg'
17- import { Avatar , AvatarFallback , AvatarImage } from " @/components/ui/avatar"
12+ import testimonialCard from '@/public/assets/testimonials/testimonial-card.svg' ;
13+ import yellowStarIcon from '@/public/assets/testimonials/yellow-star.svg' ;
14+ import whiteStarIcon from '@/public/assets/testimonials/white-star.svg' ;
15+ import nextArrowIcon from '@/public/assets/testimonials/next-arrow.svg' ;
16+ import prevArrowIcon from '@/public/assets/testimonials/previous-arrow.svg' ;
17+ import { Avatar , AvatarFallback , AvatarImage } from ' @/components/ui/avatar' ;
1818import { useState } from 'react' ;
1919import { useEffect } from 'react' ;
2020import { cn } from '@/lib/utils' ;
2121
2222type testimonial = {
23- name : string
24- date : string
25- comment : string
26- rate : number
27- profilePic : string
28- className : string
29- }
23+ name : string ;
24+ date : string ;
25+ comment : string ;
26+ rate : number ;
27+ profilePic : string ;
28+ className : string ;
29+ } ;
3030
3131export function Testimonials ( ) {
3232 const dummyData = [
3333 {
34- "name" : "AlexByte_97" , "date" : "2 days ago" , "comment" : "I've been following similar content for a while, but this one really stands out. The attention to detail and the way everything is explained so clearly make it incredibly easy to understand. Honestly, I wish more people put this level of effort into their posts. Keep it up! Looking forward to more amazing content like this! ????" ,
35- "rate" : 5 , "profilePic" : "https://github.com/shadcn.png"
34+ name : 'AlexByte_97' ,
35+ date : '2 days ago' ,
36+ comment :
37+ "I've been following similar content for a while, but this one really stands out. The attention to detail and the way everything is explained so clearly make it incredibly easy to understand. Honestly, I wish more people put this level of effort into their posts. Keep it up! Looking forward to more amazing content like this! ????" ,
38+ rate : 5 ,
39+ profilePic : 'https://github.com/shadcn.png' ,
3640 } ,
37- { "name" : "GamerXtreme" , "date" : "3 weeks ago" , "comment" : "Not bad, but I expected a bit more tbh. ??" , "rate" : 3 , "profilePic" : "https://github.com/shadcn.png" } ,
38- { "name" : "TechieTasha" , "date" : "5 days ago" , "comment" : "Super useful, definitely sharing this! ??" , "rate" : 4 , "profilePic" : "https://github.com/shadcn.png" } ,
39- { "name" : "MemeLord420" , "date" : "1 month ago" , "comment" : "Bro, this ain't it... ??" , "rate" : 2 , "profilePic" : "https://github.com/shadcn.png" } ,
4041 {
41- "name" : "NeonC0der" , "date" : "10 hours ago" , "comment" : "I appreciate the effort that went into this, but I feel like some parts could have been elaborated on a bit more. Certain sections were great, but others felt a little rushed. That being said, I still learned a lot and really enjoyed the overall message. Keep refining your style because you definitely have potential! Excited to see how your content evolves over time. ??" ,
42- "rate" : 4 , "profilePic" : "https://github.com/shadcn.png"
43- }
44- ]
42+ name : 'GamerXtreme' ,
43+ date : '3 weeks ago' ,
44+ comment : 'Not bad, but I expected a bit more tbh. ??' ,
45+ rate : 3 ,
46+ profilePic : 'https://github.com/shadcn.png' ,
47+ } ,
48+ {
49+ name : 'TechieTasha' ,
50+ date : '5 days ago' ,
51+ comment : 'Super useful, definitely sharing this! ??' ,
52+ rate : 4 ,
53+ profilePic : 'https://github.com/shadcn.png' ,
54+ } ,
55+ {
56+ name : 'MemeLord420' ,
57+ date : '1 month ago' ,
58+ comment : "Bro, this ain't it... ??" ,
59+ rate : 2 ,
60+ profilePic : 'https://github.com/shadcn.png' ,
61+ } ,
62+ {
63+ name : 'NeonC0der' ,
64+ date : '10 hours ago' ,
65+ comment :
66+ 'I appreciate the effort that went into this, but I feel like some parts could have been elaborated on a bit more. Certain sections were great, but others felt a little rushed. That being said, I still learned a lot and really enjoyed the overall message. Keep refining your style because you definitely have potential! Excited to see how your content evolves over time. ??' ,
67+ rate : 4 ,
68+ profilePic : 'https://github.com/shadcn.png' ,
69+ } ,
70+ ] ;
4571
46- const [ api , setApi ] = useState < CarouselApi > ( )
47- const [ current , setCurrent ] = useState ( 0 )
48- const [ isInteracting , setIsInteracting ] = useState ( false )
72+ const [ api , setApi ] = useState < CarouselApi > ( ) ;
73+ const [ current , setCurrent ] = useState ( 0 ) ;
74+ const [ isInteracting , setIsInteracting ] = useState ( false ) ;
4975
5076 useEffect ( ( ) => {
5177 if ( ! api ) {
52- return
78+ return ;
5379 }
5480
55- setCurrent ( api . selectedScrollSnap ( ) )
81+ setCurrent ( api . selectedScrollSnap ( ) ) ;
5682
57- api . on ( " select" , ( ) => {
58- setCurrent ( api . selectedScrollSnap ( ) )
59- } )
60- } , [ api ] )
83+ api . on ( ' select' , ( ) => {
84+ setCurrent ( api . selectedScrollSnap ( ) ) ;
85+ } ) ;
86+ } , [ api ] ) ;
6187
6288 return (
63- < section className = ' pt-10 pb-40 relative' >
89+ < section className = " pt-10 pb-40 relative" >
6490 { /* DurianPy Ratings */ }
65- < div className = '' >
66- DurianPy Ratings
67- </ div >
91+ < div className = "" > DurianPy Ratings</ div >
6892
6993 { /* Carousel */ }
70- < div className = 'relative' onClick = { ( ) => setIsInteracting ( true ) } onMouseLeave = { ( ) => setIsInteracting ( false ) } >
71- < button className = 'z-20 absolute left-0 md:left-8 bottom-1/2 bg-opacity-0' onClick = { ( ) => api ?. scrollTo ( current - 1 ) } >
72- < Image src = { prevArrowIcon } alt = 'Prev' className = 'w-2/3' />
94+ < div
95+ className = "relative"
96+ onClick = { ( ) => setIsInteracting ( true ) }
97+ onMouseLeave = { ( ) => setIsInteracting ( false ) }
98+ >
99+ < button
100+ className = "z-20 absolute left-0 md:left-8 bottom-1/2 bg-opacity-0"
101+ onClick = { ( ) => api ?. scrollTo ( current - 1 ) }
102+ >
103+ < Image src = { prevArrowIcon } alt = "Prev" className = "w-2/3" />
73104 </ button >
74- < CarouselContainer setApi = { setApi }
105+ < CarouselContainer
106+ setApi = { setApi }
75107 opts = { { loop : true } }
76108 autoplay = { ! isInteracting }
77109 autoplayInterval = { 5000 }
78110 className = "mx-auto px-[10%]"
79111 >
80- < CarouselContent className = ' mx-auto py-20' >
112+ < CarouselContent className = " mx-auto py-20" >
81113 { dummyData . map ( ( data , index ) => (
82- < CarouselItem className = "relative px-[3%] flex justify-center lg:basis-1/3" key = { index } >
83- < TestimonialCard name = { data . name } date = { data . date } comment = { data . comment } rate = { data . rate } profilePic = { data . profilePic } className = { current === index ? "sm:scale-110 sm:-mt-8" : "" } />
114+ < CarouselItem
115+ className = "relative px-[3%] flex justify-center lg:basis-1/3"
116+ key = { index }
117+ >
118+ < TestimonialCard
119+ name = { data . name }
120+ date = { data . date }
121+ comment = { data . comment }
122+ rate = { data . rate }
123+ profilePic = { data . profilePic }
124+ className = { current === index ? 'sm:scale-110 sm:-mt-8' : '' }
125+ />
84126 </ CarouselItem >
85127 ) ) }
86128 </ CarouselContent >
87129 < CarouselDots className = "z-10 absolute bottom-4 left-1/2 -translate-x-1/2 text-2xl py-4 text" />
88130 </ CarouselContainer >
89- < button className = 'z-20 absolute -right-3 md:right-8 bottom-1/2 bg-opacity-0' onClick = { ( ) => api ?. scrollTo ( current + 1 ) } >
90- < Image src = { nextArrowIcon } alt = 'Next' className = "w-2/3" />
131+ < button
132+ className = "z-20 absolute -right-3 md:right-8 bottom-1/2 bg-opacity-0"
133+ onClick = { ( ) => api ?. scrollTo ( current + 1 ) }
134+ >
135+ < Image src = { nextArrowIcon } alt = "Next" className = "w-2/3" />
91136 </ button >
92137 </ div >
93138 </ section >
94- )
139+ ) ;
95140}
96141
97142// Number of Stars depending on rating.
98143const Ratings = ( { rate } : { rate : number } ) => {
99- const starRate = [ ]
144+ const starRate = [ ] ;
100145
101146 // Append stars
102147 for ( let i = 0 ; i < 5 ; i ++ ) {
103148 // If index is greater than the rating, append white star, else yellow star.
104149 if ( i >= rate ) {
105- starRate . push ( < Image src = { whiteStarIcon } alt = 'yellow star' key = { i } className = 'p-1' /> )
150+ starRate . push (
151+ < Image src = { whiteStarIcon } alt = "yellow star" key = { i } className = "p-1" />
152+ ) ;
106153 } else {
107- starRate . push ( < Image src = { yellowStarIcon } alt = 'yellow star' key = { i } className = 'p-1' /> )
154+ starRate . push (
155+ < Image src = { yellowStarIcon } alt = "yellow star" key = { i } className = "p-1" />
156+ ) ;
108157 }
109158 }
110159
111160 return (
112- < div className = 'flex justify-center absolute top-[5%] left-1/2 -translate-x-1/2' > { starRate } </ div >
113- )
114- }
161+ < div className = "flex justify-center absolute top-[5%] left-1/2 -translate-x-1/2" >
162+ { starRate }
163+ </ div >
164+ ) ;
165+ } ;
115166
116- const TestimonialCard = ( { name, date, comment, rate, profilePic, className } : testimonial ) => {
167+ const TestimonialCard = ( {
168+ name,
169+ date,
170+ comment,
171+ rate,
172+ profilePic,
173+ className,
174+ } : testimonial ) => {
117175 return (
118- < div className = { cn ( 'transition-all duration-300 ease-in-out space-y-4' , className ) } >
176+ < div
177+ className = { cn (
178+ 'transition-all duration-300 ease-in-out space-y-4' ,
179+ className
180+ ) }
181+ >
119182 { /* SPEECH BUBBLE */ }
120- < div className = ' relative' >
121- < Image src = { testimonialCard } alt = ' testimonial card' priority = { true } />
183+ < div className = " relative" >
184+ < Image src = { testimonialCard } alt = " testimonial card" priority = { true } />
122185 < Ratings rate = { rate } />
123- < div className = ' absolute h-1/2 inset-y-1/4 px-[5%] text-white text-xs sm:text-base lg:text-base xl:text-lg overflow-hidden text-ellipsis xl:leading-6' >
186+ < div className = " absolute h-1/2 inset-y-1/4 px-[5%] text-white text-xs sm:text-base lg:text-base xl:text-lg overflow-hidden text-ellipsis xl:leading-6" >
124187 { comment }
125188 </ div >
126- < a href = '/404' target = '_blank' className = "absolute h-fit pt-[15%] px-[4%] inset-x-1 bottom-[24%] text-[#B3B3B3] underline underline-offset-2 decoration-1 text-xs sm:text-base bg-gradient-to-t from-medium-dark-green from-50% -mt-3" > Read More</ a >
189+ < a
190+ href = "/404"
191+ target = "_blank"
192+ className = "absolute h-fit pt-[15%] px-[4%] inset-x-1 bottom-[24%] text-[#B3B3B3] underline underline-offset-2 decoration-1 text-xs sm:text-base bg-gradient-to-t from-medium-dark-green from-50% -mt-3"
193+ >
194+ { ' ' }
195+ Read More
196+ </ a >
127197 </ div >
128198
129199 { /* USER AVATAR & NAME */ }
130- < div className = ' flex space-x-3 px-[17%] items-center' >
131- < Avatar className = ' h-full w-full max-h-14 max-w-14 sm:max-h-16 sm:max-w-16' >
200+ < div className = " flex space-x-3 px-[17%] items-center" >
201+ < Avatar className = " h-full w-full max-h-14 max-w-14 sm:max-h-16 sm:max-w-16" >
132202 < AvatarImage src = { profilePic } />
133203 < AvatarFallback > { name [ 0 ] } </ AvatarFallback >
134204 </ Avatar >
135205 < div >
136- < div className = "text-white text-xs sm:text-base lg:text-base xl:text-lg" > { name } </ div >
137- < div className = 'text-[#B3B3B3] text-xs xl:text-base' > { date } </ div >
206+ < div className = "text-white text-xs sm:text-base lg:text-base xl:text-lg" >
207+ { name }
208+ </ div >
209+ < div className = "text-[#B3B3B3] text-xs xl:text-base" > { date } </ div >
138210 </ div >
139211 </ div >
140212 </ div >
141- )
142- }
213+ ) ;
214+ } ;
0 commit comments