diff --git a/libs/blocks/media/media.js b/libs/blocks/media/media.js index 1dbcb9e0b1..fa87946042 100644 --- a/libs/blocks/media/media.js +++ b/libs/blocks/media/media.js @@ -114,6 +114,7 @@ export default async function init(el) { decorateTextOverrides(el); if (el.classList.contains('countdown-timer')) { - await loadCDT(container, el.classList); + const textBlock = container.querySelector('.text'); + if (textBlock) await loadCDT(textBlock, el.classList); } } diff --git a/libs/blocks/notification/notification.js b/libs/blocks/notification/notification.js index 5ee6398d6c..8dd8ceb5bf 100644 --- a/libs/blocks/notification/notification.js +++ b/libs/blocks/notification/notification.js @@ -14,7 +14,7 @@ * Notification - v1.2 */ -import { decorateBlockText, decorateBlockBg, decorateTextOverrides, decorateMultiViewport } from '../../utils/decorate.js'; +import { decorateBlockText, decorateBlockBg, decorateTextOverrides, decorateMultiViewport, loadCDT } from '../../utils/decorate.js'; import { createTag, getConfig, loadStyle } from '../../utils/utils.js'; const { miloLibs, codeRoot } = getConfig(); @@ -135,6 +135,9 @@ async function decorateLockup(lockupArea, el) { async function decorateForegroundText(el, container) { const text = container?.querySelector('h1, h2, h3, h4, h5, h6, p')?.closest('div'); text?.classList.add('text'); + if (el.classList.contains('countdown-timer') && !el.classList.contains('pill') && !el.classList.contains('ribbon')) { + await loadCDT(text, el.classList); + } const iconArea = text?.querySelector('p:has(picture)'); iconArea?.classList.add('icon-area'); if (iconArea?.textContent.trim()) await decorateLockup(iconArea, el); diff --git a/libs/features/cdt/cdt.css b/libs/features/cdt/cdt.css index c67183c43a..d751f78c86 100644 --- a/libs/features/cdt/cdt.css +++ b/libs/features/cdt/cdt.css @@ -16,10 +16,7 @@ .timer-label { font-size: var(--type-body-s-size); font-weight: 700; - height: 27px; -} - -.light .timer-label { + line-height: var(--type-body-xxl-size); color: #000; } @@ -28,15 +25,20 @@ } .horizontal .timer-label { - margin: 0 2px 27px; + margin: 0 2px var(--type-body-xxl-size); } -.timer-block { - display: flex; +.timer-separator { + margin: 0px 2px; + line-height: var(--type-body-xxl-size); } .horizontal .timer-block { - margin-left: 10px; + margin-inline-start: 10px; +} + +.timer-block { + display: flex; } .timer-fragment { @@ -46,15 +48,13 @@ } .timer-box { - padding: 0 9px; - width: 10px; + padding: 0 calc(var(--font-size-multiplier, 1) * 9px); + width: var(--type-detail-s-size); border-radius: 5px; font-size: var(--type-body-m-size); font-weight: 700; text-align: center; -} - -.light .timer-box { + line-height: var(--type-body-xxl-size); background-color: #222; color: #FFF; } @@ -64,6 +64,10 @@ color: #1D1D1D; } +html[dir="rtl"] .timer-unit-container { + flex-direction: row-reverse; +} + .timer-unit-container { display: flex; column-gap: 2px; @@ -75,9 +79,7 @@ font-size: var(--type-body-xs-size); font-weight: 400; text-align: start; -} - -.light .timer-unit-label { + line-height: var(--type-body-xxl-size); color: #464646; } diff --git a/libs/features/cdt/cdt.js b/libs/features/cdt/cdt.js index 8afb6b5116..45648913bf 100644 --- a/libs/features/cdt/cdt.js +++ b/libs/features/cdt/cdt.js @@ -11,6 +11,10 @@ function loadCountdownTimer( ) { let isVisible = false; let interval; + const oneMinuteinMs = 60000; + + const instant = new URL(window.location.href)?.searchParams?.get('instant'); + let currentTime = instant ? Date.parse(instant) : Date.now(); function appendTimerBox(parent, value, label) { const fragment = createTag('div', { class: 'timer-fragment' }, null, { parent }); @@ -52,9 +56,6 @@ function loadCountdownTimer( } function updateCountdown() { - const instant = new URL(window.location.href)?.searchParams?.get('instant'); - const currentTime = instant ? new Date(instant) : Date.now(); - for (let i = 0; i < timeRangesEpoch.length; i += 2) { const startTime = timeRangesEpoch[i]; const endTime = timeRangesEpoch[i + 1]; @@ -66,6 +67,7 @@ function loadCountdownTimer( const hoursLeft = Math.floor((diffTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutesLeft = Math.floor((diffTime % (1000 * 60 * 60)) / (1000 * 60)); render(daysLeft, hoursLeft, minutesLeft); + currentTime += oneMinuteinMs; return; } } @@ -76,7 +78,6 @@ function loadCountdownTimer( } function startCountdown() { - const oneMinuteinMs = 60000; updateCountdown(); interval = setInterval(updateCountdown, oneMinuteinMs); } @@ -108,13 +109,14 @@ export default async function initCDT(el, classList) { const parsedTime = Date.parse(time?.trim()); return Number.isNaN(parsedTime) ? null : parsedTime; }); + if (timeRangesEpoch.includes(null)) { throw new Error('Invalid format for countdown timer range'); } const cdtDiv = createTag('div', { class: 'countdown-timer' }, null, { parent: el }); cdtDiv.classList.add(isMobile() ? 'vertical' : 'horizontal'); - cdtDiv.classList.add(classList.contains('dark') ? 'dark' : 'light'); + if (classList.contains('dark')) cdtDiv.classList.add('dark'); if (classList.contains('center')) cdtDiv.classList.add('center'); loadCountdownTimer(cdtDiv, cdtLabel, cdtDays, cdtHours, cdtMins, timeRangesEpoch); diff --git a/libs/utils/decorate.js b/libs/utils/decorate.js index 3e1cd0e2a5..e911fa325e 100644 --- a/libs/utils/decorate.js +++ b/libs/utils/decorate.js @@ -323,6 +323,6 @@ export async function loadCDT(el, classList) { .then(({ default: initCDT }) => initCDT(el, classList)), ]); } catch (error) { - window.lana?.log(`Failed to load countdown timer module: ${error}`, { tags: 'countdown-timer' }); + window.lana?.log(`WARN: Failed to load countdown timer: ${error}`, { tags: 'errorType=warn,module=countdown-timer' }); } } diff --git a/test/blocks/notification/mocks/body.html b/test/blocks/notification/mocks/body.html index 9a13c85a93..71658b5c1d 100644 --- a/test/blocks/notification/mocks/body.html +++ b/test/blocks/notification/mocks/body.html @@ -495,5 +495,49 @@

Desktop content

- +
+ +

notification

+
+
+
+ + + mock + +
+
+ + + mock + +
+
+ + + mock + +
+
+
+
+

Heading M 24/30 Lorem ipsum dolor sit amet, consetetur sadis elitr.

+

Body M 18/27 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eius. See terms.

+

Call to action Call to action

+
+
+ + + mock + +
+
+
+
+
+
style
+
l spacing
+
+
+
diff --git a/test/blocks/notification/notification.test.js b/test/blocks/notification/notification.test.js index 77c4a9fa29..948cf8c5dc 100644 --- a/test/blocks/notification/notification.test.js +++ b/test/blocks/notification/notification.test.js @@ -1,13 +1,16 @@ import { readFile } from '@web/test-runner-commands'; import { expect } from '@esm-bundle/chai'; -import { setConfig } from '../../../libs/utils/utils.js'; +import { setConfig, getConfig } from '../../../libs/utils/utils.js'; + +const mockBody = await readFile({ path: './mocks/body.html' }); +const { default: init } = await import('../../../libs/blocks/notification/notification.js'); const locales = { '': { ietf: 'en-US', tk: 'hah7vzn.css' } }; -const conf = { locales }; +const conf = { locales, miloLibs: 'http://localhost:2000/libs' }; setConfig(conf); +getConfig().locale.contentRoot = '/test/blocks/notification/mocks'; -const mockBody = await readFile({ path: './mocks/body.html' }); -const { default: init } = await import('../../../libs/blocks/notification/notification.js'); +document.head.innerHTML = ''; describe('notification', async () => { let notifs; @@ -45,6 +48,9 @@ describe('notification', async () => { const border = notifs[2].querySelector(':scope > .border'); expect(border).to.exist; }); + it('has a cdt', () => { + expect(notifs[15].querySelectorAll('.timer-label')).to.have.lengthOf(1); + }); }); describe('ribbon notifications', () => {