Skip to content

Commit

Permalink
starter hero slides
Browse files Browse the repository at this point in the history
  • Loading branch information
rrusher committed Dec 11, 2023
1 parent 595015d commit 459352d
Show file tree
Hide file tree
Showing 2 changed files with 258 additions and 0 deletions.
133 changes: 133 additions & 0 deletions blocks/hero-slides/hero-slides.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
.section.hero-slides-container {
padding: 0;
}

.section > .hero-slides-wrapper {
max-width: unset;
margin: unset;
}

.hero-slides {
width: 100%;
position: relative;
aspect-ratio: 600/686;
}

@media (min-width: 600px) {
.hero-slides {
height: 580px;
}
}

.hero-slides .slide {
display: flex;
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
flex-direction: column;
background-color: #394c5a;
opacity: 0;
transition: opacity 0.9s ease;
}

.hero-slides .slide.active {
opacity: 1;
z-index: 2;
}

@media (min-width: 600px) {
.hero-slides .slide {
flex-direction: row;
}
}

.hero-slides .slide .image {
flex: 0 0 66%;
height: 100%;
}

.hero-slides .slide .image img {
object-fit: cover;
object-position: top;
width: 100%;
height: 100%;
}


.hero-slides .slide .text {
color: var(--text-color-on-black-background);
align-self: center;
padding: 10px;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;

/* font size is relative to screen width, but limited in min and max size.
the actual texts then use `em` to scale with this font size.
*/
font-size: clamp(11px, 1.5vw, 16px);
}

@media (min-width: 600px) {
.hero-slides .slide .text {
height: 100%;
padding: 0 40px;
}
}

.hero-slides .slide .text .price {
text-transform: uppercase;
color: var(--text-color-secondary-on-black-background);
}

.hero-slides .slide .text .city {
margin: 0;
font-size: 1.5em;
line-height: 1.2;
font-weight: bold;
}

@media screen and (min-width: 600px) {
.hero-slides .slide .text .city {
font-size: 2.5em;
line-height: 1;
}
}

.hero-slides .slide .text .link {
text-transform: uppercase;
color: var(--text-color-secondary-on-black-background);
}


@media (min-width: 600px) {
.hero-slides .slideshow-buttons {
position: absolute;
bottom: 4rem;
right: 7%;
height: 20px;
display: flex;
justify-content: center;
gap: 0.7vw;
z-index: 3;
}

.hero-slides .slideshow-buttons button {
height: 1.1vw;
aspect-ratio: 1/1;
padding: 0;
margin: 0;
border-radius: 50%;
border: none;
background-color: #bbb;
transition: background-color 0.3s ease;
}

.hero-slides .slideshow-buttons button.active {
background-color: white;
}
}

125 changes: 125 additions & 0 deletions blocks/hero-slides/hero-slides.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { createOptimizedPicture, readBlockConfig } from '../../scripts/lib-franklin.js';

Check failure on line 1 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

Unable to resolve path to module '../../scripts/lib-franklin.js'

/**
* Slideshow with luxury listings. Supports swiping on touch screens.
* Also supports manually adding content into the block.
* @param block
*/
export default async function decorate(block) {
const config = readBlockConfig(block);
const listings = await fetchListings(config);

Check failure on line 10 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

Multiple spaces found before 'listings'

Check failure on line 10 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

'fetchListings' was used before it was defined
block.textContent = '';
const { goToSlide } = setupSlideControls(block);

Check failure on line 12 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

'setupSlideControls' was used before it was defined

const slideshowButtons = document.createElement('div');
slideshowButtons.classList.add('slideshow-buttons');

listings.forEach((listing, index) => {
const slide = document.createElement('a');
slide.classList.add('slide');
slide.href = listing.path;

const imageSizes = [
// desktop
{ media: '(min-width: 600px)', height: '600' },
// tablet and mobile sizes:
{ media: '(min-width: 400px)', height: '600' },
{ width: '400' },
];
const picture = listing.picture || createOptimizedPicture(
listing.image,
listing.city,
index === 0,
imageSizes,
);
slide.innerHTML = `
<div class="image">${picture.outerHTML}</div>
<div class="text">
<p class="city">${plainText(listing.city)}</p>

Check failure on line 38 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

'plainText' was used before it was defined
<p class="price">${plainText(listing.price)}</p>

Check failure on line 39 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

'plainText' was used before it was defined
<a class="link" href='${listing.path}'>LEARN MORE</a>
</div> `;
block.append(slide);

const button = document.createElement('button');
button.ariaLabel = `go to listing in ${listing.city}`;
button.addEventListener('click', () => goToSlide(index));
slideshowButtons.append(button);

if (index === 0) {
slide.classList.add('active');
button.classList.add('active');
}
});

block.append(slideshowButtons);
}

async function fetchListings(config) {

Check failure on line 58 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

'config' is defined but never used
const resp = await fetch(`${window.hlx.codeBasePath}/listings.json}`);
// eslint-disable-next-line no-return-await
return (await resp.json()).data;
}

function setupSlideControls(block) {
function goToSlide(index) {
block.querySelector('.slide.active').classList.remove('active');
[...block.querySelectorAll('.slide')].at(index).classList.add('active');

block.querySelector('.slideshow-buttons .active')?.classList.remove('active');
[...block.querySelectorAll('.slideshow-buttons button')].at(index).classList.add('active');

// automatically advance slides. Reset timer when user interacts with the slideshow
autoplaySlides();

Check failure on line 73 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

'autoplaySlides' was used before it was defined
}

let autoSlideInterval = null;
function autoplaySlides() {
clearInterval(autoSlideInterval);
autoSlideInterval = setInterval(() => advanceSlides(+1), 3000);

Check failure on line 79 in blocks/hero-slides/hero-slides.js

View workflow job for this annotation

GitHub Actions / build

'advanceSlides' was used before it was defined
}

function advanceSlides(diff) {
const allSlides = [...block.querySelectorAll('.slide')];
const activeSlide = block.querySelector('.slide.active');
const currentIndex = allSlides.indexOf(activeSlide);

const newSlideIndex = (allSlides.length + currentIndex + diff) % allSlides.length;
goToSlide(newSlideIndex);
}

/** detect swipe gestures on touch screens to advance slides */
function gestureStart(event) {
const touchStartX = event.changedTouches[0].screenX;

function gestureEnd(endEvent) {
const touchEndX = endEvent.changedTouches[0].screenX;
const delta = touchEndX - touchStartX;
if (delta < -5) {
advanceSlides(+1);
} else if (delta > 5) {
advanceSlides(-1);
} else {
// finger not moved enough, do nothing
}
}

block.addEventListener('touchend', gestureEnd, { once: true });
}

block.addEventListener('touchstart', gestureStart, { passive: true });

autoplaySlides();
return { goToSlide };
}

/**
* make text safe to use in innerHTML
* @param text any string
* @return {string} sanitized html string
*/
function plainText(text) {
const fragment = document.createElement('div');
fragment.append(text);
return fragment.innerHTML;
}

0 comments on commit 459352d

Please sign in to comment.