Zoeken...  ⌘K GitHub

HeroFloatingTestimonial Hero

Hero met tekstkolom links (badge, kop met cursief accent, sub, twee CTA's) en rechts een beeld met een zwevende testimonial-card.

/hero-floating-testimonial
src/components/hero/HeroFloatingTestimonial.astro
---
/**
 * HeroFloatingTestimonial
 * Hero met tekstkolom links (badge, kop met cursief accent, sub, twee CTA's)
 * en rechts een beeld met een zwevende testimonial-card (quote + auteur).
 *
 * Props: zie interface. Alle copy is prop-driven.
 */
interface Props {
  badge?: string;
  headline: string;
  accent?: string;
  sub?: string;
  primaryCta?: { label: string; href: string };
  ghostCta?: { label: string; href: string };
  image?: { src: string; alt?: string };
  testimonial?: { quote: string; author: string; role?: string };
}

const {
  badge,
  headline,
  accent,
  sub,
  primaryCta,
  ghostCta,
  image,
  testimonial,
} = Astro.props;
---

<section class:list={['bl-section', 'hft']} data-component="hero-floating-testimonial">
  <div class="bl-inner hft__inner">
    <div class="hft__content">
      {badge && <span class="hft__badge">{badge}</span>}
      <h1 class="hft__headline">{headline}{accent && <em> {accent}</em>}</h1>
      {sub && <p class="hft__sub">{sub}</p>}
      {(primaryCta || ghostCta) && (
        <div class="hft__ctas">
          {primaryCta && <a href={primaryCta.href} class="hft__cta hft__cta--primary">{primaryCta.label}</a>}
          {ghostCta && <a href={ghostCta.href} class="hft__cta hft__cta--ghost">{ghostCta.label}</a>}
        </div>
      )}
    </div>
    {image && (
      <div class="hft__visual">
        <div class="hft__img-wrap">
          <img data-allow-img src={image.src} alt={image.alt ?? ''} class="hft__img" loading="eager" fetchpriority="high" decoding="async" />
          {testimonial && (
            <div class="hft__testimonial">
              <svg class="hft__quote-icon" width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z"></path></svg>
              <p class="hft__testimonial-text">{testimonial.quote}</p>
              <div class="hft__testimonial-author">
                <div>
                  <div class="hft__author-name">{testimonial.author}</div>
                  {testimonial.role && <div class="hft__author-role">{testimonial.role}</div>}
                </div>
              </div>
            </div>
          )}
        </div>
      </div>
    )}
  </div>
</section>

<style>
.hft{background:var(--color-bg, #fff);overflow:hidden}
.hft__inner{display:grid;grid-template-columns:1fr 1fr;gap:4rem;align-items:center}
.hft__badge{display:inline-block;background:color-mix(in srgb,var(--color-accent, #6366f1) 12%,transparent);color:var(--color-accent, #6366f1);font-size:.75rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;padding:.35rem .85rem;border-radius:100px;margin-bottom:1.25rem}
.hft__headline{font-size:clamp(2.25rem,4vw,3.5rem);font-weight:800;line-height:1.1;letter-spacing:-.03em;color:var(--color-primary, #0a0a0a);margin-bottom:1.25rem}
.hft__headline em{font-style:normal;color:var(--color-accent, #6366f1)}
.hft__sub{font-size:1.125rem;color:var(--color-muted, #6b7280);line-height:1.65;margin-bottom:2rem;max-width:42ch}
.hft__ctas{display:flex;gap:.75rem;flex-wrap:wrap}
.hft__cta{display:inline-flex;align-items:center;gap:.5rem;padding:.8125rem 1.75rem;border-radius:var(--radius, .5rem);font-size:.9375rem;font-weight:700;text-decoration:none;transition: opacity, transform, background-color, color, border-color, box-shadow, filter .2s}
.hft__cta--primary{background:var(--color-accent, #6366f1);color:#fff}
.hft__cta--primary:hover{filter:brightness(1.1);transform:translateY(-1px)}
.hft__cta--ghost{color:var(--color-primary, #0a0a0a);border:1.5px solid currentColor;opacity:.75}
.hft__cta--ghost:hover{opacity:1}
.hft__visual{position:relative}
.hft__img-wrap{position:relative;border-radius:calc(var(--radius, .5rem) * 2);overflow:visible}
.hft__img{width:100%;height:480px;object-fit:cover;border-radius:calc(var(--radius, .5rem) * 2);display:block}
.hft__testimonial{position:absolute;bottom:-2rem;left:-2.5rem;background:#fff;border:1px solid rgba(0,0,0,.07);border-radius:calc(var(--radius, .5rem) * 1.5);padding:1.25rem 1.5rem;max-width:300px;box-shadow:0 20px 40px #0000001a}
.hft__quote-icon{color:var(--color-accent, #6366f1);margin-bottom:.625rem;opacity:.7}
.hft__testimonial-text{font-size:.9375rem;line-height:1.6;color:var(--color-primary, #0a0a0a);margin-bottom:.875rem}
.hft__testimonial-author{display:flex;align-items:center;gap:.625rem}
.hft__author-name{font-size:.875rem;font-weight:700;color:var(--color-primary, #0a0a0a)}
.hft__author-role{font-size:.8125rem;color:var(--color-muted, #6b7280)}
@media (max-width:768px){
  .hft__inner{grid-template-columns:1fr;gap:2rem}
  .hft__testimonial{position:static;margin-top:1rem;max-width:100%}
  .hft__img{height:300px}
}
</style>

Props

Prop Type Default Beschrijving
badge string - Badge boven de kop
headline * string - H1-kop
accent string - Cursief accent direct na de kop
sub string - Ondertitel
primaryCta { label: string; href: string } - Primaire knop
ghostCta { label: string; href: string } - Ghost-knop
image { src: string; alt?: string } - Beeld rechts
testimonial { quote: string; author: string; role?: string } - Zwevende testimonial-card

* = verplicht