Files
frontend/src/components/ha-icon.ts
Zack Arnett 71492d0467 Calendar Panel: FullCalendar (#5742)
* WIP

* remove big calendar

* remove file

* Convert to lit

* More

* Ready for the public to see? prob not

* Fix types and imports

* Remove dependencies

* ignore the typing that hasnt been finished in Beta

* Convert paper to MWC

* Styling

* View list as name of view | MWC components version

* Updates action directive for ripple. MWC 14.1.0

* Update

* Updates

* Update height styling

* Toggle Button Group

* Adds Toggle group transition

* style updates

* Few fixes

* Fix Yarn lock from merge | height of celndar as parent

* Update package Json and yarn | remove unneeded pkg

* Remove mwc-list

* Search hass.states for calendars instead of api

* Move function to file in data | event fetch logic

* compute state name

* add ha button menu | refresh

* Remove Event ffetch logic

* copy pasta

* Types

* Fix for toggling

* Translations

* Update ha-button-toggle-group

* Update ha-button-toggle-group.ts

* Update ha-button-toggle-group.ts

* Change mobile view

* Locale in fullcalendar

* Comments

* ha-button-menu trigger slot

* Comments

* icon-x

* Update src/panels/calendar/ha-panel-calendar.ts

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

* Update src/panels/calendar/ha-panel-calendar.ts

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-05-06 17:22:12 -04:00

140 lines
3.2 KiB
TypeScript

import "@polymer/iron-icon/iron-icon";
import { get, set, clear, Store } from "idb-keyval";
import {
customElement,
LitElement,
property,
PropertyValues,
html,
TemplateResult,
css,
CSSResult,
} from "lit-element";
import "./ha-svg-icon";
import { debounce } from "../common/util/debounce";
import { iconMetadata } from "../resources/icon-metadata";
import { IconMeta } from "../types";
interface Icons {
[key: string]: string;
}
interface Chunks {
[key: string]: Promise<Icons>;
}
const iconStore = new Store("hass-icon-db", "mdi-icon-store");
get("_version", iconStore).then((version) => {
if (!version) {
set("_version", iconMetadata.version, iconStore);
} else if (version !== iconMetadata.version) {
clear(iconStore).then(() =>
set("_version", iconMetadata.version, iconStore)
);
}
});
const chunks: Chunks = {};
const MDI_PREFIXES = ["mdi", "hass", "hassio", "hademo"];
const findIconChunk = (icon): string => {
let lastChunk: IconMeta;
for (const chunk of iconMetadata.parts) {
if (chunk.start !== undefined && icon < chunk.start) {
break;
}
lastChunk = chunk;
}
return lastChunk!.file;
};
const debouncedWriteCache = debounce(async () => {
const keys = Object.keys(chunks);
const iconsSets: Icons[] = await Promise.all(Object.values(chunks));
// We do a batch opening the store just once, for (considerable) performance
iconStore._withIDBStore("readwrite", (store) => {
iconsSets.forEach((icons, idx) => {
Object.entries(icons).forEach(([name, path]) => {
store.put(path, name);
});
delete chunks[keys[idx]];
});
});
}, 2000);
@customElement("ha-icon")
export class HaIcon extends LitElement {
@property() public icon?: string;
@property() private _path?: string;
@property() private _noMdi = false;
protected updated(changedProps: PropertyValues) {
if (changedProps.has("icon")) {
this._loadIcon();
}
}
protected render(): TemplateResult {
if (!this.icon) {
return html``;
}
if (this._noMdi) {
return html`<iron-icon .icon=${this.icon}></iron-icon>`;
}
return html`<ha-svg-icon .path=${this._path}></ha-svg-icon>`;
}
private async _loadIcon() {
if (!this.icon) {
return;
}
const icon = this.icon.split(":", 2);
if (!MDI_PREFIXES.includes(icon[0])) {
this._noMdi = true;
return;
}
this._noMdi = false;
const iconName = icon[1];
const cachedPath: string = await get(iconName, iconStore);
if (cachedPath) {
this._path = cachedPath;
return;
}
const chunk = findIconChunk(iconName);
if (chunk in chunks) {
this._setPath(chunks[chunk], iconName);
return;
}
const iconPromise = fetch(`/static/mdi/${chunk}.json`).then((response) =>
response.json()
);
chunks[chunk] = iconPromise;
this._setPath(iconPromise, iconName);
debouncedWriteCache();
}
private async _setPath(promise: Promise<Icons>, iconName: string) {
const iconPack = await promise;
this._path = iconPack[iconName];
}
static get styles(): CSSResult {
return css`
:host {
fill: currentcolor;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-icon": HaIcon;
}
}