<div class="carousel-container">
    <div class="carousel" data-behavior="carousel">
        <div>
            <div style="border:2px solid; height: 300px;"> 1 </div>
        </div>
        <div>
            <div style="border:2px solid; height: 300px;"> 2 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 3 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 4 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 5 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 6 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 7 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 8 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 9 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 10 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 11</div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 12 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 13 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 14 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 15 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 16 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 17 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 18 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 19 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 20 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 21 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 22 </div>
        </div>
        <div>
            <div style="border:2px solid ; height: 300px;"> 23 </div>
        </div>

    </div>
    <div class="carousel-nav-block">
        <div class="carousel-nav-wrapper">
            <div role="tablist" class="carousel__pagination"></div>
            <div class="carousel-navigation">
                <button aria-label="Previous" class="carousel__cta carousel__prev"><span class="visually-hidden">Previous
                        page</span><svg fill="none" viewBox="0 0 10 17" xmlns="http://www.w3.org/2000/svg">
                        <path d="m9.2722 9.3355-6.75 6.75c-0.46089 0.4609-1.2087 0.4609-1.6706 0-0.46089-0.4609-0.46089-1.2097 0-1.6706l5.9146-5.9146-5.9146-5.9146c-0.46089-0.46089-0.46089-1.2097 0-1.6706 0.46194-0.46089 1.2097-0.46089 1.6706 0l6.75 6.75c0.46194 0.46089 0.46194 1.2097 0 1.6706v-1.4e-4z" fill="currentColor" />
                    </svg></button>
                <button aria-label="Next" class="carousel__cta carousel__next"><span class="visually-hidden">Next
                        page</span><svg fill="none" viewBox="0 0 10 17" xmlns="http://www.w3.org/2000/svg">
                        <path d="m9.2722 9.3355-6.75 6.75c-0.46089 0.4609-1.2087 0.4609-1.6706 0-0.46089-0.4609-0.46089-1.2097 0-1.6706l5.9146-5.9146-5.9146-5.9146c-0.46089-0.46089-0.46089-1.2097 0-1.6706 0.46194-0.46089 1.2097-0.46089 1.6706 0l6.75 6.75c0.46194 0.46089 0.46194 1.2097 0 1.6706v-1.4e-4z" fill="currentColor" />
                    </svg></button>
            </div>
        </div>
    </div>
</div>

No notes defined.

