From fa445d4066d180c97df9c6b85d020eac8e3b9865 Mon Sep 17 00:00:00 2001 From: Mat Strange Date: Sat, 9 May 2020 12:00:26 +0100 Subject: [PATCH 01/21] Added translation to bade on alarm panel --- src/panels/lovelace/cards/hui-alarm-panel-card.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts index 387ec493ac..fe829448cf 100644 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.ts +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts @@ -170,7 +170,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
@@ -225,15 +225,6 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard { `; } - private _stateIconLabel(state: string): string { - const stateLabel = state.split("_").pop(); - return stateLabel === "disarmed" || - stateLabel === "triggered" || - !stateLabel - ? "" - : stateLabel; - } - private _actionDisplay(state: string): string { return this.hass!.localize(`ui.card.alarm_control_panel.${state}`); } From a27428ebcdbcafea54cd8853ae2bf7d36d89df7c Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sat, 9 May 2020 21:17:55 +0200 Subject: [PATCH 02/21] Simplify enter handling --- src/components/ha-tab.ts | 16 ++-------------- src/layouts/hass-tabs-subpage.ts | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/components/ha-tab.ts b/src/components/ha-tab.ts index 0b956429c1..f3a6b510ea 100644 --- a/src/components/ha-tab.ts +++ b/src/components/ha-tab.ts @@ -18,13 +18,6 @@ import "./ha-svg-icon"; import { ifDefined } from "lit-html/directives/if-defined"; import { fireEvent } from "../common/dom/fire_event"; -declare global { - // for fire event - interface HASSDomEvents { - activated: undefined; - } -} - @customElement("ha-tab") export class HaTab extends LitElement { @property({ type: Boolean, reflect: true }) public active = false; @@ -54,11 +47,10 @@ export class HaTab extends LitElement { @touchend=${this.handleRippleDeactivate} @touchcancel=${this.handleRippleDeactivate} @keydown=${this._handleKeyDown} - @click=${this._handleClick} > ${this.narrow ? html`` : ""} ${!this.narrow || this.active - ? html` ${this.name} ` + ? html`${this.name}` : ""} ${this._shouldRenderRipple ? html`` : ""}
@@ -72,14 +64,10 @@ export class HaTab extends LitElement { private _handleKeyDown(ev: KeyboardEvent): void { if (ev.keyCode === 13) { - fireEvent(this, "activated"); + (ev.target as HTMLElement).click(); } } - private _handleClick(): void { - fireEvent(this, "activated"); - } - @eventOptions({ passive: true }) private handleRippleActivate(evt?: Event) { this._rippleHandlers.startPress(evt); diff --git a/src/layouts/hass-tabs-subpage.ts b/src/layouts/hass-tabs-subpage.ts index f5a4d1be4b..454898f824 100644 --- a/src/layouts/hass-tabs-subpage.ts +++ b/src/layouts/hass-tabs-subpage.ts @@ -74,7 +74,7 @@ class HassTabsSubpage extends LitElement { html` Date: Sat, 9 May 2020 21:22:46 +0200 Subject: [PATCH 03/21] Unused import --- src/components/ha-tab.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ha-tab.ts b/src/components/ha-tab.ts index f3a6b510ea..e58f820303 100644 --- a/src/components/ha-tab.ts +++ b/src/components/ha-tab.ts @@ -16,7 +16,6 @@ import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers"; import "./ha-icon"; import "./ha-svg-icon"; import { ifDefined } from "lit-html/directives/if-defined"; -import { fireEvent } from "../common/dom/fire_event"; @customElement("ha-tab") export class HaTab extends LitElement { From 8768304ec57ee3ac4c92499c119c9c9d32521e69 Mon Sep 17 00:00:00 2001 From: Mat Strange Date: Sat, 9 May 2020 20:30:44 +0100 Subject: [PATCH 04/21] Returned to no label on disarm/trigger as before --- src/panels/lovelace/cards/hui-alarm-panel-card.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts index fe829448cf..64001e5e62 100644 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.ts +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts @@ -170,7 +170,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
@@ -225,6 +225,15 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard { `; } + private _stateIconLabel(state: string): string { + const stateLabel = state.split("_").pop(); + return stateLabel === "disarmed" || + stateLabel === "triggered" || + !stateLabel + ? "" + : this._stateDisplay(state); + } + private _actionDisplay(state: string): string { return this.hass!.localize(`ui.card.alarm_control_panel.${state}`); } From d1cceb2013ded6d77fe2e31dda73dc9f95c0227f Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Sun, 10 May 2020 00:33:23 +0000 Subject: [PATCH 05/21] [ci skip] Translation update --- translations/frontend/da.json | 3 +++ translations/frontend/de.json | 3 +++ translations/frontend/es.json | 3 +++ translations/frontend/fi.json | 8 +++++-- translations/frontend/it.json | 4 ++++ translations/frontend/nl.json | 14 ++++++++++++ translations/frontend/pt.json | 27 ++++++++++++++---------- translations/frontend/ro.json | 34 ++++++++++++++++++------------ translations/frontend/sv.json | 21 ++++++++++++++++++ translations/frontend/zh-Hant.json | 3 +++ 10 files changed, 94 insertions(+), 26 deletions(-) diff --git a/translations/frontend/da.json b/translations/frontend/da.json index dd7322b11b..2b66efa7a3 100644 --- a/translations/frontend/da.json +++ b/translations/frontend/da.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "og", "cancel": "Annuller", "close": "Luk", "delete": "Slet", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "Editor er deaktiveret, fordi config er gemt i 'configuration.yaml'.", "elevation": "Højde", "elevation_meters": "meter", + "external_url": "Ekstern webadresse", "imperial_example": "Fahrenheit, pund", + "internal_url": "Intern webadresse", "latitude": "Breddegrad", "location_name": "Navn på din Home Assistant-installation", "longitude": "Længdegrad", diff --git a/translations/frontend/de.json b/translations/frontend/de.json index c4c4c364be..4f0b0eee38 100644 --- a/translations/frontend/de.json +++ b/translations/frontend/de.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "und", "cancel": "Abbrechen", "close": "Schließen", "delete": "Löschen", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "Editor deaktiviert, da die Konfiguration in configuration.yaml gespeichert ist.", "elevation": "Höhe", "elevation_meters": "Meter", + "external_url": "Externe Adresse", "imperial_example": "Fahrenheit, Pfund", + "internal_url": "Interne Adresse", "latitude": "Breitengrad", "location_name": "Name deiner Home Assistant Installation", "longitude": "Längengrad", diff --git a/translations/frontend/es.json b/translations/frontend/es.json index 7690ae77b7..908f22051d 100644 --- a/translations/frontend/es.json +++ b/translations/frontend/es.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "y", "cancel": "Cancelar", "close": "Cerrar", "delete": "Eliminar", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "Editor deshabilitado debido a la configuración almacenada en configuration.yaml.", "elevation": "Altitud", "elevation_meters": "metros", + "external_url": "URL externa", "imperial_example": "Fahrenheit, libras", + "internal_url": "URL interna", "latitude": "Latitud", "location_name": "Nombre de tu instalación de Home Assistant", "longitude": "Longitud", diff --git a/translations/frontend/fi.json b/translations/frontend/fi.json index 959f0eb4f3..4ca8c78362 100644 --- a/translations/frontend/fi.json +++ b/translations/frontend/fi.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "ja", "cancel": "Peruuta", "close": "Sulje", "delete": "Poista", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "Editori on poistettu käytöstä, koska asetuksia on annettu configuration.yaml:ssa.", "elevation": "Korkeus merenpinnasta", "elevation_meters": "metriä", + "external_url": "Ulkoinen URL-osoite", "imperial_example": "Fahrenheit, paunaa", + "internal_url": "Sisäinen URL-osoite", "latitude": "Leveysaste", "location_name": "Home Assistant -järjestelmäsi nimi", "longitude": "Pituusaste", @@ -1247,6 +1250,7 @@ }, "delete": "Poista", "description": "Hallitse yhdistettyjä laitteita.", + "device_info": "Laitteen tiedot", "device_not_found": "Laitetta ei löydy.", "entities": { "add_entities_lovelace": "Lisää Lovelace näkymään", @@ -1602,7 +1606,7 @@ "core": "Lataa ydin uudelleen", "group": "Lataa ryhmät uudelleen", "heading": "Asetusten uudelleenlataus", - "introduction": "Jotkut kotiassistentin osat voidaan ladata uudelleen ilman, että tarvitaan uudelleenkäynnistystä. Painamalla uudelleenlatausta uudet asetukset luetaan yaml tiedostosta.", + "introduction": "Jotkut Home Assistantin osat voidaan ladata uudelleen ilman, että tarvitaan uudelleenkäynnistystä. Painamalla uudelleenlatausta yaml-tiedosto luetaan uudelleen.", "person": "Lataa henkilöt uudelleen", "scene": "Lataa tilanteet uudelleen", "script": "Lataa skriptit uudelleen", @@ -1612,7 +1616,7 @@ "confirm_restart": "Haluatko varmasti käynnistää Home Assistantin uudelleen?", "confirm_stop": "Haluatko varmasti pysäyttää Home Assistantin?", "heading": "Palvelimen hallinta", - "introduction": "Hallitse Home Assistantia... suoraan Home Assistantista", + "introduction": "Hallitse Home Assistantia suoraan käyttöliittymästä.", "restart": "Käynnistä uudelleen", "stop": "Pysäytä" }, diff --git a/translations/frontend/it.json b/translations/frontend/it.json index 3a5cd3ab16..a566fb6fde 100644 --- a/translations/frontend/it.json +++ b/translations/frontend/it.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "e", "cancel": "Annulla", "close": "Chiudi", "delete": "Elimina", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "Editor disabilitato perché la configurazione è memorizzata in configuration.yaml.", "elevation": "Altitudine", "elevation_meters": "metri", + "external_url": "URL esterno", "imperial_example": "Fahrenheit, libbre", + "internal_url": "URL interno", "latitude": "Latitudine", "location_name": "Nome della tua installazione di Home Assistant", "longitude": "Longitudine", @@ -1247,6 +1250,7 @@ }, "delete": "Elimina", "description": "Gestisci i dispositivi collegati", + "device_info": "Informazioni sul dispositivo", "device_not_found": "Dispositivo non trovato.", "entities": { "add_entities_lovelace": "Aggiungi a Lovelace", diff --git a/translations/frontend/nl.json b/translations/frontend/nl.json index 40f27f533a..f9f250905f 100644 --- a/translations/frontend/nl.json +++ b/translations/frontend/nl.json @@ -473,11 +473,15 @@ } }, "common": { + "and": "en", "cancel": "Annuleren", "close": "Sluiten", "delete": "Verwijderen", "loading": "Bezig met laden", + "next": "Volgende", "no": "Nee", + "previous": "Vorige", + "refresh": "Vernieuwen", "save": "Opslaan", "successfully_deleted": "Succesvol verwijderd", "successfully_saved": "Succesvol opgeslagen", @@ -737,6 +741,10 @@ "triggered": "Geactiveerd {name}" }, "panel": { + "calendar": { + "my_calendars": "Mijn agenda's", + "today": "Vandaag" + }, "config": { "advanced_mode": { "hint_enable": "Ontbrekende configuratie-opties? Schakel geavanceerde modus in", @@ -839,6 +847,9 @@ }, "label": "Apparaat" }, + "not": { + "label": "Niet" + }, "numeric_state": { "above": "Boven", "below": "Onder", @@ -1170,7 +1181,9 @@ "edit_requires_storage": "Editor uitgeschakeld omdat de configuratie is opgeslagen in configuration.yaml", "elevation": "Hoogte", "elevation_meters": "meter", + "external_url": "Externe URL", "imperial_example": "Fahrenheit, ponden", + "internal_url": "Interne URL", "latitude": "Breedtegraad", "location_name": "Naam van Home Assistant installatie", "longitude": "Lengtegraad", @@ -1237,6 +1250,7 @@ }, "delete": "Verwijderen", "description": "Beheer verbonden apparaten", + "device_info": "Apparaat info", "device_not_found": "Apparaat niet gevonden.", "entities": { "add_entities_lovelace": "Voeg toe aan de Lovelace gebruikersinterface", diff --git a/translations/frontend/pt.json b/translations/frontend/pt.json index 261d8d6ba8..bd7d3b1133 100644 --- a/translations/frontend/pt.json +++ b/translations/frontend/pt.json @@ -332,7 +332,7 @@ "auth_store": { "ask": "Deseja continuar com sessão iniciada?", "confirm": "Guardar login", - "decline": "Não, obrigado" + "decline": "Não" }, "card": { "alarm_control_panel": { @@ -473,6 +473,7 @@ } }, "common": { + "and": "e", "cancel": "Cancelar", "close": "Fechar", "delete": "Apagar", @@ -761,8 +762,8 @@ "editor": { "create": "Criar", "default_name": "Nova área", - "delete": "APAGAR", - "update": "ATUALIZAR" + "delete": "Apagar", + "update": "Atualizar" }, "picker": { "create_area": "Criar área", @@ -1178,7 +1179,9 @@ "edit_requires_storage": "Editor desativado por causa da configuração existente em configuration.yaml.", "elevation": "Elevação", "elevation_meters": "metros", + "external_url": "URL externo", "imperial_example": "Fahrenheit, libras", + "internal_url": "URL interno", "latitude": "Latitude", "location_name": "Nome da instalação do seu Home Assistant", "longitude": "Longitude", @@ -1204,7 +1207,7 @@ "description": "Personalizar as suas entidades", "pick_attribute": "Escolha um atributo para substituir.", "picker": { - "header": "Personalização", + "header": "Personalizações", "introduction": "Ajustar atributos por entidade. Personalizações acrescentadas/editadas terão efeitos imediatos. Remoção de personalizações terão efeito quando a entidade for atualizada." }, "warning": { @@ -1244,6 +1247,7 @@ }, "delete": "Apagar", "description": "Gerir dispositivos ligados", + "device_info": "Informação do dispositivo", "device_not_found": "Dispositivo não encontrado.", "entities": { "add_entities_lovelace": "Adicionar ao Lovelace", @@ -1592,8 +1596,8 @@ "automation": "Recarregar automações", "core": "Recarregar localização e personalizações", "group": "Recarregar grupos", - "heading": "A recarregar configuração", - "introduction": "Algumas partes do Home Assistant podem ser recarregadas sem necessidade de reiniciar. Ao carregar em Recarregar configuração irá descarregar a configuração atual e carregar a nova.", + "heading": "A recarregar a configuração YAML", + "introduction": "Algumas partes do Home Assistant podem ser recarregadas sem a necessidade de reiniciar. Ao carregar em Recarregar a configuração irá descartar a configuração atual e carregar a nova.", "person": "Recarregar pessoas", "scene": "Recarregar cenas", "script": "Recarregar scripts", @@ -1796,7 +1800,7 @@ "config_parameter": "Parâmetro de configuração", "config_value": "Valor de Configuração", "false": "Falso", - "header": "Configurar opçoes do nó", + "header": "Opções de configuração de nó", "seconds": "Segundos", "set_config_parameter": "Definir o Parâmetro de Configuração", "set_wakeup": "Definir intervalo de acordar", @@ -1973,7 +1977,7 @@ } }, "changed_toast": { - "message": "A configuração do Lovelace foi atualizada, gostaria de atualizar?", + "message": "A configuração do Lovelace foi atualizada para este painel, gostaria de atualizar?", "refresh": "Atualizar" }, "editor": { @@ -2147,7 +2151,7 @@ "header": "Configuração do cartão", "move": "Mover para Vista", "options": "Mais opções", - "pick_card": "Escolha o cartão que deseja adicionar.", + "pick_card": "Que cartão gostaria de adicionar?", "pick_card_view_title": "Que cartão você gostaria de adicionar à sua vista {name}?", "show_code_editor": "Mostrar Editor de Código", "show_visual_editor": "Mostrar Editor Visual", @@ -2191,7 +2195,7 @@ "error_parse_yaml": "Não foi possível analisar o YAML: {error}", "error_remove": "Não foi possível remover a configuração: {error}", "error_save_yaml": "Não é possível salvar o YAML: {error}", - "header": "Editar configuração", + "header": "Editar Configuração", "resources_moved": "Os recursos não devem mais ser adicionados ao editor de configuração do código fonte do Lovelace, mas podem ser adicionados no painel de configuração do Lovelace.", "save": "Guardar", "saved": "Guardada", @@ -2229,7 +2233,7 @@ "refresh": "Atualizar", "reload_resources": "Recarregar recursos" }, - "reload_lovelace": "Recarregar Lovelace", + "reload_lovelace": "Recarregar UI", "reload_resources": { "refresh_body": "É preciso atualizar a página para concluir o carregamento. Deseja atualizar agora?", "refresh_header": "Deseja atualizar?" @@ -2392,6 +2396,7 @@ "mirror": "Espelho", "patio": "Pátio", "right": "Direita", + "temperature_study": "Estudo da Temperatura", "upstairs": "Andar de cima" }, "unit": { diff --git a/translations/frontend/ro.json b/translations/frontend/ro.json index a0d6aa9139..ee5ae14f53 100644 --- a/translations/frontend/ro.json +++ b/translations/frontend/ro.json @@ -330,8 +330,8 @@ }, "ui": { "auth_store": { - "ask": "Doriți să salvați aceste date de conectare?", - "confirm": "Salvați datele de conectare", + "ask": "Vrei să rămâi autentificat?", + "confirm": "Da", "decline": "Nu" }, "card": { @@ -541,7 +541,7 @@ "dismiss": "Ascunde", "editor": { "confirm_delete": "Sigur dorești să ștergi această intrare?", - "delete": "ȘTERGE", + "delete": "Șterge", "enabled_cause": "Dezactivat de către {cause}.", "enabled_description": "Entitățile dezactivate nu vof fi adăugate in Home Assistant", "enabled_label": "Activează entitatea", @@ -550,7 +550,7 @@ "name": "Suprascriere nume", "note": "Notă: este posibil să nu funcționeze încă cu toate integrările.", "unavailable": "Această entitate nu este disponibilă momentan.", - "update": "ACTUALIZARE" + "update": "Actualizare" }, "no_unique_id": "Această entitate nu are un ID unic, prin urmare, setările sale nu pot fi gestionate de la interfața cu utilizatorul.", "related": "În legătură cu", @@ -594,7 +594,9 @@ "password": "Parola", "text": "Text" }, - "required_error_msg": "Acest câmp este obligatoriu" + "platform_not_loaded": "Integrarea {platform} nu este încărcată. Vă rugăm să-i adăugați configurația dvs. fie adăugând 'default_config:' sau '{platform}:'.", + "required_error_msg": "Acest câmp este obligatoriu", + "yaml_not_editable": "Setările acestei entități nu se pot edita din interfața grafica. Numai entitățile configurate in interfața grafica sunt configurabile din interfața grafica." }, "more_info_control": { "dismiss": "Se respinge dialogul", @@ -723,11 +725,12 @@ }, "description": "Privire de ansamblu asupra tuturor zonelor din casa ta.", "editor": { - "create": "CREAȚI", - "delete": "ȘTERGEȚI", - "update": "ACTUALIZAȚI" + "create": "Creează", + "delete": "Șterge", + "update": "Actualizare" }, "picker": { + "create_area": "Creare zonă", "header": "Zone", "integrations_page": "Pagina de integrari", "introduction": "Zonele sunt folosite pentru a organiza unde sunt dispozitivele. Aceste informații vor fi utilizate de către Home Assistant pentru a vă ajuta să vă organizați interfața, permisiunile și integrarea cu alte sisteme.", @@ -851,7 +854,7 @@ "triggers": { "add": "Adăugați acțiune", "delete": "Ștergeți", - "delete_confirm": "Sigur doriți să ștergeți?", + "delete_confirm": "Sigur dorești să ștergi această intrare?", "duplicate": "Dublura", "header": "Declanșatoare", "introduction": "Declanșatoarele sunt cele ce încep procesarea unei reguli de automatizare. Este posibil să specificați mai multe declanșatoare pentru aceeași regulă. Odată ce începe declanșarea, Home Assistant o să valideze condițiile, dacă este cazul, și va apela acțiunea. \n\n [Aflați mai multe despre declanșatoare.] (https://home-assistant.io/docs/automation/trigger/)", @@ -1172,7 +1175,7 @@ "ignore": { "confirm_delete_ignore": "Acest lucru va face ca integrarea să apară din nou în integrările descoperite atunci când este descoperită. Acest lucru ar putea necesita o repornire sau să dureze ceva timp.", "confirm_delete_ignore_title": "Încetați să ignorați {name} ?", - "confirm_ignore": "Sunteți sigur că nu doriți să configurați această integrare? Puteți anula acest lucru făcând clic pe „Afișați integrări ignorate” din meniul de preaplin din partea dreaptă sus.", + "confirm_ignore": "Sunteți sigur că nu doriți să configurați această integrare? Puteți anula acest lucru făcând clic pe „Afișați integrări ignorate” din meniul overflow din partea dreaptă sus.", "confirm_ignore_title": "Ignorați descoperirea {name} ?", "hide_ignored": "Ascundeți integrările ignorate", "ignore": "Ignora", @@ -1194,6 +1197,7 @@ "lovelace": { "caption": "Panouri de bord Lovelace", "dashboards": { + "cant_edit_default": "Tabloul de bord standard Lovelace nu poate fi editat din UI. Îl puteți ascunde setând un alt tablou de bord ca implicit.", "cant_edit_yaml": "Tablourile de bord definite în YAML nu pot fi editate din UI. Schimbați-le în configuration.yaml.", "caption": "Tablouri de bord", "conf_mode": { @@ -1207,13 +1211,13 @@ "delete": "Șterge", "dismiss": "Închide", "edit_dashboard": "Editează tabloul de bord", - "icon": "Pictograma barei laterale", + "icon": "Pictograma", "new_dashboard": "Adăugați un nou tablou de bord", "remove_default": "Eliminare ca implicit pe acest dispozitiv", "require_admin": "Doar administrator", "set_default": "Setare ca implicită pe acest dispozitiv", "show_sidebar": "Afișați în bara laterală", - "title": "Titlul barei laterale", + "title": "Titlu", "title_required": "Titlul este necesar.", "update": "Actualizare", "url": "Url", @@ -1229,7 +1233,7 @@ "sidebar": "Afișați în bara laterală", "title": "Titlu" }, - "open": "Deschide tabloul de bord" + "open": "Deschide" } }, "resources": { @@ -1703,6 +1707,9 @@ "history-graph": { "description": "Fișa History Graph vă permite să afișați un grafic pentru fiecare dintre entitățile listate." }, + "iframe": { + "name": "Pagină web" + }, "light": { "description": "Cardul Light vă permite să schimbați luminozitatea luminii." }, @@ -1835,6 +1842,7 @@ "title": "Entități neutilizate" }, "views": { + "confirm_delete": "Ștergeți vizualizarea?", "confirm_delete_existing_cards": "Ștergerea acestei vizualizări va elimina și cardurile", "confirm_delete_text": "Sigur doriți să ștergeți vizualizarea „{name}”?" }, diff --git a/translations/frontend/sv.json b/translations/frontend/sv.json index e623659206..48ae93c4eb 100644 --- a/translations/frontend/sv.json +++ b/translations/frontend/sv.json @@ -473,11 +473,15 @@ } }, "common": { + "and": "och", "cancel": "Avbryt", "close": "Stäng", "delete": "Radera", "loading": "Läser in", + "next": "Nästa", "no": "Nej", + "previous": "Föregående", + "refresh": "Uppdatera", "save": "Spara", "successfully_deleted": "Har raderats", "successfully_saved": "Inställningar sparades", @@ -736,6 +740,10 @@ "triggered": "Utlöst {name}" }, "panel": { + "calendar": { + "my_calendars": "Mina Kalendrar", + "today": "Idag" + }, "config": { "advanced_mode": { "hint_enable": "Saknas konfigurationsalternativ? Aktivera avancerat läge på", @@ -838,6 +846,9 @@ }, "label": "Enhet" }, + "not": { + "label": "Inte" + }, "numeric_state": { "above": "Över", "below": "Under", @@ -1169,7 +1180,9 @@ "edit_requires_storage": "Redigeraren är inaktiverad eftersom konfigurationen lagras i configuration.yaml.", "elevation": "Höjd över havet", "elevation_meters": "meter", + "external_url": "Extern URL", "imperial_example": "Fahrenheit, pounds", + "internal_url": "Intern URL", "latitude": "Latitud", "location_name": "Namn på din Home Assistant-installation", "longitude": "Longitud", @@ -1236,6 +1249,7 @@ }, "delete": "Ta bort", "description": "Hantera anslutna enheter", + "device_info": "Enhetsinformation", "device_not_found": "Enheten hittades inte.", "entities": { "add_entities_lovelace": "Lägg till i Lovelace", @@ -2095,21 +2109,27 @@ "name": "Markdown" }, "media-control": { + "description": "Mediakontrolkortet används för att visa mediaspelarenheter på ett gränssnitt med lättanvända kontroller.", "name": "Mediaspelare" }, "picture-elements": { + "description": "Bildlementkortet är en av de mest mångsidiga typerna av kort. Korten låter dig placera ikoner eller text och till och med tjänster! På en bild baserad på koordinater.", "name": "Bildelement" }, "picture-entity": { + "description": "Bildentitetskortet visar en enhet i form av en bild. I stället för bilder från URL kan den också visa bilden av kameraenheter.", "name": "Bildentitet" }, "picture-glance": { + "description": "Picture Glance-kortet visar en bild och motsvarande enhetstillstånd som en ikon. Enheterna på höger sida tillåter att växla åtgärder, andra visar dialogrutan för mer information.", "name": "Bildblick" }, "picture": { + "description": "Bildkortet låter dig ställa in en bild som ska användas för att navigera till olika banor i ditt gränssnitt eller för att ringa en tjänst.", "name": "Bild" }, "plant-status": { + "description": "Plant Status-kortet är för alla de härliga botanikerna där ute.", "name": "Växtstatus" }, "sensor": { @@ -2125,6 +2145,7 @@ "name": "Termostat" }, "vertical-stack": { + "description": "Med Vertical Stack-kortet kan du gruppera flera kort så att de alltid sitter i samma kolumn.", "name": "Vertikal trave" }, "weather-forecast": { diff --git a/translations/frontend/zh-Hant.json b/translations/frontend/zh-Hant.json index b294c2d257..f1d15ae5a3 100644 --- a/translations/frontend/zh-Hant.json +++ b/translations/frontend/zh-Hant.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "及", "cancel": "取消", "close": "關閉", "delete": "刪除", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "由於 configuration.yaml 內已儲存設定,編輯功能已關閉。", "elevation": "海拔", "elevation_meters": "公尺", + "external_url": "外部 URL", "imperial_example": "華氏、磅", + "internal_url": "內部 URL", "latitude": "緯度", "location_name": "Home Assistant 安裝名稱", "longitude": "經度", From 79935b2d4cadd02e9f92c69867c22871fd5321a6 Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Mon, 11 May 2020 00:32:59 +0000 Subject: [PATCH 06/21] [ci skip] Translation update --- translations/frontend/hu.json | 3 +++ translations/frontend/pl.json | 3 +++ translations/frontend/pt.json | 3 +++ translations/frontend/ro.json | 29 ++++++++++++++++++++++++++++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/translations/frontend/hu.json b/translations/frontend/hu.json index 0f3e72c456..1def0024db 100644 --- a/translations/frontend/hu.json +++ b/translations/frontend/hu.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "És", "cancel": "Mégse", "close": "Bezárás", "delete": "Törlés", @@ -1181,6 +1182,7 @@ "elevation": "Magasság", "elevation_meters": "méter", "imperial_example": "Fahrenheit, font", + "internal_url": "Érvénytelen URL", "latitude": "Szélesség", "location_name": "A Home Assistant rendszered neve", "longitude": "Hosszúság", @@ -1247,6 +1249,7 @@ }, "delete": "Törlés", "description": "Csatlakoztatott eszközök kezelése", + "device_info": "Eszköz információ", "device_not_found": "Eszköz nem található.", "entities": { "add_entities_lovelace": "Hozzáadás a Lovelace-hez", diff --git a/translations/frontend/pl.json b/translations/frontend/pl.json index d58d4c8918..0a92cc0b82 100644 --- a/translations/frontend/pl.json +++ b/translations/frontend/pl.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "i", "cancel": "Anuluj", "close": "Zamknij", "delete": "Usuń", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "Edytor wyłączony, ponieważ konfiguracja jest przechowywana w pliku configuration.yaml.", "elevation": "Wysokość", "elevation_meters": "metry/-ów", + "external_url": "Publiczny adres URL", "imperial_example": "stopnie Fahrenheita, funty", + "internal_url": "Lokalny adres URL", "latitude": "Szerokość geograficzna", "location_name": "Nazwa instalacji Home Assistant", "longitude": "Długość geograficzna", diff --git a/translations/frontend/pt.json b/translations/frontend/pt.json index bd7d3b1133..c26711e8f1 100644 --- a/translations/frontend/pt.json +++ b/translations/frontend/pt.json @@ -1713,8 +1713,10 @@ "caption": "Grupos", "create": "Criar grupo", "create_group": "Zigbee Home Automation - Criar grupo", + "create_group_details": "Digite os detalhes necessários para criar um novo grupo zigbee", "creating_group": "Criação de grupo", "description": "Criar e modificar grupos Zigbee", + "group_details": "Aqui estão todos os detalhes do grupo Zigbee selecionado.", "group_id": "ID do grupo", "group_info": "Informações sobre o grupo", "group_name_placeholder": "Nome do Grupo", @@ -1722,6 +1724,7 @@ "group-header": "Zigbee Home Automation - Detalhes do grupo", "groups": "Grupos", "groups-header": "Zigbee Home Automation - Gestão de Grupos", + "header": "Zigbee Home Automation - Gestão de Grupos", "introduction": "Criar e modificar grupos zigbee", "manage_groups": "Gerir Grupos Zigbee", "members": "Membros", diff --git a/translations/frontend/ro.json b/translations/frontend/ro.json index ee5ae14f53..f570ef5f49 100644 --- a/translations/frontend/ro.json +++ b/translations/frontend/ro.json @@ -459,17 +459,20 @@ } }, "common": { + "and": "Și", "cancel": "Revocare", "close": "Închide", "delete": "Șterge", "loading": "Se încarcă", "next": "Următorul", + "no": "Nu", "previous": "Anterior", "refresh": "Reîmprospătare", "save": "Salvați", "successfully_deleted": "Șters cu succes", "successfully_saved": "Opțiunile salvate cu succes.", - "undo": "Undo" + "undo": "Undo", + "yes": "Da" }, "components": { "area-picker": { @@ -536,6 +539,9 @@ "title": "Opțiuni de sistem pentru {integration}", "update": "Actualizare" }, + "domain_toggler": { + "title": "Comutare domenii" + }, "entity_registry": { "control": "Control", "dismiss": "Ascunde", @@ -574,6 +580,7 @@ "time": "Timp" }, "input_number": { + "box": "Introdu textul", "max": "Valoare maximă", "min": "Valoare minimă", "mode": "Mod de afișare", @@ -592,6 +599,7 @@ "min": "Lungime minimă", "mode": "Mod de afișare", "password": "Parola", + "pattern": "Modelul Regex pentru validarea de partea clientului", "text": "Text" }, "platform_not_loaded": "Integrarea {platform} nu este încărcată. Vă rugăm să-i adăugați configurația dvs. fie adăugând 'default_config:' sau '{platform}:'.", @@ -655,6 +663,10 @@ } }, "voice_command": { + "did_not_hear": "Home Assistant nu a auzit nimic", + "error": "Oops, a apărut o eroare", + "found": "Am găsit următoarele pentru tine:", + "how_can_i_help": "Cu ce vă pot ajuta?", "label": "Scrieți o întrebare și apăsați „Enter”", "label_voice": "Tastați și apăsați „Enter” sau atingeți microfonul pentru a vorbi" }, @@ -997,14 +1009,22 @@ } }, "customize": { + "attributes_customize": "Următoarele atribute sunt deja setate în customize.yaml", "attributes_not_set": "Următoarele atribute nu au fost setate. Setați-le dacă doriți.", + "attributes_outside": "Următoarele atribute sunt personalizate din afara customize.yaml", "attributes_override": "Poți să le suprascrii dacă vrei.", + "attributes_set": "Următoarele atribute ale entității sunt setate programatic.", "caption": "Personalizare", "description": "Personalizați-vă entitățile", + "different_include": "Posibil printr-un domeniu, un glob sau alta includere", "pick_attribute": "Alegeți un atribut pentru suprascriere", "picker": { "header": "Personalizări", "introduction": "Atributele per entitate. Particularizările adăugate/editate vor avea efect imediat. Particularizările eliminate vor avea efect atunci când entitatea este actualizată." + }, + "warning": { + "include_link": "include customize.yaml", + "include_sentence": "Se pare că configurația dvs..yaml nu corespunde" } }, "devices": { @@ -1317,6 +1337,7 @@ }, "learn_more": "Aflați mai multe despre scene", "no_scenes": "Nu am putut găsi nici o scenă editabilă", + "only_editable": "Numai scenele definite în scene.yaml sunt editabile.", "pick_scene": "Alege scena pentru a edita", "show_info_scene": "Afișează informații despre scenă" } @@ -1551,7 +1572,13 @@ "developer-tools": { "tabs": { "events": { + "alert_event_type": "Tipul de eveniment este un câmp obligatoriu", "available_events": "Evenimente disponibile", + "fire_event": "Declansare eveniment", + "listening_to": "Ascultand", + "start_listening": "Incepe sa asculti", + "stop_listening": "Nu mai asculta", + "subscribe_to": "Eveniment la care să vă abonați", "title": "Evenimente" }, "info": { From cf575f83f5e514e6eac439072812e4b7e2a14926 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Mon, 11 May 2020 07:44:15 -0400 Subject: [PATCH 07/21] Weather Card: Switch State and Name (#5795) --- .../lovelace/cards/hui-weather-forecast-card.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index 2d9adf3356..576b908636 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -182,9 +182,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
-
- ${this._config.name || computeStateName(stateObj)} -
${computeStateDisplay( this.hass.localize, @@ -192,6 +189,9 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { this.hass.language )}
+
+ ${this._config.name || computeStateName(stateObj)} +
@@ -377,13 +377,13 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { top: 1px; } - .name, + .state, .temp-attribute .temp { font-size: 28px; line-height: 1.2; } - .state, + .name, .attribute { font-size: 14px; line-height: 1; @@ -440,7 +440,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { .attribute, .templow, - .state { + .name { color: var(--secondary-text-color); } @@ -469,7 +469,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { --mdc-icon-size: 52px; } - :host([narrow]) .name, + :host([narrow]) .state, :host([narrow]) .temp-attribute .temp { font-size: 22px; } @@ -485,7 +485,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { /* ============= VERY NARROW ============= */ - :host([veryNarrow]) .state, + :host([veryNarrow]) .name, :host([veryNarrow]) .attribute { display: none; } From 2d627819d973ba76c28f2880426af18c03bcdf18 Mon Sep 17 00:00:00 2001 From: Mat Strange <54028700+matstrange@users.noreply.github.com> Date: Mon, 11 May 2020 12:44:32 +0100 Subject: [PATCH 08/21] Added translation to dev-tools-info-integrations (#5834) --- .../developer-tools/info/integrations-card.ts | 14 +++++++++++--- src/translations/en.json | 5 ++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/panels/developer-tools/info/integrations-card.ts b/src/panels/developer-tools/info/integrations-card.ts index 1c9c9761ba..3b2ecd8030 100644 --- a/src/panels/developer-tools/info/integrations-card.ts +++ b/src/panels/developer-tools/info/integrations-card.ts @@ -34,7 +34,11 @@ class IntegrationsCard extends LitElement { protected render(): TemplateResult { return html` - + ${this._sortedIntegrations(this.hass!.config.components).map( @@ -62,7 +66,9 @@ class IntegrationsCard extends LitElement { target="_blank" rel="noreferrer" > - Documentation + ${this.hass.localize( + "ui.panel.developer-tools.tabs.info.documentation" + )} ${!manifest.is_built_in @@ -74,7 +80,9 @@ class IntegrationsCard extends LitElement { target="_blank" rel="noreferrer" > - Issues + ${this.hass.localize( + "ui.panel.developer-tools.tabs.info.issues" + )} `} diff --git a/src/translations/en.json b/src/translations/en.json index 71557cfd2a..eee160588a 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2186,7 +2186,10 @@ "icons_by": "Icons by", "frontend_version": "Frontend version: {version} - {type}", "custom_uis": "Custom UIs:", - "system_health_error": "System Health component is not loaded. Add 'system_health:' to configuration.yaml" + "system_health_error": "System Health component is not loaded. Add 'system_health:' to configuration.yaml", + "integrations": "Integrations", + "documentation": "Documentation", + "issues": "Issues" }, "logs": { "title": "Logs", From 60be14dc7791576ff897949aeeabdfa5d0d8d820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 11 May 2020 13:45:00 +0200 Subject: [PATCH 09/21] Use manifest.issue_tracker for issues URL if not built_in (#5818) --- src/data/integration.ts | 6 +++++- .../developer-tools/info/integrations-card.ts | 13 ++++++++----- .../logs/dialog-system-log-detail.ts | 14 +++++++++----- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/data/integration.ts b/src/data/integration.ts index ce0bf07fb5..8a59d2d4d7 100644 --- a/src/data/integration.ts +++ b/src/data/integration.ts @@ -18,7 +18,11 @@ export interface IntegrationManifest { quality_scale?: string; } -export const integrationIssuesUrl = (domain: string) => +export const integrationIssuesUrl = ( + domain: string, + manifest: IntegrationManifest +) => + manifest.issue_tracker || `https://github.com/home-assistant/home-assistant/issues?q=is%3Aissue+is%3Aopen+label%3A%22integration%3A+${domain}%22`; export const domainToName = (localize: LocalizeFunc, domain: string) => diff --git a/src/panels/developer-tools/info/integrations-card.ts b/src/panels/developer-tools/info/integrations-card.ts index 3b2ecd8030..6dd26b38ba 100644 --- a/src/panels/developer-tools/info/integrations-card.ts +++ b/src/panels/developer-tools/info/integrations-card.ts @@ -71,12 +71,14 @@ class IntegrationsCard extends LitElement { )} - ${!manifest.is_built_in - ? "" - : html` + ${manifest.is_built_in || manifest.issue_tracker + ? html` - `} + ` + : ""} `} `; diff --git a/src/panels/developer-tools/logs/dialog-system-log-detail.ts b/src/panels/developer-tools/logs/dialog-system-log-detail.ts index f799ec0475..7db4d653c2 100644 --- a/src/panels/developer-tools/logs/dialog-system-log-detail.ts +++ b/src/panels/developer-tools/logs/dialog-system-log-detail.ts @@ -84,15 +84,19 @@ class DialogSystemLogDetail extends LitElement { target="_blank" rel="noreferrer" >documentation${!this._manifest.is_built_in - ? "" - : html`, + >${this._manifest.is_built_in || + this._manifest.issue_tracker + ? html`, issues`}) + >` + : ""}) `} ` : ""} From 6d0823328dd19ec6edff46cd41b9435a14301518 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 11 May 2020 10:28:05 -0700 Subject: [PATCH 10/21] Fix generated Lovelace translating domain names (#5803) --- .../integrations/ha-config-integrations.ts | 3 +- .../common/generate-lovelace-config.ts | 5 ++-- src/panels/lovelace/ha-panel-lovelace.ts | 6 ++-- src/state/translations-mixin.ts | 29 ++++++++++++------- src/types.ts | 2 +- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/panels/config/integrations/ha-config-integrations.ts b/src/panels/config/integrations/ha-config-integrations.ts index 5cf93900db..9fb6aa140d 100644 --- a/src/panels/config/integrations/ha-config-integrations.ts +++ b/src/panels/config/integrations/ha-config-integrations.ts @@ -60,6 +60,7 @@ import type { import { HASSDomEvent } from "../../../common/dom/fire_event"; import "../../../components/ha-svg-icon"; import { mdiPlus } from "@mdi/js"; +import { LocalizeFunc } from "../../../common/translations/localize"; interface DataEntryFlowProgressExtended extends DataEntryFlowProgress { localized_title?: string; @@ -121,7 +122,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { this._deviceRegistryEntries = entries; }), subscribeConfigFlowInProgress(this.hass, async (flowsInProgress) => { - const translationsPromisses: Promise[] = []; + const translationsPromisses: Promise[] = []; flowsInProgress.forEach((flow) => { // To render title placeholders if (flow.context.title_placeholders) { diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts index 80d5230bb6..2e80710fcb 100644 --- a/src/panels/lovelace/common/generate-lovelace-config.ts +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -465,7 +465,8 @@ export const generateLovelaceConfigFromData = async ( }; export const generateLovelaceConfigFromHass = async ( - hass: HomeAssistant + hass: HomeAssistant, + localize?: LocalizeFunc ): Promise => { // We want to keep the registry subscriptions alive after generating the UI // so that we don't serve up stale data after changing areas. @@ -488,6 +489,6 @@ export const generateLovelaceConfigFromHass = async ( deviceEntries, entityEntries, hass.states, - hass.localize + localize || hass.localize ); }; diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index 16a0054c92..0e802519ce 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -288,7 +288,8 @@ class LovelacePanel extends LitElement { this._errorMsg = err.message; return; } - conf = await generateLovelaceConfigFromHass(this.hass!); + const localize = await this.hass!.loadBackendTranslation("title"); + conf = await generateLovelaceConfigFromHass(this.hass!, localize); confMode = "generated"; } finally { // Ignore updates for another 2 seconds. @@ -370,8 +371,9 @@ class LovelacePanel extends LitElement { const { config: previousConfig, mode: previousMode } = this.lovelace!; try { // Optimistic update + const localize = await this.hass!.loadBackendTranslation("title"); this._updateLovelace({ - config: await generateLovelaceConfigFromHass(this.hass!), + config: await generateLovelaceConfigFromHass(this.hass!, localize), mode: "generated", editMode: false, }); diff --git a/src/state/translations-mixin.ts b/src/state/translations-mixin.ts index 345f0d13d6..215752dfa8 100644 --- a/src/state/translations-mixin.ts +++ b/src/state/translations-mixin.ts @@ -1,5 +1,5 @@ import { atLeastVersion } from "../common/config/version"; -import { computeLocalize } from "../common/translations/localize"; +import { computeLocalize, LocalizeFunc } from "../common/translations/localize"; import { computeRTL } from "../common/util/compute_rtl"; import { debounce } from "../common/util/debounce"; import { @@ -104,29 +104,37 @@ export default >(superClass: T) => this._loadFragmentTranslations(hass.language, hass.panelUrl); } + /** + * Load translations from the backend + * @param language language to fetch + * @param category category to fetch + * @param integration optional, if having to fetch for specific integration + * @param configFlow optional, if having to fetch for all integrations with a config flow + * @param force optional, load even if already cached + */ private async _loadHassTranslations( language: string, category: Parameters[2], integration?: Parameters[3], configFlow?: Parameters[4], force = false - ) { + ): Promise { if ( __BACKWARDS_COMPAT__ && !atLeastVersion(this.hass!.connection.haVersion, 0, 109) ) { if (category !== "state") { - return; + return this.hass!.localize; } const resources = await getHassTranslationsPre109(this.hass!, language); // Ignore the repsonse if user switched languages before we got response if (this.hass!.language !== language) { - return; + return this.hass!.localize; } this._updateResources(language, resources); - return; + return this.hass!.localize; } let alreadyLoaded: LoadedTranslationCategory; @@ -145,12 +153,12 @@ export default >(superClass: T) => if (!force) { if (integration) { if (alreadyLoaded.integrations.includes(integration)) { - return; + return this.hass!.localize; } } else if ( configFlow ? alreadyLoaded.configFlow : alreadyLoaded.setup ) { - return; + return this.hass!.localize; } } @@ -176,10 +184,11 @@ export default >(superClass: T) => // Ignore the repsonse if user switched languages before we got response if (this.hass!.language !== language) { - return; + return this.hass!.localize; } this._updateResources(language, resources); + return this.hass!.localize; } private async _loadFragmentTranslations( @@ -214,9 +223,7 @@ export default >(superClass: T) => // multiple fragments. const resources = { [language]: { - ...(this.hass && - this.hass.resources && - this.hass.resources[language]), + ...this.hass?.resources?.[language], ...data, }, }; diff --git a/src/types.ts b/src/types.ts index 95033824a5..2f7493f4b8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -224,7 +224,7 @@ export interface HomeAssistant { category: Parameters[2], integration?: Parameters[3], configFlow?: Parameters[4] - ): Promise; + ): Promise; } export type LightEntity = HassEntityBase & { From c861ee025e7d2614536d08245cd7dcaddceefd2e Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Mon, 11 May 2020 16:11:48 -0400 Subject: [PATCH 11/21] Weather Card: Ability to choose Secondary Attribute (#5820) --- .../cards/hui-weather-forecast-card.ts | 15 ++++++++- src/panels/lovelace/cards/types.ts | 1 + .../hui-weather-forecast-card-editor.ts | 31 +++++++++++++++---- src/translations/en.json | 6 ++-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index 576b908636..76688e0c56 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -200,7 +200,20 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { >
- ${getSecondaryWeatherAttribute(this.hass, stateObj)} + ${this._config.secondary_info_attribute !== undefined + ? html` + ${this.hass!.localize( + `ui.card.weather.attributes.${this._config.secondary_info_attribute}` + )} + ${stateObj.attributes[ + this._config.secondary_info_attribute + ]} + ${getWeatherUnit( + this.hass, + this._config.secondary_info_attribute + )} + ` + : getSecondaryWeatherAttribute(this.hass, stateObj)}
diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index 5dd1c46ac1..1d3fbea65b 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -275,4 +275,5 @@ export interface WeatherForecastCardConfig extends LovelaceCardConfig { entity: string; name?: string; show_forecast?: boolean; + secondary_info_attribute?: string; } 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 e4f9ab4815..3ec4e4397f 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 @@ -22,6 +22,7 @@ const cardConfigStruct = struct({ name: "string?", theme: "string?", show_forecast: "boolean?", + secondary_info_attribute: "string?", }); const includeDomains = ["weather"]; @@ -54,6 +55,10 @@ export class HuiWeatherForecastCardEditor extends LitElement return this._config!.show_forecast || true; } + get _secondary_info_attribute(): string { + return this._config!.secondary_info_attribute || ""; + } + protected render(): TemplateResult { if (!this.hass || !this._config) { return html``; @@ -93,12 +98,26 @@ export class HuiWeatherForecastCardEditor extends LitElement @value-changed=${this._valueChanged} > - Show forecast +
+ + ${this.hass.localize( + "ui.panel.lovelace.editor.card.weather.show_forecast" + )} +
`; } diff --git a/src/translations/en.json b/src/translations/en.json index eee160588a..18d2068be9 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1841,7 +1841,8 @@ "no_theme": "No theme", "unit": "Unit", "url": "Url", - "state": "State" + "state": "State", + "secondary_info_attribute": "Secondary Info Attribute" }, "map": { "name": "Map", @@ -1902,7 +1903,8 @@ }, "weather-forecast": { "name": "Weather Forecast", - "description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall." + "description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.", + "show_forecast": "Show Forecast" } }, "view": { From ebbe7e805f3a11de77c7ed03670b1251f5548b0b Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Mon, 11 May 2020 17:14:02 -0400 Subject: [PATCH 12/21] Gauge Card: Convert to Round Slider (#5510) * Use round slider for gauge * Update guage to slider * Add severity back * Remove Base Unit * fix merge * resize observer * Update src/panels/lovelace/cards/hui-gauge-card.ts Co-authored-by: Bram Kragten * Update Install Resize Observer to be a helper * Type import * Reviews * Updates to other cards Co-authored-by: Bram Kragten --- package.json | 2 +- src/panels/lovelace/cards/hui-gauge-card.ts | 231 ++++++++++-------- .../lovelace/cards/hui-media-control-card.ts | 17 +- .../cards/hui-weather-forecast-card.ts | 20 +- .../common/install-resize-observer.ts | 6 + .../hui-media-player-entity-row.ts | 19 +- yarn.lock | 8 +- 7 files changed, 161 insertions(+), 142 deletions(-) create mode 100644 src/panels/lovelace/common/install-resize-observer.ts diff --git a/package.json b/package.json index e1c47e9cf3..d5f286178b 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@polymer/paper-toast": "^3.0.1", "@polymer/paper-tooltip": "^3.0.1", "@polymer/polymer": "3.1.0", - "@thomasloven/round-slider": "0.3.7", + "@thomasloven/round-slider": "0.4.1", "@vaadin/vaadin-combo-box": "^5.0.10", "@vaadin/vaadin-date-picker": "^4.0.7", "@webcomponents/shadycss": "^1.9.0", diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index c2e24d6d00..9378f4da0f 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -10,17 +10,21 @@ import { TemplateResult, } from "lit-element"; import { styleMap } from "lit-html/directives/style-map"; +import "@thomasloven/round-slider"; + import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { isValidEntityId } from "../../../common/entity/valid_entity_id"; import "../../../components/ha-card"; -import { HomeAssistant } from "../../../types"; +import type { HomeAssistant } from "../../../types"; import { findEntities } from "../common/find-entites"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../components/hui-warning"; -import { LovelaceCard, LovelaceCardEditor } from "../types"; -import { GaugeCardConfig } from "./types"; +import type { LovelaceCard, LovelaceCardEditor } from "../types"; +import type { GaugeCardConfig } from "./types"; +import { debounce } from "../../../common/util/debounce"; +import { installResizeObserver } from "../common/install-resize-observer"; export const severityMap = { red: "var(--label-badge-red)", @@ -63,11 +67,20 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { @property() public hass?: HomeAssistant; - @property() private _baseUnit = "50px"; - @property() private _config?: GaugeCardConfig; - private _updated?: boolean; + private _resizeObserver?: ResizeObserver; + + public connectedCallback(): void { + super.connectedCallback(); + this.updateComplete.then(() => this._attachObserver()); + } + + public disconnectedCallback(): void { + if (this._resizeObserver) { + this._resizeObserver.disconnect(); + } + } public getCardSize(): number { return 2; @@ -83,11 +96,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { this._config = { min: 0, max: 100, ...config }; } - public connectedCallback(): void { - super.connectedCallback(); - this._setBaseUnit(); - } - protected render(): TemplateResult { if (!this._config || !this.hass) { return html``; @@ -121,33 +129,32 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { `; } + const sliderBarColor = this._computeSeverity(state); + return html` -
-
-
-
-
+
-
+
${stateObj.state} ${this._config.unit || stateObj.attributes.unit_of_measurement || ""}
-
+
${this._config.name || computeStateName(stateObj)}
@@ -160,10 +167,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { } protected firstUpdated(): void { - this._updated = true; - this._setBaseUnit(); - // eslint-disable-next-line wc/no-self-class - this.classList.add("init"); + this._attachObserver(); } protected updated(changedProps: PropertyValues): void { @@ -187,16 +191,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { } } - private _setBaseUnit(): void { - if (!this.isConnected || !this._updated) { - return; - } - const baseUnit = this._computeBaseUnit(); - if (baseUnit !== "0px") { - this._baseUnit = baseUnit; - } - } - private _computeSeverity(numberValue: number): string { const sections = this._config!.severity; @@ -229,95 +223,122 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { return severityMap.normal; } - private _translateTurn(value: number): number { - const { min, max } = this._config!; - const maxTurnValue = Math.min(Math.max(value, min!), max!); - return (5 * (maxTurnValue - min!)) / (max! - min!) / 10; - } - - private _computeBaseUnit(): string { - return this.clientWidth < 200 ? this.clientWidth / 5 + "px" : "50px"; - } - private _handleClick(): void { fireEvent(this, "hass-more-info", { entityId: this._config!.entity }); } + private async _attachObserver(): Promise { + await installResizeObserver(); + + this._resizeObserver = new ResizeObserver( + debounce(() => this._measureCard(), 250, false) + ); + + const card = this.shadowRoot!.querySelector("ha-card"); + // If we show an error or warning there is no ha-card + if (!card) { + return; + } + this._resizeObserver.observe(card); + } + + private _measureCard() { + if (this.offsetWidth < 200) { + this.setAttribute("narrow", ""); + } else { + this.removeAttribute("narrow"); + } + if (this.offsetWidth < 150) { + this.setAttribute("veryNarrow", ""); + } else { + this.removeAttribute("veryNarrow"); + } + } + static get styles(): CSSResult { return css` ha-card { cursor: pointer; - padding: 16px 16px 0 16px; height: 100%; + overflow: hidden; + padding: 16px 16px 0 16px; display: flex; + align-items: center; + justify-content: center; flex-direction: column; box-sizing: border-box; - justify-content: center; - align-items: center; } + ha-card:focus { outline: none; background: var(--divider-color); } - .container { - width: calc(var(--base-unit) * 4); - height: calc(var(--base-unit) * 2); - overflow: hidden; - position: relative; - } - .gauge-a { - position: absolute; - background-color: var(--primary-background-color); - width: calc(var(--base-unit) * 4); - height: calc(var(--base-unit) * 2); - top: 0%; - border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5) - 0px 0px; - } - .gauge-b { - position: absolute; - background-color: var(--paper-card-background-color); - width: calc(var(--base-unit) * 2.5); - height: calc(var(--base-unit) * 1.25); - top: calc(var(--base-unit) * 0.75); - margin-left: calc(var(--base-unit) * 0.75); - margin-right: auto; - border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5) - 0px 0px; - } - .gauge-c { - position: absolute; - background-color: var(--label-badge-blue); - width: calc(var(--base-unit) * 4); - height: calc(var(--base-unit) * 2); - top: calc(var(--base-unit) * 2); - margin-left: auto; - margin-right: auto; - border-radius: 0px 0px calc(var(--base-unit) * 2) - calc(var(--base-unit) * 2); - transform-origin: center top; - } - .init .gauge-c { - transition: all 1.3s ease-in-out; + + round-slider { + max-width: 200px; + --round-slider-path-width: 35px; + --round-slider-path-color: var(--disabled-text-color); + --round-slider-linecap: "butt"; } + .gauge-data { + line-height: 1; text-align: center; - color: var(--primary-text-color); - line-height: calc(var(--base-unit) * 0.3); - width: 100%; position: relative; - top: calc(var(--base-unit) * -0.5); + color: var(--primary-text-color); + margin-top: -28px; + margin-bottom: 14px; } - .init .gauge-data { - transition: all 1s ease-out; + + .gauge-data .percent { + font-size: 28px; } - .gauge-data #percent { - font-size: calc(var(--base-unit) * 0.55); - line-height: calc(var(--base-unit) * 0.55); + + .gauge-data .name { + padding-top: 6px; + font-size: 14px; } - .gauge-data #name { - padding-top: calc(var(--base-unit) * 0.15); - font-size: calc(var(--base-unit) * 0.3); + + /* ============= NARROW ============= */ + + :host([narrow]) round-slider { + --round-slider-path-width: 22px; + } + + :host([narrow]) .gauge-data { + margin-top: -24px; + margin-bottom: 12px; + } + + :host([narrow]) .gauge-data .percent { + font-size: 24px; + } + + :host([narrow]) .gauge-data .name { + font-size: 12px; + } + + /* ============= VERY NARROW ============= */ + + :host([veryNarrow]) round-slider { + --round-slider-path-width: 15px; + } + + :host([veryNarrow]) ha-card { + padding-bottom: 16px; + } + + :host([veryNarrow]) .gauge-data { + margin-top: 0; + margin-bottom: 0; + } + + :host([veryNarrow]) .gauge-data .percent { + font-size: 20px; + } + + :host([veryNarrow]) .gauge-data .name { + font-size: 10px; } `; } diff --git a/src/panels/lovelace/cards/hui-media-control-card.ts b/src/panels/lovelace/cards/hui-media-control-card.ts index f417ed131b..9e66390f5b 100644 --- a/src/panels/lovelace/cards/hui-media-control-card.ts +++ b/src/panels/lovelace/cards/hui-media-control-card.ts @@ -46,6 +46,7 @@ import "../components/hui-marquee"; import type { LovelaceCard, LovelaceCardEditor } from "../types"; import "../components/hui-warning"; import { MediaControlCardConfig } from "./types"; +import { installResizeObserver } from "../common/install-resize-observer"; function getContrastRatio( rgb1: [number, number, number], @@ -223,7 +224,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { public connectedCallback(): void { super.connectedCallback(); - this.updateComplete.then(() => this._measureCard()); + this.updateComplete.then(() => this._attachObserver()); if (!this.hass || !this._config) { return; @@ -252,6 +253,9 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { clearInterval(this._progressInterval); this._progressInterval = undefined; } + if (this._resizeObserver) { + this._resizeObserver.disconnect(); + } } protected render(): TemplateResult { @@ -624,15 +628,8 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { this._cardHeight = card.offsetHeight; } - private _attachObserver(): void { - if (typeof ResizeObserver !== "function") { - import("resize-observer").then((modules) => { - modules.install(); - this._attachObserver(); - }); - return; - } - + private async _attachObserver(): Promise { + await installResizeObserver(); this._resizeObserver = new ResizeObserver( debounce(() => this._measureCard(), 250, false) ); diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index 76688e0c56..8fa9356417 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -31,6 +31,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../components/hui-warning"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { WeatherForecastCardConfig } from "./types"; +import { installResizeObserver } from "../common/install-resize-observer"; const DAY_IN_MILLISECONDS = 86400000; @@ -72,7 +73,13 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { public connectedCallback(): void { super.connectedCallback(); - this.updateComplete.then(() => this._measureCard()); + this.updateComplete.then(() => this._attachObserver()); + } + + public disconnectedCallback(): void { + if (this._resizeObserver) { + this._resizeObserver.disconnect(); + } } public getCardSize(): number { @@ -299,15 +306,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { fireEvent(this, "hass-more-info", { entityId: this._config!.entity }); } - private _attachObserver(): void { - if (typeof ResizeObserver !== "function") { - import("resize-observer").then((modules) => { - modules.install(); - this._attachObserver(); - }); - return; - } - + private async _attachObserver(): Promise { + await installResizeObserver(); this._resizeObserver = new ResizeObserver( debounce(() => this._measureCard(), 250, false) ); diff --git a/src/panels/lovelace/common/install-resize-observer.ts b/src/panels/lovelace/common/install-resize-observer.ts new file mode 100644 index 0000000000..f675858d99 --- /dev/null +++ b/src/panels/lovelace/common/install-resize-observer.ts @@ -0,0 +1,6 @@ +export const installResizeObserver = async () => { + if (typeof ResizeObserver !== "function") { + const modules = await import("resize-observer"); + modules.install(); + } +}; diff --git a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts index ed2e230f90..3792aef585 100644 --- a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts @@ -31,6 +31,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../components/hui-generic-entity-row"; import "../components/hui-warning"; import { EntityConfig, LovelaceRow } from "./types"; +import { installResizeObserver } from "../common/install-resize-observer"; @customElement("hui-media-player-entity-row") class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow { @@ -209,19 +210,13 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow { } private _attachObserver(): void { - if (typeof ResizeObserver !== "function") { - import("resize-observer").then((modules) => { - modules.install(); - this._attachObserver(); - }); - return; - } + installResizeObserver().then(() => { + this._resizeObserver = new ResizeObserver(() => + this._debouncedResizeListener() + ); - this._resizeObserver = new ResizeObserver(() => - this._debouncedResizeListener() - ); - - this._resizeObserver.observe(this); + this._resizeObserver.observe(this); + }); } private _computeControlIcon(stateObj: HassEntity): string { diff --git a/yarn.lock b/yarn.lock index 69e66b6ce9..c33003fb3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2613,10 +2613,10 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== -"@thomasloven/round-slider@0.3.7": - version "0.3.7" - resolved "https://registry.yarnpkg.com/@thomasloven/round-slider/-/round-slider-0.3.7.tgz#3f8f16f90296e1062d932f5ea8ebf244aa7e58f6" - integrity sha512-rIdEvyLt4YNahpAp1Ibk7qOn9mdgP3Qo2gORyojHqaBTV+t29N1zlTo/G0SbKTLDUtSGDslQWD3/nAdD3yBOYA== +"@thomasloven/round-slider@0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@thomasloven/round-slider/-/round-slider-0.4.1.tgz#42ddd28abb25c378dce35c4c0ccdd72ea63b3b25" + integrity sha512-Z6jrXG5vowKQkOwdsyGDLi8ZT9lUfcYjFsaQe8djhDE8+x41GYp5lkJ4uCwT787A8WcODbtQfYtuxPOlZcizTw== dependencies: lit-element "^2.2.1" From 466a1af902e1492cb226b1acdba174ad5c135d33 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Mon, 11 May 2020 17:58:17 -0400 Subject: [PATCH 13/21] Weather Card/Row: Weather Icons as SVG, Themeable, user definable (#5736) * SVG * no-unneeded-ternary * declared ubnused * moving stuff around * Few updates * All svgs in | update row * No slots * Remove public/static/images/weather * style for user defined * few updates to missing fils * classes * wind color --- public/static/images/weather/cloudy.png | Bin 655 -> 0 bytes .../static/images/weather/lightning-rainy.png | Bin 888 -> 0 bytes public/static/images/weather/lightning.png | Bin 807 -> 0 bytes public/static/images/weather/night.png | Bin 639 -> 0 bytes .../static/images/weather/partly-cloudy.png | Bin 1130 -> 0 bytes public/static/images/weather/pouring.png | Bin 840 -> 0 bytes public/static/images/weather/rainy.png | Bin 798 -> 0 bytes public/static/images/weather/snowy.png | Bin 1140 -> 0 bytes public/static/images/weather/sunny.png | Bin 487 -> 0 bytes public/static/images/weather/windy.png | Bin 774 -> 0 bytes src/data/weather.ts | 240 +++++++++++- .../cards/hui-weather-forecast-card.ts | 366 +++++++++--------- .../entity-rows/hui-weather-entity-row.ts | 169 ++++++-- 13 files changed, 528 insertions(+), 247 deletions(-) delete mode 100644 public/static/images/weather/cloudy.png delete mode 100644 public/static/images/weather/lightning-rainy.png delete mode 100644 public/static/images/weather/lightning.png delete mode 100644 public/static/images/weather/night.png delete mode 100644 public/static/images/weather/partly-cloudy.png delete mode 100644 public/static/images/weather/pouring.png delete mode 100644 public/static/images/weather/rainy.png delete mode 100644 public/static/images/weather/snowy.png delete mode 100644 public/static/images/weather/sunny.png delete mode 100644 public/static/images/weather/windy.png diff --git a/public/static/images/weather/cloudy.png b/public/static/images/weather/cloudy.png deleted file mode 100644 index 1277a7ad6762ddcd4016a68f8715c4486d03ffdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 655 zcmV;A0&x9_P)dYq+ow}uL(>y4l=Y^!jl+lhT~a{!4zkA>ji@JVsFRk+dC*P10CGLy&Hqki694{@( zNi-Vig=L&!>7>4;1^e`!j4Exsg~A>?kl)Ti1_PBY&%zs8sN3nCL8*T2SXi+jc#gjd zxpDqs61P(5;xkCX`Jmr@p0F&iP%OuwuiP!fr{7Vfi5^Po-dD?j1n^`a!qTm=Q-y!U zJ7ItXU_rf*f6G6l!m{^+A`V8?gusHZ(?VFt!+@56(FlPBw*hp1f-O|xWg}J@XlMDs z%z%vqCJT=1IB&o8EN-VT>L~zU2GzX%y+PVa0Z&FNMA$J0QZ!%*17j{|X^3MI?ym2? zVVQxRf;|_!GcpMw&#k_ pF`zLDG=)J1vcV`A1*2dT007w2^2~>{w{ZXf002ovPDHLkV1i-yHQoRK diff --git a/public/static/images/weather/lightning-rainy.png b/public/static/images/weather/lightning-rainy.png deleted file mode 100644 index 07f78b6c6ff6d9f9b1f2e29cc880acba8520a3ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 888 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!<_GwMxB}^yc)_bzuYmGz-n@aU zdiU<#hYugVeEIV8=g+@?|9=1e{rB(R|Ns973IZ7rHiQ8rKmGjk?bjb5`0?Y%`}gk+ zHvcCHX>3@y4CqADk|4ie1_g(J1t0!jn2_+`fPj9(h613SV6Y!hQ$-*)f&Z#->- zv5Ci~D|YLOpSiIA$e(nj(f*6Fu*WB*#`|GmFILxYb`N?Sc=15(+5?;S{M`L9hROb4 znNx702V=R2#55-TgB?;8lE=0j5RwS~z%H>^>p_Xcb%w>qqF=4q)8oa}xIOh`W<~#= z6Rgr7wm;2%!O(Nr=DhGGmukzpDP1on`tOife^uYuXw|clx+R}7Q$#jou;gtqJaxRx z4DY$S5`Kca%T0g^-TH|Uly^WC8HsR#X92E0%gX}MmBd2 z7IHpLb#P@BQ@hf*tT1+AQ%~3d(;e?NeBBY#%Hy@2^@_r^gBvTt)=e**rg8_UB96uJ zJSXdnZoWHr-!Lc$ny?Dp?JjO?i+d6%w5)m0j_%b`s)^SU?eZBjKSkbqk#OumzW?Ox zZHIR{+&!?Y@$lE%2|o#EuA*^d^ODP$bom{j8a;=qLD<<_PdRw5^MEoZFI zJhJa3f6y8~>9hj|yV%P8bg=d#Wzp$Pz9MBsq{ diff --git a/public/static/images/weather/lightning.png b/public/static/images/weather/lightning.png deleted file mode 100644 index a6aaed9a0c68831d4352c622dd8957dad6a135a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 807 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!rUm$fxB}^yIKZ1XZ!l%vzJ2@o z^XK2cfB*ga_y7O@-@ktcs(}dp`t=Ja2$TYf1KB_l2>P%6k2&(c`W%RDu$fq-tvLNH z&}Bv?L4Lsu0tp)){68=uKz>2Pg@O+TAd~+8cli8xcl=%McX|fduO^uC-FRv_Z?|@8 zm~64fgp+rzFZwYsF!6c1IEGX(CN1D)C_VCuT$Ld@pB|E}NBD9zEi^*H+Q zAFkL|Y$Y79z4exxH|JNi?nR3=+j)Nl@Xz_ax8B{!S!i#Rv%k{eOkZZ^ zlXI@uJ2Z-NnHv6HZg5HG?mE5+wf6-?XG!O3`aF)f9JR~n@&08ob_vP8(Uy-j^*Jww zU;7f6Vjdy=S|aH}G4?kyiV zxvqb@aZpD)Myb){;3cM|R!4*%aQH;TsM|O`Ol;um;V)9(dg%N8!apvHzr@KMGj?bX zw`As+2my4ztpNlRF<+rkH;$;h$l# z!=c*9iO;f19G>;1t)8(+jgNsnQNE`ny04ittf+y-_U~*P3Hzoe48H{~{Swq$c78&6 zLoLUny@y2NE!qFrv-qC4u&U*~e4oH~MU|(mvp)R(`}Onp&s{@(-FFn1L zk=a0i*@08=~cOO3evBGBVeZA}3dH`;Hnlb1M0-2Q(8Xg*Lq$k@Lp@BTh@_y37|zd^R#{c{|w{p6j$C+_~%sqNbabdY{YkY6x^ zpuNvy9sbS#*C}1MdCO$>b<(q+Y=_S`EHo~N^G|PE9V*?wcj;v(G1t3OE0arlMYQjq zVqjn_@^oS;o^fe`^&)Mlu!6D$n!$@yB(@clF6mTP-PM$+cWTnY8wbzMl;`8})B9u6INQ)Z z*EQONXI;U=jY}*JH}2Y)vSBLgErUS5@(XJUZXCQdH}p#ihqv`vujOl0qu*%r@q)vKCidTd|nE_L&1 zFMHP~ct3q_===AFyzxlN4g0i%e7>I5y#-^>gTe~DWM4f Drk7eh diff --git a/public/static/images/weather/partly-cloudy.png b/public/static/images/weather/partly-cloudy.png deleted file mode 100644 index 6c59f6cc936b1d7b4ebb67e98e679c11e2ece5ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1130 zcmXw1X;4#F6b^*N27^F`F$FAvVX*{lKz|5?vL&)e;jvZ0s-SkPK!IVAH7rR8AW&%$ zMuP~&ZZcD9ktxe4Yq5m{Ww8(Ln4uYs$4GL z+}zyS+5#A4Pz6A#RH6bZf*@cE9zZxGYo|R9I39@56M)^7Cg7u1s{satL%CK6B%ZSW z1DU1*2)dv%Zs?>tdfuvzP_$dD8MIx7O+?hXg~|hW$@Sr zyefs?$zk5MxL>(cs-92Kh_1@u@tw8jszrusF;_Dig$RQXVIa+sv;T9U^ze`f%nQX1 zqE;z(-iwC(#m^e6vTcb3wM--!_?elU6k(*1yno$ZQ&F0KCjtugIB92n+|? z)ZHSOiFr!@X6nv3j?P#~ZA0W;{i9g~`<|bafnG)p$>cA(;^bF~L)95jbGT?Y=_amI z@NedAy0_npp%5MSRsRM$$J_^TE}OV}EzhSO{q)h84R1S_jpJ3Z^7-a7%S)jVE}eY^ zr-z}!J(gou-|`#B?@RAd`z*-k^arg<1lJ!A1(0D^ro++2>U1`F$h+@i&wOFF{zG;i zr=0IWbRPAJ?Y0`3tdF+fpW*ja1>Y*iPVQ2REGfEb*s9`hO_rQPi?L$kk96b}r|Q#oHF204UB zAAVQfbEf)c=ZUW(dq^C84Q-xuR%&7Agh{Ke=v^auMGp>Ea^K=l1(&$gy|L2mXCTCZ zbYd%ZspzwEJ_#mqV~?G?@6T<+wmz7XVD5VQ3FG?ts99E4#;FdhY?(0lQS9n$rC~aS zsx|u2X&z#v-;&4Yy*9I{3Hr5VQ4*e)MqY-TGej&xh;j-skbY~g!|VOW6kKymAU%ZE I;v38S4^xPX^8f$< diff --git a/public/static/images/weather/pouring.png b/public/static/images/weather/pouring.png deleted file mode 100644 index 487d5ac82772fa8125a2515eb853dc6d0b45ce95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 840 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!<^=eJxB}^y*udMjZ?Or3#NNGo z_xbbZFJHdAdGqG`_wRrI{{8*?_lFN3{{R2~?b|mX7by7a*Ds*ppFe+qT%aD6;-!os6FxQt39)D@Z?@?P^v1%Jy5J!vPGQZ{2L&wbfthjN?_b;msrt7ew@|2t7; zIpgG(zH{fl6&NlRmikckqL)42FORXDwQ92U6SWf;WDP8i3vHUV;$rmi$fmO^Hyq!+ zxL9OjK73@kM)3&@jrmpiPI>#XCxLot*y=Oo1 zr9?LE)(}gO{T|RDG|f`-z_Y`$F**yJjVva;F>swX`BT_~*mmb9URi$yx4h&tw$p4d zna*G)^RB?f&&K9V|Fw(y_ZodBhPxK>ZFra4E@;Ud-W68xk}rirRKZOlsJUErf~NF0 zzd3Ji^O=2IwyN-%sFUooE9&mL$Gn~P9B$!vVf5c3^;mXJb(Di-MQHsJtDYAtnGV_Q zx7!zPAHM%d|DT#USA4HZdt}&!|9^X_mG`iNfXl^9)q+1~|6Ug}T64ju^Rvrwi|-ec zxBa<(|MJhh#!fzACtJOC|6tmx=F7OrEaUZ~ua_D9Cih&u_T%0$RtfFDO~ya)(TCR^=I!jt}o4Ls#=@_OmYmKu6{1-oD!MyRD9u zWHT@@33|FXhEy<4nVLT7umX?U#@;*DrLX_?@ANY{oYmp;;OF)y-#gVJR_&VjVZqy~ zz;gyniL=B5k6dy*vZae@l~~+N?k}nZIXC|aRai}QXD)xT){S@jiKR9UKNZqF6pmJ_ zEtuk;*q{>a$TTf%PjU;-va~hqb(~q8JAJBuaV$;bkI-K@#ZO?-efj4r`FJPn)shz2 zV$@+RW@-P;R}GW36{W^d+WFJB=oa-iy1q%Os zmWi=xRJF-m?rW`Zv2&91j;Wq(_ZmfSyxd!NYYDTmLbc%1k^ zN^@HD0}n^rL=*%_-~8C;6m;H*uVU3PjT^62WUYn&bIzMk_G#H<-s*Gqy#6;Tel08i z`Z?^V@aJapO(F-q*+u4Wo*FaZk?=Xrpgo(F4thp?a!_#I#U=Nf^^`*S$@ndi3xMg0 N!PC{xWt~$(69DX%mt6n= diff --git a/public/static/images/weather/snowy.png b/public/static/images/weather/snowy.png deleted file mode 100644 index e28b6e82747cfad550104396148ae58d3816a89b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmV-)1dIELP)YJZIjJy zWv7Xq%xhQN*z9IHQvbf`_!-Z0?clH6fS{$^XpFGFT+e@&AAK1#46R1zFF}>C4dyT{( zCVxfaH@DyZ8feefSgd3Q=H=J^bwDr3Ey3WUEdaE21J-9ieZcHfuhDfuUE>N^CaQ}M zE$imnvu?jgh3XT~j(zC`HPp*y997JLde!nNbIVNmzeB249|ux5 zbCj#|XU38V#_3~LYTUX|(mbMH&fohQBW<(De@(zRHvnau8u97@wQe z)p!2@Dl#5ed%ax5LFM@)mq2br#4d1G3?dpQ#C$2zj(*#v5E~Jx8@m7zNBMAoWk$SrA*KQx*qv? zz)Z@lj9Lj}mnV#opw8gGuO)Ppy)ai)3p^Pu#7JQEg&ScC6*Iu6;fn|>5b^^2Uy~_Z zWMos&XCVKEr2WX|5_gV-d=1(R_T;~WNWF@TNR5Ok2Mk$Xtl>%qh`%4# zytT>m$%mQLnGx0$7#5!)L0kt2kl%{e@&t-?cOT4c#r#l@(n5F?yAs-3nk{KZ$nl-tap9T*M`2i`o5M!QTsTe@Ef@yLUfJ&VI_c_;&Q_ zc+*?Y-dzUh3G2*;_xO18$Io)U`y71#MF#lc%Z#_%Z@0UjdQVGy!gRdH%m%aGG=LMB z4!=pp(}qBg0O)H3=m|_iIrR4V5n#*!380Qz)f)lE43L0`dUQ&9oZkunr+#=yA%)l9 zynZ4gfT@KVdh`5x0`)U}p5SdD0U$*IVky`3RzR>tVF6Zw5EH4^^+0`81c(TO;Opo; zh2i1xCe)4e2sr7`5c=>C7o?y0iyCb zv&AiYdLsgoV$(+El5!(s_0cHfr^1ze&4Y9f5!^Q{tq(2 z`u}a~|5q*l-msbI`@{igx?D++UoZoUQB>o+HM@kfHh=tY`}2Uf^DEERCGMh&tkMhw zC+=8%XgLD|qnxLUV@L(#+v}!HtquY#7Y?m0*#0}dSXpfPOuzr#g;5_L95>LtU1)p0 zH0QL*f)o6QI-~<7e*DlY6P~A%_vh=EDdv|X-q*DA-{H~!)YRW45Z43Ha^0#dMKdwIzw_{$EKNU+t2C=ch8UWgPK$Y6)WyNx^)cc1}E zT>Gp&MhRlsW8p_W0ga@@(!aca3%opIVKL#{_w=4;H=ThU$cbbUc@cpe$)>6Q5#&rf z!Ri6IBkugqzwah6tCuGhkp@fucK}bON{YwFzXy3CL&A$^Ag}DPv`_vcXa-6oz4G?p zD>{*EIZ-u@iNuh%MPE~6;9`PVR{hl%B&q2|65KJLo7nR59xUv%`~uX2RbF%Yv;`3j zY`uyamSTzw@^GmBz7%M}46qE4F!c|%0-t4TdG6OFTVZ|<>Ng74CLrspUn;aXZ$vky zcDNY>o4AG%)t5pYhrtZY=(VtUv1Zy+IT$daADclp0X_xBK=Dr2c5&?>l5Pf0ByI31 zbof{sI*%b!R9{9SOe;Q+!A>t?s)p+4Q!vuNC`1|{wi~b~AlXKYUd2IxlAi!>7R*Kz z1fHz(Hc;E;o%RC8km%R3lAnR`yK%IEefKMn-U4PToc4ko+kbsT3X&h7VW@cdYvb3T z*#y_UAl-gHi@TFjjVX+{G!r$ZCE^e5hFU{5YUh%ENvqt{t^7^6-KcDYKiftbv5>fC^p8p3IShZZt zES!hfh!h7LJKSR9RkW>iEpC+X6OI5ZJO7J+qgGiMr1s)Xb|K#EHfnVbGUEl|( z$W19Mu*TY3=Vu)`{+PADHRIC1MWaQ=U>@*wCL5~agZ-`$DK4?fLw~hDp}h~V!K!7` z-Vetf)L-IO++aP=JQz(;97Jl$dtYAdSgx_cBKT9!Z`AVnbXy*_t^fc407*qoM6N<$ Ef&(aQ@c;k- diff --git a/src/data/weather.ts b/src/data/weather.ts index 4fe0919191..199a5e68e9 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -1,26 +1,52 @@ -import { HomeAssistant, WeatherEntity } from "../types"; +import { SVGTemplateResult, svg, html, TemplateResult, css } from "lit-element"; +import { styleMap } from "lit-html/directives/style-map"; -export const weatherImages = { - "clear-night": "/static/images/weather/night.png", - cloudy: "/static/images/weather/cloudy.png", - fog: "/static/images/weather/cloudy.png", - lightning: "/static/images/weather/lightning.png", - "lightning-rainy": "/static/images/weather/lightning-rainy.png", - partlycloudy: "/static/images/weather/partly-cloudy.png", - pouring: "/static/images/weather/pouring.png", - rainy: "/static/images/weather/rainy.png", - hail: "/static/images/weather/rainy.png", - snowy: "/static/images/weather/snowy.png", - "snowy-rainy": "/static/images/weather/snowy.png", - sunny: "/static/images/weather/sunny.png", - windy: "/static/images/weather/windy.png", - "windy-variant": "/static/images/weather/windy.png", -}; +import type { HomeAssistant, WeatherEntity } from "../types"; + +export const weatherSVGs = new Set([ + "clear-night", + "cloudy", + "fog", + "lightning", + "lightning-rainy", + "partlycloudy", + "pouring", + "rainy", + "hail", + "snowy", + "snowy-rainy", + "sunny", + "windy", + "windy-variant", +]); export const weatherIcons = { exceptional: "hass:alert-circle-outline", }; +const cloudyStates = new Set([ + "partlycloudy", + "cloudy", + "fog", + "windy", + "windy-variant", + "hail", + "rainy", + "snowy", + "snowy-rainy", + "pouring", + "lightning", + "lightning-rainy", +]); + +const rainStates = new Set(["hail", "rainy", "pouring"]); + +const windyStates = new Set(["windy", "windy-variant"]); + +const snowyStates = new Set(["snowy", "snowy-rainy"]); + +const lightningStates = new Set(["lightning", "lightning-rainy"]); + export const cardinalDirections = [ "N", "NNE", @@ -164,3 +190,183 @@ const getWeatherExtrema = ( } `; }; + +export const weatherSVGStyles = css` + .rain { + fill: var(--weather-icon-rain-color, #30b3ff); + } + .sun { + fill: var(--weather-icon-sun-color, #fdd93c); + } + .moon { + fill: var(--weather-icon-moon-color, #fdf9cc); + } + .cloud-back { + fill: var(--weather-icon-cloud-back-color, #d4d4d4); + } + .cloud-front { + fill: var(--weather-icon-cloud-front-color, #f9f9f9); + } +`; + +export const getWeatherStateSVG = (state: string): SVGTemplateResult => { + return svg` + + ${ + state === "sunny" + ? svg` + + ` + : "" + } + ${ + state === "clear-night" + ? svg` + + ` + : "" + } + ${ + state === "partlycloudy" + ? svg` + + ` + : "" + } + ${ + cloudyStates.has(state) + ? svg` + + + ` + : "" + } + ${ + rainStates.has(state) + ? svg` + + + + + ` + : "" + } + ${ + state === "pouring" + ? svg` + + + ` + : "" + } + ${ + windyStates.has(state) + ? svg` + + + ` + : "" + } + ${ + snowyStates.has(state) + ? svg` + + + + ` + : "" + } + ${ + lightningStates.has(state) + ? svg` + + ` + : "" + } + `; +}; + +export const getWeatherStateIcon = ( + state: string, + element: HTMLElement +): TemplateResult | undefined => { + const userDefinedIcon = getComputedStyle(element).getPropertyValue( + `--weather-icon-${state}` + ); + + if (userDefinedIcon) { + return html` +
+ `; + } + + if (weatherSVGs.has(state)) { + return html`${getWeatherStateSVG(state)}`; + } + + if (state in weatherIcons) { + return html` + + `; + } + + return undefined; +}; diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index 8fa9356417..3b5f7bc377 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -21,16 +21,16 @@ import { UNAVAILABLE } from "../../../data/entity"; import { getSecondaryWeatherAttribute, getWeatherUnit, - weatherIcons, - weatherImages, + getWeatherStateIcon, + weatherSVGStyles, } from "../../../data/weather"; -import { HomeAssistant, WeatherEntity } from "../../../types"; +import type { HomeAssistant, WeatherEntity } from "../../../types"; import { actionHandler } from "../common/directives/action-handler-directive"; import { findEntities } from "../common/find-entites"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../components/hui-warning"; -import { LovelaceCard, LovelaceCardEditor } from "../types"; -import { WeatherForecastCardConfig } from "./types"; +import type { LovelaceCard, LovelaceCardEditor } from "../types"; +import type { WeatherForecastCardConfig } from "./types"; import { installResizeObserver } from "../common/install-resize-observer"; const DAY_IN_MILLISECONDS = 86400000; @@ -165,6 +165,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { hourly = timeDiff < DAY_IN_MILLISECONDS; } + const weatherStateIcon = getWeatherStateIcon(stateObj.state, this); + return html`
- ${stateObj.state in weatherImages - ? html` - - ` - : html` - - `} + ${weatherStateIcon || + html` + + `}
@@ -251,21 +247,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { ${item.condition !== undefined && item.condition !== null ? html`
- ${item.condition in weatherImages - ? html` - - ` - : item.condition in weatherIcons - ? html` - - ` - : ""} + ${getWeatherStateIcon(item.condition, this)}
` : ""} @@ -334,201 +316,205 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { } } - static get styles(): CSSResult { - return css` - :host { - display: block; - } + static get styles(): CSSResult[] { + return [ + weatherSVGStyles, + css` + :host { + display: block; + } - ha-card { - cursor: pointer; - padding: 16px; - } + ha-card { + cursor: pointer; + padding: 16px; + } - .content { - display: flex; - flex-wrap: nowrap; - justify-content: space-between; - align-items: center; - } + .content { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + align-items: center; + } - .icon-image { - display: flex; - align-items: center; - min-width: 64px; - margin-right: 16px; - } + .icon-image { + display: flex; + align-items: center; + min-width: 64px; + margin-right: 16px; + } - .weather-image, - .weather-icon { - flex: 0 0 64px; - } + .icon-image > * { + flex: 0 0 64px; + height: 64px; + } - .weather-icon { - --mdc-icon-size: 64px; - } + .weather-icon { + --mdc-icon-size: 64px; + } - .info { - display: flex; - justify-content: space-between; - flex-grow: 1; - overflow: hidden; - } + .info { + display: flex; + justify-content: space-between; + flex-grow: 1; + overflow: hidden; + } - .temp-attribute { - text-align: right; - } + .temp-attribute { + text-align: right; + } - .temp-attribute .temp { - position: relative; - margin-right: 24px; - } + .temp-attribute .temp { + position: relative; + margin-right: 24px; + } - .temp-attribute .temp span { - position: absolute; - font-size: 24px; - top: 1px; - } + .temp-attribute .temp span { + position: absolute; + font-size: 24px; + top: 1px; + } - .state, - .temp-attribute .temp { - font-size: 28px; - line-height: 1.2; - } + .name, + .temp-attribute .temp { + font-size: 28px; + line-height: 1.2; + } - .name, - .attribute { - font-size: 14px; - line-height: 1; - } + .state, + .attribute { + font-size: 14px; + line-height: 1; + } - .name-state { - overflow: hidden; - padding-right: 12px; - width: 100%; - } + .name-state { + overflow: hidden; + padding-right: 12px; + width: 100%; + } - .name, - .state { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } + .name, + .state { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } - .attribute { - white-space: nowrap; - } + .attribute { + white-space: nowrap; + } - .forecast { - display: flex; - justify-content: space-around; - padding-top: 16px; - } + .forecast { + display: flex; + justify-content: space-around; + padding-top: 16px; + } - .forecast > div { - text-align: center; - } + .forecast > div { + text-align: center; + } - .forecast .icon, - .forecast .temp { - margin: 4px 0; - } + .forecast .icon, + .forecast .temp { + margin: 4px 0; + } - .forecast .temp { - font-size: 16px; - } + .forecast .temp { + font-size: 16px; + } - .forecast-image-icon { - padding-top: 4px; - padding-bottom: 4px; - } + .forecast-image-icon { + padding-top: 4px; + padding-bottom: 4px; + display: flex; + } - .forecast-image { - width: 40px; - } + .forecast-image-icon > * { + width: 40px; + } - .forecast-icon { - --mdc-icon-size: 40px; - } + .forecast-icon { + --mdc-icon-size: 40px; + } - .attribute, - .templow, - .name { - color: var(--secondary-text-color); - } + .attribute, + .templow, + .state { + color: var(--secondary-text-color); + } - .unavailable { - height: 100px; - display: flex; - justify-content: center; - align-items: center; - font-size: 16px; - padding: 10px 20px; - text-align: center; - } + .unavailable { + height: 100px; + display: flex; + justify-content: center; + align-items: center; + font-size: 16px; + padding: 10px 20px; + text-align: center; + } - /* ============= NARROW ============= */ + /* ============= NARROW ============= */ - :host([narrow]) .icon-image { - min-width: 52px; - } + :host([narrow]) .icon-image { + min-width: 52px; + } - :host([narrow]) .weather-image { - flex: 0 0 52px; - width: 52px; - } + :host([narrow]) .weather-image { + flex: 0 0 52px; + width: 52px; + } - :host([narrow]) .weather-icon { - --mdc-icon-size: 52px; - } + :host([narrow]) .weather-icon { + --mdc-icon-size: 52px; + } - :host([narrow]) .state, - :host([narrow]) .temp-attribute .temp { - font-size: 22px; - } + :host([narrow]) .name, + :host([narrow]) .temp-attribute .temp { + font-size: 22px; + } - :host([narrow]) .temp-attribute .temp { - margin-right: 16px; - } + :host([narrow]) .temp-attribute .temp { + margin-right: 16px; + } - :host([narrow]) .temp span { - top: 1px; - font-size: 16px; - } + :host([narrow]) .temp span { + top: 1px; + font-size: 16px; + } - /* ============= VERY NARROW ============= */ + /* ============= VERY NARROW ============= */ - :host([veryNarrow]) .name, - :host([veryNarrow]) .attribute { - display: none; - } + :host([veryNarrow]) .state, + :host([veryNarrow]) .attribute { + display: none; + } - :host([veryNarrow]) .info { - flex-direction: column; - align-items: flex-start; - } + :host([veryNarrow]) .info { + flex-direction: column; + align-items: flex-start; + } - :host([veryNarrow]) .name-state { - padding-right: 0; - } + :host([veryNarrow]) .name-state { + padding-right: 0; + } - /* ============= VERY VERY NARROW ============= */ + /* ============= VERY VERY NARROW ============= */ - :host([veryVeryNarrow]) .info { - padding-top: 4px; - align-items: center; - } + :host([veryVeryNarrow]) .info { + padding-top: 4px; + align-items: center; + } - :host([veryVeryNarrow]) .content { - flex-wrap: wrap; - justify-content: center; - flex-direction: column; - } + :host([veryVeryNarrow]) .content { + flex-wrap: wrap; + justify-content: center; + flex-direction: column; + } - :host([veryVeryNarrow]) .icon-image { - margin-right: 0; - } - `; + :host([veryVeryNarrow]) .icon-image { + margin-right: 0; + } + `, + ]; } } diff --git a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts index 2e04013bb1..d0ff194bc2 100644 --- a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts @@ -8,21 +8,32 @@ import { PropertyValues, TemplateResult, } from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; +import { ifDefined } from "lit-html/directives/if-defined"; + import { computeStateDisplay } from "../../../common/entity/compute_state_display"; import "../../../components/entity/state-badge"; import { UNAVAILABLE_STATES } from "../../../data/entity"; import { getSecondaryWeatherAttribute, getWeatherUnit, - weatherIcons, - weatherImages, + getWeatherStateIcon, + weatherSVGStyles, } from "../../../data/weather"; -import { HomeAssistant, WeatherEntity } from "../../../types"; -import { EntitiesCardEntityConfig } from "../cards/types"; +import type { HomeAssistant, WeatherEntity } from "../../../types"; +import type { EntitiesCardEntityConfig } from "../cards/types"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../components/hui-generic-entity-row"; import "../components/hui-warning"; -import { LovelaceRow } from "./types"; +import type { LovelaceRow } from "./types"; +import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const"; +import { computeDomain } from "../../../common/entity/compute_domain"; +import { actionHandler } from "../common/directives/action-handler-directive"; +import { hasAction } from "../common/has-action"; +import { computeStateName } from "../../../common/entity/compute_state_name"; +import { ActionHandlerEvent } from "../../../data/lovelace"; +import { handleAction } from "../common/handle-action"; +import { stateIcon } from "../../../common/entity/state_icon"; @customElement("hui-weather-entity-row") class HuiWeatherEntityRow extends LitElement implements LovelaceRow { @@ -61,48 +72,126 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { `; } - const weatherRowConfig = { - ...this._config, - icon: weatherIcons[stateObj.state], - image: weatherImages[stateObj.state], - }; + const pointer = + (this._config.tap_action && this._config.tap_action.action !== "none") || + (this._config.entity && + !DOMAINS_HIDE_MORE_INFO.includes(computeDomain(this._config.entity))); + + const weatherStateIcon = getWeatherStateIcon(stateObj.state, this); return html` - -
-
- ${UNAVAILABLE_STATES.includes(stateObj.state) - ? computeStateDisplay( - this.hass.localize, - stateObj, - this.hass.language - ) - : html` - ${stateObj.attributes.temperature} - ${getWeatherUnit(this.hass, "temperature")} - `} -
-
- ${getSecondaryWeatherAttribute(this.hass!, stateObj)} -
+
+ ${weatherStateIcon || + html` + + `} +
+
+ ${this._config.name || computeStateName(stateObj)} +
+
+
+ ${UNAVAILABLE_STATES.includes(stateObj.state) + ? computeStateDisplay( + this.hass.localize, + stateObj, + this.hass.language + ) + : html` + ${stateObj.attributes.temperature} + ${getWeatherUnit(this.hass, "temperature")} + `}
- +
+ ${getSecondaryWeatherAttribute(this.hass!, stateObj)} +
+
`; } - static get styles(): CSSResult { - return css` - .attributes { - display: flex; - flex-direction: column; - justify-content: center; - text-align: right; - } + private _handleAction(ev: ActionHandlerEvent) { + handleAction(this, this.hass!, this._config!, ev.detail.action!); + } - .secondary { - color: var(--secondary-text-color); - } - `; + static get styles(): CSSResult[] { + return [ + weatherSVGStyles, + css` + :host { + display: flex; + align-items: center; + flex-direction: row; + } + + .info { + margin-left: 16px; + flex: 1 0 60px; + } + + .info, + .info > * { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .icon-image { + display: flex; + align-items: center; + min-width: 40px; + } + + .icon-image > * { + flex: 0 0 40px; + height: 40px; + } + + .weather-icon { + --iron-icon-width: 40px; + --iron-icon-height: 40px; + } + + :host([rtl]) .flex { + margin-left: 0; + margin-right: 16px; + } + + .pointer { + cursor: pointer; + } + + .attributes { + display: flex; + flex-direction: column; + justify-content: center; + text-align: right; + margin-left: 8px; + } + + .secondary { + color: var(--secondary-text-color); + } + `, + ]; } } From 84a2676a9c04ac399cb0d1ac96074de876f4f083 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 11 May 2020 23:59:29 +0200 Subject: [PATCH 14/21] compress icons (#5836) --- build-scripts/gulp/compress.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/build-scripts/gulp/compress.js b/build-scripts/gulp/compress.js index de604f7fa3..aee165c5f7 100644 --- a/build-scripts/gulp/compress.js +++ b/build-scripts/gulp/compress.js @@ -9,25 +9,30 @@ const paths = require("../paths"); gulp.task("compress-app", function compressApp() { const jsLatest = gulp .src(path.resolve(paths.output, "**/*.js")) - .pipe(zopfli()) + .pipe(zopfli({ threshold: 150 })) .pipe(gulp.dest(paths.output)); const jsEs5 = gulp .src(path.resolve(paths.output_es5, "**/*.js")) - .pipe(zopfli()) + .pipe(zopfli({ threshold: 150 })) .pipe(gulp.dest(paths.output_es5)); const polyfills = gulp .src(path.resolve(paths.static, "polyfills/*.js")) - .pipe(zopfli()) + .pipe(zopfli({ threshold: 150 })) .pipe(gulp.dest(path.resolve(paths.static, "polyfills"))); const translations = gulp - .src(path.resolve(paths.static, "translations/*.json")) - .pipe(zopfli()) + .src(path.resolve(paths.static, "translations/**/*.json")) + .pipe(zopfli({ threshold: 150 })) .pipe(gulp.dest(path.resolve(paths.static, "translations"))); - return merge(jsLatest, jsEs5, polyfills, translations); + const icons = gulp + .src(path.resolve(paths.static, "mdi/*.json")) + .pipe(zopfli({ threshold: 150 })) + .pipe(gulp.dest(path.resolve(paths.static, "mdi"))); + + return merge(jsLatest, jsEs5, polyfills, translations, icons); }); gulp.task("compress-hassio", function compressApp() { From f85cf0a23805f6bb3d704eef44729f1ef115256d Mon Sep 17 00:00:00 2001 From: HomeAssistant Azure Date: Tue, 12 May 2020 00:33:00 +0000 Subject: [PATCH 15/21] [ci skip] Translation update --- translations/frontend/en.json | 7 ++++++- translations/frontend/hu.json | 1 + translations/frontend/lb.json | 2 +- translations/frontend/nb.json | 3 +++ translations/frontend/pt.json | 7 +++++-- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/translations/frontend/en.json b/translations/frontend/en.json index 4fd0fb44fc..302b07c87a 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -1878,10 +1878,13 @@ "built_using": "Built using", "custom_uis": "Custom UIs:", "developed_by": "Developed by a bunch of awesome people.", + "documentation": "Documentation", "frontend": "frontend-ui", "frontend_version": "Frontend version: {version} - {type}", "home_assistant_logo": "Home Assistant logo", "icons_by": "Icons by", + "integrations": "Integrations", + "issues": "Issues", "license": "Published under the Apache 2.0 license", "path_configuration": "Path to configuration.yaml: {path}", "server": "server", @@ -2072,6 +2075,7 @@ "name": "Name", "no_theme": "No theme", "refresh_interval": "Refresh Interval", + "secondary_info_attribute": "Secondary Info Attribute", "show_icon": "Show Icon?", "show_name": "Show Name?", "show_state": "Show State?", @@ -2162,7 +2166,8 @@ }, "weather-forecast": { "description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.", - "name": "Weather Forecast" + "name": "Weather Forecast", + "show_forecast": "Show Forecast" } }, "cardpicker": { diff --git a/translations/frontend/hu.json b/translations/frontend/hu.json index 1def0024db..b665183ee2 100644 --- a/translations/frontend/hu.json +++ b/translations/frontend/hu.json @@ -1181,6 +1181,7 @@ "edit_requires_storage": "A szerkesztő le van tiltva, mert a konfiguráció a configuration.yaml fájlban van tárolva.", "elevation": "Magasság", "elevation_meters": "méter", + "external_url": "Externe URL", "imperial_example": "Fahrenheit, font", "internal_url": "Érvénytelen URL", "latitude": "Szélesség", diff --git a/translations/frontend/lb.json b/translations/frontend/lb.json index b819186ab7..3cf3a82567 100644 --- a/translations/frontend/lb.json +++ b/translations/frontend/lb.json @@ -1602,7 +1602,7 @@ "automation": "Automatisme nei lueden", "core": "Standuert and Personnalisatioun néi lueden", "group": "Gruppe nei lueden", - "heading": "YAML Konfiguratioun gëtt frësch gelueden", + "heading": "YAML Konfiguratioun frësch lueden", "introduction": "E puer Deeler vum Home Assistant kënne frësch geluede ginn ouni datt een Neistart néideg ass. Klick op nei luede fir di aktuell Konfiguratioun z'entlueden an di nei Konfiguratioun ze lueden.", "person": "Persoune frësch lueden", "scene": "Szeene néi lueden", diff --git a/translations/frontend/nb.json b/translations/frontend/nb.json index 62cb160a92..6d74a61c2d 100644 --- a/translations/frontend/nb.json +++ b/translations/frontend/nb.json @@ -473,6 +473,7 @@ } }, "common": { + "and": "og", "cancel": "Avbryt", "close": "Lukk", "delete": "Slett", @@ -1180,7 +1181,9 @@ "edit_requires_storage": "Redigering deaktivert da konfigurasjonen er lagret i configuration.yaml.", "elevation": "Høyde", "elevation_meters": "meter", + "external_url": "Ekstern URL", "imperial_example": "Fahrenheit, pund", + "internal_url": "Intern URL", "latitude": "Breddegrad", "location_name": "Navn på installasjonen av Home Assistant", "longitude": "Lengdegrad", diff --git a/translations/frontend/pt.json b/translations/frontend/pt.json index c26711e8f1..518daefd1e 100644 --- a/translations/frontend/pt.json +++ b/translations/frontend/pt.json @@ -331,7 +331,6 @@ "ui": { "auth_store": { "ask": "Deseja continuar com sessão iniciada?", - "confirm": "Guardar login", "decline": "Não" }, "card": { @@ -1372,6 +1371,7 @@ "aborted": "Abortado", "close": "Fechar", "created_config": "Configuração criada para {name}.", + "dismiss": "Descartar diálogo", "error_saving_area": "Erro ao salvar a área: {error}", "external_step": { "description": "Para ser concluída, esta etapa exige que visite um sítio web externo.", @@ -1665,7 +1665,8 @@ "spinner": "À procura de dispositivos ZHA Zigbee..." }, "add": { - "caption": "Adicionar Dispositivos" + "caption": "Adicionar Dispositivos", + "description": "Adicionar dispositivos à rede Zigbee" }, "caption": "ZHA", "cluster_attributes": { @@ -1735,6 +1736,7 @@ "zha_zigbee_groups": "Grupos ZHA Zigbee" }, "header": "Configurar a automação residencial Zigbee", + "introduction": "Aqui é possível configurar o componente ZHA. Ainda não é possível configurar tudo a partir do IU, mas estamos a trabalhar nisso.", "network_management": { "header": "Gestão ", "introduction": "Comandos que afetam toda a rede" @@ -2192,6 +2194,7 @@ "para_no_id": "Este elemento não possui um ID. Por favor adicione um ID a este elemento em 'ui-lovelace.yaml'." }, "raw_editor": { + "confirm_remove_config_text": "Iremos gerar automaticamente as suas vistas do Lovelace UI com as suas áreas e dispositivos se você remover a sua configuração do Lovelace UI.", "confirm_unsaved_changes": "Existem alterações não guardadas. De certeza de que quer sair?", "confirm_unsaved_comments": "A sua configuração contém comentário(s), eles não serão salvos. Deseja continuar?", "error_invalid_config": "A sua configuração não é válida: {error}", From 96ab057853d1cdadf25a53a3de61e80a54b566a8 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 12 May 2020 12:17:41 +0200 Subject: [PATCH 16/21] Ignore ResizeObserver loop limit exceeded error (#5838) --- src/entrypoints/core.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/entrypoints/core.ts b/src/entrypoints/core.ts index 9e738b8042..a80af0d428 100644 --- a/src/entrypoints/core.ts +++ b/src/entrypoints/core.ts @@ -104,6 +104,11 @@ window.hassConnection.then(({ conn }) => { }); window.addEventListener("error", (e) => { + if (!__DEV__ && e.message === "ResizeObserver loop limit exceeded") { + e.stopImmediatePropagation(); + e.stopPropagation(); + return; + } const homeAssistant = document.querySelector("home-assistant") as any; if ( homeAssistant && From 845511e32208e647b95763630e0866c6323cc644 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 12 May 2020 11:29:43 -0500 Subject: [PATCH 17/21] Add 'brightness' as a secondary_info option (#5731) --- src/panels/lovelace/cards/types.ts | 3 ++- src/panels/lovelace/components/hui-generic-entity-row.ts | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index 1d3fbea65b..3ce3342309 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -34,7 +34,8 @@ export interface EntitiesCardEntityConfig extends EntityConfig { | "last-changed" | "last-triggered" | "position" - | "tilt-position"; + | "tilt-position" + | "brightness"; action_name?: string; service?: string; service_data?: object; diff --git a/src/panels/lovelace/components/hui-generic-entity-row.ts b/src/panels/lovelace/components/hui-generic-entity-row.ts index fe154e0775..a33127ce02 100644 --- a/src/panels/lovelace/components/hui-generic-entity-row.ts +++ b/src/panels/lovelace/components/hui-generic-entity-row.ts @@ -122,6 +122,11 @@ class HuiGenericEntityRow extends LitElement { ? `${this.hass.localize("ui.card.cover.tilt_position")}: ${ stateObj.attributes.current_tilt_position }` + : this.config.secondary_info === "brightness" && + stateObj.attributes.brightness + ? html`${Math.round( + (stateObj.attributes.brightness / 255) * 100 + )}%` : "")}
` From 1b2841eef9a6b0ff4926935703371f46cee28471 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 12 May 2020 20:09:30 +0200 Subject: [PATCH 18/21] Recreate cards only on config change (#5839) --- .../lovelace/components/hui-card-options.ts | 13 +- src/panels/lovelace/hui-root.ts | 194 +++++++------- src/panels/lovelace/types.ts | 1 + src/panels/lovelace/views/hui-view.ts | 241 ++++++++++-------- 4 files changed, 237 insertions(+), 212 deletions(-) diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index dcd770421e..e199c1b141 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -10,25 +10,30 @@ import { LitElement, property, TemplateResult, + queryAssignedNodes, } from "lit-element"; -import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog"; import { showMoveCardViewDialog } from "../editor/card-editor/show-move-card-view-dialog"; import { swapCard } from "../editor/config-util"; import { confDeleteCard } from "../editor/delete-card"; -import { Lovelace } from "../types"; +import { Lovelace, LovelaceCard } from "../types"; +import { computeCardSize } from "../common/compute-card-size"; @customElement("hui-card-options") export class HuiCardOptions extends LitElement { - public cardConfig?: LovelaceCardConfig; - @property() public hass?: HomeAssistant; @property() public lovelace?: Lovelace; @property() public path?: [number, number]; + @queryAssignedNodes() private _assignedNodes?: NodeListOf; + + public getCardSize() { + return this._assignedNodes ? computeCardSize(this._assignedNodes[0]) : 1; + } + protected render(): TemplateResult { return html` diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index ffdc503e52..e801a0c751 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -369,100 +369,6 @@ class HUIRoot extends LitElement { `; } - static get styles(): CSSResult[] { - return [ - haStyle, - css` - :host { - --dark-color: #455a64; - --text-dark-color: #fff; - -ms-user-select: none; - -webkit-user-select: none; - -moz-user-select: none; - } - - ha-app-layout { - min-height: 100%; - } - paper-menu-button { - padding: 0; - } - paper-tabs { - margin-left: 12px; - --paper-tabs-selection-bar-color: var(--text-primary-color, #fff); - text-transform: uppercase; - } - .edit-mode { - background-color: var(--dark-color, #455a64); - color: var(--text-dark-color); - } - .edit-mode div[main-title] { - pointer-events: auto; - } - paper-tab.iron-selected .edit-icon { - display: inline-flex; - } - .edit-icon { - color: var(--accent-color); - padding-left: 8px; - vertical-align: middle; - --mdc-theme-text-disabled-on-light: var(--disabled-text-color); - } - .edit-icon.view { - display: none; - } - #add-view { - position: absolute; - height: 44px; - } - #add-view ha-icon { - background-color: var(--accent-color); - border-radius: 5px; - margin-top: 4px; - } - app-toolbar a { - color: var(--text-primary-color, white); - } - mwc-button.warning:not([disabled]) { - color: var(--google-red-500); - } - #view { - min-height: calc(100vh - 112px); - /** - * Since we only set min-height, if child nodes need percentage - * heights they must use absolute positioning so we need relative - * positioning here. - * - * https://www.w3.org/TR/CSS2/visudet.html#the-height-property - */ - position: relative; - display: flex; - } - #view > * { - /** - * The view could get larger than the window in Firefox - * to prevent that we set the max-width to 100% - * flex-grow: 1 and flex-basis: 100% should make sure the view - * stays full width. - * - * https://github.com/home-assistant/home-assistant-polymer/pull/3806 - */ - flex: 1 1 100%; - max-width: 100%; - } - #view.tabs-hidden { - min-height: calc(100vh - 64px); - } - paper-item { - cursor: pointer; - } - .hide-tab { - display: none; - } - `, - ]; - } - protected updated(changedProperties: PropertyValues): void { super.updated(changedProperties); @@ -527,8 +433,10 @@ class HUIRoot extends LitElement { navigate(this, `${this.route?.prefix}/${views[0]?.path || 0}`); newSelectView = 0; } - // On edit mode change, recreate the current view from scratch - force = true; + } + + if (!force) { + huiView.lovelace = this.lovelace; } } @@ -734,6 +642,100 @@ class HUIRoot extends LitElement { // Recalculate to see if we need to adjust content area for tab bar fireEvent(this, "iron-resize"); } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + :host { + --dark-color: #455a64; + --text-dark-color: #fff; + -ms-user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + } + + ha-app-layout { + min-height: 100%; + } + paper-menu-button { + padding: 0; + } + paper-tabs { + margin-left: 12px; + --paper-tabs-selection-bar-color: var(--text-primary-color, #fff); + text-transform: uppercase; + } + .edit-mode { + background-color: var(--dark-color, #455a64); + color: var(--text-dark-color); + } + .edit-mode div[main-title] { + pointer-events: auto; + } + paper-tab.iron-selected .edit-icon { + display: inline-flex; + } + .edit-icon { + color: var(--accent-color); + padding-left: 8px; + vertical-align: middle; + --mdc-theme-text-disabled-on-light: var(--disabled-text-color); + } + .edit-icon.view { + display: none; + } + #add-view { + position: absolute; + height: 44px; + } + #add-view ha-icon { + background-color: var(--accent-color); + border-radius: 5px; + margin-top: 4px; + } + app-toolbar a { + color: var(--text-primary-color, white); + } + mwc-button.warning:not([disabled]) { + color: var(--google-red-500); + } + #view { + min-height: calc(100vh - 112px); + /** + * Since we only set min-height, if child nodes need percentage + * heights they must use absolute positioning so we need relative + * positioning here. + * + * https://www.w3.org/TR/CSS2/visudet.html#the-height-property + */ + position: relative; + display: flex; + } + #view > * { + /** + * The view could get larger than the window in Firefox + * to prevent that we set the max-width to 100% + * flex-grow: 1 and flex-basis: 100% should make sure the view + * stays full width. + * + * https://github.com/home-assistant/home-assistant-polymer/pull/3806 + */ + flex: 1 1 100%; + max-width: 100%; + } + #view.tabs-hidden { + min-height: calc(100vh - 64px); + } + paper-item { + cursor: pointer; + } + .hide-tab { + display: none; + } + `, + ]; + } } declare global { diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index 0799e1c7ea..dd5511eac3 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -34,6 +34,7 @@ export interface LovelaceCard extends HTMLElement { hass?: HomeAssistant; isPanel?: boolean; editMode?: boolean; + index?: number; getCardSize(): number; setConfig(config: LovelaceCardConfig): void; } diff --git a/src/panels/lovelace/views/hui-view.ts b/src/panels/lovelace/views/hui-view.ts index 3c0c303db5..279741e6f8 100644 --- a/src/panels/lovelace/views/hui-view.ts +++ b/src/panels/lovelace/views/hui-view.ts @@ -4,8 +4,9 @@ import { property, PropertyValues, TemplateResult, + CSSResult, + css, } from "lit-element"; -// This one is for types import { classMap } from "lit-html/directives/class-map"; import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element"; import { computeRTL } from "../../../common/util/compute_rtl"; @@ -92,7 +93,6 @@ export class HUIView extends LitElement { protected render(): TemplateResult { return html` - ${this.renderStyles()}
${this.lovelace!.editMode @@ -113,82 +113,6 @@ export class HUIView extends LitElement { `; } - protected renderStyles(): TemplateResult { - return html` - - `; - } - protected updated(changedProperties: PropertyValues): void { super.updated(changedProperties); @@ -201,6 +125,7 @@ export class HUIView extends LitElement { } const hassChanged = changedProperties.has("hass"); + let editModeChanged = false; let configChanged = false; @@ -209,7 +134,7 @@ export class HUIView extends LitElement { } else if (changedProperties.has("lovelace")) { const oldLovelace = changedProperties.get("lovelace") as Lovelace; editModeChanged = - !oldLovelace || lovelace.editMode !== oldLovelace.editMode; + oldLovelace && lovelace.editMode !== oldLovelace.editMode; configChanged = !oldLovelace || lovelace.config !== oldLovelace.config; } @@ -221,9 +146,15 @@ export class HUIView extends LitElement { }); } - if (configChanged || editModeChanged || changedProperties.has("columns")) { + if (configChanged) { this._createCards(lovelace.config.views[this.index!]); - } else if (hassChanged) { + } else if (editModeChanged) { + this._switchEditMode(); + } else if (changedProperties.has("columns")) { + this._recreateColumns(); + } + + if (hassChanged && !configChanged) { this._cards.forEach((element) => { element.hass = this.hass; }); @@ -280,38 +211,34 @@ export class HUIView extends LitElement { root.style.display = elements.length > 0 ? "block" : "none"; } - private _createCards(config: LovelaceViewConfig): void { + private _switchEditMode() { + if (this.lovelace!.editMode) { + const wrappedCards = this._cards.map((element) => { + const wrapper = document.createElement("hui-card-options"); + wrapper.hass = this.hass; + wrapper.lovelace = this.lovelace; + wrapper.path = [this.index!, (element as LovelaceCard).index!]; + (element as LovelaceCard).editMode = true; + wrapper.appendChild(element); + return wrapper; + }); + this._createColumns(wrappedCards); + } else { + this._createColumns(this._cards); + } + } + + private _recreateColumns() { + this._createColumns(this._cards); + } + + private _createColumns(elements: HTMLElement[]) { const root = this.shadowRoot!.getElementById("columns")!; while (root.lastChild) { root.removeChild(root.lastChild); } - if (!config || !config.cards || !Array.isArray(config.cards)) { - this._cards = []; - return; - } - - const elements: LovelaceCard[] = []; - const elementsToAppend: HTMLElement[] = []; - config.cards.forEach((cardConfig, cardIndex) => { - const element = this.createCardElement(cardConfig); - elements.push(element); - - if (!this.lovelace!.editMode) { - elementsToAppend.push(element); - return; - } - - const wrapper = document.createElement("hui-card-options"); - wrapper.hass = this.hass; - wrapper.lovelace = this.lovelace; - wrapper.path = [this.index!, cardIndex]; - element.editMode = true; - wrapper.appendChild(element); - elementsToAppend.push(wrapper); - }); - let columns: HTMLElement[][] = []; const columnEntityCount: number[] = []; for (let i = 0; i < this.columns!; i++) { @@ -319,12 +246,11 @@ export class HUIView extends LitElement { columnEntityCount.push(0); } - elements.forEach((el, index) => { - const cardSize = computeCardSize(el); - // Element to append might be the wrapped card when we're editing. - columns[getColumnIndex(columnEntityCount, cardSize)].push( - elementsToAppend[index] + elements.forEach((el) => { + const cardSize = computeCardSize( + (el.tagName === "HUI-CARD-OPTIONS" ? el.firstChild : el) as LovelaceCard ); + columns[getColumnIndex(columnEntityCount, cardSize)].push(el); }); // Remove empty columns @@ -336,8 +262,28 @@ export class HUIView extends LitElement { column.forEach((el) => columnEl.appendChild(el)); root.appendChild(columnEl); }); + } + + private _createCards(config: LovelaceViewConfig): void { + if (!config || !config.cards || !Array.isArray(config.cards)) { + this._cards = []; + return; + } + + const elements: LovelaceCard[] = []; + config.cards.forEach((cardConfig, index) => { + const element = this.createCardElement(cardConfig); + element.index = index; + elements.push(element); + }); this._cards = elements; + + if (this.lovelace!.editMode) { + this._switchEditMode(); + } else { + this._createColumns(this._cards); + } } private _rebuildCard( @@ -361,6 +307,77 @@ export class HUIView extends LitElement { curBadgeEl === badgeElToReplace ? newBadgeEl : curBadgeEl ); } + + static get styles(): CSSResult { + return css` + :host { + display: block; + box-sizing: border-box; + padding: 4px 4px 0; + transform: translateZ(0); + position: relative; + color: var(--primary-text-color); + background: var(--lovelace-background, var(--primary-background-color)); + } + + #badges { + margin: 8px 16px; + font-size: 85%; + text-align: center; + } + + #columns { + display: flex; + flex-direction: row; + justify-content: center; + } + + .column { + flex: 1 0 0; + max-width: 500px; + min-width: 0; + /* on iOS devices the column can become wider when toggling a switch */ + overflow-x: hidden; + } + + .column > * { + display: block; + margin: 4px 4px 8px; + } + + mwc-fab { + position: sticky; + float: right; + bottom: 16px; + right: 16px; + z-index: 1; + } + + mwc-fab.rtl { + float: left; + right: auto; + left: 16px; + } + + @media (max-width: 500px) { + :host { + padding-left: 0; + padding-right: 0; + } + + .column > * { + margin-left: 0; + margin-right: 0; + } + } + + @media (max-width: 599px) { + .column { + max-width: 600px; + } + } + `; + } } declare global { From 577a21fc5ca19ac7bca0bbdd547671924db54c3d Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Tue, 12 May 2020 15:42:29 -0400 Subject: [PATCH 19/21] Rework ZHA group adds and removes (#5602) --- src/data/zha.ts | 22 ++- src/panels/config/zha/zha-add-group-page.ts | 34 ++-- src/panels/config/zha/zha-config-dashboard.ts | 13 +- .../zha/zha-device-endpoint-data-table.ts | 182 ++++++++++++++++++ .../config/zha/zha-devices-data-table.ts | 124 ------------ src/panels/config/zha/zha-group-page.ts | 95 +++++---- 6 files changed, 276 insertions(+), 194 deletions(-) create mode 100644 src/panels/config/zha/zha-device-endpoint-data-table.ts delete mode 100644 src/panels/config/zha/zha-devices-data-table.ts diff --git a/src/data/zha.ts b/src/data/zha.ts index af8f79be8d..41c4f0805c 100644 --- a/src/data/zha.ts +++ b/src/data/zha.ts @@ -3,6 +3,7 @@ import { HomeAssistant } from "../types"; export interface ZHAEntityReference extends HassEntity { name: string; + original_name?: string; } export interface ZHADevice { @@ -26,6 +27,12 @@ export interface ZHADevice { signature: any; } +export interface ZHADeviceEndpoint { + device: ZHADevice; + endpoint_id: number; + entities: ZHAEntityReference[]; +} + export interface Attribute { name: string; id: number; @@ -56,7 +63,12 @@ export interface ReadAttributeServiceData { export interface ZHAGroup { name: string; group_id: number; - members: ZHADevice[]; + members: ZHADeviceEndpoint[]; +} + +export interface ZHAGroupMember { + ieee: string; + endpoint_id: string; } export const reconfigureNode = ( @@ -213,7 +225,7 @@ export const fetchGroup = ( export const fetchGroupableDevices = ( hass: HomeAssistant -): Promise => +): Promise => hass.callWS({ type: "zha/devices/groupable", }); @@ -221,7 +233,7 @@ export const fetchGroupableDevices = ( export const addMembersToGroup = ( hass: HomeAssistant, groupId: number, - membersToAdd: string[] + membersToAdd: ZHAGroupMember[] ): Promise => hass.callWS({ type: "zha/group/members/add", @@ -232,7 +244,7 @@ export const addMembersToGroup = ( export const removeMembersFromGroup = ( hass: HomeAssistant, groupId: number, - membersToRemove: string[] + membersToRemove: ZHAGroupMember[] ): Promise => hass.callWS({ type: "zha/group/members/remove", @@ -243,7 +255,7 @@ export const removeMembersFromGroup = ( export const addGroup = ( hass: HomeAssistant, groupName: string, - membersToAdd?: string[] + membersToAdd?: ZHAGroupMember[] ): Promise => hass.callWS({ type: "zha/group/add", diff --git a/src/panels/config/zha/zha-add-group-page.ts b/src/panels/config/zha/zha-add-group-page.ts index c52e6da84a..eb85e899ab 100644 --- a/src/panels/config/zha/zha-add-group-page.ts +++ b/src/panels/config/zha/zha-add-group-page.ts @@ -18,31 +18,31 @@ import type { SelectionChangedEvent } from "../../../components/data-table/ha-da import { addGroup, fetchGroupableDevices, - ZHADevice, ZHAGroup, + ZHADeviceEndpoint, } from "../../../data/zha"; import "../../../layouts/hass-error-screen"; import "../../../layouts/hass-subpage"; import type { PolymerChangedEvent } from "../../../polymer-types"; import type { HomeAssistant } from "../../../types"; import "../ha-config-section"; -import "./zha-devices-data-table"; -import type { ZHADevicesDataTable } from "./zha-devices-data-table"; +import "./zha-device-endpoint-data-table"; +import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table"; @customElement("zha-add-group-page") export class ZHAAddGroupPage extends LitElement { - @property() public hass!: HomeAssistant; + @property({ type: Object }) public hass!: HomeAssistant; - @property() public narrow!: boolean; + @property({ type: Boolean }) public narrow!: boolean; - @property() public devices: ZHADevice[] = []; + @property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = []; @property() private _processingAdd = false; @property() private _groupName = ""; - @query("zha-devices-data-table") - private _zhaDevicesDataTable!: ZHADevicesDataTable; + @query("zha-device-endpoint-data-table") + private _zhaDevicesDataTable!: ZHADeviceEndpointDataTable; private _firstUpdatedCalled = false; @@ -87,14 +87,14 @@ export class ZHAAddGroupPage extends LitElement { ${this.hass.localize("ui.panel.config.zha.groups.add_members")}
- - +
{ this._processingAdd = true; - const group: ZHAGroup = await addGroup( - this.hass, - this._groupName, - this._selectedDevicesToAdd - ); + const members = this._selectedDevicesToAdd.map((member) => { + const memberParts = member.split("_"); + return { ieee: memberParts[0], endpoint_id: memberParts[1] }; + }); + const group: ZHAGroup = await addGroup(this.hass, this._groupName, members); this._selectedDevicesToAdd = []; this._processingAdd = false; this._groupName = ""; diff --git a/src/panels/config/zha/zha-config-dashboard.ts b/src/panels/config/zha/zha-config-dashboard.ts index 4acf5faa91..88422f56c8 100644 --- a/src/panels/config/zha/zha-config-dashboard.ts +++ b/src/panels/config/zha/zha-config-dashboard.ts @@ -16,6 +16,7 @@ import "../../../components/data-table/ha-data-table"; import type { DataTableColumnContainer, RowClickedEvent, + DataTableRowData, } from "../../../components/data-table/ha-data-table"; import "../../../components/ha-card"; import "../../../components/ha-icon-next"; @@ -27,19 +28,19 @@ import type { HomeAssistant, Route } from "../../../types"; import "../ha-config-section"; import { formatAsPaddedHex, sortZHADevices } from "./functions"; -export interface DeviceRowData extends ZHADevice { +export interface DeviceRowData extends DataTableRowData { device?: DeviceRowData; } @customElement("zha-config-dashboard") class ZHAConfigDashboard extends LitElement { - @property() public hass!: HomeAssistant; + @property({ type: Object }) public hass!: HomeAssistant; - @property() public route!: Route; + @property({ type: Object }) public route!: Route; - @property() public narrow!: boolean; + @property({ type: Boolean }) public narrow!: boolean; - @property() public isWide!: boolean; + @property({ type: Boolean }) public isWide!: boolean; @property() private _devices: ZHADevice[] = []; @@ -91,7 +92,7 @@ class ZHAConfigDashboard extends LitElement { title: "IEEE", sortable: true, filterable: true, - width: "25%", + width: "30%", }, } ); diff --git a/src/panels/config/zha/zha-device-endpoint-data-table.ts b/src/panels/config/zha/zha-device-endpoint-data-table.ts new file mode 100644 index 0000000000..e758bb79e0 --- /dev/null +++ b/src/panels/config/zha/zha-device-endpoint-data-table.ts @@ -0,0 +1,182 @@ +import { + customElement, + html, + LitElement, + property, + query, + TemplateResult, + css, + CSSResult, +} from "lit-element"; +import memoizeOne from "memoize-one"; +import "../../../components/data-table/ha-data-table"; +import type { + DataTableColumnContainer, + HaDataTable, + DataTableRowData, +} from "../../../components/data-table/ha-data-table"; +import "../../../components/entity/ha-state-icon"; +import type { ZHADeviceEndpoint, ZHAEntityReference } from "../../../data/zha"; +import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info"; +import type { HomeAssistant } from "../../../types"; + +export interface DeviceEndpointRowData extends DataTableRowData { + id: string; + name: string; + model: string; + manufacturer: string; + endpoint_id: number; + entities: ZHAEntityReference[]; +} + +@customElement("zha-device-endpoint-data-table") +export class ZHADeviceEndpointDataTable extends LitElement { + @property({ type: Object }) public hass!: HomeAssistant; + + @property({ type: Boolean }) public narrow = false; + + @property({ type: Boolean }) public selectable = false; + + @property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = []; + + @query("ha-data-table") private _dataTable!: HaDataTable; + + private _deviceEndpoints = memoizeOne( + (deviceEndpoints: ZHADeviceEndpoint[]) => { + const outputDevices: DeviceEndpointRowData[] = []; + + deviceEndpoints.forEach((deviceEndpoint) => { + outputDevices.push({ + name: + deviceEndpoint.device.user_given_name || deviceEndpoint.device.name, + model: deviceEndpoint.device.model, + manufacturer: deviceEndpoint.device.manufacturer, + id: deviceEndpoint.device.ieee + "_" + deviceEndpoint.endpoint_id, + ieee: deviceEndpoint.device.ieee, + endpoint_id: deviceEndpoint.endpoint_id, + entities: deviceEndpoint.entities, + }); + }); + + return outputDevices; + } + ); + + private _columns = memoizeOne( + (narrow: boolean): DataTableColumnContainer => + narrow + ? { + name: { + title: "Devices", + sortable: true, + filterable: true, + direction: "asc", + grows: true, + template: (name) => html` +
+ ${name} +
+ `, + }, + endpoint_id: { + title: "Endpoint", + sortable: true, + filterable: true, + }, + } + : { + name: { + title: "Name", + sortable: true, + filterable: true, + direction: "asc", + grows: true, + template: (name) => html` +
+ ${name} +
+ `, + }, + endpoint_id: { + title: "Endpoint", + sortable: true, + filterable: true, + }, + entities: { + title: "Associated Entities", + sortable: false, + filterable: false, + width: "50%", + template: (entities) => html` + ${entities.length + ? entities.length > 3 + ? html`${entities.slice(0, 2).map( + (entity) => + html`
+ ${entity.name || entity.original_name} +
` + )} +
And ${entities.length - 2} more...
` + : entities.map( + (entity) => + html`
+ ${entity.name || entity.original_name} +
` + ) + : "This endpoint has no associated entities"} + `, + }, + } + ); + + public clearSelection() { + this._dataTable.clearSelection(); + } + + protected render(): TemplateResult { + return html` + + `; + } + + private async _handleClicked(ev: CustomEvent) { + const rowId = ((ev.target as HTMLElement).closest( + ".mdc-data-table__row" + ) as any).rowId; + const ieee = rowId.substring(0, rowId.indexOf("_")); + showZHADeviceInfoDialog(this, { ieee }); + } + + static get styles(): CSSResult[] { + return [ + css` + .table-cell-text { + word-break: break-word; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-device-endpoint-data-table": ZHADeviceEndpointDataTable; + } +} diff --git a/src/panels/config/zha/zha-devices-data-table.ts b/src/panels/config/zha/zha-devices-data-table.ts deleted file mode 100644 index 3808868633..0000000000 --- a/src/panels/config/zha/zha-devices-data-table.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; -import memoizeOne from "memoize-one"; -import "../../../components/data-table/ha-data-table"; -import type { - DataTableColumnContainer, - HaDataTable, -} from "../../../components/data-table/ha-data-table"; -import "../../../components/entity/ha-state-icon"; -import type { ZHADevice } from "../../../data/zha"; -import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info"; -import type { HomeAssistant } from "../../../types"; - -export interface DeviceRowData extends ZHADevice { - device?: DeviceRowData; -} - -@customElement("zha-devices-data-table") -export class ZHADevicesDataTable extends LitElement { - @property() public hass!: HomeAssistant; - - @property() public narrow = false; - - @property({ type: Boolean }) public selectable = false; - - @property() public devices: ZHADevice[] = []; - - @query("ha-data-table") private _dataTable!: HaDataTable; - - private _devices = memoizeOne((devices: ZHADevice[]) => { - let outputDevices: DeviceRowData[] = devices; - - outputDevices = outputDevices.map((device) => { - return { - ...device, - name: device.user_given_name || device.name, - model: device.model, - manufacturer: device.manufacturer, - id: device.ieee, - }; - }); - - return outputDevices; - }); - - private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => - narrow - ? { - name: { - title: "Devices", - sortable: true, - filterable: true, - direction: "asc", - grows: true, - template: (name) => html` -
- ${name} -
- `, - }, - } - : { - name: { - title: "Name", - sortable: true, - filterable: true, - direction: "asc", - grows: true, - template: (name) => html` -
- ${name} -
- `, - }, - manufacturer: { - title: "Manufacturer", - sortable: true, - filterable: true, - width: "20%", - }, - model: { - title: "Model", - sortable: true, - filterable: true, - width: "20%", - }, - } - ); - - public clearSelection() { - this._dataTable.clearSelection(); - } - - protected render(): TemplateResult { - return html` - - `; - } - - private async _handleClicked(ev: CustomEvent) { - const ieee = ((ev.target as HTMLElement).closest( - ".mdc-data-table__row" - ) as any).rowId; - showZHADeviceInfoDialog(this, { ieee }); - } -} - -declare global { - interface HTMLElementTagNameMap { - "zha-devices-data-table": ZHADevicesDataTable; - } -} diff --git a/src/panels/config/zha/zha-group-page.ts b/src/panels/config/zha/zha-group-page.ts index cdb0ee2dc0..461df7d9fd 100644 --- a/src/panels/config/zha/zha-group-page.ts +++ b/src/panels/config/zha/zha-group-page.ts @@ -9,8 +9,8 @@ import { LitElement, property, PropertyValues, + query, } from "lit-element"; -import memoizeOne from "memoize-one"; import { HASSDomEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table"; @@ -20,8 +20,8 @@ import { fetchGroupableDevices, removeGroups, removeMembersFromGroup, - ZHADevice, ZHAGroup, + ZHADeviceEndpoint, } from "../../../data/zha"; import "../../../layouts/hass-error-screen"; import "../../../layouts/hass-subpage"; @@ -29,37 +29,40 @@ import { HomeAssistant } from "../../../types"; import "../ha-config-section"; import { formatAsPaddedHex } from "./functions"; import "./zha-device-card"; -import "./zha-devices-data-table"; +import "./zha-device-endpoint-data-table"; +import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table"; @customElement("zha-group-page") export class ZHAGroupPage extends LitElement { - @property() public hass!: HomeAssistant; + @property({ type: Object }) public hass!: HomeAssistant; - @property() public group?: ZHAGroup; + @property({ type: Object }) public group?: ZHAGroup; - @property() public groupId!: number; + @property({ type: Number }) public groupId!: number; - @property() public narrow!: boolean; + @property({ type: Boolean }) public narrow!: boolean; - @property() public isWide!: boolean; + @property({ type: Boolean }) public isWide!: boolean; - @property() public devices: ZHADevice[] = []; + @property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = []; @property() private _processingAdd = false; @property() private _processingRemove = false; - @property() private _filteredDevices: ZHADevice[] = []; + @property() private _filteredDeviceEndpoints: ZHADeviceEndpoint[] = []; @property() private _selectedDevicesToAdd: string[] = []; @property() private _selectedDevicesToRemove: string[] = []; - private _firstUpdatedCalled = false; + @query("#addMembers") + private _zhaAddMembersDataTable!: ZHADeviceEndpointDataTable; - private _members = memoizeOne( - (group: ZHAGroup): ZHADevice[] => group.members - ); + @query("#removeMembers") + private _zhaRemoveMembersDataTable!: ZHADeviceEndpointDataTable; + + private _firstUpdatedCalled = false; public connectedCallback(): void { super.connectedCallback(); @@ -74,8 +77,8 @@ export class ZHAGroupPage extends LitElement { this._processingRemove = false; this._selectedDevicesToRemove = []; this._selectedDevicesToAdd = []; - this.devices = []; - this._filteredDevices = []; + this.deviceEndpoints = []; + this._filteredDeviceEndpoints = []; } protected firstUpdated(changedProperties: PropertyValues): void { @@ -97,8 +100,6 @@ export class ZHAGroupPage extends LitElement { `; } - const members = this._members(this.group); - return html` - ${members.length - ? members.map( + ${this.group.members.length + ? this.group.members.map( (member) => html` `} - ${members.length + ${this.group.members.length ? html`
${this.hass.localize( @@ -148,14 +149,15 @@ export class ZHAGroupPage extends LitElement { )}
- - +
- - +
{ - return !this.group!.members.some((member) => member.ieee === device.ieee); - }); + this._filteredDeviceEndpoints = this.deviceEndpoints.filter( + (deviceEndpoint) => { + return !this.group!.members.some( + (member) => + member.device.ieee === deviceEndpoint.device.ieee && + member.endpoint_id === deviceEndpoint.endpoint_id + ); + } + ); } private _handleAddSelectionChanged( @@ -244,25 +253,27 @@ export class ZHAGroupPage extends LitElement { private async _addMembersToGroup(): Promise { this._processingAdd = true; - this.group = await addMembersToGroup( - this.hass, - this.groupId, - this._selectedDevicesToAdd - ); + const members = this._selectedDevicesToAdd.map((member) => { + const memberParts = member.split("_"); + return { ieee: memberParts[0], endpoint_id: memberParts[1] }; + }); + this.group = await addMembersToGroup(this.hass, this.groupId, members); this._filterDevices(); this._selectedDevicesToAdd = []; + this._zhaAddMembersDataTable.clearSelection(); this._processingAdd = false; } private async _removeMembersFromGroup(): Promise { this._processingRemove = true; - this.group = await removeMembersFromGroup( - this.hass, - this.groupId, - this._selectedDevicesToRemove - ); + const members = this._selectedDevicesToRemove.map((member) => { + const memberParts = member.split("_"); + return { ieee: memberParts[0], endpoint_id: memberParts[1] }; + }); + this.group = await removeMembersFromGroup(this.hass, this.groupId, members); this._filterDevices(); this._selectedDevicesToRemove = []; + this._zhaRemoveMembersDataTable.clearSelection(); this._processingRemove = false; } From 825db8a56ad5aba8ab98e1b135e48b72577a0db0 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 12 May 2020 21:59:06 +0200 Subject: [PATCH 20/21] Bumped version to 20200512.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 44e5ce0fe4..770c6db60a 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20200509.0", + version="20200512.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From eb2b24d57cb8776e0e28807f60d29142dbe14e3e Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 12 May 2020 16:24:20 -0400 Subject: [PATCH 21/21] Weather Card: Fix overwritten changes (#5841) --- src/panels/lovelace/cards/hui-weather-forecast-card.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index 3b5f7bc377..3362162792 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -374,13 +374,13 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { top: 1px; } - .name, + .state, .temp-attribute .temp { font-size: 28px; line-height: 1.2; } - .state, + .name, .attribute { font-size: 14px; line-height: 1; @@ -438,7 +438,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { .attribute, .templow, - .state { + .name { color: var(--secondary-text-color); } @@ -467,7 +467,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { --mdc-icon-size: 52px; } - :host([narrow]) .name, + :host([narrow]) .state, :host([narrow]) .temp-attribute .temp { font-size: 22px; } @@ -483,7 +483,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { /* ============= VERY NARROW ============= */ - :host([veryNarrow]) .state, + :host([veryNarrow]) .name, :host([veryNarrow]) .attribute { display: none; }
@@ -85,7 +87,8 @@ class IntegrationsCard extends LitElement { )}