Improve icon translations support (#19516)
* Use slot for icon picker * Use icon translations for disabled entities in device page * Don't use fallback for light effect * Fix device class * Fix climate hvac mode * Migrate fan direction to icon translations * Remove attribute fallback * Rename variable * Update src/panels/lovelace/card-features/hui-climate-hvac-modes-card-feature.ts Co-authored-by: Bram Kragten <mail@bramkragten.nl> --------- Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
beb3454f8d
commit
85f086d02e
|
@ -1,46 +0,0 @@
|
|||
/** Return an icon representing a attribute. */
|
||||
import { mdiCircleMedium, mdiCreation } from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
computeFanModeIcon,
|
||||
computeHvacModeIcon,
|
||||
computePresetModeIcon,
|
||||
computeSwingModeIcon,
|
||||
} from "../../data/climate";
|
||||
import { computeHumidiferModeIcon } from "../../data/humidifier";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
|
||||
const iconGenerators: Record<string, Record<string, (value: any) => string>> = {
|
||||
climate: {
|
||||
fan_mode: computeFanModeIcon,
|
||||
hvac_mode: computeHvacModeIcon,
|
||||
preset_mode: computePresetModeIcon,
|
||||
swing_mode: computeSwingModeIcon,
|
||||
},
|
||||
humidifier: {
|
||||
mode: computeHumidiferModeIcon,
|
||||
},
|
||||
light: {
|
||||
effect: () => mdiCreation,
|
||||
},
|
||||
fan: {
|
||||
preset_mode: () => mdiCircleMedium,
|
||||
},
|
||||
};
|
||||
|
||||
export const attributeIconPath = (
|
||||
state: HassEntity | undefined,
|
||||
attribute: string,
|
||||
attributeValue?: string
|
||||
) => {
|
||||
if (!state) {
|
||||
return undefined;
|
||||
}
|
||||
const domain = computeDomain(state.entity_id);
|
||||
if (iconGenerators[domain]?.[attribute]) {
|
||||
return iconGenerators[domain]?.[attribute](
|
||||
attributeValue || state.attributes[attribute]
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
};
|
|
@ -6,7 +6,6 @@ import { attributeIcon } from "../data/icons";
|
|||
import { HomeAssistant } from "../types";
|
||||
import "./ha-icon";
|
||||
import "./ha-svg-icon";
|
||||
import { attributeIconPath } from "../common/entity/attribute_icon_path";
|
||||
|
||||
@customElement("ha-attribute-icon")
|
||||
export class HaAttributeIcon extends LitElement {
|
||||
|
@ -30,7 +29,7 @@ export class HaAttributeIcon extends LitElement {
|
|||
}
|
||||
|
||||
if (!this.hass) {
|
||||
return this._renderFallback();
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const icon = attributeIcon(
|
||||
|
@ -42,23 +41,11 @@ export class HaAttributeIcon extends LitElement {
|
|||
if (icn) {
|
||||
return html`<ha-icon .icon=${icn}></ha-icon>`;
|
||||
}
|
||||
return this._renderFallback();
|
||||
return nothing;
|
||||
});
|
||||
|
||||
return html`${until(icon)}`;
|
||||
}
|
||||
|
||||
private _renderFallback() {
|
||||
return html`
|
||||
<ha-svg-icon
|
||||
.path=${attributeIconPath(
|
||||
this.stateObj!,
|
||||
this.attribute!,
|
||||
this.attributeValue!
|
||||
)}
|
||||
></ha-svg-icon>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
|
|
@ -84,8 +84,6 @@ export class HaIconPicker extends LitElement {
|
|||
|
||||
@property() public placeholder?: string;
|
||||
|
||||
@property() public fallbackPath?: string;
|
||||
|
||||
@property({ attribute: "error-message" }) public errorMessage?: string;
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
@ -120,12 +118,7 @@ export class HaIconPicker extends LitElement {
|
|||
<ha-icon .icon=${this._value || this.placeholder} slot="icon">
|
||||
</ha-icon>
|
||||
`
|
||||
: this.fallbackPath
|
||||
? html`<ha-svg-icon
|
||||
.path=${this.fallbackPath}
|
||||
slot="icon"
|
||||
></ha-svg-icon>`
|
||||
: ""}
|
||||
: html`<slot name="fallback"></slot>`}
|
||||
</ha-combo-box>
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { html, LitElement } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { until } from "lit/directives/until";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { domainIcon } from "../../common/entity/domain_icon";
|
||||
import { entityIcon } from "../../data/icons";
|
||||
import { IconSelector } from "../../data/selector";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "../ha-icon-picker";
|
||||
import "../ha-state-icon";
|
||||
|
||||
@customElement("ha-selector-icon")
|
||||
export class HaIconSelector extends LitElement {
|
||||
|
@ -39,11 +38,6 @@ export class HaIconSelector extends LitElement {
|
|||
stateObj?.attributes.icon ||
|
||||
(stateObj && until(entityIcon(this.hass, stateObj)));
|
||||
|
||||
const fallbackPath =
|
||||
!placeholder && stateObj
|
||||
? domainIcon(computeDomain(iconEntity!), stateObj)
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<ha-icon-picker
|
||||
.hass=${this.hass}
|
||||
|
@ -52,10 +46,19 @@ export class HaIconSelector extends LitElement {
|
|||
.required=${this.required}
|
||||
.disabled=${this.disabled}
|
||||
.helper=${this.helper}
|
||||
.fallbackPath=${this.selector.icon?.fallbackPath ?? fallbackPath}
|
||||
.placeholder=${this.selector.icon?.placeholder ?? placeholder}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-icon-picker>
|
||||
>
|
||||
${!placeholder && stateObj
|
||||
? html`
|
||||
<ha-state-icon
|
||||
slot="fallback"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
></ha-state-icon>
|
||||
`
|
||||
: nothing}
|
||||
</ha-icon-picker>
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +1,12 @@
|
|||
import {
|
||||
mdiAccountArrowRight,
|
||||
mdiArrowAll,
|
||||
mdiArrowLeftRight,
|
||||
mdiArrowOscillating,
|
||||
mdiArrowOscillatingOff,
|
||||
mdiArrowUpDown,
|
||||
mdiBed,
|
||||
mdiCircleMedium,
|
||||
mdiClockOutline,
|
||||
mdiFan,
|
||||
mdiFanAuto,
|
||||
mdiFanOff,
|
||||
mdiFire,
|
||||
mdiHeatWave,
|
||||
mdiHome,
|
||||
mdiLeaf,
|
||||
mdiMotionSensor,
|
||||
mdiPower,
|
||||
mdiRocketLaunch,
|
||||
mdiSnowflake,
|
||||
mdiSofa,
|
||||
mdiSpeedometer,
|
||||
mdiSpeedometerMedium,
|
||||
mdiSpeedometerSlow,
|
||||
mdiSunSnowflakeVariant,
|
||||
mdiTarget,
|
||||
mdiThermostat,
|
||||
mdiThermostatAuto,
|
||||
mdiWaterPercent,
|
||||
mdiWeatherWindy,
|
||||
} from "@mdi/js";
|
||||
import {
|
||||
HassEntityAttributeBase,
|
||||
|
@ -116,16 +95,6 @@ export const CLIMATE_HVAC_ACTION_TO_MODE: Record<HvacAction, HvacMode> = {
|
|||
off: "off",
|
||||
};
|
||||
|
||||
export const CLIMATE_HVAC_ACTION_ICONS: Record<HvacAction, string> = {
|
||||
cooling: mdiSnowflake,
|
||||
drying: mdiWaterPercent,
|
||||
fan: mdiFan,
|
||||
heating: mdiFire,
|
||||
idle: mdiClockOutline,
|
||||
off: mdiPower,
|
||||
preheating: mdiHeatWave,
|
||||
};
|
||||
|
||||
export const CLIMATE_HVAC_MODE_ICONS: Record<HvacMode, string> = {
|
||||
cool: mdiSnowflake,
|
||||
dry: mdiWaterPercent,
|
||||
|
@ -136,81 +105,5 @@ export const CLIMATE_HVAC_MODE_ICONS: Record<HvacMode, string> = {
|
|||
heat_cool: mdiSunSnowflakeVariant,
|
||||
};
|
||||
|
||||
export const computeHvacModeIcon = (mode: HvacMode) =>
|
||||
CLIMATE_HVAC_MODE_ICONS[mode];
|
||||
|
||||
type ClimateBuiltInPresetMode =
|
||||
| "eco"
|
||||
| "away"
|
||||
| "boost"
|
||||
| "comfort"
|
||||
| "home"
|
||||
| "sleep"
|
||||
| "activity";
|
||||
|
||||
export const CLIMATE_PRESET_MODE_ICONS: Record<
|
||||
ClimateBuiltInPresetMode,
|
||||
string
|
||||
> = {
|
||||
away: mdiAccountArrowRight,
|
||||
boost: mdiRocketLaunch,
|
||||
comfort: mdiSofa,
|
||||
eco: mdiLeaf,
|
||||
home: mdiHome,
|
||||
sleep: mdiBed,
|
||||
activity: mdiMotionSensor,
|
||||
};
|
||||
|
||||
export const computePresetModeIcon = (mode: string) =>
|
||||
mode in CLIMATE_PRESET_MODE_ICONS
|
||||
? CLIMATE_PRESET_MODE_ICONS[mode]
|
||||
: mdiCircleMedium;
|
||||
|
||||
type ClimateBuiltInFanMode =
|
||||
| "on"
|
||||
| "off"
|
||||
| "auto"
|
||||
| "low"
|
||||
| "medium"
|
||||
| "high"
|
||||
| "middle"
|
||||
| "focus"
|
||||
| "diffuse";
|
||||
|
||||
export const CLIMATE_FAN_MODE_ICONS: Record<ClimateBuiltInFanMode, string> = {
|
||||
on: mdiFan,
|
||||
off: mdiFanOff,
|
||||
auto: mdiFanAuto,
|
||||
low: mdiSpeedometerSlow,
|
||||
medium: mdiSpeedometerMedium,
|
||||
high: mdiSpeedometer,
|
||||
middle: mdiSpeedometerMedium,
|
||||
focus: mdiTarget,
|
||||
diffuse: mdiWeatherWindy,
|
||||
};
|
||||
|
||||
export const computeFanModeIcon = (mode: string) =>
|
||||
mode in CLIMATE_FAN_MODE_ICONS
|
||||
? CLIMATE_FAN_MODE_ICONS[mode]
|
||||
: mdiCircleMedium;
|
||||
|
||||
type ClimateBuiltInSwingMode =
|
||||
| "off"
|
||||
| "on"
|
||||
| "vertical"
|
||||
| "horizontal"
|
||||
| "both";
|
||||
|
||||
export const CLIMATE_SWING_MODE_ICONS: Record<ClimateBuiltInSwingMode, string> =
|
||||
{
|
||||
on: mdiArrowOscillating,
|
||||
off: mdiArrowOscillatingOff,
|
||||
vertical: mdiArrowUpDown,
|
||||
horizontal: mdiArrowLeftRight,
|
||||
both: mdiArrowAll,
|
||||
};
|
||||
|
||||
export const computeSwingModeIcon = (mode: string) =>
|
||||
mode in CLIMATE_SWING_MODE_ICONS
|
||||
? CLIMATE_SWING_MODE_ICONS[mode]
|
||||
: mdiCircleMedium;
|
||||
export const climateHvacModeIcon = (mode: string) =>
|
||||
CLIMATE_HVAC_MODE_ICONS[mode] || mdiThermostat;
|
||||
|
|
|
@ -1,19 +1,3 @@
|
|||
import {
|
||||
mdiAccountArrowRight,
|
||||
mdiArrowDownBold,
|
||||
mdiArrowUpBold,
|
||||
mdiBabyCarriage,
|
||||
mdiCircleMedium,
|
||||
mdiClockOutline,
|
||||
mdiHome,
|
||||
mdiLeaf,
|
||||
mdiPower,
|
||||
mdiPowerSleep,
|
||||
mdiRefreshAuto,
|
||||
mdiRocketLaunch,
|
||||
mdiSofa,
|
||||
mdiWaterPercent,
|
||||
} from "@mdi/js";
|
||||
import {
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
|
@ -44,39 +28,6 @@ export const enum HumidifierEntityDeviceClass {
|
|||
DEHUMIDIFIER = "dehumidifier",
|
||||
}
|
||||
|
||||
type HumidifierBuiltInMode =
|
||||
| "normal"
|
||||
| "eco"
|
||||
| "away"
|
||||
| "boost"
|
||||
| "comfort"
|
||||
| "home"
|
||||
| "sleep"
|
||||
| "auto"
|
||||
| "baby";
|
||||
|
||||
export const HUMIDIFIER_MODE_ICONS: Record<HumidifierBuiltInMode, string> = {
|
||||
auto: mdiRefreshAuto,
|
||||
away: mdiAccountArrowRight,
|
||||
baby: mdiBabyCarriage,
|
||||
boost: mdiRocketLaunch,
|
||||
comfort: mdiSofa,
|
||||
eco: mdiLeaf,
|
||||
home: mdiHome,
|
||||
normal: mdiWaterPercent,
|
||||
sleep: mdiPowerSleep,
|
||||
};
|
||||
|
||||
export const computeHumidiferModeIcon = (mode?: string) =>
|
||||
HUMIDIFIER_MODE_ICONS[mode as HumidifierBuiltInMode] ?? mdiCircleMedium;
|
||||
|
||||
export const HUMIDIFIER_ACTION_ICONS: Record<HumidifierAction, string> = {
|
||||
drying: mdiArrowDownBold,
|
||||
humidifying: mdiArrowUpBold,
|
||||
idle: mdiClockOutline,
|
||||
off: mdiPower,
|
||||
};
|
||||
|
||||
export const HUMIDIFIER_ACTION_MODE: Record<HumidifierAction, HumidifierState> =
|
||||
{
|
||||
drying: "on",
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||
import { HomeAssistant } from "../types";
|
||||
import {
|
||||
EntityRegistryDisplayEntry,
|
||||
EntityRegistryEntry,
|
||||
} from "./entity_registry";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
|
||||
const resources: Record<IconCategory, any> = {
|
||||
entity: {},
|
||||
|
@ -15,7 +20,13 @@ interface PlatformIcons {
|
|||
[domain: string]: {
|
||||
[translation_key: string]: {
|
||||
state: Record<string, string>;
|
||||
state_attributes: Record<string, { state: Record<string, string> }>;
|
||||
state_attributes: Record<
|
||||
string,
|
||||
{
|
||||
state: Record<string, string>;
|
||||
default: string;
|
||||
}
|
||||
>;
|
||||
default: string;
|
||||
};
|
||||
};
|
||||
|
@ -24,7 +35,13 @@ interface PlatformIcons {
|
|||
interface ComponentIcons {
|
||||
[device_class: string]: {
|
||||
state: Record<string, string>;
|
||||
state_attributes: Record<string, { state: Record<string, string> }>;
|
||||
state_attributes: Record<
|
||||
string,
|
||||
{
|
||||
state: Record<string, string>;
|
||||
default: string;
|
||||
}
|
||||
>;
|
||||
default: string;
|
||||
};
|
||||
}
|
||||
|
@ -76,32 +93,67 @@ export const entityIcon = async (
|
|||
state: HassEntity,
|
||||
stateValue?: string
|
||||
) => {
|
||||
let icon: string | undefined;
|
||||
const domain = computeStateDomain(state);
|
||||
const entity = hass.entities?.[state.entity_id];
|
||||
const value = stateValue ?? state.state;
|
||||
const entity = hass.entities?.[state.entity_id] as
|
||||
| EntityRegistryDisplayEntry
|
||||
| undefined;
|
||||
|
||||
if (entity?.icon) {
|
||||
return entity.icon;
|
||||
}
|
||||
if (entity?.translation_key && entity.platform) {
|
||||
const platformIcons = await getPlatformIcons(hass, entity.platform);
|
||||
const domain = computeStateDomain(state);
|
||||
const deviceClass = state.attributes.device_class;
|
||||
|
||||
return getEntityIcon(
|
||||
hass,
|
||||
domain,
|
||||
deviceClass,
|
||||
stateValue ?? state.state,
|
||||
entity?.platform,
|
||||
entity?.translation_key
|
||||
);
|
||||
};
|
||||
|
||||
export const entryIcon = async (
|
||||
hass: HomeAssistant,
|
||||
entry: EntityRegistryEntry | EntityRegistryDisplayEntry
|
||||
) => {
|
||||
if (entry.icon) {
|
||||
return entry.icon;
|
||||
}
|
||||
const domain = computeDomain(entry.entity_id);
|
||||
return getEntityIcon(
|
||||
hass,
|
||||
domain,
|
||||
undefined,
|
||||
undefined,
|
||||
entry.platform,
|
||||
entry.translation_key
|
||||
);
|
||||
};
|
||||
|
||||
const getEntityIcon = async (
|
||||
hass: HomeAssistant,
|
||||
domain: string,
|
||||
deviceClass?: string,
|
||||
value?: string,
|
||||
platform?: string,
|
||||
translation_key?: string
|
||||
) => {
|
||||
let icon: string | undefined;
|
||||
if (translation_key && platform) {
|
||||
const platformIcons = await getPlatformIcons(hass, platform);
|
||||
if (platformIcons) {
|
||||
icon =
|
||||
platformIcons[domain]?.[entity.translation_key]?.state?.[value] ||
|
||||
platformIcons[domain]?.[entity.translation_key]?.default;
|
||||
const translations = platformIcons[domain]?.[translation_key];
|
||||
icon = (value && translations?.state?.[value]) || translations?.default;
|
||||
}
|
||||
}
|
||||
if (!icon) {
|
||||
const entityComponentIcons = await getComponentIcons(hass, domain);
|
||||
|
||||
if (entityComponentIcons) {
|
||||
icon =
|
||||
entityComponentIcons[state.attributes.device_class || "_"]?.state?.[
|
||||
value
|
||||
] ||
|
||||
entityComponentIcons._?.state?.[value] ||
|
||||
entityComponentIcons[state.attributes.device_class || "_"]?.default ||
|
||||
entityComponentIcons._?.default;
|
||||
const translations =
|
||||
(deviceClass && entityComponentIcons[deviceClass]) ||
|
||||
entityComponentIcons._;
|
||||
icon = (value && translations?.state?.[value]) || translations?.default;
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
|
@ -115,24 +167,32 @@ 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);
|
||||
const deviceClass = state.attributes.device_class;
|
||||
const entity = hass.entities?.[state.entity_id] as
|
||||
| EntityRegistryDisplayEntry
|
||||
| undefined;
|
||||
const platform = entity?.platform;
|
||||
const translation_key = entity?.translation_key;
|
||||
const value =
|
||||
attributeValue ??
|
||||
(state.attributes[attribute] as string | number | undefined);
|
||||
|
||||
if (translation_key && platform) {
|
||||
const platformIcons = await getPlatformIcons(hass, platform);
|
||||
if (platformIcons) {
|
||||
icon =
|
||||
platformIcons[domain]?.[entity.translation_key]?.state_attributes?.[
|
||||
attribute
|
||||
]?.state?.[value];
|
||||
const translations =
|
||||
platformIcons[domain]?.[translation_key]?.state_attributes?.[attribute];
|
||||
icon = (value && translations?.state?.[value]) || translations?.default;
|
||||
}
|
||||
}
|
||||
if (!icon) {
|
||||
const entityComponentIcons = await getComponentIcons(hass, domain);
|
||||
if (entityComponentIcons) {
|
||||
icon =
|
||||
entityComponentIcons[state.attributes.device_class || "_"]
|
||||
.state_attributes?.[attribute]?.state?.[value] ||
|
||||
entityComponentIcons._.state_attributes?.[attribute]?.state?.[value];
|
||||
const translations =
|
||||
(deviceClass &&
|
||||
entityComponentIcons[deviceClass]?.state_attributes?.[attribute]) ||
|
||||
entityComponentIcons._?.state_attributes?.[attribute];
|
||||
icon = (value && translations?.state?.[value]) || translations?.default;
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
mdiArrowOscillating,
|
||||
mdiFan,
|
||||
mdiThermometer,
|
||||
mdiThermostat,
|
||||
mdiTuneVariant,
|
||||
mdiWaterPercent,
|
||||
} from "@mdi/js";
|
||||
|
@ -11,19 +10,20 @@ import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
|||
import { property, state } from "lit/decorators";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/ha-attribute-icon";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-icon-button-group";
|
||||
import "../../../components/ha-icon-button-toggle";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-select";
|
||||
import "../../../components/ha-switch";
|
||||
import "../../../components/ha-attribute-icon";
|
||||
import {
|
||||
ClimateEntity,
|
||||
ClimateEntityFeature,
|
||||
climateHvacModeIcon,
|
||||
compareClimateHvacModes,
|
||||
} from "../../../data/climate";
|
||||
import { UNAVAILABLE, isUnavailableState } from "../../../data/entity";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import "../../../state-control/climate/ha-state-control-climate-humidity";
|
||||
import "../../../state-control/climate/ha-state-control-climate-temperature";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
@ -161,31 +161,22 @@ class MoreInfoClimate extends LitElement {
|
|||
@selected=${this._handleOperationModeChanged}
|
||||
@closed=${stopPropagation}
|
||||
>
|
||||
${!isUnavailableState(this.stateObj.state)
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="hvac_mode"
|
||||
.attributeValue=${stateObj.state}
|
||||
></ha-attribute-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiThermostat}
|
||||
></ha-svg-icon>`}
|
||||
${html`
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${climateHvacModeIcon(stateObj.state)}
|
||||
></ha-svg-icon>
|
||||
`}
|
||||
${stateObj.attributes.hvac_modes
|
||||
.concat()
|
||||
.sort(compareClimateHvacModes)
|
||||
.map(
|
||||
(mode) => html`
|
||||
<ha-list-item .value=${mode} graphic="icon">
|
||||
<ha-attribute-icon
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="hvac_mode"
|
||||
.attributeValue=${mode}
|
||||
></ha-attribute-icon>
|
||||
.path=${climateHvacModeIcon(mode)}
|
||||
></ha-svg-icon>
|
||||
${this.hass.formatEntityState(stateObj, mode)}
|
||||
</ha-list-item>
|
||||
`
|
||||
|
@ -206,13 +197,15 @@ class MoreInfoClimate extends LitElement {
|
|||
@closed=${stopPropagation}
|
||||
>
|
||||
${stateObj.attributes.preset_mode
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="preset_mode"
|
||||
.attributeValue=${stateObj.attributes.preset_mode}
|
||||
></ha-attribute-icon>`
|
||||
? html`
|
||||
<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="preset_mode"
|
||||
.attributeValue=${stateObj.attributes.preset_mode}
|
||||
></ha-attribute-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
|
@ -255,13 +248,15 @@ class MoreInfoClimate extends LitElement {
|
|||
@closed=${stopPropagation}
|
||||
>
|
||||
${stateObj.attributes.fan_mode
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="fan_mode"
|
||||
.attributeValue=${stateObj.attributes.fan_mode}
|
||||
></ha-attribute-icon>`
|
||||
? html`
|
||||
<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="fan_mode"
|
||||
.attributeValue=${stateObj.attributes.fan_mode}
|
||||
></ha-attribute-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-svg-icon slot="icon" .path=${mdiFan}></ha-svg-icon>
|
||||
`}
|
||||
|
@ -301,13 +296,15 @@ class MoreInfoClimate extends LitElement {
|
|||
@closed=${stopPropagation}
|
||||
>
|
||||
${stateObj.attributes.swing_mode
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="swing_mode"
|
||||
.attributeValue=${stateObj.attributes.swing_mode}
|
||||
></ha-attribute-icon>`
|
||||
? html`
|
||||
<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="swing_mode"
|
||||
.attributeValue=${stateObj.attributes.swing_mode}
|
||||
></ha-attribute-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
|
|
|
@ -4,8 +4,6 @@ import {
|
|||
mdiFan,
|
||||
mdiFanOff,
|
||||
mdiPower,
|
||||
mdiRotateLeft,
|
||||
mdiRotateRight,
|
||||
mdiTuneVariant,
|
||||
} from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, PropertyValues, html, nothing } from "lit";
|
||||
|
@ -13,8 +11,8 @@ import { customElement, property, state } from "lit/decorators";
|
|||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-attribute-icon";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-outlined-icon-button";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
|
@ -237,12 +235,21 @@ class MoreInfoFan extends LitElement {
|
|||
@selected=${this._handleDirection}
|
||||
@closed=${stopPropagation}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiRotateLeft}></ha-svg-icon>
|
||||
<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="direction"
|
||||
.attributeValue=${this.stateObj.attributes.direction}
|
||||
></ha-attribute-icon>
|
||||
<ha-list-item value="forward" graphic="icon">
|
||||
<ha-svg-icon
|
||||
<ha-attribute-icon
|
||||
slot="graphic"
|
||||
.path=${mdiRotateRight}
|
||||
></ha-svg-icon>
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="direction"
|
||||
attributeValue="forward"
|
||||
></ha-attribute-icon>
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"direction",
|
||||
|
@ -250,10 +257,13 @@ class MoreInfoFan extends LitElement {
|
|||
)}
|
||||
</ha-list-item>
|
||||
<ha-list-item value="reverse" graphic="icon">
|
||||
<ha-svg-icon
|
||||
<ha-attribute-icon
|
||||
slot="graphic"
|
||||
.path=${mdiRotateLeft}
|
||||
></ha-svg-icon>
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="direction"
|
||||
attributeValue="reverse"
|
||||
></ha-attribute-icon>
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj,
|
||||
"direction",
|
||||
|
|
|
@ -110,17 +110,21 @@ class MoreInfoHumidifier extends LitElement {
|
|||
@closed=${stopPropagation}
|
||||
>
|
||||
${stateObj.attributes.mode
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="mode"
|
||||
.attributeValue=${stateObj.attributes.mode}
|
||||
></ha-attribute-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiTuneVariant}
|
||||
></ha-svg-icon>`}
|
||||
? html`
|
||||
<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
attribute="mode"
|
||||
.attributeValue=${stateObj.attributes.mode}
|
||||
></ha-attribute-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiTuneVariant}
|
||||
></ha-svg-icon>
|
||||
`}
|
||||
${stateObj.attributes.available_modes!.map(
|
||||
(mode) => html`
|
||||
<ha-list-item .value=${mode} graphic="icon">
|
||||
|
|
|
@ -285,19 +285,19 @@ class MoreInfoLight extends LitElement {
|
|||
.path=${mdiCreation}
|
||||
></ha-svg-icon>`}
|
||||
${this.stateObj.attributes.effect_list?.map(
|
||||
(mode) => html`
|
||||
<ha-list-item .value=${mode} graphic="icon">
|
||||
(effect) => html`
|
||||
<ha-list-item .value=${effect} graphic="icon">
|
||||
<ha-attribute-icon
|
||||
slot="graphic"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="effect"
|
||||
.attributeValue=${mode}
|
||||
.attributeValue=${effect}
|
||||
></ha-attribute-icon>
|
||||
${this.hass.formatEntityAttributeValue(
|
||||
this.stateObj!,
|
||||
"effect",
|
||||
mode
|
||||
effect
|
||||
)}
|
||||
</ha-list-item>
|
||||
`
|
||||
|
|
|
@ -8,9 +8,8 @@ import {
|
|||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { computeDomain } from "../../../../common/entity/compute_domain";
|
||||
import { until } from "lit/directives/until";
|
||||
import { computeStateName } from "../../../../common/entity/compute_state_name";
|
||||
import { domainIcon } from "../../../../common/entity/domain_icon";
|
||||
import { stripPrefixFromEntityName } from "../../../../common/entity/strip_prefix_from_entity_name";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon";
|
||||
|
@ -19,6 +18,7 @@ import {
|
|||
ExtEntityRegistryEntry,
|
||||
getExtendedEntityRegistryEntry,
|
||||
} from "../../../../data/entity_registry";
|
||||
import { entryIcon } from "../../../../data/icons";
|
||||
import { showMoreInfoDialog } from "../../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { HuiErrorCard } from "../../../lovelace/cards/hui-error-card";
|
||||
|
@ -198,6 +198,8 @@ export class HaDeviceEntitiesCard extends LitElement {
|
|||
entry.name ||
|
||||
(entry as ExtEntityRegistryEntry).original_name;
|
||||
|
||||
const icon = until(entryIcon(this.hass, entry));
|
||||
|
||||
return html`
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
|
@ -205,10 +207,7 @@ export class HaDeviceEntitiesCard extends LitElement {
|
|||
.entry=${entry}
|
||||
@click=${this._openEditEntry}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${domainIcon(computeDomain(entry.entity_id))}
|
||||
></ha-svg-icon>
|
||||
<ha-icon slot="graphic" .icon=${icon}></ha-icon>
|
||||
<div class="name">
|
||||
${name
|
||||
? stripPrefixFromEntityName(name, this.deviceName.toLowerCase()) ||
|
||||
|
|
|
@ -18,7 +18,6 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
|||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeObjectId } from "../../../common/entity/compute_object_id";
|
||||
import { domainIcon } from "../../../common/entity/domain_icon";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { formatNumber } from "../../../common/number/format_number";
|
||||
import { stringCompare } from "../../../common/string/compare";
|
||||
|
@ -32,6 +31,7 @@ import "../../../components/ha-area-picker";
|
|||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-button-next";
|
||||
import "../../../components/ha-icon-picker";
|
||||
import "../../../components/ha-state-icon";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-radio";
|
||||
import "../../../components/ha-select";
|
||||
|
@ -373,29 +373,30 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
|||
></ha-textfield>`}
|
||||
${this.hideIcon
|
||||
? nothing
|
||||
: html`<ha-icon-picker
|
||||
.hass=${this.hass}
|
||||
.value=${this._icon}
|
||||
@value-changed=${this._iconChanged}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.icon"
|
||||
)}
|
||||
.placeholder=${this.entry.original_icon ||
|
||||
stateObj?.attributes.icon ||
|
||||
(stateObj && until(entityIcon(this.hass, stateObj)))}
|
||||
.fallbackPath=${!this._icon &&
|
||||
!stateObj?.attributes.icon &&
|
||||
stateObj
|
||||
? domainIcon(computeDomain(stateObj.entity_id), {
|
||||
...stateObj,
|
||||
attributes: {
|
||||
...stateObj.attributes,
|
||||
device_class: this._deviceClass,
|
||||
},
|
||||
})
|
||||
: undefined}
|
||||
.disabled=${this.disabled}
|
||||
></ha-icon-picker>`}
|
||||
: html`
|
||||
<ha-icon-picker
|
||||
.hass=${this.hass}
|
||||
.value=${this._icon}
|
||||
@value-changed=${this._iconChanged}
|
||||
.label=${this.hass.localize(
|
||||
"ui.dialogs.entity_registry.editor.icon"
|
||||
)}
|
||||
.placeholder=${this.entry.original_icon ||
|
||||
stateObj?.attributes.icon ||
|
||||
(stateObj && until(entityIcon(this.hass, stateObj)))}
|
||||
.disabled=${this.disabled}
|
||||
>
|
||||
${!this._icon && !stateObj?.attributes.icon && stateObj
|
||||
? html`
|
||||
<ha-state-icon
|
||||
slot="fallback"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObj}
|
||||
></ha-state-icon>
|
||||
`
|
||||
: nothing}
|
||||
</ha-icon-picker>
|
||||
`}
|
||||
${domain === "switch"
|
||||
? html`<ha-select
|
||||
.label=${this.hass.localize(
|
||||
|
|
|
@ -6,13 +6,13 @@ import { styleMap } from "lit/directives/style-map";
|
|||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import "../../../components/ha-attribute-icon";
|
||||
import "../../../components/ha-control-select";
|
||||
import type { ControlSelectOption } from "../../../components/ha-control-select";
|
||||
import "../../../components/ha-control-select-menu";
|
||||
import type { HaControlSelectMenu } from "../../../components/ha-control-select-menu";
|
||||
import {
|
||||
ClimateEntity,
|
||||
climateHvacModeIcon,
|
||||
compareClimateHvacModes,
|
||||
HvacMode,
|
||||
} from "../../../data/climate";
|
||||
|
@ -130,13 +130,12 @@ class HuiClimateHvacModesCardFeature
|
|||
.map<ControlSelectOption>((mode) => ({
|
||||
value: mode,
|
||||
label: this.hass!.formatEntityState(this.stateObj!, mode),
|
||||
icon: html`<ha-attribute-icon
|
||||
slot="graphic"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="hvac_mode"
|
||||
.attributeValue=${mode}
|
||||
></ha-attribute-icon>`,
|
||||
icon: html`
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${climateHvacModeIcon(mode)}
|
||||
></ha-svg-icon>
|
||||
`,
|
||||
}));
|
||||
|
||||
if (this._config.style === "dropdown") {
|
||||
|
@ -154,17 +153,15 @@ class HuiClimateHvacModesCardFeature
|
|||
@closed=${stopPropagation}
|
||||
>
|
||||
${this._currentHvacMode
|
||||
? html`<ha-attribute-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
attribute="hvac_mode"
|
||||
.attributeValue=${this._currentHvacMode}
|
||||
></ha-attribute-icon>`
|
||||
: html`<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiThermostat}
|
||||
></ha-svg-icon>`}
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${climateHvacModeIcon(this._currentHvacMode)}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-svg-icon slot="icon" .path=${mdiThermostat}></ha-svg-icon>
|
||||
`}
|
||||
${options.map(
|
||||
(option) => html`
|
||||
<ha-list-item .value=${option.value} graphic="icon">
|
||||
|
|
|
@ -10,9 +10,9 @@ import {
|
|||
import { RenderBadgeFunction } from "./tile-badge";
|
||||
|
||||
export const renderHumidifierBadge: RenderBadgeFunction = (stateObj, hass) => {
|
||||
const hvacAction = (stateObj as HumidifierEntity).attributes.action;
|
||||
const action = (stateObj as HumidifierEntity).attributes.action;
|
||||
|
||||
if (!hvacAction || hvacAction === "off") {
|
||||
if (!action || action === "off") {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ export const renderHumidifierBadge: RenderBadgeFunction = (stateObj, hass) => {
|
|||
style=${styleMap({
|
||||
"--tile-badge-background-color": stateColorCss(
|
||||
stateObj,
|
||||
HUMIDIFIER_ACTION_MODE[hvacAction]
|
||||
HUMIDIFIER_ACTION_MODE[action]
|
||||
),
|
||||
})}
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue