Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 1x 18x 90x | import React from 'react';
import { Star } from 'lucide-react';
interface TestimonialCardProps {
quote: string;
author: string;
role: string;
company: string;
avatarUrl?: string;
rating?: number;
}
const TestimonialCard: React.FC<TestimonialCardProps> = ({
quote,
author,
role,
company,
avatarUrl,
rating = 5,
}) => {
return (
<div className="flex flex-col p-6 bg-white dark:bg-gray-800 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-sm hover:shadow-md transition-shadow">
{/* Stars */}
<div className="flex gap-1 mb-4">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className={`h-5 w-5 ${
i < rating
? 'text-yellow-400 fill-yellow-400'
: 'text-gray-300 dark:text-gray-600'
}`}
/>
))}
</div>
{/* Quote */}
<blockquote className="flex-1 text-gray-700 dark:text-gray-300 mb-6 leading-relaxed">
"{quote}"
</blockquote>
{/* Author */}
<div className="flex items-center gap-3">
{avatarUrl ? (
<img
src={avatarUrl}
alt={author}
className="w-12 h-12 rounded-full object-cover"
/>
) : (
<div className="w-12 h-12 rounded-full bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<span className="text-lg font-semibold text-brand-600 dark:text-brand-400">
{author.charAt(0)}
</span>
</div>
)}
<div>
<div className="font-semibold text-gray-900 dark:text-white">{author}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
{role} at {company}
</div>
</div>
</div>
</div>
);
};
export default TestimonialCard;
|