Add dark mode toggle to gallery cards (#7532)

This commit is contained in:
Bram Kragten 2020-11-02 10:46:52 +01:00 committed by GitHub
parent 57500f6c97
commit da12233ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 131 additions and 129 deletions

View File

@ -5,11 +5,16 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../src/components/ha-switch"; import "../../../src/components/ha-switch";
import "../../../src/components/ha-formfield"; import "../../../src/components/ha-formfield";
import "./demo-card"; import "./demo-card";
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
class DemoCards extends PolymerElement { class DemoCards extends PolymerElement {
static get template() { static get template() {
return html` return html`
<style> <style>
#container {
min-height: calc(100vh - 128px);
background: var(--primary-background-color);
}
.cards { .cards {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -24,6 +29,9 @@ class DemoCards extends PolymerElement {
.filters { .filters {
margin-left: 60px; margin-left: 60px;
} }
ha-formfield {
margin-right: 16px;
}
</style> </style>
<app-toolbar> <app-toolbar>
<div class="filters"> <div class="filters">
@ -31,16 +39,21 @@ class DemoCards extends PolymerElement {
<ha-switch checked="[[_showConfig]]" on-change="_showConfigToggled"> <ha-switch checked="[[_showConfig]]" on-change="_showConfigToggled">
</ha-switch> </ha-switch>
</ha-formfield> </ha-formfield>
<ha-formfield label="Dark theme">
<ha-switch on-change="_darkThemeToggled"> </ha-switch>
</ha-formfield>
</div> </div>
</app-toolbar> </app-toolbar>
<div class="cards"> <div id="container">
<template is="dom-repeat" items="[[configs]]"> <div class="cards">
<demo-card <template is="dom-repeat" items="[[configs]]">
config="[[item]]" <demo-card
show-config="[[_showConfig]]" config="[[item]]"
hass="[[hass]]" show-config="[[_showConfig]]"
></demo-card> hass="[[hass]]"
</template> ></demo-card>
</template>
</div>
</div> </div>
`; `;
} }
@ -59,6 +72,12 @@ class DemoCards extends PolymerElement {
_showConfigToggled(ev) { _showConfigToggled(ev) {
this._showConfig = ev.target.checked; this._showConfig = ev.target.checked;
} }
_darkThemeToggled(ev) {
applyThemesOnElement(this.$.container, { themes: {} }, "default", {
dark: ev.target.checked,
});
}
} }
customElements.define("demo-cards", DemoCards); customElements.define("demo-cards", DemoCards);

View File

@ -3,7 +3,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element"; import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";
import "../../../src/state-summary/state-card-content"; import "../../../src/state-summary/state-card-content";
import "./more-info-content"; import "../../../src/dialogs/more-info/more-info-content";
class DemoMoreInfo extends PolymerElement { class DemoMoreInfo extends PolymerElement {
static get template() { static get template() {
@ -16,15 +16,12 @@ class DemoMoreInfo extends PolymerElement {
ha-card { ha-card {
width: 333px; width: 333px;
padding: 20px 24px;
} }
state-card-content { state-card-content {
display: block; display: block;
padding: 16px; margin-bottom: 16px;
}
more-info-content {
padding: 0 16px;
} }
pre { pre {

View File

@ -1,73 +0,0 @@
import { HassEntity } from "home-assistant-js-websocket";
import { property, PropertyValues, UpdatingElement } from "lit-element";
import dynamicContentUpdater from "../../../src/common/dom/dynamic_content_updater";
import { stateMoreInfoType } from "../../../src/dialogs/more-info/state_more_info_control";
import "../../../src/dialogs/more-info/controls/more-info-alarm_control_panel";
import "../../../src/dialogs/more-info/controls/more-info-automation";
import "../../../src/dialogs/more-info/controls/more-info-camera";
import "../../../src/dialogs/more-info/controls/more-info-climate";
import "../../../src/dialogs/more-info/controls/more-info-configurator";
import "../../../src/dialogs/more-info/controls/more-info-counter";
import "../../../src/dialogs/more-info/controls/more-info-cover";
import "../../../src/dialogs/more-info/controls/more-info-default";
import "../../../src/dialogs/more-info/controls/more-info-fan";
import "../../../src/dialogs/more-info/controls/more-info-group";
import "../../../src/dialogs/more-info/controls/more-info-humidifier";
import "../../../src/dialogs/more-info/controls/more-info-input_datetime";
import "../../../src/dialogs/more-info/controls/more-info-light";
import "../../../src/dialogs/more-info/controls/more-info-lock";
import "../../../src/dialogs/more-info/controls/more-info-media_player";
import "../../../src/dialogs/more-info/controls/more-info-person";
import "../../../src/dialogs/more-info/controls/more-info-script";
import "../../../src/dialogs/more-info/controls/more-info-sun";
import "../../../src/dialogs/more-info/controls/more-info-timer";
import "../../../src/dialogs/more-info/controls/more-info-vacuum";
import "../../../src/dialogs/more-info/controls/more-info-water_heater";
import "../../../src/dialogs/more-info/controls/more-info-weather";
import { HomeAssistant } from "../../../src/types";
class MoreInfoContent extends UpdatingElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@property() public stateObj?: HassEntity;
private _detachedChild?: ChildNode;
protected firstUpdated(): void {
this.style.position = "relative";
this.style.display = "block";
}
// This is not a lit element, but an updating element, so we implement update
protected update(changedProps: PropertyValues): void {
super.update(changedProps);
const stateObj = this.stateObj;
const hass = this.hass;
if (!stateObj || !hass) {
if (this.lastChild) {
this._detachedChild = this.lastChild;
// Detach child to prevent it from doing work.
this.removeChild(this.lastChild);
}
return;
}
if (this._detachedChild) {
this.appendChild(this._detachedChild);
this._detachedChild = undefined;
}
const moreInfoType =
stateObj.attributes && "custom_ui_more_info" in stateObj.attributes
? stateObj.attributes.custom_ui_more_info
: "more-info-" + stateMoreInfoType(stateObj);
dynamicContentUpdater(this, moreInfoType.toUpperCase(), {
hass,
stateObj,
});
}
}
customElements.define("more-info-content", MoreInfoContent);

View File

@ -15,6 +15,10 @@ const ENTITIES = [
getEntity("alarm_control_panel", "unavailable", "unavailable", { getEntity("alarm_control_panel", "unavailable", "unavailable", {
friendly_name: "Alarm", friendly_name: "Alarm",
}), }),
getEntity("alarm_control_panel", "alarm_code", "disarmed", {
friendly_name: "Alarm",
code_format: "number",
}),
]; ];
const CONFIGS = [ const CONFIGS = [
@ -30,7 +34,14 @@ const CONFIGS = [
config: ` config: `
- type: alarm-panel - type: alarm-panel
entity: alarm_control_panel.alarm_armed entity: alarm_control_panel.alarm_armed
title: My Alarm name: My Alarm
`,
},
{
heading: "Code Example",
config: `
- type: alarm-panel
entity: alarm_control_panel.alarm_code
`, `,
}, },
{ {
@ -83,8 +94,12 @@ class DemoAlarmPanelEntity extends PolymerElement {
public ready() { public ready() {
super.ready(); super.ready();
this._setupDemo();
}
private async _setupDemo() {
const hass = provideHass(this.$.demos); const hass = provideHass(this.$.demos);
hass.updateTranslations(null, "en"); await hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES); hass.addEntities(ENTITIES);
} }
} }

View File

@ -98,4 +98,4 @@ class DemoButtonEntity extends PolymerElement {
} }
} }
customElements.define("demo-hui-button-card", DemoButtonEntity); customElements.define("demo-hui-entity-button-card", DemoButtonEntity);

View File

@ -6,7 +6,7 @@ import { SUPPORT_BRIGHTNESS } from "../../../src/data/light";
import { getEntity } from "../../../src/fake_data/entity"; import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass"; import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-more-infos"; import "../components/demo-more-infos";
import "../components/more-info-content"; import "../../../src/dialogs/more-info/more-info-content";
const ENTITIES = [ const ENTITIES = [
getEntity("light", "bed_light", "on", { getEntity("light", "bed_light", "on", {
@ -40,8 +40,12 @@ class DemoMoreInfoLight extends PolymerElement {
public ready() { public ready() {
super.ready(); super.ready();
this._setupDemo();
}
private async _setupDemo() {
const hass = provideHass(this); const hass = provideHass(this);
hass.updateTranslations(null, "en"); await hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES); hass.addEntities(ENTITIES);
} }
} }

View File

@ -17,14 +17,10 @@ import {
DOMAINS_MORE_INFO_NO_HISTORY, DOMAINS_MORE_INFO_NO_HISTORY,
DOMAINS_WITH_MORE_INFO, DOMAINS_WITH_MORE_INFO,
} from "../../common/const"; } from "../../common/const";
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
import { fireEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event";
import { computeDomain } from "../../common/entity/compute_domain"; import { computeDomain } from "../../common/entity/compute_domain";
import { computeStateName } from "../../common/entity/compute_state_name"; import { computeStateName } from "../../common/entity/compute_state_name";
import {
stateMoreInfoType,
importMoreInfoControl,
} from "./state_more_info_control";
import { navigate } from "../../common/navigate"; import { navigate } from "../../common/navigate";
import "../../components/ha-dialog"; import "../../components/ha-dialog";
import "../../components/ha-header-bar"; import "../../components/ha-header-bar";
@ -39,6 +35,7 @@ import "./ha-more-info-history";
import "./ha-more-info-logbook"; import "./ha-more-info-logbook";
import "./controls/more-info-default"; import "./controls/more-info-default";
import { CONTINUOUS_DOMAINS } from "../../data/logbook"; import { CONTINUOUS_DOMAINS } from "../../data/logbook";
import "./more-info-content";
const DOMAINS_NO_INFO = ["camera", "configurator"]; const DOMAINS_NO_INFO = ["camera", "configurator"];
/** /**
@ -63,8 +60,6 @@ export class MoreInfoDialog extends LitElement {
@internalProperty() private _entityId?: string | null; @internalProperty() private _entityId?: string | null;
@internalProperty() private _moreInfoType?: string;
@internalProperty() private _currTabIndex = 0; @internalProperty() private _currTabIndex = 0;
public showDialog(params: MoreInfoDialogParams) { public showDialog(params: MoreInfoDialogParams) {
@ -74,18 +69,6 @@ export class MoreInfoDialog extends LitElement {
return; return;
} }
this.large = false; this.large = false;
const stateObj = this.hass.states[this._entityId];
if (!stateObj) {
return;
}
if (stateObj.attributes && "custom_ui_more_info" in stateObj.attributes) {
this._moreInfoType = stateObj.attributes.custom_ui_more_info;
} else {
const type = stateMoreInfoType(stateObj);
importMoreInfoControl(type);
this._moreInfoType = type === "hidden" ? undefined : `more-info-${type}`;
}
} }
public closeDialog() { public closeDialog() {
@ -218,12 +201,10 @@ export class MoreInfoDialog extends LitElement {
.hass=${this.hass} .hass=${this.hass}
.entityId=${this._entityId} .entityId=${this._entityId}
></ha-more-info-logbook>`} ></ha-more-info-logbook>`}
${this._moreInfoType <more-info-content
? dynamicElement(this._moreInfoType, { .stateObj=${stateObj}
hass: this.hass, .hass=${this.hass}
stateObj, ></more-info-content>
})
: ""}
${stateObj.attributes.restored ${stateObj.attributes.restored
? html` ? html`
<p> <p>

View File

@ -0,0 +1,57 @@
import { HassEntity } from "home-assistant-js-websocket";
import { property, PropertyValues, UpdatingElement } from "lit-element";
import { HomeAssistant } from "../../types";
import dynamicContentUpdater from "../../common/dom/dynamic_content_updater";
import { stateMoreInfoType } from "./state_more_info_control";
import { importMoreInfoControl } from "../../panels/lovelace/custom-card-helpers";
class MoreInfoContent extends UpdatingElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@property() public stateObj?: HassEntity;
private _detachedChild?: ChildNode;
// This is not a lit element, but an updating element, so we implement update
protected update(changedProps: PropertyValues): void {
super.update(changedProps);
const stateObj = this.stateObj;
const hass = this.hass;
if (!stateObj || !hass) {
if (this.lastChild) {
this._detachedChild = this.lastChild;
// Detach child to prevent it from doing work.
this.removeChild(this.lastChild);
}
return;
}
if (this._detachedChild) {
this.appendChild(this._detachedChild);
this._detachedChild = undefined;
}
let moreInfoType: string | undefined;
if (stateObj.attributes && "custom_ui_more_info" in stateObj.attributes) {
moreInfoType = stateObj.attributes.custom_ui_more_info;
} else {
const type = stateMoreInfoType(stateObj);
importMoreInfoControl(type);
moreInfoType = type === "hidden" ? undefined : `more-info-${type}`;
}
if (!moreInfoType) {
return;
}
dynamicContentUpdater(this, moreInfoType.toUpperCase(), {
hass,
stateObj,
});
}
}
customElements.define("more-info-content", MoreInfoContent);

View File

@ -53,19 +53,21 @@ export const provideHass = (
} = {}; } = {};
const entities = {}; const entities = {};
function updateTranslations(fragment: null | string, language?: string) { async function updateTranslations(
fragment: null | string,
language?: string
) {
const lang = language || getLocalLanguage(); const lang = language || getLocalLanguage();
getTranslation(fragment, lang).then(async (translation) => { const translation = await getTranslation(fragment, lang);
const resources = { const resources = {
[lang]: { [lang]: {
...(hass().resources && hass().resources[lang]), ...(hass().resources && hass().resources[lang]),
...translation.data, ...translation.data,
}, },
}; };
hass().updateHass({ hass().updateHass({
resources, resources,
localize: await computeLocalize(elements[0], lang, resources), localize: await computeLocalize(elements[0], lang, resources),
});
}); });
} }