Update to material-ui 1.0 beta
This commit is contained in:
parent
48a96b57fa
commit
bef07649d0
14 changed files with 1164 additions and 395 deletions
|
|
@ -1,5 +1,4 @@
|
||||||
[ignore]
|
[ignore]
|
||||||
.*node_modules/react-event-listener/.*
|
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
src/
|
src/
|
||||||
|
|
|
||||||
BIN
img/layers/rzl/details.png
Normal file
BIN
img/layers/rzl/details.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
img/layers/rzl/labels.png
Normal file
BIN
img/layers/rzl/labels.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
img/layers/rzl/rooms.png
Normal file
BIN
img/layers/rzl/rooms.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
|
|
@ -57,11 +57,14 @@
|
||||||
/* Support for IE. */
|
/* Support for IE. */
|
||||||
font-feature-settings: 'liga';
|
font-feature-settings: 'liga';
|
||||||
}
|
}
|
||||||
|
#drawer_uiComponents .material-icons {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="public/dist/main.js"></script>
|
<script src="dist/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
10
package.json
10
package.json
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "reacttest",
|
"name": "spacemap",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "uwap <me@uwap.name>",
|
"author": "uwap <me+spacemap.package.json@uwap.name>",
|
||||||
"description": "react",
|
"description": "control devices via mqtt on a beautiful map of your space",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --bail",
|
"build": "webpack --bail",
|
||||||
"watch": "webpack --watch"
|
"watch": "webpack --watch"
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-preset-env": "^1.6.0",
|
"babel-preset-env": "^1.6.0",
|
||||||
"leaflet": "^1.2.0",
|
"leaflet": "^1.2.0",
|
||||||
"material-ui": "^0.18.7",
|
"material-ui": "next",
|
||||||
|
"material-ui-old": "npm:material-ui@latest",
|
||||||
"mqtt": "^2.11.0",
|
"mqtt": "^2.11.0",
|
||||||
"ramda": "^0.24.1",
|
"ramda": "^0.24.1",
|
||||||
"react": "^15.6.1",
|
"react": "^15.6.1",
|
||||||
|
|
@ -26,6 +27,7 @@
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
"flow": "^0.2.3",
|
"flow": "^0.2.3",
|
||||||
"flow-bin": "^0.50.0",
|
"flow-bin": "^0.50.0",
|
||||||
|
"flow-typed": "^2.2.1",
|
||||||
"webpack": "^3.1.0",
|
"webpack": "^3.1.0",
|
||||||
"webpack-shell-plugin": "^0.5.0"
|
"webpack-shell-plugin": "^0.5.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,38 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Toggle from "material-ui/Toggle";
|
import Switch from "material-ui/Switch";
|
||||||
import SelectField from 'material-ui/SelectField';
|
import Select from 'material-ui/Select';
|
||||||
import MenuItem from 'material-ui/MenuItem';
|
import { MenuItem } from 'material-ui/Menu';
|
||||||
import Slider from 'material-ui/Slider';
|
import Slider from 'material-ui-old/Slider';
|
||||||
|
import MuiThemeProvider from 'material-ui-old/styles/MuiThemeProvider';
|
||||||
|
import Icon from 'material-ui/Icon';
|
||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
import { keyOf } from "./util";
|
import { keyOf } from "./util";
|
||||||
|
import Input, { InputLabel } from 'material-ui/Input';
|
||||||
|
import { FormControl } from 'material-ui/Form';
|
||||||
import R from "ramda";
|
import R from "ramda";
|
||||||
|
import List, {
|
||||||
|
ListItem,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemSecondaryAction,
|
||||||
|
ListItemText,
|
||||||
|
ListSubheader,
|
||||||
|
} from 'material-ui/List';
|
||||||
|
|
||||||
const enabled = (props: ControlUI, state: State) => {
|
const enabled = (props: ControlUI, state: State) => {
|
||||||
if (props.enableCondition == null) return true;
|
if (props.enableCondition == null) return true;
|
||||||
else {
|
else {
|
||||||
const val = state.values[props.topic];
|
const val = state.values[props.topic];
|
||||||
return props.enableCondition(
|
return props.enableCondition(
|
||||||
val.internal == null ? val.actual : val.internal, val.actual);
|
val.internal == null ? val.actual : val.internal, val.actual, R.map(x => x.internal == null ?
|
||||||
|
x.actual : x.internal, state.values == null ? {} : state.values));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getValue = (topic: string, val: string) =>
|
const getValue = (topic: string, val: string) =>
|
||||||
Config.topics[topic].values[val];
|
Config.topics[topic].values[val];
|
||||||
|
|
||||||
const onToggle = (topic: string, props: ControlUI, state: State) =>
|
const onSwitch = (topic: string, props: ControlUI, state: State) =>
|
||||||
(x, toggled: boolean) => {
|
(x, toggled: boolean) => {
|
||||||
if (state.mqtt != null) {
|
if (state.mqtt != null) {
|
||||||
state.mqtt.publish(Config.topics[topic].command,
|
state.mqtt.publish(Config.topics[topic].command,
|
||||||
|
|
@ -39,31 +51,49 @@ export const toggle = (state: State, props: ControlUI) => {
|
||||||
return val.internal === R.propOr("on", "on", props);
|
return val.internal === R.propOr("on", "on", props);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return (<Toggle label={props.text}
|
return (
|
||||||
toggled={toggled}
|
<ListItem>
|
||||||
onToggle={onToggle(props.topic, props, state)}
|
{props.icon && <ListItemIcon><Icon>{props.icon}</Icon></ListItemIcon>}
|
||||||
|
<ListItemText primary={props.text} />
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<Switch label={props.text}
|
||||||
|
checked={toggled}
|
||||||
|
onChange={onSwitch(props.topic, props, state)}
|
||||||
disabled={!(enabled(props, state))} />
|
disabled={!(enabled(props, state))} />
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDropDownChange = (topic: string, props: ControlUI, state: State) =>
|
const onDropDownChange = (topic: string, props: ControlUI, state: State) =>
|
||||||
(event, index, value) => {
|
(event) => {
|
||||||
if (state.mqtt != null) {
|
if (state.mqtt != null) {
|
||||||
state.mqtt.publish(Config.topics[topic].command, value);
|
state.mqtt.publish(Config.topics[topic].command, event.target.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const dropDownItem = (topic: string) => (text: string, key: string) => (
|
const dropDownItem = (topic: string) => (text: string, key: string) => (
|
||||||
<MenuItem value={Config.topics[topic].values[key]} primaryText={text} />
|
<MenuItem value={Config.topics[topic].values[key]} key={key}>{text}</MenuItem>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const dropDown = (state: State, props: ControlUI) => (
|
export const dropDown = (state: State, props: ControlUI) => {
|
||||||
<SelectField value={state.values[props.topic].actual}
|
const id = `${props.topic}.${Object.keys(props.options).reduce((v,r) => v + "." + r)}`;
|
||||||
|
return (
|
||||||
|
<ListItem>
|
||||||
|
{props.icon && <ListItemIcon><Icon>{props.icon}</Icon></ListItemIcon>}
|
||||||
|
<FormControl>
|
||||||
|
<InputLabel htmlFor={id}>{props.text}</InputLabel>
|
||||||
|
<Select value={state.values[props.topic].actual}
|
||||||
onChange={onDropDownChange(props.topic, props, state)}
|
onChange={onDropDownChange(props.topic, props, state)}
|
||||||
disabled={!(enabled(props, state))}>
|
disabled={!(enabled(props, state))}
|
||||||
|
input={<Input id={id} />}
|
||||||
|
>
|
||||||
{R.values(R.mapObjIndexed(dropDownItem(props.topic), props.options))}
|
{R.values(R.mapObjIndexed(dropDownItem(props.topic), props.options))}
|
||||||
</SelectField>
|
</Select>
|
||||||
);
|
</FormControl>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const onSliderChange = (state: State, props: ControlUI) =>
|
const onSliderChange = (state: State, props: ControlUI) =>
|
||||||
(event, value) => {
|
(event, value) => {
|
||||||
|
|
@ -73,13 +103,22 @@ const onSliderChange = (state: State, props: ControlUI) =>
|
||||||
};
|
};
|
||||||
|
|
||||||
export const slider = (state: State, props: ControlUI) => (
|
export const slider = (state: State, props: ControlUI) => (
|
||||||
<div>
|
<ListItem>
|
||||||
<span>{props.text}</span>
|
{props.icon && <ListItemIcon><Icon>{props.icon}</Icon></ListItemIcon>}
|
||||||
|
<ListItemText primary={props.text} />
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<MuiThemeProvider>
|
||||||
<Slider value={state.values[props.topic].actual}
|
<Slider value={state.values[props.topic].actual}
|
||||||
min={props.min == null ? 0 : props.min}
|
min={props.min == null ? 0 : props.min}
|
||||||
max={props.max == null ? 1 : props.max}
|
max={props.max == null ? 1 : props.max}
|
||||||
step={props.step == null ? 1 : props.step}
|
step={props.step == null ? 1 : props.step}
|
||||||
onChange={onSliderChange(state, props)}
|
onChange={onSliderChange(state, props)}
|
||||||
/>
|
style={{width: 100}}
|
||||||
</div>
|
/></MuiThemeProvider>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const section = (state: State, props: ControlUI) => (
|
||||||
|
<ListSubheader>{props.text}</ListSubheader>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,44 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import AppBar from "material-ui/AppBar";
|
import AppBar from "material-ui/AppBar";
|
||||||
import CircularProgress from "material-ui/CircularProgress";
|
import Toolbar from 'material-ui/Toolbar';
|
||||||
import MapIcon from "material-ui/svg-icons/maps/map";
|
import { CircularProgress } from "material-ui/Progress";
|
||||||
import PhonelinkOffIcon from "material-ui/svg-icons/hardware/phonelink-off";
|
import Icon from 'material-ui/Icon';
|
||||||
import LayersIcon from "material-ui/svg-icons/maps/layers";
|
|
||||||
import IconMenu from "material-ui/IconMenu";
|
|
||||||
import IconButton from "material-ui/IconButton";
|
import IconButton from "material-ui/IconButton";
|
||||||
import MenuItem from "material-ui/MenuItem";
|
import Menu, { MenuItem } from "material-ui/Menu";
|
||||||
import { orange400, grey50 } from "material-ui/styles/colors";
|
import Typography from 'material-ui/Typography';
|
||||||
|
|
||||||
const TopBarLayerSelector = (props: Object) => (
|
const TopBarLayerSelector = (props: Object) => (
|
||||||
<IconMenu
|
<IconButton>
|
||||||
iconButtonElement={
|
<Icon>layers</Icon>
|
||||||
<IconButton style={{width: 48, height: 48, padding: 0}}
|
</IconButton>
|
||||||
iconStyle={{width: 48, height: 48}}>
|
|
||||||
<LayersIcon color={grey50} />
|
|
||||||
</IconButton>}
|
|
||||||
style={{width:48, height:48}}>
|
|
||||||
<MenuItem primaryText="Layer1" />
|
|
||||||
</IconMenu>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const TopBarIndicatorMenu = (props: Object) => (
|
const TopBarIndicatorMenu = (props: Object) => (
|
||||||
<IconMenu
|
<IconButton>
|
||||||
iconButtonElement={
|
|
||||||
<IconButton style={{width:48, height:48, padding: 0}}
|
|
||||||
iconStyle={{width:48, height: 48}}
|
|
||||||
tooltip={props.mqtt.connected ? "Connected!" : "Disconnected!"}>
|
|
||||||
{props.mqtt.connected ?
|
{props.mqtt.connected ?
|
||||||
(<MapIcon color={grey50} />) :
|
(<Icon style={{fontSize: 48}}>map</Icon>) :
|
||||||
(<PhonelinkOffIcon color={grey50} />)}
|
(<Icon style={{fontSize: 48}}>phonelink_off</Icon>)}
|
||||||
</IconButton>}
|
</IconButton>
|
||||||
style={{width:48, height:48}}>
|
|
||||||
<MenuItem primaryText="Reconnect (Not yet implemented)" />
|
|
||||||
</IconMenu>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const TopBarIndicator = (props: Object) => {
|
const TopBarIndicator = (props: Object) => {
|
||||||
if (props.mqtt == null || props.mqtt.reconnecting) {
|
if (props.mqtt == null || props.mqtt.reconnecting) {
|
||||||
return (<CircularProgress size={48} color={grey50} />);
|
return (<CircularProgress size={48} style={{color: "rgba(0, 0, 0, 0.54)"}} />);
|
||||||
} else {
|
} else {
|
||||||
return (<TopBarIndicatorMenu {...props} />);
|
return (<TopBarIndicatorMenu {...props} />);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const TopBar = (props: Object) => (
|
const TopBar = (props: Object) => (
|
||||||
<AppBar title={props.title}
|
<AppBar position="static">
|
||||||
style={{background:orange400}}
|
<Toolbar>
|
||||||
iconElementLeft={<TopBarIndicator {...props} />}
|
<TopBarIndicator {...props} />
|
||||||
iconElementRight={<TopBarLayerSelector {...props} />}
|
<Typography type="title">{props.title}</Typography>
|
||||||
className="nav"
|
{false && <TopBarLayerSelector {...props} />}
|
||||||
/>);
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
);
|
||||||
|
|
||||||
export default TopBar;
|
export default TopBar;
|
||||||
|
|
|
||||||
130
src/config.js
130
src/config.js
|
|
@ -51,6 +51,20 @@ const config : Config = {
|
||||||
blue: "blue", green: "green", red: "red", random: "random",
|
blue: "blue", green: "green", red: "red", random: "random",
|
||||||
cycle: "cycle-random" }
|
cycle: "cycle-random" }
|
||||||
},
|
},
|
||||||
|
onkyo_power: {
|
||||||
|
state: "/service/onkyo/status/system-power",
|
||||||
|
command: "/service/onkyo/command",
|
||||||
|
defaultValue: "PWR00",
|
||||||
|
values: { off: "PWR00", on: "PWR01" },
|
||||||
|
parseState: msg => JSON.parse(msg.toString()).onkyo_raw
|
||||||
|
},
|
||||||
|
onkyo_mute: {
|
||||||
|
state: "/service/onkyo/status/audio-muting",
|
||||||
|
command: "/service/onkyo/command",
|
||||||
|
defaultValue: "AMT00",
|
||||||
|
values: { off: "AMT00", on: "AMT01" },
|
||||||
|
parseState: msg => JSON.parse(msg.toString()).onkyo_raw
|
||||||
|
},
|
||||||
onkyo_volume: {
|
onkyo_volume: {
|
||||||
state: "/service/onkyo/status/volume",
|
state: "/service/onkyo/status/volume",
|
||||||
command: "/service/onkyo/set/volume",
|
command: "/service/onkyo/set/volume",
|
||||||
|
|
@ -62,9 +76,16 @@ const config : Config = {
|
||||||
state: "/service/onkyo/status/input-selector",
|
state: "/service/onkyo/status/input-selector",
|
||||||
command: "/service/onkyo/command",
|
command: "/service/onkyo/command",
|
||||||
defaultValue: "SLI00",
|
defaultValue: "SLI00",
|
||||||
values: { tisch: "SLI11", chromecast: "SLI01", pult: "SLI10" },
|
values: { tisch: "SLI11", chromecast: "SLI01", pult: "SLI10", netzwerk: "SLI2B" },
|
||||||
parseState: msg => JSON.parse(msg.toString()).onkyo_raw
|
parseState: msg => JSON.parse(msg.toString()).onkyo_raw
|
||||||
},
|
},
|
||||||
|
onkyo_radios: {
|
||||||
|
state: "/service/onkyo/status/latest-NPR",
|
||||||
|
command: "/service/onkyo/command",
|
||||||
|
defaultValue: "",
|
||||||
|
values: { mpd: "NPR01", kohina: "NPR02", somafm_dronezone: "NPR03", somafm_thetrip: "NPR04",
|
||||||
|
querfunk: "NPR05", somafm_defconradio: "NPR06", somafm_secretagent: "NPR07", somafm_lush: "NPR08"}
|
||||||
|
},
|
||||||
rundumleuchte: {
|
rundumleuchte: {
|
||||||
state: "/service/openhab/out/pca301_rundumleuchte/state",
|
state: "/service/openhab/out/pca301_rundumleuchte/state",
|
||||||
command: "/service/openhab/in/pca301_rundumleuchte/command",
|
command: "/service/openhab/in/pca301_rundumleuchte/command",
|
||||||
|
|
@ -87,98 +108,105 @@ const config : Config = {
|
||||||
controls: {
|
controls: {
|
||||||
led_stahltrager: {
|
led_stahltrager: {
|
||||||
name: "LED Stahlträger",
|
name: "LED Stahlträger",
|
||||||
position: [390, 100],
|
position: [380, 300],
|
||||||
icon: "wb_incandescent",
|
icon: "wb_incandescent",
|
||||||
iconColor: state => state.led_stahltraeger == "on" ? "#CCCC00" : "#000000",
|
iconColor: state => state.led_stahltraeger == "on" ? "#CCCC00" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Stahlträger LED",
|
text: "Stahlträger LED",
|
||||||
topic: "led_stahltraeger"
|
topic: "led_stahltraeger",
|
||||||
|
icon: "power_settings_new"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
snackbar: {
|
snackbar: {
|
||||||
name: "Snackbar",
|
name: "Snackbar",
|
||||||
position: [560, 465],
|
position: [510, 500],
|
||||||
icon: "kitchen",
|
icon: "kitchen",
|
||||||
iconColor: state => state.snackbar == "on" ? "#E20074" : "#000000",
|
iconColor: state => state.snackbar == "on" ? "#E20074" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Snackbar",
|
text: "Snackbar",
|
||||||
topic: "snackbar"
|
topic: "snackbar",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
twinkle: {
|
twinkle: {
|
||||||
name: "Twinkle",
|
name: "Twinkle",
|
||||||
position: [500, 540],
|
position: [530, 560],
|
||||||
icon: "wb_incandescent",
|
icon: "wb_incandescent",
|
||||||
iconColor: state => state.twinkle == "on" ? "#CCCC00" : "#000000",
|
iconColor: state => state.twinkle == "on" ? "#CCCC00" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Twinkle",
|
text: "Twinkle",
|
||||||
topic: "twinkle"
|
topic: "twinkle",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
fan: {
|
fan: {
|
||||||
name: "Ventilator",
|
name: "Ventilator",
|
||||||
position: [530, 450],
|
position: [510, 460],
|
||||||
icon: "toys",
|
icon: "toys",
|
||||||
iconColor: state => state.fan == "on" ? "#00FF00" : "#000000",
|
iconColor: state => state.fan == "on" ? "#00FF00" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Ventilator",
|
text: "Ventilator",
|
||||||
topic: "fan"
|
topic: "fan",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
videogames: {
|
videogames: {
|
||||||
name: "Videospiele",
|
name: "Videospiele",
|
||||||
position: [79, 50],
|
position: [100, 100],
|
||||||
icon: "videogame_asset",
|
icon: "videogame_asset",
|
||||||
iconColor: state => state.videogames == "on" ? "#00FF00" : "#000000",
|
iconColor: state => state.videogames == "on" ? "#00FF00" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Videospiele",
|
text: "Videospiele",
|
||||||
topic: "videogames"
|
topic: "videogames",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
olymp_pc: {
|
olymp_pc: {
|
||||||
name: "Rechner und Drucker",
|
name: "Rechner und Drucker",
|
||||||
position: [298, 20],
|
position: [297, 90],
|
||||||
icon: "desktop_windows",
|
icon: "desktop_windows",
|
||||||
iconColor: state => state.olymp_pc == "on" ? "#00FF00" : "#000000",
|
iconColor: state => state.olymp_pc == "on" ? "#00FF00" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Rechner und Drucker",
|
text: "Rechner und Drucker",
|
||||||
topic: "olymp_pc"
|
topic: "olymp_pc",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
flyfry: {
|
flyfry: {
|
||||||
name: "Fliegenbratgerät",
|
name: "Fliegenbratgerät",
|
||||||
position: [450, 560],
|
position: [450, 590],
|
||||||
icon: "whatshot",
|
icon: "whatshot",
|
||||||
iconColor: state => state.flyfry == "on" ? "#6666FF" : "#000000",
|
iconColor: state => state.flyfry == "on" ? "#6666FF" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Fliegenbratgerät",
|
text: "Fliegenbratgerät",
|
||||||
topic: "flyfry"
|
topic: "flyfry",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
artnet: {
|
artnet: {
|
||||||
name: "Artnet",
|
name: "Artnet",
|
||||||
position: [560,430],
|
position: [535,475],
|
||||||
icon: "wb_incandescent",
|
icon: "wb_incandescent",
|
||||||
iconColor: state =>
|
iconColor: state =>
|
||||||
({
|
({
|
||||||
|
|
@ -195,77 +223,121 @@ const config : Config = {
|
||||||
text: "An/Aus",
|
text: "An/Aus",
|
||||||
topic: "artnet",
|
topic: "artnet",
|
||||||
on: "cycle",
|
on: "cycle",
|
||||||
toggled: val => val != "off"
|
toggled: val => val != "off",
|
||||||
|
icon: "power_settings_new"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "dropDown",
|
type: "dropDown",
|
||||||
text: "Artnet",
|
text: "Farbe",
|
||||||
topic: "artnet",
|
topic: "artnet",
|
||||||
options: {
|
options: {
|
||||||
yellow: "Gelb",
|
yellow: "Gelb",
|
||||||
red: "Rot",
|
red: "Rot",
|
||||||
purple: "Pink",
|
purple: "Pink",
|
||||||
green: "Grün",
|
green: "Grün",
|
||||||
cycle: "Cycle Random"
|
cycle: "Farbwechsel"
|
||||||
},
|
},
|
||||||
enableCondition: val => val != "off"
|
enableCondition: val => val != "off",
|
||||||
|
icon: "color_lens"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
onkyo: {
|
onkyo: {
|
||||||
name: "Onkyo",
|
name: "Onkyo",
|
||||||
position: [350, 620],
|
position: [350, 650],
|
||||||
icon: "volume_up",
|
icon: "volume_up",
|
||||||
ui: [
|
ui: [
|
||||||
|
{
|
||||||
|
type: "toggle",
|
||||||
|
text: "Power",
|
||||||
|
icon: "power_settings_new",
|
||||||
|
topic: "onkyo_power"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "section",
|
||||||
|
text: "Lautstärkeregelung"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "slider",
|
type: "slider",
|
||||||
text: "Volume",
|
text: "Volume",
|
||||||
topic: "onkyo_volume",
|
topic: "onkyo_volume",
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 100
|
max: 100,
|
||||||
|
icon: "volume_up"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "toggle",
|
||||||
|
text: "Mute",
|
||||||
|
topic: "onkyo_mute",
|
||||||
|
icon: "volume_off"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "section",
|
||||||
|
text: "Eingänge"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "dropDown",
|
type: "dropDown",
|
||||||
text: "Inputs",
|
text: "Eingang",
|
||||||
topic: "onkyo_inputs",
|
topic: "onkyo_inputs",
|
||||||
options: {
|
options: {
|
||||||
|
netzwerk: "Netzwerk",
|
||||||
tisch: "Tisch",
|
tisch: "Tisch",
|
||||||
chromecast: "Chromecast",
|
chromecast: "Chromecast",
|
||||||
pult: "Pult"
|
pult: "Pult"
|
||||||
}
|
},
|
||||||
|
icon: "settings_input_component"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "dropDown",
|
||||||
|
text: "Netzwerksender",
|
||||||
|
topic: "onkyo_radios",
|
||||||
|
options: {
|
||||||
|
mpd: "MPD",
|
||||||
|
kohina: "Kohina",
|
||||||
|
somafm_dronezone: "Drone Zone (SomaFM)",
|
||||||
|
somafm_thetrip: "The Trip (SomaFM)",
|
||||||
|
querfunk: "Querfunk",
|
||||||
|
somafm_defconradio: "Defcon Radio (SomaFM)",
|
||||||
|
somafm_secretagent: "Secret Agent (SomaFM)",
|
||||||
|
somafm_lush: "Lush (SomaFM)"
|
||||||
|
},
|
||||||
|
icon: "radio",
|
||||||
|
enableCondition: (a, b, state) => state.onkyo_inputs == "netzwerk"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
rundumleuchte: {
|
rundumleuchte: {
|
||||||
name: "Rundumleuchte",
|
name: "Rundumleuchte",
|
||||||
position: [310,220],
|
position: [310,275],
|
||||||
icon: "wb_sunny",
|
icon: "wb_sunny",
|
||||||
iconColor: state => state.rundumleuchte == "on" ? "#CCCC00" : "#000000",
|
iconColor: state => state.rundumleuchte == "on" ? "#CCCC00" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Rundumleuchte",
|
text: "Rundumleuchte",
|
||||||
topic: "rundumleuchte"
|
topic: "rundumleuchte",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
door: {
|
door: {
|
||||||
name: "Tür",
|
name: "Tür",
|
||||||
position: [480,300],
|
position: [455,350],
|
||||||
icon: "swap_vert",
|
icon: "swap_vert",
|
||||||
iconColor: state => state.door_status == "on" ? "#00FF00" : "#FF0000",
|
iconColor: state => state.door_status == "on" ? "#00FF00" : "#FF0000",
|
||||||
ui: []
|
ui: []
|
||||||
},
|
},
|
||||||
infoscreen: {
|
infoscreen: {
|
||||||
name: "Infoscreen",
|
name: "Infoscreen",
|
||||||
position: [255, 455],
|
position: [255, 495],
|
||||||
icon: "developer_board",
|
icon: "developer_board",
|
||||||
iconColor: state => state.infoscreen == "on" ? "#4444FF" : "#000000",
|
iconColor: state => state.infoscreen == "on" ? "#4444FF" : "#000000",
|
||||||
ui: [
|
ui: [
|
||||||
{
|
{
|
||||||
type: "toggle",
|
type: "toggle",
|
||||||
text: "Infoscreen",
|
text: "Infoscreen",
|
||||||
topic: "infoscreen"
|
topic: "infoscreen",
|
||||||
|
icon: "power_settings_new"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,25 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
|
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
|
||||||
|
import createMuiTheme from 'material-ui/styles/createMuiTheme';
|
||||||
|
import withStyles from 'material-ui/styles/withStyles';
|
||||||
import Drawer from 'material-ui/Drawer';
|
import Drawer from 'material-ui/Drawer';
|
||||||
import injectTapEventPlugin from 'react-tap-event-plugin';
|
import injectTapEventPlugin from 'react-tap-event-plugin';
|
||||||
import { store } from "./state";
|
import { store, Actions } from "./state";
|
||||||
import connectMqtt from "./mqtt";
|
import connectMqtt from "./mqtt";
|
||||||
import AppBar from "./appbar";
|
import SpaceMapBar from "./appbar";
|
||||||
import Toggle from "material-ui/Toggle";
|
import Switch from "material-ui/Switch";
|
||||||
import * as UiItems from "./UiItems.js";
|
import * as UiItems from "./UiItems.js";
|
||||||
import SpaceMap from "./map.js";
|
import SpaceMap from "./map.js";
|
||||||
import R from "ramda";
|
import R from "ramda";
|
||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
import { Toolbar, ToolbarGroup, ToolbarTitle } from "material-ui/Toolbar";
|
import Toolbar from "material-ui/Toolbar";
|
||||||
|
import orange from 'material-ui/colors/orange';
|
||||||
|
import Typography from 'material-ui/Typography';
|
||||||
|
import List, { ListSubheader } from 'material-ui/List';
|
||||||
|
import IconButton from 'material-ui/IconButton';
|
||||||
|
import Icon from 'material-ui/Icon';
|
||||||
|
import AppBar from 'material-ui/AppBar';
|
||||||
|
|
||||||
injectTapEventPlugin();
|
injectTapEventPlugin();
|
||||||
|
|
||||||
|
|
@ -23,36 +31,60 @@ const renderUi = (state: State, key: ?string) =>
|
||||||
key != null && Config.controls[key] != null ?
|
key != null && Config.controls[key] != null ?
|
||||||
R.map(UiItem(state), Config.controls[key].ui) : null;
|
R.map(UiItem(state), Config.controls[key].ui) : null;
|
||||||
|
|
||||||
const App = (state: State) => {
|
const theme = createMuiTheme({
|
||||||
|
palette: {
|
||||||
|
primary: orange
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const appStyles = withStyles((theme) => ({
|
||||||
|
drawerPaper: {
|
||||||
|
width: 320
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
class app extends React.Component<{state: State, classes: Object}> {
|
||||||
|
render() {
|
||||||
|
const state = this.props.state;
|
||||||
|
const classes = this.props.classes;
|
||||||
if (state == null) return (<div></div>);
|
if (state == null) return (<div></div>);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<MuiThemeProvider>
|
<MuiThemeProvider theme={theme}>
|
||||||
<div>
|
<div>
|
||||||
<AppBar title="RZL Map" {...state} />
|
<SpaceMapBar title="RZL Map" {...state} />
|
||||||
<Drawer open={state.uiOpened != null}
|
<Drawer open={state.uiOpened != null}
|
||||||
openSecondary={true} disableSwipeToOpen={true}>
|
anchor="right"
|
||||||
|
onRequestClose={() => store.dispatch({type: Actions.CHANGE_UI})}
|
||||||
|
classes={{paper: classes.drawerPaper}}
|
||||||
|
type="persistent"
|
||||||
|
>
|
||||||
|
<AppBar position="static">
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarGroup firstChild={true}>
|
<IconButton onClick={() => store.dispatch({type: Actions.CHANGE_UI})}>
|
||||||
<ToolbarTitle text={
|
<Icon>keyboard_tab</Icon>
|
||||||
state.uiOpened == null ? "" : Config.controls[state.uiOpened].name}
|
</IconButton>
|
||||||
style={{"marginLeft": 10}} />
|
<Typography type="title">
|
||||||
</ToolbarGroup>
|
{state.uiOpened == null ? "" : Config.controls[state.uiOpened].name}
|
||||||
|
</Typography>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
<div id="drawer_uiComponents">
|
</AppBar>
|
||||||
|
<List id="drawer_uiComponents">
|
||||||
{renderUi(state, state.uiOpened)}
|
{renderUi(state, state.uiOpened)}
|
||||||
</div>
|
</List>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
</MuiThemeProvider>
|
</MuiThemeProvider>
|
||||||
<SpaceMap width={950} height={640} image="rzl.png" zoom={0.1} state={state} />
|
<SpaceMap width={1000} height={700} image="rzl.png" zoom={0.1} state={state} />
|
||||||
</div>
|
</div>
|
||||||
);}
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const App = appStyles(app);
|
||||||
|
|
||||||
store.subscribe(() => ReactDOM.render(<App {...store.getState()} />, document.getElementById("content")));
|
store.subscribe(() => ReactDOM.render(<App state={store.getState()} />, document.getElementById("content")));
|
||||||
|
|
||||||
store.dispatch({type:null});
|
store.dispatch({type:null});
|
||||||
|
|
||||||
// 192.168.178.6
|
connectMqtt("ws://172.22.36.207:1884", store);
|
||||||
connectMqtt("ws://172.22.36.207:1884", store); // wss://mqtt.starletp9.de/mqtt", store);
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import { Actions } from "./state";
|
||||||
import { keyOf } from "./util";
|
import { keyOf } from "./util";
|
||||||
import { store } from "./state";
|
import { store } from "./state";
|
||||||
|
|
||||||
import ActionInfo from 'material-ui/svg-icons/action/info';
|
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
|
|
||||||
// convert width/height coordinates to -height/width coordinates
|
// convert width/height coordinates to -height/width coordinates
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,8 @@ const handleEvent = (state: State = initState, action: StateAction) => {
|
||||||
return match(action.type, {
|
return match(action.type, {
|
||||||
[Actions.MQTT_CONNECT ]: R.merge(state, { mqtt: action.payload }),
|
[Actions.MQTT_CONNECT ]: R.merge(state, { mqtt: action.payload }),
|
||||||
[Actions.MQTT_MESSAGE ]: onMessage(state, action),
|
[Actions.MQTT_MESSAGE ]: onMessage(state, action),
|
||||||
[Actions.CHANGE_UI ]: R.merge(state, { uiOpened: action.payload })
|
[Actions.CHANGE_UI ]: R.merge(state, { uiOpened: action.payload }),
|
||||||
|
[null]: state
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,10 @@ declare type Topic = {
|
||||||
declare type Topics = Map<string,Topic>;
|
declare type Topics = Map<string,Topic>;
|
||||||
|
|
||||||
declare type ControlUI = {
|
declare type ControlUI = {
|
||||||
type: "toggle" | "dropDown" | "slider",
|
type: "toggle" | "dropDown" | "slider" | "section",
|
||||||
text: string,
|
text: string,
|
||||||
topic: string,
|
topic?: string,
|
||||||
|
icon?: string,
|
||||||
|
|
||||||
enableCondition?: (internal: string, actual: any) => boolean,
|
enableCondition?: (internal: string, actual: any) => boolean,
|
||||||
|
|
||||||
|
|
@ -23,6 +24,7 @@ declare type ControlUI = {
|
||||||
|
|
||||||
// DROPDOWN optional properties
|
// DROPDOWN optional properties
|
||||||
options?: Map<string,any>, //options for dropDown
|
options?: Map<string,any>, //options for dropDown
|
||||||
|
renderValue?: (value: string) => string
|
||||||
|
|
||||||
// SLIDER optional properties
|
// SLIDER optional properties
|
||||||
min?: number,
|
min?: number,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue