Skip to content
Snippets Groups Projects
Commit b45697a1 authored by Ekaterina Kondareva's avatar Ekaterina Kondareva Committed by Tuukka Turu
Browse files

Nxstage 1001 upper navigation advanced

parent cf39da0f
No related branches found
No related tags found
No related merge requests found
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
position: relative; position: relative;
.desktop-menu-link__heading__icon { .desktop-menu-link__heading__icon {
bottom: 14px; bottom: 0;
display: block; display: block;
left: 0; left: 0;
position: absolute; position: absolute;
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
justify-content: center; justify-content: center;
transform: rotateX(180deg); transform: rotateX(180deg);
svg { svg {
padding: 4px 0; padding: 8px 0;
} }
} }
} }
...@@ -82,11 +82,11 @@ ...@@ -82,11 +82,11 @@
background-color: var(--grayscale-white); background-color: var(--grayscale-white);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center;
opacity: 1; opacity: 1;
position: absolute; position: absolute;
left: 0; left: 0;
top: 104px; padding-left: 300px;
padding-bottom: 28px;
width: 100%; width: 100%;
z-index: 510; z-index: 510;
} }
...@@ -115,7 +115,13 @@ ...@@ -115,7 +115,13 @@
&__desktop-menu { &__desktop-menu {
display: flex; display: flex;
position: relative; //position: relative;
&__menu-items {
//@todo check max-with in Specs
min-width: 450px;
max-width: 550px;
}
// first level link inside panel // first level link inside panel
&__first-level-menu-item { &__first-level-menu-item {
...@@ -199,7 +205,7 @@ ...@@ -199,7 +205,7 @@
flex-direction: row; flex-direction: row;
letter-spacing: -0.47px; letter-spacing: -0.47px;
padding-left: 24px; padding-left: 24px;
padding-right: 24px; padding-right: 48px;
text-transform: none; text-transform: none;
} }
...@@ -238,8 +244,14 @@ ...@@ -238,8 +244,14 @@
// Shortcuts // Shortcuts
.shortcuts-panel { .shortcuts-panel {
position: absolute;
left: 0; // override in js
list-style: none; list-style: none;
margin-left: 48px; min-width: 350px;
max-width: 400px;
//margin: 0 48px;
padding: 0 48px;
top: 0;
&__title { &__title {
@include font-size(18px, 22px); @include font-size(18px, 22px);
...@@ -264,11 +276,13 @@ ...@@ -264,11 +276,13 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
font-family: var(--main-font-family); font-family: var(--main-font-family);
justify-content: space-between;
letter-spacing: -0.5px; letter-spacing: -0.5px;
padding: 19px 0; padding: 19px 0;
text-decoration: none; text-decoration: none;
.icon { .icon {
padding-left: 24px;
svg { svg {
padding: 4px; padding: 4px;
} }
......
...@@ -7,10 +7,13 @@ export interface ShortcutLinks { ...@@ -7,10 +7,13 @@ export interface ShortcutLinks {
export interface DesktopLinks { export interface DesktopLinks {
label: string; label: string;
labelExtra: string;
url: string; url: string;
description: string; description: string;
menuLinkId: string; menuLinkId: string;
isActive: string; isActive: string;
shortcutsTitle: string;
closeButtonTitle: string;
items: Array<DesktopLinks>; items: Array<DesktopLinks>;
shortcuts: Array<ShortcutLinks>; shortcuts: Array<ShortcutLinks>;
} }
...@@ -32,8 +35,14 @@ export class HyDesktopMenuLinks { ...@@ -32,8 +35,14 @@ export class HyDesktopMenuLinks {
private _dataDesktopLinks: DesktopLinks[]; private _dataDesktopLinks: DesktopLinks[];
@State() firstLevelLinksList: Array<object> = []; @State() firstLevelLinksList: Array<object> = [];
@State() menuLinkItems: Array<object> = []; @State() menuLinkItems: Array<object> = [];
@State() hasToolbar: boolean = false;
@State() isDesktopMenuOpen: boolean = false;
@Watch('dataDesktopLinks') dataDesktopLinksWatcher(data: DesktopLinks[] | string) { private _submenuLeftMargin: number = 32;
private _headerBorderOffset: number = 8;
@Watch('dataDesktopLinks')
dataDesktopLinksWatcher(data: DesktopLinks[] | string) {
this._dataDesktopLinks = typeof data === 'string' ? JSON.parse(data) : data; this._dataDesktopLinks = typeof data === 'string' ? JSON.parse(data) : data;
} }
...@@ -41,13 +50,33 @@ export class HyDesktopMenuLinks { ...@@ -41,13 +50,33 @@ export class HyDesktopMenuLinks {
this.dataDesktopLinksWatcher(this.dataDesktopLinks); this.dataDesktopLinksWatcher(this.dataDesktopLinks);
} }
showBackdropShadow(state = 'close', top = 0) {
let hyHeader = this.el.closest('.hy-site-header') as HTMLElement;
let hyBackdropDiv = hyHeader.children[0] as HTMLElement;
if (hyBackdropDiv) {
if (state === 'open') {
hyBackdropDiv.classList.add('is-active');
hyBackdropDiv.style.top = `${top}px`;
}
if (state === 'close') {
hyBackdropDiv.classList.remove('is-active');
hyBackdropDiv.style.top = '0';
}
}
}
handleDesktopMenuClose() { handleDesktopMenuClose() {
this.isDesktopMenuOpen = false;
this.showBackdropShadow();
const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`); const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`);
const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel');
const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[aria-expanded="true"]`); const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[aria-expanded="true"]`) as HTMLElement;
// Return focus to the button of the last desktop panel that was active. // Return focus to the button of the last desktop panel that was active.
if (activeMenuItem !== null) (activeMenuItem as HTMLElement).focus(); if (activeMenuItem !== null) activeMenuItem.focus();
// Reset elements by removing the active classes. // Reset elements by removing the active classes.
menuItems.forEach((item) => { menuItems.forEach((item) => {
...@@ -61,10 +90,11 @@ export class HyDesktopMenuLinks { ...@@ -61,10 +90,11 @@ export class HyDesktopMenuLinks {
} }
handleDesktopMenuToggle(id) { handleDesktopMenuToggle(id) {
this.isDesktopMenuOpen = true;
const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`); const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`);
const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); // all panels const menuPanelItems = this.el.shadowRoot.querySelectorAll('.hy-desktop-menu-panel'); // all panels
const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`); const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`) as HTMLElement;
const activeMenuItemSibling = activeMenuItem.nextElementSibling; // current panel const activeMenuItemSibling = activeMenuItem.nextElementSibling as HTMLElement; // current panel
// Reset elements by removing the active classes. // Reset elements by removing the active classes.
menuItems.forEach((item) => { menuItems.forEach((item) => {
...@@ -80,109 +110,202 @@ export class HyDesktopMenuLinks { ...@@ -80,109 +110,202 @@ export class HyDesktopMenuLinks {
activeMenuItem.classList.add('desktop-menu-link--is-active'); activeMenuItem.classList.add('desktop-menu-link--is-active');
activeMenuItem.setAttribute('aria-expanded', 'true'); activeMenuItem.setAttribute('aria-expanded', 'true');
activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active'); activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active');
if (this.hasToolbar) {
activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active--has-toolbar');
}
activeMenuItemSibling.setAttribute('aria-hidden', 'false'); activeMenuItemSibling.setAttribute('aria-hidden', 'false');
// Add panels top value automatically with the correct header height
const headerHeight = `${
this.el.parentElement.offsetTop + this.el.parentElement.offsetHeight + this._headerBorderOffset
}px`;
activeMenuItemSibling.style.top = headerHeight;
// Add shadow backdrop
let rect = activeMenuItemSibling.getBoundingClientRect();
this.showBackdropShadow('open', rect.bottom);
// Position submenu block under the activated top menu item.
let activeButtonRect = activeMenuItem.getBoundingClientRect();
const menuPanelLeftPosition = activeButtonRect.left - this._submenuLeftMargin;
activeMenuItemSibling.style.paddingLeft = `${menuPanelLeftPosition}px`;
// Position shortcuts block.
let shortcutsDiv = activeMenuItemSibling.querySelectorAll('ul.shortcuts-panel')[0] as HTMLElement; // shortcuts block
if (shortcutsDiv) {
let subMenuDiv = activeMenuItemSibling.querySelectorAll(
'.hy-desktop-menu-panel__desktop-menu__menu-items'
)[0] as HTMLElement; // 2nd level menu block
let spaceLeftAfterSubmenu = subMenuDiv.getBoundingClientRect().right + shortcutsDiv.offsetWidth;
if (spaceLeftAfterSubmenu >= document.body.scrollWidth) {
// Shortcuts should be placed to the left.
let shortcutsLeftPosition = subMenuDiv.getBoundingClientRect().left - shortcutsDiv.offsetWidth;
shortcutsDiv.style.left = shortcutsLeftPosition.toString().concat('px');
} else {
// Shortcuts should be placed to the right.
let shortcutsLeftPosition = subMenuDiv.getBoundingClientRect().right;
shortcutsDiv.style.left = shortcutsLeftPosition.toString().concat('px');
}
}
}
handleDesktopMenuClick(id) {
const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`);
const activeMenuItemSibling = activeMenuItem.nextElementSibling as HTMLElement; // current panel
if (!this.isDesktopMenuOpen) {
// Add active classes to the currently active item and its sibling element.
this.isDesktopMenuOpen = true;
activeMenuItem.classList.add('desktop-menu-link--is-active');
activeMenuItem.setAttribute('aria-expanded', 'true');
activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active');
if (this.hasToolbar) {
activeMenuItemSibling.classList.add('hy-desktop-menu-panel--is-active--has-toolbar');
}
activeMenuItemSibling.setAttribute('aria-hidden', 'false');
let rect = activeMenuItemSibling.getBoundingClientRect();
this.showBackdropShadow('open', rect.bottom);
} else {
// Remove active classes to the currently active item and its sibling element.
this.isDesktopMenuOpen = false;
activeMenuItem.classList.remove('desktop-menu-link--is-active');
activeMenuItem.setAttribute('aria-expanded', 'false');
activeMenuItemSibling.classList.remove('hy-desktop-menu-panel--is-active');
if (this.hasToolbar) {
activeMenuItemSibling.classList.remove('hy-desktop-menu-panel--is-active--has-toolbar');
}
activeMenuItemSibling.setAttribute('aria-hidden', 'true');
this.showBackdropShadow();
}
} }
componentDidLoad() { componentDidLoad() {
let hyToolbar = document.querySelectorAll('#toolbar-administration')[0];
if (hyToolbar) {
this.hasToolbar = true;
}
const links = this._dataDesktopLinks as Array<DesktopLinks>; const links = this._dataDesktopLinks as Array<DesktopLinks>;
let menuLinkItems = []; let menuLinkItems = [];
links.map(({menuLinkId: id, shortcuts, items, url, description, label, isActive}) => { links.map(
let classAttributes = ['desktop-menu-link', isActive === 'true' ? 'desktop-menu-link--is-active-trail' : ''].join( ({
' ' menuLinkId: id,
); shortcuts,
items,
menuLinkItems.push( url,
<li> description,
<button label,
type="button" labelExtra,
class={classAttributes} isActive,
link-id={id} shortcutsTitle,
onMouseOver={() => this.handleDesktopMenuToggle(id)} closeButtonTitle,
onFocus={() => this.handleDesktopMenuToggle(id)} }) => {
aria-expanded="false" let classAttributes = [
> 'desktop-menu-link',
{label} isActive === 'true' ? 'desktop-menu-link--is-active-trail' : '',
<span class="desktop-menu-link__heading__icon"> ].join(' ');
<hy-icon icon={'hy-icon-caret-down'} size={16} />
</span> menuLinkItems.push(
</button> <li>
<div class="hy-desktop-menu-panel" onMouseLeave={() => this.handleDesktopMenuClose()} aria-hidden="true">
<div class="hy-desktop-menu-panel__desktop-menu">
<div class="hy-desktop-menu-panel__desktop-menu__menu-items">
<a
aria-current={label}
href={url}
class="hy-desktop-menu-panel__desktop-menu__first-level-menu-item"
menu-link-id={id}
>
<span class="heading-icon">
<hy-icon icon={'hy-icon-arrow-right'} size={40} />
</span>
<span class="label">{label}</span>
{description && <span class="description">{description}</span>}
</a>
<ul class={'hy-desktop-menu-panel__desktop-menu__second-level-menu'} menu-link-id={id}>
{items.map(({label, url}) => (
<li>
<a href={url}>
<span class="heading-icon">
<hy-icon icon={'hy-icon-caret-right'} size={12} />
</span>
<span class="label">{label}</span>
</a>
</li>
))}
</ul>
</div>
{shortcuts.length > 0 && (
<ul class="shortcuts-panel">
<h2 class="shortcuts-panel__title">{'Shortcuts'}</h2>
{shortcuts.map(({shortcut_title, shortcut_url, shortcut_is_external, shortcut_aria_label}, index) => {
let target = shortcut_is_external ? '_blank' : '_self';
let shortcutClass = [
'shortcuts-panel__shortcut-item',
index == 0 ? 'shortcuts-panel__shortcut-item__first' : '',
].join(' ');
return (
<li class={shortcutClass}>
<a
aria-current={shortcut_aria_label}
href={shortcut_url}
class="shortcut-item__link"
target={target}
aria-label={shortcut_aria_label}
>
<span class="label">{shortcut_title}</span>
<span class="icon">
<hy-icon icon={'hy-icon-arrow-right'} size={24} />
</span>
</a>
</li>
);
})}
</ul>
)}
</div>
<button <button
onClick={() => this.handleDesktopMenuClose()} type="button"
class={{ class={classAttributes}
'hy-desktop-menu-panel__panel-toggle': true, link-id={id}
}} onClick={() => this.handleDesktopMenuClick(id)}
aria-label="Close menu" onMouseOver={() => this.handleDesktopMenuToggle(id)}
onFocus={() => this.handleDesktopMenuToggle(id)}
aria-expanded="false"
> >
<span class="hy-desktop-menu-panel__panel-toggle__label"> {label}
<span class="hy-desktop-menu-panel__panel-toggle__label__title">CLOSE</span> <span class="desktop-menu-link__heading__icon">
<hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.black} /> <hy-icon icon={'hy-icon-caret-down'} size={32} />
</span> </span>
</button> </button>
</div> <div class="hy-desktop-menu-panel" onMouseLeave={() => this.handleDesktopMenuClose()} aria-hidden="true">
</li> <div class="hy-desktop-menu-panel__desktop-menu">
); <div class="hy-desktop-menu-panel__desktop-menu__menu-items">
}); <a
aria-current={label}
href={url}
class="hy-desktop-menu-panel__desktop-menu__first-level-menu-item"
menu-link-id={id}
>
<span class="heading-icon">
<hy-icon icon={'hy-icon-arrow-right'} size={40} />
</span>
{labelExtra ? <span class="label">{labelExtra}</span> : <span class="label">{label}</span>}
{description && <span class="description">{description}</span>}
</a>
<ul class={'hy-desktop-menu-panel__desktop-menu__second-level-menu'} menu-link-id={id}>
{items.map(({label, url}) => (
<li>
<a href={url}>
<span class="heading-icon">
<hy-icon icon={'hy-icon-caret-right'} size={12} />
</span>
<span class="label">{label}</span>
</a>
</li>
))}
</ul>
</div>
{shortcuts.length > 0 && (
<ul class="shortcuts-panel">
<h2 class="shortcuts-panel__title">{shortcutsTitle}</h2>
{shortcuts.map(
({shortcut_title, shortcut_url, shortcut_is_external, shortcut_aria_label}, index) => {
let target = shortcut_is_external ? '_blank' : '_self';
let shortcutClass = [
'shortcuts-panel__shortcut-item',
index == 0 ? 'shortcuts-panel__shortcut-item__first' : '',
].join(' ');
return (
<li class={shortcutClass}>
<a
aria-current={shortcut_aria_label}
href={shortcut_url}
class="shortcut-item__link"
target={target}
aria-label={shortcut_aria_label}
>
<span class="label">{shortcut_title}</span>
<span class="icon">
<hy-icon icon={'hy-icon-arrow-right'} size={24} />
</span>
</a>
</li>
);
}
)}
</ul>
)}
</div>
<button
onClick={() => this.handleDesktopMenuClose()}
class={{
'hy-desktop-menu-panel__panel-toggle': true,
}}
aria-label="Close menu"
>
<span class="hy-desktop-menu-panel__panel-toggle__label">
<span class="hy-desktop-menu-panel__panel-toggle__label__title">{closeButtonTitle}</span>
<hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.black} />
</span>
</button>
</div>
</li>
);
}
);
this.menuLinkItems = menuLinkItems; this.menuLinkItems = menuLinkItems;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment