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;