Skip to content

Commit

Permalink
Breadcrumbs #44 (#213)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonatan-lledo-netcentric authored Feb 15, 2024
1 parent c543ce0 commit 636c424
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 12 deletions.
63 changes: 63 additions & 0 deletions blocks/v2-breadcrumb/v2-breadcrumb.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
.v2-breadcrumb-wrapper{
background-color: #333;
}

.v2-breadcrumb {
padding: 16px;
color: var(--c-primary-white);
max-width: var(--wrapper-width);
margin: 0 auto;
display: flex;
}

.v2-breadcrumb .v2-breadcrumb__crumb-list {
display: flex;
}

.v2-breadcrumb .v2-breadcrumb__crumb-item {
display: flex;
margin: 0;
}

.v2-breadcrumb__crumb-item + .v2-breadcrumb__crumb-item::before {
content: '/';
margin: 0 10px;
}

.v2-breadcrumb .v2-breadcrumb__crumb-item--hidden::before {
content: '';
margin: 0;
}

.v2-breadcrumb .v2-breadcrumb__crumb {
text-transform: capitalize;
color: inherit;
display: flex;
}

.v2-breadcrumb__crumb:focus {
outline: none;
}

.v2-breadcrumb__crumb:focus-visible {
outline: 2px solid var(--border-focus);
border-radius: 2px;
outline-offset: 2px
}

.v2-breadcrumb__crumb--active {
color: var(--c-primary-white);
font-family: var(--ff-body-bold);
white-space: nowrap;
}

.v2-breadcrumb__crumb--active:hover {
text-decoration: none;
}


@media (min-width: 1200px) {
.v2-breadcrumb {
padding: 16px 0;
}
}
122 changes: 122 additions & 0 deletions blocks/v2-breadcrumb/v2-breadcrumb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { readBlockConfig } from '../../scripts/lib-franklin.js';
import { createElement, getTextLabel } from '../../scripts/common.js';

const blockName = 'v2-breadcrumb';
const sectionStatus = 'data-section-status';
const breadcrumb = getTextLabel('breadcrumb');
const homeText = {
home: getTextLabel('home'),
ellipsis: '…', // unicode ellipsis
};

const formatText = (str) => str.replace(/-/g, ' ').toLowerCase();

const getPadding = (elCompCSS) => parseInt(elCompCSS.getPropertyValue('padding-left'), 10)
+ parseInt(elCompCSS.getPropertyValue('padding-right'), 10);

const getCrumbsWidth = (block) => {
const crumbs = block.querySelectorAll(`.${blockName}__crumb-item`);
return [...crumbs].reduce((acc, item) => {
const itemCompCSS = window.getComputedStyle(item);
return acc + parseInt(itemCompCSS.getPropertyValue('width'), 10);
}, 0);
};

const getBlockWidth = (block) => {
const computedCSS = window.getComputedStyle(block);
const blockWidth = parseInt(computedCSS.getPropertyValue('width'), 10);
const boxSizing = computedCSS.getPropertyValue('box-sizing');
const padding = boxSizing === 'border-box' ? getPadding(computedCSS) : 0;
return blockWidth - padding;
};

