From 82fb6229042ee85217b91718f9db8b0e913701a5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Jan 2020 00:34:08 -0800 Subject: [PATCH] Add buttons header-footer (#4601) * Add buttons header-footer * Simplify * Update src/panels/lovelace/header-footer/hui-buttons-header-footer.ts Co-Authored-By: Ian Richardson * Address comments Co-authored-by: Ian Richardson --- src/components/entity/state-badge.ts | 2 +- .../lovelace/cards/hui-entities-card.ts | 14 ++- src/panels/lovelace/common/compute-tooltip.ts | 7 +- .../create-header-footer-element.ts | 3 +- .../hui-entities-card-editor.ts | 6 +- .../hui-buttons-header-footer.ts | 102 ++++++++++++++++++ src/panels/lovelace/header-footer/types.ts | 16 ++- 7 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 src/panels/lovelace/header-footer/hui-buttons-header-footer.ts diff --git a/src/components/entity/state-badge.ts b/src/components/entity/state-badge.ts index d000865d5d..b01ea63f34 100644 --- a/src/components/entity/state-badge.ts +++ b/src/components/entity/state-badge.ts @@ -20,7 +20,7 @@ import { computeActiveState } from "../../common/entity/compute_active_state"; import { ifDefined } from "lit-html/directives/if-defined"; import { iconColorCSS } from "../../common/style/icon_color_css"; -class StateBadge extends LitElement { +export class StateBadge extends LitElement { public hass?: HomeAssistant; @property() public stateObj?: HassEntity; @property() public overrideIcon?: string; diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index b892899ba8..c43a70442e 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -14,7 +14,11 @@ import "../components/hui-entities-toggle"; import { HomeAssistant } from "../../../types"; import { LovelaceRow } from "../entity-rows/types"; -import { LovelaceCard, LovelaceCardEditor } from "../types"; +import { + LovelaceCard, + LovelaceCardEditor, + LovelaceHeaderFooter, +} from "../types"; import { processConfigEntities } from "../common/process-config-entities"; import { createRowElement } from "../create-element/create-row-element"; import { EntitiesCardConfig, EntitiesCardEntityConfig } from "./types"; @@ -48,6 +52,11 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { (element as LovelaceRow).hass = hass; } ); + this.shadowRoot!.querySelectorAll(".header-footer > *").forEach( + (element: unknown) => { + (element as LovelaceHeaderFooter).hass = hass; + } + ); const entitiesToggle = this.shadowRoot!.querySelector( "hui-entities-toggle" ); @@ -135,6 +144,7 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { this.renderEntity(entityConf) )} + ${this._config.footer ? this.renderHeaderFooter(this._config.footer, "footer") : ""} @@ -192,7 +202,7 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { element.hass = this._hass; } return html` -
${element}
+ `; } diff --git a/src/panels/lovelace/common/compute-tooltip.ts b/src/panels/lovelace/common/compute-tooltip.ts index 0b972a7e8e..b5d7ed9955 100644 --- a/src/panels/lovelace/common/compute-tooltip.ts +++ b/src/panels/lovelace/common/compute-tooltip.ts @@ -1,9 +1,8 @@ import { computeStateName } from "../../../common/entity/compute_state_name"; import { HomeAssistant } from "../../../types"; -import { LovelaceElementConfig } from "../elements/types"; import { ActionConfig } from "../../../data/lovelace"; -interface Config extends LovelaceElementConfig { +interface Config { entity?: string; title?: string; tap_action?: ActionConfig; @@ -30,6 +29,10 @@ export const computeTooltip = (hass: HomeAssistant, config: Config): string => { : config.entity; } + if (!config.tap_action && !config.hold_action) { + return stateName; + } + const tapTooltip = config.tap_action ? computeActionTooltip(hass, stateName, config.tap_action, false) : ""; diff --git a/src/panels/lovelace/create-element/create-header-footer-element.ts b/src/panels/lovelace/create-element/create-header-footer-element.ts index 76ad7f3b2c..28d74d148b 100644 --- a/src/panels/lovelace/create-element/create-header-footer-element.ts +++ b/src/panels/lovelace/create-element/create-header-footer-element.ts @@ -1,8 +1,9 @@ import "../header-footer/hui-picture-header-footer"; +import "../header-footer/hui-buttons-header-footer"; import { LovelaceHeaderFooterConfig } from "../header-footer/types"; import { createLovelaceElement } from "./create-element-base"; -const SPECIAL_TYPES = new Set(["picture"]); +const SPECIAL_TYPES = new Set(["picture", "buttons"]); export const createHeaderFooterElement = (config: LovelaceHeaderFooterConfig) => createLovelaceElement("header-footer", config, SPECIAL_TYPES); diff --git a/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts index 4f34d5ff98..3f5953d7e8 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts @@ -31,7 +31,7 @@ import { EntitiesCardConfig, EntitiesCardEntityConfig, } from "../../cards/types"; -import { pictureHeaderFooterConfigStruct } from "../../header-footer/types"; +import { headerFooterConfigStructs } from "../../header-footer/types"; const cardConfigStruct = struct({ type: "string", @@ -39,8 +39,8 @@ const cardConfigStruct = struct({ theme: "string?", show_header_toggle: "boolean?", entities: [entitiesConfigStruct], - header: struct.optional(pictureHeaderFooterConfigStruct), - footer: struct.optional(pictureHeaderFooterConfigStruct), + header: struct.optional(headerFooterConfigStructs), + footer: struct.optional(headerFooterConfigStructs), }); @customElement("hui-entities-card-editor") diff --git a/src/panels/lovelace/header-footer/hui-buttons-header-footer.ts b/src/panels/lovelace/header-footer/hui-buttons-header-footer.ts new file mode 100644 index 0000000000..35e3b6eefd --- /dev/null +++ b/src/panels/lovelace/header-footer/hui-buttons-header-footer.ts @@ -0,0 +1,102 @@ +import { + html, + LitElement, + TemplateResult, + customElement, + css, + CSSResult, + queryAll, +} from "lit-element"; +import "@material/mwc-ripple"; + +import "../../../components/entity/state-badge"; +import "../../../components/ha-card"; +import "../../../components/ha-icon"; +import "../components/hui-warning-element"; + +import { HomeAssistant } from "../../../types"; +import { LovelaceHeaderFooter } from "../types"; +import { ButtonsHeaderFooterConfig } from "./types"; +import { EntityConfig } from "../entity-rows/types"; +import { processConfigEntities } from "../common/process-config-entities"; +import { toggleEntity } from "../common/entity/toggle-entity"; +import { computeTooltip } from "../common/compute-tooltip"; +// tslint:disable-next-line: no-duplicate-imports +import { StateBadge } from "../../../components/entity/state-badge"; + +@customElement("hui-buttons-header-footer") +export class HuiButtonsHeaderFooter extends LitElement + implements LovelaceHeaderFooter { + public static getStubConfig(): object { + return { entities: [] }; + } + + private _configEntities?: EntityConfig[]; + private _hass?: HomeAssistant; + @queryAll("state-badge") private _badges!: StateBadge[]; + + public setConfig(config: ButtonsHeaderFooterConfig): void { + this._configEntities = processConfigEntities(config.entities); + this.requestUpdate(); + } + + set hass(hass: HomeAssistant) { + this._hass = hass; + this._badges.forEach((badge, index: number) => { + badge.hass = hass; + badge.stateObj = hass.states[this._configEntities![index].entity]; + }); + } + + protected render(): TemplateResult | void { + return html` + ${(this._configEntities || []).map((entityConf) => { + const stateObj = this._hass!.states[entityConf.entity]; + if (!stateObj) { + return html`
`; + } + + return html` +
+ + +
+ `; + })} + `; + } + + private async _toggle(ev) { + await toggleEntity(this._hass!, ev.target.stateObj.entity_id); + } + + static get styles(): CSSResult { + return css` + :host { + display: flex; + justify-content: space-evenly; + } + .missing { + color: #fce588; + } + state-badge { + cursor: pointer; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-buttons-header-footer": HuiButtonsHeaderFooter; + } +} diff --git a/src/panels/lovelace/header-footer/types.ts b/src/panels/lovelace/header-footer/types.ts index 03a3a18f36..65c4ba6c7f 100644 --- a/src/panels/lovelace/header-footer/types.ts +++ b/src/panels/lovelace/header-footer/types.ts @@ -1,11 +1,15 @@ import { ActionConfig } from "../../../data/lovelace"; import { struct } from "../common/structs/struct"; -import { actionConfigStruct } from "../editor/types"; +import { actionConfigStruct, entitiesConfigStruct } from "../editor/types"; export interface LovelaceHeaderFooterConfig { type: string; } +export interface ButtonsHeaderFooterConfig extends LovelaceHeaderFooterConfig { + entities: string[]; +} + export interface PictureHeaderFooterConfig extends LovelaceHeaderFooterConfig { image: string; tap_action?: ActionConfig; @@ -20,3 +24,13 @@ export const pictureHeaderFooterConfigStruct = struct({ hold_action: struct.optional(actionConfigStruct), double_tap_action: struct.optional(actionConfigStruct), }); + +export const buttonsHeaderFooterConfigStruct = struct({ + type: "string", + entities: [entitiesConfigStruct], +}); + +export const headerFooterConfigStructs = struct.union([ + pictureHeaderFooterConfigStruct, + buttonsHeaderFooterConfigStruct, +]);