/** * @license * Copyright 2025-2026 Open Home Foundation * SPDX-License-Identifier: Apache-2.0 */ import "@material/web/button/outlined-button"; import "@material/web/divider/divider"; import "@material/web/iconbutton/icon-button"; import "@material/web/list/list"; import "@material/web/list/list-item"; import { consume } from "@lit/context"; import { MatterClient } from "@matter-server/ws-client"; import { mdiArrowLeft, mdiBrightnessAuto, mdiCog, mdiHome, mdiLogout, mdiWeatherNight, mdiWeatherSunny } from "@mdi/js"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { clientContext, tickContext } from "../../client/client-context.js"; import { showSettingsDialog } from "../../components/dialogs/settings/show-settings-dialog.js"; import "../../components/ha-svg-icon"; import { DevModeService } from "../../util/dev-mode-service.js"; import { reducedMotionStyles } from "../../util/shared-styles.js"; import { EffectiveTheme, ThemePreference, ThemeService } from "../../util/theme-service.js"; interface HeaderAction { label: string; icon: string; action: void; } export type ActiveView = "nodes" | "thread" | "wifi"; @customElement("dashboard-header") export class DashboardHeader extends LitElement { @property() public backButton?: string; @property() public actions?: HeaderAction[]; @property() public activeView?: ActiveView; @property({ type: Boolean }) public hasThreadDevices?: boolean; @property({ type: Boolean }) public hasWifiDevices?: boolean; @consume({ context: clientContext }) public client?: MatterClient; @consume({ context: tickContext, subscribe: true }) protected _tick = 0; @state() private _themePreference: ThemePreference = ThemeService.preference; @state() private _effectiveTheme: EffectiveTheme = ThemeService.effectiveTheme; @state() private _devMode = DevModeService.active; private _unsubscribeTheme?: () => void; private _unsubscribeDevMode?: () => void; override connectedCallback() { super.connectedCallback(); this._unsubscribeTheme = ThemeService.subscribe(theme => { this._effectiveTheme = theme; this._themePreference = ThemeService.preference; }); this._unsubscribeDevMode = DevModeService.subscribe(active => { this._devMode = active; }); } override disconnectedCallback() { super.disconnectedCallback(); this._unsubscribeTheme?.(); this._unsubscribeDevMode?.(); } private _goBack() { if (this.backButton) { location.hash = this.backButton; } } private _goHome() { location.hash = "#"; } private _cycleTheme() { ThemeService.cycleTheme(); } private _openSettings() { showSettingsDialog(); } private _getThemeIcon(): string { switch (this._themePreference) { case "light": return mdiWeatherSunny; case "dark": return mdiWeatherNight; case "system": return mdiBrightnessAuto; } } private _getThemeTooltip(): string { switch (this._themePreference) { case "light": return "Theme: Light"; case "dark": return "Theme: Dark"; case "system": return `Theme: System (${this._effectiveTheme})`; } } private _renderNavTabs() { if (this.activeView === undefined) { return nothing; } // Only show tabs if at least one network type has devices const showThreadTab = this.hasThreadDevices === true; const showWifiTab = this.hasWifiDevices === true; // Don't show nav tabs if no network devices exist if (!showThreadTab && !showWifiTab) { return nothing; } return html` `; } protected override render() { return html`