Skip to content

Commit

Permalink
MWPW-161015 Adds new segment-timeline classes (#3328)
Browse files Browse the repository at this point in the history
* Initial updates to handle new UX requirements

* Add segment udpates

* Fix class

* Fix center text

* rtl updates for segments

* Remove rtl test

* Add back padding

* Fix padding and columns

* Add fix for bad class

* Remove comment

* Update tests

* Fix test

* Update libs/blocks/timeline/timeline.js

---------

Co-authored-by: Vivian A Goodrich <101133187+vgoodric@users.noreply.github.com>
  • Loading branch information
markpadbe and vgoodric authored Dec 9, 2024
1 parent b72ed94 commit 02bf866
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 18 deletions.
127 changes: 118 additions & 9 deletions libs/blocks/timeline/timeline.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
width: 100%;
margin: 0 auto;
}

.dialog-modal .timeline {
padding: 0 var(--spacing-xl) var(--spacing-xl) var(--spacing-xl);
}
Expand All @@ -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,
Expand Down Expand Up @@ -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 *,
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -140,4 +250,3 @@
padding: 0 var(--spacing-xl) var(--spacing-xl) var(--spacing-xl);
}
}

30 changes: 25 additions & 5 deletions libs/blocks/timeline/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
Expand Down Expand Up @@ -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)`;
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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);
}
22 changes: 22 additions & 0 deletions test/blocks/timeline/mocks/brokensegmentclass.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="timeline segment-timeline-9">
<div>
<div data-valign="middle">
<p>linear-gradient(to right, #E63888 0, #E9740A 100%)</p>
<h3 id="day-1">Day 1</h3>
<p>If you start your free trial today | 14 <strong>-day free trial</strong></p>
</div>
</div>
<div>
<div data-valign="middle">
<p>#FFCE2E</p>
<h3 id="day-8">Day 8</h3>
<p>Your subscription starts and billing begins | 7 <strong>-day full refund period</strong></p>
</div>
</div>
<div>
<div data-valign="middle">
<h3 id="day-21">Day 21</h3>
<p>Full refund period ends</p>
</div>
</div>
</div>
22 changes: 22 additions & 0 deletions test/blocks/timeline/mocks/segmentclasses.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="timeline segment-timeline-9-3">
<div>
<div data-valign="middle">
<p>linear-gradient(to right, #E63888 0, #E9740A 100%)</p>
<h3 id="day-1">Day 1</h3>
<p>If you start your free trial today | 14 <strong>-day free trial</strong></p>
</div>
</div>
<div>
<div data-valign="middle">
<p>#FFCE2E</p>
<h3 id="day-8">Day 8</h3>
<p>Your subscription starts and billing begins | 7 <strong>-day full refund period</strong></p>
</div>
</div>
<div>
<div data-valign="middle">
<h3 id="day-21">Day 21</h3>
<p>Full refund period ends</p>
</div>
</div>
</div>
37 changes: 33 additions & 4 deletions test/blocks/timeline/timeline.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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;
});
});
});

0 comments on commit 02bf866

Please sign in to comment.