<div class="porthole">
    <div class="porthole__images">
        <img src="https://bildermangel.de/600x600/fe7c09/130f26.webp" width="600" height="600" class="porthole__image">
        <img src="https://bildermangel.de/600x600/EDFF21/130f26.webp" width="600" height="600" class="porthole__image" load="lazy">
        <img src="https://bildermangel.de/600x600/063971/130f26.webp" width="600" height="600" class="porthole__image" load="lazy">
        <img src="https://bildermangel.de/600x600/FDF4E3/130f26.webp" width="600" height="600" class="porthole__image" load="lazy">
    </div>

    <div class="porthole__buttons" aria-hidden="true">
        <button class="porthole__button porthole__button--prev" type="button" data-porthole="prev" title="Previous image" disabled>
            <svg class="icon icon--angle-up" viewBox="0 0 200 200" aria-hidden="true">
                <use xlink:href="/assets/icons/icons.dcaca1c147.svg#angle-up"></use>
            </svg> </button>

        <button class="porthole__button porthole__button--next" type="button" data-porthole="next" title="Next image" disabled>
            <svg class="icon icon--angle-down" viewBox="0 0 200 200" aria-hidden="true">
                <use xlink:href="/assets/icons/icons.dcaca1c147.svg#angle-down"></use>
            </svg> </button>
    </div>
</div>
<div {{ html_attributes({
  id: id ?? false,
  class: 'porthole',
}, attrs ?? {}) }}>
  <div class="porthole__images">
    {% for image in images %}
      <img {{ html_attributes(image, {
        class: 'porthole__image',
        load: not loop.first ? 'lazy',
      }) }}>
    {% endfor %}
  </div>

  <div class="porthole__buttons" aria-hidden="true">
    <button {{ html_attributes({
      class: 'porthole__button porthole__button--prev',
      type: 'button',
      'data-porthole': 'prev',
      title: 'Previous image' | t('site'),
      disabled: true,
    }) }}>
      {% include '@icon' with {
        icon: 'angle-up',
      } only %}
    </button>

    <button {{ html_attributes({
      class: 'porthole__button porthole__button--next',
      type: 'button',
      'data-porthole': 'next',
      title: 'Next image' | t('site'),
      disabled: true,
    }) }}>
      {% include '@icon' with {
        icon: 'angle-down',
      } only %}
    </button>
  </div>
</div>
{
  "images": [
    {
      "src": "https://bildermangel.de/600x600/fe7c09/130f26.webp",
      "width": 600,
      "height": 600
    },
    {
      "src": "https://bildermangel.de/600x600/EDFF21/130f26.webp",
      "width": 600,
      "height": 600
    },
    {
      "src": "https://bildermangel.de/600x600/063971/130f26.webp",
      "width": 600,
      "height": 600
    },
    {
      "src": "https://bildermangel.de/600x600/FDF4E3/130f26.webp",
      "width": 600,
      "height": 600
    }
  ]
}
  • Content:
    .porthole {
      --box-shadow-color: #000;
    
      aspect-ratio: 1;
      background-color: var(--color-white);
      border-radius: 50%;
      box-shadow: var(--box-shadow-xxl-dense);
      container-name: porthole;
      container-type: inline-size;
      overflow: clip;
      position: relative;
    }
    
    .porthole__images {
      block-size: 100cqi;
      display: flex;
      flex-direction: column;
      overflow-x: auto;
      overflow-y: none;
      overscroll-behavior-inline: contain;
      position: relative;
      scroll-behavior: smooth;
      scroll-snap-type: y mandatory;
      scrollbar-width: none;
      z-index: 1;
    
      &::-webkit-scrollbar {
        display: none;
      }
    }
    
    .porthole__image {
      aspect-ratio: 1;
      inline-size: 100%;
      object-fit: cover;
      scroll-snap-align: start;
    }
    
    .porthole__buttons {
      align-items: center;
      display: flex;
      flex-direction: column;
      inset: 0;
      justify-content: space-between;
      padding: 5cqi;
      pointer-events: none;
      position: absolute;
      z-index: 2;
    }
    
    .porthole__button {
      --icon-size: 7cqi;
    
      align-items: center;
      aspect-ratio: 1;
      background-color: var(--color-white);
      block-size: calc(var(--icon-size) + 2cqi);
      border-radius: 50%;
      color: var(--color-gray-300);
      display: flex;
      inline-size: calc(var(--icon-size) + 2cqi);
      justify-content: center;
      line-height: 0;
      pointer-events: all;
      transition-property: color, opacity;
    
      &:not([disabled]):is(:hover, :focus-visible) {
        color: var(--color-gray-800);
      }
    
      &:is([disabled]) {
        opacity: 0.5;
      }
    }
    
  • URL: /components/raw/porthole/porthole.scss
  • Filesystem Path: src/components/3-molecules/porthole/porthole.scss
  • Size: 1.5 KB
  • Content:
    import abort from '../../../javascripts/utils/abort';
    import onLoad from '../../../javascripts/utils/onLoad';
    
    onLoad<HTMLElement>('.porthole', ($porthole) => {
      const $images = $porthole.querySelector('.porthole__images') ?? abort();
      const $prevButton = $porthole.querySelector<HTMLButtonElement>('[data-porthole="prev"]') ?? abort();
      const $nextButton = $porthole.querySelector<HTMLButtonElement>('[data-porthole="next"]') ?? abort();
    
      const onScroll = () => {
        $prevButton.disabled = $images.scrollTop < $images.clientHeight;
        $nextButton.disabled = $images.scrollTop > ($images.scrollHeight - $images.clientHeight * 2);
      };
    
      $images.addEventListener('scroll', onScroll, { passive: true });
      onScroll();
    
      $prevButton.addEventListener('click', (event) => {
        event.preventDefault();
        $images.scrollBy({ top: $images.clientHeight * -1 });
      });
    
      $nextButton.addEventListener('click', (event) => {
        event.preventDefault();
        $images.scrollBy({ top: $images.clientHeight });
      });
    });
    
  • URL: /components/raw/porthole/porthole.ts
  • Filesystem Path: src/components/3-molecules/porthole/porthole.ts
  • Size: 1 KB

No notes defined.