diff --git a/README.md b/README.md index ae27c71..14625e8 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,8 @@ A minimalistic yet customizable climate card for [Home Assistant](https://github | toggle: `hide` | boolean | optional | v1.0.2 | Hide button, default value `False` | toggle: `default` | boolean | optional | v1.0.2 | Default toggle button state, default value `off`. | **secondary_info** | object | optional | v1.1.0 | secondary_info config. [secondary info examples](#secondary-info) -| secondary_info: `type` | string | optional | v1.1.0 | available types: `last-changed, fan-mode, hvac-mode, hvac-action` -| secondary_info: `icon` | string | optional | v1.1.0 | icon for types: `fan-mode, hvac-mode`, `hvac-action` +| secondary_info: `type` | string | optional | v1.1.0 | available types: `last-changed, fan-mode, fan-mode-dropdown, hvac-mode, hvac-action` +| secondary_info: `icon` | string | optional | v1.1.0 | icon for types: `fan-mode, fan-mode-dropdown, hvac-mode`, `hvac-action` | secondary_info: `source` | object | optional | v1.2.1 | source available types: `hvac-action` | secondary_info: `source:{item_name}` | object | optional | v1.2.1 | source item name | secondary_info: `source:{item_name}:icon` | object | optional | v1.2.1 | Specify a custom icon from any of the available mdi icons. @@ -602,6 +602,15 @@ Or you can use one permanent icon icon: 'mdi:cached' ``` +##### fan-mode-dropdown + +```yaml +- type: custom:mini-climate + entity: climate.dahatsu + secondary_info: fan-mode-dropdown +``` +![image](https://user-images.githubusercontent.com/861063/84180244-d80d0a80-aa8f-11ea-8275-f4e3db85fd31.png) + ### Theme variables The following variables are available and can be set in your theme to change the appearence of the card. Can be specified by color name, hexadecimal, rgb, rgba, hsl, hsla, basically anything supported by CSS. diff --git a/release_notes/v1.2.1.md b/release_notes/v1.2.1.md index 45874b3..0fe2f57 100644 --- a/release_notes/v1.2.1.md +++ b/release_notes/v1.2.1.md @@ -49,3 +49,12 @@ Or you can use one permanent icon type: hvac-action icon: 'mdi:cached' ``` + +- Add new secondary_info type: `fan-mode-dropdown` #10 + +```yaml +- type: custom:mini-climate + entity: climate.dahatsu + secondary_info: fan-mode-dropdown +``` +![image](https://user-images.githubusercontent.com/861063/84180244-d80d0a80-aa8f-11ea-8275-f4e3db85fd31.png) diff --git a/src/components/fan-mode-secondary.js b/src/components/fan-mode-secondary.js new file mode 100644 index 0000000..3bbfea3 --- /dev/null +++ b/src/components/fan-mode-secondary.js @@ -0,0 +1,127 @@ +import { LitElement, html, css } from 'lit-element'; +import sharedStyle from '../sharedStyle'; + +class FanModeSecondary extends LitElement { + constructor() { + super(); + this.fanMode = {}; + this.config = {}; + this.timer = undefined; + this._selected = {}; + this.source = {}; + } + + static get properties() { + return { + fanMode: { type: Object }, + config: { type: Object }, + }; + } + + get selectedIndex() { + return this.fanMode.source.map(item => item.id).indexOf(this._selected.id); + } + + handleChange(e) { + const index = e.target.selected; + + if (index === this.selectedIndex || !this.fanMode.source[index]) + return; + + clearTimeout(this.timer); + + const selected = this.fanMode.source[index]; + const { entity } = this.fanMode; + const oldSelected = this._selected; + this._selected = selected; + + this.timer = setTimeout(async () => { + if (this.fanMode.entity === entity) { + this._selected = oldSelected; + return this.requestUpdate('_selected'); + } + }, this.fanMode.actionTimeout); + + this.fanMode.handleChange(selected.id); + + return this.requestUpdate('_selected'); + } + + renderFanMode() { + const label = this._selected ? this._selected.name : this.fanMode.state; + const icon = this.config.secondary_info.icon ? this.config.secondary_info.icon + : this.fanMode.icon; + + return html` + + ${label} + `; + } + + renderFanModeDropdown() { + return html` + +
+ ${this.renderFanMode()} +
+ + ${this.fanMode.source.map(item => html` + + ${item.name} + `)} + +
+ `; + } + + render() { + const { type } = this.config.secondary_info; + + if (type === 'fan-mode-dropdown') { + return this.renderFanModeDropdown(); + } + + return this.renderFanMode(); + } + + updated(changedProps) { + if (changedProps.has('fanMode')) { + clearTimeout(this.timer); + this._selected = this.fanMode.selected; + this.requestUpdate('_selected').then(); + } + } + + static get styles() { + return [ + sharedStyle, + css` + paper-menu-button { + padding: 0; + } + .name { + font-size: calc(var(--mc-unit) * .35); + font-weight: var(--mc-info-font-weight); + line-height: calc(var(--mc-unit) * .5); + vertical-align: middle; + display: inline-block; + } + .icon { + color: var(--mc-icon-color); + height: calc(var(--mc-unit) * .475); + width: calc(var(--mc-unit) * .5); + min-width: calc(var(--mc-unit) * .5); + --mdc-icon-size: calc(var(--mc-unit) * 0.5); + } + `]; + } +} + +customElements.define('mc-fan-mode-secondary', FanModeSecondary); diff --git a/src/components/secondary-info.js b/src/components/secondary-info.js index 26590ad..e6747d9 100644 --- a/src/components/secondary-info.js +++ b/src/components/secondary-info.js @@ -1,5 +1,6 @@ import { LitElement, html, css } from 'lit-element'; import sharedStyle from '../sharedStyle'; +import './fan-mode-secondary'; class SecondaryInfo extends LitElement { constructor() { @@ -44,18 +45,6 @@ class SecondaryInfo extends LitElement { `; } - renderFanMode() { - const { selected } = this.fanMode; - const label = selected ? selected.name : this.fanMode.state; - const icon = this.config.secondary_info.icon ? this.config.secondary_info.icon - : this.fanMode.icon; - - return html` - - ${label} - `; - } - render() { const { type } = this.config.secondary_info; @@ -67,7 +56,7 @@ class SecondaryInfo extends LitElement { case 'last-changed': return html``; default: - return this.renderFanMode(); + return html``; } } diff --git a/src/main.js b/src/main.js index 1c7e882..234a0c6 100644 --- a/src/main.js +++ b/src/main.js @@ -458,6 +458,7 @@ class MiniClimate extends LitElement { } render() { + const handle = this.config.secondary_info.type !== 'fan-mode-dropdown'; return html`
-
this.handlePopup(e)}> +
this.handlePopup(e, handle)}> ${this.renderEntityName()}
@@ -492,7 +492,10 @@ class MiniClimate extends LitElement { return this.requestUpdate('targetTemperatureChanging'); } - handlePopup(e) { + handlePopup(e, handle) { + if (!handle) + return; + e.stopPropagation(); handleClick(this, this.hass, this.config.tap_action, this.climate.id); } @@ -558,7 +561,7 @@ class MiniClimate extends LitElement { renderEntityName() { return html` -
+
this.handlePopup(e, true)}> ${this.name}
${this.renderSecondaryInfo()}