Zoeken...  ⌘K GitHub

TestimonialsCarousel Social Proof

Horizontaal scrollbare carousel van testimonials.

/testimonials-carousel
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