HeroSplitDark Hero
Donkere split-hero: tekstpaneel met kicker, accent-kop, sub en twee CTA's links; full-bleed beeld met caption rechts.
src/components/hero/HeroSplitDark.astro
---
/**
* HeroSplitDark — donkere split-hero: links een tekstpaneel met kicker,
* statement-kop met accent-woord, sub en twee CTA's; rechts een full-bleed
* beeld met caption. Verticale marquee op de paneelgrens. Alleen dark.
*
* Props:
* - kicker?: string
* - headline?: string
* - accent?: string accent-woord binnen de kop (cursief gemarkeerd via <em>)
* - sub?: string
* - ctaPrimary?: { label: string; href: string }
* - ctaSecondary?: { label: string; href: string }
* - image?: string src van het rechterbeeld
* - imageAlt?: string
* - caption?: string caption-tekst rechtsonder op het beeld
* - marquee?: string tekst voor de verticale rand-marquee
*/
interface Props {
kicker?: string;
headline?: string;
accent?: string;
sub?: string;
ctaPrimary?: { label: string; href: string };
ctaSecondary?: { label: string; href: string };
image?: string;
imageAlt?: string;
caption?: string;
marquee?: string;
}
const {
kicker = 'Online Marketing Bureau',
headline = 'Resultaten die',
accent = 'spreken',
sub = 'Data-gedreven marketing zonder bullshit. Wij leveren ROAS, leads en groei, niet alleen rapporten.',
ctaPrimary = { label: 'Ontdek meer', href: '#' },
ctaSecondary = { label: 'Cases bekijken', href: '#' },
image = '/img/ext/photo-1504384308090-c894fdcc538d-w1200-7ef4c6.jpg',
imageAlt = 'Marketing resultaten',
caption = 'Gemiddeld 4.2× ROAS voor onze klanten',
marquee = 'Premium · Quality · Design · ',
} = Astro.props;
---
<section class:list={['bl-section', 'hsd']}>
<div class="bl-inner hsd-inner">
<!-- Left dark panel -->
<div class="hsd__left">
<div class="hsd__left-content">
{kicker && (
<p class="hsd__kicker">
<span class="hsd__kicker-line"></span>
{kicker}
</p>
)}
<h1 class="hsd__headline">{headline}{accent && <> <em>{accent}</em></>}</h1>
{sub && <p class="hsd__sub">{sub}</p>}
{(ctaPrimary || ctaSecondary) && (
<div class="hsd__actions">
{ctaPrimary && <a href={ctaPrimary.href} class="hsd__cta">{ctaPrimary.label}</a>}
{ctaSecondary && (
<a href={ctaSecondary.href} class="hsd__secondary">
{ctaSecondary.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>
)}
</div>
{marquee && (
<div class="hsd__v-label" aria-hidden="true">
<span class="hsd__v-label-track">
{Array.from({ length: 6 }).map(() => <span>{marquee}</span>)}
</span>
</div>
)}
</div>
<!-- Right image panel -->
<div class="hsd__right">
<div class="hsd__img-wrap">
{image && (
<img data-allow-img src={image} alt={imageAlt} class="hsd__img" loading="eager" fetchpriority="high" decoding="async" />
)}
<div class="hsd__vignette"></div>
</div>
{caption && (
<div class="hsd__caption">
<span class="hsd__caption-dot"></span>
{caption}
</div>
)}
</div>
</div>
</section>
<style>
.hsd{background:#080810;color:#e8e8e8;overflow:hidden}
.hsd-inner{display:grid;grid-template-columns:1fr 1fr;gap:0;align-items:stretch}
.hsd__left{display:flex;align-items:stretch;position:relative;overflow:hidden}
.hsd__left-content{flex:1;display:flex;flex-direction:column;justify-content:center;padding:5rem 4rem 5rem 0;max-width:580px}
.hsd__kicker{display:flex;align-items:center;gap:.875rem;font-size:.75rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#999;margin-bottom:1.75rem;animation:hsd-fade-up .5s .1s cubic-bezier(.22,1,.36,1) both}
.hsd__kicker-line{width:24px;height:1px;background:var(--color-accent, #6366f1);flex-shrink:0}
.hsd__headline{font-size:clamp(2.75rem, 5.5vw, 5rem);font-weight:900;line-height:.97;letter-spacing:-.045em;color:#fff;margin-bottom:1.5rem;animation:hsd-fade-up .7s .2s cubic-bezier(.22,1,.36,1) both}
.hsd__headline em{font-style:normal;color:var(--color-accent, #6366f1)}
.hsd__sub{font-size:1.0625rem;line-height:1.7;color:#aaa;max-width:40ch;margin-bottom:2.5rem;animation:hsd-fade-up .6s .35s cubic-bezier(.22,1,.36,1) both}
.hsd__actions{display:flex;align-items:center;gap:1.5rem;animation:hsd-fade-up .6s .45s cubic-bezier(.22,1,.36,1) both}
.hsd__cta{display:inline-flex;align-items:center;background:#fff;color:#080810;padding:.9375rem 2rem;border-radius:var(--radius, .5rem);font-weight:800;font-size:.9375rem;text-decoration:none;transition:background .2s,transform .2s}
.hsd__cta:hover{background:var(--color-accent, #6366f1);color:#fff;transform:translateY(-2px)}
.hsd__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}
.hsd__secondary:hover{color:#fff;gap:.65rem}
.hsd__v-label{width:32px;display:flex;align-items:center;justify-content:center;border-left:1px solid rgba(255,255,255,.06);overflow:hidden;flex-shrink:0}
.hsd__v-label-track{display:flex;flex-direction:column;white-space:nowrap;font-size:.6875rem;letter-spacing:.12em;text-transform:uppercase;color:#666;writing-mode:vertical-lr;animation:hsd-scroll-up 20s linear infinite;gap:1rem}
.hsd__right{position:relative;background:#0d0d18;overflow:hidden;min-height:520px;animation:hsd-scale-in 1s .1s cubic-bezier(.22,1,.36,1) both}
.hsd__img-wrap{position:absolute;inset:0}
.hsd__img{width:100%;height:100%;object-fit:cover;display:block;opacity:.85;mix-blend-mode:luminosity}
.hsd__right:hover .hsd__img{mix-blend-mode:normal;transition:mix-blend-mode 0s}
.hsd__vignette{position:absolute;inset:0;background:linear-gradient(to right,#080810 0%,transparent 20%),linear-gradient(to top,#080810 0%,transparent 20%);pointer-events:none}
.hsd__caption{position:absolute;bottom:1.5rem;right:1.5rem;z-index:1;display:flex;align-items:center;gap:.5rem;font-size:.8125rem;color:#aaa;letter-spacing:.05em}
.hsd__caption-dot{width:6px;height:6px;border-radius:50%;background:var(--color-accent, #6366f1);flex-shrink:0}
@keyframes hsd-fade-up{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@keyframes hsd-scale-in{from{opacity:0;transform:scale(1.04)}to{opacity:1;transform:none}}
@keyframes hsd-scroll-up{from{transform:translateY(0)}to{transform:translateY(-50%)}}
@media (max-width: 768px){
.hsd__kicker,.hsd__headline,.hsd__sub,.hsd__actions,.hsd__right,.hsd__v-label-track{animation:none}
.hsd-inner{grid-template-columns:1fr}
.hsd__right{height:55vw;min-height:280px;order:-1}
.hsd__v-label{display:none}
.hsd__left-content{padding:3rem 0;max-width:none}
}
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
kicker | string | 'Online Marketing Bureau' | Kicker-label boven de kop |
headline | string | 'Resultaten die' | H1-kop |
accent | string | 'spreken' | Accent-woord (gekleurd) binnen de kop |
sub | string | - | Ondertitel |
ctaPrimary | { label: string; href: string } | - | Primaire CTA-knop |
ctaSecondary | { label: string; href: string } | - | Secundaire tekst-CTA met pijl |
image | string | - | Src van het rechterbeeld |
imageAlt | string | - | Alt-tekst van het beeld |
caption | string | - | Caption rechtsonder op het beeld |
marquee | string | - | Tekst voor de verticale rand-marquee |
* = verplicht