diff --git a/build-scripts/gulp/gen-icons-json.js b/build-scripts/gulp/gen-icons-json.js index 58bb4faaaa..42563d15af 100644 --- a/build-scripts/gulp/gen-icons-json.js +++ b/build-scripts/gulp/gen-icons-json.js @@ -22,17 +22,38 @@ const getMeta = () => { const svg = fs.readFileSync(`${ICON_PATH}/${icon.name}.svg`, { encoding, }); - return { path: svg.match(/ d="([^"]+)"/)[1], name: icon.name }; + return { + path: svg.match(/ d="([^"]+)"/)[1], + name: icon.name, + tags: icon.tags, + }; }); }; const addRemovedMeta = (meta) => { const file = fs.readFileSync(REMOVED_ICONS_PATH, { encoding }); const removed = JSON.parse(file); - const combinedMeta = [...meta, ...removed]; + const removedMeta = removed.map((removeIcon) => ({ + path: removeIcon.path, + name: removeIcon.name, + tags: [], + })); + const combinedMeta = [...meta, ...removedMeta]; return combinedMeta.sort((a, b) => a.name.localeCompare(b.name)); }; +const homeAutomationTag = "Home Automation"; + +const orderMeta = (meta) => { + const homeAutomationMeta = meta.filter((icon) => + icon.tags.includes(homeAutomationTag) + ); + const otherMeta = meta.filter( + (icon) => !icon.tags.includes(homeAutomationTag) + ); + return [...homeAutomationMeta, ...otherMeta]; +}; + const splitBySize = (meta) => { const chunks = []; const CHUNK_SIZE = 50000; @@ -77,8 +98,9 @@ const findDifferentiator = (curString, prevString) => { }; gulp.task("gen-icons-json", (done) => { - const meta = addRemovedMeta(getMeta()); - const split = splitBySize(meta); + const meta = getMeta(); + const metaAndRemoved = addRemovedMeta(meta); + const split = splitBySize(metaAndRemoved); if (!fs.existsSync(OUTPUT_DIR)) { fs.mkdirSync(OUTPUT_DIR, { recursive: true }); @@ -116,5 +138,12 @@ gulp.task("gen-icons-json", (done) => { JSON.stringify({ version: package.version, parts }) ); + const orderedMeta = orderMeta(meta); + + fs.writeFileSync( + path.resolve(OUTPUT_DIR, "iconList.json"), + JSON.stringify(orderedMeta.map((icon) => icon.name)) + ); + done(); }); diff --git a/src/components/ha-icon-picker.ts b/src/components/ha-icon-picker.ts new file mode 100644 index 0000000000..added27c6e --- /dev/null +++ b/src/components/ha-icon-picker.ts @@ -0,0 +1,142 @@ +import "@polymer/paper-input/paper-input"; +import { mdiCheck } from "@mdi/js"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query } from "lit/decorators"; +import { fireEvent } from "../common/dom/fire_event"; +import { PolymerChangedEvent } from "../polymer-types"; +import "./ha-icon"; +import iconList from "../../build/mdi/iconList.json"; + +const mdiIconList = iconList.map((icon) => `mdi:${icon}`); + +// eslint-disable-next-line lit/prefer-static-styles +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + + + + ${item} + `; + +@customElement("ha-icon-picker") +export class HaIconPicker extends LitElement { + @property() public value?: string; + + @property() public label?: string; + + @property() public placeholder?: string; + + @property({ attribute: "error-message" }) public errorMessage?: string; + + @property({ type: Boolean }) public disabled = false; + + @query("vaadin-combo-box-light", true) private comboBox!: HTMLElement; + + @property({ type: Boolean }) private _opened = false; + + protected render(): TemplateResult { + return html` + + + ${!this._opened && (this._value || this.placeholder) + ? html` + + + ` + : ""} + + + `; + } + + private _openedChanged(ev: PolymerChangedEvent) { + this._opened = ev.detail.value; + } + + private _valueChanged(ev: PolymerChangedEvent) { + this._setValue(ev.detail.value); + } + + private _setValue(value: string) { + this.value = value; + fireEvent( + this, + "value-changed", + { value }, + { + bubbles: false, + composed: false, + } + ); + } + + private _filterChanged(ev: CustomEvent): void { + const filterString = ev.detail.value.toLowerCase(); + const characterCount = filterString.length; + if (characterCount >= 2) { + const filteredItems = mdiIconList.filter((icon) => + icon.toLowerCase().includes(filterString) + ); + if (filteredItems.length > 0) { + (this.comboBox as any).filteredItems = filteredItems; + } else { + (this.comboBox as any).filteredItems = [filterString]; + } + } else { + (this.comboBox as any).filteredItems = []; + } + } + + private get _value() { + return this.value || ""; + } + + static get styles() { + return css` + ha-icon { + position: absolute; + bottom: 2px; + right: 0; + } + `; + } +} diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index b7936933e6..15dacde33d 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -15,7 +15,7 @@ import { computeDomain } from "../../../common/entity/compute_domain"; import { domainIcon } from "../../../common/entity/domain_icon"; import "../../../components/ha-area-picker"; import "../../../components/ha-expansion-panel"; -import "../../../components/ha-icon-input"; +import "../../../components/ha-icon-picker"; import "../../../components/ha-switch"; import type { HaSwitch } from "../../../components/ha-switch"; import { @@ -133,7 +133,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { .placeholder=${this.entry.original_name} .disabled=${this._submitting} > - + > - + > - + > `; } diff --git a/src/panels/config/helpers/forms/ha-input_datetime-form.ts b/src/panels/config/helpers/forms/ha-input_datetime-form.ts index d28277078c..87c6931c8d 100644 --- a/src/panels/config/helpers/forms/ha-input_datetime-form.ts +++ b/src/panels/config/helpers/forms/ha-input_datetime-form.ts @@ -4,7 +4,7 @@ import "@polymer/paper-radio-group/paper-radio-group"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/ha-icon-input"; +import "../../../../components/ha-icon-picker"; import { InputDateTime } from "../../../../data/input_datetime"; import { haStyle } from "../../../../resources/styles"; import { HomeAssistant } from "../../../../types"; @@ -70,14 +70,14 @@ class HaInputDateTimeForm extends LitElement { .invalid=${nameInvalid} dialogInitialFocus > - + >
${this.hass.localize("ui.dialogs.helper_settings.input_datetime.mode")}:
diff --git a/src/panels/config/helpers/forms/ha-input_number-form.ts b/src/panels/config/helpers/forms/ha-input_number-form.ts index a87ea0cde0..b65e5d1ed8 100644 --- a/src/panels/config/helpers/forms/ha-input_number-form.ts +++ b/src/panels/config/helpers/forms/ha-input_number-form.ts @@ -4,7 +4,7 @@ import "@polymer/paper-radio-group/paper-radio-group"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/ha-icon-input"; +import "../../../../components/ha-icon-picker"; import { InputNumber } from "../../../../data/input_number"; import { haStyle } from "../../../../resources/styles"; import { HomeAssistant } from "../../../../types"; @@ -85,14 +85,14 @@ class HaInputNumberForm extends LitElement { .invalid=${nameInvalid} dialogInitialFocus > - + > - + > ${this.hass!.localize( "ui.dialogs.helper_settings.input_select.options" )}: diff --git a/src/panels/config/helpers/forms/ha-input_text-form.ts b/src/panels/config/helpers/forms/ha-input_text-form.ts index 3c951bc8f3..6262913d46 100644 --- a/src/panels/config/helpers/forms/ha-input_text-form.ts +++ b/src/panels/config/helpers/forms/ha-input_text-form.ts @@ -4,7 +4,7 @@ import "@polymer/paper-radio-group/paper-radio-group"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/ha-icon-input"; +import "../../../../components/ha-icon-picker"; import { InputText } from "../../../../data/input_text"; import { haStyle } from "../../../../resources/styles"; import { HomeAssistant } from "../../../../types"; @@ -76,14 +76,14 @@ class HaInputTextForm extends LitElement { .invalid=${nameInvalid} dialogInitialFocus > - + > ${this.hass.userData?.showAdvanced ? html` - + > - + > ${!this._params.dashboard && this.hass.userData?.showAdvanced ? html` - - + diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index 6e7e15d3a2..e6d617990e 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -30,7 +30,7 @@ import "../../../components/ha-button-menu"; import "../../../components/ha-card"; import "../../../components/ha-fab"; import "../../../components/ha-icon-button"; -import "../../../components/ha-icon-input"; +import "../../../components/ha-icon-picker"; import "../../../components/ha-svg-icon"; import "../../../components/ha-yaml-editor"; import type { HaYamlEditor } from "../../../components/ha-yaml-editor"; @@ -213,7 +213,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { @change=${this._aliasChanged} > - - + ${!this.scriptEntityId ? html` - + >
diff --git a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts index af18dd6edd..51796a5546 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entity-card-editor.ts @@ -5,7 +5,7 @@ import { assert, assign, boolean, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../common/dom/fire_event"; import { stateIcon } from "../../../../common/entity/state_icon"; import "../../../../components/entity/ha-entity-attribute-picker"; -import "../../../../components/ha-icon-input"; +import "../../../../components/ha-icon-picker"; import { HomeAssistant } from "../../../../types"; import { EntityCardConfig } from "../../cards/types"; import "../../components/hui-action-editor"; @@ -103,7 +103,7 @@ export class HuiEntityCardEditor .configValue=${"name"} @value-changed=${this._valueChanged} > - + >
- + >
- + >
- + > - + >