Zoeken...  ⌘K GitHub

FeaturesHorizontal Sections

Alternerende horizontale feature rijen — afbeelding en tekst wisselen per rij.

/features-horizontal
src/components/sections/FeaturesHorizontal.astro
---
/**
 * FeaturesHorizontal
 * Alternating horizontale feature rijen: afbeelding + tekst, steeds wisselend.
 */
interface Feature {
  label?: string;
  headline: string;
  body: string;
  image: string;
  imageAlt?: string;
  ctaLabel?: string;
  ctaHref?: string;
}

interface Props {
  eyebrow?: string;
  headline?: string;
  features: Feature[];
}

const { eyebrow, headline, features = [] } = Astro.props;
---

<section class="fh" data-component="features-horizontal">
  {(eyebrow || headline) && (
    <div class="fh__header">
      {eyebrow && <p class="fh__eyebrow">{eyebrow}</p>}
      {headline && <h2 class="fh__title" set:html={headline} />}
    </div>
  )}

  <div class="fh__rows">
    {features.map((f, i) => (
      <div class:list={['fh__row', { 'fh__row--reversed': i % 2 !== 0 }]}>
        <div class="fh__row-img">
          <img src={f.image} alt={f.imageAlt ?? ''} loading="lazy" />
        </div>
        <div class="fh__row-text">
          {f.label && <span class="fh__label">{f.label}</span>}
          <h3 class="fh__row-headline" set:html={f.headline} />
          <p class="fh__row-body">{f.body}</p>
          {f.ctaLabel && (
            <a href={f.ctaHref ?? '#'} class="fh__row-cta">
              {f.ctaLabel} →
            </a>
          )}
        </div>
      </div>
    ))}
  </div>
</section>

<style>
  .fh {
    background: var(--color-bg, #fff);
    padding: 5rem 1.5rem;
  }

  .fh__header {
    max-width: 640px;
    margin: 0 auto 4rem;
    text-align: center;
  }

  .fh__eyebrow {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent, #6366f1);
    margin-bottom: 0.75rem;
  }

  .fh__title {
    font-size: clamp(1.875rem, 3vw, 2.75rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--color-primary, #0a0a0a);
  }

  .fh__title :global(em) {
    font-style: normal;
    color: var(--color-accent, #6366f1);
  }

  .fh__rows {
    max-width: 1100px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 5rem;
  }

  .fh__row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4rem;
    align-items: center;
  }

  .fh__row--reversed {
    direction: rtl;
  }

  .fh__row--reversed > * {
    direction: ltr;
  }

  .fh__row-img img {
    width: 100%;
    height: 400px;
    object-fit: cover;
    border-radius: calc(var(--radius, 0.5rem) * 2);
  }

  .fh__label {
    display: inline-block;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-accent, #6366f1);
    background: color-mix(in srgb, var(--color-accent, #6366f1) 10%, transparent);
    padding: 0.3rem 0.75rem;
    border-radius: 100px;
    margin-bottom: 1rem;
  }

  .fh__row-headline {
    font-size: clamp(1.5rem, 2.5vw, 2.125rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.2;
    color: var(--color-primary, #0a0a0a);
    margin-bottom: 1rem;
  }

  .fh__row-headline :global(em) {
    font-style: normal;
    color: var(--color-accent, #6366f1);
  }

  .fh__row-body {
    font-size: 1rem;
    line-height: 1.7;
    color: var(--color-muted, #6b7280);
    margin-bottom: 1.5rem;
  }

  .fh__row-cta {
    display: inline-block;
    font-weight: 700;
    font-size: 0.9375rem;
    color: var(--color-accent, #6366f1);
    text-decoration: none;
    transition: gap 0.15s;
  }

  .fh__row-cta:hover { opacity: 0.8; }

  @media (max-width: 768px) {
    .fh__row {
      grid-template-columns: 1fr;
      gap: 2rem;
    }

    .fh__row--reversed { direction: ltr; }

    .fh__row-img img { height: 260px; }
  }
</style>

Props

Prop Type Default Beschrijving
features * Feature[] Array van features. Elke feature heeft image, headline, body.
eyebrow string Label boven sectie headline
headline string Sectie headline

* = verplicht