Skip to content

Commit

Permalink
Add stateValue parameter to ha-state-icon (#19508)
Browse files Browse the repository at this point in the history
* Add state value option to entityIcon

* Migrate lock, valve and cover more info to icon translations

* Migrate tile card

* Remove domain icon from area card

* Use attribute
  • Loading branch information
piitaya authored Jan 22, 2024
1 parent f6af73b commit 1c9ea0a
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 178 deletions.
14 changes: 9 additions & 5 deletions src/components/ha-state-icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export class HaStateIcon extends LitElement {

@property({ attribute: false }) public stateObj?: HassEntity;

@property({ attribute: false }) public stateValue?: string;

@property() public icon?: string;

protected render() {
Expand All @@ -30,12 +32,14 @@ export class HaStateIcon extends LitElement {
if (!this.hass) {
return this._renderFallback();
}
const icon = entityIcon(this.hass, this.stateObj).then((icn) => {
if (icn) {
return html`<ha-icon .icon=${icn}></ha-icon>`;
const icon = entityIcon(this.hass, this.stateObj, this.stateValue).then(
(icn) => {
if (icn) {
return html`<ha-icon .icon=${icn}></ha-icon>`;
}
return this._renderFallback();
}
return this._renderFallback();
});
);
return html`${until(icon)}`;
}

Expand Down
13 changes: 3 additions & 10 deletions src/components/tile/ha-tile-badge.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { customElement } from "lit/decorators";
import "../ha-icon";

@customElement("ha-tile-badge")
export class HaTileBadge extends LitElement {
@property() public iconPath?: string;

@property() public icon?: string;

protected render(): TemplateResult {
return html`
<div class="badge">
${this.icon
? html`<ha-icon .icon=${this.icon}></ha-icon>`
: html`<ha-svg-icon .path=${this.iconPath}></ha-svg-icon>`}
<slot></slot>
</div>
`;
}
Expand All @@ -36,8 +30,7 @@ export class HaTileBadge extends LitElement {
background-color: var(--tile-badge-background-color);
transition: background-color 280ms ease-in-out;
}
.badge ha-icon,
.badge ha-svg-icon {
.badge ::slotted(*) {
color: var(--tile-badge-icon-color);
}
`;
Expand Down
15 changes: 4 additions & 11 deletions src/components/tile/ha-tile-icon.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { CSSResultGroup, html, css, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
import { customElement } from "lit/decorators";
import "../ha-icon";
import "../ha-svg-icon";

@customElement("ha-tile-icon")
export class HaTileIcon extends LitElement {
@property() public iconPath?: string;

@property() public icon?: string;

protected render(): TemplateResult {
return html`
<div class="shape">
${this.icon
? html`<ha-icon .icon=${this.icon}></ha-icon>`
: html`<ha-svg-icon .path=${this.iconPath}></ha-svg-icon>`}
<slot></slot>
</div>
`;
}
Expand Down Expand Up @@ -47,8 +41,7 @@ export class HaTileIcon extends LitElement {
transition: color 180ms ease-in-out;
overflow: hidden;
}
.shape ha-icon,
.shape ha-svg-icon {
.shape ::slotted(*) {
display: flex;
color: var(--tile-icon-color);
transition: color 180ms ease-in-out;
Expand Down
25 changes: 14 additions & 11 deletions src/data/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,29 +71,35 @@ export const getComponentIcons = async (
return resources.entity_component.then((res) => res[domain]);
};

export const entityIcon = async (hass: HomeAssistant, state: HassEntity) => {
export const entityIcon = async (
hass: HomeAssistant,
state: HassEntity,
stateValue?: string
) => {
let icon: string | undefined;
const domain = computeStateDomain(state);
const entity = hass.entities?.[state.entity_id];
const value = stateValue ?? state.state;
if (entity?.icon) {
return entity.icon;
}
if (entity?.translation_key && entity.platform) {
const platformIcons = await getPlatformIcons(hass, entity.platform);
if (platformIcons) {
icon =
platformIcons[domain]?.[entity.translation_key]?.state?.[state.state] ||
platformIcons[domain]?.[entity.translation_key]?.state?.[value] ||
platformIcons[domain]?.[entity.translation_key]?.default;
}
}
if (!icon) {
const entityComponentIcons = await getComponentIcons(hass, domain);

if (entityComponentIcons) {
icon =
entityComponentIcons[state.attributes.device_class || "_"]?.state?.[
state.state
value
] ||
entityComponentIcons._?.state?.[state.state] ||
entityComponentIcons._?.state?.[value] ||
entityComponentIcons[state.attributes.device_class || "_"]?.default ||
entityComponentIcons._?.default;
}
Expand All @@ -110,26 +116,23 @@ export const attributeIcon = async (
let icon: string | undefined;
const domain = computeStateDomain(state);
const entity = hass.entities?.[state.entity_id];
const value = attributeValue ?? state.attributes[attribute];
if (entity?.translation_key && entity.platform) {
const platformIcons = await getPlatformIcons(hass, entity.platform);
if (platformIcons) {
icon =
platformIcons[domain]?.[entity.translation_key]?.state_attributes?.[
attribute
]?.state?.[attributeValue || state.attributes[attribute]];
]?.state?.[value];
}
}
if (!icon) {
const entityComponentIcons = await getComponentIcons(hass, domain);
if (entityComponentIcons) {
icon =
entityComponentIcons[state.attributes.device_class || "_"]
.state_attributes?.[attribute]?.state?.[
attributeValue || state.attributes[attribute]
] ||
entityComponentIcons._.state_attributes?.[attribute]?.state?.[
attributeValue || state.attributes[attribute]
];
.state_attributes?.[attribute]?.state?.[value] ||
entityComponentIcons._.state_attributes?.[attribute]?.state?.[value];
}
}
return icon;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { mdiShieldOff } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { domainIcon } from "../../../common/entity/domain_icon";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-outlined-button";
import "../../../components/ha-state-icon";
import { AlarmControlPanelEntity } from "../../../data/alarm_control_panel";
import "../../../state-control/alarm_control_panel/ha-state-control-alarm_control_panel-modes";
import type { HomeAssistant } from "../../../types";
Expand Down Expand Up @@ -59,9 +59,8 @@ class MoreInfoAlarmControlPanel extends LitElement {
<div class="status">
<span></span>
<div class="icon">
<ha-svg-icon
.path=${domainIcon("alarm_control_panel", this.stateObj)}
></ha-svg-icon>
<ha-state-icon .hass=${this.hass} .stateObj=${this.stateObj}>
</ha-state-icon>
</div>
<ha-outlined-button @click=${this._disarm}>
${this.hass.localize("ui.card.alarm_control_panel.disarm")}
Expand Down
9 changes: 5 additions & 4 deletions src/dialogs/more-info/controls/more-info-lock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { mdiDoorOpen, mdiLock, mdiLockOff } from "@mdi/js";
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { domainIcon } from "../../../common/entity/domain_icon";
import { stateColorCss } from "../../../common/entity/state_color";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-attributes";
import "../../../components/ha-outlined-icon-button";
import "../../../components/ha-state-icon";
import { UNAVAILABLE } from "../../../data/entity";
import {
LockEntity,
Expand Down Expand Up @@ -62,9 +62,10 @@ class MoreInfoLock extends LitElement {
<div class="status">
<span></span>
<div class="icon">
<ha-svg-icon
.path=${domainIcon("lock", this.stateObj)}
></ha-svg-icon>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
></ha-state-icon>
</div>
</div>
`
Expand Down
17 changes: 9 additions & 8 deletions src/panels/lovelace/cards/hui-area-card.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import "@material/mwc-ripple";
import {
mdiFan,
mdiFanOff,
mdiLightbulbMultiple,
mdiLightbulbMultipleOff,
mdiRun,
Expand All @@ -9,30 +11,30 @@ import {
} from "@mdi/js";
import type { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
css,
html,
nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one";
import { STATES_OFF, FIXED_DEVICE_CLASS_ICONS } from "../../../common/const";
import { FIXED_DEVICE_CLASS_ICONS, STATES_OFF } from "../../../common/const";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { computeDomain } from "../../../common/entity/compute_domain";
import { binarySensorIcon } from "../../../common/entity/binary_sensor_icon";
import { domainIcon } from "../../../common/entity/domain_icon";
import { computeDomain } from "../../../common/entity/compute_domain";
import { navigate } from "../../../common/navigate";
import {
formatNumber,
isNumericState,
} from "../../../common/number/format_number";
import { subscribeOne } from "../../../common/util/subscribe-one";
import { blankBeforeUnit } from "../../../common/translations/blank_before_unit";
import parseAspectRatio from "../../../common/util/parse-aspect-ratio";
import { subscribeOne } from "../../../common/util/subscribe-one";
import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import "../../../components/ha-svg-icon";
Expand All @@ -56,7 +58,6 @@ import "../components/hui-image";
import "../components/hui-warning";
import { LovelaceCard, LovelaceCardEditor } from "../types";
import { AreaCardConfig } from "./types";
import { blankBeforeUnit } from "../../../common/translations/blank_before_unit";

export const DEFAULT_ASPECT_RATIO = "16:9";

Expand All @@ -76,7 +77,7 @@ export const DEVICE_CLASSES = {
const DOMAIN_ICONS = {
light: { on: mdiLightbulbMultiple, off: mdiLightbulbMultipleOff },
switch: { on: mdiToggleSwitch, off: mdiToggleSwitchOff },
fan: { on: domainIcon("fan"), off: domainIcon("fan") },
fan: { on: mdiFan, off: mdiFanOff },
binary_sensor: {
motion: mdiRun,
moisture: mdiWaterAlert,
Expand Down
Loading

0 comments on commit 1c9ea0a

Please sign in to comment.