Skip to content

Commit

Permalink
#514117 - Fix navigation and footer
Browse files Browse the repository at this point in the history
  • Loading branch information
infloent committed Aug 23, 2024
1 parent 1dd3520 commit bd0d1f2
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 78 deletions.
14 changes: 11 additions & 3 deletions blocks/accordion/accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,26 @@ export default class Accordion extends ComponentBase {
this.setupContent(children.filter((_, ind) => ind % 2 === 1));
}

createIcon(elem) {
const icon = document.createElement('raqn-icon');
icon.dataset.icon = 'chevron-right';

const hasIcon = elem?.querySelectorAll(`raqn-icon[data-icon="${icon.dataset.icon}"]`)?.length;
if (!hasIcon) {
elem.append(icon);
}
}

setupControls(controls) {
controls.forEach((control, index) => {
const icon = document.createElement('raqn-icon');
icon.dataset.icon = 'chevron-right';
const children = Array.from(control.children);
if (children.length === 0) {
const child = document.createElement('span');
child.textContent = control.textContent;
control.innerHTML = '';
control.append(child);
}
control.children[0].append(icon);
this.createIcon(control.children[0]);
control.setAttribute('role', 'button');
control.setAttribute('aria-expanded', 'false');
control.setAttribute('tabindex', '0');
Expand Down
2 changes: 1 addition & 1 deletion blocks/footer/footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class Footer extends ComponentBase {
if (!child) return;
child.replaceWith(...child.children);
this.nav = this.querySelector('ul');
this.nav.setAttribute('role', 'navigation');
this.nav?.setAttribute('role', 'navigation');
this.classList.add('full-width');
this.classList.add('horizontal');
}
Expand Down
31 changes: 19 additions & 12 deletions blocks/navigation/navigation.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ raqn-navigation > nav p {
padding: 0;
}

raqn-navigation > nav ul {
list-style: none;
}

raqn-navigation .level-1 a:not(:hover) {
color: var(--accent-background, #000);
}
Expand All @@ -34,6 +38,10 @@ raqn-navigation.active > nav p {
display: block;
}

raqn-navigation > nav a {
display: inline-block;
}

raqn-navigation.active > nav a {
display: inline-flex;
align-items: center;
Expand Down Expand Up @@ -73,7 +81,6 @@ raqn-navigation.active button {
raqn-navigation.active > nav > ul {
position: fixed;
display: block;
list-style: none;
max-width: 0;
background: var(--background, #fff);
min-width: 100%;
Expand All @@ -82,12 +89,9 @@ raqn-navigation.active > nav > ul {
height: 100%;
max-height: calc(100vh - var(--header-height, 64px));
margin: 0 auto;
padding: 0;
}

raqn-navigation.active > nav > ul li {
max-width: var(--max-width, 100%);
margin: 0 auto;
padding-block: 0;
padding-inline: var(--container-width);
overflow-y: auto;
}

raqn-navigation.active > nav > ul li a {
Expand All @@ -105,6 +109,8 @@ raqn-navigation:not([data-compact='true']) > nav a {
raqn-navigation:not([data-compact='true']) > nav ul {
list-style: none;
display: flex;
column-gap: var(--padding-vertical, 40px);
margin: 0;
}

raqn-navigation:not([data-compact='true']) > nav > ul {
Expand All @@ -120,8 +126,8 @@ raqn-navigation:not([data-compact='true']) > nav [data-icon='chevron-right'] {
transform: rotate(90deg);
}

raqn-navigation:not([data-compact='true']) > nav .level-1 a {
padding: var(--padding-vertical, 10px) var(--padding-horizontal, 20px);
raqn-navigation:not([data-compact='true']) > nav :where(.level-1, .level-2) > a {
padding-block: var(--padding-horizontal, 20px);
}

raqn-navigation:not([data-compact='true']) > nav .level-2 > a {
Expand Down Expand Up @@ -150,9 +156,11 @@ raqn-navigation:not([data-compact='true']) > nav .level-1 > ul {
position: absolute;
padding: 0;
inset-block-start: var(--header-height, 64px);
inset-inline-start: calc((100vw - var(--max-width)) / 2);
inset-inline-start: 0;
width: 100%;
transition: clip-path 0.4s ease-in-out;
overflow: visible;
padding-inline: var(--container-width);
}

raqn-navigation:not([data-compact='true']) > nav .level-1 > ul .level-2 {
Expand All @@ -164,10 +172,9 @@ raqn-navigation:not([data-compact='true']) > nav .level-1 > ul .level-2 {

raqn-navigation:not([data-compact='true']) > nav .level-1 > ul::after {
content: ' ';
margin-inline: calc(-1 * ((100vw - var(--max-width)) / 2));
position: absolute;
height: 100%;
width: 100vw;
width: 100%;
inset-inline-start: 0;
background: var(--background, #fff);
border-block-start: 1px solid var(--accent-background, #000);
Expand Down
226 changes: 178 additions & 48 deletions blocks/navigation/navigation.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,218 @@
import component from '../../scripts/init.js';
import { blockBodyScroll } from '../../scripts/libs.js';
import Column from '../column/column.js';

export default class Navigation extends Column {
static observedAttributes = ['data-icon', 'data-compact', 'data-justify'];
static observedAttributes = ['data-menu-icon', 'data-item-icon', 'data-compact', ...Column.observedAttributes];

dependencies = ['icon', 'accordion'];

createButton() {
const button = document.createElement('button');
button.setAttribute('aria-label', 'Menu');
button.setAttribute('aria-expanded', 'false');
button.setAttribute('aria-controls', 'navigation');
button.setAttribute('aria-haspopup', 'true');
button.setAttribute('type', 'button');
button.setAttribute('tabindex', '0');
button.innerHTML = '<raqn-icon icon=menu></raqn-icon>';
button.addEventListener('click', () => {
this.classList.toggle('active');
button.setAttribute('aria-expanded', this.classList.contains('active'));
});
return button;
}
attributesValues = {
all: {
data: {
menu: {
icon: 'menu__close',
},
item: {
icon: 'chevron-right',
},
},
},
m: {
data: {
compact: true,
},
},
x: {
data: {
compact: true,
},
},
xs: {
data: {
compact: true,
},
},
};

ready() {
setDefaults() {
super.setDefaults();
this.active = {};
this.list = this.querySelector('ul');
this.isActive = false;
this.navContentInit = false;
this.navCompactedContentInit = false;
}

async ready() {
this.navContent = this.querySelector('ul');
this.innerHTML = '';
this.navCompactedContent = this.navContent.cloneNode(true); // the clone need to be done before `this.navContent` is modified
this.nav = document.createElement('nav');
this.nav.append(this.list);
this.setAttribute('role', 'navigation');
this.compact = this.getAttribute('compact') === 'true' || false;
this.icon = this.getAttribute('icon') || 'menu';
if (this.compact) {
this.nav.append(this.createButton());
}
this.isCompact = this.dataset.compact === 'true';
this.append(this.nav);
this.setupClasses(this.list);
if (this.compact) {
this.addEventListener('click', (e) => this.activate(e));
this.nav.setAttribute('role', 'navigation');
this.nav.setAttribute('id', 'navigation');

if (this.isCompact) {
await this.setupCompactedNav();
} else {
this.setupNav();
}
}

setupNav() {
if (!this.navContentInit) {
this.navContentInit = true;
this.setupClasses(this.navContent);
}
this.navButton?.remove();
this.nav.append(this.navContent);
}

createIcon(name = this.icon) {
async setupCompactedNav() {
if (!this.navCompactedContentInit) {
this.navCompactedContentInit = true;
await component.multiLoadAndDefine(['accordion', 'icon']);
this.setupClasses(this.navCompactedContent, true);
this.navCompactedContent.addEventListener('click', (e) => this.activate(e));
}

this.prepend(this.createButton());
this.nav.append(this.navCompactedContent);
}

onAttributeCompactChanged({ oldValue, newValue }) {
if (!this.initialized) return;
if (oldValue === newValue) return;
this.isCompact = newValue === 'true';
this.nav.innerHTML = '';

if (this.isCompact) {
this.setupCompactedNav();
} else {
if (this.navButton) {
this.isActive = false;
this.classList.remove('active');
this.navButton.removeAttribute('aria-expanded');
this.navIcon.dataset.active = this.isActive;
this.closeAllLevels();
}
this.setupNav();
}
}

onAttributeIconChanged({ newValue }) {
if (!this.initialized) return;
if (!this.isCompact) return;
this.navIcon.dataset.icon = newValue;
}

createButton() {
this.navButton = document.createElement('button');
this.navButton.setAttribute('aria-label', 'Menu');
this.navButton.setAttribute('aria-expanded', 'false');
this.navButton.setAttribute('aria-controls', 'navigation');
this.navButton.setAttribute('aria-haspopup', 'true');
this.navButton.setAttribute('type', 'button');
this.navButton.innerHTML = `<raqn-icon data-icon=${this.dataset.menuIcon}></raqn-icon>`;
this.navIcon = this.navButton.querySelector('raqn-icon');
this.navButton.addEventListener('click', () => {
this.isActive = !this.isActive;
this.classList.toggle('active');
this.navButton.setAttribute('aria-expanded', this.isActive);
this.navIcon.dataset.active = this.isActive;
blockBodyScroll(this.isActive);
this.closeAllLevels();
});
return this.navButton;
}

addIcon(elem) {
const icon = document.createElement('raqn-icon');
icon.setAttribute('icon', name);
return icon;
icon.dataset.icon = this.dataset.itemIcon;
elem.append(icon);
}

creaeteAccordion(replaceChildrenElement) {
createAccordionOld(elem) {
component.init({
componentName: 'accordion',
targets: [elem],
componentConfig: {
addToTargetMethod: 'append',
},
nestedComponentsConfig: {
button: { active: false },
},
});
}

createAccordion(replaceChildrenElement) {
const accordion = document.createElement('raqn-accordion');
const children = Array.from(replaceChildrenElement.children);
accordion.append(...children);
accordion.append(...replaceChildrenElement.childNodes);
replaceChildrenElement.append(accordion);
}

setupClasses(ul, level = 1) {
setupClasses(ul, isCompact, level = 1) {
const children = Array.from(ul.children);
children.forEach((child) => {

children.forEach(async (child) => {
const hasChildren = child.querySelector('ul');
child.classList.add(`level-${level}`);
child.dataset.level = level;

if (hasChildren) {
const anchor = child.querySelector('a');
if (this.compact) {
this.creaeteAccordion(child);
if (isCompact) {
this.createAccordion(child);
} else if (level === 1) {
anchor.append(this.createIcon('chevron-right'));
const anchor = child.querySelector('a');

this.addIcon(anchor);
}
child.classList.add('has-children');
this.setupClasses(hasChildren, level + 1);
this.setupClasses(hasChildren, isCompact, level + 1);
}
});
}

activate(e) {
e.preventDefault();
if (e.target.tagName.toLowerCase() === 'a') {
if (e.target.tagName.toLowerCase() === 'raqn-icon' || e.target.closest('raqn-icon')) {
e.preventDefault();

const current = e.target.closest('li');
const { level } = current.dataset;
if (this.active[level] && this.active[level] !== current) {
this.active[level].classList.remove('active');
const currentLevel = Number(level);
const activeLevel = Number(this.getAttribute('active'));
const isCurrentLevel = this.active[currentLevel] && this.active[currentLevel] === current;
const hasActiveChildren = currentLevel < activeLevel;

if (!isCurrentLevel || hasActiveChildren) {
const whileCurrentLevel = isCurrentLevel && hasActiveChildren ? currentLevel + 1 : currentLevel;
this.closeLevels(activeLevel, whileCurrentLevel);
}
this.active[level] = current;
this.setAttribute('active', level);
this.active[level].classList.toggle('active');

this.setAttribute('active', isCurrentLevel ? Math.max(0, currentLevel - 1) || '' : currentLevel);
this.active[currentLevel]?.classList.toggle('active');
this.active[currentLevel] = isCurrentLevel ? null : current;
}
}

closeLevels(activeLevel, currentLevel = 1) {
let whileCurrentLevel = currentLevel;
while (whileCurrentLevel <= activeLevel) {
this.active[whileCurrentLevel].classList.remove('active');
const accordion = this.active[whileCurrentLevel].querySelector('raqn-accordion');
const control = accordion.querySelector('.accordion-control');
accordion.toggleControl(control);
this.active[whileCurrentLevel] = null;
whileCurrentLevel += 1;
}
}

closeAllLevels() {
const activeLevel = Number(this.getAttribute('active'));
if (activeLevel) {
this.closeLevels(activeLevel);
this.removeAttribute('active');
}
}
}
Loading

0 comments on commit bd0d1f2

Please sign in to comment.