Skip to content

Commit

Permalink
MWPW-155621 - Adding functionality to the Pill Notification (#2783)
Browse files Browse the repository at this point in the history
* add multiviewport content control

* minor style tweaks, leaving text.js alone for now

* Revert "MWPW-151936 - Aside Tiger Team Enhancements (redux)" (#2777)

Revert "MWPW-151936 - Aside Tiger Team Enhancements (redux) (#2767)"

This reverts commit 88cb101.

* per-viewport dom replacing, and popup behavior support

* account for flexible box shadow

* update mock

* improvements based on PR feedback

* handle resize multi-viewport edge case

* accounting for ribbon edge cases

* sticky top pill edge case, default bg

* handle body-only copy area
  • Loading branch information
elan-tbx authored Aug 29, 2024
1 parent adb35eb commit 6012fcb
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 29 deletions.
65 changes: 56 additions & 9 deletions libs/blocks/notification/notification.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
--icon-size: 56px;
--icon-size-xl: 64px;
--pill-radius: 16px;
--pill-shadow: 0 3px 6px #707070;

display: flex;
inline-size: 100%;
Expand All @@ -25,6 +26,7 @@
flex-wrap: wrap;
overflow: hidden;
min-block-size: var(--min-block-size);
background: var(--color-white);
}

.notification.ribbon {
Expand Down Expand Up @@ -151,13 +153,24 @@
inline-size: 100%;
}

.notification.ribbon [class*="heading-"]:only-child {
margin-block-end: var(--spacing-s);
}

.notification.ribbon.space-between [class*="heading-"]:only-child {
margin-block-end: 0;
}

.notification.ribbon.space-between .foreground .text {
flex-wrap: nowrap;
inline-size: 100%;
}

.notification.ribbon.space-between .foreground .copy-wrap {
margin-inline-end: var(--spacing-s);
display: flex;
flex-direction: column;
justify-content: center;
}

.notification .foreground .image {
Expand Down Expand Up @@ -197,6 +210,12 @@
flex-wrap: nowrap;
}

.notification .foreground .image :is(picture, video),
.notification .foreground .image picture img {
inline-size: 100%;
display: flex;
}

.notification:is(.ribbon.m-icon, .pill) .icon-area img {
max-block-size: var(--icon-size-m);
}
Expand Down Expand Up @@ -250,12 +269,6 @@
margin-block-end: 0;
}

.notification .foreground .image :is(picture, video),
.notification .foreground .image picture img {
inline-size: 100%;
display: flex;
}

.notification .foreground .text a:not(.con-button) {
inline-size: auto;
font-weight: normal;
Expand Down Expand Up @@ -283,6 +296,7 @@
border-radius: var(--pill-radius);
inline-size: calc(100% - var(--spacing-m));
margin-inline: auto;
box-shadow: var(--pill-shadow);
}

