diff --git a/src/dialogs/more-info/const.ts b/src/dialogs/more-info/const.ts index 7c77de80cea1..b0795eb5381f 100644 --- a/src/dialogs/more-info/const.ts +++ b/src/dialogs/more-info/const.ts @@ -33,6 +33,7 @@ export const DOMAINS_WITH_NEW_MORE_INFO = [ "switch", "valve", "water_heater", + "weather", ]; /** Domains with full height more info dialog */ export const DOMAINS_FULL_HEIGHT_MORE_INFO = ["update"]; diff --git a/src/dialogs/more-info/controls/more-info-weather.ts b/src/dialogs/more-info/controls/more-info-weather.ts index d881d7f6b83a..edf30a2baf72 100644 --- a/src/dialogs/more-info/controls/more-info-weather.ts +++ b/src/dialogs/more-info/controls/more-info-weather.ts @@ -1,18 +1,13 @@ import "@material/mwc-tab"; import "@material/mwc-tab-bar"; -import { - mdiEye, - mdiGauge, - mdiThermometer, - mdiWaterPercent, - mdiWeatherWindy, -} from "@mdi/js"; -import type { PropertyValues } from "lit"; +import { mdiEye, mdiGauge, mdiWaterPercent, mdiWeatherWindy } from "@mdi/js"; +import type { CSSResultGroup, PropertyValues } from "lit"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; -import { formatDateWeekdayDay } from "../../../common/datetime/format_date"; -import { formatTimeWeekday } from "../../../common/datetime/format_time"; +import { formatDateWeekdayShort } from "../../../common/datetime/format_date"; +import { formatTime } from "../../../common/datetime/format_time"; +import { formatNumber } from "../../../common/number/format_number"; import "../../../components/ha-svg-icon"; import type { ForecastEvent, @@ -23,11 +18,16 @@ import { getDefaultForecastType, getForecast, getSupportedForecastTypes, + getSecondaryWeatherAttribute, + getWeatherStateIcon, + getWeatherUnit, getWind, subscribeForecast, - weatherIcons, + weatherSVGStyles, } from "../../../data/weather"; import type { HomeAssistant } from "../../../types"; +import "../../../components/ha-relative-time"; +import "../../../components/ha-state-icon"; @customElement("more-info-weather") class MoreInfoWeather extends LitElement { @@ -137,23 +137,90 @@ class MoreInfoWeather extends LitElement { const hourly = forecastData?.type === "hourly"; const dayNight = forecastData?.type === "twice_daily"; + const weatherStateIcon = getWeatherStateIcon(this.stateObj.state, this); + return html` - ${this._showValue(this.stateObj.attributes.temperature) - ? html` -
- -
- ${this.hass.localize("ui.card.weather.attributes.temperature")} -
-
- ${this.hass.formatEntityAttributeValue( - this.stateObj, - "temperature" - )} -
+
+
+ ${weatherStateIcon || + html` + + `} +
+
+
+
+ ${this.hass.formatEntityState(this.stateObj)}
- ` - : ""} +
+ + +
+
+ + ${this.hass.localize( + "ui.dialogs.more_info_control.last_changed" + )}: + + +
+
+ + ${this.hass.localize( + "ui.dialogs.more_info_control.last_updated" + )}: + + +
+
+
+
+
+
+
+ ${this.stateObj.attributes.temperature !== undefined && + this.stateObj.attributes.temperature !== null + ? html` + ${formatNumber( + this.stateObj.attributes.temperature, + this.hass.locale + )} ${getWeatherUnit( + this.hass.config, + this.stateObj, + "temperature" + )} + ` + : nothing} +
+
+ ${getSecondaryWeatherAttribute( + this.hass, + this.stateObj, + forecast! + )} +
+
+
+
${this._showValue(this.stateObj.attributes.pressure) ? html`
@@ -169,7 +236,7 @@ class MoreInfoWeather extends LitElement {
` - : ""} + : nothing} ${this._showValue(this.stateObj.attributes.humidity) ? html`
@@ -185,7 +252,7 @@ class MoreInfoWeather extends LitElement {
` - : ""} + : nothing} ${this._showValue(this.stateObj.attributes.wind_speed) ? html`
@@ -203,7 +270,7 @@ class MoreInfoWeather extends LitElement {
` - : ""} + : nothing} ${this._showValue(this.stateObj.attributes.visibility) ? html`
@@ -219,7 +286,7 @@ class MoreInfoWeather extends LitElement {
` - : ""} + : nothing} ${forecast ? html`
@@ -242,76 +309,90 @@ class MoreInfoWeather extends LitElement { )} ` : nothing} - ${forecast.map((item) => - this._showValue(item.templow) || this._showValue(item.temperature) - ? html`
- ${item.condition - ? html` - - ` - : ""} -
- ${dayNight - ? html` - ${formatDateWeekdayDay( - new Date(item.datetime), - this.hass!.locale, - this.hass!.config - )} - (${item.is_daytime !== false - ? this.hass!.localize("ui.card.weather.day") - : this.hass!.localize("ui.card.weather.night")}) - ` - : hourly +
+ ${forecast.map((item) => + this._showValue(item.templow) || + this._showValue(item.temperature) + ? html` +
+
+ ${dayNight + ? html` + ${formatDateWeekdayShort( + new Date(item.datetime), + this.hass!.locale, + this.hass!.config + )} +
+ ${item.is_daytime !== false + ? this.hass!.localize("ui.card.weather.day") + : this.hass!.localize( + "ui.card.weather.night" + )}
+
+ ` + : hourly + ? html` + ${formatTime( + new Date(item.datetime), + this.hass!.locale, + this.hass!.config + )} + ` + : html` + ${formatDateWeekdayShort( + new Date(item.datetime), + this.hass!.locale, + this.hass!.config + )} + `} +
+ ${this._showValue(item.condition) ? html` - ${formatTimeWeekday( - new Date(item.datetime), - this.hass!.locale, - this.hass!.config - )} +
+ ${getWeatherStateIcon( + item.condition!, + this, + !( + item.is_daytime || + item.is_daytime === undefined + ) + )} +
` - : html` - ${formatDateWeekdayDay( - new Date(item.datetime), - this.hass!.locale, - this.hass!.config - )} - `} -
-
- ${this._showValue(item.templow) - ? this.hass.formatEntityAttributeValue( - this.stateObj!, - "templow", - item.templow - ) - : hourly - ? "" - : "—"} -
-
- ${this._showValue(item.temperature) - ? this.hass.formatEntityAttributeValue( - this.stateObj!, - "temperature", - item.temperature - ) - : "—"} -
-
` - : "" - )} + : nothing} +
+ ${this._showValue(item.temperature) + ? html`${formatNumber( + item.temperature, + this.hass!.locale + )}°` + : "—"} +
+
+ ${this._showValue(item.templow) + ? html`${formatNumber( + item.templow!, + this.hass!.locale + )}°` + : hourly + ? nothing + : "—"} +
+
+ ` + : nothing + )} +
` - : ""} + : nothing} ${this.stateObj.attributes.attribution ? html`
${this.stateObj.attributes.attribution}
` - : ""} + : nothing} `; } @@ -321,56 +402,186 @@ class MoreInfoWeather extends LitElement { ]; } - static styles = css` - ha-svg-icon { - color: var(--paper-item-icon-color); - margin-left: 8px; - margin-inline-start: 8px; - margin-inline-end: initial; - } + static get styles(): CSSResultGroup { + return [ + weatherSVGStyles, + css` + ha-svg-icon { + color: var(--paper-item-icon-color); + margin-left: 8px; + margin-inline-start: 8px; + margin-inline-end: initial; + } - mwc-tab-bar { - margin-bottom: 4px; - } + mwc-tab-bar { + margin-bottom: 4px; + } - .section { - margin: 16px 0 8px 0; - font-size: 1.2em; - } + .section { + margin: 16px 0 8px 0; + font-size: 1.2em; + } - .flex { - display: flex; - height: 32px; - align-items: center; - } - .flex > div:last-child { - direction: ltr; - } + .flex { + display: flex; + height: 32px; + align-items: center; + } + .flex > div:last-child { + direction: ltr; + } - .main { - flex: 1; - margin-left: 24px; - margin-inline-start: 24px; - margin-inline-end: initial; - } + .main { + flex: 1; + margin-left: 24px; + margin-inline-start: 24px; + margin-inline-end: initial; + } - .temp, - .templow { - min-width: 48px; - text-align: right; - direction: ltr; - } + .attribution { + text-align: center; + margin-top: 16px; + } - .templow { - margin: 0 16px; - color: var(--secondary-text-color); - } + .time-ago, + .attribute { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } - .attribution { - color: var(--secondary-text-color); - text-align: center; - } - `; + .attribution, + .templow, + .daynight, + .attribute, + .time-ago { + color: var(--secondary-text-color); + } + + .content { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; + } + + .icon-image { + display: flex; + align-items: center; + min-width: 64px; + margin-right: 16px; + margin-inline-end: 16px; + margin-inline-start: initial; + } + + .icon-image > * { + flex: 0 0 64px; + height: 64px; + } + + .weather-icon { + --mdc-icon-size: 64px; + } + + .info { + display: flex; + justify-content: space-between; + flex-grow: 1; + overflow: hidden; + } + + .temp-attribute { + text-align: var(--float-end); + } + + .temp-attribute .temp { + position: relative; + margin-right: 24px; + direction: ltr; + } + + .temp-attribute .temp span { + position: absolute; + font-size: 24px; + top: 1px; + } + + .state, + .temp-attribute .temp { + font-size: 28px; + line-height: 1.2; + } + + .attribute { + font-size: 14px; + line-height: 1; + } + + .name-state { + overflow: hidden; + padding-right: 12px; + padding-inline-end: 12px; + padding-inline-start: initial; + width: 100%; + } + + .state { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .forecast { + display: flex; + justify-content: space-around; + padding: 16px; + padding-bottom: 0px; + overflow-x: auto; + scrollbar-color: var(--scrollbar-thumb-color) transparent; + scrollbar-width: thin; + mask-image: linear-gradient( + 90deg, + transparent 0%, + black 5%, + black 94%, + transparent 100% + ); + } + + .forecast > div { + text-align: center; + padding: 0 10px; + } + + .forecast .icon, + .forecast .temp { + margin: 4px 0; + } + + .forecast .temp { + font-size: 16px; + } + + .forecast-image-icon { + padding-top: 4px; + padding-bottom: 4px; + display: flex; + justify-content: center; + } + + .forecast-image-icon > * { + width: 40px; + height: 40px; + --mdc-icon-size: 40px; + } + + .forecast-icon { + --mdc-icon-size: 40px; + } + `, + ]; + } private _showValue(item: number | string | undefined): boolean { return typeof item !== "undefined" && item !== null;