import {LitElement, html, css, unsafeCSS} from 'lit'; import { customElement, property, 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{ justify-content: space-between; align-items: start; padding-top: var(--iu-spacing-2); padding-bottom: calc(var(--iu-spacing-2) + (var(--iu-logo-height) - 47px)); background: var(--theme-color-white); grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: 0; } @media ${unsafeCSS(breakpoints.xl)} { :host iu-container{ display: grid; height: 3.75rem; } } .logo{ font-weight: 700; grid-column: span 1; } .nav{ grid-column: 2 / 5; display: none; justify-content: space-between; align-items: center; } @media ${unsafeCSS(breakpoints.xl)} { .nav{ display: flex; } } .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; } .mobile-actions{ grid-column: 4 / 4; display: flex; align-items: center; justify-content: flex-end; & a{ margin-right: var(--iu-spacing-0); } } @media ${unsafeCSS(breakpoints.xl)} { .mobile-actions{ display: none; } } .hamburger{ transform: translateX(var(--iu-grid-gutter)); background: transparent; border: 0; cursor: pointer; width: 50px; height: 50px; padding: 0; svg{ width: 100%; height: 100%; } } `; @property({ type: Boolean }) mobileMenuOpen = false; @property({type: Boolean}) i18n = false; // 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 } 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') } } ); }); } // Mobile menu private toggleMobileMenu(){ // Show overlay const overlay = document.querySelector('iu-overlay') as Overlay; overlay.visible = !overlay.visible; // Change internal var this.mobileMenuOpen = !this.mobileMenuOpen; if (this.mobileMenuOpen) { // Get scrolled height document.body.dataset.scrollY = window.scrollY.toString(); // Lock body document.body.style.top = `-${window.scrollY}px`; document.body.style.position = 'fixed'; } else { // Remove and restore previous scroll position document.body.style.top = ''; document.body.style.position = ''; // Restore scroll position window.scrollTo(0, Number(document.body.dataset.scrollY || '0')); } // Dispatch event this.dispatchEvent(new CustomEvent('toggle-mobile-menu', { bubbles: true, composed: true })); } // Toggle mobile menu off is xl breakpoint private handleResize = () => { if (window.innerWidth < 1280) { this.closeAllSubmenu(); this.requestUpdate(); } if (window.innerWidth > 1280 && this.mobileMenuOpen) { this.mobileMenuOpen = false; this.dispatchEvent(new CustomEvent('toggle-mobile-menu', { detail: false, bubbles: true, composed: true })); // Reset body document.body.style.top = ''; document.body.style.position = ''; // Ensure the overlay is also hidden const overlay = document.querySelector('iu-overlay') as Overlay; if (overlay) overlay.visible = false; this.requestUpdate(); } } override connectedCallback() { super.connectedCallback(); this.addEventListener('iu-header-toggle-submenu', this.handleSubmenuToggle as EventListener); // Update the button visibility on initial load this.updateActionsVisibility(); this.addEventListener('close-mobile-menu', () => { this.mobileMenuOpen = false; this.requestUpdate(); }); // Manage resizing window window.addEventListener('resize', this.handleResize); } override disconnectedCallback() { this.removeEventListener('iu-header-toggle-submenu', this.handleSubmenuToggle as EventListener); // Remove event listener when component is disconnected window.removeEventListener('resize', this.handleResize); super.disconnectedCallback(); } override render() { return html` <iu-container> <div class="logo"> <a href="/" class="logo"> <svg width="162" height="47" viewBox="0 0 162 47" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M13.4636 0.357056H15.7904V11.5014C15.7904 15.0233 14.9408 18.3424 8.8776 18.3424C2.81446 18.3424 1.96484 14.9557 1.96484 11.2892V0.357056H4.36886V11.7137C4.36886 15.8531 7.00459 16.4127 8.88725 16.4127C10.7699 16.4127 13.4732 15.8531 13.4732 11.926V0.357056H13.4636Z" fill="black"/> <path d="M22.0011 18.053H19.8867V5.77969H22.0011V8.20155C22.0011 7.85419 23.6231 5.49988 25.9788 5.49988C29.6476 5.49988 29.6959 8.6068 29.6959 11.6172V18.053H27.5815V11.1927C27.5815 9.31116 27.3691 7.41034 25.274 7.41034C23.6038 7.41034 22.0011 8.77083 22.0011 10.9322V18.053Z" fill="black"/> <path d="M35.8273 18.0529H33.7129V5.77964H35.8273V18.0529ZM33.7129 0H35.8273V2.74991H33.7129V0Z" fill="black"/> <path d="M42.295 18.053L38.2207 5.77966H40.4413L43.5887 15.7951L46.7361 5.77966H48.8795L44.8149 18.053H42.295Z" fill="black"/> <path d="M52.4817 10.5076H58.9697C58.8732 8.79012 57.9366 7.05334 55.745 7.05334C53.4183 7.05334 52.5493 8.9831 52.4721 10.5076M50.2129 11.9163C50.2129 8.39452 52.279 5.49988 55.745 5.49988C59.3945 5.49988 61.2289 8.65504 61.2965 11.9839H52.4528C52.4528 14.1259 52.9934 16.7118 55.8126 16.7118C58.207 16.7118 58.8249 15.0908 58.8925 14.1066H61.0358C60.891 16.2969 59.1049 18.3425 55.8126 18.3425C52.3562 18.3425 50.2129 15.4478 50.2129 11.926" fill="black"/> <path d="M66.4523 18.053H64.3379V5.77969H66.4523V8.90591C66.4523 8.34628 67.9777 5.49988 70.8258 5.49988V7.90243C68.026 7.90243 66.4523 9.73571 66.4523 11.7813V18.0626V18.053Z" fill="black"/> <path d="M77.6905 16.7118C78.4919 16.7118 80.278 16.3355 80.278 14.8303C80.278 11.6558 72.8439 13.8461 72.8439 9.23397C72.8439 7.16912 74.7458 5.49988 77.1981 5.49988C80.8186 5.49988 81.7648 8.10506 81.9 9.09889H79.718C79.6504 8.29803 79.0808 7.12088 77.1981 7.12088C75.972 7.12088 74.8231 7.7577 74.8231 8.88661C74.8231 11.7813 82.2572 9.65852 82.2572 14.4829C82.2572 16.6443 80.307 18.3328 77.6905 18.3328C73.4328 18.3328 72.5156 15.5153 72.5156 14.2417H74.7072C74.7072 15.1583 75.3444 16.7118 77.6905 16.7118Z" fill="black"/> <path d="M87.4131 18.0529H85.2987V5.77964H87.4131V18.0529ZM85.2891 0H87.4034V2.74991H85.2891V0Z" fill="black"/> <path d="M92.1344 7.61286H90.2324V5.77958H92.1344V1.90076H94.1136V5.77958H96.4404V7.61286H94.1136V15.3898C94.1136 15.9784 94.4419 16.374 95.2432 16.374C95.977 16.374 96.5176 16.2292 96.5176 16.2292V18.1301C96.5176 18.1301 96.0252 18.3134 94.8474 18.3134C91.9027 18.3134 92.1441 15.9205 92.1441 15.303V7.59356L92.1344 7.61286Z" fill="black"/> <path d="M103.352 3.66651L101.305 0.0675049H103.748L104.897 3.66651H103.342H103.352ZM106.316 13.3539V12.0127C104.385 12.0803 100.745 12.4083 100.745 14.7626C100.745 16.2679 101.856 16.6442 102.937 16.6442C104.704 16.6442 106.326 14.9749 106.326 13.3539M106.471 15.4188C106.471 16.2872 104.655 18.3327 102.049 18.3327C99.7413 18.3327 98.6406 16.6442 98.6406 14.7626C98.6406 10.7873 104.404 10.8645 106.335 10.7391V9.51369C106.384 7.68042 104.945 7.11114 103.748 7.11114C102.01 7.11114 101.112 8.14356 101.112 9.58124H98.7854C98.7854 7.96024 99.8475 5.49014 103.748 5.49014C106.403 5.49014 108.45 6.80238 108.45 9.51369V15.1775C108.45 16.1907 109.058 16.3065 109.415 16.3065C110.004 16.3065 110.265 16.2582 110.265 16.2582V18.159C110.265 18.159 110.052 18.3231 108.952 18.3231C106.857 18.3231 106.48 16.4898 106.48 15.4091" fill="black"/> <path d="M121.107 0.357056H118.992V18.0626H121.107V0.357056Z" fill="black"/> <path d="M133.107 5.77955H135.222V18.0528H133.107V15.9108C133.107 16.2678 131.621 18.3327 129.41 18.3327C125.837 18.3327 125.625 15.438 125.625 12.2153V5.77955H127.739V12.4276C127.739 14.7047 127.884 16.3546 129.834 16.3546C131.505 16.3546 133.107 15.0617 133.107 12.5434V5.7699V5.77955Z" fill="black"/> <path d="M146.093 13.354V12.0128C144.163 12.0804 140.523 12.4084 140.523 14.7627C140.523 16.268 141.633 16.6443 142.714 16.6443C144.481 16.6443 146.103 14.975 146.103 13.354M146.248 15.4189C146.248 16.2873 144.433 18.3328 141.826 18.3328C139.519 18.3328 138.418 16.6443 138.418 14.7627C138.418 10.7874 144.182 10.8646 146.113 10.7392V9.51379C146.161 7.68052 144.722 7.11124 143.525 7.11124C141.787 7.11124 140.89 8.14366 140.89 9.58133H138.563C138.563 7.96033 139.625 5.49023 143.525 5.49023C146.18 5.49023 148.227 6.80247 148.227 9.51379V15.1776C148.227 16.1908 148.835 16.3066 149.193 16.3066C149.782 16.3066 150.042 16.2583 150.042 16.2583V18.1591C150.042 18.1591 149.83 18.3232 148.729 18.3232C146.634 18.3232 146.258 16.4899 146.258 15.4092" fill="black"/> <path d="M154.514 18.053L150.449 5.77966H152.66L155.808 15.7951L158.965 5.77966H161.098L157.034 18.053H154.514Z" fill="black"/> <path d="M9.45194 40.0812C9.45194 37.1383 8.25476 35.3533 5.57075 35.334C3.12812 35.3147 2.32678 37.9391 2.32678 39.8496C2.32678 41.7601 2.93502 44.8573 5.57075 44.8573C8.20648 44.8573 9.45194 43.0723 9.45194 40.0812ZM5.57075 46.5459C1.75715 46.5459 0 43.1591 0 39.8496C0 36.5401 1.95024 33.713 5.57075 33.713C8.38992 33.713 9.30712 35.8743 9.30712 35.8743V28.2131H11.4215V46.2661H9.30712V44.0565C9.30712 44.2688 8.27407 46.5459 5.57075 46.5459Z" fill="black"/> <path d="M18.1202 46.2661H16.0059V33.9928H18.1202V46.2661ZM16.0059 28.2131H18.1202V30.963H16.0059V28.2131Z" fill="black"/> <path d="M26.6562 28.5605H29.012L34.6793 42.8987L39.9701 28.5605H42.2486L35.471 46.2661H33.7138L26.6562 28.5605Z" fill="black"/> <path d="M44.3626 38.7111H50.8506C50.754 36.9936 49.8175 35.2568 47.6259 35.2568C45.2991 35.2568 44.4302 37.1866 44.3529 38.7111M42.0938 40.1198C42.0938 36.598 44.1599 33.7034 47.6259 33.7034C51.2754 33.7034 53.1098 36.8585 53.1773 40.1874H44.3336C44.3336 42.3294 44.8743 44.9153 47.7031 44.9153C50.0975 44.9153 50.7154 43.2943 50.783 42.3101H52.9263C52.7815 44.5004 50.9954 46.5459 47.7031 46.5459C44.2467 46.5459 42.1034 43.6513 42.1034 40.1295" fill="black"/> <path d="M58.3331 46.2661H56.2188V33.9928H58.3331V36.4147C58.3331 36.0673 59.9551 33.713 62.3109 33.713C65.9796 33.713 66.0279 36.8199 66.0279 39.8304V46.2661H63.9135V39.4058C63.9135 37.5243 63.7011 35.6235 61.6061 35.6235C59.9358 35.6235 58.3331 36.984 58.3331 39.1453V46.2661Z" fill="black"/> <path d="M71.2513 38.7111H77.7392C77.6427 36.9936 76.7062 35.2568 74.5146 35.2568C72.1878 35.2568 71.3189 37.1866 71.2416 38.7111M68.9824 40.1198C68.9824 36.598 71.0485 33.7034 74.5146 33.7034C78.164 33.7034 79.9984 36.8585 80.066 40.1874H71.2223C71.2223 42.3294 71.763 44.9153 74.5821 44.9153C76.9765 44.9153 77.5944 43.2943 77.662 42.3101H79.8053C79.6605 44.5004 77.8744 46.5459 74.5821 46.5459C71.1258 46.5459 68.9824 43.6513 68.9824 40.1295" fill="black"/> <path d="M82.4023 46.266V44.3555L88.3979 35.826H82.6147V33.9927H90.773V35.8935L84.7774 44.423H91.1302V46.266H82.4023Z" fill="black"/> <path d="M96.5558 46.2661H94.4414V33.9928H96.5558V46.2661ZM94.4414 28.2131H96.5558V30.963H94.4414V28.2131Z" fill="black"/> <path d="M107.425 41.5575V40.2163C105.495 40.2839 101.855 40.6119 101.855 42.9662C101.855 44.4715 102.965 44.8478 104.046 44.8478C105.813 44.8478 107.435 43.1785 107.435 41.5575M107.58 43.6224C107.58 44.4907 105.765 46.5363 103.158 46.5363C100.851 46.5363 99.75 44.8478 99.75 42.9662C99.75 38.9909 105.514 39.0681 107.445 38.9427V37.7173C107.493 35.884 106.055 35.3147 104.857 35.3147C103.119 35.3147 102.222 36.3472 102.222 37.7848H99.8948C99.8948 36.1638 100.957 33.6937 104.857 33.6937C107.512 33.6937 109.559 35.006 109.559 37.7173V43.3811C109.559 44.3943 110.167 44.51 110.525 44.51C111.114 44.51 111.374 44.4618 111.374 44.4618V46.3626C111.374 46.3626 111.162 46.5267 110.061 46.5267C107.966 46.5267 107.59 44.6934 107.59 43.6127" fill="black"/> </svg> </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> <!-- Toggle mobile menu --> <div class="mobile-actions"> ${this.i18n ? html` <a href="">EN</a> ` : ``} <button class="hamburger" @click="${this.toggleMobileMenu}"> ${this.mobileMenuOpen ? html` <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path fill-rule="evenodd" clip-rule="evenodd" d="M23.132 24.546 15 16.414 16.414 15l8.132 8.132L32.678 15l1.414 1.414-8.132 8.132 8.132 8.132-1.414 1.414-8.132-8.132-8.132 8.132L15 32.678l8.132-8.132Z" fill="currentColor"/></svg> ` : html` <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path fill-rule="evenodd" clip-rule="evenodd" d="M13 24h25v2H13v-2Zm0-7h25v2H13v-2Zm0 14h25v2H13v-2Z" fill="currentColor"/></svg> `} </button> </div> </iu-container> `; } } declare global { interface HTMLElementTagNameMap { 'iu-header-navbar': SiteHeaderNavbar; } }