Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "MWPW-140452 - Icon authoring in milo using the federal repo and individual SVG assets" #3356

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion libs/blocks/table/table.css
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,6 @@
width: 15px;
height: 15px;
cursor: pointer;
margin-inline: unset;
}

.table .section-head-title:hover .icon.expand {
Expand Down
7 changes: 6 additions & 1 deletion libs/blocks/text/text.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
position: relative;
}

.text-block .icon-list-item .icon.node-index-first {
.text-block .icon-list-item .icon.margin-right:not(.margin-left) { /* target first node only */
position: absolute;
inset: 0 100% auto auto;
}
Expand All @@ -122,6 +122,7 @@

.text-block .icon-area {
display: flex;
column-gap: var(--spacing-xs);
}

.text-block p.icon-area { /* NOT <a/> tags with icons in them */
Expand Down Expand Up @@ -217,6 +218,10 @@
max-width: unset;
}

.text-block .icon-area.con-button {
column-gap: unset;
}

.text-block .icon-area picture {
line-height: 0em;
height: inherit; /* Safari + FF bug fix */
Expand Down
1 change: 0 additions & 1 deletion libs/features/georoutingv2/georoutingv2.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
}

.dialog-modal.locale-modal-v2 span.icon {
display: inline;
vertical-align: middle;
}

Expand Down
2 changes: 1 addition & 1 deletion libs/features/georoutingv2/georoutingv2.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ function buildContent(currentPage, locale, geoData, locales) {
{ once: true },
);
img.src = `${config.miloLibs || config.codeRoot}/img/georouting/${flagFile}`;
const span = createTag('span', { class: 'icon node-index-first' }, img);
const span = createTag('span', { class: 'icon margin-inline-end' }, img);
const mainAction = createTag('a', {
class: 'con-button blue button-l', lang, role: 'button', 'aria-haspopup': !!locales, 'aria-expanded': false, href: '#',
}, span);
Expand Down
2 changes: 1 addition & 1 deletion libs/features/icons/icons.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
border-bottom: none;
}

