export interface DesktopLinks { label: string; url: string; menuLinkId: string; } export interface DonateLink { url: string; label: string; } export interface ComponentLabels { open: string; close: string; expand?: string; label?: string; } import {Component, Element, h, Listen, Prop, State} from '@stencil/core'; import ResizeObserver from 'resize-observer-polyfill'; import {MenuType, ColorVariant, SiteLogoSize} from '../../utils/utils'; @Component({ tag: 'hy-site-header', styleUrl: 'site-header.scss', shadow: true, }) export class SiteHeader { @Element() el: HTMLElement; @Prop() dataMenuLanguage: string; @Prop() dataMenuDonate: string; @Prop() dataSiteHeaderLabels: string; @Prop() logoUrl?: string; @Prop() logoLabel?: string; @Prop() menuLabelOpen?: string; @Prop() menuLabelClose?: string; @Prop({reflect: true}) menuType: MenuType = MenuType.default; /* First level menu links to be displayed on Desktop screens. * */ @Prop() dataDesktopLinks: DesktopLinks[] | string; @State() isMobile: boolean; @State() isMenuOpen: boolean = false; @State() isDesktopMenuOpen: boolean = false; private ro: ResizeObserver; private donateLink: DonateLink[]; private menuLabels: ComponentLabels[]; private searchLabels: ComponentLabels[]; private languageLabels: ComponentLabels[]; // Listener for toggling mobile menu panel on or off. @Listen('mobileMenuToggle') mobileMenuToggle() { this.isMenuOpen = !this.isMenuOpen; } componentDidLoad() { // Set the browser resize observer to gather information about browser width. this.ro = new ResizeObserver((entries) => { for (const entry of entries) { this.applySizeClasses(entry.contentRect.width); } }); this.ro.observe(document.body); // Pass the dataMenuLanguage prop to menu component. this.el.children[0].setAttribute('data-menu-language', this.dataMenuLanguage); } componentWillLoad() { // Check for site header labels and set them to variables accordingly. if (this.dataSiteHeaderLabels) { const labels = JSON.parse(this.dataSiteHeaderLabels); this.menuLabels = labels.menu_labels; this.languageLabels = labels.language_labels; this.searchLabels = labels.search_labels; } // Check for the donation link information and set it to variables accordingly. // Also pass the donation link data to menu-component. if (this.dataMenuDonate) { this.donateLink = JSON.parse(this.dataMenuDonate); this.el.children[0].setAttribute('data-menu-donate', this.dataMenuDonate); } } componentWillUpdate() { // Pass the necessary information to menu component. These props will be // used in mobile menu. this.el.children[0].setAttribute('open', this.isMenuOpen.toString()); this.el.children[0].setAttribute('logo-label', this.logoLabel); this.el.children[0].setAttribute('logo-url', this.logoUrl); this.el.children[0].setAttribute('menu-button-submenu-expand', this.menuLabels['expand']); this.el.children[0].setAttribute('menu-button-breadcrumb-return', this.menuLabels['return']); this.el.children[0].setAttribute('menu-language-label-open', this.languageLabels['open']); this.el.children[0].setAttribute('menu-language-label-close', this.languageLabels['close']); this.el.children[0].setAttribute('label-front-page', this.menuLabels['front_page']); } componentDidUnload() { this.ro.disconnect(); } applySizeClasses(size: number) { // Set the menu-type based on the width of the browser. if (size <= 1200 && size > 960) { this.menuType = MenuType.tablet; } else if (size <= 960) { this.menuType = MenuType.mobile; } else { this.menuType = MenuType.desktop; } // Pass the menu type to menu component. this.isMobile = this.menuType === (MenuType.mobile || MenuType.tablet); const menuAttribute = this.menuType === MenuType.tablet ? MenuType.mobile : this.menuType; this.el.children[0].setAttribute('menu-type', menuAttribute); } render() { const logoSize = this.isMobile ? SiteLogoSize.small : SiteLogoSize.big; const logoColor = ColorVariant.black; let classAttributes = ['hy-site-header', 'hy-site-header--' + this.menuType]; switch (this.menuType) { case MenuType.desktop: return [ <header class={classAttributes.join(' ')}> <div class={{'hy-backdrop': true, 'is-active': this.isMenuOpen}} /> <div class={'hy-site-header__logo-container'}> <hy-site-logo size={logoSize} color={logoColor} url={this.logoUrl} label={this.logoLabel} /> </div> <hy-desktop-menu-links data-desktop-links={this.dataDesktopLinks}></hy-desktop-menu-links> <div class={'menu--secondary'}> <hy-menu-language class={'menu--secondary__item is-first'} is-mobile={false} data-menu-language={this.dataMenuLanguage} labels={this.languageLabels} /> <hy-site-search class={'menu--secondary__item'} size={14} color={ColorVariant.black} show-label={true} labels={this.searchLabels} /> {this.donateLink.map((i) => { return ( <a class={'menu--secondary__item hy-link__donate'} href={i.url}> <hy-icon icon={'hy-icon-euro'} size={14} fill={ColorVariant.black} /> <span class={'hy-link__donate__label'}>{i.label}</span> </a> ); })} </div> </header>, <hy-desktop-menu-panel> <slot name={'menu'} /> </hy-desktop-menu-panel>, ]; case MenuType.tablet: return ( <header class={classAttributes.join(' ')}> <div class={{'hy-backdrop': true, 'is-active': this.isMenuOpen}} /> <div class={'hy-site-header__logo-container'}> <hy-site-logo size={logoSize} color={logoColor} url={this.logoUrl} label={this.logoLabel} /> </div> <div class={'menu--secondary'}> <hy-menu-language class={'menu--secondary__item is-first'} is-mobile={false} data-menu-language={this.dataMenuLanguage} labels={this.languageLabels} /> <hy-site-search class={'menu--secondary__item'} size={14} color={ColorVariant.black} show-label={true} labels={this.searchLabels} /> {this.donateLink.map((i) => { return ( <a class={'menu--secondary__item hy-link__donate'} href={i.url}> <hy-icon icon={'hy-icon-euro'} size={14} fill={ColorVariant.black} /> <span class={'hy-link__donate__label'}>{i.label}</span> </a> ); })} </div> <div class={'hy-site-header__menu-container'}> <button onClick={() => this.mobileMenuToggle()} class={{ 'hy-site-header__panel-toggle': true, 'is-open': this.isMenuOpen, }} aria-label={this.isMenuOpen ? this.menuLabels['close'] : this.menuLabels['open']} > {this.isMenuOpen ? ( <span class="hy-site-header__panel-toggle__label"> {this.menuLabelClose} <hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.black} /> </span> ) : ( <span class="hy-site-header__panel-toggle__label"> {this.menuLabelOpen} <hy-icon icon={'hy-icon-hamburger'} size={20} fill={ColorVariant.black} /> </span> )} </button> <div class={{ 'is-open': this.isMenuOpen, 'hy-site-header__panel': true, }} > <slot name={'menu'} /> </div> </div> </header> ); case MenuType.mobile: return ( <header class={classAttributes.join(' ')}> <div class={{'hy-backdrop': true, 'is-active': this.isMenuOpen}} /> <div class={'hy-site-header__logo-container'}> <hy-site-logo size={logoSize} color={logoColor} url={this.logoUrl} label={this.logoLabel} /> </div> <div class={'hy-site-header__menu-container'}> <hy-site-search class={'menu--secondary__item'} size={14} color={ColorVariant.black} show-label={true} labels={this.searchLabels} /> <button onClick={() => this.mobileMenuToggle()} class={{ 'hy-site-header__panel-toggle': true, 'is-open': this.isMenuOpen, }} aria-label={this.isMenuOpen ? this.menuLabels['close'] : this.menuLabels['open']} > {this.isMenuOpen ? ( <span class="hy-site-header__panel-toggle__label"> {this.menuLabelClose} <hy-icon icon={'hy-icon-remove'} size={20} fill={ColorVariant.black} /> </span> ) : ( <span class="hy-site-header__panel-toggle__label"> {this.menuLabelOpen} <hy-icon icon={'hy-icon-hamburger'} size={20} fill={ColorVariant.black} /> </span> )} </button> <div class={{ 'is-open': this.isMenuOpen, 'hy-site-header__panel': true, }} > <slot name={'menu'} /> </div> </div> </header> ); } } }