Add stateValue parameter to ha-state-icon (#19508)

* 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
This commit is contained in:
Paul Bottein 2024-01-22 20:10:08 +01:00 committed by GitHub
parent f6af73b222
commit 1c9ea0a9d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 241 additions and 178 deletions

View File

@ -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() {
@ -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)}`;
}

View File

@ -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>
`;
}
@ -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);
}
`;

View File

@ -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>
`;
}
@ -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;

View File

@ -71,10 +71,15 @@ 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;
}
@ -82,18 +87,19 @@ export const entityIcon = async (hass: HomeAssistant, state: HassEntity) => {
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;
}
@ -110,13 +116,14 @@ 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) {
@ -124,12 +131,8 @@ export const attributeIcon = async (
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;

View File

@ -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";
@ -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")}

View File

@ -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,
@ -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>
`

View File

@ -1,5 +1,7 @@
import "@material/mwc-ripple";
import {
mdiFan,
mdiFanOff,
mdiLightbulbMultiple,
mdiLightbulbMultipleOff,
mdiRun,
@ -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";
@ -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";
@ -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,

View File

@ -28,8 +28,9 @@ import { DOMAINS_TOGGLE } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
import { stateActive } from "../../../common/entity/state_active";
import { stateColorCss } from "../../../common/entity/state_color";
import { stateIconPath } from "../../../common/entity/state_icon_path";
import "../../../components/ha-card";
import "../../../components/ha-state-icon";
import "../../../components/ha-svg-icon";
import "../../../components/tile/ha-tile-badge";
import "../../../components/tile/ha-tile-icon";
import "../../../components/tile/ha-tile-image";
@ -48,7 +49,7 @@ import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
import "../components/hui-timestamp-display";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import { computeTileBadge } from "./tile/badges/tile-badge";
import { renderTileBadge } from "./tile/badges/tile-badge";
import type { ThermostatCardConfig, TileCardConfig } from "./types";
const TIMESTAMP_STATE_DOMAINS = ["button", "input_button", "scene"];
@ -341,17 +342,14 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
<ha-card>
<div class="content ${classMap(contentClasses)}">
<div class="icon-container">
<ha-tile-icon class="icon" .iconPath=${mdiHelp}></ha-tile-icon>
<ha-tile-badge
class="badge"
.iconPath=${mdiExclamationThick}
style=${styleMap({
"--tile-badge-background-color": `var(--red-color)`,
})}
></ha-tile-badge>
<ha-tile-icon>
<ha-svg-icon .path=${mdiHelp}></ha-svg-icon>
</ha-tile-icon>
<ha-tile-badge class="not-found">
<ha-svg-icon .path=${mdiExclamationThick}></ha-svg-icon>
</ha-tile-badge>
</div>
<ha-tile-info
class="info"
.primary=${entityId}
secondary=${this.hass.localize("ui.card.tile.not_found")}
></ha-tile-info>
@ -360,9 +358,6 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
`;
}
const icon = this._config.icon || stateObj.attributes.icon;
const iconPath = stateIconPath(stateObj);
const name = this._config.name || stateObj.attributes.friendly_name;
const localizedState = this._config.hide_state
@ -382,7 +377,6 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
const imageUrl = this._config.show_entity_picture
? this._getImageUrl(stateObj)
: undefined;
const badge = computeTileBadge(stateObj, this.hass);
return html`
<ha-card style=${styleMap(style)} class=${classMap({ active })}>
@ -420,7 +414,6 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
? html`
<ha-tile-image
.imageStyle=${DOMAIN_IMAGE_STYLE[domain] || "circle"}
class="icon"
.imageUrl=${imageUrl}
></ha-tile-image>
`
@ -428,27 +421,18 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
<ha-tile-icon
data-domain=${ifDefined(domain)}
data-state=${ifDefined(stateObj?.state)}
class="icon"
.icon=${icon}
.iconPath=${iconPath}
></ha-tile-icon>
>
<ha-state-icon
.icon=${this._config.icon}
.stateObj=${stateObj}
.hass=${this.hass}
></ha-state-icon>
</ha-tile-icon>
`}
${badge
? html`
<ha-tile-badge
class="badge"
.icon=${badge.icon}
.iconPath=${badge.iconPath}
style=${styleMap({
"--tile-badge-background-color": badge.color,
})}
></ha-tile-badge>
`
: nothing}
${renderTileBadge(stateObj, this.hass)}
</div>
<ha-tile-info
id="info"
class="info"
.primary=${name}
.secondary=${localizedState}
></ha-tile-info>
@ -516,7 +500,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
margin-inline-start: initial;
margin-inline-end: initial;
}
.vertical .info {
.vertical ha-tile-info {
width: 100%;
}
.icon-container {
@ -528,14 +512,15 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
direction: var(--direction);
transition: transform 180ms ease-in-out;
}
.icon-container .icon {
.icon-container ha-tile-icon,
.icon-container ha-tile-image {
--tile-icon-color: var(--tile-color);
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
.icon-container .badge {
.icon-container ha-tile-badge {
position: absolute;
top: -3px;
right: -3px;
@ -544,7 +529,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
.icon-container[role="button"]:active {
transform: scale(1.2);
}
.info {
ha-tile-info {
position: relative;
padding: 12px;
flex: 1;
@ -564,6 +549,10 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
animation: pulse 1s infinite;
}
ha-tile-badge.not-found {
--tile-badge-background-color: var(--red-color);
}
@keyframes pulse {
0% {
opacity: 1;

View File

@ -1,20 +1,36 @@
import { html, nothing } from "lit";
import { styleMap } from "lit/directives/style-map";
import { stateColorCss } from "../../../../../common/entity/state_color";
import "../../../../../components/ha-attribute-icon";
import "../../../../../components/tile/ha-tile-badge";
import {
CLIMATE_HVAC_ACTION_ICONS,
CLIMATE_HVAC_ACTION_TO_MODE,
ClimateEntity,
} from "../../../../../data/climate";
import { ComputeBadgeFunction } from "./tile-badge";
import { RenderBadgeFunction } from "./tile-badge";
export const computeClimateBadge: ComputeBadgeFunction = (stateObj) => {
export const renderClimateBadge: RenderBadgeFunction = (stateObj, hass) => {
const hvacAction = (stateObj as ClimateEntity).attributes.hvac_action;
if (!hvacAction || hvacAction === "off") {
return undefined;
return nothing;
}
return {
iconPath: CLIMATE_HVAC_ACTION_ICONS[hvacAction],
color: stateColorCss(stateObj, CLIMATE_HVAC_ACTION_TO_MODE[hvacAction]),
};
return html`
<ha-tile-badge
style=${styleMap({
"--tile-badge-background-color": stateColorCss(
stateObj,
CLIMATE_HVAC_ACTION_TO_MODE[hvacAction]
),
})}
>
<ha-attribute-icon
.hass=${hass}
.stateObj=${stateObj}
attribute="hvac_action"
>
</ha-attribute-icon>
</ha-tile-badge>
`;
};

View File

@ -1,20 +1,32 @@
import { html, nothing } from "lit";
import { styleMap } from "lit/directives/style-map";
import { stateColorCss } from "../../../../../common/entity/state_color";
import "../../../../../components/ha-attribute-icon";
import "../../../../../components/tile/ha-tile-badge";
import {
HUMIDIFIER_ACTION_ICONS,
HUMIDIFIER_ACTION_MODE,
HumidifierEntity,
} from "../../../../../data/humidifier";
import { ComputeBadgeFunction } from "./tile-badge";
import { RenderBadgeFunction } from "./tile-badge";
export const computeHumidifierBadge: ComputeBadgeFunction = (stateObj) => {
export const renderHumidifierBadge: RenderBadgeFunction = (stateObj, hass) => {
const hvacAction = (stateObj as HumidifierEntity).attributes.action;
if (!hvacAction || hvacAction === "off") {
return undefined;
return nothing;
}
return {
iconPath: HUMIDIFIER_ACTION_ICONS[hvacAction],
color: stateColorCss(stateObj, HUMIDIFIER_ACTION_MODE[hvacAction]),
};
return html`
<ha-tile-badge
style=${styleMap({
"--tile-badge-background-color": stateColorCss(
stateObj,
HUMIDIFIER_ACTION_MODE[hvacAction]
),
})}
>
<ha-attribute-icon .hass=${hass} .stateObj=${stateObj} attribute="action">
</ha-attribute-icon>
</ha-tile-badge>
`;
};

View File

@ -1,8 +1,13 @@
import { mdiHome, mdiHomeExportOutline } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket";
import { html } from "lit";
import { styleMap } from "lit/directives/style-map";
import { stateColorCss } from "../../../../../common/entity/state_color";
import "../../../../../components/ha-icon";
import "../../../../../components/ha-svg-icon";
import "../../../../../components/tile/ha-tile-badge";
import { HomeAssistant } from "../../../../../types";
import { ComputeBadgeFunction } from "./tile-badge";
import { RenderBadgeFunction } from "./tile-badge";
function getZone(entity: HassEntity, hass: HomeAssistant) {
const state = entity.state;
@ -15,17 +20,33 @@ function getZone(entity: HassEntity, hass: HomeAssistant) {
return zones.find((z) => state === z.attributes.friendly_name);
}
function personBadgeIcon(entity: HassEntity) {
const state = entity.state;
return state === "not_home" ? mdiHomeExportOutline : mdiHome;
}
export const computePersonBadge: ComputeBadgeFunction = (stateObj, hass) => {
export const renderPersonBadge: RenderBadgeFunction = (stateObj, hass) => {
const zone = getZone(stateObj, hass);
return {
iconPath: personBadgeIcon(stateObj),
icon: zone?.attributes.icon,
color: stateColorCss(stateObj),
};
const zoneIcon = zone?.attributes.icon;
if (zoneIcon) {
return html`
<ha-tile-badge
style=${styleMap({
"--tile-badge-background-color": stateColorCss(stateObj),
})}
>
<ha-icon .icon=${zoneIcon}></ha-icon>
</ha-tile-badge>
`;
}
const defaultIcon =
stateObj.state === "not_home" ? mdiHomeExportOutline : mdiHome;
return html`
<ha-tile-badge
style=${styleMap({
"--tile-badge-background-color": stateColorCss(stateObj),
})}
>
<ha-svg-icon .path=${defaultIcon}></ha-svg-icon>
</ha-tile-badge>
`;
};

View File

@ -1,43 +1,46 @@
import { mdiExclamationThick } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket";
import { TemplateResult, html, nothing } from "lit";
import { styleMap } from "lit/directives/style-map";
import { computeDomain } from "../../../../../common/entity/compute_domain";
import { UNAVAILABLE, UNKNOWN } from "../../../../../data/entity";
import { HomeAssistant } from "../../../../../types";
import { computeClimateBadge } from "./tile-badge-climate";
import { computePersonBadge } from "./tile-badge-person";
import { computeHumidifierBadge } from "./tile-badge-humidifier";
import { renderClimateBadge } from "./tile-badge-climate";
import { renderHumidifierBadge } from "./tile-badge-humidifier";
import { renderPersonBadge } from "./tile-badge-person";
import "../../../../../components/tile/ha-tile-badge";
import "../../../../../components/ha-svg-icon";
export type TileBadge = {
color?: string;
icon?: string;
iconPath?: string;
};
export type ComputeBadgeFunction = (
export type RenderBadgeFunction = (
stateObj: HassEntity,
hass: HomeAssistant
) => TileBadge | undefined;
) => TemplateResult | typeof nothing;
export const computeTileBadge: ComputeBadgeFunction = (stateObj, hass) => {
export const renderTileBadge: RenderBadgeFunction = (stateObj, hass) => {
if (stateObj.state === UNKNOWN) {
return undefined;
return nothing;
}
if (stateObj.state === UNAVAILABLE) {
return {
color: "var(--orange-color)",
iconPath: mdiExclamationThick,
};
return html`
<ha-tile-badge
style=${styleMap({
"--tile-badge-background-color": "var(--orange-color)",
})}
>
<ha-svg-icon .path=${mdiExclamationThick}></ha-svg-icon>
</ha-tile-badge>
`;
}
const domain = computeDomain(stateObj.entity_id);
switch (domain) {
case "person":
case "device_tracker":
return computePersonBadge(stateObj, hass);
return renderPersonBadge(stateObj, hass);
case "climate":
return computeClimateBadge(stateObj, hass);
return renderClimateBadge(stateObj, hass);
case "humidifier":
return computeHumidifierBadge(stateObj, hass);
return renderHumidifierBadge(stateObj, hass);
default:
return undefined;
return nothing;
}
};

View File

@ -3,10 +3,10 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { domainIcon } from "../../common/entity/domain_icon";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-button";
import "../../components/ha-control-switch";
import "../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import { HomeAssistant } from "../../types";
@ -77,9 +77,11 @@ export class HaStateControlCoverToggle extends LitElement {
"--color": onColor,
})}
>
<ha-svg-icon
.path=${domainIcon("cover", this.stateObj, "open")}
></ha-svg-icon>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="open"
></ha-state-icon>
</ha-control-button>
<ha-control-button
.label=${this.hass.localize("ui.card.cover.close_cover")}
@ -92,9 +94,11 @@ export class HaStateControlCoverToggle extends LitElement {
"--color": offColor,
})}
>
<ha-svg-icon
.path=${domainIcon("cover", this.stateObj, "closed")}
></ha-svg-icon>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="closed"
></ha-state-icon>
</ha-control-button>
</div>
`;
@ -102,8 +106,6 @@ export class HaStateControlCoverToggle extends LitElement {
return html`
<ha-control-switch
.pathOn=${domainIcon("cover", this.stateObj, "open")}
.pathOff=${domainIcon("cover", this.stateObj, "closed")}
vertical
reversed
.checked=${isOn}
@ -117,6 +119,18 @@ export class HaStateControlCoverToggle extends LitElement {
})}
.disabled=${this.stateObj.state === UNAVAILABLE}
>
<ha-state-icon
slot="icon-on"
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="open"
></ha-state-icon>
<ha-state-icon
slot="icon-off"
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="closed"
></ha-state-icon>
</ha-control-switch>
`;
}

View File

@ -9,10 +9,10 @@ import {
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { domainIcon } from "../../common/entity/domain_icon";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-button";
import "../../components/ha-control-switch";
import "../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import { callProtectedLockService, LockEntity } from "../../data/lock";
@ -81,18 +81,6 @@ export class HaStateControlLockToggle extends LitElement {
const color = stateColorCss(this.stateObj);
const onIcon = domainIcon(
"lock",
this.stateObj,
locking ? "locking" : "locked"
);
const offIcon = domainIcon(
"lock",
this.stateObj,
unlocking ? "unlocking" : "unlocked"
);
if (this.stateObj.state === UNKNOWN) {
return html`
<div class="buttons">
@ -100,13 +88,21 @@ export class HaStateControlLockToggle extends LitElement {
.label=${this.hass.localize("ui.card.lock.lock")}
@click=${this._turnOn}
>
<ha-svg-icon .path=${onIcon}></ha-svg-icon>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${locking ? "locking" : "locked"}
></ha-state-icon>
</ha-control-button>
<ha-control-button
.label=${this.hass.localize("ui.card.lock.unlock")}
@click=${this._turnOff}
>
<ha-svg-icon .path=${offIcon}></ha-svg-icon>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${unlocking ? "unlocking" : "unlocked"}
></ha-state-icon>
</ha-control-button>
</div>
`;
@ -127,16 +123,20 @@ export class HaStateControlLockToggle extends LitElement {
})}
.disabled=${this.stateObj.state === UNAVAILABLE}
>
<ha-svg-icon
<ha-state-icon
slot="icon-on"
.path=${onIcon}
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${locking ? "locking" : "locked"}
class=${classMap({ pulse: locking })}
></ha-svg-icon>
<ha-svg-icon
></ha-state-icon>
<ha-state-icon
slot="icon-off"
.path=${offIcon}
.hass=${this.hass}
.stateObj=${this.stateObj}
.stateValue=${unlocking ? "unlocking" : "unlocked"}
class=${classMap({ pulse: unlocking })}
></ha-svg-icon>
></ha-state-icon>
</ha-control-switch>
`;
}

View File

@ -3,10 +3,10 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { domainIcon } from "../../common/entity/domain_icon";
import { stateColorCss } from "../../common/entity/state_color";
import "../../components/ha-control-button";
import "../../components/ha-control-switch";
import "../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import { HomeAssistant } from "../../types";
@ -77,9 +77,11 @@ export class HaStateControlValveToggle extends LitElement {
"--color": onColor,
})}
>
<ha-svg-icon
.path=${domainIcon("valve", this.stateObj, "open")}
></ha-svg-icon>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="open"
></ha-state-icon>
</ha-control-button>
<ha-control-button
.label=${this.hass.localize("ui.card.valve.close_valve")}
@ -92,9 +94,11 @@ export class HaStateControlValveToggle extends LitElement {
"--color": offColor,
})}
>
<ha-svg-icon
.path=${domainIcon("valve", this.stateObj, "closed")}
></ha-svg-icon>
<ha-state-icon
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="closed"
></ha-state-icon>
</ha-control-button>
</div>
`;
@ -102,8 +106,6 @@ export class HaStateControlValveToggle extends LitElement {
return html`
<ha-control-switch
.pathOn=${domainIcon("valve", this.stateObj, "open")}
.pathOff=${domainIcon("valve", this.stateObj, "closed")}
vertical
reversed
.checked=${isOn}
@ -117,6 +119,18 @@ export class HaStateControlValveToggle extends LitElement {
})}
.disabled=${this.stateObj.state === UNAVAILABLE}
>
<ha-state-icon
slot="icon-on"
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="open"
></ha-state-icon>
<ha-state-icon
slot="icon-off"
.hass=${this.hass}
.stateObj=${this.stateObj}
stateValue="closed"
></ha-state-icon>
</ha-control-switch>
`;
}