<div class="hero-carousel h-margin-bottom-2" data-carousel-delay="7000">
    <h1 class="h-visibility-hidden">This is the hero carousel heading!</h1>
    <div class="hero-carousel__media swiper-container">
        <div class="swiper-wrapper">
            <div class="swiper-slide">
                <figure>
                    <img src="/mocks/img/hero-carousel.jpg" srcset="/mocks/img/hero-carousel.jpg 375w, /mocks/img/hero-carousel.jpg 750w, /mocks/img/hero-carousel.jpg 1430w, /mocks/img/hero-carousel.jpg 2860w" alt="#" />
                </figure>
            </div>
            <div class="swiper-slide">
                <figure>
                    <img src="/mocks/img/hero-carousel-2.jpg" srcset="/mocks/img/hero-carousel-2.jpg 375w, /mocks/img/hero-carousel-2.jpg 750w, /mocks/img/hero-carousel-2.jpg 1430w, /mocks/img/hero-carousel-2.jpg 2860w" alt="#" />
                </figure>
            </div>
            <div class="swiper-slide">
                <figure>
                    <img src="/mocks/img/hero-carousel-3.jpg" srcset="/mocks/img/hero-carousel-3.jpg 375w, /mocks/img/hero-carousel-3.jpg 750w, /mocks/img/hero-carousel-3.jpg 1430w, /mocks/img/hero-carousel-3.jpg 2860w" alt="#" />
                </figure>
            </div>
            <div class="swiper-slide">
                <figure>
                    <img src="/mocks/img/hero-carousel-4.jpg" srcset="/mocks/img/hero-carousel-4.jpg 375w, /mocks/img/hero-carousel-4.jpg 750w, /mocks/img/hero-carousel-4.jpg 1430w, /mocks/img/hero-carousel-4.jpg 2860w" alt="#" />
                </figure>
            </div>
        </div>
        <div class="hero-carousel__navigation">
            <ul>
                <li>
                    <button data-index="0">

                        <span>Vill du snabbt få förslag på rätt ventilation?</span>
                    </button>
                </li>
                <li>
                    <button data-index="1">
                        <span class="hero-carousel__label">Ny produkt</span>
                        <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
                    </button>
                </li>
                <li>
                    <button data-index="2">

                        <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
                    </button>
                </li>
                <li>
                    <button data-index="3">

                        <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
                    </button>
                </li>
            </ul>
        </div>
    </div>
    <div class="hero-carousel__content">
        <div class="hero-carousel__content-item">

            <h2>Vill du snabbt få förslag på rätt ventilation?</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
            <a href="#" class="button">Primary</a>

        </div>
        <div class="hero-carousel__content-item">

            <h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
            <a href="#" class="button">Primary</a>

        </div>
        <div class="hero-carousel__content-item">

            <h2>Consectetur adipiscing elit.</h2>
            <p>Consectetur adipiscing elit.</p>

        </div>
        <div class="hero-carousel__content-item">

            <h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
            <a href="#" class="button">Primary</a>

        </div>
    </div>
    <div class="hero-carousel__options">
        <button class="hero-carousel__toggle-autoplay">
            <svg class="icon hero-carousel_play-button" focusable="false">
                <use xlink:href="#icon-play"></use>
            </svg>
            <svg class="icon hero-carousel_pause-button" focusable="false">
                <use xlink:href="#icon-pause"></use>
            </svg>
        </button>
    </div>