const fitting = (block) => getCrumbsWidth(block) < getBlockWidth(block);
export default function decorate(block) {
const cfg = readBlockConfig(block);
const hasPath = cfg && Object.hasOwn(cfg, 'path');
const url = hasPath ? cfg.path : window.location.pathname;
const path = url.split('/').filter(Boolean);
const nav = createElement('nav', { classes: [`${blockName}__crumb-nav`] });
const ul = createElement('ul', { classes: [`${blockName}__crumb-list`] });
const crumbs = path.map((_, i) => {
const liEl = createElement('li', { classes: [`${blockName}__crumb-item`] });
const content = formatText(path[i]);
const crumbProps = { 'data-content': content };
const crumbClasses = [`${blockName}__crumb`];
if (i !== path.length - 1) {
crumbProps.href = `/${path.slice(0, i + 1).join('/')}/`;
} else {
crumbClasses.push(`${blockName}__crumb--active`);
crumbProps['aria-current'] = 'page';
}
const crumb = createElement('a', { classes: crumbClasses, props: crumbProps });
crumb.textContent = content;
liEl.append(crumb);
return liEl;
});
const homeItem = createElement('li', { classes: [`${blockName}__crumb-item`] });
const homeEl = createElement('a', {
classes: [`${blockName}__crumb`, `${blockName}__crumb--home`],
props: { href: '/' },
});

homeEl.textContent = homeText.home;
homeItem.append(homeEl);
crumbs.unshift(homeItem);
ul.append(...crumbs);
nav.append(ul);
block.textContent = '';
block.append(nav);
block.parentElement.classList.add('full-width');
block.setAttribute('aria-label', breadcrumb);

const checkCrumbsFits = () => {
// 1st check if home fits, if not it become an ellipsis
if (!fitting(block) && crumbs.length > 2) homeEl.textContent = homeText.ellipsis;
// if still doesn't fit, remove active crumb
if (!fitting(block)) {
crumbs.at(-1).firstElementChild.textContent = '';
crumbs.at(-1).classList.add(`${blockName}__crumb-item--hidden`);
}
// if it still doesn't fit again, remove the crumbs from the middle
if (!fitting(block)) {
let i = 1;
while (i < crumbs.length - 2 && !fitting(block)) {
crumbs[i].firstElementChild.textContent = '';
crumbs[i].classList.add(`${blockName}__crumb-item--hidden`);
i += 1;
}
}
};

const rObserver = new ResizeObserver((entries) => {
entries.forEach((entry) => {
if (!entry.contentBoxSize) return;
// add again the content from each item and check if it fits again or not
homeEl.textContent = homeText.home;
crumbs.forEach((crumb, i) => {
const link = crumb.firstElementChild;
if (i > 0) {
crumb.classList.remove(`${blockName}__crumb-item--hidden`);
link.textContent = link.dataset.content;
}
});
checkCrumbsFits();
});
});

const mObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
// check if the attribute data-section-status has the value 'loaded'
if (mutation.attributeName !== sectionStatus) return;
const section = mutation.target;
const status = section.getAttribute(sectionStatus);
if (status !== 'loaded') return;
rObserver.observe(block);
mObserver.disconnect();
});
});
mObserver.observe(block.closest('.section'), {
childList: true, attributeFilter: [sectionStatus],
});
}
32 changes: 20 additions & 12 deletions placeholder.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"total": 26,
"total": 52,
"offset": 0,
"limit": 26,
"limit": 52,
"data": [
{
"Key": "Low resolution video message",
Expand Down Expand Up @@ -102,19 +102,19 @@
{
"Key": "vinlabel",
"Text": "Enter your 17-digit VIN (Vehicle Identification Number)"
},
},
{
"Key": "submit",
"Text": "Submit"
},
},
{
"Key": "vinformat",
"Text": "Please provide correct vin number format"
},
},
{
"Key": "result text",
"Text": "${count} recalls available for \"${vin}\" VIN"
},
},
{
"Key": "recalls",
"Text": "Recalls"
Expand All @@ -134,7 +134,7 @@
{
"Key": "remedy_description",
"Text": "Remedy"
},
},
{
"Key": "published_info",
"Text": "Information last updated"
Expand All @@ -150,11 +150,11 @@
{
"Key": "recall_incomplete",
"Text": "Recall Incomplete"
},
},
{
"Key": "recall_incomplete_no_remedy",
"Text": "Recall In Complete, remedy not available"
},
},
{
"Key": "loading recalls",
"Text": " Loading Recalls ....."
Expand All @@ -166,11 +166,11 @@
{
"Key": "mfr_notes",
"Text": "Next steps"
},
},
{
"Key": "mfr_recall_number",
"Text": "Brand Recall Number"
},
},
{
"Key": "nhtsa_recall_number",
"Text": "NHTSA recall number"
Expand All @@ -182,7 +182,7 @@
{
"Key": "All trucks",
"Text": "All trucks"
},
},
{
"Key": "recall_available_info",
"Text": "since:"
Expand All @@ -202,6 +202,14 @@
{
"Key": "tc_recall_nbr",
"Text": "Transport Canada Number"
},
{
"Key": "home",
"Text": "home"
},
{
"Key": "breadcrumb",
"Text": "Breadcrumb"
}
],
":type": "sheet"
Expand Down

0 comments on commit 636c424

Please sign in to comment.