diff --git a/libs/blocks/timeline/timeline.css b/libs/blocks/timeline/timeline.css index ebf0842787..58635b9bc8 100644 --- a/libs/blocks/timeline/timeline.css +++ b/libs/blocks/timeline/timeline.css @@ -4,6 +4,7 @@ width: 100%; margin: 0 auto; } + .dialog-modal .timeline { padding: 0 var(--spacing-xl) var(--spacing-xl) var(--spacing-xl); } @@ -12,6 +13,22 @@ display: grid; } +.timeline.segment-timeline-3-9 .row, +.timeline.segment-timeline-4-8 .row, +.timeline.segment-timeline-5-7 .row { + grid-template-columns: 1fr 58.3%; +} + +.timeline.segment-timeline-6-6 .row { + grid-template-columns: 50% 50%; +} + +.timeline.segment-timeline-7-5 .row, +.timeline.segment-timeline-8-4 .row, +.timeline.segment-timeline-9-3 .row { + grid-template-columns: 1fr 41.7%; +} + .timeline h1, .timeline h2, .timeline h3, @@ -40,7 +57,6 @@ .timeline .row:nth-of-type(1)>.left>div>* { max-width: 100px; - padding-right: var(--spacing-m); } .dark .timeline .row:nth-child(3)>div *, @@ -59,7 +75,68 @@ } .timeline .row:nth-of-type(1)>.right { - grid-template-columns: minmax(110px, 1fr) 1fr; + grid-template-columns: 1.5fr 1fr; + grid-gap: 8px; +} + +[dir="rtl"] .timeline .row:nth-of-type(1)>.right { + grid-template-columns: 1fr 1fr; +} + +.timeline.segment-timeline-3-9 .left-center, +.timeline.segment-timeline-4-8 .left-center, +.timeline.segment-timeline-5-7 .left-center, +.timeline.segment-timeline-6-6 .left-center { + display: none; +} +@media screen and (max-width: 599.99px) { + .timeline.segment-timeline-7-5 .row:nth-of-type(1)>.right, + .timeline.segment-timeline-8-4 .row:nth-of-type(1)>.right, + .timeline.segment-timeline-9-3 .row:nth-of-type(1)>.right { + grid-template-columns: 1fr; + } + + .timeline.segment-timeline-7-5 .row:nth-of-type(1)>.left, + .timeline.segment-timeline-8-4 .row:nth-of-type(1)>.left, + .timeline.segment-timeline-9-3 .row:nth-of-type(1)>.left { + grid-template-columns: 1fr 1.5fr; + display: grid; + justify-content: space-between; + grid-gap: 8px; + } + + .timeline.segment-timeline-7-5 .right-center, + .timeline.segment-timeline-8-4 .right-center, + .timeline.segment-timeline-9-3 .right-center { + display: none; + } + + .timeline.segment-timeline-7-5 .left-center, + .timeline.segment-timeline-8-4 .left-center, + .timeline.segment-timeline-9-3 .left-center { + text-align: right; + display: flex; + flex-direction: column; + align-items: flex-end; + } + + [dir="rtl"] .timeline.segment-timeline-7-5 .left-center, + [dir="rtl"] .timeline.segment-timeline-8-4 .left-center, + [dir="rtl"] .timeline.segment-timeline-9-3 .left-center { + text-align: left; + } + + .timeline .row:nth-of-type(1)>.left .left-center>* { + padding-right: 0; + } +} + +@media screen and (min-width: 600px) { + .timeline.segment-timeline-7-5 .left-center, + .timeline.segment-timeline-8-4 .left-center, + .timeline.segment-timeline-9-3 .left-center { + display: none; + } } .timeline .row:nth-of-type(2)>.right { @@ -68,7 +145,7 @@ .timeline .row:nth-of-type(1)>.right>div:nth-of-type(1) { max-width: 135px; - padding-right: var(--spacing-xxs); + /* padding-right: var(--spacing-xxs); */ } .timeline .bar { @@ -103,10 +180,18 @@ } [dir="rtl"] .timeline .row:nth-of-type(1)>.left>div>* { - padding: 0 0 0 var(--spacing-m); + /* padding: 0 0 0 var(--spacing-m); */ + padding: 0; text-align: right; } +[dir="rtl"] .timeline.timeline.segment-timeline-7-5 .row:nth-of-type(1)>.left>.left-center>*, +[dir="rtl"] .timeline.timeline.segment-timeline-8-4 .row:nth-of-type(1)>.left>.left-center>*, +[dir="rtl"] .timeline.timeline.segment-timeline-9-3 .row:nth-of-type(1)>.left>.left-center>* { + padding: 0; + text-align: left; +} + [dir="rtl"] .timeline .row:nth-of-type(1)>.right>div+div { padding: 0 0 var(--spacing-xxs) 0; text-align: left; @@ -120,15 +205,40 @@ margin: 0 3px 0 0; } -[dir="rtl"] .timeline .row:nth-of-type(1)>.right>div:nth-of-type(1) { - padding: 0 0 0 var(--spacing-xxs); -} - @media screen and (min-width: 600px) { .dialog-modal .timeline { padding: 0 var(--spacing-xl) var(--spacing-xl) var(--spacing-xl); } } +@media screen and (min-width: 1200px) { + .timeline.segment-timeline-3-9 .row { + grid-template-columns: 1fr 75% + } + + .timeline.segment-timeline-4-8 .row { + grid-template-columns: 1fr 66.69%; + } + + .timeline.segment-timeline-5-7 .row { + grid-template-columns: 1fr 58.3%; + } + + .timeline.segment-timeline-6-6 .row { + grid-template-columns: 1fr 50%; + } + + .timeline.segment-timeline-7-5 .row { + grid-template-columns: 1fr 41.7%; + } + + .timeline.segment-timeline-8-4 .row { + grid-template-columns: 1fr 33.3%; + } + + .timeline.segment-timeline-9-3 .row { + grid-template-columns: 1fr 25%; + } +} @media screen and (min-width:1120px) { .timeline { @@ -140,4 +250,3 @@ padding: 0 var(--spacing-xl) var(--spacing-xl) var(--spacing-xl); } } - diff --git a/libs/blocks/timeline/timeline.js b/libs/blocks/timeline/timeline.js index ba2ea4aacf..035ef739ac 100644 --- a/libs/blocks/timeline/timeline.js +++ b/libs/blocks/timeline/timeline.js @@ -14,7 +14,20 @@ function isColorOrGradient(str) { return isColor(str) || isGradient(str); } -function getColWidth(text, colWidths) { +function hasSegmentClass(el) { + const segmentClassRegex = /^segment-timeline-(3-9|4-8|5-7|6-6|7-5|8-4|9-3)$/; + const startsWithSegmentTimelineRegex = /^segment-timeline-/; + let hasValidSegmentClass = Array.from(el.classList).some((cls) => segmentClassRegex.test(cls)); + if (!hasValidSegmentClass + && Array.from(el.classList).some((cls) => startsWithSegmentTimelineRegex.test(cls))) { + el.classList.add('segment-timeline-6-6'); + hasValidSegmentClass = true; + } + return hasValidSegmentClass; +} + +function getColWidth(text, colWidths, hasSegment) { + if (hasSegment || colWidths.length === 2) return; const numRegex = /\b\d{1,3}\b/; colWidths.push((text.match(numRegex) || [])[0]); } @@ -109,8 +122,8 @@ function setColors(colors, fragment, el) { function colWidthsNotValid(colWidths) { return (colWidths.length !== 2 || colWidths.some((value) => Number.isNaN(value))); } -function updateColWidths(colWidths, fragment) { - if (colWidthsNotValid(colWidths)) return; +function updateColWidths(colWidths, fragment, hasSegment) { + if (colWidthsNotValid(colWidths) || hasSegment) return; const total = Number(colWidths[0]) + Number(colWidths[1]); const right = Math.floor((Number(colWidths[1]) / total) * 10000) / 100; const colString = `1fr minmax(${String(right)}%, 150px)`; @@ -123,6 +136,7 @@ export default function init(el) { const [textRow, left, right] = createRow(); const rows = el.querySelectorAll(':scope > div > div'); const colors = []; const periodText = []; const colWidths = []; + const hasSegment = hasSegmentClass(el); rows.forEach((row, index) => { const side = index === 0 ? left : right; const color = row.firstElementChild?.textContent?.trim(); @@ -131,7 +145,7 @@ export default function init(el) { const [text, period] = p.textContent.trim().split('|'); if (period) { periodText.push(period.trim()); - getColWidth(period, colWidths); + getColWidth(period, colWidths, hasSegment); } if (text) { p.textContent = text.trim(); @@ -143,11 +157,17 @@ export default function init(el) { row.firstElementChild.remove(); } row.parentElement.remove(); + if (index === 1 && hasSegment) { + const mobileCenterLeft = row.cloneNode(true); + mobileCenterLeft.classList.add('left-center'); + left.append(mobileCenterLeft); + row.classList.add('right-center'); + } side.append(row); }); textRow.append(left, right); [textRow, addBarRow(), addBottomRow(periodText)].forEach((row) => fragment.append(row)); - updateColWidths(colWidths, fragment, el); + updateColWidths(colWidths, fragment, hasSegment); setColors(colors, fragment, el); el.append(fragment); } diff --git a/test/blocks/timeline/mocks/brokensegmentclass.html b/test/blocks/timeline/mocks/brokensegmentclass.html new file mode 100644 index 0000000000..acba31bd95 --- /dev/null +++ b/test/blocks/timeline/mocks/brokensegmentclass.html @@ -0,0 +1,22 @@ +
+
+
+

linear-gradient(to right, #E63888 0, #E9740A 100%)

+

Day 1

+

If you start your free trial today | 14 -day free trial

+
+
+
+
+

#FFCE2E

+

Day 8

+

Your subscription starts and billing begins | 7 -day full refund period

+
+
+
+
+

Day 21

+

Full refund period ends

+
+
+
diff --git a/test/blocks/timeline/mocks/segmentclasses.html b/test/blocks/timeline/mocks/segmentclasses.html new file mode 100644 index 0000000000..f00d2e3dd3 --- /dev/null +++ b/test/blocks/timeline/mocks/segmentclasses.html @@ -0,0 +1,22 @@ +
+
+
+

linear-gradient(to right, #E63888 0, #E9740A 100%)

+

Day 1

+

If you start your free trial today | 14 -day free trial

+
+
+
+
+

#FFCE2E

+

Day 8

+

Your subscription starts and billing begins | 7 -day full refund period

+
+
+
+
+

Day 21

+

Full refund period ends

+
+
+
diff --git a/test/blocks/timeline/timeline.test.js b/test/blocks/timeline/timeline.test.js index 204f3719a6..17478d3794 100644 --- a/test/blocks/timeline/timeline.test.js +++ b/test/blocks/timeline/timeline.test.js @@ -41,7 +41,7 @@ describe('Timeline', () => { expect(trialPeriod.textContent).to.equal('7-day free trial'); expect(refundPeriod.textContent).to.equal('14-day full refund period'); - expect(trialPeriod.style.background.includes('to right')).to.true; + expect(trialPeriod.style.background.includes('to right')).to.be.true; }); it('it sets bar background colors based on colors in free trial and refund period section', async () => { const timelineEl = document.querySelector('.timeline'); @@ -59,19 +59,48 @@ describe('Timeline', () => { const trialPeriod = timelineEl.querySelector('.row .left .period'); expect(trialPeriod.style.background.includes('to left')).to.be.true; }); - describe('Timeline', () => { + describe('rtl ', () => { beforeEach(async () => { document.body.innerHTML = await readFile({ path: './mocks/switchcolors.html' }); }); afterEach(() => { document.body.innerHTML = ''; }); - it('handles linear-gradient for either side', async () => { + it('updates linear-gradient for rtl', async () => { const timelineEl = document.querySelector('.timeline'); init(timelineEl); const refundPeriod = timelineEl.querySelector('.row .right .period'); expect(refundPeriod.textContent).to.equal('14-day full refund period'); - expect(refundPeriod.style.background.includes('to left')).to.true; + expect(refundPeriod.style.background.includes('to left')).to.be.true; + }); + }); + describe('segment classes', () => { + beforeEach(async () => { + document.body.innerHTML = await readFile({ path: './mocks/segmentclasses.html' }); + }); + afterEach(() => { + document.body.innerHTML = ''; + }); + it('adds classes to handle center text alignment', async () => { + const timelineEl = document.querySelector('.timeline'); + init(timelineEl); + const leftCenter = timelineEl.querySelector('.row .left-center'); + const rightCenter = timelineEl.querySelector('.row .right-center'); + expect(rightCenter).to.exist; + expect(leftCenter).to.exist; + }); + }); + describe('broken segment classes', () => { + beforeEach(async () => { + document.body.innerHTML = await readFile({ path: './mocks/brokensegmentclass.html' }); + }); + afterEach(() => { + document.body.innerHTML = ''; + }); + it('replaces broken segment class width segment-timeline-6-6', async () => { + const timelineEl = document.querySelector('.timeline'); + init(timelineEl); + expect(timelineEl.classList.contains('segment-timeline-6-6')).to.be.true; }); }); });