Skip to content

Commit 646c02d

Browse files
authored
Implement more attribute icons (home-assistant#19469)
1 parent 77dd2a8 commit 646c02d

10 files changed

+164
-49
lines changed

lint-staged.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export default {
22
"*.?(c|m){js,ts}": [
33
"eslint --cache --cache-strategy=content --cache-location=node_modules/.cache/eslint/.eslintcache --fix",
44
"prettier --cache --write",
5-
"lit-analyzer",
5+
"lit-analyzer --quiet",
66
],
77
"*.{json,css,md,markdown,html,y?aml}": "prettier --cache --write",
88
"translations/*/*.json": (files) =>

src/common/entity/attribute_icon_path.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
/** Return an icon representing a attribute. */
2+
import { mdiCircleMedium, mdiCreation } from "@mdi/js";
23
import { HassEntity } from "home-assistant-js-websocket";
34
import {
45
computeFanModeIcon,
56
computeHvacModeIcon,
67
computePresetModeIcon,
78
computeSwingModeIcon,
89
} from "../../data/climate";
10+
import { computeHumidiferModeIcon } from "../../data/humidifier";
911
import { computeDomain } from "./compute_domain";
1012

1113
const iconGenerators: Record<string, Record<string, (value: any) => string>> = {
@@ -15,6 +17,15 @@ const iconGenerators: Record<string, Record<string, (value: any) => string>> = {
1517
preset_mode: computePresetModeIcon,
1618
swing_mode: computeSwingModeIcon,
1719
},
20+
humidifier: {
21+
mode: computeHumidiferModeIcon,
22+
},
23+
light: {
24+
effect: () => mdiCreation,
25+
},
26+
fan: {
27+
preset_mode: () => mdiCircleMedium,
28+
},
1829
};
1930

2031
export const attributeIconPath = (

src/components/ha-control-select.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
LitElement,
66
nothing,
77
PropertyValues,
8+
TemplateResult,
89
} from "lit";
910
import { customElement, property, state } from "lit/decorators";
1011
import { classMap } from "lit/directives/class-map";
@@ -17,15 +18,15 @@ import "./ha-svg-icon";
1718
export type ControlSelectOption = {
1819
value: string;
1920
label?: string;
20-
icon?: string;
21+
icon?: TemplateResult;
2122
path?: string;
2223
};
2324

2425
@customElement("ha-control-select")
2526
export class HaControlSelect extends LitElement {
2627
@property({ type: Boolean, reflect: true }) disabled = false;
2728

28-
@property() public options?: ControlSelectOption[];
29+
@property({ attribute: false }) public options?: ControlSelectOption[];
2930

3031
@property() public value?: string;
3132

@@ -183,9 +184,7 @@ export class HaControlSelect extends LitElement {
183184
<div class="content">
184185
${option.path
185186
? html`<ha-svg-icon .path=${option.path}></ha-svg-icon>`
186-
: option.icon
187-
? html`<ha-icon .icon=${option.icon}></ha-icon> `
188-
: nothing}
187+
: option.icon || nothing}
189188
${option.label && !this.hideLabel
190189
? html`<span>${option.label}</span>`
191190
: nothing}

src/dialogs/more-info/controls/more-info-fan.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { stopPropagation } from "../../../common/dom/stop_propagation";
1414
import { stateActive } from "../../../common/entity/state_active";
1515
import { supportsFeature } from "../../../common/entity/supports-feature";
1616
import "../../../components/ha-control-select-menu";
17+
import "../../../components/ha-attribute-icon";
1718
import "../../../components/ha-list-item";
1819
import "../../../components/ha-outlined-icon-button";
1920
import { UNAVAILABLE } from "../../../data/entity";
@@ -187,10 +188,30 @@ class MoreInfoFan extends LitElement {
187188
@selected=${this._handlePresetMode}
188189
@closed=${stopPropagation}
189190
>
190-
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
191+
${this.stateObj.attributes.preset_mode
192+
? html`<ha-attribute-icon
193+
slot="icon"
194+
.hass=${this.hass}
195+
.stateObj=${this.stateObj}
196+
attribute="preset_mode"
197+
.attributeValue=${this.stateObj.attributes.preset_mode}
198+
></ha-attribute-icon>`
199+
: html`
200+
<ha-svg-icon
201+
slot="icon"
202+
.path=${mdiTuneVariant}
203+
></ha-svg-icon>
204+
`}
191205
${this.stateObj.attributes.preset_modes?.map(
192206
(mode) => html`
193-
<ha-list-item .value=${mode}>
207+
<ha-list-item .value=${mode} graphic="icon">
208+
<ha-attribute-icon
209+
slot="graphic"
210+
.hass=${this.hass}
211+
.stateObj=${this.stateObj}
212+
attribute="preset_mode"
213+
.attributeValue=${mode}
214+
></ha-attribute-icon>
194215
${this.hass.formatEntityAttributeValue(
195216
this.stateObj!,
196217
"preset_mode",

src/dialogs/more-info/controls/more-info-humidifier.ts

+19-5
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ import { stopPropagation } from "../../../common/dom/stop_propagation";
1212
import { supportsFeature } from "../../../common/entity/supports-feature";
1313
import "../../../components/ha-control-select-menu";
1414
import "../../../components/ha-list-item";
15+
import "../../../components/ha-attribute-icon";
1516
import { UNAVAILABLE } from "../../../data/entity";
1617
import {
1718
HumidifierEntity,
1819
HumidifierEntityFeature,
19-
computeHumidiferModeIcon,
2020
} from "../../../data/humidifier";
2121
import "../../../state-control/humidifier/ha-state-control-humidifier-humidity";
2222
import { HomeAssistant } from "../../../types";
@@ -109,14 +109,28 @@ class MoreInfoHumidifier extends LitElement {
109109
@selected=${this._handleModeChanged}
110110
@closed=${stopPropagation}
111111
>
112-
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
112+
${stateObj.attributes.mode
113+
? html`<ha-attribute-icon
114+
slot="icon"
115+
.hass=${this.hass}
116+
.stateObj=${stateObj}
117+
attribute="mode"
118+
.attributeValue=${stateObj.attributes.mode}
119+
></ha-attribute-icon>`
120+
: html`<ha-svg-icon
121+
slot="icon"
122+
.path=${mdiTuneVariant}
123+
></ha-svg-icon>`}
113124
${stateObj.attributes.available_modes!.map(
114125
(mode) => html`
115126
<ha-list-item .value=${mode} graphic="icon">
116-
<ha-svg-icon
127+
<ha-attribute-icon
117128
slot="graphic"
118-
.path=${computeHumidiferModeIcon(mode)}
119-
></ha-svg-icon>
129+
.hass=${this.hass}
130+
.stateObj=${stateObj}
131+
attribute="mode"
132+
.attributeValue=${mode}
133+
></ha-attribute-icon>
120134
${this.hass.formatEntityAttributeValue(
121135
stateObj!,
122136
"mode",

src/dialogs/more-info/controls/more-info-light.ts

+21-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { customElement, property, state } from "lit/decorators";
1919
import { stopPropagation } from "../../../common/dom/stop_propagation";
2020
import { supportsFeature } from "../../../common/entity/supports-feature";
2121
import "../../../components/ha-attributes";
22+
import "../../../components/ha-attribute-icon";
2223
import "../../../components/ha-control-select-menu";
2324
import "../../../components/ha-icon-button-group";
2425
import "../../../components/ha-icon-button-toggle";
@@ -271,10 +272,28 @@ class MoreInfoLight extends LitElement {
271272
@selected=${this._handleEffect}
272273
@closed=${stopPropagation}
273274
>
274-
<ha-svg-icon slot="icon" .path=${mdiCreation}></ha-svg-icon>
275+
${this.stateObj.attributes.effect
276+
? html`<ha-attribute-icon
277+
slot="icon"
278+
.hass=${this.hass}
279+
.stateObj=${this.stateObj}
280+
attribute="effect"
281+
.attributeValue=${this.stateObj.attributes.effect}
282+
></ha-attribute-icon>`
283+
: html`<ha-svg-icon
284+
slot="icon"
285+
.path=${mdiCreation}
286+
></ha-svg-icon>`}
275287
${this.stateObj.attributes.effect_list?.map(
276288
(mode) => html`
277-
<ha-list-item .value=${mode}>
289+
<ha-list-item .value=${mode} graphic="icon">
290+
<ha-attribute-icon
291+
slot="graphic"
292+
.hass=${this.hass}
293+
.stateObj=${this.stateObj}
294+
attribute="effect"
295+
.attributeValue=${mode}
296+
></ha-attribute-icon>
278297
${this.hass.formatEntityAttributeValue(
279298
this.stateObj!,
280299
"effect",

src/panels/lovelace/card-features/hui-climate-fan-modes-card-feature.ts

+19-9
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@ import { customElement, property, query, state } from "lit/decorators";
55
import { stopPropagation } from "../../../common/dom/stop_propagation";
66
import { computeDomain } from "../../../common/entity/compute_domain";
77
import { supportsFeature } from "../../../common/entity/supports-feature";
8+
import "../../../components/ha-attribute-icon";
89
import "../../../components/ha-control-select";
910
import type { ControlSelectOption } from "../../../components/ha-control-select";
1011
import "../../../components/ha-control-select-menu";
1112
import type { HaControlSelectMenu } from "../../../components/ha-control-select-menu";
12-
import {
13-
ClimateEntity,
14-
ClimateEntityFeature,
15-
computeFanModeIcon,
16-
} from "../../../data/climate";
13+
import { ClimateEntity, ClimateEntityFeature } from "../../../data/climate";
1714
import { UNAVAILABLE } from "../../../data/entity";
1815
import { HomeAssistant } from "../../../types";
1916
import { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
@@ -136,7 +133,13 @@ class HuiClimateFanModesCardFeature
136133
"fan_mode",
137134
mode
138135
),
139-
path: computeFanModeIcon(mode),
136+
icon: html`<ha-attribute-icon
137+
slot="graphic"
138+
.hass=${this.hass}
139+
.stateObj=${stateObj}
140+
attribute="fan_mode"
141+
.attributeValue=${mode}
142+
></ha-attribute-icon>`,
140143
}));
141144

142145
if (this._config.style === "icons") {
@@ -171,12 +174,19 @@ class HuiClimateFanModesCardFeature
171174
@selected=${this._valueChanged}
172175
@closed=${stopPropagation}
173176
>
174-
<ha-svg-icon slot="icon" .path=${mdiFan}></ha-svg-icon>
177+
${this._currentFanMode
178+
? html`<ha-attribute-icon
179+
slot="icon"
180+
.hass=${this.hass}
181+
.stateObj=${stateObj}
182+
attribute="fan_mode"
183+
.attributeValue=${this._currentFanMode}
184+
></ha-attribute-icon>`
185+
: html` <ha-svg-icon slot="icon" .path=${mdiFan}></ha-svg-icon>`}
175186
${options.map(
176187
(option) => html`
177188
<ha-list-item .value=${option.value} graphic="icon">
178-
<ha-svg-icon slot="graphic" .path=${option.path}></ha-svg-icon>
179-
${option.label}
189+
${option.icon}${option.label}
180190
</ha-list-item>
181191
`
182192
)}

src/panels/lovelace/card-features/hui-climate-hvac-modes-card-feature.ts

+22-9
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import { styleMap } from "lit/directives/style-map";
66
import { stopPropagation } from "../../../common/dom/stop_propagation";
77
import { computeDomain } from "../../../common/entity/compute_domain";
88
import { stateColorCss } from "../../../common/entity/state_color";
9+
import "../../../components/ha-attribute-icon";
910
import "../../../components/ha-control-select";
10-
import "../../../components/ha-control-select-menu";
1111
import type { ControlSelectOption } from "../../../components/ha-control-select";
12+
import "../../../components/ha-control-select-menu";
1213
import type { HaControlSelectMenu } from "../../../components/ha-control-select-menu";
1314
import {
1415
ClimateEntity,
1516
compareClimateHvacModes,
16-
computeHvacModeIcon,
1717
HvacMode,
1818
} from "../../../data/climate";
1919
import { UNAVAILABLE } from "../../../data/entity";
@@ -130,7 +130,13 @@ class HuiClimateHvacModesCardFeature
130130
.map<ControlSelectOption>((mode) => ({
131131
value: mode,
132132
label: this.hass!.formatEntityState(this.stateObj!, mode),
133-
path: computeHvacModeIcon(mode),
133+
icon: html`<ha-attribute-icon
134+
slot="graphic"
135+
.hass=${this.hass}
136+
.stateObj=${this.stateObj}
137+
attribute="hvac_mode"
138+
.attributeValue=${mode}
139+
></ha-attribute-icon>`,
134140
}));
135141

136142
if (this._config.style === "dropdown") {
@@ -147,15 +153,22 @@ class HuiClimateHvacModesCardFeature
147153
@selected=${this._valueChanged}
148154
@closed=${stopPropagation}
149155
>
150-
<ha-svg-icon slot="icon" .path=${mdiThermostat}></ha-svg-icon>
156+
${this._currentHvacMode
157+
? html`<ha-attribute-icon
158+
slot="icon"
159+
.hass=${this.hass}
160+
.stateObj=${this.stateObj}
161+
attribute="hvac_mode"
162+
.attributeValue=${this._currentHvacMode}
163+
></ha-attribute-icon>`
164+
: html`<ha-svg-icon
165+
slot="icon"
166+
.path=${mdiThermostat}
167+
></ha-svg-icon>`}
151168
${options.map(
152169
(option) => html`
153170
<ha-list-item .value=${option.value} graphic="icon">
154-
<ha-svg-icon
155-
slot="graphic"
156-
.path=${option.path}
157-
></ha-svg-icon>
158-
${option.label}
171+
${option.icon}${option.label}
159172
</ha-list-item>
160173
`
161174
)}

src/panels/lovelace/card-features/hui-climate-preset-modes-card-feature.ts

+21-9
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@ import { customElement, property, query, state } from "lit/decorators";
55
import { stopPropagation } from "../../../common/dom/stop_propagation";
66
import { computeDomain } from "../../../common/entity/compute_domain";
77
import { supportsFeature } from "../../../common/entity/supports-feature";
8+
import "../../../components/ha-attribute-icon";
89
import "../../../components/ha-control-select";
910
import type { ControlSelectOption } from "../../../components/ha-control-select";
1011
import "../../../components/ha-control-select-menu";
1112
import type { HaControlSelectMenu } from "../../../components/ha-control-select-menu";
12-
import {
13-
ClimateEntity,
14-
ClimateEntityFeature,
15-
computePresetModeIcon,
16-
} from "../../../data/climate";
13+
import { ClimateEntity, ClimateEntityFeature } from "../../../data/climate";
1714
import { UNAVAILABLE } from "../../../data/entity";
1815
import { HomeAssistant } from "../../../types";
1916
import { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
@@ -138,7 +135,13 @@ class HuiClimatePresetModesCardFeature
138135
"preset_mode",
139136
mode
140137
),
141-
path: computePresetModeIcon(mode),
138+
icon: html`<ha-attribute-icon
139+
slot="graphic"
140+
.hass=${this.hass}
141+
.stateObj=${stateObj}
142+
attribute="preset_mode"
143+
.attributeValue=${mode}
144+
></ha-attribute-icon>`,
142145
}));
143146

144147
if (this._config.style === "icons") {
@@ -176,12 +179,21 @@ class HuiClimatePresetModesCardFeature
176179
@selected=${this._valueChanged}
177180
@closed=${stopPropagation}
178181
>
179-
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
182+
${this._currentPresetMode
183+
? html`<ha-attribute-icon
184+
slot="icon"
185+
.hass=${this.hass}
186+
.stateObj=${stateObj}
187+
attribute="preset_mode"
188+
.attributeValue=${this._currentPresetMode}
189+
></ha-attribute-icon>`
190+
: html`
191+
<ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
192+
`}
180193
${options.map(
181194
(option) => html`
182195
<ha-list-item .value=${option.value} graphic="icon">
183-
<ha-svg-icon slot="graphic" .path=${option.path}></ha-svg-icon>
184-
${option.label}
196+
${option.icon}${option.label}
185197
</ha-list-item>
186198
`
187199
)}

0 commit comments

Comments
 (0)