mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
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:
parent
f6af73b222
commit
1c9ea0a9d9
@ -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)}`;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
`;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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")}
|
||||
|
@ -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>
|
||||
`
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
`;
|
||||
};
|
||||
|
@ -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>
|
||||
`;
|
||||
};
|
||||
|
@ -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>
|
||||
`;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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>
|
||||
`;
|
||||
}
|
||||
|
@ -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>
|
||||
`;
|
||||
}
|
||||
|
@ -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>
|
||||
`;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user