import { html, css, LitElement, PropertyValues, nothing } from 'lit' import { property, state } from 'lit/decorators.js' import { repeat } from 'lit/directives/repeat.js' import { InputData } from './definition-schema' import '@material/web/icon/icon' import '@material/web/tabs/tabs' import '@material/web/tabs/primary-tab' import '@material/web/tabs/secondary-tab' type Theme = { theme_name: string theme_object: any } export class WidgetNavbar extends LitElement { @property({ type: Object }) inputData?: InputData @property({ type: Object }) theme?: Theme @property({ type: String }) route?: string @state() private themeBgColor?: string @state() private themeTitleColor?: string version: string = 'versionplaceholder' update(changedProperties: Map) { if (changedProperties.has('theme')) { this.registerTheme(this.theme) } super.update(changedProperties) } protected firstUpdated(_changedProperties: PropertyValues): void { this.registerTheme(this.theme) } registerTheme(theme?: Theme) { const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim() const cssBgColor = getComputedStyle(this).getPropertyValue('--re-tile-background-color').trim() this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color } handleNavItemClick(route?: string) { // console.log('Navigating to:', item.route) const event = new CustomEvent('nav-submit', { detail: { path: route }, bubbles: true, composed: true }) this.dispatchEvent(event) } normalizeRoute(route?: string) { if (!route) return '/' return route } static styles = css` :host { display: block; font-family: sans-serif; box-sizing: border-box; margin: auto; } .paging:not([active]) { display: none !important; } .wrapper { display: flex; align-items: end; height: 100%; width: 100%; padding: 0 16px; box-sizing: border-box; } md-icon { font-family: 'Material Symbols Outlined'; } .selected { font-weight: bold; background-color: rgba(0, 0, 0, 0.1); } h2 { margin: 0; padding: 0px; font-size: 1.2em; line-height: 2.5; height: 48px; } ` trimRoute(route?: string) { if (!route) return '' return '/' + route.split('/').filter(Boolean).join('/') } resolveRoute(item?: any): string | undefined { let route = String(item?.route ?? '') if (item?.variables) { for (const variable of item.variables) { if (variable.label) { route = route .split(`{{${variable.label}}}`) .join(encodeURIComponent(String(variable.value ?? ''))) } } } if (route.includes('*')) { const currentSegments = (this.route || '').split('/').filter(Boolean) const routeSegments = route.split('/').filter(Boolean) for (let i = 0; i < routeSegments.length; i++) { if (routeSegments[i] === '*') { routeSegments[i] = currentSegments[i] ?? '' } } route = (route.startsWith('/') ? '/' : '') + routeSegments.filter(Boolean).join('/') } return route } matchesRoute(itemRoute?: string) { if (itemRoute === undefined) return false const route = this.trimRoute(decodeURIComponent(this.route || '/')) const subRoute = this.trimRoute(itemRoute) if (itemRoute.startsWith('/')) { return route.startsWith(subRoute) } else { return route.endsWith(subRoute) || route === subRoute } } render() { const fontSize = this.inputData?.style?.fontSize ?? 16 const iconFontSize = (this.inputData?.style?.fontSize ?? 16) * 1.5 const fontColor = this.inputData?.style?.color || this.themeTitleColor || 'black' const bgColor = this.inputData?.style?.backgroundColor || this.themeBgColor || 'white' return html`

this.handleNavItemClick( this.resolveRoute({ route: this.inputData?.route, variables: this.inputData?.variables }) )} > ${this.inputData?.title}

${repeat( this.inputData?.navItems || [], (item) => item.label, (item) => html` this.handleNavItemClick(this.resolveRoute(item))} > ${item.iconName ? html` ${item.iconName} ` : nothing} ${item.label} ` )}
` } } window.customElements.define('widget-navbar-versionplaceholder', WidgetNavbar)