mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Convert thermostat to round-slider (#3734)
* Convert to round-slider Closes https://github.com/home-assistant/home-assistant-polymer/issues/3622 Closes https://github.com/home-assistant/home-assistant-polymer/issues/2756 * scaling * address review comments * css tweaks * remove jquery * address comments * simplify set-temperature * handle long name * remove increased handleSize * address comments * address comments * address comments * address comment * need coffee
This commit is contained in:
parent
141c3f1ea4
commit
f5e3a9ad40
@ -84,7 +84,6 @@
|
|||||||
"hls.js": "^0.12.4",
|
"hls.js": "^0.12.4",
|
||||||
"home-assistant-js-websocket": "^4.4.0",
|
"home-assistant-js-websocket": "^4.4.0",
|
||||||
"intl-messageformat": "^2.2.0",
|
"intl-messageformat": "^2.2.0",
|
||||||
"jquery": "^3.4.0",
|
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"leaflet": "^1.4.0",
|
"leaflet": "^1.4.0",
|
||||||
"lit-element": "^2.2.1",
|
"lit-element": "^2.2.1",
|
||||||
@ -98,7 +97,6 @@
|
|||||||
"react-big-calendar": "^0.20.4",
|
"react-big-calendar": "^0.20.4",
|
||||||
"regenerator-runtime": "^0.13.2",
|
"regenerator-runtime": "^0.13.2",
|
||||||
"roboto-fontface": "^0.10.0",
|
"roboto-fontface": "^0.10.0",
|
||||||
"round-slider": "^1.3.3",
|
|
||||||
"superstruct": "^0.6.1",
|
"superstruct": "^0.6.1",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^1.10.0",
|
||||||
"unfetch": "^4.1.0",
|
"unfetch": "^4.1.0",
|
||||||
|
@ -5,9 +5,12 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
customElement,
|
customElement,
|
||||||
property,
|
property,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { classMap } from "lit-html/directives/class-map";
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
|
import "@thomasloven/round-slider";
|
||||||
|
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
@ -19,7 +22,6 @@ import { computeStateName } from "../../../common/entity/compute_state_name";
|
|||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { loadRoundslider } from "../../../resources/jquery.roundslider.ondemand";
|
|
||||||
import { UNIT_F } from "../../../common/const";
|
import { UNIT_F } from "../../../common/const";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { ThermostatCardConfig } from "./types";
|
import { ThermostatCardConfig } from "./types";
|
||||||
@ -29,17 +31,7 @@ import {
|
|||||||
compareClimateHvacModes,
|
compareClimateHvacModes,
|
||||||
CLIMATE_PRESET_NONE,
|
CLIMATE_PRESET_NONE,
|
||||||
} from "../../../data/climate";
|
} from "../../../data/climate";
|
||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
const thermostatConfig = {
|
|
||||||
radius: 150,
|
|
||||||
circleShape: "pie",
|
|
||||||
startAngle: 315,
|
|
||||||
width: 5,
|
|
||||||
lineCap: "round",
|
|
||||||
handleSize: "+10",
|
|
||||||
showTooltip: false,
|
|
||||||
animation: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const modeIcons: { [mode in HvacMode]: string } = {
|
const modeIcons: { [mode in HvacMode]: string } = {
|
||||||
auto: "hass:calendar-repeat",
|
auto: "hass:calendar-repeat",
|
||||||
@ -63,18 +55,15 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() private _config?: ThermostatCardConfig;
|
@property() private _config?: ThermostatCardConfig;
|
||||||
|
@property() private _loaded?: boolean;
|
||||||
@property() private _roundSliderStyle?: TemplateResult;
|
@property() private _setTemp?: number | number[];
|
||||||
|
|
||||||
@property() private _jQuery?: any;
|
|
||||||
|
|
||||||
private _broadCard?: boolean;
|
|
||||||
|
|
||||||
private _loaded?: boolean;
|
|
||||||
|
|
||||||
private _updated?: boolean;
|
private _updated?: boolean;
|
||||||
|
private _large?: boolean;
|
||||||
|
private _medium?: boolean;
|
||||||
|
private _small?: boolean;
|
||||||
|
private _radius?: number;
|
||||||
|
|
||||||
public getCardSize(): number {
|
public getCardSize(): number {
|
||||||
return 4;
|
return 4;
|
||||||
@ -114,26 +103,69 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mode = stateObj.state in modeIcons ? stateObj.state : "unknown-mode";
|
const mode = stateObj.state in modeIcons ? stateObj.state : "unknown-mode";
|
||||||
|
const name =
|
||||||
|
this._config!.name ||
|
||||||
|
computeStateName(this.hass!.states[this._config!.entity]);
|
||||||
|
|
||||||
|
if (!this._radius || this._radius === 0) {
|
||||||
|
this._radius = 100;
|
||||||
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyle()}
|
|
||||||
<ha-card
|
<ha-card
|
||||||
class="${classMap({
|
class=${classMap({
|
||||||
[mode]: true,
|
[mode]: true,
|
||||||
large: this._broadCard!,
|
large: this._large!,
|
||||||
small: !this._broadCard,
|
medium: this._medium!,
|
||||||
})}"
|
small: this._small!,
|
||||||
|
longName: name.length > 10,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<div id="root">
|
<div id="root">
|
||||||
<paper-icon-button
|
<paper-icon-button
|
||||||
icon="hass:dots-vertical"
|
icon="hass:dots-vertical"
|
||||||
class="more-info"
|
class="more-info"
|
||||||
@click="${this._handleMoreInfo}"
|
@click=${this._handleMoreInfo}
|
||||||
></paper-icon-button>
|
></paper-icon-button>
|
||||||
<div id="thermostat"></div>
|
<div id="thermostat">
|
||||||
|
${stateObj.state === "unavailable"
|
||||||
|
? html`
|
||||||
|
<round-slider
|
||||||
|
.radius=${this._radius}
|
||||||
|
disabled="true"
|
||||||
|
></round-slider>
|
||||||
|
`
|
||||||
|
: stateObj.attributes.target_temp_low &&
|
||||||
|
stateObj.attributes.target_temp_high
|
||||||
|
? html`
|
||||||
|
<round-slider
|
||||||
|
.radius=${this._radius}
|
||||||
|
.low=${stateObj.attributes.target_temp_low}
|
||||||
|
.high=${stateObj.attributes.target_temp_high}
|
||||||
|
.min=${stateObj.attributes.min_temp}
|
||||||
|
.max=${stateObj.attributes.max_temp}
|
||||||
|
.step=${this._stepSize}
|
||||||
|
@value-changing=${this._dragEvent}
|
||||||
|
@value-changed=${this._setTemperature}
|
||||||
|
></round-slider>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<round-slider
|
||||||
|
.radius=${this._radius}
|
||||||
|
.value=${stateObj.attributes.temperature !== null &&
|
||||||
|
Number.isFinite(Number(stateObj.attributes.temperature))
|
||||||
|
? stateObj.attributes.temperature
|
||||||
|
: stateObj.attributes.min_temp}
|
||||||
|
.step=${this._stepSize}
|
||||||
|
.min=${stateObj.attributes.min_temp}
|
||||||
|
.max=${stateObj.attributes.max_temp}
|
||||||
|
@value-changing=${this._dragEvent}
|
||||||
|
@value-changed=${this._setTemperature}
|
||||||
|
></round-slider>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
<div id="tooltip">
|
<div id="tooltip">
|
||||||
<div class="title">
|
<div class="title">${name}</div>
|
||||||
${this._config.name || computeStateName(stateObj)}
|
|
||||||
</div>
|
|
||||||
<div class="current-temperature">
|
<div class="current-temperature">
|
||||||
<span class="current-temperature-text">
|
<span class="current-temperature-text">
|
||||||
${stateObj.attributes.current_temperature}
|
${stateObj.attributes.current_temperature}
|
||||||
@ -147,7 +179,18 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="climate-info">
|
<div class="climate-info">
|
||||||
<div id="set-temperature"></div>
|
<div id="set-temperature">
|
||||||
|
${!this._setTemp
|
||||||
|
? ""
|
||||||
|
: Array.isArray(this._setTemp)
|
||||||
|
? html`
|
||||||
|
${this._setTemp[0].toFixed(1)} -
|
||||||
|
${this._setTemp[1].toFixed(1)}
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
${this._setTemp.toFixed(1)}
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
<div class="current-mode">
|
<div class="current-mode">
|
||||||
${stateObj.attributes.hvac_action
|
${stateObj.attributes.hvac_action
|
||||||
? this.hass!.localize(
|
? this.hass!.localize(
|
||||||
@ -185,13 +228,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
return hasConfigOrEntityChanged(this, changedProps);
|
return hasConfigOrEntityChanged(this, changedProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(): void {
|
|
||||||
this._updated = true;
|
|
||||||
if (this.isConnected && !this._loaded) {
|
|
||||||
this._initialLoad();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
if (!this._config || !this.hass || !changedProps.has("hass")) {
|
if (!this._config || !this.hass || !changedProps.has("hass")) {
|
||||||
@ -204,29 +240,29 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
applyThemesOnElement(this, this.hass.themes, this._config.theme);
|
applyThemesOnElement(this, this.hass.themes, this._config.theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
|
this._setTemp = this._getSetTemp(this.hass!.states[this._config!.entity]);
|
||||||
|
}
|
||||||
|
|
||||||
if (!stateObj) {
|
protected firstUpdated(): void {
|
||||||
return;
|
this._updated = true;
|
||||||
|
if (this.isConnected && !this._loaded) {
|
||||||
|
this._initialLoad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _initialLoad(): Promise<void> {
|
||||||
|
this._large = this._medium = this._small = false;
|
||||||
|
this._radius = this.clientWidth / 3.9;
|
||||||
|
|
||||||
|
if (this.clientWidth > 450) {
|
||||||
|
this._large = true;
|
||||||
|
} else if (this.clientWidth < 350) {
|
||||||
|
this._small = true;
|
||||||
|
} else {
|
||||||
|
this._medium = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
this._loaded = true;
|
||||||
this._jQuery &&
|
|
||||||
// If jQuery changed, we just rendered in firstUpdated
|
|
||||||
!changedProps.has("_jQuery") &&
|
|
||||||
(!oldHass || oldHass.states[this._config.entity] !== stateObj)
|
|
||||||
) {
|
|
||||||
const [sliderValue, uiValue, sliderType] = this._genSliderValue(stateObj);
|
|
||||||
|
|
||||||
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
|
|
||||||
sliderType,
|
|
||||||
value: sliderValue,
|
|
||||||
disabled: sliderValue === null,
|
|
||||||
min: stateObj.attributes.min_temp,
|
|
||||||
max: stateObj.attributes.max_temp,
|
|
||||||
});
|
|
||||||
this._updateSetTemp(uiValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _stepSize(): number {
|
private get _stepSize(): number {
|
||||||
@ -238,119 +274,55 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
return this.hass!.config.unit_system.temperature === UNIT_F ? 1 : 0.5;
|
return this.hass!.config.unit_system.temperature === UNIT_F ? 1 : 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initialLoad(): Promise<void> {
|
private _getSetTemp(stateObj: HassEntity) {
|
||||||
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
|
|
||||||
|
|
||||||
if (!stateObj) {
|
|
||||||
// Card will require refresh to work again
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._loaded = true;
|
|
||||||
|
|
||||||
await this.updateComplete;
|
|
||||||
|
|
||||||
let radius = this.clientWidth / 3.2;
|
|
||||||
this._broadCard = this.clientWidth > 390;
|
|
||||||
|
|
||||||
if (radius === 0) {
|
|
||||||
radius = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
(this.shadowRoot!.querySelector(
|
|
||||||
"#thermostat"
|
|
||||||
) as HTMLElement)!.style.height = radius * 2 + "px";
|
|
||||||
|
|
||||||
const loaded = await loadRoundslider();
|
|
||||||
|
|
||||||
this._roundSliderStyle = loaded.roundSliderStyle;
|
|
||||||
this._jQuery = loaded.jQuery;
|
|
||||||
|
|
||||||
const [sliderValue, uiValue, sliderType] = this._genSliderValue(stateObj);
|
|
||||||
|
|
||||||
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
|
|
||||||
...thermostatConfig,
|
|
||||||
radius,
|
|
||||||
min: stateObj.attributes.min_temp,
|
|
||||||
max: stateObj.attributes.max_temp,
|
|
||||||
sliderType,
|
|
||||||
change: (value) => this._setTemperature(value),
|
|
||||||
drag: (value) => this._dragEvent(value),
|
|
||||||
value: sliderValue,
|
|
||||||
disabled: sliderValue === null,
|
|
||||||
step: this._stepSize,
|
|
||||||
});
|
|
||||||
this._updateSetTemp(uiValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _genSliderValue(
|
|
||||||
stateObj: ClimateEntity
|
|
||||||
): [string | number | null, string, string] {
|
|
||||||
let sliderType: string;
|
|
||||||
let sliderValue: string | number | null;
|
|
||||||
let uiValue: string;
|
|
||||||
|
|
||||||
if (stateObj.state === "unavailable") {
|
if (stateObj.state === "unavailable") {
|
||||||
sliderType = "min-range";
|
return this.hass!.localize("state.default.unavailable");
|
||||||
sliderValue = null;
|
|
||||||
uiValue = this.hass!.localize("state.default.unavailable");
|
|
||||||
} else if (
|
|
||||||
stateObj.attributes.target_temp_low &&
|
|
||||||
stateObj.attributes.target_temp_high
|
|
||||||
) {
|
|
||||||
sliderType = "range";
|
|
||||||
sliderValue = `${stateObj.attributes.target_temp_low}, ${
|
|
||||||
stateObj.attributes.target_temp_high
|
|
||||||
}`;
|
|
||||||
uiValue = this.formatTemp(
|
|
||||||
[
|
|
||||||
String(stateObj.attributes.target_temp_low),
|
|
||||||
String(stateObj.attributes.target_temp_high),
|
|
||||||
],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
sliderType = "min-range";
|
|
||||||
sliderValue = Number.isFinite(Number(stateObj.attributes.temperature))
|
|
||||||
? stateObj.attributes.temperature
|
|
||||||
: null;
|
|
||||||
uiValue = sliderValue !== null ? String(sliderValue) : "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [sliderValue, uiValue, sliderType];
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateSetTemp(value: string): void {
|
|
||||||
this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dragEvent(e): void {
|
|
||||||
this._updateSetTemp(this.formatTemp(String(e.value).split(","), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private _setTemperature(e): void {
|
|
||||||
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
|
|
||||||
if (
|
if (
|
||||||
stateObj.attributes.target_temp_low &&
|
stateObj.attributes.target_temp_low &&
|
||||||
stateObj.attributes.target_temp_high
|
stateObj.attributes.target_temp_high
|
||||||
) {
|
) {
|
||||||
if (e.handle.index === 1) {
|
return [
|
||||||
this.hass!.callService("climate", "set_temperature", {
|
stateObj.attributes.target_temp_low,
|
||||||
entity_id: this._config!.entity,
|
stateObj.attributes.target_temp_high,
|
||||||
target_temp_low: e.handle.value,
|
];
|
||||||
target_temp_high: stateObj.attributes.target_temp_high,
|
}
|
||||||
});
|
|
||||||
} else {
|
return stateObj.attributes.temperature;
|
||||||
this.hass!.callService("climate", "set_temperature", {
|
}
|
||||||
entity_id: this._config!.entity,
|
|
||||||
target_temp_low: stateObj.attributes.target_temp_low,
|
private _dragEvent(e): void {
|
||||||
target_temp_high: e.handle.value,
|
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
|
||||||
});
|
|
||||||
}
|
if (e.detail.low) {
|
||||||
|
this._setTemp = [e.detail.low, stateObj.attributes.target_temp_high];
|
||||||
|
} else if (e.detail.high) {
|
||||||
|
this._setTemp = [stateObj.attributes.target_temp_low, e.detail.high];
|
||||||
|
} else {
|
||||||
|
this._setTemp = e.detail.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _setTemperature(e): void {
|
||||||
|
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
|
||||||
|
|
||||||
|
if (e.detail.low) {
|
||||||
|
this.hass!.callService("climate", "set_temperature", {
|
||||||
|
entity_id: this._config!.entity,
|
||||||
|
target_temp_low: e.detail.low,
|
||||||
|
target_temp_high: stateObj.attributes.target_temp_high,
|
||||||
|
});
|
||||||
|
} else if (e.detail.high) {
|
||||||
|
this.hass!.callService("climate", "set_temperature", {
|
||||||
|
entity_id: this._config!.entity,
|
||||||
|
target_temp_low: stateObj.attributes.target_temp_low,
|
||||||
|
target_temp_high: e.detail.high,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.hass!.callService("climate", "set_temperature", {
|
this.hass!.callService("climate", "set_temperature", {
|
||||||
entity_id: this._config!.entity,
|
entity_id: this._config!.entity,
|
||||||
temperature: e.value,
|
temperature: e.detail.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,217 +354,199 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatTemp(temps: string[], spaceStepSize: boolean): string {
|
static get styles(): CSSResult {
|
||||||
temps = temps.filter(Boolean);
|
return css`
|
||||||
|
:host {
|
||||||
// If we are sliding the slider, append 0 to the temperatures if we're
|
display: block;
|
||||||
// having a 0.5 step size, so that the text doesn't jump while sliding
|
}
|
||||||
if (spaceStepSize) {
|
ha-card {
|
||||||
const stepSize = this._stepSize;
|
overflow: hidden;
|
||||||
temps = temps.map((val) =>
|
--rail-border-color: transparent;
|
||||||
val.includes(".") || stepSize === 1 ? val : `${val}.0`
|
--auto-color: green;
|
||||||
);
|
--eco-color: springgreen;
|
||||||
}
|
--cool-color: #2b9af9;
|
||||||
|
--heat-color: #ff8100;
|
||||||
return temps.join("-");
|
--manual-color: #44739e;
|
||||||
}
|
--off-color: #8a8a8a;
|
||||||
|
--fan_only-color: #8a8a8a;
|
||||||
private renderStyle(): TemplateResult {
|
--dry-color: #efbd07;
|
||||||
return html`
|
--idle-color: #8a8a8a;
|
||||||
${this._roundSliderStyle}
|
--unknown-color: #bac;
|
||||||
<style>
|
}
|
||||||
:host {
|
#root {
|
||||||
display: block;
|
position: relative;
|
||||||
}
|
overflow: hidden;
|
||||||
ha-card {
|
}
|
||||||
overflow: hidden;
|
.auto,
|
||||||
--rail-border-color: transparent;
|
.heat_cool {
|
||||||
--auto-color: green;
|
--mode-color: var(--auto-color);
|
||||||
--eco-color: springgreen;
|
}
|
||||||
--cool-color: #2b9af9;
|
.cool {
|
||||||
--heat-color: #ff8100;
|
--mode-color: var(--cool-color);
|
||||||
--manual-color: #44739e;
|
}
|
||||||
--off-color: #8a8a8a;
|
.heat {
|
||||||
--fan_only-color: #8a8a8a;
|
--mode-color: var(--heat-color);
|
||||||
--dry-color: #efbd07;
|
}
|
||||||
--idle-color: #8a8a8a;
|
.manual {
|
||||||
--unknown-color: #bac;
|
--mode-color: var(--manual-color);
|
||||||
}
|
}
|
||||||
#root {
|
.off {
|
||||||
position: relative;
|
--mode-color: var(--off-color);
|
||||||
overflow: hidden;
|
}
|
||||||
}
|
.fan_only {
|
||||||
.auto,
|
--mode-color: var(--fan_only-color);
|
||||||
.heat_cool {
|
}
|
||||||
--mode-color: var(--auto-color);
|
.eco {
|
||||||
}
|
--mode-color: var(--eco-color);
|
||||||
.cool {
|
}
|
||||||
--mode-color: var(--cool-color);
|
.dry {
|
||||||
}
|
--mode-color: var(--dry-color);
|
||||||
.heat {
|
}
|
||||||
--mode-color: var(--heat-color);
|
.idle {
|
||||||
}
|
--mode-color: var(--idle-color);
|
||||||
.manual {
|
}
|
||||||
--mode-color: var(--manual-color);
|
.unknown-mode {
|
||||||
}
|
--mode-color: var(--unknown-color);
|
||||||
.off {
|
}
|
||||||
--mode-color: var(--off-color);
|
.no-title {
|
||||||
}
|
--title-position-top: 33% !important;
|
||||||
.fan_only {
|
}
|
||||||
--mode-color: var(--fan_only-color);
|
.large {
|
||||||
}
|
--thermostat-padding-top: 32px;
|
||||||
.eco {
|
--thermostat-margin-bottom: 32px;
|
||||||
--mode-color: var(--eco-color);
|
--title-font-size: 28px;
|
||||||
}
|
--title-position-top: 25%;
|
||||||
.dry {
|
--climate-info-position-top: 80%;
|
||||||
--mode-color: var(--dry-color);
|
--set-temperature-font-size: 25px;
|
||||||
}
|
--current-temperature-font-size: 71px;
|
||||||
.idle {
|
--current-temperature-position-top: 10%;
|
||||||
--mode-color: var(--idle-color);
|
--current-temperature-text-padding-left: 15px;
|
||||||
}
|
--uom-font-size: 20px;
|
||||||
.unknown-mode {
|
--uom-margin-left: -18px;
|
||||||
--mode-color: var(--unknown-color);
|
--current-mode-font-size: 18px;
|
||||||
}
|
--current-mod-margin-top: 6px;
|
||||||
.no-title {
|
--current-mod-margin-bottom: 12px;
|
||||||
--title-position-top: 33% !important;
|
--set-temperature-margin-bottom: -5px;
|
||||||
}
|
}
|
||||||
.large {
|
.medium {
|
||||||
--thermostat-padding-top: 25px;
|
--thermostat-padding-top: 20px;
|
||||||
--thermostat-margin-bottom: 25px;
|
--thermostat-margin-bottom: 20px;
|
||||||
--title-font-size: 28px;
|
--title-font-size: 23px;
|
||||||
--title-position-top: 27%;
|
--title-position-top: 27%;
|
||||||
--climate-info-position-top: 81%;
|
--climate-info-position-top: 84%;
|
||||||
--set-temperature-font-size: 25px;
|
--set-temperature-font-size: 20px;
|
||||||
--current-temperature-font-size: 71px;
|
--current-temperature-font-size: 65px;
|
||||||
--current-temperature-position-top: 10%;
|
--current-temperature-position-top: 10%;
|
||||||
--current-temperature-text-padding-left: 15px;
|
--current-temperature-text-padding-left: 15px;
|
||||||
--uom-font-size: 20px;
|
--uom-font-size: 18px;
|
||||||
--uom-margin-left: -18px;
|
--uom-margin-left: -16px;
|
||||||
--current-mode-font-size: 18px;
|
--current-mode-font-size: 16px;
|
||||||
--set-temperature-margin-bottom: -5px;
|
--current-mod-margin-top: 4px;
|
||||||
}
|
--current-mod-margin-bottom: 4px;
|
||||||
.small {
|
--set-temperature-margin-bottom: -5px;
|
||||||
--thermostat-padding-top: 15px;
|
}
|
||||||
--thermostat-margin-bottom: 15px;
|
.small {
|
||||||
--title-font-size: 18px;
|
--thermostat-padding-top: 15px;
|
||||||
--title-position-top: 28%;
|
--thermostat-margin-bottom: 15px;
|
||||||
--climate-info-position-top: 79%;
|
--title-font-size: 18px;
|
||||||
--set-temperature-font-size: 16px;
|
--title-position-top: 28%;
|
||||||
--current-temperature-font-size: 25px;
|
--climate-info-position-top: 78%;
|
||||||
--current-temperature-position-top: 5%;
|
--set-temperature-font-size: 16px;
|
||||||
--current-temperature-text-padding-left: 7px;
|
--current-temperature-font-size: 55px;
|
||||||
--uom-font-size: 12px;
|
--current-temperature-position-top: 5%;
|
||||||
--uom-margin-left: -5px;
|
--current-temperature-text-padding-left: 16px;
|
||||||
--current-mode-font-size: 14px;
|
--uom-font-size: 16px;
|
||||||
--set-temperature-margin-bottom: 0px;
|
--uom-margin-left: -14px;
|
||||||
}
|
--current-mode-font-size: 14px;
|
||||||
#thermostat {
|
--current-mod-margin-top: 2px;
|
||||||
margin: 0 auto var(--thermostat-margin-bottom);
|
--current-mod-margin-bottom: 4px;
|
||||||
padding-top: var(--thermostat-padding-top);
|
--set-temperature-margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
#thermostat .rs-range-color {
|
.longName {
|
||||||
background-color: var(--mode-color, var(--disabled-text-color));
|
--title-font-size: 18px;
|
||||||
}
|
}
|
||||||
#thermostat .rs-path-color {
|
#thermostat {
|
||||||
background-color: var(--disabled-text-color);
|
margin: 0 auto var(--thermostat-margin-bottom);
|
||||||
}
|
padding-top: var(--thermostat-padding-top);
|
||||||
#thermostat .rs-handle {
|
padding-bottom: 32px;
|
||||||
background-color: var(--paper-card-background-color, white);
|
display: flex;
|
||||||
padding: 10px;
|
justify-content: center;
|
||||||
margin: -10px 0 0 -8px !important;
|
align-items: center;
|
||||||
border: 2px solid var(--disabled-text-color);
|
}
|
||||||
}
|
#thermostat round-slider {
|
||||||
#thermostat .rs-handle.rs-focus {
|
margin: 0 auto;
|
||||||
border-color: var(--mode-color, var(--disabled-text-color));
|
display: inline-block;
|
||||||
}
|
--round-slider-path-color: var(--disabled-text-color);
|
||||||
#thermostat .rs-handle:after {
|
--round-slider-bar-color: var(--mode-color);
|
||||||
border-color: var(--mode-color, var(--disabled-text-color));
|
z-index: 20;
|
||||||
background-color: var(--mode-color, var(--disabled-text-color));
|
}
|
||||||
}
|
#tooltip {
|
||||||
#thermostat .rs-border {
|
position: absolute;
|
||||||
border-color: var(--rail-border-color);
|
top: 0;
|
||||||
}
|
left: 0;
|
||||||
#thermostat .rs-bar.rs-transition.rs-first,
|
right: 0;
|
||||||
.rs-bar.rs-transition.rs-second {
|
height: 100%;
|
||||||
z-index: 20 !important;
|
text-align: center;
|
||||||
}
|
z-index: 15;
|
||||||
#thermostat .rs-readonly {
|
color: var(--primary-text-color);
|
||||||
z-index: 10;
|
}
|
||||||
top: auto;
|
#set-temperature {
|
||||||
}
|
font-size: var(--set-temperature-font-size);
|
||||||
#thermostat .rs-inner.rs-bg-color.rs-border,
|
margin-bottom: var(--set-temperature-margin-bottom);
|
||||||
#thermostat .rs-overlay.rs-transition.rs-bg-color {
|
min-height: 1.2em;
|
||||||
background-color: var(--paper-card-background-color, white);
|
}
|
||||||
}
|
.title {
|
||||||
#tooltip {
|
font-size: var(--title-font-size);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: var(--title-position-top);
|
||||||
left: 0;
|
left: 50%;
|
||||||
right: 0;
|
transform: translate(-50%, -50%);
|
||||||
height: 100%;
|
}
|
||||||
text-align: center;
|
.climate-info {
|
||||||
z-index: 15;
|
position: absolute;
|
||||||
color: var(--primary-text-color);
|
top: var(--climate-info-position-top);
|
||||||
}
|
left: 50%;
|
||||||
#set-temperature {
|
transform: translate(-50%, -50%);
|
||||||
font-size: var(--set-temperature-font-size);
|
width: 100%;
|
||||||
margin-bottom: var(--set-temperature-margin-bottom);
|
}
|
||||||
min-height: 1.2em;
|
.current-mode {
|
||||||
}
|
font-size: var(--current-mode-font-size);
|
||||||
.title {
|
color: var(--secondary-text-color);
|
||||||
font-size: var(--title-font-size);
|
margin-top: var(--current-mod-margin-top);
|
||||||
position: absolute;
|
margin-bottom: var(--current-mod-margin-bottom);
|
||||||
top: var(--title-position-top);
|
}
|
||||||
left: 50%;
|
.modes ha-icon {
|
||||||
transform: translate(-50%, -50%);
|
color: var(--disabled-text-color);
|
||||||
}
|
cursor: pointer;
|
||||||
.climate-info {
|
display: inline-block;
|
||||||
position: absolute;
|
margin: 0 10px;
|
||||||
top: var(--climate-info-position-top);
|
}
|
||||||
left: 50%;
|
.modes ha-icon.selected-icon {
|
||||||
transform: translate(-50%, -50%);
|
color: var(--mode-color);
|
||||||
width: 100%;
|
}
|
||||||
}
|
.current-temperature {
|
||||||
.current-mode {
|
position: absolute;
|
||||||
font-size: var(--current-mode-font-size);
|
top: 50%;
|
||||||
color: var(--secondary-text-color);
|
left: 50%;
|
||||||
}
|
transform: translate(-50%, -50%);
|
||||||
.modes {
|
font-size: var(--current-temperature-font-size);
|
||||||
margin-top: 16px;
|
}
|
||||||
}
|
.current-temperature-text {
|
||||||
.modes ha-icon {
|
padding-left: var(--current-temperature-text-padding-left);
|
||||||
color: var(--disabled-text-color);
|
}
|
||||||
cursor: pointer;
|
.uom {
|
||||||
display: inline-block;
|
font-size: var(--uom-font-size);
|
||||||
margin: 0 10px;
|
vertical-align: top;
|
||||||
}
|
margin-left: var(--uom-margin-left);
|
||||||
.modes ha-icon.selected-icon {
|
}
|
||||||
color: var(--mode-color);
|
.more-info {
|
||||||
}
|
position: absolute;
|
||||||
.current-temperature {
|
cursor: pointer;
|
||||||
position: absolute;
|
top: 0;
|
||||||
top: 50%;
|
right: 0;
|
||||||
left: 50%;
|
z-index: 25;
|
||||||
transform: translate(-50%, -50%);
|
color: var(--secondary-text-color);
|
||||||
font-size: var(--current-temperature-font-size);
|
}
|
||||||
}
|
|
||||||
.current-temperature-text {
|
|
||||||
padding-left: var(--current-temperature-text-padding-left);
|
|
||||||
}
|
|
||||||
.uom {
|
|
||||||
font-size: var(--uom-font-size);
|
|
||||||
vertical-align: top;
|
|
||||||
margin-left: var(--uom-margin-left);
|
|
||||||
}
|
|
||||||
.more-info {
|
|
||||||
position: absolute;
|
|
||||||
cursor: pointer;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 25;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { html } from "lit-element";
|
|
||||||
// jQuery import should come before plugin import
|
|
||||||
import { jQuery as jQuery_ } from "./jquery";
|
|
||||||
import "round-slider";
|
|
||||||
// eslint-disable-next-line
|
|
||||||
import roundSliderCSS from "round-slider/dist/roundslider.min.css";
|
|
||||||
|
|
||||||
export const jQuery = jQuery_;
|
|
||||||
|
|
||||||
export const roundSliderStyle = html`
|
|
||||||
<style>
|
|
||||||
${roundSliderCSS}
|
|
||||||
</style>
|
|
||||||
`;
|
|
@ -1,15 +0,0 @@
|
|||||||
import { TemplateResult } from "lit-element";
|
|
||||||
|
|
||||||
interface LoadedRoundSlider {
|
|
||||||
roundSliderStyle: TemplateResult;
|
|
||||||
jQuery: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
let loaded: Promise<LoadedRoundSlider>;
|
|
||||||
|
|
||||||
export const loadRoundslider = async (): Promise<LoadedRoundSlider> => {
|
|
||||||
if (!loaded) {
|
|
||||||
loaded = import(/* webpackChunkName: "jquery-roundslider" */ "./jquery.roundslider");
|
|
||||||
}
|
|
||||||
return loaded;
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
import jQuery_ from "jquery";
|
|
||||||
|
|
||||||
(window as any).jQuery = jQuery_;
|
|
||||||
|
|
||||||
export const jQuery = jQuery_;
|
|
12
yarn.lock
12
yarn.lock
@ -7686,11 +7686,6 @@ joi@^14.3.1:
|
|||||||
isemail "3.x.x"
|
isemail "3.x.x"
|
||||||
topo "3.x.x"
|
topo "3.x.x"
|
||||||
|
|
||||||
"jquery@>= 1.4.1", jquery@^3.4.0:
|
|
||||||
version "3.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.0.tgz#8de513fa0fa4b2c7d2e48a530e26f0596936efdf"
|
|
||||||
integrity sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ==
|
|
||||||
|
|
||||||
js-levenshtein@^1.1.3:
|
js-levenshtein@^1.1.3:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
|
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
|
||||||
@ -11050,13 +11045,6 @@ rollup@^1.3.0:
|
|||||||
"@types/node" "^11.11.6"
|
"@types/node" "^11.11.6"
|
||||||
acorn "^6.1.1"
|
acorn "^6.1.1"
|
||||||
|
|
||||||
round-slider@^1.3.3:
|
|
||||||
version "1.3.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/round-slider/-/round-slider-1.3.3.tgz#0ec82261317b0aba35ac86a48fbd024baa50b261"
|
|
||||||
integrity sha512-Mo6HYiN5l6O0UNI/ytjr8ERgtZcXGRZ6A6+V6f2S/hKkbSaQnKCW+lpLPfoxWuW1xiPbAJs3qrXeps1xC+sjVg==
|
|
||||||
dependencies:
|
|
||||||
jquery ">= 1.4.1"
|
|
||||||
|
|
||||||
run-async@^2.2.0:
|
run-async@^2.2.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
|
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user