From f89fec35403fd846cc52f5899bc4680cd81dea9f Mon Sep 17 00:00:00 2001 From: "conary.hernandez" <“conary.hernandez@herodigital.com”> Date: Wed, 16 Apr 2025 08:42:42 -0600 Subject: [PATCH 1/5] STERICMS-821: Add toast banner styles and functionality --- blocks/banner/banner.css | 72 +++++++++++++++++++++++++++++++++++++++- blocks/banner/banner.js | 33 ++++++++++++++---- 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/blocks/banner/banner.css b/blocks/banner/banner.css index a6b4a08c..9753dc5f 100644 --- a/blocks/banner/banner.css +++ b/blocks/banner/banner.css @@ -22,6 +22,31 @@ margin: 0; } +.block.banner.toast { + position: fixed; + left: 0; + z-index: 100; + width: 100%; + bottom: 42px; + padding: 36px 32px; + max-width: initial; +} + +.block.banner.toast::before { + content: ''; + position: absolute; + bottom: -42px; + left: -36px; + width: 100%; + height: 100%; + background-image: url('/icons/row-promo-banner-lines-mobile.svg'); + background-repeat: no-repeat; + background-position: bottom right; + z-index: 0; + transform: scale(-1, 1); +} + + .block.banner.fixed-to-bottom { position: fixed; left: 0; @@ -78,6 +103,21 @@ text-decoration: underline; } +.block.banner.toast > .banner-content > .banner-content-page * { + font-size: 18px; + font-style: normal; + font-weight: 700; + line-height: 140%; /* 25.2px */ + letter-spacing: 0.18px; + text-decoration: none; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + gap: 24px; + flex-direction: column; +} + .block.banner > .banner-content > .banner-content-page { display: none; } @@ -116,6 +156,13 @@ font-size: 12px; } +.block.banner.toast > .banner-actions > .close-button { + position: absolute; + top: 10px; + right: 10px; +} + + .block.banner > .banner-actions > .close-button::before { content: "X"; color: var(--color-white); @@ -125,7 +172,7 @@ .block.banner p:has(a) a:any-link, .block.banner p:has(strong+a) a:any-link, .block.banner p:has(strong > a) a:any-link { - color: var(--color-yellow); + color: var(--color-text-primary); } .block.banner p.button-container a:any-link { @@ -169,4 +216,27 @@ button.fa-chevron-right { overflow: unset; text-overflow: unset; border-radius: unset; +} + +@media (min-width: 1400px /* breakpoint-xl */) { + .block.banner.toast { + bottom: 0; + } + + .block.banner.toast::before { + left: 0; + bottom: 0; + background-size: contain; + } + + .block.banner.toast > .banner-actions > .close-button { + position: relative; + top: 0; + right: 0; + } + + .block.banner.toast > .banner-content > .banner-content-page * { + flex-direction: row; + gap: 48px; + } } \ No newline at end of file diff --git a/blocks/banner/banner.js b/blocks/banner/banner.js index c63040cf..2831c663 100644 --- a/blocks/banner/banner.js +++ b/blocks/banner/banner.js @@ -53,12 +53,32 @@ export default async function decorate(block) { block.append(child); child.classList.add('banner-content-page'); - const arrowRightEl = p( - { class: 'button-container' }, - span({ class: 'icon icon-right-arrow-bolder', 'data-icon-src': '/icons/right-arrow-bolder.svg', style: '--mask-image: url(/icons/right-arrow-bolder.svg);' }), - ); + if (block.classList.contains('toast')) { + const ctas = child.querySelectorAll('a'); - child.append(arrowRightEl); + ctas.forEach((cta) => { + const originalParent = cta.parentNode; + const topLevel = originalParent.parentNode; + + if (topLevel && (topLevel.tagName === 'P' || topLevel.tagName === 'DIV')) { + const actionButton = originalParent.querySelector('a'); + if (originalParent.tagName === 'STRONG') { + actionButton.classList.add('button', 'primary'); + } + + if (originalParent.tagName === 'EM') { + actionButton.classList.add('button', 'secondary'); + } + } + }); + } else { + const arrowRightEl = p( + { class: 'button-container' }, + span({ class: 'icon icon-right-arrow-bolder', 'data-icon-src': '/icons/right-arrow-bolder.svg', style: '--mask-image: url(/icons/right-arrow-bolder.svg);' }), + ); + + child.append(arrowRightEl); + } if (idx === 0) { child.classList.add('active'); @@ -77,7 +97,7 @@ export default async function decorate(block) { decorateCloseButton(block); - if (block.classList.contains('fixed-to-top')) { + if (block.classList.contains('fixed-to-top') || block.classList.contains('toast')) { block.classList.add('cmp-notification-bar'); // analytics trigger contentWrapper.classList.add('cmp-carousel__item__content'); // analytics trigger const body = block.closest('body'); @@ -96,6 +116,7 @@ export default async function decorate(block) { copyBlock.prepend(leftChevron); copyBlock.append(rightChevron); } + const closeButton = copyBlock.querySelector('button.close-button'); closeButton.classList.add('cmp-carousel__action--close'); // analytics trigger closeButton.addEventListener('click', () => copyBlock.remove()); From cda85ddd62e5dee28f04929c8817d4354bb4fb59 Mon Sep 17 00:00:00 2001 From: "conary.hernandez" <“conary.hernandez@herodigital.com”> Date: Wed, 16 Apr 2025 08:50:04 -0600 Subject: [PATCH 2/5] STERICMS-821: Implement toast banner cookie functionality to manage visibility --- blocks/banner/banner.js | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/blocks/banner/banner.js b/blocks/banner/banner.js index 2831c663..4ad59f58 100644 --- a/blocks/banner/banner.js +++ b/blocks/banner/banner.js @@ -2,6 +2,25 @@ import { decorateButtons } from '../../scripts/aem.js'; import { loadFragment } from '../fragment/fragment.js'; import { span, button, p } from '../../scripts/dom-helpers.js'; +const TOAST_BANNER = 'toast'; +const TOAST_BANNER_COOKIE = 'bannerDismissed'; + +function setCookie(name, value, days) { + const date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + const expires = `expires=${date.toUTCString()}`; + document.cookie = `${name}=${value}; ${expires}; path=/`; +} + +export function getCookie(name) { + const value = `; ${document.cookie}`; + const parts = value.split(`; ${name}=`); + if (parts.length === 2) { + return parts.pop().split(';').shift(); + } + return null; +} + function decorateCloseButton(block) { const buttonWrapper = document.createElement('div'); buttonWrapper.classList.add('banner-actions'); @@ -30,6 +49,11 @@ function navigateContent(block, direction) { } export default async function decorate(block) { + if (getCookie(TOAST_BANNER_COOKIE) && block.classList.contains(TOAST_BANNER)) { + block.closest('.section').remove(); + return; + } + // Set default background if no other is present if (!(/-background/.test(block.className))) { block.classList.add('blue-background'); @@ -53,7 +77,7 @@ export default async function decorate(block) { block.append(child); child.classList.add('banner-content-page'); - if (block.classList.contains('toast')) { + if (block.classList.contains(TOAST_BANNER)) { const ctas = child.querySelectorAll('a'); ctas.forEach((cta) => { @@ -97,7 +121,7 @@ export default async function decorate(block) { decorateCloseButton(block); - if (block.classList.contains('fixed-to-top') || block.classList.contains('toast')) { + if (block.classList.contains('fixed-to-top') || block.classList.contains(TOAST_BANNER)) { block.classList.add('cmp-notification-bar'); // analytics trigger contentWrapper.classList.add('cmp-carousel__item__content'); // analytics trigger const body = block.closest('body'); @@ -119,6 +143,14 @@ export default async function decorate(block) { const closeButton = copyBlock.querySelector('button.close-button'); closeButton.classList.add('cmp-carousel__action--close'); // analytics trigger + + // Add event to set a cookie when the banner is closed + if (block.classList.contains(TOAST_BANNER)) { + closeButton.addEventListener('click', () => { + setCookie(TOAST_BANNER_COOKIE, 'true', 3); + }); + } + closeButton.addEventListener('click', () => copyBlock.remove()); body.prepend(copySection); copySection.style = '{display: block;}'; From a7dd3045368f9fd3c2181febc2996796a8a860dc Mon Sep 17 00:00:00 2001 From: "conary.hernandez" <“conary.hernandez@herodigital.com”> Date: Wed, 16 Apr 2025 09:49:08 -0600 Subject: [PATCH 3/5] STERICMS-821: Refactor header and banner styles to improve alert menu handling and CSS variable usage --- blocks/banner/banner.css | 6 ------ blocks/header/nav.css | 14 ++++++++++---- blocks/header/utils.js | 25 ++++++++++++++++--------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/blocks/banner/banner.css b/blocks/banner/banner.css index 9753dc5f..c260636a 100644 --- a/blocks/banner/banner.css +++ b/blocks/banner/banner.css @@ -169,12 +169,6 @@ margin: auto; } -.block.banner p:has(a) a:any-link, -.block.banner p:has(strong+a) a:any-link, -.block.banner p:has(strong > a) a:any-link { - color: var(--color-text-primary); -} - .block.banner p.button-container a:any-link { background-color: var(--color-button-primary); border-color: var(--color-button-primary); diff --git a/blocks/header/nav.css b/blocks/header/nav.css index cc242066..3fd13d78 100644 --- a/blocks/header/nav.css +++ b/blocks/header/nav.css @@ -1,4 +1,10 @@ /* Updated CSS with .header added to each rule */ +:root { + --menu-offset-without-banner: 0px; + --menu-offset-with-banner: 146px; + --menu-desktop-offset-without-banner: 0px; + --menu-desktop-offset-with-banner: 168px; +} header { position: sticky; @@ -26,7 +32,7 @@ header { } .header nav.nav-alert { - top: 124px; + top: var(--menu-offset-with-banner); } .header nav.open { @@ -89,7 +95,7 @@ header { } .header .submenu-alert.submenu { - top: 124px; + top: var(--menu-offset-with-banner); } .header .nav-item:not(.hover) { @@ -797,11 +803,11 @@ header { } .header .submenu-alert.submenu { - top: 168px; + top: var(--menu-desktop-offset-with-banner); } .header .submenu-alert.submenu-scrolled { - top: 168px; + top: var(--menu-desktop-offset-with-banner); } .header .submenu.open { diff --git a/blocks/header/utils.js b/blocks/header/utils.js index 75dd0b03..d20cb1a4 100644 --- a/blocks/header/utils.js +++ b/blocks/header/utils.js @@ -20,6 +20,7 @@ const FOCUSABLE_ELEMENTS = const MOBILE_MENU_OPEN_CLASSNAME = 'open'; const DESKTOP_MENU_OPEN_CLASSNAME = 'hover'; +const ALERT_MENU_CLASSNAME = 'submenu-alert'; const handleScroll = (submenu) => { if (window.scrollY > 50) { @@ -200,7 +201,10 @@ export function generateMenuFromSection( } const nav = document.createElement('nav'); - const hasAlertBanner = document.querySelector('.cmp-notification-bar'); + + const hasAlertBanner = document.querySelector( + '.cmp-notification-bar:not(.toast)', + ); nav.role = 'menu'; nav.id = 'nav'; @@ -266,10 +270,10 @@ export function generateMenuFromSection( if (hasAlertBanner) { const alertCloseButton = hasAlertBanner.querySelector('.close-button'); - submenu.classList.add('submenu-alert'); + submenu.classList.add(ALERT_MENU_CLASSNAME); alertCloseButton.addEventListener('click', () => { - submenu.classList.remove('submenu-alert'); + submenu.classList.remove(ALERT_MENU_CLASSNAME); nav.classList.remove('nav-alert'); }); @@ -746,8 +750,9 @@ export function buildCtasSection( const contactModalButtonTitle = placeHolders.contactustext || 'Open Contact Us Information'; const searchModalButtonTitle = placeHolders.searchtext || 'Open Search box'; - const hasAlertBanner = document.querySelector('.cmp-notification-bar'); - + const hasAlertBanner = document.querySelector( + '.cmp-notification-bar:not(.toast)', + ); const contactModalButton = button({ class: 'icon-button button contact-button', 'aria-label': contactModalButtonTitle, @@ -819,7 +824,7 @@ export function buildCtasSection( const contactModal = div( { class: `submenu modal contact-modal ${ - hasAlertBanner ? 'submenu-alert' : '' + hasAlertBanner ? ALERT_MENU_CLASSNAME : '' }`, id: 'contact-modal', }, @@ -841,7 +846,9 @@ export function buildCtasSection( const searchModal = div( { - class: `submenu search-modal ${hasAlertBanner ? 'submenu-alert' : ''}`, + class: `submenu search-modal ${ + hasAlertBanner ? ALERT_MENU_CLASSNAME : '' + }`, id: 'search-modal', }, div( @@ -880,8 +887,8 @@ export function buildCtasSection( const alertCloseButton = hasAlertBanner.querySelector('.close-button'); alertCloseButton.addEventListener('click', () => { - searchModal.classList.remove('submenu-alert'); - contactModal.classList.remove('submenu-alert'); + searchModal.classList.remove(ALERT_MENU_CLASSNAME); + contactModal.classList.remove(ALERT_MENU_CLASSNAME); }); } From 8f6693d8aad71cbc31c4826bbb8529a122c56e04 Mon Sep 17 00:00:00 2001 From: Allan Montilla Date: Fri, 9 May 2025 09:36:26 -0600 Subject: [PATCH 4/5] STERICMS-821_AM: Add rounded top edges to banner to match Figma --- blocks/banner/banner.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/blocks/banner/banner.css b/blocks/banner/banner.css index c260636a..150ab2fa 100644 --- a/blocks/banner/banner.css +++ b/blocks/banner/banner.css @@ -29,6 +29,7 @@ width: 100%; bottom: 42px; padding: 36px 32px; + border-radius: 8px 8px 0px 0px; max-width: initial; } @@ -93,6 +94,10 @@ color: var(--color-white); margin-left: 10px; } + + .block.banner.toast { + border-radius: 12px 12px 0px 0px; + } } .block.banner > .banner-content > .banner-content-page * { From 36e293c5a414339a0bab8de3c31f04f1fdff2fe4 Mon Sep 17 00:00:00 2001 From: Allan Montilla Date: Fri, 9 May 2025 09:38:23 -0600 Subject: [PATCH 5/5] STERICMS-821_AM: Fix lint issues --- blocks/banner/banner.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blocks/banner/banner.css b/blocks/banner/banner.css index 150ab2fa..6f59ecae 100644 --- a/blocks/banner/banner.css +++ b/blocks/banner/banner.css @@ -29,7 +29,7 @@ width: 100%; bottom: 42px; padding: 36px 32px; - border-radius: 8px 8px 0px 0px; + border-radius: 8px 8px 0 0; max-width: initial; } @@ -96,7 +96,7 @@ } .block.banner.toast { - border-radius: 12px 12px 0px 0px; + border-radius: 12px 12px 0 0; } }