mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 02:06:42 +00:00
Custom iconsets in Icon Picker (#10399)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
5ef7a37c20
commit
df572d59c5
@ -7,6 +7,7 @@ import { css, html, LitElement, TemplateResult } from "lit";
|
|||||||
import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers";
|
import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { customIcons } from "../data/custom_icons";
|
||||||
import { PolymerChangedEvent } from "../polymer-types";
|
import { PolymerChangedEvent } from "../polymer-types";
|
||||||
import "./ha-icon";
|
import "./ha-icon";
|
||||||
import "./ha-icon-button";
|
import "./ha-icon-button";
|
||||||
@ -111,11 +112,36 @@ export class HaIconPicker extends LitElement {
|
|||||||
this._opened = ev.detail.value;
|
this._opened = ev.detail.value;
|
||||||
if (this._opened && !iconItems.length) {
|
if (this._opened && !iconItems.length) {
|
||||||
const iconList = await import("../../build/mdi/iconList.json");
|
const iconList = await import("../../build/mdi/iconList.json");
|
||||||
|
|
||||||
iconItems = iconList.default.map((icon) => ({
|
iconItems = iconList.default.map((icon) => ({
|
||||||
icon: `mdi:${icon.name}`,
|
icon: `mdi:${icon.name}`,
|
||||||
keywords: icon.keywords,
|
keywords: icon.keywords,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
(this.comboBox as any).filteredItems = iconItems;
|
(this.comboBox as any).filteredItems = iconItems;
|
||||||
|
|
||||||
|
Object.keys(customIcons).forEach((iconSet) => {
|
||||||
|
this._loadCustomIconItems(iconSet);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _loadCustomIconItems(iconsetPrefix: string) {
|
||||||
|
try {
|
||||||
|
const getIconList = customIcons[iconsetPrefix].getIconList;
|
||||||
|
if (typeof getIconList !== "function") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const iconList = await getIconList();
|
||||||
|
const customIconItems = iconList.map((icon) => ({
|
||||||
|
icon: `${iconsetPrefix}:${icon.name}`,
|
||||||
|
keywords: icon.keywords ?? [],
|
||||||
|
}));
|
||||||
|
iconItems.push(...customIconItems);
|
||||||
|
(this.comboBox as any).filteredItems = iconItems;
|
||||||
|
} catch (e) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
console.warn(`Unable to load icon list for ${iconsetPrefix} iconset`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +184,9 @@ export class HaIconPicker extends LitElement {
|
|||||||
if (filteredItems.length > 0) {
|
if (filteredItems.length > 0) {
|
||||||
(this.comboBox as any).filteredItems = filteredItems;
|
(this.comboBox as any).filteredItems = filteredItems;
|
||||||
} else {
|
} else {
|
||||||
(this.comboBox as any).filteredItems = [filterString];
|
(this.comboBox as any).filteredItems = [
|
||||||
|
{ icon: filterString, keywords: [] },
|
||||||
|
];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(this.comboBox as any).filteredItems = iconItems;
|
(this.comboBox as any).filteredItems = iconItems;
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { debounce } from "../common/util/debounce";
|
import { debounce } from "../common/util/debounce";
|
||||||
import { CustomIcon, customIconsets } from "../data/custom_iconsets";
|
import { CustomIcon, customIcons } from "../data/custom_icons";
|
||||||
import {
|
import {
|
||||||
checkCacheVersion,
|
checkCacheVersion,
|
||||||
Chunks,
|
Chunks,
|
||||||
@ -356,7 +356,7 @@ export class HaIcon extends LitElement {
|
|||||||
|
|
||||||
@state() private _path?: string;
|
@state() private _path?: string;
|
||||||
|
|
||||||
@state() private _viewBox?;
|
@state() private _viewBox?: string;
|
||||||
|
|
||||||
@state() private _legacy = false;
|
@state() private _legacy = false;
|
||||||
|
|
||||||
@ -386,6 +386,7 @@ export class HaIcon extends LitElement {
|
|||||||
if (!this.icon) {
|
if (!this.icon) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const requestedIcon = this.icon;
|
||||||
const [iconPrefix, origIconName] = this.icon.split(":", 2);
|
const [iconPrefix, origIconName] = this.icon.split(":", 2);
|
||||||
|
|
||||||
let iconName = origIconName;
|
let iconName = origIconName;
|
||||||
@ -395,10 +396,10 @@ export class HaIcon extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!MDI_PREFIXES.includes(iconPrefix)) {
|
if (!MDI_PREFIXES.includes(iconPrefix)) {
|
||||||
if (iconPrefix in customIconsets) {
|
if (iconPrefix in customIcons) {
|
||||||
const customIconset = customIconsets[iconPrefix];
|
const customIcon = customIcons[iconPrefix];
|
||||||
if (customIconset) {
|
if (customIcon && typeof customIcon.getIcon === "function") {
|
||||||
this._setCustomPath(customIconset(iconName));
|
this._setCustomPath(customIcon.getIcon(iconName), requestedIcon);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -441,14 +442,16 @@ export class HaIcon extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (databaseIcon) {
|
if (databaseIcon) {
|
||||||
|
if (this.icon === requestedIcon) {
|
||||||
this._path = databaseIcon;
|
this._path = databaseIcon;
|
||||||
|
}
|
||||||
cachedIcons[iconName] = databaseIcon;
|
cachedIcons[iconName] = databaseIcon;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const chunk = findIconChunk(iconName);
|
const chunk = findIconChunk(iconName);
|
||||||
|
|
||||||
if (chunk in chunks) {
|
if (chunk in chunks) {
|
||||||
this._setPath(chunks[chunk], iconName);
|
this._setPath(chunks[chunk], iconName, requestedIcon);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,19 +459,31 @@ export class HaIcon extends LitElement {
|
|||||||
response.json()
|
response.json()
|
||||||
);
|
);
|
||||||
chunks[chunk] = iconPromise;
|
chunks[chunk] = iconPromise;
|
||||||
this._setPath(iconPromise, iconName);
|
this._setPath(iconPromise, iconName, requestedIcon);
|
||||||
debouncedWriteCache();
|
debouncedWriteCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _setCustomPath(promise: Promise<CustomIcon>) {
|
private async _setCustomPath(
|
||||||
|
promise: Promise<CustomIcon>,
|
||||||
|
requestedIcon: string
|
||||||
|
) {
|
||||||
const icon = await promise;
|
const icon = await promise;
|
||||||
|
if (this.icon !== requestedIcon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._path = icon.path;
|
this._path = icon.path;
|
||||||
this._viewBox = icon.viewBox;
|
this._viewBox = icon.viewBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _setPath(promise: Promise<Icons>, iconName: string) {
|
private async _setPath(
|
||||||
|
promise: Promise<Icons>,
|
||||||
|
iconName: string,
|
||||||
|
requestedIcon: string
|
||||||
|
) {
|
||||||
const iconPack = await promise;
|
const iconPack = await promise;
|
||||||
|
if (this.icon === requestedIcon) {
|
||||||
this._path = iconPack[iconName];
|
this._path = iconPack[iconName];
|
||||||
|
}
|
||||||
cachedIcons[iconName] = iconPack[iconName];
|
cachedIcons[iconName] = iconPack[iconName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
src/data/custom_icons.ts
Normal file
40
src/data/custom_icons.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { customIconsets } from "./custom_iconsets";
|
||||||
|
|
||||||
|
export interface CustomIcon {
|
||||||
|
path: string;
|
||||||
|
viewBox?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomIconListItem {
|
||||||
|
name: string;
|
||||||
|
keywords?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomIconHelpers {
|
||||||
|
getIcon: (name: string) => Promise<CustomIcon>;
|
||||||
|
getIconList?: () => Promise<CustomIconListItem[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomIconsWindow {
|
||||||
|
customIcons?: {
|
||||||
|
[key: string]: CustomIconHelpers;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const customIconsWindow = window as CustomIconsWindow;
|
||||||
|
|
||||||
|
if (!("customIcons" in customIconsWindow)) {
|
||||||
|
customIconsWindow.customIcons = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy for backward compatibility with icon sets
|
||||||
|
export const customIcons = new Proxy(customIconsWindow.customIcons!, {
|
||||||
|
get: (obj, prop: string) =>
|
||||||
|
obj[prop] ??
|
||||||
|
(customIconsets[prop]
|
||||||
|
? {
|
||||||
|
getIcon: customIconsets[prop],
|
||||||
|
}
|
||||||
|
: undefined),
|
||||||
|
has: (obj, prop: string) => prop in obj || prop in customIconsets,
|
||||||
|
});
|
@ -1,9 +1,6 @@
|
|||||||
export interface CustomIcon {
|
import { CustomIcon } from "./custom_icons";
|
||||||
path: string;
|
|
||||||
viewBox?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CustomIconsetsWindow {
|
interface CustomIconsetsWindow {
|
||||||
customIconsets?: { [key: string]: (name: string) => Promise<CustomIcon> };
|
customIconsets?: { [key: string]: (name: string) => Promise<CustomIcon> };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user