Skip to content

Commit

Permalink
Marquee Transpilation (#9)
Browse files Browse the repository at this point in the history
* mostly working with further component fixes needed

* remove console.log

* transpile a variant class

* more native buttons approach with sub-text support

* marquee variant styling correction

* no color detection

* Update styles-deprecated.css

* CSS split

* fixed video play link look

* lint

* add double icon generation guard

* make transpilation syncronous

---------

Co-authored-by: Victor Hargrave <[email protected]>
  • Loading branch information
qiyundai and vhargrave authored Apr 17, 2024
1 parent 7f5ad97 commit 242cfe2
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ logs/*
node_modules/*
.DS_Store
.idea
.env
6 changes: 3 additions & 3 deletions express/scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ const CONFIG = {
links: 'on',
};

// Decorate the page with site specific needs.
decorateArea();

/*
* ------------------------------------------------------------
* Edit below at your own risk
Expand All @@ -76,6 +73,9 @@ decorateArea();

const miloLibs = setLibs(LIBS);

// Decorate the page with site specific needs.
decorateArea();

(function loadStyles() {
const paths = [`${miloLibs}/styles/styles.css`];
if (STYLES) { paths.push(STYLES); }
Expand Down
167 changes: 160 additions & 7 deletions express/scripts/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,42 @@ export const [setLibs, getLibs] = (() => {
];
})();

export function toClassName(name) {
return name && typeof name === 'string'
? name.toLowerCase().replace(/[^0-9a-z]/gi, '-')
: '';
}

/*
* ------------------------------------------------------------
* Edit above at your own risk.
*
* Note: This file should have no self-invoking functions.
* ------------------------------------------------------------
*/

function createTag(tag, attributes, html, options = {}) {
const el = document.createElement(tag);
if (html) {
if (html instanceof HTMLElement
|| html instanceof SVGElement
|| html instanceof DocumentFragment) {
el.append(html);
} else if (Array.isArray(html)) {
el.append(...html);
} else {
el.insertAdjacentHTML('beforeend', html);
}
}
if (attributes) {
Object.entries(attributes).forEach(([key, val]) => {
el.setAttribute(key, val);
});
}
options.parent?.append(el);
return el;
}

export function toClassName(name) {
return name && typeof name === 'string'
? name.toLowerCase().replace(/[^0-9a-z]/gi, '-')
: '';
}

export function readBlockConfig(block) {
const config = {};
block.querySelectorAll(':scope>div').forEach(($row) => {
Expand Down Expand Up @@ -75,6 +98,7 @@ export function readBlockConfig(block) {

export function removeIrrelevantSections(area) {
if (!area) return;

const getMetadata = (name, doc = document) => {
const attr = name && name.includes(':') ? 'property' : 'name';
const meta = doc.head.querySelector(`meta[${attr}="${name}"]`);
Expand Down Expand Up @@ -214,12 +238,141 @@ export function listenMiloEvents() {
window.addEventListener('milo:postSection:loading', postSectionLoadingHandler);
}

function transpileMarquee(area) {
const handleSubCTAText = (oldContainer, newContainer) => {
const elAfterBtn = oldContainer.nextElementSibling;
if (!elAfterBtn || elAfterBtn?.tagName !== 'BLOCKQUOTE') return;

const subText = elAfterBtn.querySelector('p');

if (subText) {
const subTextEl = createTag('span', { class: 'cta-sub-text' }, subText.innerHTML);
newContainer.append(subTextEl);
}
elAfterBtn.remove();
};

const needsTranspile = (block) => {
const firstRow = block.querySelector(':scope > div:first-of-type');
return firstRow.children.length > 1 && ['default', 'mobile', 'desktop', 'hd'].includes(firstRow.querySelector(':scope > div')?.textContent?.trim().toLowerCase());
};

const isVideoLink = (url) => {
if (!url) return null;
return url.includes('youtube.com/watch')
|| url.includes('youtu.be/')
|| url.includes('vimeo')
|| /.*\/media_.*(mp4|webm|m3u8)$/.test(new URL(url).pathname);
};

const transpile = (block) => {
const assetArea = createTag('div');

block.classList.add('transpiled', 'xl-button');

if (block.classList.contains('short')) {
block.classList.remove('short');
block.classList.add('small');
}

if (!block.classList.contains('dark')) {
block.classList.add('light');
}

const rows = block.querySelectorAll(':scope > div');

if (rows.length) {
rows.forEach((r, i, arr) => {
if (i < arr.length - 1) {
r.querySelector(':scope > div:first-of-type')?.remove();

if (document.body.dataset.device === 'mobile') {
const valCol = r.querySelector(':scope > div:last-of-type');
assetArea.innerHTML = valCol.innerHTML;
if (block.classList.contains('dark')) valCol.innerHTML = '#000000';
if (block.classList.contains('light')) valCol.innerHTML = '#ffffff00';
}

if (i > 0) {
r.remove();
}
}

if (i === arr.length - 1) {
const aTags = r.querySelectorAll('p > a');
const btnContainers = [];
const elsToAppend = [];
const actionArea = createTag('p', { class: 'action-area' });

aTags.forEach((a) => {
if (!btnContainers.includes(a.parentElement)) {
btnContainers.push(a.parentElement);
}

if (isVideoLink(a.href) && !a.querySelector('span.icon.icon-play')) {
const playIcon = createTag('span', { class: 'icon icon-play' });
a.prepend(playIcon);
}
});

const isInlineButtons = btnContainers.length === 1;

aTags.forEach((a) => {
const buttonContainer = a.parentElement;

if (buttonContainer?.childNodes.length === 1) {
const buttonWrapper = createTag('span');
buttonWrapper.append(a);
handleSubCTAText(buttonContainer, buttonWrapper);
buttonContainer.remove();

elsToAppend.push(buttonWrapper);
}
});

elsToAppend.forEach((e, index) => {
actionArea.append(e);
const link = e.querySelector('a');

if (!link) return;
if (index === 0) {
const strong = createTag('strong');
e.prepend(strong);
strong.append(link);
}
if (index === 1) {
if (!isInlineButtons) {
const em = createTag('em');
e.prepend(em);
em.append(link);
}
}
});

const lastPInFirstDiv = r.querySelector(':scope > div > p:last-of-type');
lastPInFirstDiv?.after(actionArea);
r.append(assetArea);
}
});
}
};

const marquees = [...area.querySelectorAll('div.marquee')].filter((m) => m.classList[0] === 'marquee');
marquees.forEach((block) => {
if (needsTranspile(block)) transpile(block);
});
}

export function decorateArea(area = document) {
removeIrrelevantSections(area);
document.body.dataset.device = navigator.userAgent.includes('Mobile') ? 'mobile' : 'desktop';
removeIrrelevantSections(area.tagName === 'main' ? area : area.querySelector('main', 'body'));
// LCP image decoration
(function decorateLCPImage() {
const lcpImg = area.querySelector('img');
lcpImg?.removeAttribute('loading');
}());

// transpile conflicting blocks
transpileMarquee(area);
overrideMiloColumns(area);
}
72 changes: 50 additions & 22 deletions express/styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
--color-info-secondary: #e8e8e8;
--color-info-secondary-hover: #d4d4d4;
--color-info-secondary-down: #cdcdcd;
--color-premium: #ebcf2d;
--color-info-premium: #ebcf2d;
--gradient-highlight-vertical: linear-gradient(15deg, #7c84fc, #ff4dd2);
--gradient-highlight-horizontal: linear-gradient(90deg, #ff4dd2, #7c84fc);
--gradient-highlight-diagonal: linear-gradient(45deg, #7c84fc, #ff4dd2);
Expand Down Expand Up @@ -438,7 +438,6 @@ body.light-grey {
}

main {
text-align: center;
overflow-x: clip;
}

Expand Down Expand Up @@ -478,7 +477,6 @@ main p {

main a:any-link {
color: var(--color-info-accent);
text-decoration: none;
font-weight: 600;
}

Expand All @@ -491,30 +489,30 @@ main .section:last-of-type > .default-content-wrapper {
}

@media (min-width: 600px) {
main h2 {
main > h2 {
font-size: var(--heading-font-size-l);
text-align: center;
}

main h3 {
main > h3 {
font-size: var(--heading-font-size-l);
text-align: center;
}

main h4 {
main > h4 {
font-size: var(--heading-font-size-m);
margin-top: 56px;
text-align: center;
}

main h1 + h5 {
main > h1 + h5 {
font-size: var(--body-font-size-xxl);
font-weight: var(--body-font-weight);
margin-top: 32px;
margin-bottom: 16px;
}

main p {
main > p {
font-size: var(--body-font-size-l);
}

Expand Down Expand Up @@ -714,8 +712,6 @@ main .section.secondary {

main .section > div {
margin: auto;
max-width: 375px;
padding: 0;
}

main .section > div:empty {
Expand Down Expand Up @@ -754,18 +750,6 @@ body[data-device='mobile']
display: block;
}

@media (min-width: 900px) {
main .section > div {
max-width: 830px;
}
}

@media (min-width: 1200px) {
main .section > div {
max-width: 1024px;
}
}

/* jank protection for async blocks/sections */

main .pricing,
Expand Down Expand Up @@ -1148,3 +1132,47 @@ body.has-floating-panel #adbMsgClientWrapper .adbmsgAuthoredBotPopUpContainer.ou
body.has-floating-panel #adbMsgClientWrapper #adbmsgCta {
bottom: 140px!important;
}

/*Styles can be removed once we stop using block transpilations*/
.marquee.transpiled p.action-area > span {
display: flex;
flex-direction: column;
text-align: center;
}

.marquee.transpiled p.action-area > span > a {
margin: 0;
}

.marquee.transpiled.small .text {
order: 2;
}

.marquee.transpiled.small .asset {
order: 1;
}

.marquee.transpiled .foreground .text h2 {
font-weight: 700;
text-transform: none;
font-size: clamp(var(--heading-font-size-s), 3vw, var(--heading-font-size-l));
margin: 0 0 8px 0;
}

@media screen and (min-width: 600px) {
.marquee.transpiled .foreground .text h2 {
font-size: var(--heading-font-size-s);
}

.marquee.transpiled .action-area {
align-items: flex-start;
}

.marquee.transpiled.small .text {
order: 1;
}

.marquee.transpiled.small .asset {
order: 2;
}
}

0 comments on commit 242cfe2

Please sign in to comment.