ImageWithCaption image
Enkelvoudig beeld met caption-regel en optioneel fotocredit. Drie breedte-modes: contained, narrow of full.
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