Improve the entire icon logic

- Tree Shaking for Icons (Closes #53)
- New API for the config (See 
https://github.com/uwap/mqtt-control-map/wiki/Icons)
- Icons can now be colored everywhere, not just on the map
This commit is contained in:
uwap 2020-10-08 08:36:56 +02:00
parent 43a33c3ab3
commit 856aab41ad
18 changed files with 288 additions and 269 deletions

View file

@ -100,7 +100,6 @@ export type Control = {
name: string,
position: [number, number],
icon: Icon,
iconColor?: (state: State) => Color,
ui: Array<ControlUI>
};
export type Controls = Map<string, Control>;

View file

@ -1,54 +1,85 @@
// @flow
import * as React from "react";
import React from "react";
import ReactIcon from "@mdi/react";
import ReactContext from "mqtt/context";
import { hex, type Color } from "./colors"
import * as mdiIcons from "@mdi/js"
export opaque type RawIcon: string = string;
export type Icon = (State) => RawIcon;
export const rawMdi = (name: string): RawIcon => {
return `mdi ${name.split(" ").map((icon) => "mdi-".concat(icon)).join(" ")}`;
export type Icon = {
render: (s: State) => React.Node,
size: (n: number) => Icon,
rotate: (n: number) => Icon,
flip: () => Icon,
flipV: () => Icon,
color: (c: Color | (State) => Color) => Icon
};
export const mdi = (icon: string) => () => rawMdi(icon);
type IconPropHelper = {
size?: number,
rotate?: number,
horizontal?: boolean,
vertical?: boolean,
color?: Color
};
export const mdiBattery = (topic: string) => (state: State) => {
export const svg = (data: string, props?: IconPropHelper): Icon => {
const propColor = ((c: Color | (State) => Color) => (state: State) => {
if (typeof c === "function") {
return c(state);
}
return c;
})(props?.color ?? "black");
return {
render: (state) => (
<ReactIcon path={data} size={props?.size ?? 1.5}
rotate={props?.rotate ?? 0}
horizontal={props?.horizontal ?? false}
vertical={props?.vertical ?? false}
color={propColor(state)}
/>
),
size: (n: number) => svg(data, {...props, size: n}),
rotate: (n: number) => svg(data, {...props, rotate: n}),
flip: () => svg(data, {...props, horizontal: !props?.horizontal ?? true}),
flipV: () => svg(data, {...props, vertical: !props?.vertical ?? true}),
color: (c: Color | (State) => Color) => svg(data, {...props, color: c})
};
}
export const withState = (f: (s: State) => Icon): Icon => {
return {
render: (state) => f(state).render(state),
size: () => withState(f),
rotate: () => withState(f),
flip: () => withState(f),
flipV: () => withState(f),
color: () => withState(f)
};
}
export const mdiBattery = (topic: string): Icon => withState((state) => {
const rawval = state[topic];
const val = parseInt(rawval, 10);
if (isNaN(val)) {
return rawMdi("battery-unknown");
return svg(mdiIcons.mdiBatteryUnknown);
} else if (val > 95) {
return rawMdi("battery");
return svg(mdiIcons.mdiBattery);
} else if (val > 85) {
return rawMdi("battery-90");
return svg(mdiIcons.mdiBattery90);
} else if (val > 75) {
return rawMdi("battery-80");
return svg(mdiIcons.mdiBattery80);
} else if (val > 65) {
return rawMdi("battery-70");
return svg(mdiIcons.mdiBattery70);
} else if (val > 55) {
return rawMdi("battery-60");
return svg(mdiIcons.mdiBattery60);
} else if (val > 45) {
return rawMdi("battery-50");
return svg(mdiIcons.mdiBattery50);
} else if (val > 35) {
return rawMdi("battery-40");
return svg(mdiIcons.mdiBattery40);
} else if (val > 25) {
return rawMdi("battery-30");
return svg(mdiIcons.mdiBattery30);
} else if (val > 15) {
return rawMdi("battery-20");
return svg(mdiIcons.mdiBattery20);
}
return rawMdi("battery-10");
};
export const renderRawIcon =
(icon: RawIcon, extraClass?: string): React.Node => {
return <i className={`${extraClass || ""} ${icon}`}></i>;
};
export const renderIcon =
(icon: Icon, extraClass?: string): React.Node => {
return (
<ReactContext.Consumer>
{({state}) => renderRawIcon(icon(state), extraClass)}
</ReactContext.Consumer>
);
};
return svg(mdiIcons.mdiBattery10);
});