/** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ import {LitElement, html, css, unsafeCSS} from 'lit'; import {customElement, property} from 'lit/decorators.js'; import { breakpoints } from '../../breakpoints'; import Swiper from 'swiper'; import { EffectFade, Navigation, Pagination } from 'swiper/modules'; import swiperStyles from 'swiper/css/bundle?raw'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; @customElement('iu-carousel') export class Carousel extends LitElement { static override styles = [ css([swiperStyles]), css` .img{ aspect-ratio: 3/2; height: auto; } .img img{ width: 100%; height: 100%; object-fit: cover; } .caption p{ font: var(--iu-f-0); background: #fff; margin-bottom: 0; margin-top: 1.75rem; height: 100%; } :host .swiper-button-prev, :host .swiper-button-next{ width: 50%; height: var(--carousel-img-height); top: 0; margin-top: 0; } :host .swiper-button-prev::after, :host .swiper-button-next::after{ content: none; } :host .swiper-pagination{ display: flex; gap: 0.625rem; position: absolute; top: calc(var(--carousel-img-height) + 0.625rem); } :host .swiper-pagination .swiper-pagination-bullet{ width:100%; border-radius: 0; height: 1px; margin: 0; background: var(--iu-color-grey-300); opacity: 1; } :host .swiper-pagination .swiper-pagination-bullet-active{ background: var(--iu-color-black); height: 3px; } :host .swiper-slide{ opacity: 0; } :host .swiper-slide-active, :host .swiper.slide-duplicate-active{ opacity: 1; } ` ]; @property({ type: Array }) items: Array<{ path: string; caption?: string }> = []; override firstUpdated() { // Initialize Swiper once the component is rendered new Swiper(this.shadowRoot.querySelector('.swiper'), { modules: [EffectFade, Navigation, Pagination], loop: true, effect: 'fade', crossFade: true, pagination: { el: this.shadowRoot.querySelector('.swiper-pagination') }, navigation: { nextEl: this.shadowRoot.querySelector('.swiper-button-next'), prevEl: this.shadowRoot.querySelector('.swiper-button-prev') }, }); requestAnimationFrame(() => { const height = Math.floor(this.clientWidth / 1.5) this.style.setProperty('--carousel-img-height', `${height}px`); }); } override render() { return html` <div class="swiper"> <div class="swiper-wrapper"> ${this.items.map( (item) => html` <div class="swiper-slide"> <div class="img"> <img src="${item.path}" alt="${item.caption || 'Image'}" /> ${item.caption ? html` <div class="caption"><p>${unsafeHTML(item.caption)}</p></div>` : '' } </div> </div> ` )} </div> <div class="swiper-pagination"></div> <div class="swiper-button-prev"></div> <div class="swiper-button-next"></div> </div> `; } } declare global { interface HTMLElementTagNameMap { 'iu-carousel': Carousel; } }