Newer
Older
iuav-ui / src / components / header / header-navbar.ts
import {LitElement, html, css, unsafeCSS} from 'lit';
import { customElement, queryAssignedElements } from 'lit/decorators.js';
import { breakpoints } from '../../breakpoints';

@customElement('iu-header-navbar')

export class SiteHeaderNavbar extends LitElement {
  static override styles = css`
    @media ${unsafeCSS(breakpoints.xxl)} {
      :host{
        display: block;
      }
    }
    :host a{
      color: var(--theme-color-black);
      text-decoration: none;
    }
    :host iu-container{
      align-items: center;
      height: 3.75rem;
      background: var(--theme-color-white);
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
    .logo{
      font-weight: 700;
    }
    .nav{
      grid-column: 2 / 5;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .nav ul{
      margin: 0;
      padding: 0;
      list-style-type: none;
      display: flex;
    }
    :host nav ul ::slotted(*:not(:last-child)){
      margin-right: var(--iu-spacing-4);
    }
    .actions button{
      width: 50px;
      height: 50px;
      background: transparent;
      border: 0;
      padding: 0;
      cursor: pointer;
      display: none;
      margin-right: calc((50px - 16px) / 2 * -1)
    }
    .actions button svg{
      height: 16px;
      width: 16px;
    }
  `;

  // Query all `iu-header-navbar-item` elements
  @queryAssignedElements({ slot: '' })
  navbarItems!: HTMLElement[];
  
  private isAnySubmenuOpen(): boolean {
    return !this.navbarItems.some((item: any) => item.isActive);
  }

  private updateActionsVisibility() {
    const actionsButton = this.shadowRoot?.querySelector('.actions button') as HTMLElement;
    if (actionsButton) {
      if (this.isAnySubmenuOpen()) {
        actionsButton.style.display = 'block'; // Show the button
      } else {
        actionsButton.style.display = 'none'; // Hide the button
      }
    }
  }
  
  private handleSubmenuToggle(event: CustomEvent) {

    const { source } = event.detail;

    this.navbarItems.forEach((item: any) => {
      // Close all other submenus
      if (item !== source) {
        item.isActive = false;
        item.submenuElements.forEach((submenu: HTMLElement) =>
          submenu.classList.remove('is-active')
        );
      }
      // Handle closing animation if same element toggled
      if (event.detail.closing && item === source) {
        item.submenuElements.forEach((submenu: HTMLElement) => {
          submenu.classList.add('is-closing')
          const container = submenu.container;
          const containerHeight = container.scrollHeight;
          container.animate(
            [
                { height: `${containerHeight}px` },
                { height: 0 }
            ],
            {
                duration: 250,
                delay: 250,
                easing: 'ease-out'
            }
          ).onfinish = () => {
            submenu.classList.remove('is-closing'),
            submenu.classList.remove('is-active')
          }
        });
      }
    });

    // Check if any submenu is open and toggle button visibility
    this.updateActionsVisibility();

  }

  private closeAllSubmenu(){

    const actionsButton = this.shadowRoot?.querySelector('.actions button') as HTMLElement;
    if (actionsButton) {
      actionsButton.style.display = 'none'; // Hide the button
    }

    document.body.classList.remove('is-locked');

    this.navbarItems.forEach((item: any) => {
      // Close all submenus
      item.isActive = false;
      item.submenuElements.forEach((submenu: HTMLElement) => {
        // Animate open submenu 
        if (submenu.classList.contains('is-active')){
          const overlay = document.querySelector('iu-overlay') as Overlay;
          overlay.visible = false;
          submenu.classList.add('is-closing');
          const container = submenu.container;
          const containerHeight = container.scrollHeight;
          container.animate(
            [
                { height: `${containerHeight}px` },
                { height: 0 }
            ],
            {
                duration: 250,
                delay: 250,
                easing: 'ease-out'
            }
          ).onfinish = () => {
            submenu.classList.remove('is-closing'),
            submenu.classList.remove('is-active')
          }
        } else {
          submenu.classList.remove('is-active')
        }
      }
      );
    });

  }

  override connectedCallback() {
    super.connectedCallback();
    this.addEventListener('iu-header-toggle-submenu', this.handleSubmenuToggle as EventListener);

    // Update the button visibility on initial load
    this.updateActionsVisibility();

  }

  override disconnectedCallback() {
    this.removeEventListener('iu-header-toggle-submenu', this.handleSubmenuToggle as EventListener);
    super.disconnectedCallback();
  }

  override render() {
    return html`
      <iu-container>
        <div class="logo">
          <a href="#" class="logo">Università Iuav di Venezia</a>
        </div>
        <div class="nav">
          <nav role="navigation">
            <ul>
              <slot></slot>
            </ul>
          </nav>
          <div class="actions">
            <button @click="${this.closeAllSubmenu}" role="button"><svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M18.838 1.161 1.16 18.84M18.838 18.839 1.16 1.16" stroke="#000" stroke-width="2"/></svg></button>
          </div>
        </div>
      </iu-container>
    `;
  }

}

declare global {
  interface HTMLElementTagNameMap {
    'iu-header-navbar': SiteHeaderNavbar;
  }
}