Weather Card/Row: Weather Icons as SVG, Themeable, user definable (#5736)
* SVG * no-unneeded-ternary * declared ubnused * moving stuff around * Few updates * All svgs in | update row * No slots * Remove public/static/images/weather * style for user defined * few updates to missing fils * classes * wind color
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 |
|
@ -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 = {
|
||||
"clear-night": "/static/images/weather/night.png",
|
||||
cloudy: "/static/images/weather/cloudy.png",
|
||||
fog: "/static/images/weather/cloudy.png",
|
||||
lightning: "/static/images/weather/lightning.png",
|
||||
"lightning-rainy": "/static/images/weather/lightning-rainy.png",
|
||||
partlycloudy: "/static/images/weather/partly-cloudy.png",
|
||||
pouring: "/static/images/weather/pouring.png",
|
||||
rainy: "/static/images/weather/rainy.png",
|
||||
hail: "/static/images/weather/rainy.png",
|
||||
snowy: "/static/images/weather/snowy.png",
|
||||
"snowy-rainy": "/static/images/weather/snowy.png",
|
||||
sunny: "/static/images/weather/sunny.png",
|
||||
windy: "/static/images/weather/windy.png",
|
||||
"windy-variant": "/static/images/weather/windy.png",
|
||||
};
|
||||
import type { HomeAssistant, WeatherEntity } from "../types";
|
||||
|
||||
export const weatherSVGs = new Set<string>([
|
||||
"clear-night",
|
||||
"cloudy",
|
||||
"fog",
|
||||
"lightning",
|
||||
"lightning-rainy",
|
||||
"partlycloudy",
|
||||
"pouring",
|
||||
"rainy",
|
||||
"hail",
|
||||
"snowy",
|
||||
"snowy-rainy",
|
||||
"sunny",
|
||||
"windy",
|
||||
"windy-variant",
|
||||
]);
|
||||
|
||||
export const weatherIcons = {
|
||||
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 = [
|
||||
"N",
|
||||
"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;
|
||||
};
|
||||
|
|
|
@ -21,16 +21,16 @@ import { UNAVAILABLE } from "../../../data/entity";
|
|||
import {
|
||||
getSecondaryWeatherAttribute,
|
||||
getWeatherUnit,
|
||||
weatherIcons,
|
||||
weatherImages,
|
||||
getWeatherStateIcon,
|
||||
weatherSVGStyles,
|
||||
} from "../../../data/weather";
|
||||
import { HomeAssistant, WeatherEntity } from "../../../types";
|
||||
import type { HomeAssistant, WeatherEntity } from "../../../types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-warning";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { WeatherForecastCardConfig } from "./types";
|
||||
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import type { WeatherForecastCardConfig } from "./types";
|
||||
import { installResizeObserver } from "../common/install-resize-observer";
|
||||
|
||||
const DAY_IN_MILLISECONDS = 86400000;
|
||||
|
@ -165,6 +165,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||
hourly = timeDiff < DAY_IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
const weatherStateIcon = getWeatherStateIcon(stateObj.state, this);
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
@action=${this._handleAction}
|
||||
|
@ -173,19 +175,13 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||
>
|
||||
<div class="content">
|
||||
<div class="icon-image">
|
||||
${stateObj.state in weatherImages
|
||||
? html`
|
||||
<img
|
||||
class="weather-image"
|
||||
src="${weatherImages[stateObj.state]}"
|
||||
/>
|
||||
`
|
||||
: html`
|
||||
<ha-icon
|
||||
class="weather-icon"
|
||||
.icon=${weatherIcons[stateObj.state] || stateIcon(stateObj)}
|
||||
></ha-icon>
|
||||
`}
|
||||
${weatherStateIcon ||
|
||||
html`
|
||||
<ha-icon
|
||||
class="weather-icon"
|
||||
.icon=${stateIcon(stateObj)}
|
||||
></ha-icon>
|
||||
`}
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name-state">
|
||||
|
@ -251,21 +247,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||
${item.condition !== undefined && item.condition !== null
|
||||
? html`
|
||||
<div class="forecast-image-icon">
|
||||
${item.condition in weatherImages
|
||||
? 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>
|
||||
`
|
||||
: ""}
|
||||
${getWeatherStateIcon(item.condition, this)}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
|
@ -334,201 +316,205 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
|||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
weatherSVGStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
ha-card {
|
||||
cursor: pointer;
|
||||
padding: 16px;
|
||||
}
|
||||
ha-card {
|
||||
cursor: pointer;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 64px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
.icon-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 64px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.weather-image,
|
||||
.weather-icon {
|
||||
flex: 0 0 64px;
|
||||
}
|
||||
.icon-image > * {
|
||||
flex: 0 0 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.weather-icon {
|
||||
--mdc-icon-size: 64px;
|
||||
}
|
||||
.weather-icon {
|
||||
--mdc-icon-size: 64px;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.temp-attribute {
|
||||
text-align: right;
|
||||
}
|
||||
.temp-attribute {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.temp-attribute .temp {
|
||||
position: relative;
|
||||
margin-right: 24px;
|
||||
}
|
||||
.temp-attribute .temp {
|
||||
position: relative;
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
.temp-attribute .temp span {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
top: 1px;
|
||||
}
|
||||
.temp-attribute .temp span {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.state,
|
||||
.temp-attribute .temp {
|
||||
font-size: 28px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.name,
|
||||
.temp-attribute .temp {
|
||||
font-size: 28px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.name,
|
||||
.attribute {
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
}
|
||||
.state,
|
||||
.attribute {
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.name-state {
|
||||
overflow: hidden;
|
||||
padding-right: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
.name-state {
|
||||
overflow: hidden;
|
||||
padding-right: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.name,
|
||||
.state {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.name,
|
||||
.state {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.attribute {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.attribute {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.forecast {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding-top: 16px;
|
||||
}
|
||||
.forecast {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.forecast > div {
|
||||
text-align: center;
|
||||
}
|
||||
.forecast > div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.forecast .icon,
|
||||
.forecast .temp {
|
||||
margin: 4px 0;
|
||||
}
|
||||
.forecast .icon,
|
||||
.forecast .temp {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.forecast .temp {
|
||||
font-size: 16px;
|
||||
}
|
||||
.forecast .temp {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.forecast-image-icon {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.forecast-image-icon {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.forecast-image {
|
||||
width: 40px;
|
||||
}
|
||||
.forecast-image-icon > * {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.forecast-icon {
|
||||
--mdc-icon-size: 40px;
|
||||
}
|
||||
.forecast-icon {
|
||||
--mdc-icon-size: 40px;
|
||||
}
|
||||
|
||||
.attribute,
|
||||
.templow,
|
||||
.name {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.attribute,
|
||||
.templow,
|
||||
.state {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
.unavailable {
|
||||
height: 100px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.unavailable {
|
||||
height: 100px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ============= NARROW ============= */
|
||||
/* ============= NARROW ============= */
|
||||
|
||||
:host([narrow]) .icon-image {
|
||||
min-width: 52px;
|
||||
}
|
||||
:host([narrow]) .icon-image {
|
||||
min-width: 52px;
|
||||
}
|
||||
|
||||
:host([narrow]) .weather-image {
|
||||
flex: 0 0 52px;
|
||||
width: 52px;
|
||||
}
|
||||
:host([narrow]) .weather-image {
|
||||
flex: 0 0 52px;
|
||||
width: 52px;
|
||||
}
|
||||
|
||||
:host([narrow]) .weather-icon {
|
||||
--mdc-icon-size: 52px;
|
||||
}
|
||||
:host([narrow]) .weather-icon {
|
||||
--mdc-icon-size: 52px;
|
||||
}
|
||||
|
||||
:host([narrow]) .state,
|
||||
:host([narrow]) .temp-attribute .temp {
|
||||
font-size: 22px;
|
||||
}
|
||||
:host([narrow]) .name,
|
||||
:host([narrow]) .temp-attribute .temp {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
:host([narrow]) .temp-attribute .temp {
|
||||
margin-right: 16px;
|
||||
}
|
||||
:host([narrow]) .temp-attribute .temp {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
:host([narrow]) .temp span {
|
||||
top: 1px;
|
||||
font-size: 16px;
|
||||
}
|
||||
:host([narrow]) .temp span {
|
||||
top: 1px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* ============= VERY NARROW ============= */
|
||||
/* ============= VERY NARROW ============= */
|
||||
|
||||
:host([veryNarrow]) .name,
|
||||
:host([veryNarrow]) .attribute {
|
||||
display: none;
|
||||
}
|
||||
:host([veryNarrow]) .state,
|
||||
:host([veryNarrow]) .attribute {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([veryNarrow]) .info {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
:host([veryNarrow]) .info {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
:host([veryNarrow]) .name-state {
|
||||
padding-right: 0;
|
||||
}
|
||||
:host([veryNarrow]) .name-state {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
/* ============= VERY VERY NARROW ============= */
|
||||
/* ============= VERY VERY NARROW ============= */
|
||||
|
||||
:host([veryVeryNarrow]) .info {
|
||||
padding-top: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
:host([veryVeryNarrow]) .info {
|
||||
padding-top: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:host([veryVeryNarrow]) .content {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
:host([veryVeryNarrow]) .content {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:host([veryVeryNarrow]) .icon-image {
|
||||
margin-right: 0;
|
||||
}
|
||||
`;
|
||||
:host([veryVeryNarrow]) .icon-image {
|
||||
margin-right: 0;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,21 +8,32 @@ import {
|
|||
PropertyValues,
|
||||
TemplateResult,
|
||||
} 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 "../../../components/entity/state-badge";
|
||||
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
||||
import {
|
||||
getSecondaryWeatherAttribute,
|
||||
getWeatherUnit,
|
||||
weatherIcons,
|
||||
weatherImages,
|
||||
getWeatherStateIcon,
|
||||
weatherSVGStyles,
|
||||
} from "../../../data/weather";
|
||||
import { HomeAssistant, WeatherEntity } from "../../../types";
|
||||
import { EntitiesCardEntityConfig } from "../cards/types";
|
||||
import type { HomeAssistant, WeatherEntity } from "../../../types";
|
||||
import type { EntitiesCardEntityConfig } from "../cards/types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
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")
|
||||
class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
||||
|
@ -61,48 +72,126 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
|||
`;
|
||||
}
|
||||
|
||||
const weatherRowConfig = {
|
||||
...this._config,
|
||||
icon: weatherIcons[stateObj.state],
|
||||
image: weatherImages[stateObj.state],
|
||||
};
|
||||
const pointer =
|
||||
(this._config.tap_action && this._config.tap_action.action !== "none") ||
|
||||
(this._config.entity &&
|
||||
!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(this._config.entity)));
|
||||
|
||||
const weatherStateIcon = getWeatherStateIcon(stateObj.state, this);
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${weatherRowConfig}>
|
||||
<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 class="secondary">
|
||||
${getSecondaryWeatherAttribute(this.hass!, stateObj)}
|
||||
</div>
|
||||
<div
|
||||
class="icon-image${classMap({
|
||||
pointer,
|
||||
})}"
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: hasAction(this._config!.hold_action),
|
||||
hasDoubleClick: hasAction(this._config!.double_tap_action),
|
||||
})}
|
||||
tabindex=${ifDefined(pointer ? "0" : undefined)}
|
||||
>
|
||||
${weatherStateIcon ||
|
||||
html`
|
||||
<ha-icon class="weather-icon" .icon=${stateIcon(stateObj)}></ha-icon>
|
||||
`}
|
||||
</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>
|
||||
</hui-generic-entity-row>
|
||||
<div class="secondary">
|
||||
${getSecondaryWeatherAttribute(this.hass!, stateObj)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.attributes {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: right;
|
||||
}
|
||||
private _handleAction(ev: ActionHandlerEvent) {
|
||||
handleAction(this, this.hass!, this._config!, ev.detail.action!);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
`;
|
||||
static get styles(): CSSResult[] {
|
||||
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);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|