From 6af277a71efdf7c2707305f14be5c0f4a7227bb6 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 18 Aug 2020 18:57:10 -0500 Subject: [PATCH] Continued work --- src/components/ha-labeled-slider.js | 1 + src/components/ha-vertical-range-input.ts | 155 +++++++++ .../more-info/controls/more-info-light.ts | 300 ++++++++++-------- 3 files changed, 321 insertions(+), 135 deletions(-) create mode 100644 src/components/ha-vertical-range-input.ts diff --git a/src/components/ha-labeled-slider.js b/src/components/ha-labeled-slider.js index ef49e80077..8e23619d9d 100644 --- a/src/components/ha-labeled-slider.js +++ b/src/components/ha-labeled-slider.js @@ -30,6 +30,7 @@ class HaLabeledSlider extends PolymerElement { ha-paper-slider { flex-grow: 1; background-image: var(--ha-slider-background); + border-radius: var(--ha-slider-border-radius); } diff --git a/src/components/ha-vertical-range-input.ts b/src/components/ha-vertical-range-input.ts new file mode 100644 index 0000000000..df3bc4c72f --- /dev/null +++ b/src/components/ha-vertical-range-input.ts @@ -0,0 +1,155 @@ +import { + LitElement, + TemplateResult, + html, + CSSResult, + css, + customElement, + property, +} from "lit-element"; +import { fireEvent } from "../common/dom/fire_event"; + +@customElement("ha-vertical-range-input") +class HaVerticalRangeInput extends LitElement { + @property({ type: Number }) public value!: number; + + @property({ type: Number }) public max = 100; + + @property({ type: Number }) public min = 1; + + @property({ type: Number }) public step = 1; + + protected render(): TemplateResult { + if (!this.value) { + return html``; + } + + return html` + + `; + } + + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "value-changed", { + value: (ev.currentTarget as HTMLInputElement).value, + }); + } + + static get styles(): CSSResult { + return css` + :host { + height: calc(var(--vertical-range-height, 300px) + 5px); + width: var(--vertical-range-width, 100px); + position: relative; + display: block; + max-height: none; + } + + :host input { + width: var(--vertical-range-height, 300px); + height: var(--vertical-range-width, 100px); + margin: 0; + outline: 0; + overflow: hidden; + border: 1px solid var(--divider-color); + /* background: var(--vertical-range-track-color, #fafafa); */ + border-radius: 8px; + position: absolute; + top: calc(50% - var(--vertical-range-width, 100px) / 2); + right: calc(50% - var(--vertical-range-height, 300px) / 2); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -o-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); + -webkit-appearance: none; + } + + :host input::-webkit-slider-runnable-track { + height: 100%; + background: var(--vertical-range-track-color, #fafafa); + } + + :host input::-webkit-slider-thumb { + -webkit-appearance: none; + position: relative; + cursor: grab; + width: var(--vertical-range-thumb-height, 25px); + height: var(--vertical-range-thumb-width, 100%); + background: var(--vertical-range-thumb-color, #fafafa); + box-shadow: calc(var(--vertical-range-height, 300px) * -1) 0 0 + var(--vertical-range-height, 300px) + var(--vertical-range-color, var(--state-icon-active-color)); + border-right: 10px solid + var( + --vertical-range-thumb-padding-color, + var(--state-icon-active-color) + ); + border-left: 10px solid + var( + --vertical-range-thumb-padding-color, + var(--state-icon-active-color) + ); + border-top: 20px solid + var( + --vertical-range-thumb-padding-color, + var(--state-icon-active-color) + ); + border-bottom: 20px solid + var( + --vertical-range-thumb-padding-color, + var(--state-icon-active-color) + ); + transition: box-shadow 0.2s ease-in-out; + } + + :host input::-webkit-slider-thumb:active { + cursor: grabbing; + } + + /* Firefox */ + :host input::-moz-thumb-track { + height: 100%; + background-color: var(--vertical-range-track-color, #fafafa); + } + + :host input::-moz-range-thumb { + width: 5px; + height: calc(var(--vertical-range-width, 100px) * 0.4); + position: relative; + top: 0px; + cursor: grab; + background: var(--vertical-range-track-color, #fafafa); + box-shadow: -350px 0 0 350px + var(--vertical-range-color, var(--state-icon-active-color)), + inset 0 0 0 80px var(--vertical-range-track-color, #fafafa); + border-right: 9px solid + var(--vertical-range-color, var(--state-icon-active-color)); + border-left: 9px solid + var(--vertical-range-color, var(--state-icon-active-color)); + border-top: 22px solid + var(--vertical-range-color, var(--state-icon-active-color)); + border-bottom: 22px solid + var(--vertical-range-color, var(--state-icon-active-color)); + border-radius: 0; + transition: box-shadow 0.2s ease-in-out; + } + + :host input::-moz-range-thumb:active { + cursor: grabbing; + } + `; + } +} +declare global { + interface HTMLElementTagNameMap { + "ha-vertical-range-input": HaVerticalRangeInput; + } +} diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts index 3abab21a99..6f116df26b 100644 --- a/src/dialogs/more-info/controls/more-info-light.ts +++ b/src/dialogs/more-info/controls/more-info-light.ts @@ -1,5 +1,7 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; +import "@material/mwc-tab-bar"; +import "@material/mwc-tab"; import { css, CSSResult, @@ -11,7 +13,6 @@ import { internalProperty, PropertyValues, } from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; import { SUPPORT_BRIGHTNESS, @@ -26,8 +27,10 @@ import type { HomeAssistant, LightEntity } from "../../../types"; import "../../../components/ha-attributes"; import "../../../components/ha-color-picker"; import "../../../components/ha-labeled-slider"; +import "../../../components/ha-svg-icon"; import "../../../components/ha-icon-button"; import "../../../components/ha-paper-dropdown-menu"; +import "../../../components/ha-vertical-range-input"; interface HueSatColor { h: number; @@ -52,106 +55,144 @@ class MoreInfoLight extends LitElement { @internalProperty() private _colorPickerColor?: HueSatColor; + @internalProperty() private _tabIndex = 0; + protected render(): TemplateResult { if (!this.hass || !this.stateObj) { return html``; } + const supportsBrightness = supportsFeature( + this.stateObj!, + SUPPORT_BRIGHTNESS + ); + const supportsColorTemp = supportsFeature( + this.stateObj, + SUPPORT_COLOR_TEMP + ); + const supportsWhiteValue = supportsFeature( + this.stateObj, + SUPPORT_WHITE_VALUE + ); + const supportsColor = supportsFeature(this.stateObj, SUPPORT_COLOR); + const supportsEffect = + supportsFeature(this.stateObj, SUPPORT_EFFECT) && + this.stateObj!.attributes.effect_list?.length; + + if (!supportsBrightness && !this._tabIndex) { + this._tabIndex = 1; + } + return html` -
{ + this._tabIndex = ev.detail.index; + }} > - ${this.stateObj.state === "on" - ? html` - ${supportsFeature(this.stateObj!, SUPPORT_BRIGHTNESS) - ? html` - - ` - : ""} - ${supportsFeature(this.stateObj, SUPPORT_COLOR_TEMP) - ? html` - - ` - : ""} - ${supportsFeature(this.stateObj, SUPPORT_WHITE_VALUE) - ? html` - - ` - : ""} - ${supportsFeature(this.stateObj, SUPPORT_COLOR) - ? html` -
- - - -
- ` - : ""} - ${supportsFeature(this.stateObj, SUPPORT_EFFECT) && - this.stateObj!.attributes.effect_list?.length - ? html` - - ${this.stateObj.attributes.effect_list.map( - (effect: string) => html` - ${effect} - ` - )} - - - ` - : ""} - ` + ${supportsBrightness + ? html`` : ""} - -
+ ${supportsColor || + supportsColorTemp || + supportsEffect || + supportsWhiteValue + ? html`` + : ""} + + ${this._tabIndex === 0 + ? html` + ${supportsBrightness + ? html` +
+
+ ${Math.round((this._brightnessSliderValue / 255) * 100)}% +
+ + +
+ ` + : ""} + ` + : html` + ${supportsColorTemp + ? html` + + ` + : ""} + ${supportsWhiteValue + ? html` + + ` + : ""} + ${supportsColor + ? html` +
+ + + +
+ ` + : ""} + ${supportsEffect + ? html` + + ${this.stateObj.attributes.effect_list!.map( + (effect: string) => html` + ${effect} + ` + )} + + + ` + : ""} + `} +
+ ${this.hass.user?.is_admin + ? html` + + ` + : ""} `; } @@ -159,7 +200,7 @@ class MoreInfoLight extends LitElement { const stateObj = this.stateObj! as LightEntity; if (changedProps.has("stateObj") && stateObj.state === "on") { this._brightnessSliderValue = stateObj.attributes.brightness; - this._ctSliderValue = stateObj.attributes.color_temp; + this._ctSliderValue = stateObj.attributes.color_temp || 326; this._wvSliderValue = stateObj.attributes.white_value; if (stateObj.attributes.hs_color) { @@ -184,42 +225,24 @@ class MoreInfoLight extends LitElement { }); } - private _brightnessSliderChanged(ev: CustomEvent) { - const bri = parseInt((ev.target as any).value, 10); - - if (isNaN(bri)) { - return; - } - + private _brightnessChanged(ev: CustomEvent) { this.hass.callService("light", "turn_on", { entity_id: this.stateObj!.entity_id, - brightness: bri, + brightness: parseInt(ev.detail.value, 10), }); } - private _ctSliderChanged(ev: CustomEvent) { - const ct = parseInt((ev.target as any).value, 10); - - if (isNaN(ct)) { - return; - } - + private _colorTempChanged(ev: CustomEvent) { this.hass.callService("light", "turn_on", { entity_id: this.stateObj!.entity_id, - color_temp: ct, + color_temp: parseInt((ev.currentTarget as any).value, 10), }); } - private _wvSliderChanged(ev: CustomEvent) { - const wv = parseInt((ev.target as any).value, 10); - - if (isNaN(wv)) { - return; - } - + private _whiteValueChanged(ev: CustomEvent) { this.hass.callService("light", "turn_on", { entity_id: this.stateObj!.entity_id, - white_value: wv, + white_value: parseInt((ev.target as any).value, 10), }); } @@ -246,21 +269,27 @@ class MoreInfoLight extends LitElement { static get styles(): CSSResult { return css` - .content { + ha-labeled-slider, + ha-paper-dropdown-menu, + .padding { + width: 100%; + overflow: hidden; + padding-top: 16px; + } + + .brightness { display: flex; flex-direction: column; align-items: center; + margin-top: 16px; } - .content.is-on { - margin-top: -16px; - } - - .content > * { - width: 100%; - max-height: 84px; - overflow: hidden; - padding-top: 16px; + .brightness div { + font-size: 20px; + line-height: 1.2; + padding: 4px 0; + font-weight: 500; + color: var(--secondary-text-color); } .color_temp { @@ -272,13 +301,20 @@ class MoreInfoLight extends LitElement { ); /* The color temp minimum value shouldn't be rendered differently. It's not "off". */ --paper-slider-knob-start-border-color: var(--primary-color); + --ha-slider-border-radius: 8px; } - .segmentationContainer { + .color-picker { position: relative; max-height: 500px; } + .color-picker ha-icon-button { + position: absolute; + top: 5%; + color: var(--secondary-text-color); + } + ha-color-picker { --ha-color-picker-wheel-borderwidth: 5; --ha-color-picker-wheel-bordercolor: white; @@ -287,12 +323,6 @@ class MoreInfoLight extends LitElement { --ha-color-picker-marker-bordercolor: white; } - .segmentationButton { - position: absolute; - top: 5%; - color: var(--secondary-text-color); - } - paper-item { cursor: pointer; }