/* No context defined. */
  • Content:
    import debounce from 'lodash.debounce';
    import Glide from '@glidejs/glide';
    
    export default ({ carouselGlideElement, responsive = [], ...options }) => {
      const slides = carouselGlideElement.querySelectorAll('.glide__slides > li');
      const carouselLoop = carouselGlideElement.getAttribute('data-carousel-loop');
      const MOBILE_BREAKPOINT = 820;
      let glide;
      const glideType4 = slides.length <= 4 ? 'slider' : 'carousel';
      const glideType2 = slides.length <= 2 ? 'slider' : 'carousel';
      // eslint-disable-next-line no-unneeded-ternary
      const isSwipe4 = slides.length <= 4 ? false : true;
      // eslint-disable-next-line no-unneeded-ternary
      const isSwipe2 = slides.length <= 2 ? false : true;
      const breakpointSettings = {
        500: {
          perView: 1,
          peek: { before: 40, after: 30 },
        },
        900: {
          perView: 2,
          type: glideType2,
          swipeThreshold: isSwipe2,
          dragThreshold: isSwipe2,
        },
        1200: {
          perView: 4,
          type: glideType4,
          swipeThreshold: isSwipe4,
          dragThreshold: isSwipe4,
        },
        ...responsive,
      };
    
      const getCurrentSettings = () => {
        const screenWidth = window.innerWidth;
    
        // Because the `perView` changes at different breakpoints, find
        // the relevant setting for the current screensize.
        // Filter out any settings that are smaller than the current size, and
        // then use the first in the list, as this will be the most relevant.
        // If none are available, assume we are using the biggest setting.
    
        // TODO: We should be able to reuse this, if we want to change the pagination
        // to scroll full pages, rather than individual items
        const breakpointSettingsForCurrentSize =
          Object.keys(breakpointSettings).filter(
            i => parseInt(i, 10) > screenWidth
          )[0] || Object.keys(breakpointSettings).slice(-1);
    
        return breakpointSettings[breakpointSettingsForCurrentSize];
      };
    
      const enablePrevButton = () => {
        carouselGlideElement
          .querySelector('.carousel__prev')
          .classList.remove('disabled');
        carouselGlideElement
          .querySelector('.carousel__prev')
          .removeAttribute('disabled');
      };
    
      const enableNextButton = () => {
        carouselGlideElement
          .querySelector('.carousel__next')
          .classList.remove('disabled');
        carouselGlideElement
          .querySelector('.carousel__next')
          .removeAttribute('disabled');
      };
    
      const disablePrevButton = () => {
        carouselGlideElement
          .querySelector('.carousel__prev')
          .classList.add('disabled');
        carouselGlideElement
          .querySelector('.carousel__prev')
          .setAttribute('disabled', true);
      };
    
      const disableNextButton = () => {
        carouselGlideElement
          .querySelector('.carousel__next')
          .classList.add('disabled');
        carouselGlideElement
          .querySelector('.carousel__next')
          .setAttribute('disabled', true);
      };
    
      const showPaginationByPage = () => {
        // Glide shows a pagination button for each item, and doesn't provide
        // an option to navigate whole pages at a time.
        // This function hides extra individual dots, so that only the first item of
        // each page is shown. (Based on the `perView` setting).
        const { perView } = getCurrentSettings();
    
        const paginationElements = carouselGlideElement.querySelectorAll(
          `.glide-carousel__pagination button:not(:nth-child(${perView}n + 1))`
        );
        const visiblePaginationElements = carouselGlideElement.querySelectorAll(
          `.glide-carousel__pagination button:nth-child(${perView}n + 1)`
        );
    
        paginationElements.forEach(item => {
          item.classList.add('hidden');
        });
    
        visiblePaginationElements.forEach((item, index) => {
          // eslint-disable-next-line no-param-reassign
          item.ariaLabel = `Page ${index + 1} Button`;
        });
    
        if (carouselLoop && window.innerWidth > MOBILE_BREAKPOINT) {
          return;
        }
        // disabling prev button by default
        disablePrevButton();
      };
    
      const slideToNext = () => {
        const maxPerView = getCurrentSettings().perView;
    
        carouselGlideElement
          .querySelector('.carousel__next')
          .addEventListener('click', event => {
            const { target } = event;
            let activeDots = 0;
    
            carouselGlideElement
              .querySelectorAll('.glide-carousel__pagination > *')
              .forEach((dot, index) => {
                if (dot.getAttribute('class') === 'glide__bullet--active') {
                  activeDots = index;
                }
              });
    
            const nextSlide = activeDots + maxPerView;
    
            if (carouselLoop && window.innerWidth > MOBILE_BREAKPOINT) {
              if (nextSlide > slides.length) {
                glide.go(`=0`);
              } else {
                glide.go(`=${nextSlide}`);
              }
            } else {
              glide.go(`=${nextSlide}`);
              if (nextSlide + maxPerView > slides.length) {
                target.closest('button').classList.add('disabled');
                target.closest('button').setAttribute('disabled', true);
              }
              enablePrevButton();
            }
          });
      };
    
      const slideToPrevious = () => {
        const maxPerView = getCurrentSettings().perView;
    
        carouselGlideElement
          .querySelector('.carousel__prev')
          .addEventListener('click', event => {
            const { target } = event;
            let activeDots = 0;
    
            carouselGlideElement
              .querySelectorAll('.glide-carousel__pagination > *')
              .forEach((dot, index) => {
                if (dot.getAttribute('class') === 'glide__bullet--active') {
                  activeDots = index;
                }
              });
    
            const prevSlide = activeDots - maxPerView;
    
            if (carouselLoop && window.innerWidth > MOBILE_BREAKPOINT) {
              if (prevSlide < 0) {
                const lastslide =
                  Math.floor(slides.length / maxPerView) * maxPerView;
    
                glide.go(`=${lastslide}`);
              } else {
                glide.go(`=${prevSlide}`);
              }
            } else {
              if (prevSlide >= 0) {
                glide.go(`=${prevSlide}`);
              }
    
              if (prevSlide - maxPerView < 0) {
                target.closest('button').classList.add('disabled');
                target.closest('button').setAttribute('disabled', true);
              }
    
              enableNextButton();
            }
          });
      };
    
      const enableNextPrev = () => {
        const maxPerView = getCurrentSettings().perView;
    
        carouselGlideElement
          .querySelectorAll('.glide-carousel__pagination > *')
          .forEach((dot, index) => {
            dot.addEventListener('click', () => {
              if (index > 0) {
                enablePrevButton();
              }
              if (index === 0) {
                enableNextButton();
                disablePrevButton();
              }
              if (index + maxPerView > slides.length) {
                disableNextButton();
              }
              if (index + maxPerView < slides.length) {
                enableNextButton();
              }
            });
          });
      };
    
      const showHideNavigation = () => {
        const maxPerView = getCurrentSettings().perView;
    
        const navigationElements = carouselGlideElement.querySelectorAll(
          '[data-glide-dir]'
        );
    
        if (!slides || slides.length <= maxPerView) {
          navigationElements.forEach(item => item.classList.add('hidden'));
          // eslint-disable-next-line no-param-reassign
          carouselGlideElement.querySelector('.carousel-navigation').style.display =
            'none';
          return;
        }
        navigationElements.forEach(item => {
          item.classList.remove('hidden');
          item.removeAttribute('aria-label');
        });
    
        showPaginationByPage();
        // added manual arrow next/previous button action
        slideToNext();
        slideToPrevious();
        enableNextPrev();
      };
    
      const createPagination = () => {
        const bulletContainer = document.createElement('div');
    
        bulletContainer.classList.add('glide-carousel__pagination');
        bulletContainer.dataset.glideEl = 'controls[nav]';
    
        slides.forEach((slide, index) => {
          const button = document.createElement('button');
    
          button.dataset.glideDir = `=${index}`;
          bulletContainer.appendChild(button);
        });
    
        carouselGlideElement
          .querySelector('.carousel-nav-wrapper')
          .appendChild(bulletContainer);
        showHideNavigation();
      };
    
      createPagination();
    
      window.addEventListener(
        'resize',
        debounce(() => {
          // Hide the navigation when we don't have more items than we can show on screen
          showHideNavigation();
        }, 250)
      );
    
      glide = new Glide(carouselGlideElement, {
        perView: 4,
        breakpoints: breakpointSettings,
        type: glideType4,
        swipeThreshold: isSwipe4,
        dragThreshold: isSwipe4,
        ...options,
      }).mount();
      return glide;
    };
    
  • URL: /components/raw/carousel/carousel-glide.js
  • Filesystem Path: src/library/components/carousel/carousel-glide.js
  • Size: 8.7 KB
  • Content:
    import debounce from 'lodash.debounce';
    import Glide from '@glidejs/glide';
    
    export default ({ imageGalleryElement, responsive = [], ...options }) => {
      const slides = imageGalleryElement.querySelectorAll('.glide__slides > li');
      const images = imageGalleryElement.querySelectorAll('.image-gallery__img');
      const totalSlides = imageGalleryElement.querySelector(
        '.image-gallery__totalslides'
      );
      const navigation = imageGalleryElement.querySelector(
        '.image-gallery__navigation'
      );
      const MOBILE_BREAKPOINT = 820;
      let DEFAULT_SCREEN_WIDTH;
      let glide = '';
      let transformCount = 0;
      const imgLink = imageGalleryElement.querySelectorAll('.image-gallery__link');
    
      imgLink.forEach(link => {
        if (link) {
          link.removeAttribute('href');
        }
      });
    
      const breakpointSettings = {
        500: {
          perView: 1,
          peek: { before: 0, after: 0 },
        },
        954: {
          perView: 1,
        },
        1200: {
          perView: 1,
          peek: { before: 'auto', after: 'auto' },
          slideWidth: 954,
        },
        ...responsive,
      };
    
      const getCurrentSettings = () => {
        const screenWidth = window.innerWidth;
    
        // Because the `perView` changes at different breakpoints, find
        // the relevant setting for the current screensize.
        // Filter out any settings that are smaller than the current size, and
        // then use the first in the list, as this will be the most relevant.
        // If none are available, assume we are using the biggest setting.
    
        // TODO: We should be able to reuse this, if we want to change the pagination
        // to scroll full pages, rather than individual items
        const breakpointSettingsForCurrentSize =
          Object.keys(breakpointSettings).filter(
            i => parseInt(i, 10) > screenWidth
          )[0] || Object.keys(breakpointSettings).slice(-1);
    
        return breakpointSettings[breakpointSettingsForCurrentSize];
      };
    
      const updateBulletSize = (dot, action) => {
        if (action === 'add') {
          imageGalleryElement
            .querySelector(`.glide-carousel__pagination > [data-slide-no='${dot}']`)
            .classList.add('small');
        } else {
          imageGalleryElement
            .querySelector(`.glide-carousel__pagination > [data-slide-no='${dot}']`)
            .classList.remove('small');
        }
      };
    
      const setBulletDefaultSize = () => {
        const maxDots = 5;
        const totalCount = slides.length;
        const navigationElements = imageGalleryElement.querySelectorAll(
          `.glide-carousel__pagination > [data-slide-no]`
        );
    
        if (totalCount > maxDots) {
          navigationElements.forEach(item => {
            item.classList.remove('small');
          });
          transformCount = 0;
          // eslint-disable-next-line no-param-reassign
          imageGalleryElement.querySelector(
            '.glide-carousel__pagination'
          ).style.transform = 'translateX(0)';
          updateBulletSize(4, 'add');
        }
      };
    
      const setBulletSize = (currentSlide, nextSlide) => {
        const maxDots = 5;
        const transformXIntervalNext = -24;
        const transformXIntervalPrev = 24;
        const totalCount = slides.length;
    
        if (totalCount > maxDots) {
          if (nextSlide > currentSlide) {
            if (
              imageGalleryElement
                .querySelector(
                  `.glide-carousel__pagination > [data-slide-no='${nextSlide}']`
                )
                .classList.contains('small')
            ) {
              if (
                !imageGalleryElement
                  .querySelector(
                    `.glide-carousel__pagination > [data-slide-no]:last-child`
                  )
                  .classList.contains('small')
              ) {
                // eslint-disable-next-line operator-assignment
                transformCount = transformCount + transformXIntervalNext;
                updateBulletSize(nextSlide, 'remove');
                const nextSlidePlusOne = nextSlide + 1;
    
                updateBulletSize(nextSlidePlusOne, 'add');
                // eslint-disable-next-line no-param-reassign
                imageGalleryElement.querySelector(
                  '.glide-carousel__pagination'
                ).style.transform = `translateX(${transformCount}px)`;
                const pPointer = nextSlide - 3;
                const pPointerMinusOne = pPointer - 1;
    
                updateBulletSize(pPointerMinusOne, 'remove');
                updateBulletSize(pPointer, 'add');
              }
            } else {
              // eslint-disable-next-line no-lonely-if
              if (nextSlide === slides.length - 1) {
                const navigationElements = imageGalleryElement.querySelectorAll(
                  `.glide-carousel__pagination > [data-slide-no]`
                );
    
                navigationElements.forEach(item => {
                  item.classList.remove('small');
                });
                updateBulletSize(slides.length - 5, 'add');
                transformCount = (slides.length - 5) * transformXIntervalNext;
                // eslint-disable-next-line no-param-reassign
                imageGalleryElement.querySelector(
                  '.glide-carousel__pagination'
                ).style.transform = `translateX(${transformCount}px)`;
              }
            }
          } else {
            // eslint-disable-next-line no-lonely-if
            if (
              imageGalleryElement
                .querySelector(
                  `.glide-carousel__pagination > [data-slide-no='${nextSlide}']`
                )
                .classList.contains('small')
            ) {
              if (
                !imageGalleryElement
                  .querySelector(
                    `.glide-carousel__pagination > [data-slide-no]:first-child`
                  )
                  .classList.contains('small')
              ) {
                // eslint-disable-next-line operator-assignment
                transformCount = transformCount + transformXIntervalPrev;
                updateBulletSize(nextSlide, 'remove');
                const nextSlidePlusOne = nextSlide - 1;
    
                updateBulletSize(nextSlidePlusOne, 'add');
                // eslint-disable-next-line no-param-reassign
                imageGalleryElement.querySelector(
                  '.glide-carousel__pagination'
                ).style.transform = `translateX(${transformCount}px)`;
                const nPointer = currentSlide + 3;
                const nPointerMinusOne = nPointer - 1;
    
                // console.log(`${nPointer} - ${nPointerMinusOne}`);
                updateBulletSize(nPointer, 'remove');
                updateBulletSize(nPointerMinusOne, 'add');
              }
            } else {
              // eslint-disable-next-line no-lonely-if
              if (nextSlide === 0) {
                setBulletDefaultSize();
              }
            }
          }
        }
      };
    
      const countLeftPad = number => {
        const slideCount = number.toString();
    
        // eslint-disable-next-line no-undef
        return slideCount.padStart(2, '0');
      };
    
      const setSlideCount = currentIndex => {
        const slideCountBlock = imageGalleryElement.querySelector(
          '.image-gallery__totalslides--count'
        );
    
        slideCountBlock.innerHTML = `${countLeftPad(
          currentIndex + 1
        )}/${countLeftPad(slides.length)}`;
      };
    
      const showPaginationByPage = () => {
        // Glide shows a pagination button for each item, and doesn't provide
        // an option to navigate whole pages at a time.
        // This function hides extra individual dots, so that only the first item of
        // each page is shown. (Based on the `perView` setting).
        const { perView } = getCurrentSettings();
    
        const paginationElements = imageGalleryElement.querySelectorAll(
          `.glide-carousel__pagination button:not(:nth-child(${perView}n + 1))`
        );
    
        paginationElements.forEach(item => {
          item.classList.add('hidden');
        });
    
        setSlideCount(0);
        setBulletDefaultSize();
      };
    
      const showHideNavigation = () => {
        const maxPerView = getCurrentSettings().perView;
        const navigationElements = imageGalleryElement.querySelectorAll(
          '[data-slide-no]'
        );
    
        if (!slides || slides.length <= maxPerView) {
          navigationElements.forEach(item => item.classList.add('hidden'));
          // eslint-disable-next-line no-param-reassign
          imageGalleryElement.querySelector(
            '.image-gallery__navigation'
          ).style.display = 'none';
          // eslint-disable-next-line no-param-reassign
          imageGalleryElement.querySelector(
            '.image-gallery__totalslides'
          ).style.display = 'none';
          imageGalleryElement
            .querySelector('.glide__slides')
            .classList.add('singleslide');
          return;
        }
        navigationElements.forEach(item => item.classList.remove('hidden'));
    
        showPaginationByPage();
      };
    
      const createPagination = () => {
        const bulletContainer = document.createElement('div');
    
        bulletContainer.classList.add('glide-carousel__pagination');
        bulletContainer.dataset.glideEl = 'controls[nav]';
    
        slides.forEach((slide, index) => {
          const button = document.createElement('button');
    
          button.dataset.slideNo = `${index}`;
          button.tabIndex = '-1';
          bulletContainer.appendChild(button);
        });
    
        imageGalleryElement
          .querySelector('.carousel-nav-wrapper')
          .appendChild(bulletContainer);
        showHideNavigation();
      };
    
      const setPeekVal = () => {
        let peekVal = 0;
        const currentSlide = imageGalleryElement.querySelector(
          '.glide__slide--active'
        );
    
        if (document.body.clientWidth > 954) {
          peekVal = (document.body.clientWidth - 954) / 2;
        }
        glide.update({
          peek: { before: peekVal, after: peekVal },
        });
        totalSlides.style.maxWidth = `${currentSlide.clientWidth}px`;
      };
    
      createPagination();
    
      const formatUIElementsMobile = () => {
        DEFAULT_SCREEN_WIDTH = window.innerWidth;
    
        // Disabled for desktop
        if (window.innerWidth >= MOBILE_BREAKPOINT) {
          totalSlides.removeAttribute('style');
          navigation.removeAttribute('style');
          return;
        }
    
        const currentImage = images[glide.index];
        const imageHeight = currentImage.offsetHeight;
    
        totalSlides.style.position = 'absolute';
        navigation.style.position = 'absolute';
        totalSlides.style.top = `${16 + imageHeight}px`;
        navigation.style.top = `${16 + imageHeight}px`;
      };
    
      glide = new Glide(imageGalleryElement, {
        perView: 1,
        type: 'slider',
        breakpoints: breakpointSettings,
        peek: { before: 100, after: 100 },
        ...options,
      }).mount();
    
      // fix for big screen when screen size bigger than carousel width
      glide.on('build.after', () => {
        if (document.body.clientWidth > slides.length * 954) {
          const offsetVal = (954 + 10) / 2;
          const carousel = imageGalleryElement.querySelector('.glide__slides');
    
          carousel.style.transform = `translate3d(${offsetVal}px, 0px, 0px)`;
        }
      });
    
      glide.on('run', () => {
        const currentSlide = imageGalleryElement
          .querySelector(
            '.glide-carousel__pagination > [data-slide-no].glide__bullet--active'
          )
          .getAttribute('data-slide-no');
        const nextSlide = glide.index;
    
        setInterval(() => {
          imgLink.forEach(link => {
            if (link) {
              link.removeAttribute('href');
            }
          });
        }, 10);
    
        // console.log(`${currentSlide} - ${nextSlide}`);
        // eslint-disable-next-line radix
        setBulletSize(parseInt(currentSlide), nextSlide);
        setSlideCount(nextSlide);
        updateBulletSize(nextSlide, 'remove');
    
        // fix for big screen when screen size bigger than carousel width
        if (document.body.clientWidth > slides.length * 954) {
          let offsetVal = (954 + 10) / 2;
          const carousel = imageGalleryElement.querySelector('.glide__slides');
    
          offsetVal =
            glide.index === slides.length - 1 ? `-${offsetVal}` : offsetVal;
          carousel.style.transform = `translate3d(${offsetVal}px, 0px, 0px)`;
        }
      });
    
      if (slides.length === 1) {
        glide.update({
          type: 'slider',
          peek: { before: 0, after: 0 },
        });
      } else {
        setPeekVal();
      }
    
      // If there is no description in image gallery component
      const imageDesc = document.querySelector('.image-gallery__caption');
    
      if (window.innerWidth <= MOBILE_BREAKPOINT) {
        if (!imageDesc) {
          const getCarouselPagination = document.querySelector(
            '.image-gallery .carousel-nav-block'
          );
    
          getCarouselPagination.classList.add('align-pagination');
        }
      }
    
      slides.forEach((slide, index) => {
        slide.addEventListener('focus', () => {
          glide.go(`=${index}`);
        });
      });
    
      // run UI Function after Glidejs and other JS has loaded
      window.addEventListener('load', () => {
        formatUIElementsMobile();
      });
    
      window.addEventListener(
        'resize',
        debounce(() => {
          // Hide the navigation when we don't have more items than we can show on screen
          showHideNavigation();
          setPeekVal();
          if (DEFAULT_SCREEN_WIDTH !== window.innerWidth) {
            formatUIElementsMobile();
          }
        }, 250)
      );
    
      return glide;
    };
    
  • URL: /components/raw/carousel/carousel-image-gallery.js
  • Filesystem Path: src/library/components/carousel/carousel-image-gallery.js
  • Size: 12.8 KB
  • Content:
    import Glider from '../../behaviours/carousel/glider/glider';
    
    export default ({ carouselElement, responsive = [], ...options }) => {
      const defaultOptions = {
        slidesToShow: 1,
        slidesToScroll: 1,
        scrollLock: true,
        draggable: true,
        arrows: {
          prev: '.carousel__prev',
          next: '.carousel__next',
        },
        dots: '.carousel__pagination',
        responsive: [
          {
            breakpoint: 600,
            settings: {
              slidesToShow: 2,
              slidesToScroll: 2,
            },
          },
          {
            breakpoint: 900,
            settings: {
              slidesToShow: 3,
              slidesToScroll: 3,
            },
          },
          {
            breakpoint: 1200,
            settings: {
              slidesToShow: 4,
              slidesToScroll: 4,
            },
          },
          ...responsive,
        ],
      };
    
      return new Glider(carouselElement, {
        ...defaultOptions,
        ...options,
      });
    };
    
  • URL: /components/raw/carousel/carousel.js
  • Filesystem Path: src/library/components/carousel/carousel.js
  • Size: 893 Bytes
  • Content:
    .glide__slides {
      margin: 0 auto;
      > li {
        display: flex;
        justify-content: center;
      }
    }
    
    [data-glide-el='track'] {
      overflow: hidden;
    }
    
    .mobile-carousel {
      [data-glide-el='track'] {
        overflow-x: auto !important;
        overflow-y: hidden !important;
        width: auto !important;
      }
      .glide__slides {
        overflow-x: auto !important;
        overflow-y: hidden !important;
        touch-action: initial !important;
        padding-left: 3.2rem;
        & > li {
          &:first-child {
            margin-left: 0;
          }
    
          margin: 0 0.6rem;
        }
        .article-session-card {
          width: 174px;
          min-width: 174px;
        }
      }
      ::-webkit-scrollbar {
        width: 1px;
      }
    }
    
    @mixin carousel-cta {
      align-items: center;
      appearance: none;
      background-color: $grey;
      border: 2px solid rgba(0, 0, 0, 0);
      border-radius: 50%;
      color: $black;
      display: flex;
      height: 0.8rem;
      justify-content: center;
      transition: background-color 0.2s ease-in;
      transition: border 0.2s ease-in;
      width: 0.8rem;
      white-space: nowrap;
    }
    
    .glider-track {
      margin: auto;
    }
    // TODO: Review this once more usecases established
    // We should look to remove markup based selectors and
    // this style might be better placed on individual usages.
    .glider-slide > * {
      margin-left: auto;
      margin-right: auto;
    }
    
    .carousel-nav-block {
      text-align: center;
      padding-bottom: 2.5rem;
    }
    .carousel-nav-wrapper {
      position: relative;
      display: inline-flex;
      align-items: center;
    }
    
    .carousel {
      &-navigation {
        display: flex;
        justify-content: flex-end;
        margin-bottom: 2rem;
      }
      &__cta {
        @include text-s--narrow;
        @include carousel-cta;
    
        svg {
          width: 0.8rem;
          height: 1.5rem;
        }
      }
      &__prev {
        position: absolute;
        left: -50px;
        transform: rotate(180deg);
        margin-right: $spacing-m;
        width: 4.4rem !important;
        height: 4.4rem !important;
        border: 2px solid rgba(0, 0, 0, 255);
        background-color: $white;
        color: black;
        &:hover {
          border: 2px solid $blue !important;
        }
      }
      &__next {
        position: absolute;
        right: -50px;
        width: 4.4rem !important;
        height: 4.4rem !important;
        border: 2px solid rgba(0, 0, 0, 255);
        background-color: $white;
        color: black;
        &:hover {
          border: 1px solid $blue !important;
        }
      }
      &__pagination {
        display: flex;
        justify-content: center;
        margin-top: $spacing-xxl;
        transition: all 0.25s;
    
        button {
          background-color: $grey;
          border: none;
          border-radius: 50%;
          height: 0.8rem;
          padding: 0;
          margin: 0 $spacing-s;
          width: 0.8rem;
    
          &.active {
            background-color: $blue;
          }
          &.glide__bullet--active {
            background-color: $blue;
          }
          &.small {
            transform: scale(0.5);
            transition: transform 300ms;
          }
          &.inactive {
            transform: scale(0);
            transition: transform 300ms;
            display: none;
          }
        }
      }
    
      @media screen and (min-width: $mq-medium) {
        &__pagination {
          counter-reset: pagination;
    
          button {
            @include carousel-cta;
            @include text-m;
    
            cursor: pointer;
    
            &:not(.active):not(.glide__bullet--active) {
              opacity: 0.7;
            }
    
            /* &::before {
              counter-increment: pagination;
              content: counter(pagination);
            } */
          }
        }
        &__cta {
          @include text-s--narrow;
          @include carousel-cta;
    
          svg {
            width: 0.8rem;
            height: 1.5rem;
          }
    
          &:not(.disabled) {
            cursor: pointer;
          }
    
          &:hover {
            border: 2px solid $black;
          }
    
          &.disabled {
            border: 2px solid $color-disabled !important;
            background-color: $crest-blue !important;
            color: $blue !important;
          }
        }
      }
    }
    
    //
    @media screen and (min-width: $mq-medium) {
      .mobile-carousel {
        .glide__slides {
          .article-session-card {
            width: auto;
            min-width: initial;
          }
        }
      }
      .carousel-container {
        max-width: 114rem;
      }
      .carousel-navigation {
        margin-bottom: 0;
      }
      .carousel--desktop-reset {
        .glider-track {
          width: 100% !important; // important used to override js
          flex-wrap: wrap;
        }
        [data-glide-el='track'] {
          width: 100% !important; // important used to override js
          flex-wrap: wrap;
        }
        .carousel {
          &__pagination,
          &-navigation {
            display: none;
          }
        }
      }
      .carousel__prev {
        position: absolute;
        left: -75px;
      }
      .carousel__next {
        position: absolute;
        right: -75px;
      }
    }
    
    @media (min-width: $mq-large) {
      .glider-track .glider-slide {
        float: left;
        width: 25% !important;
      }
    }
    
    .glide-carousel__pagination {
      @extend .carousel__pagination;
    }
    
    .image-gallery {
      .carousel-nav-wrapper {
        width: 11.5rem;
        overflow: hidden;
        justify-content: center;
      }
    }
    
  • URL: /components/raw/carousel/carousel.scss
  • Filesystem Path: src/library/components/carousel/carousel.scss
  • Size: 4.9 KB
  • Content:
    import debounce from 'lodash.debounce';
    import Glide from '@glidejs/glide';
    
    export default ({
      fullWidthCarouselGlideElement,
      responsive = [],
      ...options
    }) => {
      const slides = fullWidthCarouselGlideElement.querySelectorAll(
        '.glide__slides > *'
      );
      const carouselLoop = fullWidthCarouselGlideElement.getAttribute(
        'data-carousel-loop'
      );
      const paginationNavBlock = fullWidthCarouselGlideElement.querySelector(
        '.full-width-carousel-nav-block'
      );
      const SMALL_MOBILE_BREAKPOINT = 500;
      const MOBILE_BREAKPOINT = 820;
      let glide;
      let animationTime;
      const defaultWidth = window.innerWidth;
    
      if (window.innerWidth > MOBILE_BREAKPOINT) {
        animationTime = 700;
      } else {
        animationTime = 200;
      }
    
      const breakpointSettings = {
        500: {
          perView: 2,
          type: 'slider',
          peek: 0,
          gap: 12,
          swipeThreshold: true,
          dragThreshold: true,
        },
        744: {
          perView: 2,
        },
        1200: {
          perView: 3,
        },
        1366: {
          perView: 4,
        },
        1500: {
          perView: 4,
        },
        1921: {
          perView: 5,
        },
        2200: {
          perView: 6,
        },
        2321: {
          perView: 7,
        },
        2560: {
          perView: 8,
        },
        2632: {
          perView: 10,
        },
        ...responsive,
      };
    
      const visiblePipsOnFocus = () => {
        if (!slides.length) {
          return;
        }
        const pips = fullWidthCarouselGlideElement.querySelector(
          '.glide-carousel__pagination'
        );
        const pipsArray = Array.from(pips.children);
    
        pipsArray.forEach(child => {
          const pip = child;
    
          pip.onfocus = () => {
            paginationNavBlock.style.opacity = '1';
          };
        });
      };
    
      const getCurrentSettings = () => {
        const screenWidth = window.innerWidth;
    
        // Because the `perView` changes at different breakpoints, find
        // the relevant setting for the current screensize.
        // Filter out any settings that are smaller than the current size, and
        // then use the first in the list, as this will be the most relevant.
        // If none are available, assume we are using the biggest setting.
    
        // TODO: We should be able to reuse this, if we want to change the pagination
        // to scroll full pages, rather than individual items
        const breakpointSettingsForCurrentSize =
          Object.keys(breakpointSettings).filter(
            i => parseInt(i, 10) > screenWidth
          )[0] || Object.keys(breakpointSettings).slice(-1);
    
        return breakpointSettings[breakpointSettingsForCurrentSize];
      };
    
      const enablePrevButton = () => {
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__prev')
          .classList.remove('disabled');
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__prev')
          .removeAttribute('disabled');
      };
    
      const enableNextButton = () => {
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__next')
          .classList.remove('disabled');
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__next')
          .removeAttribute('disabled');
      };
    
      const disablePrevButton = () => {
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__prev')
          .classList.add('disabled');
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__prev')
          .setAttribute('disabled', true);
      };
    
      const disableNextButton = () => {
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__next')
          .classList.add('disabled');
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__next')
          .setAttribute('disabled', true);
      };
    
      const setSlidesWidth = glideSlides => {
        if (!slides.length) {
          return;
        }
        // setting the width of the full width wrapper component
        const wrapper = slides[0].parentElement.parentElement;
    
        wrapper.style.width = `${document.body.clientWidth}px`;
    
        let slideWidth;
        let gap;
        const numberOfSlides = glideSlides.length;
        const glideElement = fullWidthCarouselGlideElement.querySelector(
          '.glide__slides'
        );
    
        if (window.innerWidth > MOBILE_BREAKPOINT) {
          slideWidth = 274;
          gap = 16;
          glideElement.style.maxWidth = `${(slideWidth + gap) * numberOfSlides +
            70}px`;
          glideElement.style.minWidth = `${(slideWidth + gap) * numberOfSlides +
            70}px`;
        }
      };
    
      const showPaginationByPage = () => {
        // Glide shows a pagination button for each item, and doesn't provide
        // an option to navigate whole pages at a time.
        // This function hides extra individual dots, so that only the first item of
        // each page is shown. (Based on the `perView` setting).
        const { perView } = getCurrentSettings();
    
        const paginationElements = fullWidthCarouselGlideElement.querySelectorAll(
          `.glide-carousel__pagination button:not(:nth-child(${perView}n + 1))`
        );
        const visiblePaginationElements = fullWidthCarouselGlideElement.querySelectorAll(
          `.glide-carousel__pagination button:nth-child(${perView}n + 1)`
        );
    
        const titleElement = fullWidthCarouselGlideElement.parentElement.querySelector(
          'h2'
        );
        let title = 'Full Width';
    
        if (titleElement) {
          title = titleElement.innerHTML;
        }
    
        paginationElements.forEach(item => {
          item.classList.add('hidden');
        });
    
        visiblePaginationElements.forEach((item, index) => {
          if (!index) {
            // eslint-disable-next-line no-param-reassign
            item.ariaLabel = `${title} Carousel Page - ${index + 1} active`;
          } else {
            // eslint-disable-next-line no-param-reassign
            item.ariaLabel = `${title} Carousel Page - ${index + 1}`;
          }
        });
    
        if (carouselLoop && window.innerWidth > MOBILE_BREAKPOINT) {
          return;
        }
        setSlidesWidth(slides);
      };
    
      const slideToNext = () => {
        const maxPerView = getCurrentSettings().perView;
    
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__next')
          .addEventListener('click', event => {
            const { target } = event;
            let activeDots = 0;
    
            fullWidthCarouselGlideElement
              .querySelectorAll('.glide-carousel__pagination > *')
              .forEach((dot, index) => {
                if (dot.getAttribute('class') === 'glide__bullet--active') {
                  activeDots = index;
                }
              });
    
            const nextSlide = activeDots + maxPerView;
    
            if (carouselLoop && window.innerWidth > MOBILE_BREAKPOINT) {
              if (nextSlide > slides.length) {
                glide.go(`=0`);
              } else {
                glide.go(`=${nextSlide}`);
              }
            } else {
              glide.go(`=${nextSlide}`);
              if (nextSlide + maxPerView > slides.length) {
                target.closest('button').classList.add('disabled');
                target.closest('button').setAttribute('disabled', true);
              }
              enablePrevButton();
            }
          });
      };
    
      const slideToPrevious = () => {
        const maxPerView = getCurrentSettings().perView;
    
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel__prev')
          .addEventListener('click', event => {
            const { target } = event;
            let activeDots = 0;
    
            fullWidthCarouselGlideElement
              .querySelectorAll('.glide-carousel__pagination > *')
              .forEach((dot, index) => {
                if (dot.getAttribute('class') === 'glide__bullet--active') {
                  activeDots = index;
                }
              });
    
            const prevSlide = activeDots - maxPerView;
    
            if (carouselLoop && window.innerWidth > MOBILE_BREAKPOINT) {
              if (prevSlide < 0) {
                const lastslide =
                  Math.floor(slides.length / maxPerView) * maxPerView;
    
                glide.go(`=${lastslide}`);
              } else {
                glide.go(`=${prevSlide}`);
              }
            } else {
              if (prevSlide >= 0) {
                glide.go(`=${prevSlide}`);
              }
    
              if (prevSlide - maxPerView < 0) {
                target.closest('button').classList.add('disabled');
                target.closest('button').setAttribute('disabled', true);
              }
    
              enableNextButton();
            }
          });
      };
    
      const enableNextPrev = () => {
        const maxPerView = getCurrentSettings().perView;
    
        fullWidthCarouselGlideElement
          .querySelectorAll('.glide-carousel__pagination > *')
          .forEach((dot, index) => {
            dot.addEventListener('click', () => {
              if (index > 0) {
                enablePrevButton();
              }
              if (index === 0) {
                enableNextButton();
                disablePrevButton();
              }
              if (index + maxPerView > slides.length) {
                disableNextButton();
              }
              if (index + maxPerView < slides.length) {
                enableNextButton();
              }
            });
          });
      };
    
      const showHideNavigation = () => {
        const maxPerView = getCurrentSettings().perView;
    
        const navigationElements = fullWidthCarouselGlideElement.querySelectorAll(
          '[data-glide-dir]'
        );
    
        if (!slides || slides.length <= maxPerView) {
          const glideElement = fullWidthCarouselGlideElement.querySelector(
            '.glide__slides'
          );
    
          navigationElements.forEach(item => item.classList.add('hidden'));
          // eslint-disable-next-line no-param-reassign
          fullWidthCarouselGlideElement.querySelector(
            '.full-width-carousel-nav-block'
          ).style.display = 'none';
          glideElement.style.overflow = 'visible';
          glideElement.style.margin = '0';
          return;
        }
        navigationElements.forEach(item => {
          item.classList.remove('hidden');
          item.removeAttribute('aria-label');
        });
        showPaginationByPage();
        // added manual arrow next/previous button action
        slideToNext();
        slideToPrevious();
        enableNextPrev();
      };
    
      const createPagination = () => {
        if (!slides.length) {
          return;
        }
        const bulletContainer = document.createElement('div');
    
        bulletContainer.classList.add('glide-carousel__pagination');
        bulletContainer.dataset.glideEl = 'controls[nav]';
    
        slides.forEach((slide, index) => {
          const button = document.createElement('button');
    
          button.dataset.glideDir = `=${index}`;
          bulletContainer.appendChild(button);
        });
    
        fullWidthCarouselGlideElement
          .querySelector('.full-width-carousel-nav-wrapper')
          .appendChild(bulletContainer);
        showHideNavigation();
        // disabling prev button by default
        disablePrevButton();
        setSlidesWidth(slides);
    
        if (window.innerWidth > MOBILE_BREAKPOINT) {
          slides[0].parentElement.style.paddingLeft = '7rem';
        } else {
          slides[0].parentElement.style.paddingLeft = '3.2rem';
        }
      };
    
      const updatePagination = glideIndex => {
        const pips = fullWidthCarouselGlideElement.querySelector(
          '.glide-carousel__pagination'
        );
        const pipsArray = Array.from(pips.children);
    
        pipsArray.forEach((child, index) => {
          const pip = child;
    
          if (index === glideIndex) {
            pip.ariaSelected = true;
            // eslint-disable-next-line no-param-reassign
            const label = pip.ariaLabel;
    
            pip.ariaLabel = `${label} active`;
          } else {
            pip.ariaSelected = false;
            if (pip.ariaLabel) {
              const label = pip.ariaLabel.replace(' active', '');
    
              // eslint-disable-next-line no-param-reassign
              pip.ariaLabel = `${label}`;
            }
          }
        });
      };
    
      createPagination();
    
      window.addEventListener(
        'resize',
        debounce(() => {
          // Hide the navigation when we don't have more items than we can show on screen
          if (defaultWidth !== window.innerWidth) {
            showHideNavigation();
            setSlidesWidth(slides);
          }
        }, 250)
      );
    
      glide = new Glide(fullWidthCarouselGlideElement, {
        perView: 4,
        breakpoints: breakpointSettings,
        type: 'slider',
        swipeThreshold: false,
        dragThreshold: false,
        peek: 50,
        gap: 16,
        animationDuration: animationTime,
        animationTimingFunc: 'ease',
        ...options,
      }).mount();
    
      visiblePipsOnFocus();
    
      glide.on('run.after', () => {
        const maxPerView = getCurrentSettings().perView;
    
        if (window.innerWidth > SMALL_MOBILE_BREAKPOINT) {
          if (glide.index < 1) {
            enableNextButton();
            if (window.innerWidth > MOBILE_BREAKPOINT) {
              slides[0].parentElement.style.paddingLeft = '7rem';
            } else {
              slides[0].parentElement.style.paddingLeft = '3.2rem';
            }
          } else if (glide.index + maxPerView > slides.length - 1) {
            disableNextButton();
            slides[0].parentElement.style.paddingLeft = '0';
            const slidesWidth = parseInt(
              slides[0].parentElement.style.minWidth,
              10
            );
            const slidesOffset = slidesWidth - document.body.clientWidth;
    
            slides[0].parentElement.style.transform = `translate3d(-${slidesOffset}px, 0px, 0px)`;
          } else {
            enableNextButton();
            slides[0].parentElement.style.paddingLeft = '0';
          }
        }
        updatePagination(glide.index);
      });
    
      if (window.innerWidth <= MOBILE_BREAKPOINT) {
        glide.destroy();
        fullWidthCarouselGlideElement.classList.add('mobile-carousel');
      }
    
      return glide;
    };
    
  • URL: /components/raw/carousel/full-width-carousel-glide.js
  • Filesystem Path: src/library/components/carousel/full-width-carousel-glide.js
  • Size: 13.3 KB
  • Content:
    import { gsap } from 'gsap';
    import debounce from 'lodash.debounce';
    import Glide from '@glidejs/glide';
    import { animationTime } from '../../modules/efl-get-started/efl-get-started';
    
    const renderSlideDiv = (slideContainer, slides) => {
      let slideCardContainer;
      const MOBILE_BREAKPOINT = 768;
    
      // eslint-disable-next-line no-param-reassign
      slideContainer.innerHTML = '';
    
      slides.forEach((slide, index) => {
        const listElement = document.createElement('li');
    
        if (!index) {
          listElement.appendChild(slide);
          slideContainer.appendChild(listElement);
        } else {
          const itemPos = index - 1;
          let perView = 1;
    
          if (window.innerWidth >= MOBILE_BREAKPOINT && window.innerWidth < 1045) {
            perView = 2;
          } else if (window.innerWidth > 1045) {
            perView = 3;
          }
          if (itemPos === 0 || (index && itemPos % perView === 0)) {
            const cardElement = document.createElement('div');
    
            cardElement.className = 'card';
    
            cardElement.appendChild(slide);
            listElement.appendChild(cardElement);
            slideContainer.appendChild(listElement);
            slideCardContainer = cardElement;
          } else if (slideCardContainer) {
            slideCardContainer.appendChild(slide);
          }
        }
      });
    };
    
    // get started become coach functions
    export default ({ getStartedCarouselElement, responsive = [], ...options }) => {
      const slides = getStartedCarouselElement.querySelectorAll(
        '.glide__slides > *'
      );
      const contentOverlay = document.querySelector(
        '.get-started-become-coach__overlay'
      );
      const MOBILE_BREAKPOINT = 768;
      let glide;
      let defaultWidth = window.innerWidth;
      const slideContainer = getStartedCarouselElement.querySelector(
        '.glide__slides'
      );
    
      const breakpointSettings = {
        500: {
          perView: 1,
          type: 'slider',
          peek: 0,
          gap: 12,
          swipeThreshold: true,
          dragThreshold: true,
        },
        820: {
          perView: 1,
        },
        ...responsive,
      };
    
      window.addEventListener(
        'resize',
        debounce(() => {
          // Hide the navigation when we don't have more items than we can show on screen
          if (defaultWidth !== window.innerWidth) {
            if (window.innerWidth < MOBILE_BREAKPOINT) {
              glide.destroy();
              getStartedCarouselElement.classList.add('mobile-carousel');
            } else {
              getStartedCarouselElement.classList.remove('mobile-carousel');
              slideContainer.removeAttribute('style');
            }
            renderSlideDiv(slideContainer, slides);
            defaultWidth = window.innerWidth;
          }
        }, 250)
      );
    
      gsap.set(contentOverlay, { y: 0, ease: 'none' });
    
      renderSlideDiv(slideContainer, slides);
    
      glide = new Glide(getStartedCarouselElement, {
        perView: 1,
        breakpoints: breakpointSettings,
        type: 'slider',
        swipeThreshold: false,
        dragThreshold: false,
        peek: 0,
        gap: 16,
        animationDuration: animationTime,
        animationTimingFunc: 'cubic-bezier(0.16, 1, 0.3, 1)',
        ...options,
      }).mount();
    
      if (window.innerWidth < MOBILE_BREAKPOINT) {
        glide.destroy();
        getStartedCarouselElement.classList.add('mobile-carousel');
      }
    
      return glide;
    };
    
    export { renderSlideDiv };
    
  • URL: /components/raw/carousel/get-started-carousel-glide.js
  • Filesystem Path: src/library/components/carousel/get-started-carousel-glide.js
  • Size: 3.2 KB
