mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Update more-info dialog layout for weather entities (#22818)
* Update weather more-info style * Cleanup unused var * Use badges for attributes * Remove unnecessary flex class * CSS cleanup * Wrap badges * Revert "Cleanup unused var" This reverts commit 89ab0f6ad05e1e669b84e69f4c263e3d302794f2. * Revert badges for attributes * Scroll long forecasts * Use nothing instead of empty strings * Cleanup
This commit is contained in:
parent
35face602b
commit
e9fef1f873
@ -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"];
|
||||
|
@ -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`
|
||||
<div class="flex">
|
||||
<ha-svg-icon .path=${mdiThermometer}></ha-svg-icon>
|
||||
<div class="main">
|
||||
${this.hass.localize("ui.card.weather.attributes.temperature")}
|
||||
<div class="content">
|
||||
<div class="icon-image">
|
||||
${weatherStateIcon ||
|
||||
html`
|
||||
<ha-state-icon
|
||||
class="weather-icon"
|
||||
.stateObj=${this.stateObj}
|
||||
.hass=${this.hass}
|
||||
></ha-state-icon>
|
||||
`}
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name-state">
|
||||
<div class="state">
|
||||
${this.hass.formatEntityState(this.stateObj)}
|
||||
</div>
|
||||
<div class="time-ago">
|
||||
<ha-relative-time
|
||||
id="last_changed"
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
<simple-tooltip animation-delay="0" for="last_changed">
|
||||
<div>
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
<div class="row">
|
||||
<span class="column-name">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_changed"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_updated"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_updated}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
</div>
|
||||
</simple-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="temp-attribute">
|
||||
<div class="temp">
|
||||
${this.stateObj.attributes.temperature !== undefined &&
|
||||
this.stateObj.attributes.temperature !== null
|
||||
? html`
|
||||
${formatNumber(
|
||||
this.stateObj.attributes.temperature,
|
||||
this.hass.locale
|
||||
)} <span
|
||||
>${getWeatherUnit(
|
||||
this.hass.config,
|
||||
this.stateObj,
|
||||
"temperature"
|
||||
)}</span
|
||||
>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
<div class="attribute">
|
||||
${getSecondaryWeatherAttribute(
|
||||
this.hass,
|
||||
this.stateObj,
|
||||
forecast!
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
${this._showValue(this.stateObj.attributes.pressure)
|
||||
? html`
|
||||
<div class="flex">
|
||||
@ -169,7 +236,7 @@ class MoreInfoWeather extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
${this._showValue(this.stateObj.attributes.humidity)
|
||||
? html`
|
||||
<div class="flex">
|
||||
@ -185,7 +252,7 @@ class MoreInfoWeather extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
${this._showValue(this.stateObj.attributes.wind_speed)
|
||||
? html`
|
||||
<div class="flex">
|
||||
@ -203,7 +270,7 @@ class MoreInfoWeather extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
${this._showValue(this.stateObj.attributes.visibility)
|
||||
? html`
|
||||
<div class="flex">
|
||||
@ -219,7 +286,7 @@ class MoreInfoWeather extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
${forecast
|
||||
? html`
|
||||
<div class="section">
|
||||
@ -242,76 +309,90 @@ class MoreInfoWeather extends LitElement {
|
||||
)}
|
||||
</mwc-tab-bar>`
|
||||
: nothing}
|
||||
<div class="forecast">
|
||||
${forecast.map((item) =>
|
||||
this._showValue(item.templow) || this._showValue(item.temperature)
|
||||
? html`<div class="flex">
|
||||
${item.condition
|
||||
this._showValue(item.templow) ||
|
||||
this._showValue(item.temperature)
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.path=${weatherIcons[item.condition]}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: ""}
|
||||
<div class="main">
|
||||
<div>
|
||||
<div>
|
||||
${dayNight
|
||||
? html`
|
||||
${formatDateWeekdayDay(
|
||||
${formatDateWeekdayShort(
|
||||
new Date(item.datetime),
|
||||
this.hass!.locale,
|
||||
this.hass!.config
|
||||
)}
|
||||
(${item.is_daytime !== false
|
||||
<div class="daynight">
|
||||
${item.is_daytime !== false
|
||||
? this.hass!.localize("ui.card.weather.day")
|
||||
: this.hass!.localize("ui.card.weather.night")})
|
||||
: this.hass!.localize(
|
||||
"ui.card.weather.night"
|
||||
)}<br />
|
||||
</div>
|
||||
`
|
||||
: hourly
|
||||
? html`
|
||||
${formatTimeWeekday(
|
||||
${formatTime(
|
||||
new Date(item.datetime),
|
||||
this.hass!.locale,
|
||||
this.hass!.config
|
||||
)}
|
||||
`
|
||||
: html`
|
||||
${formatDateWeekdayDay(
|
||||
${formatDateWeekdayShort(
|
||||
new Date(item.datetime),
|
||||
this.hass!.locale,
|
||||
this.hass!.config
|
||||
)}
|
||||
`}
|
||||
</div>
|
||||
<div class="templow">
|
||||
${this._showValue(item.templow)
|
||||
? this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"templow",
|
||||
item.templow
|
||||
${this._showValue(item.condition)
|
||||
? html`
|
||||
<div class="forecast-image-icon">
|
||||
${getWeatherStateIcon(
|
||||
item.condition!,
|
||||
this,
|
||||
!(
|
||||
item.is_daytime ||
|
||||
item.is_daytime === undefined
|
||||
)
|
||||
: hourly
|
||||
? ""
|
||||
: "—"}
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
<div class="temp">
|
||||
${this._showValue(item.temperature)
|
||||
? this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"temperature",
|
||||
item.temperature
|
||||
)
|
||||
? html`${formatNumber(
|
||||
item.temperature,
|
||||
this.hass!.locale
|
||||
)}°`
|
||||
: "—"}
|
||||
</div>
|
||||
</div>`
|
||||
: ""
|
||||
)}
|
||||
<div class="templow">
|
||||
${this._showValue(item.templow)
|
||||
? html`${formatNumber(
|
||||
item.templow!,
|
||||
this.hass!.locale
|
||||
)}°`
|
||||
: hourly
|
||||
? nothing
|
||||
: "—"}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
: nothing
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
${this.stateObj.attributes.attribution
|
||||
? html`
|
||||
<div class="attribution">
|
||||
${this.stateObj.attributes.attribution}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
@ -321,7 +402,10 @@ class MoreInfoWeather extends LitElement {
|
||||
];
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
weatherSVGStyles,
|
||||
css`
|
||||
ha-svg-icon {
|
||||
color: var(--paper-item-icon-color);
|
||||
margin-left: 8px;
|
||||
@ -354,23 +438,150 @@ class MoreInfoWeather extends LitElement {
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
|
||||
.temp,
|
||||
.templow {
|
||||
min-width: 48px;
|
||||
text-align: right;
|
||||
.attribution {
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.time-ago,
|
||||
.attribute {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.templow {
|
||||
margin: 0 16px;
|
||||
color: var(--secondary-text-color);
|
||||
.temp-attribute .temp span {
|
||||
position: absolute;
|
||||
font-size: 24px;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.attribution {
|
||||
color: var(--secondary-text-color);
|
||||
text-align: center;
|
||||
.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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user