diff --git a/blocks/v2-accordion-column/v2-accordion-column.css b/blocks/v2-accordion-column/v2-accordion-column.css new file mode 100644 index 000000000..578eaabfa --- /dev/null +++ b/blocks/v2-accordion-column/v2-accordion-column.css @@ -0,0 +1,205 @@ +.section > .v2-accordion-column-wrapper.full-width { + padding: 0 16px; +} + +.v2-accordion-column__items-container { + margin: 40px 0 0; +} + +.v2-accordion-column__header-container h2 { + font-family: var(--ff-headline-medium); +} + +.v2-accordion-column__item-header-button { + background: transparent; + border: 0; + color: var(--c-primary-black); + display: flex; + justify-content: space-between; + margin: 0; + padding: 0 0 8px; + width: 100%; +} + +.v2-accordion-column__item-header-button:hover, +.v2-accordion-column__item-header-button:focus { + background: transparent; + cursor: pointer; +} + +.v2-accordion-column__item:not(.active) .v2-accordion-column__item-header-button { + padding: 0 0 12px; +} + +.v2-accordion-column__item-title { + font-family: var(--ff-subheadings-medium); + font-size: var(--headline-4-font-size); + letter-spacing: var(--headline-1-letter-spacing); + line-height: var(--headline-1-line-height); + margin: 0; +} + +.v2-accordion-column__close { + transform: rotate(0); + transition: transform var(--duration-small) var(--easing-standard); +} + +.v2-accordion-column__item .icon svg { + height: 24px; + width: 24px; +} + +.v2-accordion-column__item .icon svg, +.v2-accordion-column__item a .icon svg { + display: flex; +} + +.v2-accordion-column__item a .icon svg { + height: 16px; + width: 16px; + stroke: currentcolor; +} + +.v2-accordion-column__item.active .v2-accordion-column__close { + transform: rotate(180deg); + transition: transform var(--duration-small) var(--easing-standard); +} + +.v2-accordion-column__item :is( + .v2-accordion-column__item-image, + .v2-accordion-column__item-description){ + display: none; +} + +.v2-accordion-column__item { + margin: 0 0 16px; + border-bottom: 1px solid var(--c-secondary-steel); +} + +.v2-accordion-column__item.active { + margin: 40px 0; + display: flex; + flex-direction: column; +} + +.v2-accordion-column__item.active :is( + .v2-accordion-column__item-image, + .v2-accordion-column__item-description) { + display: initial; +} + +.v2-accordion-column__item-description .button-container .button { + align-items: stretch; + justify-content: flex-start; + gap: 4px; + margin: 0; + padding: 0; + border: 0; + background-color: transparent; + translate: none; +} + +.v2-accordion-column__item-description { + padding: 0 0 24px; +} + +.v2-accordion-column__item-description > p { + margin: 0; + padding: 16px 0 0; +} + +.v2-accordion-column__item-description .button-container:hover .button svg, +.v2-accordion-column__item-description .button-container:focus-within .button svg{ + translate: 3px; + transition: translate ease-out 0.2s; +} + +.v2-accordion-column__item-image { + background-color: var(--c-primary-gray); +} + +.v2-accordion-column__item-image img { + aspect-ratio: 16/10; + width: 100%; + height: auto; + display: block; +} + +/* Left variant */ +.v2-accordion-column--left .v2-accordion-column__item-image { + order: 1; +} + +.v2-accordion-column--left .v2-accordion-column__item-description { + order: 2; +} + +@media (min-width: 1024px) { + .section.v2-accordion-column-container { + height: 780px; + } + + .section > .v2-accordion-column-wrapper.full-width { + max-width: 1440px; + margin: 0 auto; + position: relative; + } + + .v2-accordion-column__header-container { + max-width: var(--wrapper-width); + margin: 0 auto 4em; + } + + .v2-accordion-column__header-container h2 { + font-size: var(--headline-1-font-size); + } + + .v2-accordion-column__accordion-container { + display: flex; + justify-content: end; + max-width: var(--wrapper-width); + margin: 0 auto; + } + + .v2-accordion-column__items-container { + display: flex; + flex-direction: column; + align-items: flex-start; + margin: 0; + } + + .v2-accordion-column__item { + max-width: 343px; + width: 100%; + } + + .v2-accordion-column__item, + .v2-accordion-column__item.active { + margin: 0 0 20px; + } + + .v2-accordion-column__item-image { + position: absolute; + left: 0; + top: 6em; + width: calc(50% + 80px); + background-color: var(--c-primary-gray); + } + + .v2-accordion-column__item-description > p:not(.button-container) { + padding: 0; + } + + /* Left variant */ + .v2-accordion-column--left .v2-accordion-column__accordion-container { + justify-content: start; + } + + .v2-accordion-column--left .v2-accordion-column__items-container { + width: 40%; + } + + .v2-accordion-column--left .v2-accordion-column__item-image { + left: calc(50% - 80px); + } +} diff --git a/blocks/v2-accordion-column/v2-accordion-column.js b/blocks/v2-accordion-column/v2-accordion-column.js new file mode 100644 index 000000000..bb4259115 --- /dev/null +++ b/blocks/v2-accordion-column/v2-accordion-column.js @@ -0,0 +1,68 @@ +import { createElement, variantsClassesToBEM } from '../../scripts/common.js'; + +const CLASSES = { + blockName: 'v2-accordion-column', + left: 'left', +}; + +const { blockName, left } = CLASSES; +const variants = Object.values(CLASSES).splice(1); + +const addAccordionClass = (item) => { + const hasPicture = item.querySelector('picture'); + if (hasPicture) item.classList.add(`${blockName}__item-image`); + else { + const header = item.querySelector(':is(h1, h2, h3, h4, h5, h6)'); + if (header) header.classList.add(`${blockName}__item-title`); + item.classList.add(`${blockName}__item-description`); + } +}; + +export default function decorate(block) { + const header = block.querySelector(':scope > div:first-child > div > :first-child'); + const accordionItems = [...block.querySelectorAll(':scope > div:not(:first-child)')]; + const accordionContainer = createElement('div', { classes: `${blockName}__accordion-container` }); + const itemsContainer = createElement('div', { classes: `${blockName}__items-container` }); + const hasLeftClass = block.classList.contains(left); // accordion at left side + /** @type {boolean} */ + const isLeftVariant = hasLeftClass + || (!hasLeftClass && !!accordionItems[0].lastElementChild.querySelector('picture')); + if (!hasLeftClass && isLeftVariant) block.classList.add(left); + variantsClassesToBEM(block.classList, variants, blockName); + block.parentElement.classList.add('full-width'); + header.parentElement.classList.add(`${blockName}__header-wrapper`); + header.parentElement.parentElement.classList.add(`${blockName}__header-container`); + + // style the header as an h2 with red marker over it + header.classList.add(`${blockName}__header`, 'with-marker'); + + // is responsibility of the author to add the proper amount of images and text + accordionItems.forEach((item, i) => { + const colBtnTitle = createElement('button', { + classes: `${blockName}__item-header-button`, + props: { type: 'button' }, + }); + const arrowEl = createElement('div', { classes: [`${blockName}__close`, 'icon'] }); + const dropdownArrowIcon = document.createRange().createContextualFragment(` + `); + const colItems = [...item.querySelectorAll(':scope > div')]; + + // add the proper classes to each accordion item + item.classList.add(`${blockName}__item`); + if (i === 0) item.classList.add('active'); + colItems.forEach((col) => addAccordionClass(col)); + arrowEl.appendChild(...dropdownArrowIcon.children); + colBtnTitle.prepend(item.querySelector(`.${blockName}__item-title`), arrowEl); + colBtnTitle.onclick = () => { + const active = accordionContainer.querySelector('.active'); + if (active && active !== item) active.classList.remove('active'); + item.classList.add('active'); + }; + item.prepend(colBtnTitle); + itemsContainer.appendChild(item); + }); + + accordionContainer.append(itemsContainer); + + block.appendChild(accordionContainer); +}