.notification.pill .foreground .action-area {
Expand All @@ -298,13 +312,22 @@

.notification .flexible-inner {
inline-size: 100%;
box-shadow: var(--pill-shadow);
}

.notification .foreground > :is(.tablet-up, .desktop-up) {
display: none;
}

.notification.pill .foreground .text > :not(.action-area) {
padding-inline-end: var(--spacing-xxs);
inline-size: calc(100% - var(--spacing-xxs));
}

.notification.pill .copy-wrap p:first-child:not(:only-child) {
margin-block-end: var(--spacing-xxs);
}

@media screen and (min-width: 600px) {
.notification {
--max-inline-size-image: 188px;
Expand All @@ -329,6 +352,14 @@
gap: var(--spacing-s);
}

.notification .foreground > :is(.mobile-up, .desktop-up) {
display: none;
}

.notification .foreground > .tablet-up {
display: flex;
}

.notification:is(.max-width-12-desktop, .ribbon) .foreground {
max-inline-size: var(--full-width);
margin-inline: var(--grid-margins-width);
Expand Down Expand Up @@ -418,6 +449,8 @@

.notification.pill.flexible {
pointer-events: none;
box-shadow: none;
padding-block-end: var(--spacing-xxs);
}

.notification .flexible-inner {
Expand All @@ -444,7 +477,8 @@
--max-inline-size-image-10: 300px;
--inline-size-image-full: 33.333%;
--max-inline-size-image-full: 400px;
--pill-radius: 36px;
--max-inline-size-pill: 1600px;
--pill-radius: 100px;
}

.notification:not(.pill, .ribbon) .foreground {
Expand Down Expand Up @@ -472,6 +506,14 @@
max-inline-size: calc(var(--grid-column-width) * 10);
}

.notification .foreground > :is(.mobile-up, .tablet-up) {
display: none;
}

.notification .foreground > .desktop-up {
display: flex;
}

.notification .foreground > div {
object-fit: cover;
padding-inline-start: 0;
Expand Down Expand Up @@ -511,6 +553,7 @@
.notification.pill {
min-block-size: var(--min-block-size-pill);
inline-size: var(--inline-size-pill);
max-inline-size: var(--max-inline-size-pill);
margin-inline: auto;
}

Expand All @@ -525,7 +568,6 @@
}

.notification.pill .foreground .text [class*="heading-"] {
margin-inline-end: var(--spacing-xxs);
margin-block-end: 0;
}

Expand All @@ -549,7 +591,7 @@
}

.notification.pill .foreground .icon-area {
margin-inline-end: var(--spacing-xs);
margin-inline-end: var(--spacing-s);
margin-block-end: 0;
}

Expand All @@ -576,6 +618,7 @@
flex-wrap: wrap;
align-items: baseline;
text-align: start;
gap: var(--spacing-xxs);
}

.notification.pill .copy-wrap > * {
Expand All @@ -585,4 +628,8 @@
.notification.ribbon.space-between .foreground .icon-area {
margin-inline-end: var(--spacing-s);
}

.notification.pill .copy-wrap p:first-child:not(:only-child) {
margin-block-end: 0;
}
}
50 changes: 33 additions & 17 deletions libs/blocks/notification/notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
*/

/*
* Notification - v1.1
* Notification - v1.2
*/

import { decorateBlockText, decorateBlockBg, decorateTextOverrides } from '../../utils/decorate.js';
import { decorateBlockText, decorateBlockBg, decorateTextOverrides, decorateMultiViewport } from '../../utils/decorate.js';
import { createTag, getConfig, loadStyle } from '../../utils/utils.js';

const { miloLibs, codeRoot } = getConfig();
Expand Down Expand Up @@ -54,6 +54,8 @@ const closeSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
</defs>
</svg>`;

let iconographyLoaded = false;

function getOpts(el) {
const optRows = [...el.querySelectorAll(':scope > div:nth-of-type(n+3)')];
if (!optRows.length) return {};
Expand All @@ -73,13 +75,15 @@ function getBlockData(el) {
}

function wrapCopy(foreground) {
const text = foreground.querySelector('.text');
if (!text) return;
const heading = text?.querySelector('h1, h2, h3, h4, h5, h6, p:not(.icon-area, .action-area)');
const icon = heading?.previousElementSibling;
const body = heading?.nextElementSibling?.classList.contains('action-area') ? '' : heading?.nextElementSibling;
const copy = createTag('div', { class: 'copy-wrap' }, [heading, body].filter(Boolean));
text?.insertBefore(copy, icon?.nextSibling || text.children[0]);
const texts = foreground.querySelectorAll('.text');
if (!texts) return;
texts.forEach((text) => {
const heading = text?.querySelector('h1, h2, h3, h4, h5, h6, p:not(.icon-area, .action-area)');
const icon = heading?.previousElementSibling;
const body = heading?.nextElementSibling?.classList.contains('action-area') ? '' : heading?.nextElementSibling;
const copy = createTag('div', { class: 'copy-wrap' }, [heading, body].filter(Boolean));
text?.insertBefore(copy, icon?.nextSibling || text.children[0]);
});
}

function decorateClose(el) {
Expand All @@ -104,10 +108,11 @@ function decorateFlexible(el) {

async function loadIconography() {
await new Promise((resolve) => { loadStyle(`${base}/styles/iconography.css`, resolve); });
iconographyLoaded = true;
}

async function decorateLockup(lockupArea, el) {
await loadIconography();
if (!iconographyLoaded) await loadIconography();
const icon = lockupArea.querySelector('picture');
const content = icon.nextElementSibling || icon.nextSibling;
const label = createTag('span', { class: 'lockup-label' }, content.nodeValue || content);
Expand All @@ -122,21 +127,29 @@ async function decorateLockup(lockupArea, el) {
if (pre && pre[2] === 'icon') el.classList.replace(pre[0], `${pre[1]}-lockup`);
}

async function decorateForegroundText(el, container) {
const text = container?.querySelector('h1, h2, h3, h4, h5, h6, p')?.closest('div');
text?.classList.add('text');
const iconArea = text?.querySelector('p:has(picture)');
iconArea?.classList.add('icon-area');
if (iconArea?.textContent.trim()) await decorateLockup(iconArea, el);
}

async function decorateLayout(el) {
const [background, ...rest] = el.querySelectorAll(':scope > div');
const foreground = rest.pop();
if (background) decorateBlockBg(el, background);
foreground?.classList.add('foreground', 'container');
const text = foreground?.querySelector('h1, h2, h3, h4, h5, h6, p')?.closest('div');
text?.classList.add('text');
const iconArea = text?.querySelector('p picture')?.closest('p');
iconArea?.classList.add('icon-area');
if (iconArea?.textContent.trim()) await decorateLockup(iconArea, el);
if (el.matches(`:is(.${pill}, .${ribbon})`)) {
foreground.querySelectorAll(':scope > div').forEach((div) => decorateForegroundText(el, div));
} else {
await decorateForegroundText(el, foreground);
}
const fgMedia = foreground?.querySelector(':scope > div:not(.text) :is(img, video, a[href*=".mp4"])')?.closest('div');
const bgMedia = el.querySelector(':scope > div:not(.foreground) :is(img, video, a[href*=".mp4"])')?.closest('div');
const media = fgMedia ?? bgMedia;
media?.classList.toggle('image', media && !media.classList.contains('text'));
foreground?.classList.toggle('no-image', !media && !iconArea);
foreground?.classList.toggle('no-image', !media && !el.querySelector('.icon-area'));
if (el.matches(`:is(.${pill}, .${ribbon}):not(.no-closure)`)) decorateClose(el);
if (el.matches(`.${pill}.flexible`)) decorateFlexible(el);
return foreground;
Expand All @@ -152,5 +165,8 @@ export default async function init(el) {
}
decorateTextOverrides(el);
el.querySelectorAll('a:not([class])').forEach((staticLink) => staticLink.classList.add('static'));
if (el.matches(`:is(.${ribbon}, .${pill})`)) wrapCopy(blockText);
if (el.matches(`:is(.${ribbon}, .${pill})`)) {
wrapCopy(blockText);
decorateMultiViewport(el);
}
}
4 changes: 4 additions & 0 deletions libs/blocks/section-metadata/section-metadata.css
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@
background-color: var(--color-white);
}

.section.sticky-top:has(.notification.pill) {
height: 0;
}

.section.sticky-bottom {
position: sticky;
bottom: 0;
Expand Down
6 changes: 3 additions & 3 deletions libs/blocks/section-metadata/sticky-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ function promoIntersectObserve(el, stickySectionEl, options = {}) {
function handleStickyPromobar(section, delay) {
const main = document.querySelector('main');
section.classList.add('promo-sticky-section', 'hide-sticky-section');
if (section.querySelector('.promobar.popup')) section.classList.add('popup');
if (section.querySelector('.popup:is(.promobar, .notification.pill)')) section.classList.add('popup');
let stickySectionEl = null;
let hasScrollControl;
if ((section.querySelector('.promobar').classList.contains('no-delay')) || (delay && section.classList.contains('popup'))) {
if ((section.querySelector(':is(.promobar, .notification.pill)').classList.contains('no-delay')) || (delay && section.classList.contains('popup'))) {
hasScrollControl = true;
}
if (!hasScrollControl && main.children[0] !== section) {
Expand All @@ -52,7 +52,7 @@ export default async function handleStickySection(sticky, section) {
break;
}
case 'sticky-bottom': {
if (section.querySelector('.promobar')) {
if (section.querySelector(':is(.promobar, .notification.pill.popup)')) {
const metadata = getMetadata(section.querySelector('.section-metadata'));
const delay = getDelayTime(metadata.delay?.text);
if (delay) setTimeout(() => { handleStickyPromobar(section, delay); }, delay);
Expand Down
20 changes: 20 additions & 0 deletions libs/utils/decorate.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,23 @@ export function applyInViewPortPlay(video) {
observer.observe(video);
}
}

export function decorateMultiViewport(el) {
const viewports = [
'(max-width: 599px)',
'(min-width: 600px) and (max-width: 1199px)',
'(min-width: 1200px)',
];
const foreground = el.querySelector('.foreground');
if (foreground.childElementCount === 2 || foreground.childElementCount === 3) {
[...foreground.children].forEach((child, index) => {
const mq = window.matchMedia(viewports[index]);
const setContent = () => {
if (mq.matches) foreground.replaceChildren(child);
};
setContent();
mq.addEventListener('change', setContent);
});
}
return foreground;
}
Loading

0 comments on commit 6012fcb

Please sign in to comment.