From 93d47f7d5f3f7f5087992565ea686e32cbb83120 Mon Sep 17 00:00:00 2001 From: nimithshetty17 <111452145+nimithshetty17@users.noreply.github.com> Date: Wed, 6 Sep 2023 20:21:51 +0530 Subject: [PATCH] feature(case-study-carousel): Case study carousel block. (#323) * feature(case-study-carousel): Case study carousel block. * feature(case-study-carousel): Case study carousel block bug fixes. * feature(case-study-carousel): Case study carousel arrow bug fixes. * feature(case-study-carousel): Case study carousel block arrow fixes. * feature(case-study-carousel): Testimonial carousel block bug fixes. --------- Co-authored-by: Putra Bonaccorsi --- blocks/carousel/carousel.css | 273 ++++++++++++++++++++++----- blocks/carousel/carousel.js | 129 +++++++------ icons/carousel-arrow-left-hover.svg | 11 ++ icons/carousel-arrow-left.svg | 5 + icons/carousel-arrow-right-hover.svg | 11 ++ icons/carousel-arrow-right.svg | 5 + styles/styles.css | 1 + 7 files changed, 337 insertions(+), 98 deletions(-) create mode 100644 icons/carousel-arrow-left-hover.svg create mode 100644 icons/carousel-arrow-left.svg create mode 100644 icons/carousel-arrow-right-hover.svg create mode 100644 icons/carousel-arrow-right.svg diff --git a/blocks/carousel/carousel.css b/blocks/carousel/carousel.css index 97356d76..7ed79d40 100644 --- a/blocks/carousel/carousel.css +++ b/blocks/carousel/carousel.css @@ -46,6 +46,13 @@ main .section div.carousel-wrapper { transition: height 0.2s linear } +.carousel.case-study .carousel-slide-container { + background-color: var(--neutral-carbon); + border-radius: var(--spacer-element-09); + color: var(--neutral-white); + min-height: 528px; +} + .carousel .carousel-slide { width: 100%; height: 100%; @@ -170,18 +177,34 @@ main .section div.carousel-wrapper { padding-inline-start: 0; } +.carousel.case-study ul.carousel-dots { + gap: var(--spacer-element-04); +} + .carousel .carousel-dots li { - width: 12px; - height: 12px; + width: var(--spacer-element-04); + height: var(--spacer-element-04); box-shadow: inset 0 0 100px 100px var(--neutral-sand); cursor: pointer; border-radius: 50%; } +.carousel.case-study .carousel-dots li { + width: var(--spacer-layout-05); + height: var(--spacer-element-02); + border-radius: unset; +} + .carousel .carousel-dots li.carousel-dots-active { box-shadow: inset 0 0 100px 100px var(--primary-purple); } +.carousel.case-study .carousel-dots li.carousel-dots-active { + box-shadow: inherit; + background-image: var(--gradient-left-right); + background-position: 0 100%; +} + .carousel .carousel-dots button { display: none; } @@ -192,52 +215,140 @@ main .section div.carousel-wrapper { margin: var(--spacer-layout-05) 0 0; } -/* Media queries */ -@media screen and (min-width: 1200px) { -.carousel-container { - background: var(--neutral-bone); - padding: var(--spacer-layout-06) 0 var(--spacer-layout-06); +.carousel.case-study .carousel-slide-container .carousel-slide { + text-align: left; } - -main .section div.carousel-wrapper { - padding-top: var(--spacer-layout-07); - padding-bottom: var(--spacer-layout-04); + +.carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper { + padding: var(--sticky-nav-height) var(--spacer-element-08) var(--spacer-element-10) var(--spacer-element-08); } - -.section.carousel-container .default-content-wrapper { - padding-top: 0; - padding-bottom: var(--spacer-layout-07); + +.carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__title-wrapper > p:first-child { + text-transform: uppercase; + font-family: var(--sans-serif-font-medium); + font-size: var(--font-size-11); + font-weight: var(--font-weight-medium); + line-height: var(--line-height-120); + letter-spacing: 0.1375rem; + margin: 0; } - -.carousel .carousel-slide-container { - width: 100%; - max-width: 740px; - position: relative; - overflow: hidden; - margin: 0 auto; - transition: height 0.2s linear + +.carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper > h2 { + font-size: var(--font-size-32); + font-family: var(--serif-font); + font-weight: var(--font-weight-light); + line-height: var(--line-height-120); + letter-spacing: 0.035rem; + margin: var(--spacer-element-07) 0 0 0; } - -.carousel ul.carousel-dots { - margin-top: var(--spacer-layout-02); + +.carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper > p:nth-child(2) { + font-size: var(--font-size-16); + font-family: var(--sans-serif-font-light); + font-weight: var(--font-weight-light); + line-height: var(--line-height-160); + letter-spacing: 0.01rem; + margin: var(--spacer-element-08) 0 0 0; +} + +.carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper .button-container { + margin: var(--spacer-element-08) 0 0 0; +} + +.carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper .button-container a { + color: var(--neutral-white); + border: 2px solid var(--neutral-white); + background-image: none; + white-space: nowrap; } -.carousel .carousel-slide { - width: 100%; - height: 100%; +.carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper .button-container a:hover { + background-image: var(--gradient-to-right); + transition: all .4s ease-in-out; +} + +.carousel.case-study .carousel-slide-container .carousel-slide > div.only-picture > picture { + display: flex; position: absolute; - transition: all 0.5s; + bottom: 0; } -.carousel .carousel-slide div { - display: flex; - flex-direction: column; - font-family: var(--serif-font); - font-weight: var(--font-weight-light); - line-height: 124%; - font-size: 31px; +/* Media queries */ + +/* Tablet */ +@media screen and (min-width: 768px) { + .carousel.case-study ul.carousel-dots { + margin-top: var(--spacer-layout-04); + gap: var(--gap-10); + } + + .carousel.case-study .carousel-slide-container { + min-height: 588px; + } + + .carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper { + padding: var(--spacer-layout-06) var(--spacer-layout-05) var(--spacer-layout-04) var(--spacer-layout-05); + } + } +/* Desktop */ +@media screen and (min-width: 1200px) { + .carousel-container { + background: var(--neutral-bone); + padding: var(--spacer-layout-06) 0 var(--spacer-layout-06); + } + + main .section div.carousel-wrapper { + padding-top: var(--spacer-layout-07); + padding-bottom: var(--spacer-layout-04); + } + + .section.carousel-container .default-content-wrapper { + padding-top: 0; + padding-bottom: var(--spacer-layout-07); + } + + .carousel .carousel-slide-container { + width: 100%; + position: relative; + overflow: hidden; + margin: 0 auto; + transition: height 0.2s linear + } + + .carousel.case-study .carousel-slide-container { + min-height: 774px; + min-width: var(--secton-max-container); + } + + .carousel ul.carousel-dots { + margin-top: var(--spacer-layout-02); + } + + .carousel.case-study ul.carousel-dots { + margin-top: var(--spacer-layout-05); + } + + .carousel.case-study .carousel-dots li { + width: var(--spacer-layout-07); + } + + .carousel .carousel-slide { + width: 100%; + height: 100%; + position: absolute; + transition: all 0.5s; + } + + .carousel .carousel-slide div { + display: flex; + flex-direction: column; + font-family: var(--serif-font); + font-weight: var(--font-weight-light); + line-height: 124%; + font-size: var(--font-size-32); + } /* Testimonial */ .carousel .carousel-slide .figure { @@ -255,12 +366,12 @@ main .section div.carousel-wrapper { padding-top: var(--spacer-layout-02); } -.carousel.testimonial p { - margin-left: 1em; - font-size: var(--font-size-16); - font-family: var(--sans-serif-font-regular); - letter-spacing: var(--letter-spacing-1); -} + .carousel.testimonial p { + margin-left: var(--spacer-element-05); + font-size: var(--font-size-16); + font-family: var(--sans-serif-font-regular); + letter-spacing: var(--letter-spacing-1); + } .carousel:hover .carousel-nav { opacity: 1; @@ -270,4 +381,80 @@ main .section div.carousel-wrapper { text-align: left; margin: 0; } + + .carousel.case-study .carousel-nav { + opacity: 1; + top: 36%; + background: unset; + } + + .carousel.case-study .carousel-nav.carousel-nav-prev { + transform: unset; + background: url('./../../icons/carousel-arrow-left.svg') no-repeat; + background-size: contain; + width: 100px; + height: 100px; + left: -50px; + } + + .carousel.case-study .carousel-nav.carousel-nav-prev:hover { + transform: unset; + background: url('./../../icons/carousel-arrow-left-hover.svg') no-repeat; + background-size: contain; + width: 100px; + height: 100px; + left: -50px; + } + + .carousel.case-study .carousel-nav.carousel-nav-next { + transform: unset; + background: url('./../../icons/carousel-arrow-right.svg') no-repeat; + background-size: contain; + width: 101px; + height: 101px; + right: -50px; + } + + .carousel.case-study .carousel-nav.carousel-nav-next:hover { + transform: unset; + background: url('./../../icons/carousel-arrow-right-hover.svg') no-repeat; + background-size: contain; + width: 101px; + height: 101px; + right: -50px; + } + + .carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper { + padding: var(--spacer-layout-06) var(--spacer-layout-06) 0 var(--spacer-layout-06); + } + + .carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__title-wrapper > p:first-child { + font-size: var(--font-size-14); + letter-spacing: 0.175rem; + } + + .carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper { + display: flex; + flex-direction: row; + margin-top: var(--spacer-element-07); + gap: var(--gap-24); + } + + .carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper .button-container { + margin: 0; + } + + .carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper > h2 { + font-size: var(--font-size-45); + max-width: 268px; + letter-spacing: 0.0493rem; + margin: 0; + } + + .carousel.case-study .carousel-slide-container .carousel-slide .case-study__container-wrapper .case-study__content-wrapper > p:nth-child(2) { + font-size: var(--font-size-21); + max-width: 446px; + letter-spacing: 0.013rem; + margin: 0; + } } \ No newline at end of file diff --git a/blocks/carousel/carousel.js b/blocks/carousel/carousel.js index 3e4cffa7..d5d66d37 100644 --- a/blocks/carousel/carousel.js +++ b/blocks/carousel/carousel.js @@ -32,6 +32,7 @@ */ const SLIDE_CAPTION_SIZE = 64; +const SLIDE_CAPTION_SIZE_WITH_ICON = 89; const SLIDE_ID_PREFIX = 'carousel-slide'; const SLIDE_CONTROL_ID_PREFIX = 'carousel-slide-control'; @@ -42,22 +43,22 @@ let maxSlide = 0; let carouselType = 'default'; /** - * Clear any active scroll intervals - */ + * Clear any active scroll intervals + */ function stopAutoScroll() { clearInterval(scrollInterval); scrollInterval = undefined; } /** - * Count how many lines a block of text will consume when wrapped within a container - * that has a maximum width. - * @param text The full text - * @param width Width of container - * @param options Options to be applied to context (e.g. font style) - * - * @return {number} The number of lines - */ + * Count how many lines a block of text will consume when wrapped within a container + * that has a maximum width. + * @param text The full text + * @param width Width of container + * @param options Options to be applied to context (e.g. font style) + * + * @return {number} The number of lines + */ function getLineCount(text, width, options = {}) { // re-use canvas object for better performance const canvas = getLineCount.canvas || (getLineCount.canvas = document.createElement('canvas')); @@ -82,13 +83,13 @@ function getLineCount(text, width, options = {}) { } /** - * Calculate the actual height of a slide based on its contents. - * - * @param carousel The carousel - * @param slide A slide within the carousel - */ + * Calculate the actual height of a slide based on its contents. + * + * @param carousel The carousel + * @param slide A slide within the carousel + */ function calculateSlideHeight(carousel, slide) { - if (carouselType === 'default' || carouselType === 'testimonial') { + if (carouselType === 'default' || carouselType === 'testimonial' || carouselType === 'case-study') { requestAnimationFrame(() => { const slideBody = slide.querySelector('div'); const slideH3 = slide.querySelector('H3'); @@ -103,17 +104,17 @@ function calculateSlideHeight(carousel, slide) { ); const bodyHeight = parseFloat(bodyStyle.lineHeight) * lineCount; const figureStyle = window.getComputedStyle(slide.querySelector('.figure')); - const figureHeight = figureStyle ? parseFloat(figureStyle.height) : SLIDE_CAPTION_SIZE; + const figureHeight = (figureStyle && figureStyle.height !== 'auto') ? parseFloat(figureStyle.height) : SLIDE_CAPTION_SIZE_WITH_ICON; carousel.style.height = `${bodyHeight + figureHeight}px`; }); } } /** - * Keep active dot in sync with current slide - * @param carousel The carousel - * @param activeSlide {number} The active slide - */ + * Keep active dot in sync with current slide + * @param carousel The carousel + * @param activeSlide {number} The active slide + */ function syncActiveDot(carousel, activeSlide) { carousel.querySelectorAll('ul.carousel-dots li').forEach((item, index) => { const btn = item.querySelector('button'); @@ -130,11 +131,11 @@ function syncActiveDot(carousel, activeSlide) { } /** - * Scroll a single slide into view. - * - * @param carousel The carousel - * @param slideIndex {number} The slide index - */ + * Scroll a single slide into view. + * + * @param carousel The carousel + * @param slideIndex {number} The slide index + */ function scrollToSlide(carousel, slideIndex = 0) { const carouselSlider = carousel.querySelector('.carousel-slide-container'); calculateSlideHeight(carouselSlider, carouselSlider.children[slideIndex]); @@ -154,13 +155,13 @@ function scrollToSlide(carousel, slideIndex = 0) { } /** - * Based on the direction of a scroll snap the scroll position based on the - * offset width of the scrollable element. The snap threshold is determined - * by the direction of the scroll to ensure that snap direction is natural. - * - * @param el the scrollable element - * @param dir the direction of the scroll - */ + * Based on the direction of a scroll snap the scroll position based on the + * offset width of the scrollable element. The snap threshold is determined + * by the direction of the scroll to ensure that snap direction is natural. + * + * @param el the scrollable element + * @param dir the direction of the scroll + */ function snapScroll(el, dir = 1) { if (!el) { return; @@ -179,11 +180,11 @@ function snapScroll(el, dir = 1) { } /** - * Build a navigation button for controlling the direction of carousel slides. - * - * @param dir A string of either 'prev or 'next' - * @return {HTMLDivElement} The resulting nav element - */ + * Build a navigation button for controlling the direction of carousel slides. + * + * @param dir A string of either 'prev or 'next' + * @return {HTMLDivElement} The resulting nav element + */ function buildNav(dir) { const btn = document.createElement('div'); btn.classList.add('carousel-nav', `carousel-nav-${dir}`); @@ -202,10 +203,10 @@ function buildNav(dir) { } /** - * - * @param slides An array of slide elements within the carousel - * @return {HTMLUListElement} The carousel dots element - */ + * + * @param slides An array of slide elements within the carousel + * @return {HTMLUListElement} The carousel dots element + */ function buildDots(slides = []) { const dots = document.createElement('ul'); dots.classList.add('carousel-dots'); @@ -243,12 +244,12 @@ function buildDots(slides = []) { } /** - * Decorate a base slide element. - * - * @param slide A base block slide element - * @param index The slide's position - * @return {HTMLUListElement} A decorated carousel slide element - */ + * Decorate a base slide element. + * + * @param slide A base block slide element + * @param index The slide's position + * @return {HTMLUListElement} A decorated carousel slide element + */ function buildSlide(slide, index) { slide.setAttribute('id', `${SLIDE_ID_PREFIX}${index}`); slide.setAttribute('data-slide-index', index); @@ -289,18 +290,21 @@ function startAutoScroll(block) { } /** - * Decorate and transform a carousel block. - * - * @param block HTML block from Franklin - */ + * Decorate and transform a carousel block. + * + * @param block HTML block from Franklin + */ export default function decorate(block) { const carousel = document.createElement('div'); carousel.classList.add('carousel-slide-container'); if (block.classList.contains('image-carousel-full-width')) { carouselType = 'image-carousel-full-width'; - } - if (block.classList.contains('testimonial')) { + } else if (block.classList.contains('testimonial')) { carouselType = 'testimonial'; + } else if (block.classList.contains('case-study')) { + carouselType = 'case-study'; + } else { + carouselType = 'default'; } // make carousel draggable @@ -349,6 +353,19 @@ export default function decorate(block) { const slides = [...block.children]; maxSlide = slides.length - 1; slides.forEach((slide, index) => { + if (carouselType === 'case-study') { + const titleTag = slide.querySelector('p'); + const contentDivElement = titleTag.parentElement; + const parentDivElement = contentDivElement.parentElement; + const titleDiv = document.createElement('div'); + const contentDiv = document.createElement('div'); + contentDiv.classList.add('case-study__container-wrapper'); + titleDiv.classList.add('case-study__title-wrapper'); + contentDivElement.classList.add('case-study__content-wrapper'); + titleDiv.append(titleTag); + contentDiv.append(titleDiv, contentDivElement); + parentDivElement.prepend(contentDiv); + } carousel.appendChild(buildSlide(slide, index)); }); @@ -356,7 +373,9 @@ export default function decorate(block) { block.append(carousel); // calculate height of first slide - calculateSlideHeight(carousel, slides[0]); + if (carouselType !== 'case-study') { + calculateSlideHeight(carousel, slides[0]); + } // add nav buttons and dots to block if (slides.length > 1) { diff --git a/icons/carousel-arrow-left-hover.svg b/icons/carousel-arrow-left-hover.svg new file mode 100644 index 00000000..e8a67c59 --- /dev/null +++ b/icons/carousel-arrow-left-hover.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/icons/carousel-arrow-left.svg b/icons/carousel-arrow-left.svg new file mode 100644 index 00000000..ce2e9de3 --- /dev/null +++ b/icons/carousel-arrow-left.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/icons/carousel-arrow-right-hover.svg b/icons/carousel-arrow-right-hover.svg new file mode 100644 index 00000000..765d6255 --- /dev/null +++ b/icons/carousel-arrow-right-hover.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/icons/carousel-arrow-right.svg b/icons/carousel-arrow-right.svg new file mode 100644 index 00000000..affecae2 --- /dev/null +++ b/icons/carousel-arrow-right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/styles/styles.css b/styles/styles.css index 52519c19..8f737277 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -204,6 +204,7 @@ --sticky-nav-height: 80px; /* gap spacers */ + --gap-10: 10px; --gap-16: 16px; --gap-24: 24px; --gap-48: 48px;