|
| 1 | +import { clsx } from "clsx" |
| 2 | +import Image from "next-image-export-optimizer" |
| 3 | + |
| 4 | +export interface TestimonialsProps extends React.HTMLAttributes<HTMLElement> {} |
| 5 | + |
| 6 | +interface Testimonial { |
| 7 | + quote: string |
| 8 | + author: { |
| 9 | + name: string |
| 10 | + role: string |
| 11 | + avatar: string |
| 12 | + } |
| 13 | +} |
| 14 | + |
| 15 | +const testimonials: Testimonial[] = [ |
| 16 | + { |
| 17 | + quote: |
| 18 | + "GraphQL has transformed how we build and scale our APIs at Netflix. By allowing our teams to fetch exactly the data they need, we've improved performance, reduced API complexity, and accelerated development cycles.", |
| 19 | + author: { |
| 20 | + name: "Saihajpreet Singh", |
| 21 | + role: "The Guild", |
| 22 | + avatar: "https://avatars.githubusercontent.com/u/44710980?v=4", |
| 23 | + }, |
| 24 | + }, |
| 25 | + { |
| 26 | + quote: |
| 27 | + "GraphQL has transformed how we build and scale our APIs at Netflix. By allowing our teams to fetch exactly the data they need, we've improved performance, reduced API complexity, and accelerated development cycles.", |
| 28 | + author: { |
| 29 | + name: "Saihajpreet Singh", |
| 30 | + role: "The Guild", |
| 31 | + avatar: "https://avatars.githubusercontent.com/u/44710980?v=4", |
| 32 | + }, |
| 33 | + }, |
| 34 | + { |
| 35 | + quote: |
| 36 | + "GraphQL has transformed how we build and scale our APIs at Netflix. By allowing our teams to fetch exactly the data they need, we've improved performance, reduced API complexity, and accelerated development cycles.", |
| 37 | + author: { |
| 38 | + name: "Saihajpreet Singh", |
| 39 | + role: "The Guild", |
| 40 | + avatar: "https://avatars.githubusercontent.com/u/44710980?v=4", |
| 41 | + }, |
| 42 | + }, |
| 43 | +] |
| 44 | + |
| 45 | +export function Testimonials({ className, ...rest }: TestimonialsProps) { |
| 46 | + return ( |
| 47 | + <section |
| 48 | + className={clsx( |
| 49 | + "gql-conf-container py-8 max-md:px-4 md:pb-16 md:pt-24 md:[mask-image:linear-gradient(to_right,transparent,black_5%,black_95%,transparent)]", |
| 50 | + className, |
| 51 | + )} |
| 52 | + {...rest} |
| 53 | + > |
| 54 | + <h2 className="text-center text-neu-800 typography-h2"> |
| 55 | + How was the previous edition? |
| 56 | + </h2> |
| 57 | + <div className="flex w-full snap-x snap-mandatory flex-row gap-10 overflow-x-auto px-4 py-6 lg:mt-16 lg:py-16"> |
| 58 | + {testimonials.map((testimonial, i) => ( |
| 59 | + <div |
| 60 | + key={i} |
| 61 | + className="flex shrink-0 snap-start flex-row-reverse items-center gap-6 max-md:flex-col md:px-10" |
| 62 | + > |
| 63 | + <div> |
| 64 | + <p className="max-w-[calc(100vw-16px)] typography-body-lg max-md:text-center md:max-w-[544px] xl:text-2xl"> |
| 65 | + {testimonial.quote} |
| 66 | + </p> |
| 67 | + <AuthorNameAndRole |
| 68 | + author={testimonial.author} |
| 69 | + className="mt-4 max-md:hidden" |
| 70 | + /> |
| 71 | + </div> |
| 72 | + <TestimonialAuthor author={testimonial.author} /> |
| 73 | + </div> |
| 74 | + ))} |
| 75 | + </div> |
| 76 | + </section> |
| 77 | + ) |
| 78 | +} |
| 79 | + |
| 80 | +function TestimonialAuthor({ author }: { author: Testimonial["author"] }) { |
| 81 | + return ( |
| 82 | + <div className="relative flex shrink-0 flex-col items-center justify-center whitespace-pre md:px-6 lg:h-full lg:px-8"> |
| 83 | + {/* todo: pink tint */} |
| 84 | + <Image |
| 85 | + src={author.avatar} |
| 86 | + alt={author.name} |
| 87 | + width={128} |
| 88 | + height={128} |
| 89 | + className="size-16 xl:size-32" |
| 90 | + /> |
| 91 | + <AuthorNameAndRole author={author} className="contents md:hidden" /> |
| 92 | + <div className="absolute inset-y-0 right-0 w-px bg-gradient-to-b from-transparent via-pri-lighter to-transparent max-md:hidden" /> |
| 93 | + </div> |
| 94 | + ) |
| 95 | +} |
| 96 | + |
| 97 | +function AuthorNameAndRole({ |
| 98 | + author, |
| 99 | + className, |
| 100 | +}: { |
| 101 | + author: Testimonial["author"] |
| 102 | + className?: string |
| 103 | +}) { |
| 104 | + return ( |
| 105 | + <div className={className}> |
| 106 | + <div className="mt-3 typography-body-sm">{author.name}</div> |
| 107 | + <div className="text-neu-700 typography-body-xs">{author.role}</div> |
| 108 | + </div> |
| 109 | + ) |
| 110 | +} |
0 commit comments