src/components/social-proof/TestimonialsCarousel.astro
---
/**
* TestimonialsCarousel
* Horizontale carousel van testimonials met CSS scroll snap.
*/
interface Props {
eyebrow?: string;
headline?: string;
testimonials: { quote: string; name: string; role: string; company?: string; avatar?: string; rating?: number }[];
bg?: 'white' | 'light' | 'dark';
}
const { eyebrow, headline, testimonials, bg = 'white' } = Astro.props;
---
<section class={`tc tc--${bg}`}>
<div class="tc-header">
{eyebrow && <span class="tc-eyebrow">{eyebrow}</span>}
{headline && <h2 class="tc-headline">{headline}</h2>}
</div>
<div class="tc-track">
{testimonials.map(t => (
<div class="tc-card">
{t.rating && (
<div class="tc-stars">
{Array.from({length: t.rating}).map(() => <span class="tc-star">★</span>)}
</div>
)}
<p class="tc-quote">"{t.quote}"</p>
<footer class="tc-footer">
{t.avatar && <img src={t.avatar} alt={t.name} class="tc-avatar" />}
<div>
<cite class="tc-name">{t.name}</cite>
<span class="tc-role">{t.role}{t.company && `, ${t.company}`}</span>
</div>
</footer>
</div>
))}
</div>
</section>
<style>
.tc { padding: 5rem 0; overflow: hidden; }
.tc--white { background: #fff; border-top: 1px solid #e5e7eb; }
.tc--light { background: #f8fafc; border-top: 1px solid #e5e7eb; }
.tc--dark { background: #0a0a0a; }
.tc-header { text-align: center; padding: 0 2rem; margin-bottom: 3rem; }
.tc-eyebrow { display: block; font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-accent,#6366f1); margin-bottom: 0.75rem; }
.tc-headline { font-size: clamp(1.75rem, 3.5vw, 2.5rem); font-weight: 900; letter-spacing: -0.04em; line-height: 1.15; margin: 0; }
.tc--white .tc-headline, .tc--light .tc-headline { color: #0a0a0a; }
.tc--dark .tc-headline { color: #fff; }
.tc-track { display: flex; gap: 1.5rem; overflow-x: auto; padding: 0.5rem 2rem 2rem; scroll-snap-type: x mandatory; scrollbar-width: none; -ms-overflow-style: none; }
.tc-track::-webkit-scrollbar { display: none; }
.tc-card { flex: 0 0 360px; scroll-snap-align: start; padding: 2rem; border-radius: 1rem; display: flex; flex-direction: column; gap: 1.25rem; }
.tc--white .tc-card { background: #f8fafc; border: 1px solid #e5e7eb; }
.tc--light .tc-card { background: #fff; border: 1px solid #e5e7eb; box-shadow: 0 2px 12px rgba(0,0,0,0.05); }
.tc--dark .tc-card { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.08); }
.tc-stars { display: flex; gap: 0.2rem; }
.tc-star { color: #f59e0b; font-size: 1rem; }
.tc-quote { font-size: 0.9375rem; line-height: 1.65; font-style: italic; margin: 0; flex: 1; }
.tc--white .tc-quote, .tc--light .tc-quote { color: #374151; }
.tc--dark .tc-quote { color: rgba(255,255,255,0.7); }
.tc-footer { display: flex; align-items: center; gap: 0.75rem; }
.tc-avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; }
.tc-name { display: block; font-size: 0.9375rem; font-weight: 700; font-style: normal; }
.tc--white .tc-name, .tc--light .tc-name { color: #0a0a0a; }
.tc--dark .tc-name { color: #fff; }
.tc-role { display: block; font-size: 0.8125rem; }
.tc--white .tc-role, .tc--light .tc-role { color: #6b7280; }
.tc--dark .tc-role { color: rgba(255,255,255,0.4); }
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
testimonials * | { quote: string; name: string; role: string; company?: string; avatar?: string; rating?: number }[] | — | Testimonials |
eyebrow | string | — | Eyebrow |
headline | string | — | Sectie headline |
bg | 'white' | 'light' | 'dark' | — | Achtergrond variant |
* = verplicht