Testimonal 01
Testimonal 01 é um componente para React e Tailwind CSS, da biblioteca Eldora UI, com licença MIT. Copia e cola no teu projeto.
Eldora UI
MIT
other
O que é
Testimonal 01 é um componente para React e Tailwind CSS, da biblioteca Eldora UI, com licença MIT. Copia e cola no teu projeto.
Como usar
Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.
Cinco cópias grátis por mês. Sem cartão.
Precisa de
npm i react-icons/md
Licença
Este componente vem de Eldora UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.
Testimonal 01
import Image from "next/image"
import { MdOutlineFormatQuote } from "react-icons/md"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/registry/blocks/testimonal-01/components/carousel"
import Section from "@/registry/blocks/testimonal-01/components/section"
const companies = [
{
name: "Google",
url: "https://pub-b3533f2e1c954842824758490b95c9d5.r2.dev/Google.svg",
},
{
name: "GitHub",
url: "https://pub-b3533f2e1c954842824758490b95c9d5.r2.dev/GitHub.svg",
},
{
name: "Amazon",
url: "https://pub-b3533f2e1c954842824758490b95c9d5.r2.dev/Amazon.svg",
},
{
name: "Netflix",
url: "https://pub-b3533f2e1c954842824758490b95c9d5.r2.dev/Netflix.svg",
},
{
name: "YouTube",
url: "https://pub-b3533f2e1c954842824758490b95c9d5.r2.dev/YouTube.svg",
},
{
name: "Instagram",
url: "https://pub-b3533f2e1c954842824758490b95c9d5.r2.dev/Instagram.svg",
},
{
name: "Spotify",
url: "https://pub-b3533f2e1c954842824758490b95c9d5.r2.dev/Spotify.svg",
},
]
export default function Testimonal01Page() {
return (
<div className="flex min-h-svh w-full items-center justify-center p-6 md:p-10">
<div className="w-full max-w-sm md:max-w-3xl">
<Section
title="Testimonial Highlight"
subtitle="What our customers are saying"
>
<Carousel>
<div className="relative mx-auto max-w-2xl">
<CarouselContent>
{Array.from({ length: 7 }).map((_, index) => (
<CarouselItem key={index}>
<div className="p-2 pb-5">
<div className="text-center">
<MdOutlineFormatQuote className="text-themeDarkGray mx-auto my-4 text-4xl" />
<h4 className="text-1xl mx-auto max-w-lg px-10 font-semibold">
{getTestimonialQuote(index)}
</h4>
<div className="mt-8">
<Image
width={0}
height={40}
src={companies[index % companies.length].url}
alt={`${companies[index % companies.length].name} Logo`}
className="mx-auto h-[40px] w-auto"
/>
</div>
<div>
<h4 className="text-1xl my-2 font-semibold">
{getTestimonialName(index)}
</h4>
</div>
<div className="mb-3">
<span className="text-themeDarkGray text-sm">
{getTestimonialRole(index)}
</span>
</div>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<div className="from-background pointer-events-none absolute inset-y-0 left-0 h-full w-2/12 bg-gradient-to-r"></div>
<div className="from-background pointer-events-none absolute inset-y-0 right-0 h-full w-2/12 bg-gradient-to-l"></div>
</div>
<div className="hidden md:block">
<CarouselPrevious />
<CarouselNext />
</div>
</Carousel>
</Section>
</div>
</div>
)
}
function getTestimonialQuote(index: number): string {
const quotes = [
"eldora ui has revolutionized our security testing process. We're now able to identify and address vulnerabilities faster than ever before.",
"With eldora ui, we've significantly improved our security posture. It's like having an AI-powered ethical hacker working around the clock.",
"The AI-driven insights from eldora ui have transformed how we approach cybersecurity. It's a game-changer for our platform's security.",
"eldora ui's automated penetration testing has saved us countless hours and dramatically enhanced our security measures.",
"Implementing eldora ui was seamless, and the results were immediate. We're now proactively addressing potential security issues before they become threats.",
"The continuous monitoring capabilities of eldora ui give us peace of mind. We're always one step ahead in protecting our users' data.",
"eldora ui's compliance mapping feature has streamlined our security audit processes. It's an essential tool for maintaining trust with our users.",
]
return quotes[index % quotes.length]
}
function getTestimonialName(index: number): string {
const names = [
"Alex Rivera",
"Samantha Lee",
"Raj Patel",
"Emily Chen",
"Michael Brown",
"Linda Wu",
"Carlos Gomez",
]
return names[index % names.length]
}
function getTestimonialRole(index: number): string {
const roles = [
"Head of Cybersecurity",
"Chief Information Security Officer",
"VP of Engineering",
"Security Operations Manager",
"Director of IT Security",
"Lead Security Architect",
"Chief Technology Officer",
]
return roles[index % roles.length]
}
"use client"
import * as React from "react"
import useEmblaCarousel, {
type UseEmblaCarouselType,
} from "embla-carousel-react"
import { ArrowLeft, ArrowRight } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
type CarouselApi = UseEmblaCarouselType[1]
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
type CarouselOptions = UseCarouselParameters[0]
type CarouselPlugin = UseCarouselParameters[1]
interface CarouselProps {
opts?: CarouselOptions
plugins?: CarouselPlugin
orientation?: "horizontal" | "vertical"
setApi?: (api: CarouselApi) => void
}
type CarouselContextProps = {
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
api: ReturnType<typeof useEmblaCarousel>[1]
scrollPrev: () => void
scrollNext: () => void
canScrollPrev: boolean
canScrollNext: boolean
} & CarouselProps
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
function useCarousel() {
const context = React.useContext(CarouselContext)
if (!context) {
throw new Error("useCarousel must be used within a <Carousel />")
}
return context
}
const Carousel = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & CarouselProps
>(
(
{
orientation = "horizontal",
opts,
setApi,
plugins,
className,
children,
...props
},
ref
) => {
const [carouselRef, api] = useEmblaCarousel(
{
...opts,
axis: orientation === "horizontal" ? "x" : "y",
},
plugins
)
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
const [canScrollNext, setCanScrollNext] = React.useState(false)
const onSelect = React.useCallback((api: CarouselApi) => {
if (!api) {
return
}
setCanScrollPrev(api.canScrollPrev())
setCanScrollNext(api.canScrollNext())
}, [])
const scrollPrev = React.useCallback(() => {
api?.scrollPrev()
}, [api])
const scrollNext = React.useCallback(() => {
api?.scrollNext()
}, [api])
const handleKeyDown = React.useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "ArrowLeft") {
event.preventDefault()
scrollPrev()
} else if (event.key === "ArrowRight") {
event.preventDefault()
scrollNext()
}
},
[scrollPrev, scrollNext]
)
React.useEffect(() => {
if (!api || !setApi) {
return
}
setApi(api)
}, [api, setApi])
React.useEffect(() => {
if (!api) {
return
}
onSelect(api)
api.on("reInit", onSelect)
api.on("select", onSelect)
return () => {
api?.off("select", onSelect)
}
}, [api, onSelect])
return (
<CarouselContext.Provider
value={{
carouselRef,
api,
opts,
orientation:
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
scrollPrev,
scrollNext,
canScrollPrev,
canScrollNext,
}}
>
<div
ref={ref}
onKeyDownCapture={handleKeyDown}
className={cn("relative", className)}
role="region"
aria-roledescription="carousel"
{...props}
>
{children}
</div>
</CarouselContext.Provider>
)
}
)
Carousel.displayName = "Carousel"
const CarouselContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const { carouselRef, orientation } = useCarousel()
return (
<div ref={carouselRef} className="overflow-hidden">
<div
ref={ref}
className={cn(
"flex",
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
className
)}
{...props}
/>
</div>
)
})
CarouselContent.displayName = "CarouselContent"
const CarouselItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const { orientation } = useCarousel()
return (
<div
ref={ref}
role="group"
aria-roledescription="slide"
className={cn(
"min-w-0 shrink-0 grow-0 basis-full",
orientation === "horizontal" ? "pl-4" : "pt-4",
className
)}
{...props}
/>
)
})
CarouselItem.displayName = "CarouselItem"
const CarouselPrevious = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute size-8 rounded-full",
orientation === "horizontal"
? "bottom-0 left-1/2 -translate-x-16 translate-y-4"
: "-top-12 right-1/2 -translate-x-1/2 rotate-90",
className
)}
disabled={!canScrollPrev}
onClick={scrollPrev}
{...props}
>
<ArrowLeft className="size-4" />
<span className="sr-only">Previous slide</span>
</Button>
)
})
CarouselPrevious.displayName = "CarouselPrevious"
const CarouselNext = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollNext, canScrollNext } = useCarousel()
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute size-8 rounded-full",
orientation === "horizontal"
? "right-1/2 bottom-0 translate-x-16 translate-y-4"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
className
)}
disabled={!canScrollNext}
onClick={scrollNext}
{...props}
>
<ArrowRight className="size-4" />
<span className="sr-only">Next slide</span>
</Button>
)
})
CarouselNext.displayName = "CarouselNext"
export {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
type CarouselApi,
}
interface SectionProps {
id?: string
title?: string
subtitle?: string
description?: string
children?: React.ReactNode
className?: string
}
export default function Section({
id,
title,
subtitle,
description,
children,
className,
}: SectionProps) {
const sectionId = title ? title.toLowerCase().replace(/\s+/g, "-") : id
return (
<section id={id || sectionId}>
<div className={className}>
<div className="relative container mx-auto max-w-7xl px-4 py-16">
<div className="mx-auto space-y-4 pb-6 text-center">
{title && (
<h2 className="text-primary font-mono text-sm font-medium tracking-wider uppercase">
{title}
</h2>
)}
{subtitle && (
<h3 className="mx-auto mt-4 max-w-xs text-3xl font-semibold sm:max-w-none sm:text-4xl md:text-5xl">
{subtitle}
</h3>
)}
{description && (
<p className="mx-auto mt-6 max-w-2xl text-lg leading-8 text-slate-600">
{description}
</p>
)}
</div>
{children}
</div>
</div>
</section>
)
}