71 lines
2.2 KiB
TypeScript
71 lines
2.2 KiB
TypeScript
|
|
import React from "react";
|
||
|
|
import { motion } from "framer-motion";
|
||
|
|
import { Star } from "lucide-react";
|
||
|
|
|
||
|
|
interface PortfolioTestimonialProps {
|
||
|
|
logo: string | React.ReactNode; // can be an image URL or React component
|
||
|
|
alt?: string;
|
||
|
|
rating?: number; // default 5
|
||
|
|
testimonial: string;
|
||
|
|
clientName: string;
|
||
|
|
clientRole: string;
|
||
|
|
maxWidth?: string; // optional, e.g., "max-w-4xl"
|
||
|
|
}
|
||
|
|
|
||
|
|
const PortfolioTestimonial: React.FC<PortfolioTestimonialProps> = ({
|
||
|
|
logo,
|
||
|
|
alt = "Client Logo",
|
||
|
|
rating = 5,
|
||
|
|
testimonial,
|
||
|
|
clientName,
|
||
|
|
clientRole,
|
||
|
|
maxWidth = "max-w-4xl",
|
||
|
|
}) => {
|
||
|
|
return (
|
||
|
|
<section className="py-24 bg-card/30">
|
||
|
|
<div className="container mx-auto px-4 lg:px-6">
|
||
|
|
<motion.div
|
||
|
|
initial={{ opacity: 0, y: 30 }}
|
||
|
|
whileInView={{ opacity: 1, y: 0 }}
|
||
|
|
transition={{ duration: 0.8 }}
|
||
|
|
viewport={{ once: true }}
|
||
|
|
className={`mx-auto text-center ${maxWidth}`}
|
||
|
|
>
|
||
|
|
<div className="bg-card/50 rounded-2xl p-12 border border-border/50">
|
||
|
|
{/* Logo */}
|
||
|
|
{typeof logo === "string" ? (
|
||
|
|
<div className="flex justify-center mb-8">
|
||
|
|
<img src={logo} alt={alt} className="h-12 w-auto object-contain" />
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<div className="flex justify-center mb-8">{logo}</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Rating */}
|
||
|
|
<div className="flex justify-center mb-8">
|
||
|
|
<div className="flex text-yellow-400">
|
||
|
|
{[...Array(rating)].map((_, i) => (
|
||
|
|
<Star key={i} className="w-6 h-6 fill-current" />
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Testimonial */}
|
||
|
|
<blockquote className="text-2xl lg:text-3xl text-foreground mb-8 leading-relaxed italic">
|
||
|
|
{testimonial}
|
||
|
|
</blockquote>
|
||
|
|
|
||
|
|
{/* Client Info */}
|
||
|
|
<div className="flex flex-col items-center">
|
||
|
|
<div className="text-lg font-semibold text-foreground">{clientName}</div>
|
||
|
|
<div className="text-muted-foreground">{clientRole}</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</motion.div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default PortfolioTestimonial;
|