</div>
<div class="hero-carousel h-margin-bottom-2" data-carousel-delay="{{delay}}">
    {{#if heading}}<h1 class="h-visibility-hidden">{{heading}}</h1>{{/if}}
    <div class="hero-carousel__media swiper-container">
        <div class="swiper-wrapper">
            {{#each items}}
                {{#with image}}
                    <div class="swiper-slide">
                        <figure>
                            <img
                                src="{{src}}"
                                srcset="{{src}} 375w, {{src2x}} 750w, {{src2x}} 1430w, {{src2x}} 2860w"
                                alt="{{alt}}"
                            />
                        </figure>
                    </div>
                {{/with}}
            {{/each}}
        </div>
        <div class="hero-carousel__navigation">
            <ul>
                {{#each items}}
                    {{#with navigation}}
                        <li>
                            <button data-index="{{@index}}">
                                {{#if label}}<span class="hero-carousel__label">{{label}}</span>{{/if}}
                                <span>{{text}}</span>
                            </button>
                        </li>
                    {{/with}}
                {{/each}}
            </ul>
        </div>
    </div>
    <div class="hero-carousel__content">
        {{#each items}}
            <div class="hero-carousel__content-item">
                {{#with content}}

                    <h2>{{title}}</h2>
                    {{#if body}}<p>{{body}}</p>{{/if}}
                    {{#if button}}
                        <a
                            href="{{button.link}}"
                            class="button"
                        >{{button.label}}</a>
                    {{/if}}

                {{/with}}
            </div>
        {{/each}}
    </div>
    <div class="hero-carousel__options">
        <button class="hero-carousel__toggle-autoplay">
            {{> @icon id="play" additionalClasses="hero-carousel_play-button"}}
            {{> @icon id="pause" additionalClasses="hero-carousel_pause-button"}}
        </button>
    </div>
</div>
{
  "heading": "This is the hero carousel heading!",
  "delay": 7000,
  "items": [
    {
      "content": {
        "title": "Vill du snabbt få förslag på rätt ventilation?",
        "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "button": {
          "label": "Primary",
          "link": "#"
        }
      },
      "image": {
        "src": "/mocks/img/hero-carousel.jpg",
        "src2x": "/mocks/img/hero-carousel.jpg",
        "alt": "#"
      },
      "navigation": {
        "text": "Vill du snabbt få förslag på rätt ventilation?"
      }
    },
    {
      "content": {
        "title": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "button": {
          "label": "Primary",
          "link": "#"
        }
      },
      "image": {
        "src": "/mocks/img/hero-carousel-2.jpg",
        "src2x": "/mocks/img/hero-carousel-2.jpg",
        "alt": "#"
      },
      "navigation": {
        "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "label": "Ny produkt"
      }
    },
    {
      "content": {
        "title": "Consectetur adipiscing elit.",
        "body": "Consectetur adipiscing elit."
      },
      "image": {
        "src": "/mocks/img/hero-carousel-3.jpg",
        "src2x": "/mocks/img/hero-carousel-3.jpg",
        "alt": "#"
      },
      "navigation": {
        "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
      }
    },
    {
      "image": {
        "src": "/mocks/img/hero-carousel-4.jpg",
        "src2x": "/mocks/img/hero-carousel-4.jpg",
        "alt": "#"
      },
      "content": {
        "title": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "button": {
          "label": "Primary",
          "link": "#"
        }
      },
      "navigation": {
        "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
      }
    }
  ]
}
  • Content:
    import Swiper from 'swiper';
    
    export default function HeroCarousel(el) {
        const swiperContainer = el.querySelector('.swiper-container');
        const navButtons = el.querySelectorAll('.hero-carousel__navigation button');
        const contentItems = el.querySelectorAll('.hero-carousel__content-item');
        const autoplayButton = el.querySelector('.hero-carousel__toggle-autoplay');
        const delay = el.getAttribute('data-carousel-delay') || 7000;
    
        autoplayButton.classList.add('is-playing');
    
        const swiper = new Swiper(swiperContainer, {
            loop: true,
            slidesPerView: 1,
            autoplay: {
                delay: delay,
                disableOnInteraction: true
            },
            on: {
                slideChange: function () {
                    const index = swiper.realIndex;
                    updateContent(index);
                    updateNavigation(index);
    
                    // Handle play/pause state if autoplay is not running after slideChange and drag event.
                    if (!swiper.autoplay.running) {
                        autoplayButton.classList.remove('is-playing');
                    }
                }
            }
        });
    
        function updateContent(nextIndex) {
            const currentIndex = [...contentItems].findIndex((item) =>
                item.classList.contains('active')
            );
    
            const currentItem = contentItems[currentIndex];
            const nextItem = contentItems[nextIndex];
    
            if (!nextItem) return;
    
            contentItems.forEach((item) => item.classList.remove('fade-out'));
    
            if (currentItem && currentIndex !== nextIndex) {
                currentItem.classList.remove('active');
    
                requestAnimationFrame(() => {
                    currentItem.classList.add('fade-out');
                });
    
                setTimeout(() => {
                    currentItem.classList.remove('fade-out');
                    nextItem.classList.add('active');
                }, 500);
            } else {
                contentItems.forEach((el, i) => {
                    el.classList.toggle('active', i === nextIndex);
                });
            }
        }
    
        function updateNavigation(index) {
            const scrollEl = el.querySelector('.hero-carousel__navigation ul');
    
            navButtons.forEach((btn, i) => {
                const isActive = i === index;
                btn.classList.toggle('active', isActive);
    
                if (isActive && scrollEl.scrollWidth > scrollEl.clientWidth) {
                    const item = btn.parentElement;
                    let scrollLeft;
    
                    if (i === navButtons.length - 1) {
                        scrollLeft = scrollEl.scrollWidth - scrollEl.clientWidth;
                    } else {
                        scrollLeft = item.offsetLeft;
                    }
    
                    scrollEl.scrollTo({
                        left: scrollLeft,
                        behavior: 'smooth'
                    });
                }
            });
        }
    
        navButtons.forEach((button) => {
            button.addEventListener('mousedown', (e) => e.stopPropagation());
            button.addEventListener('touchstart', (e) => e.stopPropagation());
            button.addEventListener('click', () => {
                const index = parseInt(button.dataset.index, 10);
                swiper.slideToLoop(index);
                swiper.autoplay.stop();
                autoplayButton.classList.remove('is-playing');
                updateNavigation(index);
            });
        });
    
        autoplayButton.addEventListener('click', () => {
            if (swiper.autoplay.running) {
                swiper.autoplay.stop();
                autoplayButton.classList.remove('is-playing');
            } else {
                swiper.autoplay.start();
                autoplayButton.classList.add('is-playing');
            }
        });
    
        /* Observer Purpose
            - Pause auto play when scrolled beyond Image carousel
        */
        const observer = new IntersectionObserver(
            (entries) => {
                entries.forEach((entry) => {
                    if (!entry.isIntersecting) {
                        swiper.autoplay.stop();
                        autoplayButton.classList.remove('is-playing');
                    }
                });
            },
            {
                threshold: 0
            }
        );
    
        observer.observe(swiperContainer);
    
        // Init
        updateContent(swiper.realIndex);
        updateNavigation(swiper.realIndex);
    }
    
  • URL: /components/raw/hero-carousel/HeroCarousel.js
  • Filesystem Path: src/components/hero-carousel/HeroCarousel.js
  • Size: 4.3 KB
  • Content:
    .hero-carousel {
        display: flex;
        flex-direction: column;
        position: relative;
    
        .swiper-slide {
            width: 100%;
            text-align: center;
            height: auto;
            display: flex;
            align-items: center;
            justify-content: center;
        }
    
        .button {
            margin: 0;
        }
    }
    
    // Image Carousel
    .hero-carousel__media {
        width: 100%;
        overflow: hidden;
    
        figure {
            position: relative;
            width: 100%;
            margin: 0;
            padding-bottom: 100%;
    
            @include breakpoint($m) {
                height: 570px;
                padding-bottom: 0;
            }
        }
    
        img {
            position: absolute;
            width: 100%;
            height: 100%;
            object-fit: cover;
            left: 0;
        }
    
        &:before {
            content: " ";
            position: absolute;
            width: 600px;
            height: 100%;
            background: linear-gradient(
                90deg,
                rgba(0, 0, 0, 0.4) 0%,
                rgba(0, 0, 0, 0) 100%
            );
            z-index: 2;
        }
    
        &:after {
            content: " ";
            display: block;
            bottom: 0;
            left: 0;
            right: 0;
            position: absolute;
            width: 100%;
            height: 85px;
            background: linear-gradient(
                0,
                rgba(0, 0, 0, 0.4) 0%,
                rgba(0, 0, 0, 0) 100%
            );
            z-index: 1;
        }
    }
    
    .hero-carousel__content,
    .hero-carousel__navigation {
        width: 100%;
    }
    
    // Content
    .hero-carousel__content {
        background-color: $color-white;
        padding: 20px 12px 0;
    
        @include breakpoint($m) {
            background-color: transparent;
            position: absolute;
            top: 60px;
            left: 32px;
            padding: 0;
            z-index: 1;
            max-width: 540px;
            width: 70%;
    
            h2,
            p {
                color: $color-white;
            }
        }
    }
    
    .hero-carousel__content-item {
        opacity: 0;
        transform: translateY(20px);
        transition: opacity 0.3s ease,
            transform 0.5s cubic-bezier(0.69, 0.24, 0.03, 0.87);
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        pointer-events: none;
    }
    
    .hero-carousel__content-item.active {
        opacity: 1;
        transform: translateY(0);
        pointer-events: auto;
        position: relative;
        z-index: 1;
    }
    
    .hero-carousel__content-item.fade-out {
        position: relative;
        opacity: 0;
        transform: translateY(-20px);
        pointer-events: none;
        z-index: 0;
    }
    
    // Navigation
    .hero-carousel__navigation {
        position: absolute;
        bottom: 0;
        z-index: 2;
    
        ul,
        li {
            margin: 0;
            padding: 0;
            list-style: none;
            color: $color-white;
        }
    
        ul {
            display: flex;
            flex-direction: row;
            overflow-x: auto;
            padding-bottom: 16px;
            padding-right: 8px;
            white-space: nowrap;
        }
    
        li {
            display: flex;
            align-items: flex-end;
            flex: 0 0 200px;
            text-align: left;
            padding-left: 8px;
    
            &:first-child {
                padding-left: 16px;
            }
    
            @include breakpoint(0, 440px) {
                flex: 0 0 100%;
                max-width: 60%;
            }
    
            @include breakpoint(560px, $s) {
                flex: 0 0 calc(33% - 8px);
            }
        }
    
        button {
            display: flex;
            width: 100%;
            justify-content: flex-end;
            flex-direction: column;
            text-align: left;
            cursor: pointer;
            border-bottom: 2px solid rgba($color-white, 0.4);
            padding-bottom: 2px;
            font-weight: 700;
    
            &.active {
                border-bottom: 4px solid $color-white;
                padding-bottom: 0;
            }
    
            span:not(.hero-carousel__label) {
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: normal;
            }
    
            .hero-carousel__label {
                margin-right: auto;
                background: $color-green-pale;
                color: $color-green;
                text-transform: uppercase;
                font-size: 12px;
                line-height: 20px;
                padding: 0 4px;
            }
        }
    }
    
    // Play and pause
    .hero-carousel__options {
        position: absolute;
        top: 16px;
        right: 16px;
        z-index: 1;
    
        svg {
            fill: $color-white;
            width: 36px;
            height: 36px;
        }
    }
    
    .hero-carousel_play-button,
    .hero-carousel_pause-button {
        display: none;
        cursor: pointer;
    }
    
    .hero-carousel__toggle-autoplay.is-playing .hero-carousel_pause-button {
        display: inline-block;
    }
    
    .hero-carousel__toggle-autoplay:not(.is-playing) .hero-carousel_play-button {
        display: inline-block;
    }
    
  • URL: /components/raw/hero-carousel/hero-carousel.scss
  • Filesystem Path: src/components/hero-carousel/hero-carousel.scss
  • Size: 4.7 KB
  • Content:
    import HeroCarousel from './HeroCarousel';
    const els = document.querySelectorAll('.hero-carousel');
    
    for (let el of els) {
      HeroCarousel(el);
    }
    
  • URL: /components/raw/hero-carousel/index.js
  • Filesystem Path: src/components/hero-carousel/index.js
  • Size: 145 Bytes

No notes defined.