Newer
Older
iuav-ui / src / components / carousel / carousel.ts
/**
 * @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;
  }
}