Use resize controller for weather card

This commit is contained in:
Paul Bottein 2024-02-15 09:59:12 +01:00
parent 8136cc8008
commit af6342b917
No known key found for this signature in database
1 changed files with 38 additions and 73 deletions

View File

@ -1,3 +1,4 @@
import { ResizeController } from "@lit-labs/observers/resize-controller";
import {
CSSResultGroup,
LitElement,
@ -14,7 +15,6 @@ import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_elemen
import { computeStateName } from "../../../common/entity/compute_state_name";
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
import { formatNumber } from "../../../common/number/format_number";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-card";
import "../../../components/ha-svg-icon";
import { UNAVAILABLE } from "../../../data/entity";
@ -31,7 +31,6 @@ import {
weatherAttrIcons,
weatherSVGStyles,
} from "../../../data/weather";
import { loadPolyfillIfNeeded } from "../../../resources/resize-observer.polyfill";
import type { HomeAssistant } from "../../../types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { findEntities } from "../common/find-entities";
@ -75,10 +74,25 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
@state() private _subscribed?: Promise<() => void>;
// @todo Consider reworking to eliminate need for attribute since it is manipulated internally
@property({ type: Boolean, reflect: true }) public veryVeryNarrow = false;
private _sizeController = new ResizeController(this, {
callback: (entries) => {
const width = entries[0]?.contentRect.width;
if (width < 245) {
return "very-very-narrow";
}
if (width < 300) {
return "very-narrow";
}
if (width < 375) {
return "narrow";
}
return "regular";
},
});
private _resizeObserver?: ResizeObserver;
protected firstUpdated(): void {
this._sizeController.observe(this.shadowRoot!.querySelector("ha-card")!);
}
private _needForecastSubscription() {
return (
@ -119,14 +133,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
if (this.hasUpdated && this._config && this.hass) {
this._subscribeForecastEvents();
}
this.updateComplete.then(() => this._attachObserver());
}
public disconnectedCallback(): void {
super.disconnectedCallback();
if (this._resizeObserver) {
this._resizeObserver.disconnect();
}
this._unsubscribeForecastEvents();
}
@ -160,16 +170,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
);
}
public willUpdate(): void {
if (!this.hasUpdated) {
this._measureCard();
}
}
protected firstUpdated(): void {
this._attachObserver();
}
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
if (!this._config || !this.hass) {
@ -227,7 +227,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
);
const forecast =
this._config?.show_forecast !== false && forecastData?.forecast?.length
? forecastData.forecast.slice(0, this.veryVeryNarrow ? 3 : 5)
? forecastData.forecast.slice(
0,
this._sizeController.value === "very-very-narrow" ? 3 : 5
)
: undefined;
const weather = !forecast || this._config?.show_current !== false;
@ -239,6 +242,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return html`
<ha-card
class=${ifDefined(this._sizeController.value)}
@action=${this._handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(this._config!.hold_action),
@ -417,45 +421,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
handleAction(this, this.hass!, this._config!, ev.detail.action!);
}
private async _attachObserver(): Promise<void> {
if (!this._resizeObserver) {
await loadPolyfillIfNeeded();
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.isConnected) {
return;
}
const card = this.shadowRoot!.querySelector("ha-card");
// If we show an error or warning there is no ha-card
if (!card) {
return;
}
if (card.offsetWidth < 375) {
this.setAttribute("narrow", "");
} else {
this.removeAttribute("narrow");
}
if (card.offsetWidth < 300) {
this.setAttribute("verynarrow", "");
} else {
this.removeAttribute("verynarrow");
}
this.veryVeryNarrow = card.offsetWidth < 245;
}
private _showValue(item?: any): boolean {
return typeof item !== "undefined" && item !== null;
}
@ -614,48 +579,48 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
/* ============= NARROW ============= */
:host([narrow]) .icon-image {
[class*="narrow"] .icon-image {
min-width: 52px;
}
:host([narrow]) .weather-image {
[class*="narrow"] .weather-image {
flex: 0 0 52px;
width: 52px;
}
:host([narrow]) .icon-image .weather-icon {
[class*="narrow"] .icon-image .weather-icon {
--mdc-icon-size: 52px;
}
:host([narrow]) .state,
:host([narrow]) .temp-attribute .temp {
[class*="narrow"] .state,
[class*="narrow"] .temp-attribute .temp {
font-size: 22px;
}
:host([narrow]) .temp-attribute .temp {
[class*="narrow"] .temp-attribute .temp {
margin-right: 16px;
margin-inline-end: 16px;
margin-inline-start: initial;
}
:host([narrow]) .temp span {
[class*="narrow"] .temp span {
top: 1px;
font-size: 16px;
}
/* ============= VERY NARROW ============= */
:host([veryNarrow]) .name,
:host([veryNarrow]) .attribute {
[class*="very-narrow"] .name,
[class*="very-narrow"] .attribute {
display: none;
}
:host([veryNarrow]) .info {
[class*="very-narrow"] .info {
flex-direction: column;
align-items: flex-start;
}
:host([veryNarrow]) .name-state {
[class*="very-narrow"] .name-state {
padding-right: 0;
padding-inline-end: 0;
padding-inline-start: initial;
@ -663,18 +628,18 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
/* ============= VERY VERY NARROW ============= */
:host([veryVeryNarrow]) .info {
[class*="very-very-narrow"] .info {
padding-top: 4px;
align-items: center;
}
:host([veryVeryNarrow]) .content {
[class*="very-very-narrow"] .content {
flex-wrap: wrap;
justify-content: center;
flex-direction: column;
}
:host([veryVeryNarrow]) .icon-image {
[class*="very-very-narrow"] .icon-image {
margin-right: 0;
margin-inline-end: 0;
margin-inline-start: initial;