.milo-tooltip::before {
.milo-tooltip::before {
content: attr(data-tooltip);
position: absolute;
top: 50%;
Expand Down
118 changes: 21 additions & 97 deletions libs/features/icons/icons.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { getFederatedContentRoot } from '../../utils/federated.js';
import { loadLink, loadStyle } from '../../utils/utils.js';

let fetchedIcons;
let fetched = false;
const federalIcons = {};

async function getSVGsfromFile(path) {
/* c8 ignore next */
Expand All @@ -26,7 +22,6 @@ async function getSVGsfromFile(path) {
return miloIcons;
}

// TODO: remove after all consumers have stopped calling this method
// eslint-disable-next-line no-async-promise-executor
export const fetchIcons = (config) => new Promise(async (resolve) => {
/* c8 ignore next */
Expand All @@ -39,112 +34,41 @@ export const fetchIcons = (config) => new Promise(async (resolve) => {
resolve(fetchedIcons);
});

async function decorateToolTip(icon) {
function decorateToolTip(icon) {
const wrapper = icon.closest('em');
if (!wrapper) return;
wrapper.className = 'tooltip-wrapper';
if (!wrapper) return;
const conf = wrapper.textContent.split('|');
// Text is the last part of a tooltip
const content = conf.pop().trim();
if (!content) return;
icon.dataset.tooltip = content;
// Position is the next to last part of a tooltip
const place = conf.pop()?.trim().toLowerCase() || 'right';
const defaultIcon = 'info-outline';
icon.className = `icon icon-${defaultIcon} milo-tooltip ${place}`;
icon.dataset.name = defaultIcon;
icon.className = `icon icon-info milo-tooltip ${place}`;
wrapper.parentElement.replaceChild(icon, wrapper);
}

export function getIconData(icon) {
const fedRoot = getFederatedContentRoot();
const name = [...icon.classList].find((c) => c.startsWith('icon-'))?.substring(5);
const path = `${fedRoot}/federal/assets/icons/svgs/${name}.svg`;
return { path, name };
}

function preloadInViewIconResources(config) {
const { base } = config;
loadStyle(`${base}/features/icons/icons.css`);
}

const preloadInViewIcons = async (icons = []) => icons.forEach((icon) => {
const { path } = getIconData(icon);
loadLink(path, { rel: 'preload', as: 'fetch', crossorigin: 'anonymous' });
});

function filterDuplicatedIcons(icons) {
if (!icons.length) return [];
const uniqueIconKeys = new Set();
const uniqueIcons = [];
for (const icon of icons) {
const key = [...icon.classList].find((c) => c.startsWith('icon-'))?.substring(5);
if (!uniqueIconKeys.has(key)) {
uniqueIconKeys.add(key);
uniqueIcons.push(icon);
}
}
return uniqueIcons;
}

export async function decorateIcons(area, icons, config) {
if (!icons.length) return;
const uniqueIcons = filterDuplicatedIcons(icons);
if (!uniqueIcons.length) return;
preloadInViewIcons(uniqueIcons);
preloadInViewIconResources(config);
icons.forEach((icon) => {
const iconName = [...icon.classList].find((c) => c.startsWith('icon-'))?.substring(5);
if (!iconName) return;
icon.dataset.name = iconName;
});
}

export default async function loadIcons(icons) {
const fedRoot = getFederatedContentRoot();
const iconRequests = [];
const iconsToFetch = new Map();

export default async function loadIcons(icons, config) {
const iconSVGs = await fetchIcons(config);
if (!iconSVGs) return;
icons.forEach(async (icon) => {
const isToolTip = icon.classList.contains('icon-tooltip');
if (isToolTip) decorateToolTip(icon);
const iconName = icon.dataset.name;
if (icon.dataset.svgInjected || !iconName) return;
if (!federalIcons[iconName] && !iconsToFetch.has(iconName)) {
const url = `${fedRoot}/federal/assets/icons/svgs/${iconName}.svg`;
iconsToFetch.set(iconName, fetch(url)
.then(async (res) => {
if (!res.ok) throw new Error(`Failed to fetch SVG for ${iconName}: ${res.statusText}`);
const text = await res.text();
const parser = new DOMParser();
const svgDoc = parser.parseFromString(text, 'image/svg+xml');
const svgElement = svgDoc.querySelector('svg');
if (!svgElement) {
window.lana?.log(`No SVG element found in fetched content for ${iconName}`);
return;
}
const svgClone = svgElement.cloneNode(true);
svgClone.classList.add('icon-milo', `icon-milo-${iconName}`);
federalIcons[iconName] = svgClone;
})
/* c8 ignore next 3 */
.catch((error) => {
window.lana?.log(`Error fetching SVG for ${iconName}:`, error);
}));
}
iconRequests.push(iconsToFetch.get(iconName));
const { classList } = icon;
if (classList.contains('icon-tooltip')) decorateToolTip(icon);
const iconName = icon.classList[1].replace('icon-', '');
const existingIcon = icon.querySelector('svg');
if (!iconSVGs[iconName] || existingIcon) return;
const parent = icon.parentElement;
if (parent && parent.parentElement.tagName === 'LI') parent.parentElement.classList.add('icon-list-item');
});

await Promise.all(iconRequests);

icons.forEach((icon) => {
const iconName = icon.dataset.name;
if (iconName && federalIcons[iconName] && !icon.dataset.svgInjected) {
const svgClone = federalIcons[iconName].cloneNode(true);
icon.appendChild(svgClone);
icon.dataset.svgInjected = 'true';
if (parent.childNodes.length > 1) {
if (parent.lastChild === icon) {
icon.classList.add('margin-inline-start');
} else if (parent.firstChild === icon) {
icon.classList.add('margin-inline-end');
if (parent.parentElement.tagName === 'LI') parent.parentElement.classList.add('icon-list-item');
} else {
icon.classList.add('margin-inline-start', 'margin-inline-end');
}
}
icon.insertAdjacentHTML('afterbegin', iconSVGs[iconName].outerHTML);
});
}
30 changes: 11 additions & 19 deletions libs/styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@
--icon-size-s: 32px;
--icon-size-xs: 24px;
--icon-size-xxs: 16px;
--icon-spacing: 8px;

/* z-index */
--above-all: 9000; /* Used for page tools that overlay page content */
Expand Down Expand Up @@ -350,7 +349,6 @@
line-height: 20px;
min-height: 21px;
padding: 7px 18px 8px;
--icon-spacing: 12px;
}

.xl-button .con-button,
Expand All @@ -360,7 +358,6 @@
line-height: 24px;
min-height: 28px;
padding: 10px 24px 8px;
--icon-spacing: 14px;
}

.xxl-button .con-button,
Expand All @@ -370,7 +367,6 @@
line-height: 27px;
min-height: 27px;
padding: 14px 30px 15px;
--icon-spacing: 14px;
}

.con-button.button-justified {
Expand Down Expand Up @@ -563,23 +559,19 @@ div[data-failed="true"]::before {
color: var(--color-gray-300);
}

span.icon {
width: 1em;
display: inline-block;
margin-inline: var(--icon-spacing);
}
span.icon.margin-right { margin-right: 8px; }

span.icon.node-index-first { margin-inline-start: unset; }
span.icon.node-index-middle { margin-inline: var(--icon-spacing); }
span.icon.node-index-last { margin-inline-end: unset; }
span.icon.node-index-only { margin-inline: unset; }
span.icon.margin-left { margin-left: 8px; }

span.icon svg {
height: 1em;
position: relative;
top: .1em;
width: auto;
}
span.icon.margin-inline-end { margin-inline-end: 8px; }

span.icon.margin-inline-start { margin-inline-start: 8px; }

.button-l .con-button span.icon.margin-left,
.con-button.button-l span.icon.margin-left { margin-left: 12px; }

.button-xl .con-button span.icon.margin-left,
.con-button.button-xl span.icon.margin-left { margin-left: 14px; }

/* Con Block Utils */
.con-block.xs-spacing { padding: var(--spacing-xs) 0; }
Expand Down
43 changes: 15 additions & 28 deletions libs/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,16 @@ function decorateHeader() {
if (promo?.length) header.classList.add('has-promo');
}

async function decorateIcons(area, config) {
const icons = area.querySelectorAll('span.icon');
if (icons.length === 0) return;
const { base } = config;
loadStyle(`${base}/features/icons/icons.css`);
loadLink(`${base}/img/icons/icons.svg`, { rel: 'preload', as: 'fetch', crossorigin: 'anonymous' });
const { default: loadIcons } = await import('../features/icons/icons.js');
await loadIcons(icons, config);
}

export async function customFetch({ resource, withCacheRules }) {
const options = {};
if (withCacheRules) {
Expand Down Expand Up @@ -1266,8 +1276,9 @@ function decorateDocumentExtras() {
decorateHeader();
}

async function documentPostSectionLoading(area, config) {
async function documentPostSectionLoading(config) {
decorateFooterPromo();

const appendage = getMetadata('title-append');
if (appendage) {
import('../features/title-append/title-append.js').then((module) => module.default(appendage));
Expand Down Expand Up @@ -1331,25 +1342,14 @@ async function resolveInlineFrags(section) {
section.preloadLinks = newlyDecoratedSection.preloadLinks;
}

export function setIconsIndexClass(icons) {
[...icons].forEach((icon) => {
const parent = icon.parentNode;
const children = parent.childNodes;
const nodeIndex = [...children].indexOf.call(children, icon);
let indexClass = (nodeIndex === children.length - 1) ? 'last' : 'middle';
if (nodeIndex === 0) indexClass = 'first';
if (children.length === 1) indexClass = 'only';
icon.classList.add(`node-index-${indexClass}`);
});
}

async function processSection(section, config, isDoc) {
await resolveInlineFrags(section);
const firstSection = section.el.dataset.idx === '0';
const stylePromises = firstSection ? preloadBlockResources(section.blocks) : [];
preloadBlockResources(section.preloadLinks);
await Promise.all([
decoratePlaceholders(section.el, config),
decorateIcons(section.el, config),
]);
const loadBlocks = [...stylePromises];
if (section.preloadLinks.length) {
Expand Down Expand Up @@ -1382,11 +1382,6 @@ export async function loadArea(area = document) {
decorateDocumentExtras();
}

const allIcons = area.querySelectorAll('span.icon');
if (allIcons.length) {
setIconsIndexClass(allIcons);
}

const sections = decorateSections(area, isDoc);

const areaBlocks = [];
Expand All @@ -1399,21 +1394,13 @@ export async function loadArea(area = document) {
});
}

if (allIcons.length) {
const { default: loadIcons, decorateIcons } = await import('../features/icons/icons.js');
const areaIcons = area.querySelectorAll('span.icon');
await decorateIcons(area, areaIcons, config);
await loadIcons(areaIcons);
}

const currentHash = window.location.hash;
if (currentHash) {
scrollToHashedElement(currentHash);
}

if (isDoc) {
await documentPostSectionLoading(area, config);
}
if (isDoc) await documentPostSectionLoading(config);

await loadDeferred(area, areaBlocks, config);
}

Expand Down
Loading
Loading