<div class="carousel-container">
  <div class="carousel" data-behavior="carousel">
    <div>
      <div style="border:2px solid; height: 300px;"> 1 </div>
    </div>
    <div>
      <div style="border:2px solid; height: 300px;"> 2 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 3 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 4 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 5 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 6 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 7 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 8 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 9 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 10 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 11</div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 12 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 13 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 14 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 15 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 16 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 17 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 18 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 19 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 20 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 21 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 22 </div>
    </div>
    <div>
      <div style="border:2px solid ; height: 300px;"> 23 </div>
    </div>
    
  </div>
  <div class="carousel-nav-block">
    <div class="carousel-nav-wrapper">
      <div role="tablist" class="carousel__pagination"></div>
      <div class="carousel-navigation">
          <button aria-label="Previous" class="carousel__cta carousel__prev"><span class="visually-hidden">Previous
              page</span><svg fill="none" viewBox="0 0 10 17" xmlns="http://www.w3.org/2000/svg">
              <path
                d="m9.2722 9.3355-6.75 6.75c-0.46089 0.4609-1.2087 0.4609-1.6706 0-0.46089-0.4609-0.46089-1.2097 0-1.6706l5.9146-5.9146-5.9146-5.9146c-0.46089-0.46089-0.46089-1.2097 0-1.6706 0.46194-0.46089 1.2097-0.46089 1.6706 0l6.75 6.75c0.46194 0.46089 0.46194 1.2097 0 1.6706v-1.4e-4z"
                fill="currentColor" />
            </svg></button>
          <button aria-label="Next" class="carousel__cta carousel__next"><span class="visually-hidden">Next
              page</span><svg fill="none" viewBox="0 0 10 17" xmlns="http://www.w3.org/2000/svg">
              <path
                d="m9.2722 9.3355-6.75 6.75c-0.46089 0.4609-1.2087 0.4609-1.6706 0-0.46089-0.4609-0.46089-1.2097 0-1.6706l5.9146-5.9146-5.9146-5.9146c-0.46089-0.46089-0.46089-1.2097 0-1.6706 0.46194-0.46089 1.2097-0.46089 1.6706 0l6.75 6.75c0.46194 0.46089 0.46194 1.2097 0 1.6706v-1.4e-4z"
                fill="currentColor" />
            </svg></button>
      </div>
    </div>
  </div>
</div>