diff --git a/demo/public/index.html b/demo/public/index.html index c38b7ce1f8..fae365931d 100644 --- a/demo/public/index.html +++ b/demo/public/index.html @@ -7,6 +7,32 @@ content="width=device-width, initial-scale=1, shrink-to-fit=no" /> + + + + + + + + + + + + + + Home Assistant Demo diff --git a/demo/src/configs/demo-configs.ts b/demo/src/configs/demo-configs.ts index 143c237085..4f0ee519f4 100644 --- a/demo/src/configs/demo-configs.ts +++ b/demo/src/configs/demo-configs.ts @@ -18,9 +18,12 @@ export const setDemoConfig = async ( lovelace: Lovelace, index: number ) => { + const confProm = demoConfigs[index](); + const config = await confProm; + selectedDemoConfigIndex = index; - selectedDemoConfig = demoConfigs[index](); - const config = await selectedDemoConfig; + selectedDemoConfig = confProm; + hass.addEntities(config.entities(), true); lovelace.saveConfig(config.lovelace()); hass.mockTheme(config.theme()); diff --git a/demo/src/configs/kernehed/lovelace.ts b/demo/src/configs/kernehed/lovelace.ts index a8b108c94e..e9c87e1966 100644 --- a/demo/src/configs/kernehed/lovelace.ts +++ b/demo/src/configs/kernehed/lovelace.ts @@ -352,9 +352,18 @@ export const demoLovelaceKernehed: () => LovelaceConfig = () => ({ }, { entities: [ - "sensor.pi_hole_dns_queries_today", - "sensor.pi_hole_ads_blocked_today", - "sensor.pi_hole_dns_unique_clients", + { + entity: "sensor.pi_hole_dns_queries_today", + name: "DNS Queries Today", + }, + { + entity: "sensor.pi_hole_ads_blocked_today", + name: "Ads Blocked Today", + }, + { + entity: "sensor.pi_hole_dns_unique_clients", + name: "DNS Unique Clients", + }, ], show_header_toggle: false, type: "entities", @@ -369,16 +378,16 @@ export const demoLovelaceKernehed: () => LovelaceConfig = () => ({ "binary_sensor.windows_server", "binary_sensor.teamspeak", "binary_sensor.harmony_hub", - { - style: { - height: "1px", - width: "85%", - "margin-left": "auto", - background: "#62717b", - "margin-right": "auto", - }, - type: "divider", - }, + // { + // style: { + // height: "1px", + // width: "85%", + // "margin-left": "auto", + // background: "#62717b", + // "margin-right": "auto", + // }, + // type: "divider", + // }, // { // items: ["sensor.uptime_router", "sensor.installerad_routeros"], // head: { diff --git a/demo/src/configs/teachingbirds/lovelace.ts b/demo/src/configs/teachingbirds/lovelace.ts index c28ada87d2..1ea3292746 100644 --- a/demo/src/configs/teachingbirds/lovelace.ts +++ b/demo/src/configs/teachingbirds/lovelace.ts @@ -231,62 +231,62 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ cards: [ { cards: [ - { - entities: [ - { - name: "Front door lock", - entity: "sensor.front_door_lock", - }, - { - name: "Yard door lock", - entity: "sensor.yard_door_lock", - }, - "sensor.front_door", - "sensor.back_door", - "sensor.backyard_door", - "sensor.balcony_door", - "sensor.yard_door", - { - name: "Dining area", - entity: "sensor.dining_area_window", - }, - { - name: "Bedroom", - entity: "sensor.bedroom_window", - }, - { - name: "Ring motion", - entity: "sensor.front_door_outdoor_movement", - }, - "sensor.hallway_movement", - "sensor.passage_movement", - "sensor.upstairs_hallway_movement", - "sensor.living_room_movement", - "sensor.back_door_camera_movement", - { - name: "Storage door", - entity: "sensor.yard_storage_door", - }, - "sensor.water_heater", - "sensor.kitchen_sink", - "binary_sensor.smoke_sensor_158d0001d37bdd", - "binary_sensor.smoke_sensor_158d0001d37be5", - "binary_sensor.smoke_sensor_158d0001d37c82", - ], - show_empty: false, - type: "entity-filter", - card: { - type: "glance", - show_state: false, - }, - state_filter: [ - "Open", - "Movement detected", - "Leaking", - "Unlocked", - "on", - ], - }, + // { + // entities: [ + // { + // name: "Front door lock", + // entity: "sensor.front_door_lock", + // }, + // { + // name: "Yard door lock", + // entity: "sensor.yard_door_lock", + // }, + // "sensor.front_door", + // "sensor.back_door", + // "sensor.backyard_door", + // "sensor.balcony_door", + // "sensor.yard_door", + // { + // name: "Dining area", + // entity: "sensor.dining_area_window", + // }, + // { + // name: "Bedroom", + // entity: "sensor.bedroom_window", + // }, + // { + // name: "Ring motion", + // entity: "sensor.front_door_outdoor_movement", + // }, + // "sensor.hallway_movement", + // "sensor.passage_movement", + // "sensor.upstairs_hallway_movement", + // "sensor.living_room_movement", + // "sensor.back_door_camera_movement", + // { + // name: "Storage door", + // entity: "sensor.yard_storage_door", + // }, + // "sensor.water_heater", + // "sensor.kitchen_sink", + // "binary_sensor.smoke_sensor_158d0001d37bdd", + // "binary_sensor.smoke_sensor_158d0001d37be5", + // "binary_sensor.smoke_sensor_158d0001d37c82", + // ], + // show_empty: false, + // type: "entity-filter", + // card: { + // type: "glance", + // show_state: false, + // }, + // state_filter: [ + // "Open", + // "Movement detected", + // "Leaking", + // "Unlocked", + // "on", + // ], + // }, { entities: [ "light.outdoor_lights", @@ -676,6 +676,7 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ }, ], title: "Home info", + path: "home_info", icon: "mdi:home-heart", }, { diff --git a/demo/src/configs/teachingbirds/theme.ts b/demo/src/configs/teachingbirds/theme.ts index 2bcc194c96..890100d90e 100644 --- a/demo/src/configs/teachingbirds/theme.ts +++ b/demo/src/configs/teachingbirds/theme.ts @@ -6,6 +6,7 @@ export const demoThemeTeachingbirds = () => ({ "paper-item-icon-color": "#d3d3d3", "divider-color": "rgba(255, 255, 255, 0.12)", "primary-color": "#389638", + "light-primary-color": "#6f956f", "label-badge-red": "var(--primary-color)", "paper-slider-secondary-color": "var(--light-primary-color)", "paper-slider-knob-color": "var(--primary-color)", diff --git a/demo/src/custom-cards/ha-demo-card.ts b/demo/src/custom-cards/ha-demo-card.ts index 0ea3ee5d12..0555c42bcb 100644 --- a/demo/src/custom-cards/ha-demo-card.ts +++ b/demo/src/custom-cards/ha-demo-card.ts @@ -1,6 +1,14 @@ -import { LitElement, html, CSSResult, css } from "lit-element"; +import { + LitElement, + html, + CSSResult, + css, + PropertyDeclarations, +} from "lit-element"; import { until } from "lit-html/directives/until"; import "@polymer/paper-icon-button"; +import "@polymer/paper-button"; +import "@polymer/paper-spinner/paper-spinner-lite"; import "../../../src/components/ha-card"; import { LovelaceCard, Lovelace } from "../../../src/panels/lovelace/types"; import { LovelaceCardConfig } from "../../../src/data/lovelace"; @@ -15,6 +23,15 @@ import { export class HADemoCard extends LitElement implements LovelaceCard { public lovelace?: Lovelace; public hass?: MockHomeAssistant; + private _switching?: boolean; + + static get properties(): PropertyDeclarations { + return { + lovelace: {}, + hass: {}, + _switching: {}, + }; + } public getCardSize() { return 2; @@ -28,36 +45,51 @@ export class HADemoCard extends LitElement implements LovelaceCard { protected render() { return html` - +
${ - until( - selectedDemoConfig.then( - (conf) => html` - ${conf.name} - - by - - ${conf.authorName} - - + this._switching + ? html` + ` - ), - "" - ) + : until( + selectedDemoConfig.then( + (conf) => html` + ${conf.name} + + by + + ${conf.authorName} + + + ` + ), + "" + ) }
+
+ Welcome home! You've reached the Home Assistant demo where we showcase + the best UIs created by our community. +
+
`; } @@ -78,39 +110,28 @@ export class HADemoCard extends LitElement implements LovelaceCard { ); } - private _updateConfig(index: number) { - setDemoConfig(this.hass!, this.lovelace!, index); + private async _updateConfig(index: number) { + this._switching = true; + try { + await setDemoConfig(this.hass!, this.lovelace!, index); + } catch (err) { + alert("Failed to switch config :-("); + } finally { + this._switching = false; + } } static get styles(): CSSResult[] { return [ css` - .content { - padding: 0 16px; - } - - ul { - margin-top: 0; - margin-bottom: 0; - padding: 16px 16px 16px 38px; - } - - li { - padding: 8px 0; - } - - li:first-child { - margin-top: -8px; - } - - li:last-child { - margin-bottom: -8px; - } - a { color: var(--primary-color); } + .content { + padding: 16px; + } + .picker { display: flex; justify-content: space-between; @@ -125,6 +146,15 @@ export class HADemoCard extends LitElement implements LovelaceCard { .picker small { display: block; } + + .actions { + padding-left: 5px; + } + + .actions paper-button { + color: var(--primary-color); + font-weight: 500; + } `, ]; } diff --git a/demo/src/ha-demo.ts b/demo/src/ha-demo.ts index e1992c95e3..71174d0ada 100644 --- a/demo/src/ha-demo.ts +++ b/demo/src/ha-demo.ts @@ -12,6 +12,10 @@ class HaDemo extends HomeAssistant { protected async _handleConnProm() { const initial: Partial = { panelUrl: (this as any).panelUrl, + // Override updateHass so that the correct hass lifecycle methods are called + updateHass: (hassUpdate) => + // @ts-ignore + this._updateHass(hassUpdate), }; const hass = provideHass(this, initial); diff --git a/src/fake_data/provide_hass.ts b/src/fake_data/provide_hass.ts index f1fb42b133..4bb724ee01 100644 --- a/src/fake_data/provide_hass.ts +++ b/src/fake_data/provide_hass.ts @@ -45,15 +45,8 @@ export const provideHass = ( } = {}; const entities = {}; - function updateHass(obj: Partial) { - const newHass = { ...hass(), ...obj }; - elements.forEach((el) => { - el.hass = newHass; - }); - } - function updateStates(newStates: HassEntities) { - updateHass({ + hass().updateHass({ states: { ...hass().states, ...newStates }, }); } @@ -66,7 +59,7 @@ export const provideHass = ( states[ent.entityId] = ent.toState(); }); if (replace) { - updateHass({ + hass().updateHass({ states, }); } else { @@ -93,7 +86,7 @@ export const provideHass = ( ); }); - updateHass({ + const hassObj: MockHomeAssistant = { // Home Assistant properties auth: {} as any, connection: { @@ -141,11 +134,11 @@ export const provideHass = ( panelUrl: "lovelace", language: getActiveTranslation(), - resources: null, + resources: null as any, - translationMetadata, + translationMetadata: translationMetadata as any, dockedSidebar: false, - moreInfoEntityId: null, + moreInfoEntityId: null as any, async callService(domain, service, data) { fireEvent(elements[0], "hass-notification", { message: `Called service ${domain}/${service}`, @@ -197,7 +190,12 @@ export const provideHass = ( // Mock stuff mockEntities: entities, - updateHass, + updateHass(obj: Partial) { + const newHass = { ...hass(), ...obj }; + elements.forEach((el) => { + el.hass = newHass; + }); + }, updateStates, addEntities, mockWS(type, callback) { @@ -208,7 +206,7 @@ export const provideHass = ( (eventListeners[event] || []).forEach((fn) => fn(event)); }, mockTheme(theme) { - updateHass({ + hass().updateHass({ selectedTheme: theme ? "mock" : "default", themes: { ...hass().themes, @@ -217,15 +215,22 @@ export const provideHass = ( }, }, }); - const hassObj = hass(); - elements.forEach((el) => { - applyThemesOnElement(el, hassObj.themes, hassObj.selectedTheme, true); - }); + const { themes, selectedTheme } = hass(); + applyThemesOnElement( + document.documentElement, + themes, + selectedTheme, + true + ); }, ...overrideData, - } as MockHomeAssistant); + }; + + // Update the elements. Note, we call it on hassObj so that if it was + // overridden (like in the demo), it will still work. + hassObj.updateHass(hassObj); // @ts-ignore - return hass(); + return hassObj; }; diff --git a/src/layouts/app/home-assistant.js b/src/layouts/app/home-assistant.js index 37426f25da..808db0b41b 100644 --- a/src/layouts/app/home-assistant.js +++ b/src/layouts/app/home-assistant.js @@ -47,14 +47,14 @@ export class HomeAssistant extends ext(PolymerElement, [ use-hash-as-path="[[_useHashAsPath]]" > diff --git a/src/layouts/partial-panel-resolver.js b/src/layouts/partial-panel-resolver.js index fd7fbf3ff0..f427954372 100644 --- a/src/layouts/partial-panel-resolver.js +++ b/src/layouts/partial-panel-resolver.js @@ -117,7 +117,7 @@ class PartialPanelResolver extends NavigateMixin(PolymerElement) { }