@progressive-development/pd-page
Version:
Progressive development page helper, teaser, menu, footer.
470 lines (431 loc) • 13.5 kB
JavaScript
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% ;
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 };