diff --git a/blocks/carousel/carousel.css b/blocks/carousel/carousel.css
index d06af1a..65baf92 100755
--- a/blocks/carousel/carousel.css
+++ b/blocks/carousel/carousel.css
@@ -1,170 +1,128 @@
-.carousel .carousel-slides-container {
+.carousel-wrapper {
position: relative;
}
-.carousel .carousel-slides,
-.carousel .carousel-slide-indicators {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-.carousel .carousel-slides {
- display: flex;
- scroll-behavior: smooth;
- scroll-snap-type: x mandatory;
- overflow: scroll clip;
+.carousel.swiper-carousel {
+ width: 100%;
+ height: 100%;
+ margin: 32px 0;
+ overflow: hidden;
}
-.carousel .carousel-slides::-webkit-scrollbar {
- display: none;
+.carousel {
+ padding-bottom: 28px;
+ position: relative;
}
-.carousel .carousel-slide {
- flex: 0 0 100%;
- scroll-snap-align: start;
+.carousel .swiper-slide {
+ text-align: left;
+ font-size: 18px;
display: flex;
- flex-direction: column;
+ flex-direction: row;
+ gap: 24px;
align-items: flex-start;
- justify-content: center;
- position: relative;
+}
+
+.carousel .swiper-slide img {
+ display: block;
width: 100%;
- min-height: min(40rem, calc(100svh - var(--nav-height)));
+ height: 100%;
+ object-fit: cover;
}
-.carousel .carousel-slide:has(.carousel-slide-content[data-align="center"]) {
- align-items: center;
+.carousel .swiper-slide:nth-child(2n + 1) > div:nth-child(1) {
+ width: 55.8333%;
}
-.carousel .carousel-slide:has(.carousel-slide-content[data-align="right"]) {
- align-items: flex-end;
+.carousel .swiper-slide:nth-child(2n + 1) > div:nth-child(2) {
+ width: calc(100% - 55.8333%);
+ text-align: left;
}
-.carousel .carousel-slide .carousel-slide-image picture {
- position: absolute;
- inset: 0;
+.carousel .swiper-slide:nth-child(2n) picture {
+ width: 232px;
+ display: block;
+ margin-left: 50px;
}
-.carousel .carousel-slide .carousel-slide-image picture > img {
- height: 100%;
- width: 100%;
- object-fit: cover;
+.carousel .swiper-slide h2 {
+ margin-top: 24px;
+ font-size: 28px;
+ line-height: 36px;
+ text-transform: uppercase;
}
-.carousel .carousel-slide .carousel-slide-content {
- z-index: 1;
- padding: 1rem;
- margin: 1.5rem 3rem;
- color: white;
- background-color: rgba(0 0 0 / 50%);
- position: relative;
- width: var(--slide-content-width, auto);
+.carousel .swiper-slide p {
+ font-size: 16px;
+ line-height: 24px;
}
-.carousel .carousel-slide-indicators {
+.carousel .button-container .button {
+ margin: 0;
display: flex;
- justify-content: center;
- gap: 0.5rem;
+ gap: 8px;
+ align-items: center;
}
-.carousel .carousel-slide-indicator button {
- width: 1rem;
- height: 1rem;
+.carousel .button-container .button .icon {
padding: 0;
- border-radius: 1rem;
- background-color: rgba(0 0 0 / 25%);
}
-.carousel .carousel-slide-indicator button:disabled,
-.carousel .carousel-slide-indicator button:hover,
-.carousel .carousel-slide-indicator button:focus-visible {
- background-color: rgba(0 0 0 / 80%);
+.carousel-wrapper .swiper-button-next,
+.carousel-wrapper .swiper-button-prev {
+ right: 0;
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: transparent;
+ color: rgb(0 0 0);
+ border: 1px solid rgb(0 0 0 / 0%);
+ width: 2.5rem;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ padding: 0;
+ height: 100%;
+ top: 0;
+ margin: 0;
}
-.carousel .carousel-slide-indicator span,
-.carousel .carousel-navigation-buttons span {
- border: 0;
- clip: rect(0 0 0 0);
- clip-path: inset(50%);
- height: 1px;
- margin: -1px;
- overflow: hidden;
- padding: 0;
- position: absolute;
- width: 1px;
- white-space: nowrap;
+.carousel-wrapper .swiper-button-next {
+ right: -40px;
}
-.carousel .carousel-navigation-buttons {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- left: 0.5rem;
- right: 0.5rem;
- display: flex;
- align-items: center;
- justify-content: space-between;
- z-index: 1;
+.carousel-wrapper .swiper-button-prev {
+ left: -40px;
}
-/* stylelint-disable-next-line no-descending-specificity */
-.carousel .carousel-navigation-buttons button {
- border-radius: 8px;
- margin: 0;
- padding: 0;
- width: 2rem;
- height: 2rem;
- position: relative;
- background-color: rgba(0 0 0 / 25%);
+.carousel-wrapper .swiper-button-next:hover,
+.carousel-wrapper .swiper-button-prev:hover {
+ background-color: rgb(0 0 0 / 8%);
}
-.carousel .carousel-navigation-buttons button:hover,
-.carousel .carousel-navigation-buttons button:focus-visible {
- background-color: rgba(0 0 0 / 80%);
+.carousel-wrapper .carousel .swiper-pagination {
+ top: unset;
+ left: 50%;
+ bottom: -28px;
+ transform: translateX(-50%);
+ position: relative;
+ width: 160px;
+ height: 0.5rem;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ background-color: rgb(0 0 0 / 12%);
+ border-radius: 6px;
}
-.carousel .carousel-navigation-buttons button::after {
- display: block;
- content: "";
- border: 3px white solid;
- border-bottom: 0;
- border-left: 0;
- height: 0.75rem;
- width: 0.75rem;
- position: absolute;
- top: 50%;
- left: calc(50% + 3px);
- transform: translate(-50%, -50%) rotate(-135deg);
-}
-
-.carousel .carousel-navigation-buttons button.slide-next::after {
- transform: translate(-50%, -50%) rotate(45deg);
- left: calc(50% - 3px);
-}
-
-@media (width >= 600px) {
- .carousel .carousel-navigation-buttons {
- left: 1rem;
- right: 1rem;
- }
-
- .carousel .carousel-navigation-buttons button {
- width: 3rem;
- height: 3rem;
- }
-
- .carousel .carousel-navigation-buttons button::after {
- width: 1rem;
- height: 1rem;
- }
-
- .carousel .carousel-slide .carousel-slide-content {
- --slide-content-width: 50%;
-
- margin: 2.5rem 5rem;
- }
-
- .carousel .carousel-slide .carousel-slide-content[data-align="justify"] {
- --slide-content-width: auto;
- }
+.carousel-wrapper .carousel .swiper-pagination-progressbar-fill {
+ transform: translate3d(0, 0, 0) scaleX(0.2) scaleY(1);
+ transition-duration: 300ms;
+ min-width: 6px;
+ height: 6px;
+ background: rgb(0 0 0);
+ border: 0;
+ border-radius: 6px;
+ cursor: pointer;
+ appearance: none;
}
diff --git a/blocks/carousel/carousel.js b/blocks/carousel/carousel.js
index 2b1ae16..2d15fcb 100755
--- a/blocks/carousel/carousel.js
+++ b/blocks/carousel/carousel.js
@@ -1,150 +1,46 @@
-import { fetchPlaceholders } from '../../scripts/aem.js';
+import { loadCSS, loadScript } from '../../scripts/aem.js';
+
+const buildSlider = () => {
+ // eslint-disable-next-line no-undef, no-new
+ new Swiper('.swiper-carousel', {
+ slidesPerView: 2,
+ spaceBetween: 30,
+ pagination: {
+ el: '.swiper-pagination',
+ type: 'progressbar',
+ },
+ navigation: {
+ nextEl: '.swiper-button-next',
+ prevEl: '.swiper-button-prev',
+ },
+ });
+};
-function updateActiveSlide(slide) {
- const block = slide.closest('.carousel');
- const slideIndex = parseInt(slide.dataset.slideIndex, 10);
- block.dataset.activeSlide = slideIndex;
-
- const slides = block.querySelectorAll('.carousel-slide');
-
- slides.forEach((aSlide, idx) => {
- aSlide.setAttribute('aria-hidden', idx !== slideIndex);
- aSlide.querySelectorAll('a').forEach((link) => {
- if (idx !== slideIndex) {
- link.setAttribute('tabindex', '-1');
- } else {
- link.removeAttribute('tabindex');
- }
- });
- });
-
- const indicators = block.querySelectorAll('.carousel-slide-indicator');
- indicators.forEach((indicator, idx) => {
- if (idx !== slideIndex) {
- indicator.querySelector('button').removeAttribute('disabled');
- } else {
- indicator.querySelector('button').setAttribute('disabled', 'true');
- }
- });
-}
-
-function showSlide(block, slideIndex = 0) {
- const slides = block.querySelectorAll('.carousel-slide');
- let realSlideIndex = slideIndex < 0 ? slides.length - 1 : slideIndex;
- if (slideIndex >= slides.length) realSlideIndex = 0;
- const activeSlide = slides[realSlideIndex];
-
- activeSlide.querySelectorAll('a').forEach((link) => link.removeAttribute('tabindex'));
- block.querySelector('.carousel-slides').scrollTo({
- top: 0,
- left: activeSlide.offsetLeft,
- behavior: 'smooth',
- });
-}
-
-function bindEvents(block) {
- const slideIndicators = block.querySelector('.carousel-slide-indicators');
- if (!slideIndicators) return;
-
- slideIndicators.querySelectorAll('button').forEach((button) => {
- button.addEventListener('click', (e) => {
- const slideIndicator = e.currentTarget.parentElement;
- showSlide(block, parseInt(slideIndicator.dataset.targetSlide, 10));
- });
- });
-
- block.querySelector('.slide-prev').addEventListener('click', () => {
- showSlide(block, parseInt(block.dataset.activeSlide, 10) - 1);
- });
- block.querySelector('.slide-next').addEventListener('click', () => {
- showSlide(block, parseInt(block.dataset.activeSlide, 10) + 1);
- });
-
- const slideObserver = new IntersectionObserver((entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting) updateActiveSlide(entry.target);
- });
- }, { threshold: 0.5 });
- block.querySelectorAll('.carousel-slide').forEach((slide) => {
- slideObserver.observe(slide);
- });
-}
-
-function createSlide(row, slideIndex, carouselId) {
- const slide = document.createElement('li');
- slide.dataset.slideIndex = slideIndex;
- slide.setAttribute('id', `carousel-${carouselId}-slide-${slideIndex}`);
- slide.classList.add('carousel-slide');
-
- row.querySelectorAll(':scope > div').forEach((column, colIdx) => {
- column.classList.add(`carousel-slide-${colIdx === 0 ? 'image' : 'content'}`);
- slide.append(column);
- });
-
- const labeledBy = slide.querySelector('h1, h2, h3, h4, h5, h6');
- if (labeledBy) {
- slide.setAttribute('aria-labelledby', labeledBy.getAttribute('id'));
- }
-
- return slide;
-}
-
-let carouselId = 0;
export default async function decorate(block) {
- carouselId += 1;
- block.setAttribute('id', `carousel-${carouselId}`);
- const rows = block.querySelectorAll(':scope > div');
- const isSingleSlide = rows.length < 2;
-
- const placeholders = await fetchPlaceholders();
-
- block.setAttribute('role', 'region');
- block.setAttribute('aria-roledescription', placeholders.carousel || 'Carousel');
-
- const container = document.createElement('div');
- container.classList.add('carousel-slides-container');
+ block.classList.add('swiper-carousel');
- const slidesWrapper = document.createElement('ul');
- slidesWrapper.classList.add('carousel-slides');
- block.prepend(slidesWrapper);
+ const wrapperEl = document.createElement('div');
+ wrapperEl.classList.add('swiper-wrapper');
+ wrapperEl.append(...block.querySelectorAll(':scope > div'));
+ block.append(wrapperEl);
- let slideIndicators;
- if (!isSingleSlide) {
- const slideIndicatorsNav = document.createElement('nav');
- slideIndicatorsNav.setAttribute('aria-label', placeholders.carouselSlideControls || 'Carousel Slide Controls');
- slideIndicators = document.createElement('ol');
- slideIndicators.classList.add('carousel-slide-indicators');
- slideIndicatorsNav.append(slideIndicators);
- block.append(slideIndicatorsNav);
+ const slides = [...wrapperEl.querySelectorAll(':scope > div')];
- const slideNavButtons = document.createElement('div');
- slideNavButtons.classList.add('carousel-navigation-buttons');
- slideNavButtons.innerHTML = `
-
-
- `;
-
- container.append(slideNavButtons);
- }
-
- rows.forEach((row, idx) => {
- const slide = createSlide(row, idx, carouselId);
- slidesWrapper.append(slide);
-
- if (slideIndicators) {
- const indicator = document.createElement('li');
- indicator.classList.add('carousel-slide-indicator');
- indicator.dataset.targetSlide = idx;
- indicator.innerHTML = ``;
- slideIndicators.append(indicator);
- }
- row.remove();
+ slides.forEach((slide) => {
+ slide.classList.add('swiper-slide');
});
- container.append(slidesWrapper);
- block.prepend(container);
+ const nextButton = document.createElement('button');
+ nextButton.classList.add('swiper-button-next');
+ const prevButton = document.createElement('button');
+ prevButton.classList.add('swiper-button-prev');
+ const pagination = document.createElement('div');
+ pagination.classList.add('swiper-pagination');
+
+ block.parentElement.prepend(prevButton);
+ block.parentElement.append(nextButton);
+ block.append(pagination);
- if (!isSingleSlide) {
- bindEvents(block);
- }
+ loadScript('https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js').then(() => buildSlider(block));
+ loadCSS('https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css');
}
diff --git a/blocks/header/header.css b/blocks/header/header.css
index 4fd1c6e..438a96f 100644
--- a/blocks/header/header.css
+++ b/blocks/header/header.css
@@ -4,6 +4,7 @@ header .nav-wrapper {
width: 100%;
z-index: 2;
position: fixed;
+ box-shadow: rgb(0 0 0 / 20%) 0 3px 12px 0;
}
header .nav-wrapper::before {