HeroTypography Hero
Typografische statement-hero: pill-label, drie-regelige kop met outline- en gradient-accent, lijn, sub + CTA en een ticker.
src/components/hero/HeroTypography.astro
---
/**
* HeroTypography — typografische statement-hero: pill-label, drie-regelige kop
* (middelste regel als outline), scheidingslijn, sub + CTA, en een doorlopende
* ticker onderaan. Light (wit) of dark.
*
* Props:
* - label?: string pill-label boven de kop
* - line1?: string eerste kop-regel
* - line2?: string middelste kop-regel (outline-stijl)
* - line3?: string derde kop-regel (gradient-accent)
* - sub?: string
* - cta?: { label: string; href: string }
* - ticker?: string[] woorden voor de lopende ticker onderaan
* - theme?: 'light' | 'dark' default 'light'
*/
interface Props {
label?: string;
line1?: string;
line2?: string;
line3?: string;
sub?: string;
cta?: { label: string; href: string };
ticker?: string[];
theme?: 'light' | 'dark';
}
const {
label = 'Online Marketing Bureau',
line1 = 'Wij maken',
line2 = 'marketing',
line3 = 'die werkt.',
sub = 'Data-gedreven campagnes voor ambitieuze Nederlandse bedrijven.',
cta = { label: 'Start vandaag', href: '#' },
ticker = ['Google Ads', 'Meta Ads', 'SEO', 'LinkedIn', 'TikTok', 'Analytics', 'Conversie'],
theme = 'light',
} = Astro.props;
// Ticker tweemaal renderen voor een naadloze loop.
const tickerLoop = [...ticker, ...ticker];
---
<section class:list={['bl-section', 'htg__root', `htg__root--${theme === 'dark' ? 'dark' : 'white'}`]} aria-label="Hero">
<div class="bl-inner htg__container">
{label && (
<div class="htg__pre-wrap">
<span class="htg__pre-label">{label}</span>
</div>
)}
<div class="htg__headline-block">
{line1 && <span class="htg__line htg__line--1">{line1}</span>}
{line2 && <span class="htg__line htg__line--2" aria-hidden="true">{line2}</span>}
{line3 && <span class="htg__line htg__line--3">{line3}</span>}
</div>
<div class="htg__rule-wrap" aria-hidden="true">
<div class="htg__rule"></div>
</div>
{(sub || cta) && (
<div class="htg__footer">
{sub && <p class="htg__sub">{sub}</p>}
{cta && <a href={cta.href} class="htg__cta">{cta.label}</a>}
</div>
)}
</div>
{tickerLoop.length > 0 && (
<div class="htg__ticker-track" aria-hidden="true">
<div class="htg__ticker-inner">
{tickerLoop.map((item) => (
<span class="htg__ticker-item">
{item}
<span class="htg__ticker-sep" aria-hidden="true">-</span>
</span>
))}
</div>
</div>
)}
</section>
<style>
.htg__root{position:relative;width:100%;min-height:100svh;display:flex;flex-direction:column;justify-content:center;overflow:hidden;padding-block:0}
.htg__root--white{background:var(--color-bg, #fff);--htg-text: var(--color-primary, #0a0a0a);--htg-muted: #6b7280;--htg-stroke: var(--color-primary, #0a0a0a);--htg-rule: var(--color-primary, #0a0a0a);--htg-pre-bg: rgba(10, 10, 10, .07);--htg-pre-color: var(--color-primary, #0a0a0a);--htg-ticker-bg: var(--color-primary, #0a0a0a);--htg-ticker-color: #fff}
.htg__root--light{background:#f5f5f7;--htg-text: var(--color-primary, #0a0a0a);--htg-muted: #6b7280;--htg-stroke: var(--color-primary, #0a0a0a);--htg-rule: var(--color-primary, #0a0a0a);--htg-pre-bg: rgba(10, 10, 10, .07);--htg-pre-color: var(--color-primary, #0a0a0a);--htg-ticker-bg: var(--color-primary, #0a0a0a);--htg-ticker-color: #fff}
.htg__root--dark{background:var(--color-primary, #0a0a0a);--htg-text: #fff;--htg-muted: #aaa;--htg-stroke: #fff;--htg-rule: rgba(255, 255, 255, .2);--htg-pre-bg: rgba(255, 255, 255, .1);--htg-pre-color: #e8e8e8;--htg-ticker-bg: #fff;--htg-ticker-color: var(--color-primary, #0a0a0a)}
.htg__container{padding-block:clamp(5rem, 5vw, 5rem) clamp(3rem,6vw,5rem);display:flex;flex-direction:column;gap:2.5rem}
.htg__pre-wrap{animation:htg-fadein .6s cubic-bezier(.16,1,.3,1) both}
.htg__pre-label{display:inline-block;font-size:.8125rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;background:var(--htg-pre-bg);color:var(--htg-pre-color);padding:.35rem .875rem;border-radius:999px}
.htg__headline-block{display:flex;flex-direction:column;gap:0;line-height:1;letter-spacing:-.04em}
.htg__line{display:block;font-weight:900;font-size:clamp(4rem, 5vw, 5rem)}
.htg__line--1{color:var(--htg-text);animation:htg-fadein .7s .1s cubic-bezier(.16,1,.3,1) both}
.htg__line--2{color:transparent;-webkit-text-stroke:2px var(--htg-stroke);text-stroke:2px var(--htg-stroke);animation:htg-fadein .7s .2s cubic-bezier(.16,1,.3,1) both}
.htg__line--3{background:linear-gradient(90deg,var(--color-accent, #6366f1) 0%,#a855f7 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:var(--color-accent, #6366f1);animation:htg-fadein .7s .3s cubic-bezier(.16,1,.3,1) both}
.htg__rule-wrap{overflow:hidden;animation:htg-fadein .5s .5s both}
.htg__rule{height:1px;background:var(--htg-rule);width:100%;transform-origin:left;animation:htg-scalex .8s .55s cubic-bezier(.16,1,.3,1) both}
.htg__footer{display:flex;flex-wrap:wrap;align-items:center;gap:2rem;animation:htg-fadein .6s .7s cubic-bezier(.16,1,.3,1) both}
.htg__sub{font-size:clamp(1.0625rem,1.3vw,1.125rem);color:var(--htg-muted);line-height:1.65;margin:0;max-width:48ch;flex:1 1 280px}
.htg__cta{display:inline-flex;align-items:center;gap:.5rem;background:var(--color-accent, #6366f1);color:#fff;text-decoration:none;font-weight:600;font-size:.9375rem;padding:.875rem 1.875rem;border-radius:var(--radius, .5rem);white-space:nowrap;flex-shrink:0;transition:opacity .2s,transform .2s}
.htg__cta:hover{opacity:.88;transform:translateY(-1px)}
.htg__ticker-track{background:var(--htg-ticker-bg);overflow:hidden;padding:.875rem 0;width:100%;margin-top:auto}
.htg__ticker-inner{display:flex;width:max-content;animation:htg-ticker 20s linear infinite;will-change:transform}
.htg__ticker-item{display:inline-flex;align-items:center;gap:.875rem;font-size:clamp(.875rem,1.1vw,1rem);font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--htg-ticker-color);padding:0 1rem;white-space:nowrap}
.htg__ticker-sep{opacity:.35}
@keyframes htg-fadein{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@keyframes htg-scalex{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes htg-ticker{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (max-width: 768px){
.htg__line--2{-webkit-text-stroke-width:1.5px}
.htg__footer{flex-direction:column;align-items:flex-start;gap:1.25rem}
}
</style>
Props
| Prop | Type | Default | Beschrijving |
|---|---|---|---|
label | string | 'Online Marketing Bureau' | Pill-label boven de kop |
line1 | string | 'Wij maken' | Eerste kop-regel |
line2 | string | 'marketing' | Middelste kop-regel (outline-stijl) |
line3 | string | 'die werkt.' | Derde kop-regel (gradient-accent) |
sub | string | - | Ondertitel |
cta | { label: string; href: string } | - | CTA-knop |
ticker | string[] | - | Woorden voor de lopende ticker onderaan |
theme | 'light' | 'dark' | 'light' | Achtergrond-mode |
* = verplicht