Blocks

Testimonial 26

card
2 ColumnsText Align CenterText Align LeftAvatar ImageStar RatingReviews Section
Testimonial 26

Code

relume-testimonial26.tsx
import { Card } from "@/components/ui/card";
import { StarFull } from "relume-icons";

type ImageProps = {
  src: string;
  alt?: string;
};

type Testimonial = {
  quote: string;
  avatar: ImageProps;
  name: string;
  position: string;
  companyName: string;
  numberOfStars: number;
};

type Props = {
  heading: string;
  description: string;
  testimonials: Testimonial[];
};

export type Testimonial26Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;

export const Testimonial26 = (props: Testimonial26Props) => {
  const { heading, description, testimonials } = {
    ...Testimonial26Defaults,
    ...props,
  };
  return (
    <section className="px-[5%] py-16 md:py-24 lg:py-28">
      <div className="container">
        <div className="mx-auto mb-12 w-full max-w-lg text-center md:mb-18 lg:mb-20">
          <h2 className="mb-5 text-h2 font-bold md:mb-6">{heading}</h2>
          <p className="text-medium">{description}</p>
        </div>
        <div className="columns-1 gap-x-8 after:block md:columns-2">
          {testimonials.map((testimonial, index) => (
            <Card
              key={index}
              className="mb-8 flex w-full break-inside-avoid flex-col items-start justify-between p-6 md:p-8"
            >
              <div className="mb-5 flex gap-1 md:mb-6">
                {Array(testimonial.numberOfStars)
                  .fill(null)
                  .map((_, starIndex) => (
                    <StarFull key={starIndex} className="size-6 text-scheme-text" />
                  ))}
              </div>
              <h5 className="text-medium">{testimonial.quote}</h5>
              <div className="mt-5 flex w-full flex-col items-start md:mt-6 md:w-fit md:flex-row md:items-center">
                <div>
                  <img
                    src={testimonial.avatar.src}
                    alt={testimonial.avatar.alt}
                    className="mb-4 size-12 min-h-12 min-w-12 rounded-full object-cover md:mr-4 md:mb-0"
                  />
                </div>
                <div>
                  <p className="font-semibold">{testimonial.name}</p>
                  <p>
                    <span>{testimonial.position}</span>, <span>{testimonial.companyName}</span>
                  </p>
                </div>
              </div>
            </Card>
          ))}
        </div>
      </div>
    </section>
  );
};

const testimonial1 = {
  quote:
    '"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare."',
  avatar: {
    src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
    alt: "Testimonial avatar 1",
  },
  name: "Name Surname",
  position: "Position",
  companyName: "Company name",
  numberOfStars: 5,
};

const testimonial2 = {
  quote:
    '"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat."',
  avatar: {
    src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
    alt: "Testimonial avatar 1",
  },
  name: "Name Surname",
  position: "Position",
  companyName: "Company name",
  numberOfStars: 5,
};

export const Testimonial26Defaults: Props = {
  heading: "Customer testimonials",
  description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
  testimonials: [
    testimonial1,
    testimonial1,
    testimonial1,
    testimonial2,
    testimonial2,
    testimonial1,
  ],
};

npm i @radix-ui/react-dialog @radix-ui/react-slot class-variance-authority@0.7.1 clsx@^2.1.1 embla-carousel-react@^8.5.2 motion@^12.15.0 relume-icons@1.3.0 tailwind-merge@^2.2.2