From d9e522e4d7bf8d801919dfa0df84bda606094cdd Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 20 Jan 2020 09:13:19 -0800 Subject: [PATCH] Add header/footer support to entities card (#4496) * Add header/footer support to entities card Oops debug radius Revert change to hui-picture-card Remove unused import * Use new createElement helper --- .../lovelace/cards/hui-entities-card.ts | 37 +++++++- src/panels/lovelace/cards/types.ts | 3 + .../create-element/create-element-base.ts | 7 +- .../create-header-footer-element.ts | 8 ++ .../hui-entities-card-editor.ts | 3 + .../hui-picture-header-footer.ts | 95 +++++++++++++++++++ src/panels/lovelace/header-footer/types.ts | 22 +++++ src/panels/lovelace/types.ts | 6 ++ 8 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/create-element/create-header-footer-element.ts create mode 100644 src/panels/lovelace/header-footer/hui-picture-header-footer.ts create mode 100644 src/panels/lovelace/header-footer/types.ts diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index 8a7d3d19b5..0ae66a6e5d 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -19,6 +19,8 @@ import { processConfigEntities } from "../common/process-config-entities"; import { createRowElement } from "../create-element/create-row-element"; import { EntitiesCardConfig, EntitiesCardEntityConfig } from "./types"; import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; +import { createHeaderFooterElement } from "../create-element/create-header-footer-element"; +import { LovelaceHeaderFooterConfig } from "../header-footer/types"; @customElement("hui-entities-card") class HuiEntitiesCard extends LitElement implements LovelaceCard { @@ -96,10 +98,13 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { return html` + ${this._config.header + ? this.renderHeaderFooter(this._config.header, "header") + : ""} ${!this._config.title && !this._config.show_header_toggle && !this._config.icon - ? html`` + ? "" : html`
@@ -130,6 +135,9 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { this.renderEntity(entityConf) )}
+ ${this._config.footer + ? this.renderHeaderFooter(this._config.footer, "footer") + : ""} `; } @@ -162,6 +170,33 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { .icon { padding: 0px 18px 0px 8px; } + + .header { + border-top-left-radius: var(--ha-card-border-radius, 2px); + border-top-right-radius: var(--ha-card-border-radius, 2px); + margin-bottom: 16px; + overflow: hidden; + } + + .footer { + border-bottom-left-radius: var(--ha-card-border-radius, 2px); + border-bottom-right-radius: var(--ha-card-border-radius, 2px); + margin-top: -16px; + overflow: hidden; + } + `; + } + + private renderHeaderFooter( + conf: LovelaceHeaderFooterConfig, + className: string + ): TemplateResult { + const element = createHeaderFooterElement(conf); + if (this._hass) { + element.hass = this._hass; + } + return html` +
${element}
`; } diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index 95f84d030e..6587468b6d 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -3,6 +3,7 @@ import { Condition } from "../common/validate-condition"; import { EntityConfig, EntityFilterEntityConfig } from "../entity-rows/types"; import { LovelaceElementConfig } from "../elements/types"; import { HuiImage } from "../components/hui-image"; +import { LovelaceHeaderFooterConfig } from "../header-footer/types"; export interface AlarmPanelCardConfig extends LovelaceCardConfig { entity: string; @@ -40,6 +41,8 @@ export interface EntitiesCardConfig extends LovelaceCardConfig { entities: EntitiesCardEntityConfig[]; theme?: string; icon?: string; + header?: LovelaceHeaderFooterConfig; + footer?: LovelaceHeaderFooterConfig; } export interface EntityButtonCardConfig extends LovelaceCardConfig { diff --git a/src/panels/lovelace/create-element/create-element-base.ts b/src/panels/lovelace/create-element/create-element-base.ts index 797064c8da..0810f41e0b 100644 --- a/src/panels/lovelace/create-element/create-element-base.ts +++ b/src/panels/lovelace/create-element/create-element-base.ts @@ -7,10 +7,11 @@ import { createErrorCardElement, createErrorCardConfig, } from "../cards/hui-error-card"; -import { LovelaceCard, LovelaceBadge } from "../types"; +import { LovelaceCard, LovelaceBadge, LovelaceHeaderFooter } from "../types"; import { fireEvent } from "../../../common/dom/fire_event"; import { LovelaceElementConfig, LovelaceElement } from "../elements/types"; import { EntityRow, EntityRowConfig } from "../entity-rows/types"; +import { LovelaceHeaderFooterConfig } from "../header-footer/types"; const CUSTOM_TYPE_PREFIX = "custom:"; const TIMEOUT = 2000; @@ -20,6 +21,10 @@ interface CreateElementConfigTypes { badge: { config: LovelaceBadgeConfig; element: LovelaceBadge }; element: { config: LovelaceElementConfig; element: LovelaceElement }; row: { config: EntityRowConfig; element: EntityRow }; + "header-footer": { + config: LovelaceHeaderFooterConfig; + element: LovelaceHeaderFooter; + }; } const _createElement = ( diff --git a/src/panels/lovelace/create-element/create-header-footer-element.ts b/src/panels/lovelace/create-element/create-header-footer-element.ts new file mode 100644 index 0000000000..76ad7f3b2c --- /dev/null +++ b/src/panels/lovelace/create-element/create-header-footer-element.ts @@ -0,0 +1,8 @@ +import "../header-footer/hui-picture-header-footer"; +import { LovelaceHeaderFooterConfig } from "../header-footer/types"; +import { createLovelaceElement } from "./create-element-base"; + +const SPECIAL_TYPES = new Set(["picture"]); + +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 2817b58c46..c7cf376030 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,6 +31,7 @@ import { EntitiesCardConfig, EntitiesCardEntityConfig, } from "../../cards/types"; +import { pictureHeaderFooterConfigStruct } from "../../header-footer/types"; const cardConfigStruct = struct({ type: "string", @@ -38,6 +39,8 @@ const cardConfigStruct = struct({ theme: "string?", show_header_toggle: "boolean?", entities: [entitiesConfigStruct], + header: struct.optional(pictureHeaderFooterConfigStruct), + footer: struct.optional(pictureHeaderFooterConfigStruct), }); @customElement("hui-entities-card-editor") diff --git a/src/panels/lovelace/header-footer/hui-picture-header-footer.ts b/src/panels/lovelace/header-footer/hui-picture-header-footer.ts new file mode 100644 index 0000000000..735766ba4e --- /dev/null +++ b/src/panels/lovelace/header-footer/hui-picture-header-footer.ts @@ -0,0 +1,95 @@ +import { + html, + LitElement, + TemplateResult, + customElement, + property, + css, + CSSResult, +} from "lit-element"; + +import "../../../components/ha-card"; + +import { LovelaceHeaderFooter } from "../types"; +import { HomeAssistant } from "../../../types"; +import { classMap } from "lit-html/directives/class-map"; +import { actionHandler } from "../common/directives/action-handler-directive"; +import { hasAction } from "../common/has-action"; +import { ActionHandlerEvent } from "../../../data/lovelace"; +import { handleAction } from "../common/handle-action"; +import { ifDefined } from "lit-html/directives/if-defined"; +import { PictureHeaderFooterConfig } from "./types"; + +@customElement("hui-picture-header-footer") +export class HuiPictureHeaderFooter extends LitElement + implements LovelaceHeaderFooter { + public static getStubConfig(): object { + return { + image: + "https://www.home-assistant.io/images/merchandise/shirt-frontpage.png", + tap_action: { action: "none" }, + hold_action: { action: "none" }, + }; + } + + public hass?: HomeAssistant; + + @property() protected _config?: PictureHeaderFooterConfig; + + public setConfig(config: PictureHeaderFooterConfig): void { + if (!config || !config.image) { + throw new Error("Invalid Configuration: 'image' required"); + } + + this._config = config; + } + + protected render(): TemplateResult | void { + if (!this._config || !this.hass) { + return html``; + } + + const clickable = Boolean( + this._config.tap_action || this._config.hold_action + ); + + return html` + + `; + } + + static get styles(): CSSResult { + return css` + img.clickable { + cursor: pointer; + } + + img { + display: block; + width: 100%; + } + `; + } + + private _handleAction(ev: ActionHandlerEvent) { + handleAction(this, this.hass!, this._config!, ev.detail.action!); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-picture-header-footer": HuiPictureHeaderFooter; + } +} diff --git a/src/panels/lovelace/header-footer/types.ts b/src/panels/lovelace/header-footer/types.ts new file mode 100644 index 0000000000..03a3a18f36 --- /dev/null +++ b/src/panels/lovelace/header-footer/types.ts @@ -0,0 +1,22 @@ +import { ActionConfig } from "../../../data/lovelace"; +import { struct } from "../common/structs/struct"; +import { actionConfigStruct } from "../editor/types"; + +export interface LovelaceHeaderFooterConfig { + type: string; +} + +export interface PictureHeaderFooterConfig extends LovelaceHeaderFooterConfig { + image: string; + tap_action?: ActionConfig; + hold_action?: ActionConfig; + double_tap_action?: ActionConfig; +} + +export const pictureHeaderFooterConfigStruct = struct({ + type: "string", + image: "string", + tap_action: struct.optional(actionConfigStruct), + hold_action: struct.optional(actionConfigStruct), + double_tap_action: struct.optional(actionConfigStruct), +}); diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index e9d8657e88..2e2cbab398 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -4,6 +4,7 @@ import { LovelaceConfig, LovelaceBadgeConfig, } from "../../data/lovelace"; +import { LovelaceHeaderFooterConfig } from "./header-footer/types"; declare global { // tslint:disable-next-line @@ -36,6 +37,11 @@ export interface LovelaceCard extends HTMLElement { setConfig(config: LovelaceCardConfig): void; } +export interface LovelaceHeaderFooter extends HTMLElement { + hass?: HomeAssistant; + setConfig(config: LovelaceHeaderFooterConfig): void; +} + export interface LovelaceCardEditor extends HTMLElement { hass?: HomeAssistant; setConfig(config: LovelaceCardConfig): void;