From b45697a1ff41bc53695795a900946fd08f044b86 Mon Sep 17 00:00:00 2001
From: Ekaterina Kondareva <ekaterina.kondareva@helsinki.fi>
Date: Mon, 30 Nov 2020 10:56:01 +0200
Subject: [PATCH] Nxstage 1001 upper navigation advanced

---
 .../hy-desktop-menu-links.scss                |  28 +-
 .../hy-desktop-menu-links.tsx                 | 315 ++++++++++++------
 2 files changed, 240 insertions(+), 103 deletions(-)

diff --git a/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.scss b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.scss
index 6c4f9cae..ba2dc9e1 100644
--- a/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.scss
+++ b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.scss
@@ -57,7 +57,7 @@
         position: relative;
 
         .desktop-menu-link__heading__icon {
-          bottom: 14px;
+          bottom: 0;
           display: block;
           left: 0;
           position: absolute;
@@ -67,7 +67,7 @@
             justify-content: center;
             transform: rotateX(180deg);
             svg {
-              padding: 4px 0;
+              padding: 8px 0;
             }
           }
         }
@@ -82,11 +82,11 @@
         background-color: var(--grayscale-white);
         display: flex;
         flex-direction: row;
-        justify-content: center;
         opacity: 1;
         position: absolute;
         left: 0;
-        top: 104px;
+        padding-left: 300px;
+        padding-bottom: 28px;
         width: 100%;
         z-index: 510;
       }
@@ -115,7 +115,13 @@
 
       &__desktop-menu {
         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-menu-item {
@@ -199,7 +205,7 @@
                 flex-direction: row;
                 letter-spacing: -0.47px;
                 padding-left: 24px;
-                padding-right: 24px;
+                padding-right: 48px;
                 text-transform: none;
               }
 
@@ -238,8 +244,14 @@
 
     // Shortcuts
     .shortcuts-panel {
+      position: absolute;
+      left: 0; // override in js
       list-style: none;
-      margin-left: 48px;
+      min-width: 350px;
+      max-width: 400px;
+      //margin: 0 48px;
+      padding: 0 48px;
+      top: 0;
 
       &__title {
         @include font-size(18px, 22px);
@@ -264,11 +276,13 @@
           display: flex;
           flex-direction: row;
           font-family: var(--main-font-family);
+          justify-content: space-between;
           letter-spacing: -0.5px;
           padding: 19px 0;
           text-decoration: none;
 
           .icon {
+            padding-left: 24px;
             svg {
               padding: 4px;
             }
diff --git a/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.tsx b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.tsx
index b4567b98..607d2e24 100644
--- a/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.tsx
+++ b/src/components/site-header/hy-desktop-menu-links/hy-desktop-menu-links.tsx
@@ -7,10 +7,13 @@ export interface ShortcutLinks {
 
 export interface DesktopLinks {
   label: string;
+  labelExtra: string;
   url: string;
   description: string;
   menuLinkId: string;
   isActive: string;
+  shortcutsTitle: string;
+  closeButtonTitle: string;
   items: Array<DesktopLinks>;
   shortcuts: Array<ShortcutLinks>;
 }
@@ -32,8 +35,14 @@ export class HyDesktopMenuLinks {
   private _dataDesktopLinks: DesktopLinks[];
   @State() firstLevelLinksList: 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;
   }
 
@@ -41,13 +50,33 @@ export class HyDesktopMenuLinks {
     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() {
+    this.isDesktopMenuOpen = false;
+    this.showBackdropShadow();
+
     const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`);
     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.
-    if (activeMenuItem !== null) (activeMenuItem as HTMLElement).focus();
+    if (activeMenuItem !== null) activeMenuItem.focus();
 
     // Reset elements by removing the active classes.
     menuItems.forEach((item) => {
@@ -61,10 +90,11 @@ export class HyDesktopMenuLinks {
   }
 
   handleDesktopMenuToggle(id) {
+    this.isDesktopMenuOpen = true;
     const menuItems = this.el.shadowRoot.querySelectorAll(`.desktop-menu-link`);
     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 activeMenuItemSibling = activeMenuItem.nextElementSibling; // current panel
+    const activeMenuItem = this.el.shadowRoot.querySelector(`.desktop-menu-link[link-id="${id}"]`) as HTMLElement;
+    const activeMenuItemSibling = activeMenuItem.nextElementSibling as HTMLElement; // current panel
 
     // Reset elements by removing the active classes.
     menuItems.forEach((item) => {
@@ -80,109 +110,202 @@ export class HyDesktopMenuLinks {
     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');
+
+    // 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() {
+    let hyToolbar = document.querySelectorAll('#toolbar-administration')[0];
+    if (hyToolbar) {
+      this.hasToolbar = true;
+    }
+
     const links = this._dataDesktopLinks as Array<DesktopLinks>;
 
     let menuLinkItems = [];
 
-    links.map(({menuLinkId: id, shortcuts, items, url, description, label, isActive}) => {
-      let classAttributes = ['desktop-menu-link', isActive === 'true' ? 'desktop-menu-link--is-active-trail' : ''].join(
-        ' '
-      );
-
-      menuLinkItems.push(
-        <li>
-          <button
-            type="button"
-            class={classAttributes}
-            link-id={id}
-            onMouseOver={() => this.handleDesktopMenuToggle(id)}
-            onFocus={() => this.handleDesktopMenuToggle(id)}
-            aria-expanded="false"
-          >
-            {label}
-            <span class="desktop-menu-link__heading__icon">
-              <hy-icon icon={'hy-icon-caret-down'} size={16} />
-            </span>
-          </button>
-          <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>
+    links.map(
+      ({
+        menuLinkId: id,
+        shortcuts,
+        items,
+        url,
+        description,
+        label,
+        labelExtra,
+        isActive,
+        shortcutsTitle,
+        closeButtonTitle,
+      }) => {
+        let classAttributes = [
+          'desktop-menu-link',
+          isActive === 'true' ? 'desktop-menu-link--is-active-trail' : '',
+        ].join(' ');
+
+        menuLinkItems.push(
+          <li>
             <button
-              onClick={() => this.handleDesktopMenuClose()}
-              class={{
-                'hy-desktop-menu-panel__panel-toggle': true,
-              }}
-              aria-label="Close menu"
+              type="button"
+              class={classAttributes}
+              link-id={id}
+              onClick={() => this.handleDesktopMenuClick(id)}
+              onMouseOver={() => this.handleDesktopMenuToggle(id)}
+              onFocus={() => this.handleDesktopMenuToggle(id)}
+              aria-expanded="false"
             >
-              <span class="hy-desktop-menu-panel__panel-toggle__label">
-                <span class="hy-desktop-menu-panel__panel-toggle__label__title">CLOSE</span>
-                <hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.black} />
+              {label}
+              <span class="desktop-menu-link__heading__icon">
+                <hy-icon icon={'hy-icon-caret-down'} size={32} />
               </span>
             </button>
-          </div>
-        </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>
+                    {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;
   }
-- 
GitLab