From 0078b48e3c5791451f03e7dc11c36c640067069b Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Mon, 21 Oct 2019 12:38:06 -0500 Subject: [PATCH] card level themes (#4057) * card level themes weather-forecast shopping-list plant-status markdown alarm-panel * fix markdown * address comments also added picture cards * update updated * address comments * address comments --- hassio/src/hassio-main.ts | 2 +- src/common/dom/apply_themes_on_element.ts | 6 +-- src/fake_data/provide_hass.ts | 2 +- .../lovelace/cards/hui-alarm-panel-card.ts | 38 +++++++++++++--- .../lovelace/cards/hui-entities-card.ts | 21 +++++++-- .../lovelace/cards/hui-entity-button-card.ts | 31 +++++++++---- src/panels/lovelace/cards/hui-gauge-card.ts | 12 ++++- src/panels/lovelace/cards/hui-glance-card.ts | 45 ++++++++++++------- src/panels/lovelace/cards/hui-light-card.ts | 13 +++++- .../lovelace/cards/hui-markdown-card.ts | 22 +++++++++ src/panels/lovelace/cards/hui-picture-card.ts | 22 +++++++++ .../cards/hui-picture-elements-card.ts | 22 +++++++++ .../lovelace/cards/hui-picture-entity-card.ts | 21 +++++++++ .../lovelace/cards/hui-picture-glance-card.ts | 29 ++++++++++++ .../lovelace/cards/hui-plant-status-card.ts | 21 +++++++++ src/panels/lovelace/cards/hui-sensor-card.ts | 13 +++++- .../lovelace/cards/hui-shopping-list-card.ts | 24 +++++++++- .../lovelace/cards/hui-thermostat-card.ts | 12 ++++- .../cards/hui-weather-forecast-card.ts | 18 ++++++++ src/panels/lovelace/cards/types.ts | 8 ++++ src/panels/lovelace/common/has-changed.ts | 7 +++ .../hui-alarm-panel-card-editor.ts | 14 +++++- .../hui-markdown-card-editor.ts | 13 ++++++ .../hui-picture-card-editor.ts | 12 +++++ .../hui-picture-entity-card-editor.ts | 12 +++++ .../hui-picture-glance-card-editor.ts | 12 +++++ .../hui-plant-status-card-editor.ts | 12 +++++ .../hui-shopping-list-editor.ts | 13 ++++++ .../hui-weather-forecast-card-editor.ts | 12 +++++ src/panels/lovelace/views/hui-panel-view.ts | 2 +- src/panels/lovelace/views/hui-view.ts | 2 +- src/state/themes-mixin.ts | 2 +- 32 files changed, 444 insertions(+), 51 deletions(-) diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts index 29966015f5..33bf94e573 100644 --- a/hassio/src/hassio-main.ts +++ b/hassio/src/hassio-main.ts @@ -3,7 +3,7 @@ import { PolymerElement } from "@polymer/polymer"; import "@polymer/paper-icon-button"; import "../../src/resources/ha-style"; -import applyThemesOnElement from "../../src/common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element"; import { fireEvent } from "../../src/common/dom/fire_event"; import { HassRouterPage, diff --git a/src/common/dom/apply_themes_on_element.ts b/src/common/dom/apply_themes_on_element.ts index 22b13893c0..5d5222ca7c 100644 --- a/src/common/dom/apply_themes_on_element.ts +++ b/src/common/dom/apply_themes_on_element.ts @@ -21,12 +21,12 @@ const hexToRgb = (hex: string): string | null => { * localTheme: selected theme. * updateMeta: boolean if we should update the theme-color meta element. */ -export default function applyThemesOnElement( +export const applyThemesOnElement = ( element, themes, localTheme, updateMeta = false -) { +) => { if (!element._themes) { element._themes = {}; } @@ -76,4 +76,4 @@ export default function applyThemesOnElement( styles["--primary-color"] || meta.getAttribute("default-content"); meta.setAttribute("content", themeColor); } -} +}; diff --git a/src/fake_data/provide_hass.ts b/src/fake_data/provide_hass.ts index bdb58eee00..f3101d5125 100644 --- a/src/fake_data/provide_hass.ts +++ b/src/fake_data/provide_hass.ts @@ -1,4 +1,4 @@ -import applyThemesOnElement from "../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../common/dom/apply_themes_on_element"; import { demoConfig } from "./demo_config"; import { demoServices } from "./demo_services"; diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts index bcd217f305..c9f85e20ec 100644 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.ts +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts @@ -22,6 +22,7 @@ import { } from "../../../data/alarm_control_panel"; import { AlarmPanelCardConfig } from "./types"; import { PaperInputElement } from "@polymer/paper-input/paper-input"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; const ICONS = { armed_away: "hass:shield-lock", @@ -81,19 +82,44 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard { this._code = ""; } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this.hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | AlarmPanelCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this.hass.themes, this._config.theme); + } + } + protected shouldUpdate(changedProps: PropertyValues): boolean { if (changedProps.has("_config") || changedProps.has("_code")) { return true; } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (oldHass) { - return ( - oldHass.states[this._config!.entity] !== - this.hass!.states[this._config!.entity] - ); + + if ( + !oldHass || + oldHass.themes !== this.hass!.themes || + oldHass.language !== this.hass!.language + ) { + return true; } - return true; + return ( + oldHass.states[this._config!.entity] !== + this.hass!.states[this._config!.entity] + ); } protected render(): TemplateResult | void { diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index cc680c8d60..ce5a2df85b 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -22,7 +22,7 @@ import { createRowElement } from "../common/create-row-element"; import { EntitiesCardConfig, EntitiesCardEntityConfig } from "./types"; import { computeDomain } from "../../../common/entity/compute_domain"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; @customElement("hui-entities-card") class HuiEntitiesCard extends LitElement implements LovelaceCard { @@ -71,9 +71,22 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard { this._configEntities = entities; } - protected updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); - if (this._hass && this._config) { + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this._hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | EntitiesCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { applyThemesOnElement(this, this._hass.themes, this._config.theme); } } diff --git a/src/panels/lovelace/cards/hui-entity-button-card.ts b/src/panels/lovelace/cards/hui-entity-button-card.ts index ee79f1e80b..38a02242e2 100644 --- a/src/panels/lovelace/cards/hui-entity-button-card.ts +++ b/src/panels/lovelace/cards/hui-entity-button-card.ts @@ -19,7 +19,7 @@ import { isValidEntityId } from "../../../common/entity/valid_entity_id"; import { stateIcon } from "../../../common/entity/state_icon"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { computeDomain } from "../../../common/entity/compute_domain"; import { HomeAssistant, LightEntity } from "../../../types"; @@ -91,13 +91,19 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard { } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (oldHass) { - return ( - oldHass.states[this._config!.entity] !== - this.hass!.states[this._config!.entity] - ); + + if ( + !oldHass || + oldHass.themes !== this.hass!.themes || + oldHass.language !== this.hass!.language + ) { + return true; } - return true; + + return ( + oldHass.states[this._config!.entity] !== + this.hass!.states[this._config!.entity] + ); } protected render(): TemplateResult | void { @@ -161,7 +167,16 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard { return; } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes !== this.hass.themes) { + const oldConfig = changedProps.get("_config") as + | EntityButtonCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } } diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index 8264931b39..da0a1b53ac 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -14,7 +14,7 @@ import "../../../components/ha-card"; import "../components/hui-warning"; import { isValidEntityId } from "../../../common/entity/valid_entity_id"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { HomeAssistant } from "../../../types"; @@ -149,8 +149,16 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | GaugeCardConfig + | undefined; - if (!oldHass || oldHass.themes !== this.hass.themes) { + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } } diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index 4e78f669dd..8b2daf8bd4 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -11,7 +11,7 @@ import { import { classMap } from "lit-html/directives/class-map"; import { computeStateName } from "../../../common/entity/compute_state_name"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import relativeTime from "../../../common/datetime/relative_time"; import "../../../components/entity/state-badge"; @@ -87,17 +87,23 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard { } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (oldHass && this._configEntities) { - for (const entity of this._configEntities) { - if ( - oldHass.states[entity.entity] !== this.hass!.states[entity.entity] - ) { - return true; - } - } - return false; + + if ( + !this._configEntities || + !oldHass || + oldHass.themes !== this.hass!.themes || + oldHass.language !== this.hass!.language + ) { + return true; } - return true; + + for (const entity of this._configEntities) { + if (oldHass.states[entity.entity] !== this.hass!.states[entity.entity]) { + return true; + } + } + + return false; } protected render(): TemplateResult | void { @@ -117,14 +123,23 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard { `; } - protected updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); if (!this._config || !this.hass) { return; } - const oldHass = changedProperties.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes !== this.hass.themes) { + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | GlanceCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } } diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index b93274b2a2..5aa4606197 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -11,7 +11,7 @@ import "@thomasloven/round-slider"; import { stateIcon } from "../../../common/entity/state_icon"; import { computeStateName } from "../../../common/entity/compute_state_name"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import "../../../components/ha-card"; import "../../../components/ha-icon"; @@ -145,7 +145,16 @@ export class HuiLightCard extends LitElement implements LovelaceCard { } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes !== this.hass.themes) { + const oldConfig = changedProps.get("_config") as + | LightCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } } diff --git a/src/panels/lovelace/cards/hui-markdown-card.ts b/src/panels/lovelace/cards/hui-markdown-card.ts index 1232a8e0b2..8ed40d8fda 100644 --- a/src/panels/lovelace/cards/hui-markdown-card.ts +++ b/src/panels/lovelace/cards/hui-markdown-card.ts @@ -6,6 +6,7 @@ import { property, css, CSSResult, + PropertyValues, } from "lit-element"; import { classMap } from "lit-html/directives/class-map"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; @@ -17,6 +18,7 @@ import { HomeAssistant } from "../../../types"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { MarkdownCardConfig } from "./types"; import { subscribeRenderTemplate } from "../../../data/ws-templates"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; @customElement("hui-markdown-card") export class HuiMarkdownCard extends LitElement implements LovelaceCard { @@ -84,6 +86,26 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard { `; } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this._hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | MarkdownCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this._hass.themes, this._config.theme); + } + } + private async _connect() { if (!this._unsubRenderTemplate && this._hass && this._config) { this._unsubRenderTemplate = subscribeRenderTemplate( diff --git a/src/panels/lovelace/cards/hui-picture-card.ts b/src/panels/lovelace/cards/hui-picture-card.ts index 36dffad8ab..b7a29d4dcd 100644 --- a/src/panels/lovelace/cards/hui-picture-card.ts +++ b/src/panels/lovelace/cards/hui-picture-card.ts @@ -6,6 +6,7 @@ import { property, css, CSSResult, + PropertyValues, } from "lit-element"; import "../../../components/ha-card"; @@ -17,6 +18,7 @@ import { handleClick } from "../common/handle-click"; import { longPress } from "../common/directives/long-press-directive"; import { PictureCardConfig } from "./types"; import { hasDoubleClick } from "../common/has-double-click"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; @customElement("hui-picture-card") export class HuiPictureCard extends LitElement implements LovelaceCard { @@ -49,6 +51,26 @@ export class HuiPictureCard extends LitElement implements LovelaceCard { this._config = config; } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this.hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | PictureCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this.hass.themes, this._config.theme); + } + } + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; diff --git a/src/panels/lovelace/cards/hui-picture-elements-card.ts b/src/panels/lovelace/cards/hui-picture-elements-card.ts index c135ce9265..66f97df653 100644 --- a/src/panels/lovelace/cards/hui-picture-elements-card.ts +++ b/src/panels/lovelace/cards/hui-picture-elements-card.ts @@ -6,6 +6,7 @@ import { customElement, css, CSSResult, + PropertyValues, } from "lit-element"; import { createStyledHuiElement } from "./picture-elements/create-styled-hui-element"; @@ -13,6 +14,7 @@ import { LovelaceCard } from "../types"; import { HomeAssistant } from "../../../types"; import { LovelaceElementConfig, LovelaceElement } from "../elements/types"; import { PictureElementsCardConfig } from "./types"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; @customElement("hui-picture-elements-card") class HuiPictureElementsCard extends LitElement implements LovelaceCard { @@ -49,6 +51,26 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard { this._config = config; } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this._hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | PictureElementsCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this._hass.themes, this._config.theme); + } + } + protected render(): TemplateResult | void { if (!this._config) { return html``; diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts index 22bef5170c..54880f88fe 100644 --- a/src/panels/lovelace/cards/hui-picture-entity-card.ts +++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts @@ -26,6 +26,7 @@ import { UNAVAILABLE } from "../../../data/entity"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import { PictureEntityCardConfig } from "./types"; import { hasDoubleClick } from "../common/has-double-click"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; @customElement("hui-picture-entity-card") class HuiPictureEntityCard extends LitElement implements LovelaceCard { @@ -68,6 +69,26 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard { return hasConfigOrEntityChanged(this, changedProps); } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this.hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | PictureEntityCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this.hass.themes, this._config.theme); + } + } + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index cbad92508d..bb40055ceb 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -28,6 +28,7 @@ import { handleClick } from "../common/handle-click"; import { hasDoubleClick } from "../common/has-double-click"; import { PictureGlanceCardConfig, PictureGlanceEntityConfig } from "./types"; import { hasConfigOrEntityChanged } from "../common/has-changed"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; const STATES_OFF = new Set(["closed", "locked", "not_home", "off"]); @@ -93,6 +94,14 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard { const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + if ( + !oldHass || + oldHass.themes !== this.hass!.themes || + oldHass.language !== this.hass!.language + ) { + return true; + } + if (this._entitiesDialog) { for (const entity of this._entitiesDialog) { if ( @@ -116,6 +125,26 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard { return false; } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this.hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | PictureGlanceCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this.hass.themes, this._config.theme); + } + } + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; diff --git a/src/panels/lovelace/cards/hui-plant-status-card.ts b/src/panels/lovelace/cards/hui-plant-status-card.ts index 8d4bc0f56d..82a3971602 100644 --- a/src/panels/lovelace/cards/hui-plant-status-card.ts +++ b/src/panels/lovelace/cards/hui-plant-status-card.ts @@ -20,6 +20,7 @@ import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import { PlantStatusCardConfig, PlantAttributeTarget } from "./types"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; const SENSORS = { moisture: "hass:water", @@ -60,6 +61,26 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard { return hasConfigOrEntityChanged(this, changedProps); } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this.hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | PlantStatusCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this.hass.themes, this._config.theme); + } + } + protected render(): TemplateResult | void { if (!this.hass || !this._config) { return html``; diff --git a/src/panels/lovelace/cards/hui-sensor-card.ts b/src/panels/lovelace/cards/hui-sensor-card.ts index c747334930..91a765533e 100644 --- a/src/panels/lovelace/cards/hui-sensor-card.ts +++ b/src/panels/lovelace/cards/hui-sensor-card.ts @@ -11,7 +11,7 @@ import { } from "lit-element"; import "@polymer/paper-spinner/paper-spinner"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { stateIcon } from "../../../common/entity/state_icon"; @@ -277,7 +277,16 @@ class HuiSensorCard extends LitElement implements LovelaceCard { } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes !== this.hass.themes) { + const oldConfig = changedProps.get("_config") as + | SensorCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { applyThemesOnElement(this, this.hass.themes, this._config!.theme); } diff --git a/src/panels/lovelace/cards/hui-shopping-list-card.ts b/src/panels/lovelace/cards/hui-shopping-list-card.ts index 10f391e6aa..cb0426475a 100644 --- a/src/panels/lovelace/cards/hui-shopping-list-card.ts +++ b/src/panels/lovelace/cards/hui-shopping-list-card.ts @@ -6,6 +6,7 @@ import { CSSResult, property, customElement, + PropertyValues, } from "lit-element"; import { repeat } from "lit-html/directives/repeat"; import { PaperInputElement } from "@polymer/paper-input/paper-input"; @@ -23,7 +24,8 @@ import { clearItems, addItem, } from "../../../data/shopping-list"; -import { ShoppingListCardConfig } from "./types"; +import { ShoppingListCardConfig, SensorCardConfig } from "./types"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; @customElement("hui-shopping-list-card") class HuiShoppingListCard extends LitElement implements LovelaceCard { @@ -77,6 +79,26 @@ class HuiShoppingListCard extends LitElement implements LovelaceCard { } } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (!this._config || !this.hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | SensorCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this.hass.themes, this._config.theme); + } + } + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index d4ca705b41..631fd5b1b7 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -16,7 +16,7 @@ import "../../../components/ha-card"; import "../../../components/ha-icon"; import "../components/hui-warning"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { hasConfigOrEntityChanged } from "../common/has-changed"; @@ -235,8 +235,16 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { } const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | ThermostatCardConfig + | undefined; - if (!oldHass || oldHass.themes !== this.hass.themes) { + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index e17b06d311..df76105511 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -22,6 +22,7 @@ import { WeatherForecastCardConfig } from "./types"; import { computeRTL } from "../../../common/util/compute_rtl"; import { fireEvent } from "../../../common/dom/fire_event"; import { toggleAttribute } from "../../../common/dom/toggle_attribute"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; const cardinalDirections = [ "N", @@ -92,6 +93,23 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { protected updated(changedProps: PropertyValues): void { super.updated(changedProps); + if (!this._config || !this.hass) { + return; + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + const oldConfig = changedProps.get("_config") as + | WeatherForecastCardConfig + | undefined; + + if ( + !oldHass || + !oldConfig || + oldHass.themes !== this.hass.themes || + oldConfig.theme !== this._config.theme + ) { + applyThemesOnElement(this, this.hass.themes, this._config.theme); + } + if (changedProps.has("hass")) { toggleAttribute(this, "rtl", computeRTL(this.hass!)); } diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index dcdff54c76..7b0d74c5e5 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -8,6 +8,7 @@ export interface AlarmPanelCardConfig extends LovelaceCardConfig { entity: string; name?: string; states?: string[]; + theme?: string; } export interface ConditionalCardConfig extends LovelaceCardConfig { @@ -134,6 +135,7 @@ export interface MarkdownCardConfig extends LovelaceCardConfig { title?: string; card_size?: number; entity_ids?: string | string[]; + theme?: string; } export interface MediaControlCardConfig extends LovelaceCardConfig { @@ -145,6 +147,7 @@ export interface PictureCardConfig extends LovelaceCardConfig { tap_action?: ActionConfig; hold_action?: ActionConfig; double_tap_action?: ActionConfig; + theme?: string; } export interface PictureElementsCardConfig extends LovelaceCardConfig { @@ -157,6 +160,7 @@ export interface PictureElementsCardConfig extends LovelaceCardConfig { aspect_ratio?: string; entity?: string; elements: LovelaceElementConfig[]; + theme?: string; } export interface PictureEntityCardConfig extends LovelaceCardConfig { @@ -173,6 +177,7 @@ export interface PictureEntityCardConfig extends LovelaceCardConfig { double_tap_action?: ActionConfig; show_name?: boolean; show_state?: boolean; + theme?: string; } export interface PictureGlanceCardConfig extends LovelaceCardConfig { @@ -189,6 +194,7 @@ export interface PictureGlanceCardConfig extends LovelaceCardConfig { hold_action?: ActionConfig; double_tap_action?: ActionConfig; show_state?: boolean; + theme?: string; } export interface PlantAttributeTarget extends EventTarget { @@ -198,6 +204,7 @@ export interface PlantAttributeTarget extends EventTarget { export interface PlantStatusCardConfig extends LovelaceCardConfig { name?: string; entity: string; + theme?: string; } export interface SensorCardConfig extends LovelaceCardConfig { @@ -213,6 +220,7 @@ export interface SensorCardConfig extends LovelaceCardConfig { export interface ShoppingListCardConfig extends LovelaceCardConfig { title?: string; + theme?: string; } export interface StackCardConfig extends LovelaceCardConfig { diff --git a/src/panels/lovelace/common/has-changed.ts b/src/panels/lovelace/common/has-changed.ts index 904a7c2462..121e0e39e3 100644 --- a/src/panels/lovelace/common/has-changed.ts +++ b/src/panels/lovelace/common/has-changed.ts @@ -15,6 +15,13 @@ export function hasConfigOrEntityChanged( return true; } + if ( + oldHass.themes !== element.hass!.themes || + oldHass.language !== element.hass!.language + ) { + return true; + } + return ( oldHass.states[element._config!.entity] !== element.hass!.states[element._config!.entity] || diff --git a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts index 4a4e2c7d67..c7bcf454da 100644 --- a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts @@ -17,16 +17,18 @@ import { HomeAssistant } from "../../../../types"; import { LovelaceCardEditor } from "../../types"; import { fireEvent } from "../../../../common/dom/fire_event"; import { configElementStyle } from "./config-elements-style"; +import { AlarmPanelCardConfig } from "../../cards/types"; import "../../../../components/entity/ha-entity-picker"; import "../../../../components/ha-icon"; -import { AlarmPanelCardConfig } from "../../cards/types"; +import "../../components/hui-theme-select-editor"; const cardConfigStruct = struct({ type: "string", entity: "string?", name: "string?", states: "array?", + theme: "string?", }); @customElement("hui-alarm-panel-card-editor") @@ -53,6 +55,10 @@ export class HuiAlarmPanelCardEditor extends LitElement return this._config!.states || []; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -113,6 +119,12 @@ export class HuiAlarmPanelCardEditor extends LitElement })} + `; } diff --git a/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts index 364f7ebb63..22f60e30ce 100644 --- a/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts @@ -16,10 +16,13 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { configElementStyle } from "./config-elements-style"; import { MarkdownCardConfig } from "../../cards/types"; +import "../../components/hui-theme-select-editor"; + const cardConfigStruct = struct({ type: "string", title: "string?", content: "string", + theme: "string?", }); @customElement("hui-markdown-card-editor") @@ -42,6 +45,10 @@ export class HuiMarkdownCardEditor extends LitElement return this._config!.content || ""; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -73,6 +80,12 @@ export class HuiMarkdownCardEditor extends LitElement autocomplete="off" spellcheck="false" > + `; } diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts index b68736e6b3..dacc3e7758 100644 --- a/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts @@ -8,6 +8,7 @@ import { import "@polymer/paper-input/paper-input"; import "../../components/hui-action-editor"; +import "../../components/hui-theme-select-editor"; import { struct } from "../../common/structs/struct"; import { @@ -27,6 +28,7 @@ const cardConfigStruct = struct({ image: "string?", tap_action: struct.optional(actionConfigStruct), hold_action: struct.optional(actionConfigStruct), + theme: "string?", }); @customElement("hui-picture-card-editor") @@ -53,6 +55,10 @@ export class HuiPictureCardEditor extends LitElement return this._config!.hold_action || { action: "none" }; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -98,6 +104,12 @@ export class HuiPictureCardEditor extends LitElement .configValue="${"hold_action"}" @action-changed="${this._valueChanged}" > + `; diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts index f63068b6eb..528ff23327 100644 --- a/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-picture-entity-card-editor.ts @@ -13,6 +13,7 @@ import "@polymer/paper-listbox/paper-listbox"; import "../../components/hui-action-editor"; import "../../components/hui-entity-editor"; import "../../../../components/ha-switch"; +import "../../components/hui-theme-select-editor"; import { struct } from "../../common/structs/struct"; import { @@ -39,6 +40,7 @@ const cardConfigStruct = struct({ hold_action: struct.optional(actionConfigStruct), show_name: "boolean?", show_state: "boolean?", + theme: "string?", }); @customElement("hui-picture-entity-card-editor") @@ -93,6 +95,10 @@ export class HuiPictureEntityCardEditor extends LitElement return this._config!.show_state || true; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -225,6 +231,12 @@ export class HuiPictureEntityCardEditor extends LitElement .configValue="${"hold_action"}" @action-changed="${this._valueChanged}" > + `; diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts index 1d5df3d946..9c5e73c23c 100644 --- a/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-picture-glance-card-editor.ts @@ -13,6 +13,7 @@ import "@polymer/paper-listbox/paper-listbox"; import "../../components/hui-action-editor"; import "../../components/hui-entity-editor"; import "../../../../components/entity/ha-entity-picker"; +import "../../components/hui-theme-select-editor"; import { struct } from "../../common/structs/struct"; import { @@ -41,6 +42,7 @@ const cardConfigStruct = struct({ tap_action: struct.optional(actionConfigStruct), hold_action: struct.optional(actionConfigStruct), entities: [entitiesConfigStruct], + theme: "string?", }); @customElement("hui-picture-glance-card-editor") @@ -104,6 +106,10 @@ export class HuiPictureGlanceCardEditor extends LitElement return this._config!.show_state || false; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -224,6 +230,12 @@ export class HuiPictureGlanceCardEditor extends LitElement .entities="${this._configEntities}" @entities-changed="${this._valueChanged}" > + `; } diff --git a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts index b95c170a7b..2b0fe94faa 100644 --- a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts @@ -9,6 +9,7 @@ import "@polymer/paper-input/paper-input"; import "../../../../components/entity/ha-entity-picker"; import "../../../../components/ha-icon"; +import "../../components/hui-theme-select-editor"; import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; @@ -22,6 +23,7 @@ const cardConfigStruct = struct({ type: "string", entity: "string", name: "string?", + theme: "string?", }); @customElement("hui-plant-status-card-editor") @@ -44,6 +46,10 @@ export class HuiPlantStatusCardEditor extends LitElement return this._config!.name || ""; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -75,6 +81,12 @@ export class HuiPlantStatusCardEditor extends LitElement .configValue="${"name"}" @value-changed="${this._valueChanged}" > + `; } diff --git a/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts b/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts index c963bf9173..b75adbda1e 100644 --- a/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts @@ -14,9 +14,12 @@ import { LovelaceCardEditor } from "../../types"; import { fireEvent } from "../../../../common/dom/fire_event"; import { ShoppingListCardConfig } from "../../cards/types"; +import "../../components/hui-theme-select-editor"; + const cardConfigStruct = struct({ type: "string", title: "string?", + theme: "string?", }); @customElement("hui-shopping-list-card-editor") @@ -35,6 +38,10 @@ export class HuiShoppingListEditor extends LitElement return this._config!.title || ""; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -52,6 +59,12 @@ export class HuiShoppingListEditor extends LitElement .configValue="${"title"}" @value-changed="${this._valueChanged}" > + `; } diff --git a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts index 99df6a8a03..e45ed0a9f7 100644 --- a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts @@ -7,6 +7,7 @@ import { } from "lit-element"; import "../../../../components/entity/ha-entity-picker"; +import "../../components/hui-theme-select-editor"; import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; @@ -20,6 +21,7 @@ const cardConfigStruct = struct({ type: "string", entity: "string?", name: "string?", + theme: "string?", }); @customElement("hui-weather-forecast-card-editor") @@ -42,6 +44,10 @@ export class HuiWeatherForecastCardEditor extends LitElement return this._config!.name || ""; } + get _theme(): string { + return this._config!.theme || "Backend-selected"; + } + protected render(): TemplateResult | void { if (!this.hass) { return html``; @@ -73,6 +79,12 @@ export class HuiWeatherForecastCardEditor extends LitElement .configValue="${"name"}" @value-changed="${this._valueChanged}" > + `; } diff --git a/src/panels/lovelace/views/hui-panel-view.ts b/src/panels/lovelace/views/hui-panel-view.ts index 525465c05f..2b92d68f42 100644 --- a/src/panels/lovelace/views/hui-panel-view.ts +++ b/src/panels/lovelace/views/hui-panel-view.ts @@ -5,7 +5,7 @@ import { UpdatingElement, } from "lit-element"; -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { HomeAssistant } from "../../../types"; import { LovelaceCard } from "../types"; diff --git a/src/panels/lovelace/views/hui-view.ts b/src/panels/lovelace/views/hui-view.ts index a9e413eb1d..22d2b15f37 100644 --- a/src/panels/lovelace/views/hui-view.ts +++ b/src/panels/lovelace/views/hui-view.ts @@ -9,7 +9,7 @@ import { import "../../../components/entity/ha-state-label-badge"; // This one is for types -import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { LovelaceViewConfig, diff --git a/src/state/themes-mixin.ts b/src/state/themes-mixin.ts index 4fd14c823a..6c151f2a71 100644 --- a/src/state/themes-mixin.ts +++ b/src/state/themes-mixin.ts @@ -1,4 +1,4 @@ -import applyThemesOnElement from "../common/dom/apply_themes_on_element"; +import { applyThemesOnElement } from "../common/dom/apply_themes_on_element"; import { storeState } from "../util/ha-pref-storage"; import { subscribeThemes } from "../data/ws-themes"; import { HassBaseEl } from "./hass-base-mixin";