UNPKG

@progressive-development/pd-page

Version:

Progressive development page helper, teaser, menu, footer.

470 lines (431 loc) 13.5 kB
import { LitElement, css, html } from 'lit'; import { property, state } from 'lit/decorators.js'; import { msg } from '@lit/localize'; import { installMediaQueryWatcher } from 'pwa-helpers/media-query.js'; import { pdIcons } from '@progressive-development/pd-icon'; import '@progressive-development/pd-icon/pd-icon'; var __defProp = Object.defineProperty; var __decorateClass = (decorators, target, key, kind) => { var result = void 0 ; for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (decorator(target, key, result) ) || result; if (result) __defProp(target, key, result); return result; }; const _PdMenu = class _PdMenu extends LitElement { constructor() { super(...arguments); this.activeRoute = ""; this.selectedLocale = ""; this.locales = []; this.menuItems = []; this.topMenuItems = []; this.noBurgerMenu = false; this.headerSize = 0; this._activeSecIndex = 0; this._activeBurgerMenu = false; this._activeLocaleMenu = false; this._smallScreen = false; } static { this.styles = [ css` :host { display: block; position: relative; height: var(--pd-menu-height, 100px); background-color: var(--pd-menu-bg-col, var(--pd-default-col)); box-shadow: var(--pd-menu-shadow, 3px 3px 5px grey); /* Add into component, before styled from outside by using element removed fixed again => not fit for the teaser, custom properties possible, but now handle this in SPAHelper header element width: 100%; position: fixed; top: 0; */ } .menu-container { height: 100%; padding-left: 10px; padding-right: 10px; display: flex; justify-content: space-between; align-items: center; white-space: nowrap; max-width: var(--pd-menu-wax-width, 1170px); margin: 0 auto; } .menu-ul { display: flex; align-items: center; list-style: none; margin: 0; padding: 0; } .burger-ul { visibility: hidden; overflow: hidden; z-index: -1; position: absolute; flex-direction: column; top: calc(var(--pd-menu-height, 100px) * -1); right: 0px; background-color: var( --pd-menu-burger-bg-col, var(--pd-default-light-col) ); box-shadow: var(--pd-menu-shadow, 3px 3px 5px grey); border-bottom: var(--pd-menu-burger-bottomborder); padding: var(--pd-menu-burger-padding, 0); width: 100%; -moz-border-radius: var(--pd-border-radius); border-radius: var(--pd-border-radius); transition: 0.5s; transition-timing-function: ease-out; transform: translateY(0); opacity: 0; } .locale-ul { visibility: hidden; position: absolute; flex-direction: column; top: 10px; right: 15px; z-index: 100; background-color: var( --pd-menu-burger-bg-col, var(--pd-default-light-col) ); box-shadow: var(--pd-menu-shadow, 3px 3px 5px grey); border-bottom: var(--pd-menu-burger-bottomborder); padding: var(--pd-menu-burger-padding, 0); -moz-border-radius: var(--pd-border-radius); border-radius: var(--pd-border-radius); transition: 0.5s; transition-timing-function: ease-out; transform: translateY(0); opacity: 0; } :host([_activeBurgerMenu]) .burger-ul { visibility: visible; opacity: 1; top: var(--pd-menu-burger-top, var(--pd-menu-height, 100px)); transition-timing-function: ease-in; } :host([_activeLocaleMenu]) .locale-ul { visibility: visible; opacity: 1; top: 40px; transition-timing-function: ease-in; } .menu-li { display: flex; align-items: center; cursor: pointer; border-radius: var(--pd-border-radius); } .burger-li { border-radius: var(--pd-border-radius); align-self: justify; width: 80%; font-size: 90% !important; height: 1rem; } .locale-li { position: relative; } .burger-li:hover { background-color: var(--pd-default-dark-col); } .item { color: var(--pd-menu-font-col, var(--pd-default-bg-col)); font-family: var( --pd-menu-font-family, var(--pd-default-font-title-family) ); font-size: var(--pd-menu-font-size, 1.2em); font-weight: var(--pd-menu-font-weight, bold); padding: var(--pd-menu-item-padding, 0.6em); } .burger-item { color: var(--pd-menu-burger-font-col, var(--pd-default-dark-col)); } .locale-item { padding-left: 1.5em; } .item.active, .item:hover { color: var(--pd-default-hover-col); } .item:hover { background-color: var(--pd-menu-item-bg-hover-col); } .item:hover .topItemLogo { --pd-icon-stroke-col: var(--pd-default-hover-col); } .topMenu { width: 100%; justify-content: end; padding-left: 10px; } .topItemLogo { --pd-icon-size: 1.4rem; --pd-icon-bg-col: transparent; --pd-icon-col: var(--pd-menu-font-col, var(--pd-default-bg-col)); pointer-events: none; } .burgerLogo { --pd-icon-size: 2rem; --pd-icon-bg-col: transparent; pointer-events: none; } .menu-wrapper { width: 100%; display: flex; align-items: center; justify-content: end; padding-right: 0.5rem; } .burger-menu { display: flex; gap: 0.3rem; align-items: center; cursor: pointer; --pd-icon-col: var(--pd-default-hover-col); --pd-icon-col-active: lightgrey; } .burger-menu:hover { --pd-icon-col: var(--pd-default-hover-col); --pd-icon-col-active: var(--pd-default-hover-col); } .burger-menu .item { padding: 0; font-size: 1.5em; transition: color ease 0.5s; } .burger-menu:hover .item { color: var(--pd-default-hover-col); } /* Doppelt zum logo-container, pd-logo sonst nicht mehr funktional */ ::slotted(.logo) { width: 100%; max-width: var(--pd-menu-logo-maxwidth, 8rem); padding: var(--pd-menu-logo-padding, 2em); width: 100%; fill: var(--pd-menu-logo-color, #067394); cursor: pointer; } .locale-selection-logo { --pd-icon-size: 0.8rem; --pd-icon-bg-col: transparent; --pd-icon-col: var(--pd-default-hover-col); --pd-icon-col-active: var(--pd-menu-font-col, var(--pd-default-bg-col)); margin-top: 2px; pointer-events: none; } ` ]; } firstUpdated() { const updateActiveSection = (scrollPos) => { let activeIndex = -1; let closestDistance = scrollPos > 300 ? 5e3 : 300; this.menuItems.forEach((item, index) => { if (item.ref) { const dist = Math.abs(item.ref.getBoundingClientRect().top); if (dist < closestDistance) { activeIndex = index; closestDistance = dist; } } }); this._activeSecIndex = activeIndex >= 0 ? activeIndex + 1 : 0; }; let ticking = false; document.addEventListener("scroll", () => { const scrollY = window.scrollY; if (!ticking) { window.requestAnimationFrame(() => { updateActiveSection(scrollY); ticking = false; }); ticking = true; } }); installMediaQueryWatcher(`(max-width: 700px)`, (matches) => { this._smallScreen = matches && !this.noBurgerMenu; }); } render() { return html` <div class="menu-container"> <slot name="slotLogo" @click="${this._logoClicked}"></slot> <ul class="menu-ul ${this._smallScreen ? "burger-ul" : ""}"> ${this._renderItems( this._smallScreen ? [...this.menuItems, ...this.topMenuItems] : this.menuItems, true, this._smallScreen )} </ul> ${!this._smallScreen ? html` <ul class="menu-ul topMenu"> ${this._renderItems(this.topMenuItems, false)} ${this.locales.length > 1 ? html` <li class="item menu-li locale-li" @click="${this._toggleLocaleSelection}" > ${this.selectedLocale} <pd-icon class="locale-selection-logo" icon="${pdIcons.ICON_TOOGLE_ARROW}" ?activeIcon="${!this._activeLocaleMenu}" ></pd-icon> <ul class="menu-ul locale-ul"> ${this.locales.filter((l) => l !== this.selectedLocale).map( (locale) => html` <li class="item menu-li burger-li burger-item locale-item" data-key="${locale}" @click="${this._localeClicked}" > ${locale} </li> ` )} </ul> </li> ` : ""} </ul> ` : html` <div class="menu-wrapper"> <div class="burger-menu" @click="${this._toggleBurgerMenu}"> <pd-icon class="burgerLogo" icon="${pdIcons.ICON_BURGER_MENU}" ?activeIcon="${!this._activeBurgerMenu}" ></pd-icon> <span class="item ${this._activeBurgerMenu ? "active" : ""}" >${msg("Menü", { id: "pd.menu.label" })}</span > </div> </div> `} </div> `; } _renderItems(items, highlight, disableIcons = false) { return html` ${items.map( (item, index) => html` <li class="item menu-li ${this._smallScreen ? "burger-li burger-item" : ""} ${highlight && (this._activeSecIndex === index + 1 || item.route === this.activeRoute) ? "active" : ""}" data-key="${item.key}" @click="${this._menuItemClicked}" > ${item.icon && !disableIcons ? html`<pd-icon class="topItemLogo" icon="${item.icon}" ></pd-icon>` : ""} ${item.name} </li> ` )} `; } _toggleBurgerMenu() { this._activeBurgerMenu = !this._activeBurgerMenu; } _toggleLocaleSelection() { this._activeLocaleMenu = !this._activeLocaleMenu; } _localeClicked(e) { const locale = e.target.dataset.key; this.dispatchEvent(new CustomEvent("locale-change", { detail: locale })); } _menuItemClicked(e) { const key = e.target.dataset.key; const item = [...this.menuItems, ...this.topMenuItems].find( (i) => i.key === key ); if (!item) return; if (item.sec && item.ref) { const rect = item.ref.getBoundingClientRect(); window.scrollBy({ top: rect.top - this.headerSize, behavior: "smooth" }); } else if (item.route) { this.dispatchEvent( new CustomEvent("route-event", { detail: { route: item.route === "back" ? "" : item.route }, bubbles: true, composed: true }) ); } else if (item.action) { item.action(); } if (this._activeBurgerMenu) { this._activeBurgerMenu = false; } } _logoClicked() { _PdMenu._scrollToTop(); if (this.logoRoute) { this.dispatchEvent( new CustomEvent("route-event", { detail: { route: this.logoRoute }, bubbles: true, composed: true }) ); } } static _scrollToTop() { window.scrollTo({ top: 0, behavior: "smooth" }); } }; __decorateClass([ property({ type: String }) ], _PdMenu.prototype, "activeRoute"); __decorateClass([ property({ type: String }) ], _PdMenu.prototype, "selectedLocale"); __decorateClass([ property({ type: String }) ], _PdMenu.prototype, "logoRoute"); __decorateClass([ property({ type: Array }) ], _PdMenu.prototype, "locales"); __decorateClass([ property({ type: Array }) ], _PdMenu.prototype, "menuItems"); __decorateClass([ property({ type: Array }) ], _PdMenu.prototype, "topMenuItems"); __decorateClass([ property({ type: Boolean }) ], _PdMenu.prototype, "noBurgerMenu"); __decorateClass([ property({ type: Number }) ], _PdMenu.prototype, "headerSize"); __decorateClass([ state() ], _PdMenu.prototype, "_activeSecIndex"); __decorateClass([ state() ], _PdMenu.prototype, "_activeBurgerMenu"); __decorateClass([ state() ], _PdMenu.prototype, "_activeLocaleMenu"); __decorateClass([ state() ], _PdMenu.prototype, "_smallScreen"); let PdMenu = _PdMenu; export { PdMenu };