Zoeken...  ⌘K GitHub

ImageWithCaption image

Enkelvoudig beeld met caption-regel en optioneel fotocredit. Drie breedte-modes: contained, narrow of full.

/image-with-caption
src/components/image/ImageWithCaption.astro
---
/**
 * ImageWithCaption
 * Enkelvoudig beeld met caption-regel en optioneel fotocredit.
 * Ondersteunt drie breedte-modes en een fade-in animatie.
 *
 * Props:
 * - src: string                  afbeelding-URL
 * - alt?: string                 alt-tekst
 * - caption?: string             beschrijvende tekst onder het beeld
 * - credit?: string              fotocredit (kleiner, rechts uitgelijnd)
 * - aspectRatio?: string         bijv. '16/9', '4/3', '1/1' — default '16/9'
 * - width?: 'contained' | 'narrow' | 'full'  default 'contained'
 * - rounded?: boolean            afgeronde hoeken — default true
 * - theme?: 'light' | 'dark'    default 'light'
 */
interface Props {
  src: string;
  alt?: string;
  caption?: string;
  credit?: string;
  aspectRatio?: string;
  width?: 'contained' | 'narrow' | 'full';
  rounded?: boolean;
  theme?: 'light' | 'dark';
}

const {
  src,
  alt = '',
  caption,
  credit,
  aspectRatio = '16/9',
  width = 'contained',
  rounded = true,
  theme = 'light',
} = Astro.props;
---

<section class:list={['bl-section', 'iwc', `iwc--${theme}`]}>
  <div class="bl-inner iwc-inner">
    <figure class:list={['iwc-figure', `iwc-figure--${width}`]}>
      <div
        class:list={['iwc-img-wrap', rounded && 'iwc-img-wrap--rounded']}
        style={`aspect-ratio: ${aspectRatio}`}
      >
        <img
          src={src}
          alt={alt}
          class="iwc-img"
          loading="lazy"
          decoding="async"
        />
      </div>
      {(caption || credit) && (
        <figcaption class="iwc-meta">
          {caption && <p class="iwc-caption">{caption}</p>}
          {credit && <span class="iwc-credit">{credit}</span>}
        </figcaption>
      )}
    </figure>
  </div>
</section>

<style>
  .iwc--light { background: var(--color-bg, #fff); color: var(--color-text, #0a0a0a); }
  .iwc--dark  { background: #0a0a0a; color: #e8e8e8; }

  /* Centering via flex op de inner — geen margin:auto+max-width combo nodig */
  .iwc-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  /* Figure breedte-varianten: max-width alleen, centering via parent flex */
  .iwc-figure {
    width: 100%;
    margin: 0;
    padding: 0;
  }

  .iwc-figure--contained { max-width: 880px; }
  .iwc-figure--narrow    { max-width: 580px; }
  /* full = volledige bl-inner breedte, geen extra constraint */

  .iwc-img-wrap {
    overflow: hidden;
    width: 100%;
    position: relative;
  }

  .iwc-img-wrap--rounded { border-radius: var(--radius, 10px); }

  /* Aspect-ratio positionering */
  .iwc-img-wrap[style] .iwc-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .iwc-img {
    display: block;
    width: 100%;
    height: auto;
    object-fit: cover;
  }

  .iwc-meta {
    margin: 0;
    padding: .625rem 0 0;
    border-top: 1px solid #e5e7eb;
    display: flex;
    flex-direction: column;
    gap: .25rem;
  }

  .iwc--dark .iwc-meta { border-top-color: #333; }

  .iwc-caption {
    margin: 0;
    font-size: .9375rem;
    font-style: italic;
    color: var(--color-muted, #6b7280);
    line-height: 1.55;
  }

  .iwc--dark .iwc-caption { color: #aaa; }

  .iwc-credit {
    font-size: .8125rem;
    color: #9ca3af;
    letter-spacing: .02em;
  }

  .iwc--dark .iwc-credit { color: #666; }
</style>

Props

Prop Type Default Beschrijving
src * string - Afbeelding-URL
alt string '' Alt-tekst
caption string - Beschrijvende tekst onder het beeld
credit string - Fotocredit (kleiner formaat)
aspectRatio string '16/9' Verhouding, bijv. '4/3' of '1/1'
width 'contained' | 'narrow' | 'full' 'contained' Breedte van het figuur
rounded boolean true Afgeronde hoeken
theme 'light' | 'dark' 'light' Achtergrond-mode

* = verplicht