Continued work

This commit is contained in:
Zack Arnett 2020-08-18 18:57:10 -05:00
parent c4d8aba5c8
commit 6af277a71e
3 changed files with 321 additions and 135 deletions

View File

@ -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);
}
</style>

View File

@ -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`
<input
type="range"
.max=${this.max.toString()}
.min=${this.min.toString()}
.step=${this.step.toString()}
.value=${this.value.toString()}
@change=${this._valueChanged}
/>
`;
}
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;
}
}

View File

@ -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`
<div
class="content ${classMap({
"is-on": this.stateObj.state === "on",
})}"
<mwc-tab-bar
.activeIndex=${this._tabIndex}
@MDCTabBar:activated=${(ev: CustomEvent) => {
this._tabIndex = ev.detail.index;
}}
>
${this.stateObj.state === "on"
? html`
${supportsFeature(this.stateObj!, SUPPORT_BRIGHTNESS)
? html`
<ha-labeled-slider
caption=${this.hass.localize("ui.card.light.brightness")}
icon="hass:brightness-5"
min="1"
max="255"
value=${this._brightnessSliderValue}
@change=${this._brightnessSliderChanged}
></ha-labeled-slider>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_COLOR_TEMP)
? html`
<ha-labeled-slider
class="color_temp"
caption=${this.hass.localize(
"ui.card.light.color_temperature"
)}
icon="hass:thermometer"
.min=${this.stateObj.attributes.min_mireds}
.max=${this.stateObj.attributes.max_mireds}
.value=${this._ctSliderValue}
@change=${this._ctSliderChanged}
></ha-labeled-slider>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_WHITE_VALUE)
? html`
<ha-labeled-slider
caption=${this.hass.localize("ui.card.light.white_value")}
icon="hass:file-word-box"
max="255"
.value=${this._wvSliderValue}
@change=${this._wvSliderChanged}
></ha-labeled-slider>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_COLOR)
? html`
<div class="segmentationContainer">
<ha-color-picker
class="color"
@colorselected=${this._colorPicked}
.desiredHsColor=${this._colorPickerColor}
throttle="500"
.hueSegments=${this._hueSegments}
.saturationSegments=${this._saturationSegments}
>
</ha-color-picker>
<ha-icon-button
icon="hass:palette"
@click=${this._segmentClick}
class="segmentationButton"
></ha-icon-button>
</div>
`
: ""}
${supportsFeature(this.stateObj, SUPPORT_EFFECT) &&
this.stateObj!.attributes.effect_list?.length
? html`
<ha-paper-dropdown-menu
.label=${this.hass.localize("ui.card.light.effect")}
>
<paper-listbox
slot="dropdown-content"
.selected=${this.stateObj.attributes.effect || ""}
@iron-select=${this._effectChanged}
attr-for-selected="item-name"
>${this.stateObj.attributes.effect_list.map(
(effect: string) => html`
<paper-item itemName=${effect}
>${effect}</paper-item
>
`
)}
</paper-listbox>
</ha-paper-dropdown-menu>
`
: ""}
`
${supportsBrightness
? html`<mwc-tab label="Brightness"></mwc-tab>`
: ""}
<ha-attributes
.stateObj=${this.stateObj}
extraFilters="brightness,color_temp,white_value,effect_list,effect,hs_color,rgb_color,xy_color,min_mireds,max_mireds,entity_id"
></ha-attributes>
</div>
${supportsColor ||
supportsColorTemp ||
supportsEffect ||
supportsWhiteValue
? html`<mwc-tab label="Color"></mwc-tab>`
: ""}
</mwc-tab-bar>
${this._tabIndex === 0
? html`
${supportsBrightness
? html`
<div class="brightness">
<div>
${Math.round((this._brightnessSliderValue / 255) * 100)}%
</div>
<ha-vertical-range-input
max="255"
.caption=${this.hass.localize("ui.card.light.brightness")}
.value=${this._brightnessSliderValue}
@value-changed=${this._brightnessChanged}
>
</ha-vertical-range-input>
</div>
`
: ""}
`
: html`
${supportsColorTemp
? html`
<ha-labeled-slider
class="color_temp"
icon="hass:thermometer"
.caption=${this.hass.localize(
"ui.card.light.color_temperature"
)}
.min=${this.stateObj.attributes.min_mireds}
.max=${this.stateObj.attributes.max_mireds}
.value=${this._ctSliderValue}
@change=${this._colorTempChanged}
></ha-labeled-slider>
`
: ""}
${supportsWhiteValue
? html`
<ha-labeled-slider
icon="hass:file-word-box"
max="255"
.caption=${this.hass.localize("ui.card.light.white_value")}
.value=${this._wvSliderValue}
@change=${this._whiteValueChanged}
></ha-labeled-slider>
`
: ""}
${supportsColor
? html`
<div class="color-picker">
<ha-icon-button
icon="hass:palette"
@click=${this._segmentClick}
></ha-icon-button>
<ha-color-picker
throttle="500"
.desiredHsColor=${this._colorPickerColor}
.hueSegments=${this._hueSegments}
.saturationSegments=${this._saturationSegments}
@colorselected=${this._colorPicked}
>
</ha-color-picker>
</div>
`
: ""}
${supportsEffect
? html`
<ha-paper-dropdown-menu
.label=${this.hass.localize("ui.card.light.effect")}
>
<paper-listbox
slot="dropdown-content"
attr-for-selected="item-name"
.selected=${this.stateObj.attributes.effect!}
@iron-select=${this._effectChanged}
>${this.stateObj.attributes.effect_list!.map(
(effect: string) => html`
<paper-item .itemName=${effect}>${effect}</paper-item>
`
)}
</paper-listbox>
</ha-paper-dropdown-menu>
`
: ""}
`}
<div class="padding"></div>
${this.hass.user?.is_admin
? html`
<ha-attributes
.stateObj=${this.stateObj}
extraFilters="brightness,color_temp,white_value,effect_list,effect,hs_color,rgb_color,xy_color,min_mireds,max_mireds,entity_id"
></ha-attributes>
`
: ""}
`;
}
@ -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;
}