Zoeken...  ⌘K GitHub

HeroDark Hero

Donkere fullscreen-hero met glow en grid: label-pill, kop met gradient-accent, sub, CTA + tekstlink en een stat-rij.

/hero-dark
src/components/hero/HeroDark.astro
---
/**
 * HeroDark
 * Donkere fullscreen-hero met glow, grid en grain: label-pill, kop met
 * gradient-accent, sub, primaire CTA + tekstlink, en een stat-rij. Centreert
 * binnen de pagina-rail (.bl-inner).
 *
 * Props: zie interface. Alle copy is prop-driven.
 */
interface Stat {
  value: string;
  label: string;
}
interface Props {
  label?: string;
  headline: string;
  accent?: string;
  sub?: string;
  primaryCta?: { label: string; href: string };
  secondaryCta?: { label: string; href: string };
  stats?: Stat[];
}

const {
  label,
  headline,
  accent,
  sub,
  primaryCta,
  secondaryCta,
  stats = [],
} = Astro.props;
---

<section class:list={['bl-section', 'hd']} data-component="hero-dark">
  <div class="hd__glow" aria-hidden="true"></div>
  <div class="hd__grid" aria-hidden="true"></div>
  <div class="hd__noise" aria-hidden="true"></div>
  <div class="bl-inner bl-inner--narrow hd__content">
    {label && (
      <div class="hd__label-wrap">
        <span class="hd__label">{label}</span>
      </div>
    )}
    <h1 class="hd__headline">{headline}{accent && <em> {accent}</em>}</h1>
    {sub && <p class="hd__sub">{sub}</p>}
    {(primaryCta || secondaryCta) && (
      <div class="hd__actions">
        {primaryCta && <a href={primaryCta.href} class="hd__cta">{primaryCta.label}</a>}
        {secondaryCta && (
          <a href={secondaryCta.href} class="hd__secondary">
            {secondaryCta.label}
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7h10M8 3l4 4-4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
          </a>
        )}
      </div>
    )}
    {stats.length > 0 && (
      <div class="hd__stats">
        {stats.map((stat) => (
          <div class="hd__stat">
            <span class="hd__stat-value">{stat.value}</span>
            <span class="hd__stat-label">{stat.label}</span>
          </div>
        ))}
      </div>
    )}
  </div>
  <div class="hd__corner hd__corner--tl" aria-hidden="true">
    <svg width="40" height="40" viewBox="0 0 40 40" fill="none"><path d="M0 20H20V0" stroke="rgba(255,255,255,0.15)" stroke-width="1"></path></svg>
  </div>
  <div class="hd__corner hd__corner--br" aria-hidden="true">
    <svg width="40" height="40" viewBox="0 0 40 40" fill="none"><path d="M40 20H20V40" stroke="rgba(255,255,255,0.15)" stroke-width="1"></path></svg>
  </div>
</section>

<style>
.hd{min-height:100vh;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#050508}
.hd__glow{position:absolute;width:80vw;height:80vw;max-width:900px;max-height:900px;background:radial-gradient(ellipse at center,rgba(99,102,241,.22) 0%,rgba(139,92,246,.12) 35%,transparent 65%);top:50%;left:50%;transform:translate(-50%,-50%);pointer-events:none;animation:hd-glow-pulse 8s ease-in-out infinite}
.hd__grid{position:absolute;inset:0;background-image:linear-gradient(rgba(255,255,255,.03) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.03) 1px,transparent 1px);background-size:64px 64px;pointer-events:none}
.hd__noise{position:absolute;inset:0;opacity:.04;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");background-size:256px;pointer-events:none}
.hd__content{position:relative;z-index:1;text-align:center;display:flex;flex-direction:column;align-items:center}
.hd__label-wrap{margin-bottom:2rem;animation:hd-fade-up .5s .1s cubic-bezier(.22,1,.36,1) both}
.hd__label{display:inline-flex;align-items:center;gap:.5rem;border:1px solid rgba(99,102,241,.4);background:#6366f114;padding:.375rem 1rem;border-radius:999px;font-size:.8125rem;font-weight:600;letter-spacing:.05em;color:#e8e8e8}
.hd__label:before{content:"";width:6px;height:6px;background:var(--color-accent, #6366f1);border-radius:50%;flex-shrink:0;animation:hd-pulse 2s ease-in-out infinite}
.hd__headline{font-size:clamp(3rem, 5vw, 5rem);font-weight:900;line-height:.95;letter-spacing:-.05em;color:#fff;margin-bottom:1.5rem;animation:hd-fade-up .7s .2s cubic-bezier(.22,1,.36,1) both}
.hd__headline em{font-style:normal;background:linear-gradient(135deg,#818cf8,#a78bfa,#c084fc);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.hd__sub{font-size:1.125rem;line-height:1.7;color:#aaa;max-width:48ch;margin-bottom:2.5rem;animation:hd-fade-up .6s .35s cubic-bezier(.22,1,.36,1) both}
.hd__actions{display:flex;align-items:center;gap:1.25rem;flex-wrap:wrap;justify-content:center;margin-bottom:3.5rem;animation:hd-fade-up .6s .45s cubic-bezier(.22,1,.36,1) both}
.hd__cta{display:inline-flex;align-items:center;background:var(--color-accent, #6366f1);color:#fff;padding:1rem 2.25rem;border-radius:var(--radius, .5rem);font-weight:700;font-size:.9375rem;text-decoration:none;box-shadow:0 0 40px #6366f14d;transition:transform .2s,box-shadow .2s}
.hd__cta:hover{transform:translateY(-3px);box-shadow:0 0 60px #6366f173}
.hd__secondary{display:inline-flex;align-items:center;gap:.4rem;font-size:.9375rem;font-weight:600;color:#aaa;text-decoration:none;transition:color .2s,gap .2s}
.hd__secondary:hover{color:#fff;gap:.65rem}
.hd__stats{display:flex;gap:3rem;padding-top:2.5rem;border-top:1px solid rgba(255,255,255,.07);flex-wrap:wrap;justify-content:center}
.hd__stat{display:flex;flex-direction:column;align-items:center;gap:.25rem;animation:hd-fade-up .5s cubic-bezier(.22,1,.36,1) both}
.hd__stat-value{font-size:2.25rem;font-weight:800;letter-spacing:-.04em;color:#fff;line-height:1}
.hd__stat-label{font-size:.875rem;color:#999;letter-spacing:.04em}
.hd__corner{position:absolute;pointer-events:none}
.hd__corner--tl{top:1.5rem;left:1.5rem}
.hd__corner--br{bottom:1.5rem;right:1.5rem}
@media (prefers-reduced-motion: reduce){
  .hd__label-wrap,.hd__headline,.hd__sub,.hd__actions,.hd__stat{animation:none}
  .hd__label:before{animation:none}
  .hd__glow{animation:none}
}
@media (max-width:640px){
  .hd__actions{flex-direction:column;width:100%}
  .hd__cta{width:100%;justify-content:center}
  .hd__stats{gap:2rem}
}
</style>

Props

Prop Type Default Beschrijving
label string - Label-pill boven de kop
headline * string - H1-kop
accent string - Gradient-accent direct na de kop
sub string - Ondertitel
primaryCta { label: string; href: string } - Primaire knop
secondaryCta { label: string; href: string } - Secundaire tekstlink
stats { value: string; label: string }[] - Stat-rij onderaan

* = verplicht