Zoeken...  ⌘K GitHub

ImageMosaic image

Mosaicgrid met groot uitgelicht beeld links en drie kleinere beelden rechts.

/image-mosaic
src/components/image/ImageMosaic.astro
---
interface MosaicItem {
  src?: string;
  alt?: string;
  label?: string;
  featured?: boolean;
}

interface Props {
  title?: string;
  items?: MosaicItem[];
}

const {
  title = 'Impressie',
  items = [
    { alt: 'Groot beeld', label: 'Featured project', featured: true },
    { alt: 'Klein beeld 1', label: 'Detail 1' },
    { alt: 'Klein beeld 2', label: 'Detail 2' },
    { alt: 'Klein beeld 3', label: 'Detail 3' },
  ],
} = Astro.props;
---

<section class="bl-section imo">
  <div class="bl-inner imo__inner">
    {title && <h2 class="imo__title">{title}</h2>}
    <div class="imo__grid">
      {items.map((item) => (
        <div class:list={['imo__item', { 'imo__item--large': item.featured }]}>
          {item.src
            ? <img data-allow-img class="imo__img" src={item.src} alt={item.alt ?? ''} loading="lazy" decoding="async" />
            : <div class="imo__placeholder" aria-label={item.alt ?? ''}></div>
          }
          {item.label && <span class="imo__label">{item.label}</span>}
        </div>
      ))}
    </div>
  </div>
</section>

<style>
  .imo__title {
    font-size: clamp(1.75rem, 3vw, 2.5rem);
    font-weight: 700;
    color: var(--color-primary, #0a0a0a);
    margin: 0 0 2rem;
  }
  .imo__grid {
    display: grid;
    grid-template-columns: 2fr 1fr;
    grid-template-rows: auto auto;
    gap: 0.75rem;
  }
  .imo__item {
    position: relative;
    overflow: hidden;
    border-radius: 8px;
    aspect-ratio: 4/3;
  }
  .imo__item--large {
    grid-row: span 2;
    aspect-ratio: auto;
  }
  .imo__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.35s;
  }
  .imo__item:hover .imo__img {
    transform: scale(1.04);
  }
  .imo__placeholder {
    width: 100%;
    height: 100%;
    min-height: 150px;
  }
  .imo__item--large .imo__placeholder {
    background: linear-gradient(135deg, #1a2a4a, #3a4a7a);
    min-height: 320px;
  }
  .imo__item:not(.imo__item--large) .imo__placeholder {
    background: linear-gradient(135deg, #e0e0f0, #c8c8e8);
  }
  .imo__item:nth-child(3) .imo__placeholder {
    background: linear-gradient(135deg, #e8f0e0, #c8e0c8);
  }
  .imo__label {
    position: absolute;
    bottom: 0.75rem;
    left: 0.75rem;
    background: rgba(10, 10, 10, 0.65);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.25rem 0.6rem;
    border-radius: 4px;
  }
  @media (max-width: 640px) {
    .imo__grid {
      grid-template-columns: 1fr;
    }
    .imo__item--large {
      grid-row: auto;
    }
  }
</style>

Props

Prop Type Default Beschrijving
title string - Kop boven het mosaic
items { src?: string; alt?: string; label?: string; featured?: boolean }[] - Mosaicbeelden; eerste featured item krijgt grote positie

* = verplicht