Merge pull request #5840 from home-assistant/dev
@ -9,25 +9,30 @@ const paths = require("../paths");
|
|||||||
gulp.task("compress-app", function compressApp() {
|
gulp.task("compress-app", function compressApp() {
|
||||||
const jsLatest = gulp
|
const jsLatest = gulp
|
||||||
.src(path.resolve(paths.output, "**/*.js"))
|
.src(path.resolve(paths.output, "**/*.js"))
|
||||||
.pipe(zopfli())
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(paths.output));
|
.pipe(gulp.dest(paths.output));
|
||||||
|
|
||||||
const jsEs5 = gulp
|
const jsEs5 = gulp
|
||||||
.src(path.resolve(paths.output_es5, "**/*.js"))
|
.src(path.resolve(paths.output_es5, "**/*.js"))
|
||||||
.pipe(zopfli())
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(paths.output_es5));
|
.pipe(gulp.dest(paths.output_es5));
|
||||||
|
|
||||||
const polyfills = gulp
|
const polyfills = gulp
|
||||||
.src(path.resolve(paths.static, "polyfills/*.js"))
|
.src(path.resolve(paths.static, "polyfills/*.js"))
|
||||||
.pipe(zopfli())
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(path.resolve(paths.static, "polyfills")));
|
.pipe(gulp.dest(path.resolve(paths.static, "polyfills")));
|
||||||
|
|
||||||
const translations = gulp
|
const translations = gulp
|
||||||
.src(path.resolve(paths.static, "translations/*.json"))
|
.src(path.resolve(paths.static, "translations/**/*.json"))
|
||||||
.pipe(zopfli())
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(path.resolve(paths.static, "translations")));
|
.pipe(gulp.dest(path.resolve(paths.static, "translations")));
|
||||||
|
|
||||||
return merge(jsLatest, jsEs5, polyfills, translations);
|
const icons = gulp
|
||||||
|
.src(path.resolve(paths.static, "mdi/*.json"))
|
||||||
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
|
.pipe(gulp.dest(path.resolve(paths.static, "mdi")));
|
||||||
|
|
||||||
|
return merge(jsLatest, jsEs5, polyfills, translations, icons);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("compress-hassio", function compressApp() {
|
gulp.task("compress-hassio", function compressApp() {
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
"@polymer/paper-toast": "^3.0.1",
|
"@polymer/paper-toast": "^3.0.1",
|
||||||
"@polymer/paper-tooltip": "^3.0.1",
|
"@polymer/paper-tooltip": "^3.0.1",
|
||||||
"@polymer/polymer": "3.1.0",
|
"@polymer/polymer": "3.1.0",
|
||||||
"@thomasloven/round-slider": "0.3.7",
|
"@thomasloven/round-slider": "0.4.1",
|
||||||
"@vaadin/vaadin-combo-box": "^5.0.10",
|
"@vaadin/vaadin-combo-box": "^5.0.10",
|
||||||
"@vaadin/vaadin-date-picker": "^4.0.7",
|
"@vaadin/vaadin-date-picker": "^4.0.7",
|
||||||
"@webcomponents/shadycss": "^1.9.0",
|
"@webcomponents/shadycss": "^1.9.0",
|
||||||
|
Before Width: | Height: | Size: 655 B |
Before Width: | Height: | Size: 888 B |
Before Width: | Height: | Size: 807 B |
Before Width: | Height: | Size: 639 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 840 B |
Before Width: | Height: | Size: 798 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 487 B |
Before Width: | Height: | Size: 774 B |
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20200509.0",
|
version="20200512.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -16,14 +16,6 @@ import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers";
|
|||||||
import "./ha-icon";
|
import "./ha-icon";
|
||||||
import "./ha-svg-icon";
|
import "./ha-svg-icon";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
// for fire event
|
|
||||||
interface HASSDomEvents {
|
|
||||||
activated: undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ha-tab")
|
@customElement("ha-tab")
|
||||||
export class HaTab extends LitElement {
|
export class HaTab extends LitElement {
|
||||||
@ -54,11 +46,10 @@ export class HaTab extends LitElement {
|
|||||||
@touchend=${this.handleRippleDeactivate}
|
@touchend=${this.handleRippleDeactivate}
|
||||||
@touchcancel=${this.handleRippleDeactivate}
|
@touchcancel=${this.handleRippleDeactivate}
|
||||||
@keydown=${this._handleKeyDown}
|
@keydown=${this._handleKeyDown}
|
||||||
@click=${this._handleClick}
|
|
||||||
>
|
>
|
||||||
${this.narrow ? html`<slot name="icon"></slot>` : ""}
|
${this.narrow ? html`<slot name="icon"></slot>` : ""}
|
||||||
${!this.narrow || this.active
|
${!this.narrow || this.active
|
||||||
? html` <span class="name">${this.name}</span> `
|
? html`<span class="name">${this.name}</span>`
|
||||||
: ""}
|
: ""}
|
||||||
${this._shouldRenderRipple ? html`<mwc-ripple></mwc-ripple>` : ""}
|
${this._shouldRenderRipple ? html`<mwc-ripple></mwc-ripple>` : ""}
|
||||||
</div>
|
</div>
|
||||||
@ -72,14 +63,10 @@ export class HaTab extends LitElement {
|
|||||||
|
|
||||||
private _handleKeyDown(ev: KeyboardEvent): void {
|
private _handleKeyDown(ev: KeyboardEvent): void {
|
||||||
if (ev.keyCode === 13) {
|
if (ev.keyCode === 13) {
|
||||||
fireEvent(this, "activated");
|
(ev.target as HTMLElement).click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleClick(): void {
|
|
||||||
fireEvent(this, "activated");
|
|
||||||
}
|
|
||||||
|
|
||||||
@eventOptions({ passive: true })
|
@eventOptions({ passive: true })
|
||||||
private handleRippleActivate(evt?: Event) {
|
private handleRippleActivate(evt?: Event) {
|
||||||
this._rippleHandlers.startPress(evt);
|
this._rippleHandlers.startPress(evt);
|
||||||
|
@ -18,7 +18,11 @@ export interface IntegrationManifest {
|
|||||||
quality_scale?: string;
|
quality_scale?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const integrationIssuesUrl = (domain: string) =>
|
export const integrationIssuesUrl = (
|
||||||
|
domain: string,
|
||||||
|
manifest: IntegrationManifest
|
||||||
|
) =>
|
||||||
|
manifest.issue_tracker ||
|
||||||
`https://github.com/home-assistant/home-assistant/issues?q=is%3Aissue+is%3Aopen+label%3A%22integration%3A+${domain}%22`;
|
`https://github.com/home-assistant/home-assistant/issues?q=is%3Aissue+is%3Aopen+label%3A%22integration%3A+${domain}%22`;
|
||||||
|
|
||||||
export const domainToName = (localize: LocalizeFunc, domain: string) =>
|
export const domainToName = (localize: LocalizeFunc, domain: string) =>
|
||||||
|
@ -1,26 +1,52 @@
|
|||||||
import { HomeAssistant, WeatherEntity } from "../types";
|
import { SVGTemplateResult, svg, html, TemplateResult, css } from "lit-element";
|
||||||
|
import { styleMap } from "lit-html/directives/style-map";
|
||||||
|
|
||||||
export const weatherImages = {
|
import type { HomeAssistant, WeatherEntity } from "../types";
|
||||||
"clear-night": "/static/images/weather/night.png",
|
|
||||||
cloudy: "/static/images/weather/cloudy.png",
|
export const weatherSVGs = new Set<string>([
|
||||||
fog: "/static/images/weather/cloudy.png",
|
"clear-night",
|
||||||
lightning: "/static/images/weather/lightning.png",
|
"cloudy",
|
||||||
"lightning-rainy": "/static/images/weather/lightning-rainy.png",
|
"fog",
|
||||||
partlycloudy: "/static/images/weather/partly-cloudy.png",
|
"lightning",
|
||||||
pouring: "/static/images/weather/pouring.png",
|
"lightning-rainy",
|
||||||
rainy: "/static/images/weather/rainy.png",
|
"partlycloudy",
|
||||||
hail: "/static/images/weather/rainy.png",
|
"pouring",
|
||||||
snowy: "/static/images/weather/snowy.png",
|
"rainy",
|
||||||
"snowy-rainy": "/static/images/weather/snowy.png",
|
"hail",
|
||||||
sunny: "/static/images/weather/sunny.png",
|
"snowy",
|
||||||
windy: "/static/images/weather/windy.png",
|
"snowy-rainy",
|
||||||
"windy-variant": "/static/images/weather/windy.png",
|
"sunny",
|
||||||
};
|
"windy",
|
||||||
|
"windy-variant",
|
||||||
|
]);
|
||||||
|
|
||||||
export const weatherIcons = {
|
export const weatherIcons = {
|
||||||
exceptional: "hass:alert-circle-outline",
|
exceptional: "hass:alert-circle-outline",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cloudyStates = new Set<string>([
|
||||||
|
"partlycloudy",
|
||||||
|
"cloudy",
|
||||||
|
"fog",
|
||||||
|
"windy",
|
||||||
|
"windy-variant",
|
||||||
|
"hail",
|
||||||
|
"rainy",
|
||||||
|
"snowy",
|
||||||
|
"snowy-rainy",
|
||||||
|
"pouring",
|
||||||
|
"lightning",
|
||||||
|
"lightning-rainy",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const rainStates = new Set<string>(["hail", "rainy", "pouring"]);
|
||||||
|
|
||||||
|
const windyStates = new Set<string>(["windy", "windy-variant"]);
|
||||||
|
|
||||||
|
const snowyStates = new Set<string>(["snowy", "snowy-rainy"]);
|
||||||
|
|
||||||
|
const lightningStates = new Set<string>(["lightning", "lightning-rainy"]);
|
||||||
|
|
||||||
export const cardinalDirections = [
|
export const cardinalDirections = [
|
||||||
"N",
|
"N",
|
||||||
"NNE",
|
"NNE",
|
||||||
@ -164,3 +190,183 @@ const getWeatherExtrema = (
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const weatherSVGStyles = css`
|
||||||
|
.rain {
|
||||||
|
fill: var(--weather-icon-rain-color, #30b3ff);
|
||||||
|
}
|
||||||
|
.sun {
|
||||||
|
fill: var(--weather-icon-sun-color, #fdd93c);
|
||||||
|
}
|
||||||
|
.moon {
|
||||||
|
fill: var(--weather-icon-moon-color, #fdf9cc);
|
||||||
|
}
|
||||||
|
.cloud-back {
|
||||||
|
fill: var(--weather-icon-cloud-back-color, #d4d4d4);
|
||||||
|
}
|
||||||
|
.cloud-front {
|
||||||
|
fill: var(--weather-icon-cloud-front-color, #f9f9f9);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const getWeatherStateSVG = (state: string): SVGTemplateResult => {
|
||||||
|
return svg`
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 17 17"
|
||||||
|
>
|
||||||
|
${
|
||||||
|
state === "sunny"
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="sun"
|
||||||
|
d="m 14.39303,8.4033507 c 0,3.3114723 -2.684145,5.9956173 -5.9956169,5.9956173 -3.3114716,0 -5.9956168,-2.684145 -5.9956168,-5.9956173 0,-3.311471 2.6841452,-5.995617 5.9956168,-5.995617 3.3114719,0 5.9956169,2.684146 5.9956169,5.995617"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
state === "clear-night"
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="moon"
|
||||||
|
d="m 13.502891,11.382935 c -1.011285,1.859223 -2.976664,3.121381 -5.2405751,3.121381 -3.289929,0 -5.953329,-2.663833 -5.953329,-5.9537625 0,-2.263911 1.261724,-4.228856 3.120948,-5.240575 -0.452782,0.842738 -0.712753,1.806363 -0.712753,2.832381 0,3.289928 2.663833,5.9533275 5.9533291,5.9533275 1.026017,0 1.989641,-0.259969 2.83238,-0.712752"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
state === "partlycloudy"
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="sun"
|
||||||
|
d="m14.981 4.2112c0 1.9244-1.56 3.4844-3.484 3.4844-1.9244 0-3.4844-1.56-3.4844-3.4844s1.56-3.484 3.4844-3.484c1.924 0 3.484 1.5596 3.484 3.484"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
cloudyStates.has(state)
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="cloud-back"
|
||||||
|
d="m3.8863 5.035c-0.54892 0.16898-1.04 0.46637-1.4372 0.8636-0.63077 0.63041-1.0206 1.4933-1.0206 2.455 0 1.9251 1.5589 3.4682 3.4837 3.4682h6.9688c1.9251 0 3.484-1.5981 3.484-3.5232 0-1.9251-1.5589-3.5232-3.484-3.5232h-1.0834c-0.25294-1.6916-1.6986-2.9083-3.4463-2.9083-1.7995 0-3.2805 1.4153-3.465 3.1679"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cloud-front"
|
||||||
|
d="m4.1996 7.6995c-0.33902 0.10407-0.64276 0.28787-0.88794 0.5334-0.39017 0.38982-0.63147 0.92322-0.63147 1.5176 0 1.1896 0.96414 2.1431 2.1537 2.1431h4.3071c1.1896 0 2.153-0.98742 2.153-2.1777 0-1.1896-0.96344-2.1777-2.153-2.1777h-0.66992c-0.15593-1.0449-1.0499-1.7974-2.1297-1.7974-1.112 0-2.0274 0.87524-2.1417 1.9586"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
rainStates.has(state)
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m5.2852 14.734c-0.22401 0.24765-0.57115 0.2988-0.77505 0.11395-0.20391-0.1845-0.18732-0.53481 0.036689-0.78281 0.14817-0.16298 0.59126-0.32914 0.87559-0.42369 0.12453-0.04092 0.22684 0.05186 0.19791 0.17956-0.065617 0.2921-0.18732 0.74965-0.33514 0.91299"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m11.257 14.163c-0.22437 0.24765-0.57115 0.2988-0.77505 0.11395-0.2039-0.1845-0.18768-0.53481 0.03669-0.78281 0.14817-0.16298 0.59126-0.32914 0.8756-0.42369 0.12453-0.04092 0.22684 0.05186 0.19791 0.17956-0.06562 0.2921-0.18732 0.74965-0.33514 0.91299"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m8.432 15.878c-0.15452 0.17039-0.3937 0.20567-0.53446 0.07867-0.14041-0.12735-0.12876-0.36865 0.025753-0.53975 0.10195-0.11218 0.40711-0.22684 0.60325-0.29175 0.085725-0.02858 0.15628 0.03563 0.13652 0.12382-0.045508 0.20108-0.12912 0.51647-0.23107 0.629"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m7.9991 14.118c-0.19226 0.21237-0.49001 0.25612-0.66499 0.09737-0.17462-0.15804-0.16051-0.45861 0.03175-0.67098 0.12665-0.14005 0.50729-0.28293 0.75071-0.36336 0.10689-0.03563 0.19473 0.0441 0.17004 0.15346-0.056092 0.25082-0.16051 0.64347-0.28751 0.78352"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
state === "pouring"
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m10.648 16.448c-0.19226 0.21449-0.49001 0.25894-0.66499 0.09878-0.17498-0.16016-0.16087-0.4639 0.03175-0.67874 0.12665-0.14146 0.50694-0.2854 0.75071-0.36724 0.10689-0.03563 0.19473 0.0448 0.17004 0.15558-0.05645 0.25365-0.16051 0.65017-0.28751 0.79163"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m5.9383 16.658c-0.22437 0.25012-0.5715 0.30162-0.77505 0.11501-0.20391-0.18627-0.18768-0.54046 0.036689-0.79093 0.14817-0.1651 0.59126-0.33267 0.87559-0.42827 0.12418-0.04127 0.22648 0.05221 0.19791 0.18168-0.065617 0.29528-0.18732 0.75741-0.33514 0.92251"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
windyStates.has(state)
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="cloud-back"
|
||||||
|
d="m 13.59616,15.30968 c 0,0 -0.09137,-0.0071 -0.250472,-0.0187 -0.158045,-0.01235 -0.381353,-0.02893 -0.64382,-0.05715 -0.262466,-0.02716 -0.564444,-0.06385 -0.877358,-0.124531 -0.156986,-0.03034 -0.315383,-0.06844 -0.473781,-0.111478 -0.157691,-0.04551 -0.313266,-0.09842 -0.463902,-0.161219 l -0.267406,-0.0949 c -0.09984,-0.02646 -0.205669,-0.04904 -0.305153,-0.06738 -0.193322,-0.02716 -0.3838218,-0.03316 -0.5640912,-0.02011 -0.3626556,0.02611 -0.6847417,0.119239 -0.94615,0.226483 -0.2617611,0.108656 -0.4642556,0.230364 -0.600075,0.324203 -0.1358195,0.09419 -0.2049639,0.160514 -0.2049639,0.160514 0,0 0.089958,-0.01623 0.24765,-0.04445 0.1559278,-0.02575 0.3764139,-0.06174 0.6367639,-0.08714 0.2596444,-0.02646 0.5591527,-0.0441 0.8678333,-0.02328 0.076905,0.0035 0.1538111,0.01658 0.2321278,0.02293 0.077611,0.01058 0.1534581,0.02893 0.2314221,0.04022 0.07267,0.01834 0.1397,0.03986 0.213078,0.05644 l 0.238125,0.08925 c 0.09207,0.03281 0.183444,0.07055 0.275872,0.09878 0.09243,0.0261 0.185208,0.05327 0.277636,0.07161 0.184856,0.0388 0.367947,0.06174 0.543983,0.0702 0.353131,0.01905 0.678745,-0.01341 0.951442,-0.06456 0.27305,-0.05292 0.494595,-0.123119 0.646642,-0.181681 0.152047,-0.05785 0.234597,-0.104069 0.234597,-0.104069"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cloud-back"
|
||||||
|
d="m 4.7519154,13.905801 c 0,0 0.091369,-0.0032 0.2511778,-0.0092 0.1580444,-0.0064 0.3820583,-0.01446 0.6455833,-0.03281 0.2631722,-0.01729 0.5662083,-0.04269 0.8812389,-0.09137 0.1576916,-0.02434 0.3175,-0.05609 0.4776611,-0.09384 0.1591027,-0.03951 0.3167944,-0.08643 0.4699,-0.14358 l 0.2702277,-0.08467 c 0.1008945,-0.02222 0.2074334,-0.04127 0.3072695,-0.05574 0.1943805,-0.01976 0.3848805,-0.0187 0.5651499,0.0014 0.3608917,0.03951 0.67945,0.144639 0.936625,0.261761 0.2575278,0.118534 0.4554364,0.247297 0.5873754,0.346781 0.132291,0.09913 0.198966,0.168275 0.198966,0.168275 0,0 -0.08925,-0.01976 -0.245886,-0.05397 C 9.9423347,14.087088 9.7232597,14.042988 9.4639681,14.00736 9.2057347,13.97173 8.9072848,13.94245 8.5978986,13.95162 c -0.077258,7.06e-4 -0.1541638,0.01058 -0.2328333,0.01411 -0.077964,0.0078 -0.1545166,0.02328 -0.2331861,0.03175 -0.073025,0.01588 -0.1404055,0.03422 -0.2141361,0.04798 l -0.2420055,0.08008 c -0.093486,0.02963 -0.1859139,0.06421 -0.2794,0.0889 C 7.3028516,14.23666 7.2093653,14.2603 7.116232,14.27512 6.9303181,14.30722 6.7465209,14.3231 6.5697792,14.32486 6.2166487,14.33046 5.8924459,14.28605 5.6218654,14.224318 5.3505793,14.161565 5.1318571,14.082895 4.9822793,14.01869 4.8327015,13.95519 4.7519154,13.905801 4.7519154,13.905801"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
snowyStates.has(state)
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m 8.4319893,15.348341 c 0,0.257881 -0.209197,0.467079 -0.467078,0.467079 -0.258586,0 -0.46743,-0.209198 -0.46743,-0.467079 0,-0.258233 0.208844,-0.467431 0.46743,-0.467431 0.257881,0 0.467078,0.209198 0.467078,0.467431"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m 11.263878,14.358553 c 0,0.364067 -0.295275,0.659694 -0.659695,0.659694 -0.364419,0 -0.6596937,-0.295627 -0.6596937,-0.659694 0,-0.364419 0.2952747,-0.659694 0.6596937,-0.659694 0.36442,0 0.659695,0.295275 0.659695,0.659694"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="rain"
|
||||||
|
d="m 5.3252173,13.69847 c 0,0.364419 -0.295275,0.660047 -0.659695,0.660047 -0.364067,0 -0.659694,-0.295628 -0.659694,-0.660047 0,-0.364067 0.295627,-0.659694 0.659694,-0.659694 0.36442,0 0.659695,0.295627 0.659695,0.659694"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${
|
||||||
|
lightningStates.has(state)
|
||||||
|
? svg`
|
||||||
|
<path
|
||||||
|
class="sun"
|
||||||
|
d="m 9.9252695,10.935875 -1.6483986,2.341014 1.1170184,0.05929 -1.2169864,2.02141 3.0450261,-2.616159 H 9.8864918 L 10.97937,11.294651 10.700323,10.79794 h -0.508706 l -0.2663475,0.137936"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
</svg>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getWeatherStateIcon = (
|
||||||
|
state: string,
|
||||||
|
element: HTMLElement
|
||||||
|
): TemplateResult | undefined => {
|
||||||
|
const userDefinedIcon = getComputedStyle(element).getPropertyValue(
|
||||||
|
`--weather-icon-${state}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userDefinedIcon) {
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
style="background-size: cover;${styleMap({
|
||||||
|
"background-image": userDefinedIcon,
|
||||||
|
})}"
|
||||||
|
></div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weatherSVGs.has(state)) {
|
||||||
|
return html`${getWeatherStateSVG(state)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state in weatherIcons) {
|
||||||
|
return html`
|
||||||
|
<ha-icon class="weather-icon" .icon=${weatherIcons[state]}></ha-icon>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
@ -3,6 +3,7 @@ import { HomeAssistant } from "../types";
|
|||||||
|
|
||||||
export interface ZHAEntityReference extends HassEntity {
|
export interface ZHAEntityReference extends HassEntity {
|
||||||
name: string;
|
name: string;
|
||||||
|
original_name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ZHADevice {
|
export interface ZHADevice {
|
||||||
@ -26,6 +27,12 @@ export interface ZHADevice {
|
|||||||
signature: any;
|
signature: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ZHADeviceEndpoint {
|
||||||
|
device: ZHADevice;
|
||||||
|
endpoint_id: number;
|
||||||
|
entities: ZHAEntityReference[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface Attribute {
|
export interface Attribute {
|
||||||
name: string;
|
name: string;
|
||||||
id: number;
|
id: number;
|
||||||
@ -56,7 +63,12 @@ export interface ReadAttributeServiceData {
|
|||||||
export interface ZHAGroup {
|
export interface ZHAGroup {
|
||||||
name: string;
|
name: string;
|
||||||
group_id: number;
|
group_id: number;
|
||||||
members: ZHADevice[];
|
members: ZHADeviceEndpoint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ZHAGroupMember {
|
||||||
|
ieee: string;
|
||||||
|
endpoint_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reconfigureNode = (
|
export const reconfigureNode = (
|
||||||
@ -213,7 +225,7 @@ export const fetchGroup = (
|
|||||||
|
|
||||||
export const fetchGroupableDevices = (
|
export const fetchGroupableDevices = (
|
||||||
hass: HomeAssistant
|
hass: HomeAssistant
|
||||||
): Promise<ZHADevice[]> =>
|
): Promise<ZHADeviceEndpoint[]> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/devices/groupable",
|
type: "zha/devices/groupable",
|
||||||
});
|
});
|
||||||
@ -221,7 +233,7 @@ export const fetchGroupableDevices = (
|
|||||||
export const addMembersToGroup = (
|
export const addMembersToGroup = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
groupId: number,
|
groupId: number,
|
||||||
membersToAdd: string[]
|
membersToAdd: ZHAGroupMember[]
|
||||||
): Promise<ZHAGroup> =>
|
): Promise<ZHAGroup> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/group/members/add",
|
type: "zha/group/members/add",
|
||||||
@ -232,7 +244,7 @@ export const addMembersToGroup = (
|
|||||||
export const removeMembersFromGroup = (
|
export const removeMembersFromGroup = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
groupId: number,
|
groupId: number,
|
||||||
membersToRemove: string[]
|
membersToRemove: ZHAGroupMember[]
|
||||||
): Promise<ZHAGroup> =>
|
): Promise<ZHAGroup> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/group/members/remove",
|
type: "zha/group/members/remove",
|
||||||
@ -243,7 +255,7 @@ export const removeMembersFromGroup = (
|
|||||||
export const addGroup = (
|
export const addGroup = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
groupName: string,
|
groupName: string,
|
||||||
membersToAdd?: string[]
|
membersToAdd?: ZHAGroupMember[]
|
||||||
): Promise<ZHAGroup> =>
|
): Promise<ZHAGroup> =>
|
||||||
hass.callWS({
|
hass.callWS({
|
||||||
type: "zha/group/add",
|
type: "zha/group/add",
|
||||||
|
@ -104,6 +104,11 @@ window.hassConnection.then(({ conn }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("error", (e) => {
|
window.addEventListener("error", (e) => {
|
||||||
|
if (!__DEV__ && e.message === "ResizeObserver loop limit exceeded") {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
e.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const homeAssistant = document.querySelector("home-assistant") as any;
|
const homeAssistant = document.querySelector("home-assistant") as any;
|
||||||
if (
|
if (
|
||||||
homeAssistant &&
|
homeAssistant &&
|
||||||
|
@ -74,7 +74,7 @@ class HassTabsSubpage extends LitElement {
|
|||||||
html`
|
html`
|
||||||
<ha-tab
|
<ha-tab
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@activated=${this._tabTapped}
|
@click=${this._tabTapped}
|
||||||
.path=${page.path}
|
.path=${page.path}
|
||||||
.active=${page === activeTab}
|
.active=${page === activeTab}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
|
@ -60,6 +60,7 @@ import type {
|
|||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import { mdiPlus } from "@mdi/js";
|
import { mdiPlus } from "@mdi/js";
|
||||||
|
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
|
|
||||||
interface DataEntryFlowProgressExtended extends DataEntryFlowProgress {
|
interface DataEntryFlowProgressExtended extends DataEntryFlowProgress {
|
||||||
localized_title?: string;
|
localized_title?: string;
|
||||||
@ -121,7 +122,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
this._deviceRegistryEntries = entries;
|
this._deviceRegistryEntries = entries;
|
||||||
}),
|
}),
|
||||||
subscribeConfigFlowInProgress(this.hass, async (flowsInProgress) => {
|
subscribeConfigFlowInProgress(this.hass, async (flowsInProgress) => {
|
||||||
const translationsPromisses: Promise<void>[] = [];
|
const translationsPromisses: Promise<LocalizeFunc>[] = [];
|
||||||
flowsInProgress.forEach((flow) => {
|
flowsInProgress.forEach((flow) => {
|
||||||
// To render title placeholders
|
// To render title placeholders
|
||||||
if (flow.context.title_placeholders) {
|
if (flow.context.title_placeholders) {
|
||||||
|
@ -18,31 +18,31 @@ import type { SelectionChangedEvent } from "../../../components/data-table/ha-da
|
|||||||
import {
|
import {
|
||||||
addGroup,
|
addGroup,
|
||||||
fetchGroupableDevices,
|
fetchGroupableDevices,
|
||||||
ZHADevice,
|
|
||||||
ZHAGroup,
|
ZHAGroup,
|
||||||
|
ZHADeviceEndpoint,
|
||||||
} from "../../../data/zha";
|
} from "../../../data/zha";
|
||||||
import "../../../layouts/hass-error-screen";
|
import "../../../layouts/hass-error-screen";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import type { PolymerChangedEvent } from "../../../polymer-types";
|
import type { PolymerChangedEvent } from "../../../polymer-types";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import "./zha-devices-data-table";
|
import "./zha-device-endpoint-data-table";
|
||||||
import type { ZHADevicesDataTable } from "./zha-devices-data-table";
|
import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table";
|
||||||
|
|
||||||
@customElement("zha-add-group-page")
|
@customElement("zha-add-group-page")
|
||||||
export class ZHAAddGroupPage extends LitElement {
|
export class ZHAAddGroupPage extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property() public devices: ZHADevice[] = [];
|
@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
@property() private _processingAdd = false;
|
@property() private _processingAdd = false;
|
||||||
|
|
||||||
@property() private _groupName = "";
|
@property() private _groupName = "";
|
||||||
|
|
||||||
@query("zha-devices-data-table")
|
@query("zha-device-endpoint-data-table")
|
||||||
private _zhaDevicesDataTable!: ZHADevicesDataTable;
|
private _zhaDevicesDataTable!: ZHADeviceEndpointDataTable;
|
||||||
|
|
||||||
private _firstUpdatedCalled = false;
|
private _firstUpdatedCalled = false;
|
||||||
|
|
||||||
@ -87,14 +87,14 @@ export class ZHAAddGroupPage extends LitElement {
|
|||||||
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<zha-devices-data-table
|
<zha-device-endpoint-data-table
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.devices=${this.devices}
|
.deviceEndpoints=${this.deviceEndpoints}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
selectable
|
selectable
|
||||||
@selection-changed=${this._handleAddSelectionChanged}
|
@selection-changed=${this._handleAddSelectionChanged}
|
||||||
>
|
>
|
||||||
</zha-devices-data-table>
|
</zha-device-endpoint-data-table>
|
||||||
|
|
||||||
<div class="paper-dialog-buttons">
|
<div class="paper-dialog-buttons">
|
||||||
<mwc-button
|
<mwc-button
|
||||||
@ -121,7 +121,7 @@ export class ZHAAddGroupPage extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchData() {
|
private async _fetchData() {
|
||||||
this.devices = await fetchGroupableDevices(this.hass!);
|
this.deviceEndpoints = await fetchGroupableDevices(this.hass!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleAddSelectionChanged(
|
private _handleAddSelectionChanged(
|
||||||
@ -132,11 +132,11 @@ export class ZHAAddGroupPage extends LitElement {
|
|||||||
|
|
||||||
private async _createGroup(): Promise<void> {
|
private async _createGroup(): Promise<void> {
|
||||||
this._processingAdd = true;
|
this._processingAdd = true;
|
||||||
const group: ZHAGroup = await addGroup(
|
const members = this._selectedDevicesToAdd.map((member) => {
|
||||||
this.hass,
|
const memberParts = member.split("_");
|
||||||
this._groupName,
|
return { ieee: memberParts[0], endpoint_id: memberParts[1] };
|
||||||
this._selectedDevicesToAdd
|
});
|
||||||
);
|
const group: ZHAGroup = await addGroup(this.hass, this._groupName, members);
|
||||||
this._selectedDevicesToAdd = [];
|
this._selectedDevicesToAdd = [];
|
||||||
this._processingAdd = false;
|
this._processingAdd = false;
|
||||||
this._groupName = "";
|
this._groupName = "";
|
||||||
|
@ -16,6 +16,7 @@ import "../../../components/data-table/ha-data-table";
|
|||||||
import type {
|
import type {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
RowClickedEvent,
|
RowClickedEvent,
|
||||||
|
DataTableRowData,
|
||||||
} from "../../../components/data-table/ha-data-table";
|
} from "../../../components/data-table/ha-data-table";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
@ -27,19 +28,19 @@ import type { HomeAssistant, Route } from "../../../types";
|
|||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import { formatAsPaddedHex, sortZHADevices } from "./functions";
|
import { formatAsPaddedHex, sortZHADevices } from "./functions";
|
||||||
|
|
||||||
export interface DeviceRowData extends ZHADevice {
|
export interface DeviceRowData extends DataTableRowData {
|
||||||
device?: DeviceRowData;
|
device?: DeviceRowData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("zha-config-dashboard")
|
@customElement("zha-config-dashboard")
|
||||||
class ZHAConfigDashboard extends LitElement {
|
class ZHAConfigDashboard extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public route!: Route;
|
@property({ type: Object }) public route!: Route;
|
||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property() public isWide!: boolean;
|
@property({ type: Boolean }) public isWide!: boolean;
|
||||||
|
|
||||||
@property() private _devices: ZHADevice[] = [];
|
@property() private _devices: ZHADevice[] = [];
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ class ZHAConfigDashboard extends LitElement {
|
|||||||
title: "IEEE",
|
title: "IEEE",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "25%",
|
width: "30%",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
182
src/panels/config/zha/zha-device-endpoint-data-table.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import "../../../components/data-table/ha-data-table";
|
||||||
|
import type {
|
||||||
|
DataTableColumnContainer,
|
||||||
|
HaDataTable,
|
||||||
|
DataTableRowData,
|
||||||
|
} from "../../../components/data-table/ha-data-table";
|
||||||
|
import "../../../components/entity/ha-state-icon";
|
||||||
|
import type { ZHADeviceEndpoint, ZHAEntityReference } from "../../../data/zha";
|
||||||
|
import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
|
export interface DeviceEndpointRowData extends DataTableRowData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
model: string;
|
||||||
|
manufacturer: string;
|
||||||
|
endpoint_id: number;
|
||||||
|
entities: ZHAEntityReference[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("zha-device-endpoint-data-table")
|
||||||
|
export class ZHADeviceEndpointDataTable extends LitElement {
|
||||||
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public selectable = false;
|
||||||
|
|
||||||
|
@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
|
@query("ha-data-table") private _dataTable!: HaDataTable;
|
||||||
|
|
||||||
|
private _deviceEndpoints = memoizeOne(
|
||||||
|
(deviceEndpoints: ZHADeviceEndpoint[]) => {
|
||||||
|
const outputDevices: DeviceEndpointRowData[] = [];
|
||||||
|
|
||||||
|
deviceEndpoints.forEach((deviceEndpoint) => {
|
||||||
|
outputDevices.push({
|
||||||
|
name:
|
||||||
|
deviceEndpoint.device.user_given_name || deviceEndpoint.device.name,
|
||||||
|
model: deviceEndpoint.device.model,
|
||||||
|
manufacturer: deviceEndpoint.device.manufacturer,
|
||||||
|
id: deviceEndpoint.device.ieee + "_" + deviceEndpoint.endpoint_id,
|
||||||
|
ieee: deviceEndpoint.device.ieee,
|
||||||
|
endpoint_id: deviceEndpoint.endpoint_id,
|
||||||
|
entities: deviceEndpoint.entities,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return outputDevices;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
private _columns = memoizeOne(
|
||||||
|
(narrow: boolean): DataTableColumnContainer =>
|
||||||
|
narrow
|
||||||
|
? {
|
||||||
|
name: {
|
||||||
|
title: "Devices",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
grows: true,
|
||||||
|
template: (name) => html`
|
||||||
|
<div
|
||||||
|
class="mdc-data-table__cell table-cell-text"
|
||||||
|
@click=${this._handleClicked}
|
||||||
|
style="cursor: pointer;"
|
||||||
|
>
|
||||||
|
${name}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
endpoint_id: {
|
||||||
|
title: "Endpoint",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
name: {
|
||||||
|
title: "Name",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
direction: "asc",
|
||||||
|
grows: true,
|
||||||
|
template: (name) => html`
|
||||||
|
<div
|
||||||
|
class="mdc-data-table__cell table-cell-text"
|
||||||
|
@click=${this._handleClicked}
|
||||||
|
style="cursor: pointer;"
|
||||||
|
>
|
||||||
|
${name}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
endpoint_id: {
|
||||||
|
title: "Endpoint",
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
entities: {
|
||||||
|
title: "Associated Entities",
|
||||||
|
sortable: false,
|
||||||
|
filterable: false,
|
||||||
|
width: "50%",
|
||||||
|
template: (entities) => html`
|
||||||
|
${entities.length
|
||||||
|
? entities.length > 3
|
||||||
|
? html`${entities.slice(0, 2).map(
|
||||||
|
(entity) =>
|
||||||
|
html`<div
|
||||||
|
style="overflow: hidden; text-overflow: ellipsis;"
|
||||||
|
>
|
||||||
|
${entity.name || entity.original_name}
|
||||||
|
</div>`
|
||||||
|
)}
|
||||||
|
<div>And ${entities.length - 2} more...</div>`
|
||||||
|
: entities.map(
|
||||||
|
(entity) =>
|
||||||
|
html`<div
|
||||||
|
style="overflow: hidden; text-overflow: ellipsis;"
|
||||||
|
>
|
||||||
|
${entity.name || entity.original_name}
|
||||||
|
</div>`
|
||||||
|
)
|
||||||
|
: "This endpoint has no associated entities"}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
public clearSelection() {
|
||||||
|
this._dataTable.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<ha-data-table
|
||||||
|
.columns=${this._columns(this.narrow)}
|
||||||
|
.data=${this._deviceEndpoints(this.deviceEndpoints)}
|
||||||
|
.selectable=${this.selectable}
|
||||||
|
auto-height
|
||||||
|
></ha-data-table>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _handleClicked(ev: CustomEvent) {
|
||||||
|
const rowId = ((ev.target as HTMLElement).closest(
|
||||||
|
".mdc-data-table__row"
|
||||||
|
) as any).rowId;
|
||||||
|
const ieee = rowId.substring(0, rowId.indexOf("_"));
|
||||||
|
showZHADeviceInfoDialog(this, { ieee });
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
css`
|
||||||
|
.table-cell-text {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zha-device-endpoint-data-table": ZHADeviceEndpointDataTable;
|
||||||
|
}
|
||||||
|
}
|
@ -1,124 +0,0 @@
|
|||||||
import {
|
|
||||||
customElement,
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
property,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import "../../../components/data-table/ha-data-table";
|
|
||||||
import type {
|
|
||||||
DataTableColumnContainer,
|
|
||||||
HaDataTable,
|
|
||||||
} from "../../../components/data-table/ha-data-table";
|
|
||||||
import "../../../components/entity/ha-state-icon";
|
|
||||||
import type { ZHADevice } from "../../../data/zha";
|
|
||||||
import { showZHADeviceInfoDialog } from "../../../dialogs/zha-device-info-dialog/show-dialog-zha-device-info";
|
|
||||||
import type { HomeAssistant } from "../../../types";
|
|
||||||
|
|
||||||
export interface DeviceRowData extends ZHADevice {
|
|
||||||
device?: DeviceRowData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("zha-devices-data-table")
|
|
||||||
export class ZHADevicesDataTable extends LitElement {
|
|
||||||
@property() public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@property() public narrow = false;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public selectable = false;
|
|
||||||
|
|
||||||
@property() public devices: ZHADevice[] = [];
|
|
||||||
|
|
||||||
@query("ha-data-table") private _dataTable!: HaDataTable;
|
|
||||||
|
|
||||||
private _devices = memoizeOne((devices: ZHADevice[]) => {
|
|
||||||
let outputDevices: DeviceRowData[] = devices;
|
|
||||||
|
|
||||||
outputDevices = outputDevices.map((device) => {
|
|
||||||
return {
|
|
||||||
...device,
|
|
||||||
name: device.user_given_name || device.name,
|
|
||||||
model: device.model,
|
|
||||||
manufacturer: device.manufacturer,
|
|
||||||
id: device.ieee,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return outputDevices;
|
|
||||||
});
|
|
||||||
|
|
||||||
private _columns = memoizeOne(
|
|
||||||
(narrow: boolean): DataTableColumnContainer =>
|
|
||||||
narrow
|
|
||||||
? {
|
|
||||||
name: {
|
|
||||||
title: "Devices",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
direction: "asc",
|
|
||||||
grows: true,
|
|
||||||
template: (name) => html`
|
|
||||||
<div @click=${this._handleClicked} style="cursor: pointer;">
|
|
||||||
${name}
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
name: {
|
|
||||||
title: "Name",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
direction: "asc",
|
|
||||||
grows: true,
|
|
||||||
template: (name) => html`
|
|
||||||
<div @click=${this._handleClicked} style="cursor: pointer;">
|
|
||||||
${name}
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
manufacturer: {
|
|
||||||
title: "Manufacturer",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
width: "20%",
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
title: "Model",
|
|
||||||
sortable: true,
|
|
||||||
filterable: true,
|
|
||||||
width: "20%",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
public clearSelection() {
|
|
||||||
this._dataTable.clearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-data-table
|
|
||||||
.columns=${this._columns(this.narrow)}
|
|
||||||
.data=${this._devices(this.devices)}
|
|
||||||
.selectable=${this.selectable}
|
|
||||||
auto-height
|
|
||||||
></ha-data-table>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _handleClicked(ev: CustomEvent) {
|
|
||||||
const ieee = ((ev.target as HTMLElement).closest(
|
|
||||||
".mdc-data-table__row"
|
|
||||||
) as any).rowId;
|
|
||||||
showZHADeviceInfoDialog(this, { ieee });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"zha-devices-data-table": ZHADevicesDataTable;
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,8 +9,8 @@ import {
|
|||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
|
query,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
import { SelectionChangedEvent } from "../../../components/data-table/ha-data-table";
|
||||||
@ -20,8 +20,8 @@ import {
|
|||||||
fetchGroupableDevices,
|
fetchGroupableDevices,
|
||||||
removeGroups,
|
removeGroups,
|
||||||
removeMembersFromGroup,
|
removeMembersFromGroup,
|
||||||
ZHADevice,
|
|
||||||
ZHAGroup,
|
ZHAGroup,
|
||||||
|
ZHADeviceEndpoint,
|
||||||
} from "../../../data/zha";
|
} from "../../../data/zha";
|
||||||
import "../../../layouts/hass-error-screen";
|
import "../../../layouts/hass-error-screen";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
@ -29,37 +29,40 @@ import { HomeAssistant } from "../../../types";
|
|||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import { formatAsPaddedHex } from "./functions";
|
import { formatAsPaddedHex } from "./functions";
|
||||||
import "./zha-device-card";
|
import "./zha-device-card";
|
||||||
import "./zha-devices-data-table";
|
import "./zha-device-endpoint-data-table";
|
||||||
|
import type { ZHADeviceEndpointDataTable } from "./zha-device-endpoint-data-table";
|
||||||
|
|
||||||
@customElement("zha-group-page")
|
@customElement("zha-group-page")
|
||||||
export class ZHAGroupPage extends LitElement {
|
export class ZHAGroupPage extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property({ type: Object }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public group?: ZHAGroup;
|
@property({ type: Object }) public group?: ZHAGroup;
|
||||||
|
|
||||||
@property() public groupId!: number;
|
@property({ type: Number }) public groupId!: number;
|
||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property() public isWide!: boolean;
|
@property({ type: Boolean }) public isWide!: boolean;
|
||||||
|
|
||||||
@property() public devices: ZHADevice[] = [];
|
@property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
@property() private _processingAdd = false;
|
@property() private _processingAdd = false;
|
||||||
|
|
||||||
@property() private _processingRemove = false;
|
@property() private _processingRemove = false;
|
||||||
|
|
||||||
@property() private _filteredDevices: ZHADevice[] = [];
|
@property() private _filteredDeviceEndpoints: ZHADeviceEndpoint[] = [];
|
||||||
|
|
||||||
@property() private _selectedDevicesToAdd: string[] = [];
|
@property() private _selectedDevicesToAdd: string[] = [];
|
||||||
|
|
||||||
@property() private _selectedDevicesToRemove: string[] = [];
|
@property() private _selectedDevicesToRemove: string[] = [];
|
||||||
|
|
||||||
private _firstUpdatedCalled = false;
|
@query("#addMembers")
|
||||||
|
private _zhaAddMembersDataTable!: ZHADeviceEndpointDataTable;
|
||||||
|
|
||||||
private _members = memoizeOne(
|
@query("#removeMembers")
|
||||||
(group: ZHAGroup): ZHADevice[] => group.members
|
private _zhaRemoveMembersDataTable!: ZHADeviceEndpointDataTable;
|
||||||
);
|
|
||||||
|
private _firstUpdatedCalled = false;
|
||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
@ -74,8 +77,8 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
this._processingRemove = false;
|
this._processingRemove = false;
|
||||||
this._selectedDevicesToRemove = [];
|
this._selectedDevicesToRemove = [];
|
||||||
this._selectedDevicesToAdd = [];
|
this._selectedDevicesToAdd = [];
|
||||||
this.devices = [];
|
this.deviceEndpoints = [];
|
||||||
this._filteredDevices = [];
|
this._filteredDeviceEndpoints = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||||
@ -97,8 +100,6 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const members = this._members(this.group);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage .header=${this.group.name}>
|
<hass-subpage .header=${this.group.name}>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
@ -122,13 +123,13 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
${this.hass.localize("ui.panel.config.zha.groups.members")}
|
${this.hass.localize("ui.panel.config.zha.groups.members")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${members.length
|
${this.group.members.length
|
||||||
? members.map(
|
? this.group.members.map(
|
||||||
(member) => html`
|
(member) => html`
|
||||||
<zha-device-card
|
<zha-device-card
|
||||||
class="card"
|
class="card"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.device=${member}
|
.device=${member.device}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.showActions=${false}
|
.showActions=${false}
|
||||||
.showEditableInfo=${false}
|
.showEditableInfo=${false}
|
||||||
@ -140,7 +141,7 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
This group has no members
|
This group has no members
|
||||||
</p>
|
</p>
|
||||||
`}
|
`}
|
||||||
${members.length
|
${this.group.members.length
|
||||||
? html`
|
? html`
|
||||||
<div class="header">
|
<div class="header">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -148,14 +149,15 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<zha-devices-data-table
|
<zha-device-endpoint-data-table
|
||||||
|
id="removeMembers"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.devices=${members}
|
.deviceEndpoints=${this.group.members}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
selectable
|
selectable
|
||||||
@selection-changed=${this._handleRemoveSelectionChanged}
|
@selection-changed=${this._handleRemoveSelectionChanged}
|
||||||
>
|
>
|
||||||
</zha-devices-data-table>
|
</zha-device-endpoint-data-table>
|
||||||
|
|
||||||
<div class="paper-dialog-buttons">
|
<div class="paper-dialog-buttons">
|
||||||
<mwc-button
|
<mwc-button
|
||||||
@ -182,14 +184,15 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
${this.hass.localize("ui.panel.config.zha.groups.add_members")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<zha-devices-data-table
|
<zha-device-endpoint-data-table
|
||||||
|
id="addMembers"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.devices=${this._filteredDevices}
|
.deviceEndpoints=${this._filteredDeviceEndpoints}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
selectable
|
selectable
|
||||||
@selection-changed=${this._handleAddSelectionChanged}
|
@selection-changed=${this._handleAddSelectionChanged}
|
||||||
>
|
>
|
||||||
</zha-devices-data-table>
|
</zha-device-endpoint-data-table>
|
||||||
|
|
||||||
<div class="paper-dialog-buttons">
|
<div class="paper-dialog-buttons">
|
||||||
<mwc-button
|
<mwc-button
|
||||||
@ -218,16 +221,22 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
if (this.groupId !== null && this.groupId !== undefined) {
|
if (this.groupId !== null && this.groupId !== undefined) {
|
||||||
this.group = await fetchGroup(this.hass!, this.groupId);
|
this.group = await fetchGroup(this.hass!, this.groupId);
|
||||||
}
|
}
|
||||||
this.devices = await fetchGroupableDevices(this.hass!);
|
this.deviceEndpoints = await fetchGroupableDevices(this.hass!);
|
||||||
// filter the groupable devices so we only show devices that aren't already in the group
|
// filter the groupable devices so we only show devices that aren't already in the group
|
||||||
this._filterDevices();
|
this._filterDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _filterDevices() {
|
private _filterDevices() {
|
||||||
// filter the groupable devices so we only show devices that aren't already in the group
|
// filter the groupable devices so we only show devices that aren't already in the group
|
||||||
this._filteredDevices = this.devices.filter((device) => {
|
this._filteredDeviceEndpoints = this.deviceEndpoints.filter(
|
||||||
return !this.group!.members.some((member) => member.ieee === device.ieee);
|
(deviceEndpoint) => {
|
||||||
});
|
return !this.group!.members.some(
|
||||||
|
(member) =>
|
||||||
|
member.device.ieee === deviceEndpoint.device.ieee &&
|
||||||
|
member.endpoint_id === deviceEndpoint.endpoint_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleAddSelectionChanged(
|
private _handleAddSelectionChanged(
|
||||||
@ -244,25 +253,27 @@ export class ZHAGroupPage extends LitElement {
|
|||||||
|
|
||||||
private async _addMembersToGroup(): Promise<void> {
|
private async _addMembersToGroup(): Promise<void> {
|
||||||
this._processingAdd = true;
|
this._processingAdd = true;
|
||||||
this.group = await addMembersToGroup(
|
const members = this._selectedDevicesToAdd.map((member) => {
|
||||||
this.hass,
|
const memberParts = member.split("_");
|
||||||
this.groupId,
|
return { ieee: memberParts[0], endpoint_id: memberParts[1] };
|
||||||
this._selectedDevicesToAdd
|
});
|
||||||
);
|
this.group = await addMembersToGroup(this.hass, this.groupId, members);
|
||||||
this._filterDevices();
|
this._filterDevices();
|
||||||
this._selectedDevicesToAdd = [];
|
this._selectedDevicesToAdd = [];
|
||||||
|
this._zhaAddMembersDataTable.clearSelection();
|
||||||
this._processingAdd = false;
|
this._processingAdd = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _removeMembersFromGroup(): Promise<void> {
|
private async _removeMembersFromGroup(): Promise<void> {
|
||||||
this._processingRemove = true;
|
this._processingRemove = true;
|
||||||
this.group = await removeMembersFromGroup(
|
const members = this._selectedDevicesToRemove.map((member) => {
|
||||||
this.hass,
|
const memberParts = member.split("_");
|
||||||
this.groupId,
|
return { ieee: memberParts[0], endpoint_id: memberParts[1] };
|
||||||
this._selectedDevicesToRemove
|
});
|
||||||
);
|
this.group = await removeMembersFromGroup(this.hass, this.groupId, members);
|
||||||
this._filterDevices();
|
this._filterDevices();
|
||||||
this._selectedDevicesToRemove = [];
|
this._selectedDevicesToRemove = [];
|
||||||
|
this._zhaRemoveMembersDataTable.clearSelection();
|
||||||
this._processingRemove = false;
|
this._processingRemove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,11 @@ class IntegrationsCard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-card header="Integrations">
|
<ha-card
|
||||||
|
.header=${this.hass.localize(
|
||||||
|
"ui.panel.developer-tools.tabs.info.integrations"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<table class="card-content">
|
<table class="card-content">
|
||||||
<tbody>
|
<tbody>
|
||||||
${this._sortedIntegrations(this.hass!.config.components).map(
|
${this._sortedIntegrations(this.hass!.config.components).map(
|
||||||
@ -62,22 +66,29 @@ class IntegrationsCard extends LitElement {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
Documentation
|
${this.hass.localize(
|
||||||
|
"ui.panel.developer-tools.tabs.info.documentation"
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
${!manifest.is_built_in
|
${manifest.is_built_in || manifest.issue_tracker
|
||||||
? ""
|
? html`
|
||||||
: html`
|
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
href=${integrationIssuesUrl(domain)}
|
href=${integrationIssuesUrl(
|
||||||
|
domain,
|
||||||
|
manifest
|
||||||
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
Issues
|
${this.hass.localize(
|
||||||
|
"ui.panel.developer-tools.tabs.info.issues"
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
`}
|
`
|
||||||
|
: ""}
|
||||||
`}
|
`}
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
|
@ -84,15 +84,19 @@ class DialogSystemLogDetail extends LitElement {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>documentation</a
|
>documentation</a
|
||||||
>${!this._manifest.is_built_in
|
>${this._manifest.is_built_in ||
|
||||||
? ""
|
this._manifest.issue_tracker
|
||||||
: html`,
|
? html`,
|
||||||
<a
|
<a
|
||||||
href=${integrationIssuesUrl(integration)}
|
href=${integrationIssuesUrl(
|
||||||
|
integration,
|
||||||
|
this._manifest
|
||||||
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>issues</a
|
>issues</a
|
||||||
>`})
|
>`
|
||||||
|
: ""})
|
||||||
`}
|
`}
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
@ -231,7 +231,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
stateLabel === "triggered" ||
|
stateLabel === "triggered" ||
|
||||||
!stateLabel
|
!stateLabel
|
||||||
? ""
|
? ""
|
||||||
: stateLabel;
|
: this._stateDisplay(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _actionDisplay(state: string): string {
|
private _actionDisplay(state: string): string {
|
||||||
|
@ -10,17 +10,21 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { styleMap } from "lit-html/directives/style-map";
|
import { styleMap } from "lit-html/directives/style-map";
|
||||||
|
import "@thomasloven/round-slider";
|
||||||
|
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import { findEntities } from "../common/find-entites";
|
import { findEntities } from "../common/find-entites";
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
import "../components/hui-warning";
|
import "../components/hui-warning";
|
||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { GaugeCardConfig } from "./types";
|
import type { GaugeCardConfig } from "./types";
|
||||||
|
import { debounce } from "../../../common/util/debounce";
|
||||||
|
import { installResizeObserver } from "../common/install-resize-observer";
|
||||||
|
|
||||||
export const severityMap = {
|
export const severityMap = {
|
||||||
red: "var(--label-badge-red)",
|
red: "var(--label-badge-red)",
|
||||||
@ -63,11 +67,20 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() private _baseUnit = "50px";
|
|
||||||
|
|
||||||
@property() private _config?: GaugeCardConfig;
|
@property() private _config?: GaugeCardConfig;
|
||||||
|
|
||||||
private _updated?: boolean;
|
private _resizeObserver?: ResizeObserver;
|
||||||
|
|
||||||
|
public connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.updateComplete.then(() => this._attachObserver());
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnectedCallback(): void {
|
||||||
|
if (this._resizeObserver) {
|
||||||
|
this._resizeObserver.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public getCardSize(): number {
|
public getCardSize(): number {
|
||||||
return 2;
|
return 2;
|
||||||
@ -83,11 +96,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
this._config = { min: 0, max: 100, ...config };
|
this._config = { min: 0, max: 100, ...config };
|
||||||
}
|
}
|
||||||
|
|
||||||
public connectedCallback(): void {
|
|
||||||
super.connectedCallback();
|
|
||||||
this._setBaseUnit();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._config || !this.hass) {
|
if (!this._config || !this.hass) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -121,33 +129,32 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sliderBarColor = this._computeSeverity(state);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
@click="${this._handleClick}"
|
@click=${this._handleClick}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
"--base-unit": this._baseUnit,
|
"--round-slider-bar-color": sliderBarColor,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div class="container">
|
<round-slider
|
||||||
<div class="gauge-a"></div>
|
readonly
|
||||||
<div
|
arcLength="180"
|
||||||
class="gauge-c"
|
startAngle="180"
|
||||||
style=${styleMap({
|
.value=${state}
|
||||||
transform: `rotate(${this._translateTurn(state)}turn)`,
|
.min=${this._config.min}
|
||||||
"background-color": this._computeSeverity(state),
|
.max=${this._config.max}
|
||||||
})}
|
></round-slider>
|
||||||
></div>
|
|
||||||
<div class="gauge-b"></div>
|
|
||||||
</div>
|
|
||||||
<div class="gauge-data">
|
<div class="gauge-data">
|
||||||
<div id="percent">
|
<div class="percent">
|
||||||
${stateObj.state}
|
${stateObj.state}
|
||||||
${this._config.unit ||
|
${this._config.unit ||
|
||||||
stateObj.attributes.unit_of_measurement ||
|
stateObj.attributes.unit_of_measurement ||
|
||||||
""}
|
""}
|
||||||
</div>
|
</div>
|
||||||
<div id="name">
|
<div class="name">
|
||||||
${this._config.name || computeStateName(stateObj)}
|
${this._config.name || computeStateName(stateObj)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -160,10 +167,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(): void {
|
protected firstUpdated(): void {
|
||||||
this._updated = true;
|
this._attachObserver();
|
||||||
this._setBaseUnit();
|
|
||||||
// eslint-disable-next-line wc/no-self-class
|
|
||||||
this.classList.add("init");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
@ -187,16 +191,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setBaseUnit(): void {
|
|
||||||
if (!this.isConnected || !this._updated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const baseUnit = this._computeBaseUnit();
|
|
||||||
if (baseUnit !== "0px") {
|
|
||||||
this._baseUnit = baseUnit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _computeSeverity(numberValue: number): string {
|
private _computeSeverity(numberValue: number): string {
|
||||||
const sections = this._config!.severity;
|
const sections = this._config!.severity;
|
||||||
|
|
||||||
@ -229,95 +223,122 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
return severityMap.normal;
|
return severityMap.normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _translateTurn(value: number): number {
|
|
||||||
const { min, max } = this._config!;
|
|
||||||
const maxTurnValue = Math.min(Math.max(value, min!), max!);
|
|
||||||
return (5 * (maxTurnValue - min!)) / (max! - min!) / 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _computeBaseUnit(): string {
|
|
||||||
return this.clientWidth < 200 ? this.clientWidth / 5 + "px" : "50px";
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleClick(): void {
|
private _handleClick(): void {
|
||||||
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
|
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _attachObserver(): Promise<void> {
|
||||||
|
await installResizeObserver();
|
||||||
|
|
||||||
|
this._resizeObserver = new ResizeObserver(
|
||||||
|
debounce(() => this._measureCard(), 250, false)
|
||||||
|
);
|
||||||
|
|
||||||
|
const card = this.shadowRoot!.querySelector("ha-card");
|
||||||
|
// If we show an error or warning there is no ha-card
|
||||||
|
if (!card) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._resizeObserver.observe(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _measureCard() {
|
||||||
|
if (this.offsetWidth < 200) {
|
||||||
|
this.setAttribute("narrow", "");
|
||||||
|
} else {
|
||||||
|
this.removeAttribute("narrow");
|
||||||
|
}
|
||||||
|
if (this.offsetWidth < 150) {
|
||||||
|
this.setAttribute("veryNarrow", "");
|
||||||
|
} else {
|
||||||
|
this.removeAttribute("veryNarrow");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
ha-card {
|
ha-card {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 16px 16px 0 16px;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 16px 16px 0 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-card:focus {
|
ha-card:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
background: var(--divider-color);
|
background: var(--divider-color);
|
||||||
}
|
}
|
||||||
.container {
|
|
||||||
width: calc(var(--base-unit) * 4);
|
round-slider {
|
||||||
height: calc(var(--base-unit) * 2);
|
max-width: 200px;
|
||||||
overflow: hidden;
|
--round-slider-path-width: 35px;
|
||||||
position: relative;
|
--round-slider-path-color: var(--disabled-text-color);
|
||||||
}
|
--round-slider-linecap: "butt";
|
||||||
.gauge-a {
|
|
||||||
position: absolute;
|
|
||||||
background-color: var(--primary-background-color);
|
|
||||||
width: calc(var(--base-unit) * 4);
|
|
||||||
height: calc(var(--base-unit) * 2);
|
|
||||||
top: 0%;
|
|
||||||
border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5)
|
|
||||||
0px 0px;
|
|
||||||
}
|
|
||||||
.gauge-b {
|
|
||||||
position: absolute;
|
|
||||||
background-color: var(--paper-card-background-color);
|
|
||||||
width: calc(var(--base-unit) * 2.5);
|
|
||||||
height: calc(var(--base-unit) * 1.25);
|
|
||||||
top: calc(var(--base-unit) * 0.75);
|
|
||||||
margin-left: calc(var(--base-unit) * 0.75);
|
|
||||||
margin-right: auto;
|
|
||||||
border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5)
|
|
||||||
0px 0px;
|
|
||||||
}
|
|
||||||
.gauge-c {
|
|
||||||
position: absolute;
|
|
||||||
background-color: var(--label-badge-blue);
|
|
||||||
width: calc(var(--base-unit) * 4);
|
|
||||||
height: calc(var(--base-unit) * 2);
|
|
||||||
top: calc(var(--base-unit) * 2);
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
border-radius: 0px 0px calc(var(--base-unit) * 2)
|
|
||||||
calc(var(--base-unit) * 2);
|
|
||||||
transform-origin: center top;
|
|
||||||
}
|
|
||||||
.init .gauge-c {
|
|
||||||
transition: all 1.3s ease-in-out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gauge-data {
|
.gauge-data {
|
||||||
|
line-height: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--primary-text-color);
|
|
||||||
line-height: calc(var(--base-unit) * 0.3);
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
top: calc(var(--base-unit) * -0.5);
|
color: var(--primary-text-color);
|
||||||
|
margin-top: -28px;
|
||||||
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
.init .gauge-data {
|
|
||||||
transition: all 1s ease-out;
|
.gauge-data .percent {
|
||||||
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
.gauge-data #percent {
|
|
||||||
font-size: calc(var(--base-unit) * 0.55);
|
.gauge-data .name {
|
||||||
line-height: calc(var(--base-unit) * 0.55);
|
padding-top: 6px;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.gauge-data #name {
|
|
||||||
padding-top: calc(var(--base-unit) * 0.15);
|
/* ============= NARROW ============= */
|
||||||
font-size: calc(var(--base-unit) * 0.3);
|
|
||||||
|
:host([narrow]) round-slider {
|
||||||
|
--round-slider-path-width: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([narrow]) .gauge-data {
|
||||||
|
margin-top: -24px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([narrow]) .gauge-data .percent {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([narrow]) .gauge-data .name {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= VERY NARROW ============= */
|
||||||
|
|
||||||
|
:host([veryNarrow]) round-slider {
|
||||||
|
--round-slider-path-width: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([veryNarrow]) ha-card {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([veryNarrow]) .gauge-data {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([veryNarrow]) .gauge-data .percent {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([veryNarrow]) .gauge-data .name {
|
||||||
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import "../components/hui-marquee";
|
|||||||
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import "../components/hui-warning";
|
import "../components/hui-warning";
|
||||||
import { MediaControlCardConfig } from "./types";
|
import { MediaControlCardConfig } from "./types";
|
||||||
|
import { installResizeObserver } from "../common/install-resize-observer";
|
||||||
|
|
||||||
function getContrastRatio(
|
function getContrastRatio(
|
||||||
rgb1: [number, number, number],
|
rgb1: [number, number, number],
|
||||||
@ -223,7 +224,7 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this.updateComplete.then(() => this._measureCard());
|
this.updateComplete.then(() => this._attachObserver());
|
||||||
|
|
||||||
if (!this.hass || !this._config) {
|
if (!this.hass || !this._config) {
|
||||||
return;
|
return;
|
||||||
@ -252,6 +253,9 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
|||||||
clearInterval(this._progressInterval);
|
clearInterval(this._progressInterval);
|
||||||
this._progressInterval = undefined;
|
this._progressInterval = undefined;
|
||||||
}
|
}
|
||||||
|
if (this._resizeObserver) {
|
||||||
|
this._resizeObserver.disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@ -624,15 +628,8 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
|||||||
this._cardHeight = card.offsetHeight;
|
this._cardHeight = card.offsetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _attachObserver(): void {
|
private async _attachObserver(): Promise<void> {
|
||||||
if (typeof ResizeObserver !== "function") {
|
await installResizeObserver();
|
||||||
import("resize-observer").then((modules) => {
|
|
||||||
modules.install();
|
|
||||||
this._attachObserver();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._resizeObserver = new ResizeObserver(
|
this._resizeObserver = new ResizeObserver(
|
||||||
debounce(() => this._measureCard(), 250, false)
|
debounce(() => this._measureCard(), 250, false)
|
||||||
);
|
);
|
||||||
|
@ -21,16 +21,17 @@ import { UNAVAILABLE } from "../../../data/entity";
|
|||||||
import {
|
import {
|
||||||
getSecondaryWeatherAttribute,
|
getSecondaryWeatherAttribute,
|
||||||
getWeatherUnit,
|
getWeatherUnit,
|
||||||
weatherIcons,
|
getWeatherStateIcon,
|
||||||
weatherImages,
|
weatherSVGStyles,
|
||||||
} from "../../../data/weather";
|
} from "../../../data/weather";
|
||||||
import { HomeAssistant, WeatherEntity } from "../../../types";
|
import type { HomeAssistant, WeatherEntity } from "../../../types";
|
||||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||||
import { findEntities } from "../common/find-entites";
|
import { findEntities } from "../common/find-entites";
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
import "../components/hui-warning";
|
import "../components/hui-warning";
|
||||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { WeatherForecastCardConfig } from "./types";
|
import type { WeatherForecastCardConfig } from "./types";
|
||||||
|
import { installResizeObserver } from "../common/install-resize-observer";
|
||||||
|
|
||||||
const DAY_IN_MILLISECONDS = 86400000;
|
const DAY_IN_MILLISECONDS = 86400000;
|
||||||
|
|
||||||
@ -72,7 +73,13 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this.updateComplete.then(() => this._measureCard());
|
this.updateComplete.then(() => this._attachObserver());
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnectedCallback(): void {
|
||||||
|
if (this._resizeObserver) {
|
||||||
|
this._resizeObserver.disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCardSize(): number {
|
public getCardSize(): number {
|
||||||
@ -158,6 +165,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
hourly = timeDiff < DAY_IN_MILLISECONDS;
|
hourly = timeDiff < DAY_IN_MILLISECONDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const weatherStateIcon = getWeatherStateIcon(stateObj.state, this);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
@action=${this._handleAction}
|
@action=${this._handleAction}
|
||||||
@ -166,25 +175,16 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
>
|
>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="icon-image">
|
<div class="icon-image">
|
||||||
${stateObj.state in weatherImages
|
${weatherStateIcon ||
|
||||||
? html`
|
html`
|
||||||
<img
|
<ha-icon
|
||||||
class="weather-image"
|
class="weather-icon"
|
||||||
src="${weatherImages[stateObj.state]}"
|
.icon=${stateIcon(stateObj)}
|
||||||
/>
|
></ha-icon>
|
||||||
`
|
`}
|
||||||
: html`
|
|
||||||
<ha-icon
|
|
||||||
class="weather-icon"
|
|
||||||
.icon=${weatherIcons[stateObj.state] || stateIcon(stateObj)}
|
|
||||||
></ha-icon>
|
|
||||||
`}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="name-state">
|
<div class="name-state">
|
||||||
<div class="name">
|
|
||||||
${this._config.name || computeStateName(stateObj)}
|
|
||||||
</div>
|
|
||||||
<div class="state">
|
<div class="state">
|
||||||
${computeStateDisplay(
|
${computeStateDisplay(
|
||||||
this.hass.localize,
|
this.hass.localize,
|
||||||
@ -192,6 +192,9 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
this.hass.language
|
this.hass.language
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="name">
|
||||||
|
${this._config.name || computeStateName(stateObj)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="temp-attribute">
|
<div class="temp-attribute">
|
||||||
<div class="temp">
|
<div class="temp">
|
||||||
@ -200,7 +203,20 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="attribute">
|
<div class="attribute">
|
||||||
${getSecondaryWeatherAttribute(this.hass, stateObj)}
|
${this._config.secondary_info_attribute !== undefined
|
||||||
|
? html`
|
||||||
|
${this.hass!.localize(
|
||||||
|
`ui.card.weather.attributes.${this._config.secondary_info_attribute}`
|
||||||
|
)}
|
||||||
|
${stateObj.attributes[
|
||||||
|
this._config.secondary_info_attribute
|
||||||
|
]}
|
||||||
|
${getWeatherUnit(
|
||||||
|
this.hass,
|
||||||
|
this._config.secondary_info_attribute
|
||||||
|
)}
|
||||||
|
`
|
||||||
|
: getSecondaryWeatherAttribute(this.hass, stateObj)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -231,21 +247,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
${item.condition !== undefined && item.condition !== null
|
${item.condition !== undefined && item.condition !== null
|
||||||
? html`
|
? html`
|
||||||
<div class="forecast-image-icon">
|
<div class="forecast-image-icon">
|
||||||
${item.condition in weatherImages
|
${getWeatherStateIcon(item.condition, this)}
|
||||||
? html`
|
|
||||||
<img
|
|
||||||
class="forecast-image"
|
|
||||||
src="${weatherImages[item.condition]}"
|
|
||||||
/>
|
|
||||||
`
|
|
||||||
: item.condition in weatherIcons
|
|
||||||
? html`
|
|
||||||
<ha-icon
|
|
||||||
class="forecast-icon"
|
|
||||||
.icon=${weatherIcons[item.condition]}
|
|
||||||
></ha-icon>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@ -286,15 +288,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
|
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _attachObserver(): void {
|
private async _attachObserver(): Promise<void> {
|
||||||
if (typeof ResizeObserver !== "function") {
|
await installResizeObserver();
|
||||||
import("resize-observer").then((modules) => {
|
|
||||||
modules.install();
|
|
||||||
this._attachObserver();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._resizeObserver = new ResizeObserver(
|
this._resizeObserver = new ResizeObserver(
|
||||||
debounce(() => this._measureCard(), 250, false)
|
debounce(() => this._measureCard(), 250, false)
|
||||||
);
|
);
|
||||||
@ -321,201 +316,205 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult[] {
|
||||||
return css`
|
return [
|
||||||
:host {
|
weatherSVGStyles,
|
||||||
display: block;
|
css`
|
||||||
}
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
ha-card {
|
ha-card {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-image {
|
.icon-image {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 64px;
|
min-width: 64px;
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.weather-image,
|
.icon-image > * {
|
||||||
.weather-icon {
|
flex: 0 0 64px;
|
||||||
flex: 0 0 64px;
|
height: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.weather-icon {
|
.weather-icon {
|
||||||
--mdc-icon-size: 64px;
|
--mdc-icon-size: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.temp-attribute {
|
.temp-attribute {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.temp-attribute .temp {
|
.temp-attribute .temp {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-right: 24px;
|
margin-right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.temp-attribute .temp span {
|
.temp-attribute .temp span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
top: 1px;
|
top: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name,
|
.state,
|
||||||
.temp-attribute .temp {
|
.temp-attribute .temp {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.state,
|
.name,
|
||||||
.attribute {
|
.attribute {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name-state {
|
.name-state {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name,
|
.name,
|
||||||
.state {
|
.state {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attribute {
|
.attribute {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.forecast {
|
.forecast {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.forecast > div {
|
.forecast > div {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.forecast .icon,
|
.forecast .icon,
|
||||||
.forecast .temp {
|
.forecast .temp {
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.forecast .temp {
|
.forecast .temp {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.forecast-image-icon {
|
.forecast-image-icon {
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
}
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.forecast-image {
|
.forecast-image-icon > * {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.forecast-icon {
|
.forecast-icon {
|
||||||
--mdc-icon-size: 40px;
|
--mdc-icon-size: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attribute,
|
.attribute,
|
||||||
.templow,
|
.templow,
|
||||||
.state {
|
.name {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.unavailable {
|
.unavailable {
|
||||||
height: 100px;
|
height: 100px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============= NARROW ============= */
|
/* ============= NARROW ============= */
|
||||||
|
|
||||||
:host([narrow]) .icon-image {
|
:host([narrow]) .icon-image {
|
||||||
min-width: 52px;
|
min-width: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([narrow]) .weather-image {
|
:host([narrow]) .weather-image {
|
||||||
flex: 0 0 52px;
|
flex: 0 0 52px;
|
||||||
width: 52px;
|
width: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([narrow]) .weather-icon {
|
:host([narrow]) .weather-icon {
|
||||||
--mdc-icon-size: 52px;
|
--mdc-icon-size: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([narrow]) .name,
|
:host([narrow]) .state,
|
||||||
:host([narrow]) .temp-attribute .temp {
|
:host([narrow]) .temp-attribute .temp {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([narrow]) .temp-attribute .temp {
|
:host([narrow]) .temp-attribute .temp {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([narrow]) .temp span {
|
:host([narrow]) .temp span {
|
||||||
top: 1px;
|
top: 1px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============= VERY NARROW ============= */
|
/* ============= VERY NARROW ============= */
|
||||||
|
|
||||||
:host([veryNarrow]) .state,
|
:host([veryNarrow]) .name,
|
||||||
:host([veryNarrow]) .attribute {
|
:host([veryNarrow]) .attribute {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([veryNarrow]) .info {
|
:host([veryNarrow]) .info {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([veryNarrow]) .name-state {
|
:host([veryNarrow]) .name-state {
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============= VERY VERY NARROW ============= */
|
/* ============= VERY VERY NARROW ============= */
|
||||||
|
|
||||||
:host([veryVeryNarrow]) .info {
|
:host([veryVeryNarrow]) .info {
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([veryVeryNarrow]) .content {
|
:host([veryVeryNarrow]) .content {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([veryVeryNarrow]) .icon-image {
|
:host([veryVeryNarrow]) .icon-image {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
`;
|
`,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,8 @@ export interface EntitiesCardEntityConfig extends EntityConfig {
|
|||||||
| "last-changed"
|
| "last-changed"
|
||||||
| "last-triggered"
|
| "last-triggered"
|
||||||
| "position"
|
| "position"
|
||||||
| "tilt-position";
|
| "tilt-position"
|
||||||
|
| "brightness";
|
||||||
action_name?: string;
|
action_name?: string;
|
||||||
service?: string;
|
service?: string;
|
||||||
service_data?: object;
|
service_data?: object;
|
||||||
@ -275,4 +276,5 @@ export interface WeatherForecastCardConfig extends LovelaceCardConfig {
|
|||||||
entity: string;
|
entity: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
show_forecast?: boolean;
|
show_forecast?: boolean;
|
||||||
|
secondary_info_attribute?: string;
|
||||||
}
|
}
|
||||||
|
@ -465,7 +465,8 @@ export const generateLovelaceConfigFromData = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const generateLovelaceConfigFromHass = async (
|
export const generateLovelaceConfigFromHass = async (
|
||||||
hass: HomeAssistant
|
hass: HomeAssistant,
|
||||||
|
localize?: LocalizeFunc
|
||||||
): Promise<LovelaceConfig> => {
|
): Promise<LovelaceConfig> => {
|
||||||
// We want to keep the registry subscriptions alive after generating the UI
|
// We want to keep the registry subscriptions alive after generating the UI
|
||||||
// so that we don't serve up stale data after changing areas.
|
// so that we don't serve up stale data after changing areas.
|
||||||
@ -488,6 +489,6 @@ export const generateLovelaceConfigFromHass = async (
|
|||||||
deviceEntries,
|
deviceEntries,
|
||||||
entityEntries,
|
entityEntries,
|
||||||
hass.states,
|
hass.states,
|
||||||
hass.localize
|
localize || hass.localize
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
6
src/panels/lovelace/common/install-resize-observer.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export const installResizeObserver = async () => {
|
||||||
|
if (typeof ResizeObserver !== "function") {
|
||||||
|
const modules = await import("resize-observer");
|
||||||
|
modules.install();
|
||||||
|
}
|
||||||
|
};
|
@ -10,25 +10,30 @@ import {
|
|||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
queryAssignedNodes,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
|
import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog";
|
||||||
import { showMoveCardViewDialog } from "../editor/card-editor/show-move-card-view-dialog";
|
import { showMoveCardViewDialog } from "../editor/card-editor/show-move-card-view-dialog";
|
||||||
import { swapCard } from "../editor/config-util";
|
import { swapCard } from "../editor/config-util";
|
||||||
import { confDeleteCard } from "../editor/delete-card";
|
import { confDeleteCard } from "../editor/delete-card";
|
||||||
import { Lovelace } from "../types";
|
import { Lovelace, LovelaceCard } from "../types";
|
||||||
|
import { computeCardSize } from "../common/compute-card-size";
|
||||||
|
|
||||||
@customElement("hui-card-options")
|
@customElement("hui-card-options")
|
||||||
export class HuiCardOptions extends LitElement {
|
export class HuiCardOptions extends LitElement {
|
||||||
public cardConfig?: LovelaceCardConfig;
|
|
||||||
|
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property() public lovelace?: Lovelace;
|
@property() public lovelace?: Lovelace;
|
||||||
|
|
||||||
@property() public path?: [number, number];
|
@property() public path?: [number, number];
|
||||||
|
|
||||||
|
@queryAssignedNodes() private _assignedNodes?: NodeListOf<LovelaceCard>;
|
||||||
|
|
||||||
|
public getCardSize() {
|
||||||
|
return this._assignedNodes ? computeCardSize(this._assignedNodes[0]) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -122,6 +122,11 @@ class HuiGenericEntityRow extends LitElement {
|
|||||||
? `${this.hass.localize("ui.card.cover.tilt_position")}: ${
|
? `${this.hass.localize("ui.card.cover.tilt_position")}: ${
|
||||||
stateObj.attributes.current_tilt_position
|
stateObj.attributes.current_tilt_position
|
||||||
}`
|
}`
|
||||||
|
: this.config.secondary_info === "brightness" &&
|
||||||
|
stateObj.attributes.brightness
|
||||||
|
? html`${Math.round(
|
||||||
|
(stateObj.attributes.brightness / 255) * 100
|
||||||
|
)}%`
|
||||||
: "")}
|
: "")}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@ -22,6 +22,7 @@ const cardConfigStruct = struct({
|
|||||||
name: "string?",
|
name: "string?",
|
||||||
theme: "string?",
|
theme: "string?",
|
||||||
show_forecast: "boolean?",
|
show_forecast: "boolean?",
|
||||||
|
secondary_info_attribute: "string?",
|
||||||
});
|
});
|
||||||
|
|
||||||
const includeDomains = ["weather"];
|
const includeDomains = ["weather"];
|
||||||
@ -54,6 +55,10 @@ export class HuiWeatherForecastCardEditor extends LitElement
|
|||||||
return this._config!.show_forecast || true;
|
return this._config!.show_forecast || true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _secondary_info_attribute(): string {
|
||||||
|
return this._config!.secondary_info_attribute || "";
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.hass || !this._config) {
|
if (!this.hass || !this._config) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -93,12 +98,26 @@ export class HuiWeatherForecastCardEditor extends LitElement
|
|||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
></hui-theme-select-editor>
|
></hui-theme-select-editor>
|
||||||
</div>
|
</div>
|
||||||
<ha-switch
|
<div class="side-by-side">
|
||||||
.checked=${this._config!.show_forecast !== false}
|
<paper-input
|
||||||
.configValue=${"show_forecast"}
|
.label="${this.hass.localize(
|
||||||
@change=${this._valueChanged}
|
"ui.panel.lovelace.editor.card.generic.secondary_info_attribute"
|
||||||
>Show forecast</ha-switch
|
)} (${this.hass.localize(
|
||||||
>
|
"ui.panel.lovelace.editor.card.config.optional"
|
||||||
|
)})"
|
||||||
|
.value=${this._secondary_info_attribute}
|
||||||
|
.configValue=${"secondary_info_attribute"}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></paper-input>
|
||||||
|
<ha-switch
|
||||||
|
.checked=${this._config!.show_forecast !== false}
|
||||||
|
.configValue=${"show_forecast"}
|
||||||
|
@change=${this._valueChanged}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.weather.show_forecast"
|
||||||
|
)}</ha-switch
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
|
|||||||
import "../components/hui-generic-entity-row";
|
import "../components/hui-generic-entity-row";
|
||||||
import "../components/hui-warning";
|
import "../components/hui-warning";
|
||||||
import { EntityConfig, LovelaceRow } from "./types";
|
import { EntityConfig, LovelaceRow } from "./types";
|
||||||
|
import { installResizeObserver } from "../common/install-resize-observer";
|
||||||
|
|
||||||
@customElement("hui-media-player-entity-row")
|
@customElement("hui-media-player-entity-row")
|
||||||
class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
|
class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
|
||||||
@ -209,19 +210,13 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _attachObserver(): void {
|
private _attachObserver(): void {
|
||||||
if (typeof ResizeObserver !== "function") {
|
installResizeObserver().then(() => {
|
||||||
import("resize-observer").then((modules) => {
|
this._resizeObserver = new ResizeObserver(() =>
|
||||||
modules.install();
|
this._debouncedResizeListener()
|
||||||
this._attachObserver();
|
);
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._resizeObserver = new ResizeObserver(() =>
|
this._resizeObserver.observe(this);
|
||||||
this._debouncedResizeListener()
|
});
|
||||||
);
|
|
||||||
|
|
||||||
this._resizeObserver.observe(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeControlIcon(stateObj: HassEntity): string {
|
private _computeControlIcon(stateObj: HassEntity): string {
|
||||||
|
@ -8,21 +8,32 @@ import {
|
|||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
|
|
||||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
import "../../../components/entity/state-badge";
|
import "../../../components/entity/state-badge";
|
||||||
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
||||||
import {
|
import {
|
||||||
getSecondaryWeatherAttribute,
|
getSecondaryWeatherAttribute,
|
||||||
getWeatherUnit,
|
getWeatherUnit,
|
||||||
weatherIcons,
|
getWeatherStateIcon,
|
||||||
weatherImages,
|
weatherSVGStyles,
|
||||||
} from "../../../data/weather";
|
} from "../../../data/weather";
|
||||||
import { HomeAssistant, WeatherEntity } from "../../../types";
|
import type { HomeAssistant, WeatherEntity } from "../../../types";
|
||||||
import { EntitiesCardEntityConfig } from "../cards/types";
|
import type { EntitiesCardEntityConfig } from "../cards/types";
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
import "../components/hui-generic-entity-row";
|
import "../components/hui-generic-entity-row";
|
||||||
import "../components/hui-warning";
|
import "../components/hui-warning";
|
||||||
import { LovelaceRow } from "./types";
|
import type { LovelaceRow } from "./types";
|
||||||
|
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
|
||||||
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
|
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||||
|
import { hasAction } from "../common/has-action";
|
||||||
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
|
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||||
|
import { handleAction } from "../common/handle-action";
|
||||||
|
import { stateIcon } from "../../../common/entity/state_icon";
|
||||||
|
|
||||||
@customElement("hui-weather-entity-row")
|
@customElement("hui-weather-entity-row")
|
||||||
class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
||||||
@ -61,48 +72,126 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const weatherRowConfig = {
|
const pointer =
|
||||||
...this._config,
|
(this._config.tap_action && this._config.tap_action.action !== "none") ||
|
||||||
icon: weatherIcons[stateObj.state],
|
(this._config.entity &&
|
||||||
image: weatherImages[stateObj.state],
|
!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(this._config.entity)));
|
||||||
};
|
|
||||||
|
const weatherStateIcon = getWeatherStateIcon(stateObj.state, this);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hui-generic-entity-row .hass=${this.hass} .config=${weatherRowConfig}>
|
<div
|
||||||
<div class="attributes">
|
class="icon-image${classMap({
|
||||||
<div>
|
pointer,
|
||||||
${UNAVAILABLE_STATES.includes(stateObj.state)
|
})}"
|
||||||
? computeStateDisplay(
|
@action=${this._handleAction}
|
||||||
this.hass.localize,
|
.actionHandler=${actionHandler({
|
||||||
stateObj,
|
hasHold: hasAction(this._config!.hold_action),
|
||||||
this.hass.language
|
hasDoubleClick: hasAction(this._config!.double_tap_action),
|
||||||
)
|
})}
|
||||||
: html`
|
tabindex=${ifDefined(pointer ? "0" : undefined)}
|
||||||
${stateObj.attributes.temperature}
|
>
|
||||||
${getWeatherUnit(this.hass, "temperature")}
|
${weatherStateIcon ||
|
||||||
`}
|
html`
|
||||||
</div>
|
<ha-icon class="weather-icon" .icon=${stateIcon(stateObj)}></ha-icon>
|
||||||
<div class="secondary">
|
`}
|
||||||
${getSecondaryWeatherAttribute(this.hass!, stateObj)}
|
</div>
|
||||||
</div>
|
<div
|
||||||
|
class="info ${classMap({
|
||||||
|
pointer,
|
||||||
|
})}"
|
||||||
|
@action=${this._handleAction}
|
||||||
|
.actionHandler=${actionHandler({
|
||||||
|
hasHold: hasAction(this._config!.hold_action),
|
||||||
|
hasDoubleClick: hasAction(this._config!.double_tap_action),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
${this._config.name || computeStateName(stateObj)}
|
||||||
|
</div>
|
||||||
|
<div class="attributes">
|
||||||
|
<div>
|
||||||
|
${UNAVAILABLE_STATES.includes(stateObj.state)
|
||||||
|
? computeStateDisplay(
|
||||||
|
this.hass.localize,
|
||||||
|
stateObj,
|
||||||
|
this.hass.language
|
||||||
|
)
|
||||||
|
: html`
|
||||||
|
${stateObj.attributes.temperature}
|
||||||
|
${getWeatherUnit(this.hass, "temperature")}
|
||||||
|
`}
|
||||||
</div>
|
</div>
|
||||||
</hui-generic-entity-row>
|
<div class="secondary">
|
||||||
|
${getSecondaryWeatherAttribute(this.hass!, stateObj)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
private _handleAction(ev: ActionHandlerEvent) {
|
||||||
return css`
|
handleAction(this, this.hass!, this._config!, ev.detail.action!);
|
||||||
.attributes {
|
}
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
static get styles(): CSSResult[] {
|
||||||
color: var(--secondary-text-color);
|
return [
|
||||||
}
|
weatherSVGStyles,
|
||||||
`;
|
css`
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-left: 16px;
|
||||||
|
flex: 1 0 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info,
|
||||||
|
.info > * {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-image {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-image > * {
|
||||||
|
flex: 0 0 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather-icon {
|
||||||
|
--iron-icon-width: 40px;
|
||||||
|
--iron-icon-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([rtl]) .flex {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attributes {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: right;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +288,8 @@ class LovelacePanel extends LitElement {
|
|||||||
this._errorMsg = err.message;
|
this._errorMsg = err.message;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
conf = await generateLovelaceConfigFromHass(this.hass!);
|
const localize = await this.hass!.loadBackendTranslation("title");
|
||||||
|
conf = await generateLovelaceConfigFromHass(this.hass!, localize);
|
||||||
confMode = "generated";
|
confMode = "generated";
|
||||||
} finally {
|
} finally {
|
||||||
// Ignore updates for another 2 seconds.
|
// Ignore updates for another 2 seconds.
|
||||||
@ -370,8 +371,9 @@ class LovelacePanel extends LitElement {
|
|||||||
const { config: previousConfig, mode: previousMode } = this.lovelace!;
|
const { config: previousConfig, mode: previousMode } = this.lovelace!;
|
||||||
try {
|
try {
|
||||||
// Optimistic update
|
// Optimistic update
|
||||||
|
const localize = await this.hass!.loadBackendTranslation("title");
|
||||||
this._updateLovelace({
|
this._updateLovelace({
|
||||||
config: await generateLovelaceConfigFromHass(this.hass!),
|
config: await generateLovelaceConfigFromHass(this.hass!, localize),
|
||||||
mode: "generated",
|
mode: "generated",
|
||||||
editMode: false,
|
editMode: false,
|
||||||
});
|
});
|
||||||
|
@ -369,100 +369,6 @@ class HUIRoot extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
css`
|
|
||||||
:host {
|
|
||||||
--dark-color: #455a64;
|
|
||||||
--text-dark-color: #fff;
|
|
||||||
-ms-user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-app-layout {
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
paper-menu-button {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
paper-tabs {
|
|
||||||
margin-left: 12px;
|
|
||||||
--paper-tabs-selection-bar-color: var(--text-primary-color, #fff);
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
.edit-mode {
|
|
||||||
background-color: var(--dark-color, #455a64);
|
|
||||||
color: var(--text-dark-color);
|
|
||||||
}
|
|
||||||
.edit-mode div[main-title] {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
paper-tab.iron-selected .edit-icon {
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
.edit-icon {
|
|
||||||
color: var(--accent-color);
|
|
||||||
padding-left: 8px;
|
|
||||||
vertical-align: middle;
|
|
||||||
--mdc-theme-text-disabled-on-light: var(--disabled-text-color);
|
|
||||||
}
|
|
||||||
.edit-icon.view {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#add-view {
|
|
||||||
position: absolute;
|
|
||||||
height: 44px;
|
|
||||||
}
|
|
||||||
#add-view ha-icon {
|
|
||||||
background-color: var(--accent-color);
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
app-toolbar a {
|
|
||||||
color: var(--text-primary-color, white);
|
|
||||||
}
|
|
||||||
mwc-button.warning:not([disabled]) {
|
|
||||||
color: var(--google-red-500);
|
|
||||||
}
|
|
||||||
#view {
|
|
||||||
min-height: calc(100vh - 112px);
|
|
||||||
/**
|
|
||||||
* Since we only set min-height, if child nodes need percentage
|
|
||||||
* heights they must use absolute positioning so we need relative
|
|
||||||
* positioning here.
|
|
||||||
*
|
|
||||||
* https://www.w3.org/TR/CSS2/visudet.html#the-height-property
|
|
||||||
*/
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
#view > * {
|
|
||||||
/**
|
|
||||||
* The view could get larger than the window in Firefox
|
|
||||||
* to prevent that we set the max-width to 100%
|
|
||||||
* flex-grow: 1 and flex-basis: 100% should make sure the view
|
|
||||||
* stays full width.
|
|
||||||
*
|
|
||||||
* https://github.com/home-assistant/home-assistant-polymer/pull/3806
|
|
||||||
*/
|
|
||||||
flex: 1 1 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
#view.tabs-hidden {
|
|
||||||
min-height: calc(100vh - 64px);
|
|
||||||
}
|
|
||||||
paper-item {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.hide-tab {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
super.updated(changedProperties);
|
super.updated(changedProperties);
|
||||||
|
|
||||||
@ -527,8 +433,10 @@ class HUIRoot extends LitElement {
|
|||||||
navigate(this, `${this.route?.prefix}/${views[0]?.path || 0}`);
|
navigate(this, `${this.route?.prefix}/${views[0]?.path || 0}`);
|
||||||
newSelectView = 0;
|
newSelectView = 0;
|
||||||
}
|
}
|
||||||
// On edit mode change, recreate the current view from scratch
|
}
|
||||||
force = true;
|
|
||||||
|
if (!force) {
|
||||||
|
huiView.lovelace = this.lovelace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,6 +642,100 @@ class HUIRoot extends LitElement {
|
|||||||
// Recalculate to see if we need to adjust content area for tab bar
|
// Recalculate to see if we need to adjust content area for tab bar
|
||||||
fireEvent(this, "iron-resize");
|
fireEvent(this, "iron-resize");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
--dark-color: #455a64;
|
||||||
|
--text-dark-color: #fff;
|
||||||
|
-ms-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-app-layout {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
paper-menu-button {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
paper-tabs {
|
||||||
|
margin-left: 12px;
|
||||||
|
--paper-tabs-selection-bar-color: var(--text-primary-color, #fff);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.edit-mode {
|
||||||
|
background-color: var(--dark-color, #455a64);
|
||||||
|
color: var(--text-dark-color);
|
||||||
|
}
|
||||||
|
.edit-mode div[main-title] {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
paper-tab.iron-selected .edit-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
.edit-icon {
|
||||||
|
color: var(--accent-color);
|
||||||
|
padding-left: 8px;
|
||||||
|
vertical-align: middle;
|
||||||
|
--mdc-theme-text-disabled-on-light: var(--disabled-text-color);
|
||||||
|
}
|
||||||
|
.edit-icon.view {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#add-view {
|
||||||
|
position: absolute;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
#add-view ha-icon {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
app-toolbar a {
|
||||||
|
color: var(--text-primary-color, white);
|
||||||
|
}
|
||||||
|
mwc-button.warning:not([disabled]) {
|
||||||
|
color: var(--google-red-500);
|
||||||
|
}
|
||||||
|
#view {
|
||||||
|
min-height: calc(100vh - 112px);
|
||||||
|
/**
|
||||||
|
* Since we only set min-height, if child nodes need percentage
|
||||||
|
* heights they must use absolute positioning so we need relative
|
||||||
|
* positioning here.
|
||||||
|
*
|
||||||
|
* https://www.w3.org/TR/CSS2/visudet.html#the-height-property
|
||||||
|
*/
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#view > * {
|
||||||
|
/**
|
||||||
|
* The view could get larger than the window in Firefox
|
||||||
|
* to prevent that we set the max-width to 100%
|
||||||
|
* flex-grow: 1 and flex-basis: 100% should make sure the view
|
||||||
|
* stays full width.
|
||||||
|
*
|
||||||
|
* https://github.com/home-assistant/home-assistant-polymer/pull/3806
|
||||||
|
*/
|
||||||
|
flex: 1 1 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
#view.tabs-hidden {
|
||||||
|
min-height: calc(100vh - 64px);
|
||||||
|
}
|
||||||
|
paper-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.hide-tab {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -34,6 +34,7 @@ export interface LovelaceCard extends HTMLElement {
|
|||||||
hass?: HomeAssistant;
|
hass?: HomeAssistant;
|
||||||
isPanel?: boolean;
|
isPanel?: boolean;
|
||||||
editMode?: boolean;
|
editMode?: boolean;
|
||||||
|
index?: number;
|
||||||
getCardSize(): number;
|
getCardSize(): number;
|
||||||
setConfig(config: LovelaceCardConfig): void;
|
setConfig(config: LovelaceCardConfig): void;
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@ import {
|
|||||||
property,
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
CSSResult,
|
||||||
|
css,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
// This one is for types
|
|
||||||
import { classMap } from "lit-html/directives/class-map";
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
@ -92,7 +93,6 @@ export class HUIView extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyles()}
|
|
||||||
<div id="badges"></div>
|
<div id="badges"></div>
|
||||||
<div id="columns"></div>
|
<div id="columns"></div>
|
||||||
${this.lovelace!.editMode
|
${this.lovelace!.editMode
|
||||||
@ -113,82 +113,6 @@ export class HUIView extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderStyles(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 4px 4px 0;
|
|
||||||
transform: translateZ(0);
|
|
||||||
position: relative;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
background: var(
|
|
||||||
--lovelace-background,
|
|
||||||
var(--primary-background-color)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#badges {
|
|
||||||
margin: 8px 16px;
|
|
||||||
font-size: 85%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#columns {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column {
|
|
||||||
flex: 1 0 0;
|
|
||||||
max-width: 500px;
|
|
||||||
min-width: 0;
|
|
||||||
/* on iOS devices the column can become wider when toggling a switch */
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column > * {
|
|
||||||
display: block;
|
|
||||||
margin: 4px 4px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
mwc-fab {
|
|
||||||
position: sticky;
|
|
||||||
float: right;
|
|
||||||
bottom: 16px;
|
|
||||||
right: 16px;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mwc-fab.rtl {
|
|
||||||
float: left;
|
|
||||||
right: auto;
|
|
||||||
left: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
:host {
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column > * {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 599px) {
|
|
||||||
.column {
|
|
||||||
max-width: 600px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues): void {
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
super.updated(changedProperties);
|
super.updated(changedProperties);
|
||||||
|
|
||||||
@ -201,6 +125,7 @@ export class HUIView extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hassChanged = changedProperties.has("hass");
|
const hassChanged = changedProperties.has("hass");
|
||||||
|
|
||||||
let editModeChanged = false;
|
let editModeChanged = false;
|
||||||
let configChanged = false;
|
let configChanged = false;
|
||||||
|
|
||||||
@ -209,7 +134,7 @@ export class HUIView extends LitElement {
|
|||||||
} else if (changedProperties.has("lovelace")) {
|
} else if (changedProperties.has("lovelace")) {
|
||||||
const oldLovelace = changedProperties.get("lovelace") as Lovelace;
|
const oldLovelace = changedProperties.get("lovelace") as Lovelace;
|
||||||
editModeChanged =
|
editModeChanged =
|
||||||
!oldLovelace || lovelace.editMode !== oldLovelace.editMode;
|
oldLovelace && lovelace.editMode !== oldLovelace.editMode;
|
||||||
configChanged = !oldLovelace || lovelace.config !== oldLovelace.config;
|
configChanged = !oldLovelace || lovelace.config !== oldLovelace.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,9 +146,15 @@ export class HUIView extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configChanged || editModeChanged || changedProperties.has("columns")) {
|
if (configChanged) {
|
||||||
this._createCards(lovelace.config.views[this.index!]);
|
this._createCards(lovelace.config.views[this.index!]);
|
||||||
} else if (hassChanged) {
|
} else if (editModeChanged) {
|
||||||
|
this._switchEditMode();
|
||||||
|
} else if (changedProperties.has("columns")) {
|
||||||
|
this._recreateColumns();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hassChanged && !configChanged) {
|
||||||
this._cards.forEach((element) => {
|
this._cards.forEach((element) => {
|
||||||
element.hass = this.hass;
|
element.hass = this.hass;
|
||||||
});
|
});
|
||||||
@ -280,38 +211,34 @@ export class HUIView extends LitElement {
|
|||||||
root.style.display = elements.length > 0 ? "block" : "none";
|
root.style.display = elements.length > 0 ? "block" : "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createCards(config: LovelaceViewConfig): void {
|
private _switchEditMode() {
|
||||||
|
if (this.lovelace!.editMode) {
|
||||||
|
const wrappedCards = this._cards.map((element) => {
|
||||||
|
const wrapper = document.createElement("hui-card-options");
|
||||||
|
wrapper.hass = this.hass;
|
||||||
|
wrapper.lovelace = this.lovelace;
|
||||||
|
wrapper.path = [this.index!, (element as LovelaceCard).index!];
|
||||||
|
(element as LovelaceCard).editMode = true;
|
||||||
|
wrapper.appendChild(element);
|
||||||
|
return wrapper;
|
||||||
|
});
|
||||||
|
this._createColumns(wrappedCards);
|
||||||
|
} else {
|
||||||
|
this._createColumns(this._cards);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _recreateColumns() {
|
||||||
|
this._createColumns(this._cards);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createColumns(elements: HTMLElement[]) {
|
||||||
const root = this.shadowRoot!.getElementById("columns")!;
|
const root = this.shadowRoot!.getElementById("columns")!;
|
||||||
|
|
||||||
while (root.lastChild) {
|
while (root.lastChild) {
|
||||||
root.removeChild(root.lastChild);
|
root.removeChild(root.lastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config || !config.cards || !Array.isArray(config.cards)) {
|
|
||||||
this._cards = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const elements: LovelaceCard[] = [];
|
|
||||||
const elementsToAppend: HTMLElement[] = [];
|
|
||||||
config.cards.forEach((cardConfig, cardIndex) => {
|
|
||||||
const element = this.createCardElement(cardConfig);
|
|
||||||
elements.push(element);
|
|
||||||
|
|
||||||
if (!this.lovelace!.editMode) {
|
|
||||||
elementsToAppend.push(element);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wrapper = document.createElement("hui-card-options");
|
|
||||||
wrapper.hass = this.hass;
|
|
||||||
wrapper.lovelace = this.lovelace;
|
|
||||||
wrapper.path = [this.index!, cardIndex];
|
|
||||||
element.editMode = true;
|
|
||||||
wrapper.appendChild(element);
|
|
||||||
elementsToAppend.push(wrapper);
|
|
||||||
});
|
|
||||||
|
|
||||||
let columns: HTMLElement[][] = [];
|
let columns: HTMLElement[][] = [];
|
||||||
const columnEntityCount: number[] = [];
|
const columnEntityCount: number[] = [];
|
||||||
for (let i = 0; i < this.columns!; i++) {
|
for (let i = 0; i < this.columns!; i++) {
|
||||||
@ -319,12 +246,11 @@ export class HUIView extends LitElement {
|
|||||||
columnEntityCount.push(0);
|
columnEntityCount.push(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.forEach((el, index) => {
|
elements.forEach((el) => {
|
||||||
const cardSize = computeCardSize(el);
|
const cardSize = computeCardSize(
|
||||||
// Element to append might be the wrapped card when we're editing.
|
(el.tagName === "HUI-CARD-OPTIONS" ? el.firstChild : el) as LovelaceCard
|
||||||
columns[getColumnIndex(columnEntityCount, cardSize)].push(
|
|
||||||
elementsToAppend[index]
|
|
||||||
);
|
);
|
||||||
|
columns[getColumnIndex(columnEntityCount, cardSize)].push(el);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove empty columns
|
// Remove empty columns
|
||||||
@ -336,8 +262,28 @@ export class HUIView extends LitElement {
|
|||||||
column.forEach((el) => columnEl.appendChild(el));
|
column.forEach((el) => columnEl.appendChild(el));
|
||||||
root.appendChild(columnEl);
|
root.appendChild(columnEl);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createCards(config: LovelaceViewConfig): void {
|
||||||
|
if (!config || !config.cards || !Array.isArray(config.cards)) {
|
||||||
|
this._cards = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elements: LovelaceCard[] = [];
|
||||||
|
config.cards.forEach((cardConfig, index) => {
|
||||||
|
const element = this.createCardElement(cardConfig);
|
||||||
|
element.index = index;
|
||||||
|
elements.push(element);
|
||||||
|
});
|
||||||
|
|
||||||
this._cards = elements;
|
this._cards = elements;
|
||||||
|
|
||||||
|
if (this.lovelace!.editMode) {
|
||||||
|
this._switchEditMode();
|
||||||
|
} else {
|
||||||
|
this._createColumns(this._cards);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _rebuildCard(
|
private _rebuildCard(
|
||||||
@ -361,6 +307,77 @@ export class HUIView extends LitElement {
|
|||||||
curBadgeEl === badgeElToReplace ? newBadgeEl : curBadgeEl
|
curBadgeEl === badgeElToReplace ? newBadgeEl : curBadgeEl
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 4px 4px 0;
|
||||||
|
transform: translateZ(0);
|
||||||
|
position: relative;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
background: var(--lovelace-background, var(--primary-background-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
#badges {
|
||||||
|
margin: 8px 16px;
|
||||||
|
font-size: 85%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#columns {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
flex: 1 0 0;
|
||||||
|
max-width: 500px;
|
||||||
|
min-width: 0;
|
||||||
|
/* on iOS devices the column can become wider when toggling a switch */
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column > * {
|
||||||
|
display: block;
|
||||||
|
margin: 4px 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mwc-fab {
|
||||||
|
position: sticky;
|
||||||
|
float: right;
|
||||||
|
bottom: 16px;
|
||||||
|
right: 16px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mwc-fab.rtl {
|
||||||
|
float: left;
|
||||||
|
right: auto;
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
:host {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column > * {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 599px) {
|
||||||
|
.column {
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { atLeastVersion } from "../common/config/version";
|
import { atLeastVersion } from "../common/config/version";
|
||||||
import { computeLocalize } from "../common/translations/localize";
|
import { computeLocalize, LocalizeFunc } from "../common/translations/localize";
|
||||||
import { computeRTL } from "../common/util/compute_rtl";
|
import { computeRTL } from "../common/util/compute_rtl";
|
||||||
import { debounce } from "../common/util/debounce";
|
import { debounce } from "../common/util/debounce";
|
||||||
import {
|
import {
|
||||||
@ -104,29 +104,37 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
this._loadFragmentTranslations(hass.language, hass.panelUrl);
|
this._loadFragmentTranslations(hass.language, hass.panelUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load translations from the backend
|
||||||
|
* @param language language to fetch
|
||||||
|
* @param category category to fetch
|
||||||
|
* @param integration optional, if having to fetch for specific integration
|
||||||
|
* @param configFlow optional, if having to fetch for all integrations with a config flow
|
||||||
|
* @param force optional, load even if already cached
|
||||||
|
*/
|
||||||
private async _loadHassTranslations(
|
private async _loadHassTranslations(
|
||||||
language: string,
|
language: string,
|
||||||
category: Parameters<typeof getHassTranslations>[2],
|
category: Parameters<typeof getHassTranslations>[2],
|
||||||
integration?: Parameters<typeof getHassTranslations>[3],
|
integration?: Parameters<typeof getHassTranslations>[3],
|
||||||
configFlow?: Parameters<typeof getHassTranslations>[4],
|
configFlow?: Parameters<typeof getHassTranslations>[4],
|
||||||
force = false
|
force = false
|
||||||
) {
|
): Promise<LocalizeFunc> {
|
||||||
if (
|
if (
|
||||||
__BACKWARDS_COMPAT__ &&
|
__BACKWARDS_COMPAT__ &&
|
||||||
!atLeastVersion(this.hass!.connection.haVersion, 0, 109)
|
!atLeastVersion(this.hass!.connection.haVersion, 0, 109)
|
||||||
) {
|
) {
|
||||||
if (category !== "state") {
|
if (category !== "state") {
|
||||||
return;
|
return this.hass!.localize;
|
||||||
}
|
}
|
||||||
const resources = await getHassTranslationsPre109(this.hass!, language);
|
const resources = await getHassTranslationsPre109(this.hass!, language);
|
||||||
|
|
||||||
// Ignore the repsonse if user switched languages before we got response
|
// Ignore the repsonse if user switched languages before we got response
|
||||||
if (this.hass!.language !== language) {
|
if (this.hass!.language !== language) {
|
||||||
return;
|
return this.hass!.localize;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateResources(language, resources);
|
this._updateResources(language, resources);
|
||||||
return;
|
return this.hass!.localize;
|
||||||
}
|
}
|
||||||
|
|
||||||
let alreadyLoaded: LoadedTranslationCategory;
|
let alreadyLoaded: LoadedTranslationCategory;
|
||||||
@ -145,12 +153,12 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
if (!force) {
|
if (!force) {
|
||||||
if (integration) {
|
if (integration) {
|
||||||
if (alreadyLoaded.integrations.includes(integration)) {
|
if (alreadyLoaded.integrations.includes(integration)) {
|
||||||
return;
|
return this.hass!.localize;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
configFlow ? alreadyLoaded.configFlow : alreadyLoaded.setup
|
configFlow ? alreadyLoaded.configFlow : alreadyLoaded.setup
|
||||||
) {
|
) {
|
||||||
return;
|
return this.hass!.localize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,10 +184,11 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
|
|
||||||
// Ignore the repsonse if user switched languages before we got response
|
// Ignore the repsonse if user switched languages before we got response
|
||||||
if (this.hass!.language !== language) {
|
if (this.hass!.language !== language) {
|
||||||
return;
|
return this.hass!.localize;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateResources(language, resources);
|
this._updateResources(language, resources);
|
||||||
|
return this.hass!.localize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadFragmentTranslations(
|
private async _loadFragmentTranslations(
|
||||||
@ -214,9 +223,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
// multiple fragments.
|
// multiple fragments.
|
||||||
const resources = {
|
const resources = {
|
||||||
[language]: {
|
[language]: {
|
||||||
...(this.hass &&
|
...this.hass?.resources?.[language],
|
||||||
this.hass.resources &&
|
|
||||||
this.hass.resources[language]),
|
|
||||||
...data,
|
...data,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1841,7 +1841,8 @@
|
|||||||
"no_theme": "No theme",
|
"no_theme": "No theme",
|
||||||
"unit": "Unit",
|
"unit": "Unit",
|
||||||
"url": "Url",
|
"url": "Url",
|
||||||
"state": "State"
|
"state": "State",
|
||||||
|
"secondary_info_attribute": "Secondary Info Attribute"
|
||||||
},
|
},
|
||||||
"map": {
|
"map": {
|
||||||
"name": "Map",
|
"name": "Map",
|
||||||
@ -1902,7 +1903,8 @@
|
|||||||
},
|
},
|
||||||
"weather-forecast": {
|
"weather-forecast": {
|
||||||
"name": "Weather Forecast",
|
"name": "Weather Forecast",
|
||||||
"description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall."
|
"description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.",
|
||||||
|
"show_forecast": "Show Forecast"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"view": {
|
"view": {
|
||||||
@ -2186,7 +2188,10 @@
|
|||||||
"icons_by": "Icons by",
|
"icons_by": "Icons by",
|
||||||
"frontend_version": "Frontend version: {version} - {type}",
|
"frontend_version": "Frontend version: {version} - {type}",
|
||||||
"custom_uis": "Custom UIs:",
|
"custom_uis": "Custom UIs:",
|
||||||
"system_health_error": "System Health component is not loaded. Add 'system_health:' to configuration.yaml"
|
"system_health_error": "System Health component is not loaded. Add 'system_health:' to configuration.yaml",
|
||||||
|
"integrations": "Integrations",
|
||||||
|
"documentation": "Documentation",
|
||||||
|
"issues": "Issues"
|
||||||
},
|
},
|
||||||
"logs": {
|
"logs": {
|
||||||
"title": "Logs",
|
"title": "Logs",
|
||||||
|
@ -224,7 +224,7 @@ export interface HomeAssistant {
|
|||||||
category: Parameters<typeof getHassTranslations>[2],
|
category: Parameters<typeof getHassTranslations>[2],
|
||||||
integration?: Parameters<typeof getHassTranslations>[3],
|
integration?: Parameters<typeof getHassTranslations>[3],
|
||||||
configFlow?: Parameters<typeof getHassTranslations>[4]
|
configFlow?: Parameters<typeof getHassTranslations>[4]
|
||||||
): Promise<void>;
|
): Promise<LocalizeFunc>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LightEntity = HassEntityBase & {
|
export type LightEntity = HassEntityBase & {
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "og",
|
||||||
"cancel": "Annuller",
|
"cancel": "Annuller",
|
||||||
"close": "Luk",
|
"close": "Luk",
|
||||||
"delete": "Slet",
|
"delete": "Slet",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Editor er deaktiveret, fordi config er gemt i 'configuration.yaml'.",
|
"edit_requires_storage": "Editor er deaktiveret, fordi config er gemt i 'configuration.yaml'.",
|
||||||
"elevation": "Højde",
|
"elevation": "Højde",
|
||||||
"elevation_meters": "meter",
|
"elevation_meters": "meter",
|
||||||
|
"external_url": "Ekstern webadresse",
|
||||||
"imperial_example": "Fahrenheit, pund",
|
"imperial_example": "Fahrenheit, pund",
|
||||||
|
"internal_url": "Intern webadresse",
|
||||||
"latitude": "Breddegrad",
|
"latitude": "Breddegrad",
|
||||||
"location_name": "Navn på din Home Assistant-installation",
|
"location_name": "Navn på din Home Assistant-installation",
|
||||||
"longitude": "Længdegrad",
|
"longitude": "Længdegrad",
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "und",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"close": "Schließen",
|
"close": "Schließen",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Editor deaktiviert, da die Konfiguration in configuration.yaml gespeichert ist.",
|
"edit_requires_storage": "Editor deaktiviert, da die Konfiguration in configuration.yaml gespeichert ist.",
|
||||||
"elevation": "Höhe",
|
"elevation": "Höhe",
|
||||||
"elevation_meters": "Meter",
|
"elevation_meters": "Meter",
|
||||||
|
"external_url": "Externe Adresse",
|
||||||
"imperial_example": "Fahrenheit, Pfund",
|
"imperial_example": "Fahrenheit, Pfund",
|
||||||
|
"internal_url": "Interne Adresse",
|
||||||
"latitude": "Breitengrad",
|
"latitude": "Breitengrad",
|
||||||
"location_name": "Name deiner Home Assistant Installation",
|
"location_name": "Name deiner Home Assistant Installation",
|
||||||
"longitude": "Längengrad",
|
"longitude": "Längengrad",
|
||||||
|
@ -1878,10 +1878,13 @@
|
|||||||
"built_using": "Built using",
|
"built_using": "Built using",
|
||||||
"custom_uis": "Custom UIs:",
|
"custom_uis": "Custom UIs:",
|
||||||
"developed_by": "Developed by a bunch of awesome people.",
|
"developed_by": "Developed by a bunch of awesome people.",
|
||||||
|
"documentation": "Documentation",
|
||||||
"frontend": "frontend-ui",
|
"frontend": "frontend-ui",
|
||||||
"frontend_version": "Frontend version: {version} - {type}",
|
"frontend_version": "Frontend version: {version} - {type}",
|
||||||
"home_assistant_logo": "Home Assistant logo",
|
"home_assistant_logo": "Home Assistant logo",
|
||||||
"icons_by": "Icons by",
|
"icons_by": "Icons by",
|
||||||
|
"integrations": "Integrations",
|
||||||
|
"issues": "Issues",
|
||||||
"license": "Published under the Apache 2.0 license",
|
"license": "Published under the Apache 2.0 license",
|
||||||
"path_configuration": "Path to configuration.yaml: {path}",
|
"path_configuration": "Path to configuration.yaml: {path}",
|
||||||
"server": "server",
|
"server": "server",
|
||||||
@ -2072,6 +2075,7 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"no_theme": "No theme",
|
"no_theme": "No theme",
|
||||||
"refresh_interval": "Refresh Interval",
|
"refresh_interval": "Refresh Interval",
|
||||||
|
"secondary_info_attribute": "Secondary Info Attribute",
|
||||||
"show_icon": "Show Icon?",
|
"show_icon": "Show Icon?",
|
||||||
"show_name": "Show Name?",
|
"show_name": "Show Name?",
|
||||||
"show_state": "Show State?",
|
"show_state": "Show State?",
|
||||||
@ -2162,7 +2166,8 @@
|
|||||||
},
|
},
|
||||||
"weather-forecast": {
|
"weather-forecast": {
|
||||||
"description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.",
|
"description": "The Weather Forecast card displays the weather. Very useful to include on interfaces that people display on the wall.",
|
||||||
"name": "Weather Forecast"
|
"name": "Weather Forecast",
|
||||||
|
"show_forecast": "Show Forecast"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cardpicker": {
|
"cardpicker": {
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "y",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
"delete": "Eliminar",
|
"delete": "Eliminar",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Editor deshabilitado debido a la configuración almacenada en configuration.yaml.",
|
"edit_requires_storage": "Editor deshabilitado debido a la configuración almacenada en configuration.yaml.",
|
||||||
"elevation": "Altitud",
|
"elevation": "Altitud",
|
||||||
"elevation_meters": "metros",
|
"elevation_meters": "metros",
|
||||||
|
"external_url": "URL externa",
|
||||||
"imperial_example": "Fahrenheit, libras",
|
"imperial_example": "Fahrenheit, libras",
|
||||||
|
"internal_url": "URL interna",
|
||||||
"latitude": "Latitud",
|
"latitude": "Latitud",
|
||||||
"location_name": "Nombre de tu instalación de Home Assistant",
|
"location_name": "Nombre de tu instalación de Home Assistant",
|
||||||
"longitude": "Longitud",
|
"longitude": "Longitud",
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "ja",
|
||||||
"cancel": "Peruuta",
|
"cancel": "Peruuta",
|
||||||
"close": "Sulje",
|
"close": "Sulje",
|
||||||
"delete": "Poista",
|
"delete": "Poista",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Editori on poistettu käytöstä, koska asetuksia on annettu configuration.yaml:ssa.",
|
"edit_requires_storage": "Editori on poistettu käytöstä, koska asetuksia on annettu configuration.yaml:ssa.",
|
||||||
"elevation": "Korkeus merenpinnasta",
|
"elevation": "Korkeus merenpinnasta",
|
||||||
"elevation_meters": "metriä",
|
"elevation_meters": "metriä",
|
||||||
|
"external_url": "Ulkoinen URL-osoite",
|
||||||
"imperial_example": "Fahrenheit, paunaa",
|
"imperial_example": "Fahrenheit, paunaa",
|
||||||
|
"internal_url": "Sisäinen URL-osoite",
|
||||||
"latitude": "Leveysaste",
|
"latitude": "Leveysaste",
|
||||||
"location_name": "Home Assistant -järjestelmäsi nimi",
|
"location_name": "Home Assistant -järjestelmäsi nimi",
|
||||||
"longitude": "Pituusaste",
|
"longitude": "Pituusaste",
|
||||||
@ -1247,6 +1250,7 @@
|
|||||||
},
|
},
|
||||||
"delete": "Poista",
|
"delete": "Poista",
|
||||||
"description": "Hallitse yhdistettyjä laitteita.",
|
"description": "Hallitse yhdistettyjä laitteita.",
|
||||||
|
"device_info": "Laitteen tiedot",
|
||||||
"device_not_found": "Laitetta ei löydy.",
|
"device_not_found": "Laitetta ei löydy.",
|
||||||
"entities": {
|
"entities": {
|
||||||
"add_entities_lovelace": "Lisää Lovelace näkymään",
|
"add_entities_lovelace": "Lisää Lovelace näkymään",
|
||||||
@ -1602,7 +1606,7 @@
|
|||||||
"core": "Lataa ydin uudelleen",
|
"core": "Lataa ydin uudelleen",
|
||||||
"group": "Lataa ryhmät uudelleen",
|
"group": "Lataa ryhmät uudelleen",
|
||||||
"heading": "Asetusten uudelleenlataus",
|
"heading": "Asetusten uudelleenlataus",
|
||||||
"introduction": "Jotkut kotiassistentin osat voidaan ladata uudelleen ilman, että tarvitaan uudelleenkäynnistystä. Painamalla uudelleenlatausta uudet asetukset luetaan yaml tiedostosta.",
|
"introduction": "Jotkut Home Assistantin osat voidaan ladata uudelleen ilman, että tarvitaan uudelleenkäynnistystä. Painamalla uudelleenlatausta yaml-tiedosto luetaan uudelleen.",
|
||||||
"person": "Lataa henkilöt uudelleen",
|
"person": "Lataa henkilöt uudelleen",
|
||||||
"scene": "Lataa tilanteet uudelleen",
|
"scene": "Lataa tilanteet uudelleen",
|
||||||
"script": "Lataa skriptit uudelleen",
|
"script": "Lataa skriptit uudelleen",
|
||||||
@ -1612,7 +1616,7 @@
|
|||||||
"confirm_restart": "Haluatko varmasti käynnistää Home Assistantin uudelleen?",
|
"confirm_restart": "Haluatko varmasti käynnistää Home Assistantin uudelleen?",
|
||||||
"confirm_stop": "Haluatko varmasti pysäyttää Home Assistantin?",
|
"confirm_stop": "Haluatko varmasti pysäyttää Home Assistantin?",
|
||||||
"heading": "Palvelimen hallinta",
|
"heading": "Palvelimen hallinta",
|
||||||
"introduction": "Hallitse Home Assistantia... suoraan Home Assistantista",
|
"introduction": "Hallitse Home Assistantia suoraan käyttöliittymästä.",
|
||||||
"restart": "Käynnistä uudelleen",
|
"restart": "Käynnistä uudelleen",
|
||||||
"stop": "Pysäytä"
|
"stop": "Pysäytä"
|
||||||
},
|
},
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "És",
|
||||||
"cancel": "Mégse",
|
"cancel": "Mégse",
|
||||||
"close": "Bezárás",
|
"close": "Bezárás",
|
||||||
"delete": "Törlés",
|
"delete": "Törlés",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "A szerkesztő le van tiltva, mert a konfiguráció a configuration.yaml fájlban van tárolva.",
|
"edit_requires_storage": "A szerkesztő le van tiltva, mert a konfiguráció a configuration.yaml fájlban van tárolva.",
|
||||||
"elevation": "Magasság",
|
"elevation": "Magasság",
|
||||||
"elevation_meters": "méter",
|
"elevation_meters": "méter",
|
||||||
|
"external_url": "Externe URL",
|
||||||
"imperial_example": "Fahrenheit, font",
|
"imperial_example": "Fahrenheit, font",
|
||||||
|
"internal_url": "Érvénytelen URL",
|
||||||
"latitude": "Szélesség",
|
"latitude": "Szélesség",
|
||||||
"location_name": "A Home Assistant rendszered neve",
|
"location_name": "A Home Assistant rendszered neve",
|
||||||
"longitude": "Hosszúság",
|
"longitude": "Hosszúság",
|
||||||
@ -1247,6 +1250,7 @@
|
|||||||
},
|
},
|
||||||
"delete": "Törlés",
|
"delete": "Törlés",
|
||||||
"description": "Csatlakoztatott eszközök kezelése",
|
"description": "Csatlakoztatott eszközök kezelése",
|
||||||
|
"device_info": "Eszköz információ",
|
||||||
"device_not_found": "Eszköz nem található.",
|
"device_not_found": "Eszköz nem található.",
|
||||||
"entities": {
|
"entities": {
|
||||||
"add_entities_lovelace": "Hozzáadás a Lovelace-hez",
|
"add_entities_lovelace": "Hozzáadás a Lovelace-hez",
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "e",
|
||||||
"cancel": "Annulla",
|
"cancel": "Annulla",
|
||||||
"close": "Chiudi",
|
"close": "Chiudi",
|
||||||
"delete": "Elimina",
|
"delete": "Elimina",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Editor disabilitato perché la configurazione è memorizzata in configuration.yaml.",
|
"edit_requires_storage": "Editor disabilitato perché la configurazione è memorizzata in configuration.yaml.",
|
||||||
"elevation": "Altitudine",
|
"elevation": "Altitudine",
|
||||||
"elevation_meters": "metri",
|
"elevation_meters": "metri",
|
||||||
|
"external_url": "URL esterno",
|
||||||
"imperial_example": "Fahrenheit, libbre",
|
"imperial_example": "Fahrenheit, libbre",
|
||||||
|
"internal_url": "URL interno",
|
||||||
"latitude": "Latitudine",
|
"latitude": "Latitudine",
|
||||||
"location_name": "Nome della tua installazione di Home Assistant",
|
"location_name": "Nome della tua installazione di Home Assistant",
|
||||||
"longitude": "Longitudine",
|
"longitude": "Longitudine",
|
||||||
@ -1247,6 +1250,7 @@
|
|||||||
},
|
},
|
||||||
"delete": "Elimina",
|
"delete": "Elimina",
|
||||||
"description": "Gestisci i dispositivi collegati",
|
"description": "Gestisci i dispositivi collegati",
|
||||||
|
"device_info": "Informazioni sul dispositivo",
|
||||||
"device_not_found": "Dispositivo non trovato.",
|
"device_not_found": "Dispositivo non trovato.",
|
||||||
"entities": {
|
"entities": {
|
||||||
"add_entities_lovelace": "Aggiungi a Lovelace",
|
"add_entities_lovelace": "Aggiungi a Lovelace",
|
||||||
|
@ -1602,7 +1602,7 @@
|
|||||||
"automation": "Automatisme nei lueden",
|
"automation": "Automatisme nei lueden",
|
||||||
"core": "Standuert and Personnalisatioun néi lueden",
|
"core": "Standuert and Personnalisatioun néi lueden",
|
||||||
"group": "Gruppe nei lueden",
|
"group": "Gruppe nei lueden",
|
||||||
"heading": "YAML Konfiguratioun gëtt frësch gelueden",
|
"heading": "YAML Konfiguratioun frësch lueden",
|
||||||
"introduction": "E puer Deeler vum Home Assistant kënne frësch geluede ginn ouni datt een Neistart néideg ass. Klick op nei luede fir di aktuell Konfiguratioun z'entlueden an di nei Konfiguratioun ze lueden.",
|
"introduction": "E puer Deeler vum Home Assistant kënne frësch geluede ginn ouni datt een Neistart néideg ass. Klick op nei luede fir di aktuell Konfiguratioun z'entlueden an di nei Konfiguratioun ze lueden.",
|
||||||
"person": "Persoune frësch lueden",
|
"person": "Persoune frësch lueden",
|
||||||
"scene": "Szeene néi lueden",
|
"scene": "Szeene néi lueden",
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "og",
|
||||||
"cancel": "Avbryt",
|
"cancel": "Avbryt",
|
||||||
"close": "Lukk",
|
"close": "Lukk",
|
||||||
"delete": "Slett",
|
"delete": "Slett",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Redigering deaktivert da konfigurasjonen er lagret i configuration.yaml.",
|
"edit_requires_storage": "Redigering deaktivert da konfigurasjonen er lagret i configuration.yaml.",
|
||||||
"elevation": "Høyde",
|
"elevation": "Høyde",
|
||||||
"elevation_meters": "meter",
|
"elevation_meters": "meter",
|
||||||
|
"external_url": "Ekstern URL",
|
||||||
"imperial_example": "Fahrenheit, pund",
|
"imperial_example": "Fahrenheit, pund",
|
||||||
|
"internal_url": "Intern URL",
|
||||||
"latitude": "Breddegrad",
|
"latitude": "Breddegrad",
|
||||||
"location_name": "Navn på installasjonen av Home Assistant",
|
"location_name": "Navn på installasjonen av Home Assistant",
|
||||||
"longitude": "Lengdegrad",
|
"longitude": "Lengdegrad",
|
||||||
|
@ -473,11 +473,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "en",
|
||||||
"cancel": "Annuleren",
|
"cancel": "Annuleren",
|
||||||
"close": "Sluiten",
|
"close": "Sluiten",
|
||||||
"delete": "Verwijderen",
|
"delete": "Verwijderen",
|
||||||
"loading": "Bezig met laden",
|
"loading": "Bezig met laden",
|
||||||
|
"next": "Volgende",
|
||||||
"no": "Nee",
|
"no": "Nee",
|
||||||
|
"previous": "Vorige",
|
||||||
|
"refresh": "Vernieuwen",
|
||||||
"save": "Opslaan",
|
"save": "Opslaan",
|
||||||
"successfully_deleted": "Succesvol verwijderd",
|
"successfully_deleted": "Succesvol verwijderd",
|
||||||
"successfully_saved": "Succesvol opgeslagen",
|
"successfully_saved": "Succesvol opgeslagen",
|
||||||
@ -737,6 +741,10 @@
|
|||||||
"triggered": "Geactiveerd {name}"
|
"triggered": "Geactiveerd {name}"
|
||||||
},
|
},
|
||||||
"panel": {
|
"panel": {
|
||||||
|
"calendar": {
|
||||||
|
"my_calendars": "Mijn agenda's",
|
||||||
|
"today": "Vandaag"
|
||||||
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"advanced_mode": {
|
"advanced_mode": {
|
||||||
"hint_enable": "Ontbrekende configuratie-opties? Schakel geavanceerde modus in",
|
"hint_enable": "Ontbrekende configuratie-opties? Schakel geavanceerde modus in",
|
||||||
@ -839,6 +847,9 @@
|
|||||||
},
|
},
|
||||||
"label": "Apparaat"
|
"label": "Apparaat"
|
||||||
},
|
},
|
||||||
|
"not": {
|
||||||
|
"label": "Niet"
|
||||||
|
},
|
||||||
"numeric_state": {
|
"numeric_state": {
|
||||||
"above": "Boven",
|
"above": "Boven",
|
||||||
"below": "Onder",
|
"below": "Onder",
|
||||||
@ -1170,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Editor uitgeschakeld omdat de configuratie is opgeslagen in configuration.yaml",
|
"edit_requires_storage": "Editor uitgeschakeld omdat de configuratie is opgeslagen in configuration.yaml",
|
||||||
"elevation": "Hoogte",
|
"elevation": "Hoogte",
|
||||||
"elevation_meters": "meter",
|
"elevation_meters": "meter",
|
||||||
|
"external_url": "Externe URL",
|
||||||
"imperial_example": "Fahrenheit, ponden",
|
"imperial_example": "Fahrenheit, ponden",
|
||||||
|
"internal_url": "Interne URL",
|
||||||
"latitude": "Breedtegraad",
|
"latitude": "Breedtegraad",
|
||||||
"location_name": "Naam van Home Assistant installatie",
|
"location_name": "Naam van Home Assistant installatie",
|
||||||
"longitude": "Lengtegraad",
|
"longitude": "Lengtegraad",
|
||||||
@ -1237,6 +1250,7 @@
|
|||||||
},
|
},
|
||||||
"delete": "Verwijderen",
|
"delete": "Verwijderen",
|
||||||
"description": "Beheer verbonden apparaten",
|
"description": "Beheer verbonden apparaten",
|
||||||
|
"device_info": "Apparaat info",
|
||||||
"device_not_found": "Apparaat niet gevonden.",
|
"device_not_found": "Apparaat niet gevonden.",
|
||||||
"entities": {
|
"entities": {
|
||||||
"add_entities_lovelace": "Voeg toe aan de Lovelace gebruikersinterface",
|
"add_entities_lovelace": "Voeg toe aan de Lovelace gebruikersinterface",
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "i",
|
||||||
"cancel": "Anuluj",
|
"cancel": "Anuluj",
|
||||||
"close": "Zamknij",
|
"close": "Zamknij",
|
||||||
"delete": "Usuń",
|
"delete": "Usuń",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "Edytor wyłączony, ponieważ konfiguracja jest przechowywana w pliku configuration.yaml.",
|
"edit_requires_storage": "Edytor wyłączony, ponieważ konfiguracja jest przechowywana w pliku configuration.yaml.",
|
||||||
"elevation": "Wysokość",
|
"elevation": "Wysokość",
|
||||||
"elevation_meters": "metry/-ów",
|
"elevation_meters": "metry/-ów",
|
||||||
|
"external_url": "Publiczny adres URL",
|
||||||
"imperial_example": "stopnie Fahrenheita, funty",
|
"imperial_example": "stopnie Fahrenheita, funty",
|
||||||
|
"internal_url": "Lokalny adres URL",
|
||||||
"latitude": "Szerokość geograficzna",
|
"latitude": "Szerokość geograficzna",
|
||||||
"location_name": "Nazwa instalacji Home Assistant",
|
"location_name": "Nazwa instalacji Home Assistant",
|
||||||
"longitude": "Długość geograficzna",
|
"longitude": "Długość geograficzna",
|
||||||
|
@ -331,8 +331,7 @@
|
|||||||
"ui": {
|
"ui": {
|
||||||
"auth_store": {
|
"auth_store": {
|
||||||
"ask": "Deseja continuar com sessão iniciada?",
|
"ask": "Deseja continuar com sessão iniciada?",
|
||||||
"confirm": "Guardar login",
|
"decline": "Não"
|
||||||
"decline": "Não, obrigado"
|
|
||||||
},
|
},
|
||||||
"card": {
|
"card": {
|
||||||
"alarm_control_panel": {
|
"alarm_control_panel": {
|
||||||
@ -473,6 +472,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "e",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"close": "Fechar",
|
"close": "Fechar",
|
||||||
"delete": "Apagar",
|
"delete": "Apagar",
|
||||||
@ -761,8 +761,8 @@
|
|||||||
"editor": {
|
"editor": {
|
||||||
"create": "Criar",
|
"create": "Criar",
|
||||||
"default_name": "Nova área",
|
"default_name": "Nova área",
|
||||||
"delete": "APAGAR",
|
"delete": "Apagar",
|
||||||
"update": "ATUALIZAR"
|
"update": "Atualizar"
|
||||||
},
|
},
|
||||||
"picker": {
|
"picker": {
|
||||||
"create_area": "Criar área",
|
"create_area": "Criar área",
|
||||||
@ -1178,7 +1178,9 @@
|
|||||||
"edit_requires_storage": "Editor desativado por causa da configuração existente em configuration.yaml.",
|
"edit_requires_storage": "Editor desativado por causa da configuração existente em configuration.yaml.",
|
||||||
"elevation": "Elevação",
|
"elevation": "Elevação",
|
||||||
"elevation_meters": "metros",
|
"elevation_meters": "metros",
|
||||||
|
"external_url": "URL externo",
|
||||||
"imperial_example": "Fahrenheit, libras",
|
"imperial_example": "Fahrenheit, libras",
|
||||||
|
"internal_url": "URL interno",
|
||||||
"latitude": "Latitude",
|
"latitude": "Latitude",
|
||||||
"location_name": "Nome da instalação do seu Home Assistant",
|
"location_name": "Nome da instalação do seu Home Assistant",
|
||||||
"longitude": "Longitude",
|
"longitude": "Longitude",
|
||||||
@ -1204,7 +1206,7 @@
|
|||||||
"description": "Personalizar as suas entidades",
|
"description": "Personalizar as suas entidades",
|
||||||
"pick_attribute": "Escolha um atributo para substituir.",
|
"pick_attribute": "Escolha um atributo para substituir.",
|
||||||
"picker": {
|
"picker": {
|
||||||
"header": "Personalização",
|
"header": "Personalizações",
|
||||||
"introduction": "Ajustar atributos por entidade. Personalizações acrescentadas/editadas terão efeitos imediatos. Remoção de personalizações terão efeito quando a entidade for atualizada."
|
"introduction": "Ajustar atributos por entidade. Personalizações acrescentadas/editadas terão efeitos imediatos. Remoção de personalizações terão efeito quando a entidade for atualizada."
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
@ -1244,6 +1246,7 @@
|
|||||||
},
|
},
|
||||||
"delete": "Apagar",
|
"delete": "Apagar",
|
||||||
"description": "Gerir dispositivos ligados",
|
"description": "Gerir dispositivos ligados",
|
||||||
|
"device_info": "Informação do dispositivo",
|
||||||
"device_not_found": "Dispositivo não encontrado.",
|
"device_not_found": "Dispositivo não encontrado.",
|
||||||
"entities": {
|
"entities": {
|
||||||
"add_entities_lovelace": "Adicionar ao Lovelace",
|
"add_entities_lovelace": "Adicionar ao Lovelace",
|
||||||
@ -1368,6 +1371,7 @@
|
|||||||
"aborted": "Abortado",
|
"aborted": "Abortado",
|
||||||
"close": "Fechar",
|
"close": "Fechar",
|
||||||
"created_config": "Configuração criada para {name}.",
|
"created_config": "Configuração criada para {name}.",
|
||||||
|
"dismiss": "Descartar diálogo",
|
||||||
"error_saving_area": "Erro ao salvar a área: {error}",
|
"error_saving_area": "Erro ao salvar a área: {error}",
|
||||||
"external_step": {
|
"external_step": {
|
||||||
"description": "Para ser concluída, esta etapa exige que visite um sítio web externo.",
|
"description": "Para ser concluída, esta etapa exige que visite um sítio web externo.",
|
||||||
@ -1592,8 +1596,8 @@
|
|||||||
"automation": "Recarregar automações",
|
"automation": "Recarregar automações",
|
||||||
"core": "Recarregar localização e personalizações",
|
"core": "Recarregar localização e personalizações",
|
||||||
"group": "Recarregar grupos",
|
"group": "Recarregar grupos",
|
||||||
"heading": "A recarregar configuração",
|
"heading": "A recarregar a configuração YAML",
|
||||||
"introduction": "Algumas partes do Home Assistant podem ser recarregadas sem necessidade de reiniciar. Ao carregar em Recarregar configuração irá descarregar a configuração atual e carregar a nova.",
|
"introduction": "Algumas partes do Home Assistant podem ser recarregadas sem a necessidade de reiniciar. Ao carregar em Recarregar a configuração irá descartar a configuração atual e carregar a nova.",
|
||||||
"person": "Recarregar pessoas",
|
"person": "Recarregar pessoas",
|
||||||
"scene": "Recarregar cenas",
|
"scene": "Recarregar cenas",
|
||||||
"script": "Recarregar scripts",
|
"script": "Recarregar scripts",
|
||||||
@ -1661,7 +1665,8 @@
|
|||||||
"spinner": "À procura de dispositivos ZHA Zigbee..."
|
"spinner": "À procura de dispositivos ZHA Zigbee..."
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"caption": "Adicionar Dispositivos"
|
"caption": "Adicionar Dispositivos",
|
||||||
|
"description": "Adicionar dispositivos à rede Zigbee"
|
||||||
},
|
},
|
||||||
"caption": "ZHA",
|
"caption": "ZHA",
|
||||||
"cluster_attributes": {
|
"cluster_attributes": {
|
||||||
@ -1709,8 +1714,10 @@
|
|||||||
"caption": "Grupos",
|
"caption": "Grupos",
|
||||||
"create": "Criar grupo",
|
"create": "Criar grupo",
|
||||||
"create_group": "Zigbee Home Automation - Criar grupo",
|
"create_group": "Zigbee Home Automation - Criar grupo",
|
||||||
|
"create_group_details": "Digite os detalhes necessários para criar um novo grupo zigbee",
|
||||||
"creating_group": "Criação de grupo",
|
"creating_group": "Criação de grupo",
|
||||||
"description": "Criar e modificar grupos Zigbee",
|
"description": "Criar e modificar grupos Zigbee",
|
||||||
|
"group_details": "Aqui estão todos os detalhes do grupo Zigbee selecionado.",
|
||||||
"group_id": "ID do grupo",
|
"group_id": "ID do grupo",
|
||||||
"group_info": "Informações sobre o grupo",
|
"group_info": "Informações sobre o grupo",
|
||||||
"group_name_placeholder": "Nome do Grupo",
|
"group_name_placeholder": "Nome do Grupo",
|
||||||
@ -1718,6 +1725,7 @@
|
|||||||
"group-header": "Zigbee Home Automation - Detalhes do grupo",
|
"group-header": "Zigbee Home Automation - Detalhes do grupo",
|
||||||
"groups": "Grupos",
|
"groups": "Grupos",
|
||||||
"groups-header": "Zigbee Home Automation - Gestão de Grupos",
|
"groups-header": "Zigbee Home Automation - Gestão de Grupos",
|
||||||
|
"header": "Zigbee Home Automation - Gestão de Grupos",
|
||||||
"introduction": "Criar e modificar grupos zigbee",
|
"introduction": "Criar e modificar grupos zigbee",
|
||||||
"manage_groups": "Gerir Grupos Zigbee",
|
"manage_groups": "Gerir Grupos Zigbee",
|
||||||
"members": "Membros",
|
"members": "Membros",
|
||||||
@ -1728,6 +1736,7 @@
|
|||||||
"zha_zigbee_groups": "Grupos ZHA Zigbee"
|
"zha_zigbee_groups": "Grupos ZHA Zigbee"
|
||||||
},
|
},
|
||||||
"header": "Configurar a automação residencial Zigbee",
|
"header": "Configurar a automação residencial Zigbee",
|
||||||
|
"introduction": "Aqui é possível configurar o componente ZHA. Ainda não é possível configurar tudo a partir do IU, mas estamos a trabalhar nisso.",
|
||||||
"network_management": {
|
"network_management": {
|
||||||
"header": "Gestão ",
|
"header": "Gestão ",
|
||||||
"introduction": "Comandos que afetam toda a rede"
|
"introduction": "Comandos que afetam toda a rede"
|
||||||
@ -1796,7 +1805,7 @@
|
|||||||
"config_parameter": "Parâmetro de configuração",
|
"config_parameter": "Parâmetro de configuração",
|
||||||
"config_value": "Valor de Configuração",
|
"config_value": "Valor de Configuração",
|
||||||
"false": "Falso",
|
"false": "Falso",
|
||||||
"header": "Configurar opçoes do nó",
|
"header": "Opções de configuração de nó",
|
||||||
"seconds": "Segundos",
|
"seconds": "Segundos",
|
||||||
"set_config_parameter": "Definir o Parâmetro de Configuração",
|
"set_config_parameter": "Definir o Parâmetro de Configuração",
|
||||||
"set_wakeup": "Definir intervalo de acordar",
|
"set_wakeup": "Definir intervalo de acordar",
|
||||||
@ -1973,7 +1982,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"changed_toast": {
|
"changed_toast": {
|
||||||
"message": "A configuração do Lovelace foi atualizada, gostaria de atualizar?",
|
"message": "A configuração do Lovelace foi atualizada para este painel, gostaria de atualizar?",
|
||||||
"refresh": "Atualizar"
|
"refresh": "Atualizar"
|
||||||
},
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
@ -2147,7 +2156,7 @@
|
|||||||
"header": "Configuração do cartão",
|
"header": "Configuração do cartão",
|
||||||
"move": "Mover para Vista",
|
"move": "Mover para Vista",
|
||||||
"options": "Mais opções",
|
"options": "Mais opções",
|
||||||
"pick_card": "Escolha o cartão que deseja adicionar.",
|
"pick_card": "Que cartão gostaria de adicionar?",
|
||||||
"pick_card_view_title": "Que cartão você gostaria de adicionar à sua vista {name}?",
|
"pick_card_view_title": "Que cartão você gostaria de adicionar à sua vista {name}?",
|
||||||
"show_code_editor": "Mostrar Editor de Código",
|
"show_code_editor": "Mostrar Editor de Código",
|
||||||
"show_visual_editor": "Mostrar Editor Visual",
|
"show_visual_editor": "Mostrar Editor Visual",
|
||||||
@ -2185,13 +2194,14 @@
|
|||||||
"para_no_id": "Este elemento não possui um ID. Por favor adicione um ID a este elemento em 'ui-lovelace.yaml'."
|
"para_no_id": "Este elemento não possui um ID. Por favor adicione um ID a este elemento em 'ui-lovelace.yaml'."
|
||||||
},
|
},
|
||||||
"raw_editor": {
|
"raw_editor": {
|
||||||
|
"confirm_remove_config_text": "Iremos gerar automaticamente as suas vistas do Lovelace UI com as suas áreas e dispositivos se você remover a sua configuração do Lovelace UI.",
|
||||||
"confirm_unsaved_changes": "Existem alterações não guardadas. De certeza de que quer sair?",
|
"confirm_unsaved_changes": "Existem alterações não guardadas. De certeza de que quer sair?",
|
||||||
"confirm_unsaved_comments": "A sua configuração contém comentário(s), eles não serão salvos. Deseja continuar?",
|
"confirm_unsaved_comments": "A sua configuração contém comentário(s), eles não serão salvos. Deseja continuar?",
|
||||||
"error_invalid_config": "A sua configuração não é válida: {error}",
|
"error_invalid_config": "A sua configuração não é válida: {error}",
|
||||||
"error_parse_yaml": "Não foi possível analisar o YAML: {error}",
|
"error_parse_yaml": "Não foi possível analisar o YAML: {error}",
|
||||||
"error_remove": "Não foi possível remover a configuração: {error}",
|
"error_remove": "Não foi possível remover a configuração: {error}",
|
||||||
"error_save_yaml": "Não é possível salvar o YAML: {error}",
|
"error_save_yaml": "Não é possível salvar o YAML: {error}",
|
||||||
"header": "Editar configuração",
|
"header": "Editar Configuração",
|
||||||
"resources_moved": "Os recursos não devem mais ser adicionados ao editor de configuração do código fonte do Lovelace, mas podem ser adicionados no painel de configuração do Lovelace.",
|
"resources_moved": "Os recursos não devem mais ser adicionados ao editor de configuração do código fonte do Lovelace, mas podem ser adicionados no painel de configuração do Lovelace.",
|
||||||
"save": "Guardar",
|
"save": "Guardar",
|
||||||
"saved": "Guardada",
|
"saved": "Guardada",
|
||||||
@ -2229,7 +2239,7 @@
|
|||||||
"refresh": "Atualizar",
|
"refresh": "Atualizar",
|
||||||
"reload_resources": "Recarregar recursos"
|
"reload_resources": "Recarregar recursos"
|
||||||
},
|
},
|
||||||
"reload_lovelace": "Recarregar Lovelace",
|
"reload_lovelace": "Recarregar UI",
|
||||||
"reload_resources": {
|
"reload_resources": {
|
||||||
"refresh_body": "É preciso atualizar a página para concluir o carregamento. Deseja atualizar agora?",
|
"refresh_body": "É preciso atualizar a página para concluir o carregamento. Deseja atualizar agora?",
|
||||||
"refresh_header": "Deseja atualizar?"
|
"refresh_header": "Deseja atualizar?"
|
||||||
@ -2392,6 +2402,7 @@
|
|||||||
"mirror": "Espelho",
|
"mirror": "Espelho",
|
||||||
"patio": "Pátio",
|
"patio": "Pátio",
|
||||||
"right": "Direita",
|
"right": "Direita",
|
||||||
|
"temperature_study": "Estudo da Temperatura",
|
||||||
"upstairs": "Andar de cima"
|
"upstairs": "Andar de cima"
|
||||||
},
|
},
|
||||||
"unit": {
|
"unit": {
|
||||||
|
@ -330,8 +330,8 @@
|
|||||||
},
|
},
|
||||||
"ui": {
|
"ui": {
|
||||||
"auth_store": {
|
"auth_store": {
|
||||||
"ask": "Doriți să salvați aceste date de conectare?",
|
"ask": "Vrei să rămâi autentificat?",
|
||||||
"confirm": "Salvați datele de conectare",
|
"confirm": "Da",
|
||||||
"decline": "Nu"
|
"decline": "Nu"
|
||||||
},
|
},
|
||||||
"card": {
|
"card": {
|
||||||
@ -459,17 +459,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "Și",
|
||||||
"cancel": "Revocare",
|
"cancel": "Revocare",
|
||||||
"close": "Închide",
|
"close": "Închide",
|
||||||
"delete": "Șterge",
|
"delete": "Șterge",
|
||||||
"loading": "Se încarcă",
|
"loading": "Se încarcă",
|
||||||
"next": "Următorul",
|
"next": "Următorul",
|
||||||
|
"no": "Nu",
|
||||||
"previous": "Anterior",
|
"previous": "Anterior",
|
||||||
"refresh": "Reîmprospătare",
|
"refresh": "Reîmprospătare",
|
||||||
"save": "Salvați",
|
"save": "Salvați",
|
||||||
"successfully_deleted": "Șters cu succes",
|
"successfully_deleted": "Șters cu succes",
|
||||||
"successfully_saved": "Opțiunile salvate cu succes.",
|
"successfully_saved": "Opțiunile salvate cu succes.",
|
||||||
"undo": "Undo"
|
"undo": "Undo",
|
||||||
|
"yes": "Da"
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"area-picker": {
|
"area-picker": {
|
||||||
@ -536,12 +539,15 @@
|
|||||||
"title": "Opțiuni de sistem pentru {integration}",
|
"title": "Opțiuni de sistem pentru {integration}",
|
||||||
"update": "Actualizare"
|
"update": "Actualizare"
|
||||||
},
|
},
|
||||||
|
"domain_toggler": {
|
||||||
|
"title": "Comutare domenii"
|
||||||
|
},
|
||||||
"entity_registry": {
|
"entity_registry": {
|
||||||
"control": "Control",
|
"control": "Control",
|
||||||
"dismiss": "Ascunde",
|
"dismiss": "Ascunde",
|
||||||
"editor": {
|
"editor": {
|
||||||
"confirm_delete": "Sigur dorești să ștergi această intrare?",
|
"confirm_delete": "Sigur dorești să ștergi această intrare?",
|
||||||
"delete": "ȘTERGE",
|
"delete": "Șterge",
|
||||||
"enabled_cause": "Dezactivat de către {cause}.",
|
"enabled_cause": "Dezactivat de către {cause}.",
|
||||||
"enabled_description": "Entitățile dezactivate nu vof fi adăugate in Home Assistant",
|
"enabled_description": "Entitățile dezactivate nu vof fi adăugate in Home Assistant",
|
||||||
"enabled_label": "Activează entitatea",
|
"enabled_label": "Activează entitatea",
|
||||||
@ -550,7 +556,7 @@
|
|||||||
"name": "Suprascriere nume",
|
"name": "Suprascriere nume",
|
||||||
"note": "Notă: este posibil să nu funcționeze încă cu toate integrările.",
|
"note": "Notă: este posibil să nu funcționeze încă cu toate integrările.",
|
||||||
"unavailable": "Această entitate nu este disponibilă momentan.",
|
"unavailable": "Această entitate nu este disponibilă momentan.",
|
||||||
"update": "ACTUALIZARE"
|
"update": "Actualizare"
|
||||||
},
|
},
|
||||||
"no_unique_id": "Această entitate nu are un ID unic, prin urmare, setările sale nu pot fi gestionate de la interfața cu utilizatorul.",
|
"no_unique_id": "Această entitate nu are un ID unic, prin urmare, setările sale nu pot fi gestionate de la interfața cu utilizatorul.",
|
||||||
"related": "În legătură cu",
|
"related": "În legătură cu",
|
||||||
@ -574,6 +580,7 @@
|
|||||||
"time": "Timp"
|
"time": "Timp"
|
||||||
},
|
},
|
||||||
"input_number": {
|
"input_number": {
|
||||||
|
"box": "Introdu textul",
|
||||||
"max": "Valoare maximă",
|
"max": "Valoare maximă",
|
||||||
"min": "Valoare minimă",
|
"min": "Valoare minimă",
|
||||||
"mode": "Mod de afișare",
|
"mode": "Mod de afișare",
|
||||||
@ -592,9 +599,12 @@
|
|||||||
"min": "Lungime minimă",
|
"min": "Lungime minimă",
|
||||||
"mode": "Mod de afișare",
|
"mode": "Mod de afișare",
|
||||||
"password": "Parola",
|
"password": "Parola",
|
||||||
|
"pattern": "Modelul Regex pentru validarea de partea clientului",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"required_error_msg": "Acest câmp este obligatoriu"
|
"platform_not_loaded": "Integrarea {platform} nu este încărcată. Vă rugăm să-i adăugați configurația dvs. fie adăugând 'default_config:' sau '{platform}:'.",
|
||||||
|
"required_error_msg": "Acest câmp este obligatoriu",
|
||||||
|
"yaml_not_editable": "Setările acestei entități nu se pot edita din interfața grafica. Numai entitățile configurate in interfața grafica sunt configurabile din interfața grafica."
|
||||||
},
|
},
|
||||||
"more_info_control": {
|
"more_info_control": {
|
||||||
"dismiss": "Se respinge dialogul",
|
"dismiss": "Se respinge dialogul",
|
||||||
@ -653,6 +663,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"voice_command": {
|
"voice_command": {
|
||||||
|
"did_not_hear": "Home Assistant nu a auzit nimic",
|
||||||
|
"error": "Oops, a apărut o eroare",
|
||||||
|
"found": "Am găsit următoarele pentru tine:",
|
||||||
|
"how_can_i_help": "Cu ce vă pot ajuta?",
|
||||||
"label": "Scrieți o întrebare și apăsați „Enter”",
|
"label": "Scrieți o întrebare și apăsați „Enter”",
|
||||||
"label_voice": "Tastați și apăsați „Enter” sau atingeți microfonul pentru a vorbi"
|
"label_voice": "Tastați și apăsați „Enter” sau atingeți microfonul pentru a vorbi"
|
||||||
},
|
},
|
||||||
@ -723,11 +737,12 @@
|
|||||||
},
|
},
|
||||||
"description": "Privire de ansamblu asupra tuturor zonelor din casa ta.",
|
"description": "Privire de ansamblu asupra tuturor zonelor din casa ta.",
|
||||||
"editor": {
|
"editor": {
|
||||||
"create": "CREAȚI",
|
"create": "Creează",
|
||||||
"delete": "ȘTERGEȚI",
|
"delete": "Șterge",
|
||||||
"update": "ACTUALIZAȚI"
|
"update": "Actualizare"
|
||||||
},
|
},
|
||||||
"picker": {
|
"picker": {
|
||||||
|
"create_area": "Creare zonă",
|
||||||
"header": "Zone",
|
"header": "Zone",
|
||||||
"integrations_page": "Pagina de integrari",
|
"integrations_page": "Pagina de integrari",
|
||||||
"introduction": "Zonele sunt folosite pentru a organiza unde sunt dispozitivele. Aceste informații vor fi utilizate de către Home Assistant pentru a vă ajuta să vă organizați interfața, permisiunile și integrarea cu alte sisteme.",
|
"introduction": "Zonele sunt folosite pentru a organiza unde sunt dispozitivele. Aceste informații vor fi utilizate de către Home Assistant pentru a vă ajuta să vă organizați interfața, permisiunile și integrarea cu alte sisteme.",
|
||||||
@ -851,7 +866,7 @@
|
|||||||
"triggers": {
|
"triggers": {
|
||||||
"add": "Adăugați acțiune",
|
"add": "Adăugați acțiune",
|
||||||
"delete": "Ștergeți",
|
"delete": "Ștergeți",
|
||||||
"delete_confirm": "Sigur doriți să ștergeți?",
|
"delete_confirm": "Sigur dorești să ștergi această intrare?",
|
||||||
"duplicate": "Dublura",
|
"duplicate": "Dublura",
|
||||||
"header": "Declanșatoare",
|
"header": "Declanșatoare",
|
||||||
"introduction": "Declanșatoarele sunt cele ce încep procesarea unei reguli de automatizare. Este posibil să specificați mai multe declanșatoare pentru aceeași regulă. Odată ce începe declanșarea, Home Assistant o să valideze condițiile, dacă este cazul, și va apela acțiunea. \n\n [Aflați mai multe despre declanșatoare.] (https://home-assistant.io/docs/automation/trigger/)",
|
"introduction": "Declanșatoarele sunt cele ce încep procesarea unei reguli de automatizare. Este posibil să specificați mai multe declanșatoare pentru aceeași regulă. Odată ce începe declanșarea, Home Assistant o să valideze condițiile, dacă este cazul, și va apela acțiunea. \n\n [Aflați mai multe despre declanșatoare.] (https://home-assistant.io/docs/automation/trigger/)",
|
||||||
@ -994,14 +1009,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"customize": {
|
"customize": {
|
||||||
|
"attributes_customize": "Următoarele atribute sunt deja setate în customize.yaml",
|
||||||
"attributes_not_set": "Următoarele atribute nu au fost setate. Setați-le dacă doriți.",
|
"attributes_not_set": "Următoarele atribute nu au fost setate. Setați-le dacă doriți.",
|
||||||
|
"attributes_outside": "Următoarele atribute sunt personalizate din afara customize.yaml",
|
||||||
"attributes_override": "Poți să le suprascrii dacă vrei.",
|
"attributes_override": "Poți să le suprascrii dacă vrei.",
|
||||||
|
"attributes_set": "Următoarele atribute ale entității sunt setate programatic.",
|
||||||
"caption": "Personalizare",
|
"caption": "Personalizare",
|
||||||
"description": "Personalizați-vă entitățile",
|
"description": "Personalizați-vă entitățile",
|
||||||
|
"different_include": "Posibil printr-un domeniu, un glob sau alta includere",
|
||||||
"pick_attribute": "Alegeți un atribut pentru suprascriere",
|
"pick_attribute": "Alegeți un atribut pentru suprascriere",
|
||||||
"picker": {
|
"picker": {
|
||||||
"header": "Personalizări",
|
"header": "Personalizări",
|
||||||
"introduction": "Atributele per entitate. Particularizările adăugate/editate vor avea efect imediat. Particularizările eliminate vor avea efect atunci când entitatea este actualizată."
|
"introduction": "Atributele per entitate. Particularizările adăugate/editate vor avea efect imediat. Particularizările eliminate vor avea efect atunci când entitatea este actualizată."
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"include_link": "include customize.yaml",
|
||||||
|
"include_sentence": "Se pare că configurația dvs..yaml nu corespunde"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devices": {
|
"devices": {
|
||||||
@ -1172,7 +1195,7 @@
|
|||||||
"ignore": {
|
"ignore": {
|
||||||
"confirm_delete_ignore": "Acest lucru va face ca integrarea să apară din nou în integrările descoperite atunci când este descoperită. Acest lucru ar putea necesita o repornire sau să dureze ceva timp.",
|
"confirm_delete_ignore": "Acest lucru va face ca integrarea să apară din nou în integrările descoperite atunci când este descoperită. Acest lucru ar putea necesita o repornire sau să dureze ceva timp.",
|
||||||
"confirm_delete_ignore_title": "Încetați să ignorați {name} ?",
|
"confirm_delete_ignore_title": "Încetați să ignorați {name} ?",
|
||||||
"confirm_ignore": "Sunteți sigur că nu doriți să configurați această integrare? Puteți anula acest lucru făcând clic pe „Afișați integrări ignorate” din meniul de preaplin din partea dreaptă sus.",
|
"confirm_ignore": "Sunteți sigur că nu doriți să configurați această integrare? Puteți anula acest lucru făcând clic pe „Afișați integrări ignorate” din meniul overflow din partea dreaptă sus.",
|
||||||
"confirm_ignore_title": "Ignorați descoperirea {name} ?",
|
"confirm_ignore_title": "Ignorați descoperirea {name} ?",
|
||||||
"hide_ignored": "Ascundeți integrările ignorate",
|
"hide_ignored": "Ascundeți integrările ignorate",
|
||||||
"ignore": "Ignora",
|
"ignore": "Ignora",
|
||||||
@ -1194,6 +1217,7 @@
|
|||||||
"lovelace": {
|
"lovelace": {
|
||||||
"caption": "Panouri de bord Lovelace",
|
"caption": "Panouri de bord Lovelace",
|
||||||
"dashboards": {
|
"dashboards": {
|
||||||
|
"cant_edit_default": "Tabloul de bord standard Lovelace nu poate fi editat din UI. Îl puteți ascunde setând un alt tablou de bord ca implicit.",
|
||||||
"cant_edit_yaml": "Tablourile de bord definite în YAML nu pot fi editate din UI. Schimbați-le în configuration.yaml.",
|
"cant_edit_yaml": "Tablourile de bord definite în YAML nu pot fi editate din UI. Schimbați-le în configuration.yaml.",
|
||||||
"caption": "Tablouri de bord",
|
"caption": "Tablouri de bord",
|
||||||
"conf_mode": {
|
"conf_mode": {
|
||||||
@ -1207,13 +1231,13 @@
|
|||||||
"delete": "Șterge",
|
"delete": "Șterge",
|
||||||
"dismiss": "Închide",
|
"dismiss": "Închide",
|
||||||
"edit_dashboard": "Editează tabloul de bord",
|
"edit_dashboard": "Editează tabloul de bord",
|
||||||
"icon": "Pictograma barei laterale",
|
"icon": "Pictograma",
|
||||||
"new_dashboard": "Adăugați un nou tablou de bord",
|
"new_dashboard": "Adăugați un nou tablou de bord",
|
||||||
"remove_default": "Eliminare ca implicit pe acest dispozitiv",
|
"remove_default": "Eliminare ca implicit pe acest dispozitiv",
|
||||||
"require_admin": "Doar administrator",
|
"require_admin": "Doar administrator",
|
||||||
"set_default": "Setare ca implicită pe acest dispozitiv",
|
"set_default": "Setare ca implicită pe acest dispozitiv",
|
||||||
"show_sidebar": "Afișați în bara laterală",
|
"show_sidebar": "Afișați în bara laterală",
|
||||||
"title": "Titlul barei laterale",
|
"title": "Titlu",
|
||||||
"title_required": "Titlul este necesar.",
|
"title_required": "Titlul este necesar.",
|
||||||
"update": "Actualizare",
|
"update": "Actualizare",
|
||||||
"url": "Url",
|
"url": "Url",
|
||||||
@ -1229,7 +1253,7 @@
|
|||||||
"sidebar": "Afișați în bara laterală",
|
"sidebar": "Afișați în bara laterală",
|
||||||
"title": "Titlu"
|
"title": "Titlu"
|
||||||
},
|
},
|
||||||
"open": "Deschide tabloul de bord"
|
"open": "Deschide"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
@ -1313,6 +1337,7 @@
|
|||||||
},
|
},
|
||||||
"learn_more": "Aflați mai multe despre scene",
|
"learn_more": "Aflați mai multe despre scene",
|
||||||
"no_scenes": "Nu am putut găsi nici o scenă editabilă",
|
"no_scenes": "Nu am putut găsi nici o scenă editabilă",
|
||||||
|
"only_editable": "Numai scenele definite în scene.yaml sunt editabile.",
|
||||||
"pick_scene": "Alege scena pentru a edita",
|
"pick_scene": "Alege scena pentru a edita",
|
||||||
"show_info_scene": "Afișează informații despre scenă"
|
"show_info_scene": "Afișează informații despre scenă"
|
||||||
}
|
}
|
||||||
@ -1547,7 +1572,13 @@
|
|||||||
"developer-tools": {
|
"developer-tools": {
|
||||||
"tabs": {
|
"tabs": {
|
||||||
"events": {
|
"events": {
|
||||||
|
"alert_event_type": "Tipul de eveniment este un câmp obligatoriu",
|
||||||
"available_events": "Evenimente disponibile",
|
"available_events": "Evenimente disponibile",
|
||||||
|
"fire_event": "Declansare eveniment",
|
||||||
|
"listening_to": "Ascultand",
|
||||||
|
"start_listening": "Incepe sa asculti",
|
||||||
|
"stop_listening": "Nu mai asculta",
|
||||||
|
"subscribe_to": "Eveniment la care să vă abonați",
|
||||||
"title": "Evenimente"
|
"title": "Evenimente"
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
@ -1703,6 +1734,9 @@
|
|||||||
"history-graph": {
|
"history-graph": {
|
||||||
"description": "Fișa History Graph vă permite să afișați un grafic pentru fiecare dintre entitățile listate."
|
"description": "Fișa History Graph vă permite să afișați un grafic pentru fiecare dintre entitățile listate."
|
||||||
},
|
},
|
||||||
|
"iframe": {
|
||||||
|
"name": "Pagină web"
|
||||||
|
},
|
||||||
"light": {
|
"light": {
|
||||||
"description": "Cardul Light vă permite să schimbați luminozitatea luminii."
|
"description": "Cardul Light vă permite să schimbați luminozitatea luminii."
|
||||||
},
|
},
|
||||||
@ -1835,6 +1869,7 @@
|
|||||||
"title": "Entități neutilizate"
|
"title": "Entități neutilizate"
|
||||||
},
|
},
|
||||||
"views": {
|
"views": {
|
||||||
|
"confirm_delete": "Ștergeți vizualizarea?",
|
||||||
"confirm_delete_existing_cards": "Ștergerea acestei vizualizări va elimina și cardurile",
|
"confirm_delete_existing_cards": "Ștergerea acestei vizualizări va elimina și cardurile",
|
||||||
"confirm_delete_text": "Sigur doriți să ștergeți vizualizarea „{name}”?"
|
"confirm_delete_text": "Sigur doriți să ștergeți vizualizarea „{name}”?"
|
||||||
},
|
},
|
||||||
|
@ -473,11 +473,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "och",
|
||||||
"cancel": "Avbryt",
|
"cancel": "Avbryt",
|
||||||
"close": "Stäng",
|
"close": "Stäng",
|
||||||
"delete": "Radera",
|
"delete": "Radera",
|
||||||
"loading": "Läser in",
|
"loading": "Läser in",
|
||||||
|
"next": "Nästa",
|
||||||
"no": "Nej",
|
"no": "Nej",
|
||||||
|
"previous": "Föregående",
|
||||||
|
"refresh": "Uppdatera",
|
||||||
"save": "Spara",
|
"save": "Spara",
|
||||||
"successfully_deleted": "Har raderats",
|
"successfully_deleted": "Har raderats",
|
||||||
"successfully_saved": "Inställningar sparades",
|
"successfully_saved": "Inställningar sparades",
|
||||||
@ -736,6 +740,10 @@
|
|||||||
"triggered": "Utlöst {name}"
|
"triggered": "Utlöst {name}"
|
||||||
},
|
},
|
||||||
"panel": {
|
"panel": {
|
||||||
|
"calendar": {
|
||||||
|
"my_calendars": "Mina Kalendrar",
|
||||||
|
"today": "Idag"
|
||||||
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"advanced_mode": {
|
"advanced_mode": {
|
||||||
"hint_enable": "Saknas konfigurationsalternativ? Aktivera avancerat läge på",
|
"hint_enable": "Saknas konfigurationsalternativ? Aktivera avancerat läge på",
|
||||||
@ -838,6 +846,9 @@
|
|||||||
},
|
},
|
||||||
"label": "Enhet"
|
"label": "Enhet"
|
||||||
},
|
},
|
||||||
|
"not": {
|
||||||
|
"label": "Inte"
|
||||||
|
},
|
||||||
"numeric_state": {
|
"numeric_state": {
|
||||||
"above": "Över",
|
"above": "Över",
|
||||||
"below": "Under",
|
"below": "Under",
|
||||||
@ -1169,7 +1180,9 @@
|
|||||||
"edit_requires_storage": "Redigeraren är inaktiverad eftersom konfigurationen lagras i configuration.yaml.",
|
"edit_requires_storage": "Redigeraren är inaktiverad eftersom konfigurationen lagras i configuration.yaml.",
|
||||||
"elevation": "Höjd över havet",
|
"elevation": "Höjd över havet",
|
||||||
"elevation_meters": "meter",
|
"elevation_meters": "meter",
|
||||||
|
"external_url": "Extern URL",
|
||||||
"imperial_example": "Fahrenheit, pounds",
|
"imperial_example": "Fahrenheit, pounds",
|
||||||
|
"internal_url": "Intern URL",
|
||||||
"latitude": "Latitud",
|
"latitude": "Latitud",
|
||||||
"location_name": "Namn på din Home Assistant-installation",
|
"location_name": "Namn på din Home Assistant-installation",
|
||||||
"longitude": "Longitud",
|
"longitude": "Longitud",
|
||||||
@ -1236,6 +1249,7 @@
|
|||||||
},
|
},
|
||||||
"delete": "Ta bort",
|
"delete": "Ta bort",
|
||||||
"description": "Hantera anslutna enheter",
|
"description": "Hantera anslutna enheter",
|
||||||
|
"device_info": "Enhetsinformation",
|
||||||
"device_not_found": "Enheten hittades inte.",
|
"device_not_found": "Enheten hittades inte.",
|
||||||
"entities": {
|
"entities": {
|
||||||
"add_entities_lovelace": "Lägg till i Lovelace",
|
"add_entities_lovelace": "Lägg till i Lovelace",
|
||||||
@ -2095,21 +2109,27 @@
|
|||||||
"name": "Markdown"
|
"name": "Markdown"
|
||||||
},
|
},
|
||||||
"media-control": {
|
"media-control": {
|
||||||
|
"description": "Mediakontrolkortet används för att visa mediaspelarenheter på ett gränssnitt med lättanvända kontroller.",
|
||||||
"name": "Mediaspelare"
|
"name": "Mediaspelare"
|
||||||
},
|
},
|
||||||
"picture-elements": {
|
"picture-elements": {
|
||||||
|
"description": "Bildlementkortet är en av de mest mångsidiga typerna av kort. Korten låter dig placera ikoner eller text och till och med tjänster! På en bild baserad på koordinater.",
|
||||||
"name": "Bildelement"
|
"name": "Bildelement"
|
||||||
},
|
},
|
||||||
"picture-entity": {
|
"picture-entity": {
|
||||||
|
"description": "Bildentitetskortet visar en enhet i form av en bild. I stället för bilder från URL kan den också visa bilden av kameraenheter.",
|
||||||
"name": "Bildentitet"
|
"name": "Bildentitet"
|
||||||
},
|
},
|
||||||
"picture-glance": {
|
"picture-glance": {
|
||||||
|
"description": "Picture Glance-kortet visar en bild och motsvarande enhetstillstånd som en ikon. Enheterna på höger sida tillåter att växla åtgärder, andra visar dialogrutan för mer information.",
|
||||||
"name": "Bildblick"
|
"name": "Bildblick"
|
||||||
},
|
},
|
||||||
"picture": {
|
"picture": {
|
||||||
|
"description": "Bildkortet låter dig ställa in en bild som ska användas för att navigera till olika banor i ditt gränssnitt eller för att ringa en tjänst.",
|
||||||
"name": "Bild"
|
"name": "Bild"
|
||||||
},
|
},
|
||||||
"plant-status": {
|
"plant-status": {
|
||||||
|
"description": "Plant Status-kortet är för alla de härliga botanikerna där ute.",
|
||||||
"name": "Växtstatus"
|
"name": "Växtstatus"
|
||||||
},
|
},
|
||||||
"sensor": {
|
"sensor": {
|
||||||
@ -2125,6 +2145,7 @@
|
|||||||
"name": "Termostat"
|
"name": "Termostat"
|
||||||
},
|
},
|
||||||
"vertical-stack": {
|
"vertical-stack": {
|
||||||
|
"description": "Med Vertical Stack-kortet kan du gruppera flera kort så att de alltid sitter i samma kolumn.",
|
||||||
"name": "Vertikal trave"
|
"name": "Vertikal trave"
|
||||||
},
|
},
|
||||||
"weather-forecast": {
|
"weather-forecast": {
|
||||||
|
@ -473,6 +473,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"and": "及",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"close": "關閉",
|
"close": "關閉",
|
||||||
"delete": "刪除",
|
"delete": "刪除",
|
||||||
@ -1180,7 +1181,9 @@
|
|||||||
"edit_requires_storage": "由於 configuration.yaml 內已儲存設定,編輯功能已關閉。",
|
"edit_requires_storage": "由於 configuration.yaml 內已儲存設定,編輯功能已關閉。",
|
||||||
"elevation": "海拔",
|
"elevation": "海拔",
|
||||||
"elevation_meters": "公尺",
|
"elevation_meters": "公尺",
|
||||||
|
"external_url": "外部 URL",
|
||||||
"imperial_example": "華氏、磅",
|
"imperial_example": "華氏、磅",
|
||||||
|
"internal_url": "內部 URL",
|
||||||
"latitude": "緯度",
|
"latitude": "緯度",
|
||||||
"location_name": "Home Assistant 安裝名稱",
|
"location_name": "Home Assistant 安裝名稱",
|
||||||
"longitude": "經度",
|
"longitude": "經度",
|
||||||
|
@ -2613,10 +2613,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
|
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
|
||||||
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
|
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
|
||||||
|
|
||||||
"@thomasloven/round-slider@0.3.7":
|
"@thomasloven/round-slider@0.4.1":
|
||||||
version "0.3.7"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@thomasloven/round-slider/-/round-slider-0.3.7.tgz#3f8f16f90296e1062d932f5ea8ebf244aa7e58f6"
|
resolved "https://registry.yarnpkg.com/@thomasloven/round-slider/-/round-slider-0.4.1.tgz#42ddd28abb25c378dce35c4c0ccdd72ea63b3b25"
|
||||||
integrity sha512-rIdEvyLt4YNahpAp1Ibk7qOn9mdgP3Qo2gORyojHqaBTV+t29N1zlTo/G0SbKTLDUtSGDslQWD3/nAdD3yBOYA==
|
integrity sha512-Z6jrXG5vowKQkOwdsyGDLi8ZT9lUfcYjFsaQe8djhDE8+x41GYp5lkJ4uCwT787A8WcODbtQfYtuxPOlZcizTw==
|
||||||
dependencies:
|
dependencies:
|
||||||
lit-element "^2.2.1"
|
lit-element "^2.2.1"
|
||||||
|
|
||||||
|