Skip to content

Commit

Permalink
Merge pull request #3 from Netcentric/VAT-hero-carousel
Browse files Browse the repository at this point in the history
VAT: adding logo block and carousel block
  • Loading branch information
dragandimic authored Jun 10, 2024
2 parents b1bd517 + b019296 commit 4959bf7
Show file tree
Hide file tree
Showing 6 changed files with 395 additions and 2 deletions.
227 changes: 227 additions & 0 deletions blocks/carousel/carousel.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
.section.carousel-container {
padding: 0;
}

.carousel .carousel-slides-container {
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 .carousel-slides::-webkit-scrollbar {
display: none;
}

.carousel .carousel-slide {
flex: 0 0 100%;
scroll-snap-align: start;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
width: 100%;
min-height: 1015px;
}

.carousel .carousel-slide:has(.carousel-slide-content[data-align="center"]) {
align-items: center;
}

.carousel .carousel-slide:has(.carousel-slide-content[data-align="right"]) {
align-items: flex-end;
}

.carousel .carousel-slide .carousel-slide-image picture {
position: absolute;
inset: 0;
}

.carousel .carousel-slide .carousel-slide-image picture > img {
height: 100%;
width: 100%;
object-fit: cover;
}

.carousel .carousel-slide .carousel-slide-content {
z-index: 1;
padding: 1rem;
margin: 1.5rem 3rem;
color: white;
background-color: none;
position: relative;
width: var(--slide-content-width, auto);
}

.carousel .carousel-slide .carousel-slide-content .button {
display: flex;
max-width: 260px;
align-items: center;
max-height: 60px;
position: relative;
border: 0;
height: 6rem;
width: 100%;
font-family: Calibre, Helvetica, Tahoma, Arial, sans-serif;
cursor: pointer;
appearance: none;
border-radius: .4rem;
transition: all .2s ease-in-out;
background: #80ba27;
color: #fff;
letter-spacing: -.02rem;
box-shadow: 0 .2rem .4rem 0 rgba(0 0 0 / 5%);
font-size: 18px;
font-weight: normal;
}

.carousel .carousel-slide-image::after {
width: 100vw;
height: 100vh;
display: block;
position: absolute;
top:0;
left: 0;
background-color: rgba(0 0 0 /30%);
content: " ";
}

.carousel .carousel-slide-indicators {
display: flex;
justify-content: center;
gap: 0.5rem;
}

.carousel .carousel-slide-indicator button {
width: 1rem;
height: 1rem;
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 .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 .carousel-navigation-buttons {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0.5rem;
right: 0.5rem;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 20px;
margin-right: 5rem;
z-index: 1;
}

/* 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: transparent;
}

.carousel .carousel-navigation-buttons button:hover,
.carousel .carousel-navigation-buttons button:focus-visible {
background-color: transparent;
}

.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 h3 {
color: #fff;
}

.carousel .carousel-slide .carousel-slide-content[data-align="justify"] {
--slide-content-width: auto;
}
}


.carousel-container .carousel-wrapper {
max-width: 100%;
height: calc(100vh - 64px);
min-height: calc(100vh - 64px);
}

@media (width >= 900px) {
.carousel-container .carousel-wrapper {
max-width: 100%;
min-height: 1015px;
}
}
150 changes: 150 additions & 0 deletions blocks/carousel/carousel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { fetchPlaceholders } from '../../scripts/aem.js';

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');

const slidesWrapper = document.createElement('ul');
slidesWrapper.classList.add('carousel-slides');
block.prepend(slidesWrapper);

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 slideNavButtons = document.createElement('div');
slideNavButtons.classList.add('carousel-navigation-buttons');
slideNavButtons.innerHTML = `
<button type="button" class= "slide-prev" aria-label="${placeholders.previousSlide || 'Previous Slide'}"></button>
<button type="button" class="slide-next" aria-label="${placeholders.nextSlide || 'Next Slide'}"></button>
`;

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 = `<button type="button"><span>${placeholders.showSlide || 'Show Slide'} ${idx + 1} ${placeholders.of || 'of'} ${rows.length}</span></button>`;
slideIndicators.append(indicator);
}
row.remove();
});

container.append(slidesWrapper);
block.prepend(container);

if (!isSingleSlide) {
bindEvents(block);
}
}
3 changes: 3 additions & 0 deletions blocks/logo/logo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.logo {
display: block;
}
Binary file modified favicon.ico
Binary file not shown.
13 changes: 13 additions & 0 deletions icons/arrow-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 4959bf7

Please sign in to comment.