From 01daa2800085df9799de4890a3574ef405b1ec89 Mon Sep 17 00:00:00 2001 From: Stian Aune Date: Sun, 24 Feb 2019 00:27:36 +0100 Subject: [PATCH] Hmm... --- webui/package-lock.json | 239 ++++++++++++++++++ webui/package.json | 9 +- webui/src/App.css | 9 + webui/src/App.js | 15 +- .../src/Components/{ => Forms}/LoginForm.jsx | 4 +- webui/src/Components/Group.jsx | 11 +- webui/src/Components/Groups.jsx | 10 +- webui/src/Components/Light.jsx | 40 +++ webui/src/Components/Loading.jsx | 12 + webui/src/Components/Misc/ColorPicker.jsx | 31 +++ webui/src/Components/Modals/ColorModal.jsx | 23 ++ webui/src/Components/Pages/GroupPage.jsx | 10 + .../src/Components/{ => Pages}/IndexPage.jsx | 2 +- .../src/Components/{ => Structure}/Header.jsx | 4 +- webui/src/Helpers/lights.js | 26 +- webui/src/Helpers/percentage.js | 3 + webui/src/Hooks/light.js | 6 +- 17 files changed, 427 insertions(+), 27 deletions(-) rename webui/src/Components/{ => Forms}/LoginForm.jsx (98%) create mode 100644 webui/src/Components/Light.jsx create mode 100644 webui/src/Components/Loading.jsx create mode 100644 webui/src/Components/Misc/ColorPicker.jsx create mode 100644 webui/src/Components/Modals/ColorModal.jsx create mode 100644 webui/src/Components/Pages/GroupPage.jsx rename webui/src/Components/{ => Pages}/IndexPage.jsx (77%) rename webui/src/Components/{ => Structure}/Header.jsx (93%) create mode 100644 webui/src/Helpers/percentage.js diff --git a/webui/package-lock.json b/webui/package-lock.json index f38f0f9..ed19833 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -844,6 +844,16 @@ "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==" }, + "@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==" + }, + "@jaames/iro": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@jaames/iro/-/iro-4.0.1.tgz", + "integrity": "sha512-Q4DcB7poRpH3Gok74isb5PD/FTBlxPbZ5RMovM7bUIJ7q8kDyJow1qUJ4qIywmWnUNZyXCa6dpvNXnQ24WP5TQ==" + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -1149,6 +1159,14 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==" }, + "add-dom-event-listener": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz", + "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==", + "requires": { + "object-assign": "4.x" + } + }, "address": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", @@ -2981,11 +2999,24 @@ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, + "component-classes": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz", + "integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=", + "requires": { + "component-indexof": "0.0.3" + } + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, + "component-indexof": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz", + "integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ=" + }, "compressible": { "version": "2.0.15", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz", @@ -3168,6 +3199,16 @@ "sha.js": "^2.4.8" } }, + "create-react-class": { + "version": "15.6.3", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz", + "integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==", + "requires": { + "fbjs": "^0.8.9", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -3198,6 +3239,15 @@ "randomfill": "^1.0.3" } }, + "css-animation": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.5.0.tgz", + "integrity": "sha512-hWYoWiOZ7Vr20etzLh3kpWgtC454tW5vn4I6rLANDgpzNSkO7UfOqyCEeaoBSG9CYWQpRkFWTWbWW8o3uZrNLw==", + "requires": { + "babel-runtime": "6.x", + "component-classes": "^1.2.5" + } + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -3816,6 +3866,11 @@ "esutils": "^2.0.2" } }, + "dom-align": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.8.0.tgz", + "integrity": "sha512-B85D4ef2Gj5lw0rK0KM2+D5/pH7yqNxg2mB+E8uzFaolpm7RQmsxEfjyEuNiF8UBBkffumYDeKRzTzc3LePP+w==" + }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -3965,6 +4020,14 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -4970,6 +5033,35 @@ "bser": "^2.0.0" } }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -7340,6 +7432,15 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -8305,6 +8406,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -8320,6 +8426,16 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, "lodash.isfunction": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", @@ -8330,6 +8446,16 @@ "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=" }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -8448,6 +8574,11 @@ "object-visit": "^1.0.0" } }, + "material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + }, "math-random": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", @@ -8786,6 +8917,15 @@ "lower-case": "^1.1.1" } }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", @@ -11406,6 +11546,66 @@ } } }, + "rc-align": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.5.tgz", + "integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==", + "requires": { + "babel-runtime": "^6.26.0", + "dom-align": "^1.7.0", + "prop-types": "^15.5.8", + "rc-util": "^4.0.4" + } + }, + "rc-animate": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.6.0.tgz", + "integrity": "sha512-JXDycchgbOI+7T/VKmFWnAIn042LLScK1fNkmNunb0jz5q5aPGCAybx2bTo7X5t31Jkj9OsxKNb/vZPDPWufCg==", + "requires": { + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "css-animation": "^1.3.2", + "prop-types": "15.x", + "raf": "^3.4.0", + "react-lifecycles-compat": "^3.0.4" + } + }, + "rc-color-picker": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rc-color-picker/-/rc-color-picker-1.2.6.tgz", + "integrity": "sha512-AaC9Pg7qCHSy5M4eVbqDIaNb2FC4SEw82GOHB2C4R/+vF2FVa/r5XA+Igg5+zLPmAvBLhz9tL4MAfkRA8yWNJw==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.5.8", + "rc-trigger": "1.x", + "rc-util": "^4.0.2", + "tinycolor2": "^1.4.1" + } + }, + "rc-trigger": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-1.11.5.tgz", + "integrity": "sha512-MBuUPw1nFzA4K7jQOwb7uvFaZFjXGd00EofUYiZ+l/fgKVq8wnLC0lkv36kwqM7vfKyftRo2sh7cWVpdPuNnnw==", + "requires": { + "babel-runtime": "6.x", + "create-react-class": "15.x", + "prop-types": "15.x", + "rc-align": "2.x", + "rc-animate": "2.x", + "rc-util": "4.x" + } + }, + "rc-util": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.6.0.tgz", + "integrity": "sha512-rbgrzm1/i8mgfwOI4t1CwWK7wGe+OwX+dNa7PVMgxZYPBADGh86eD4OcJO1UKGeajIMDUUKMluaZxvgraQIOmw==", + "requires": { + "add-dom-event-listener": "^1.1.0", + "babel-runtime": "6.x", + "prop-types": "^15.5.10", + "shallowequal": "^0.2.2" + } + }, "react": { "version": "16.8.1", "resolved": "https://registry.npmjs.org/react/-/react-16.8.1.tgz", @@ -11447,6 +11647,19 @@ } } }, + "react-color": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.17.0.tgz", + "integrity": "sha512-kJfE5tSaFe6GzalXOHksVjqwCPAsTl+nzS9/BWfP7j3EXbQ4IiLAF9sZGNzk3uq7HfofGYgjmcUgh0JP7xAQ0w==", + "requires": { + "@icons/material": "^0.2.4", + "lodash": ">4.17.4", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + } + }, "react-dev-utils": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-7.0.1.tgz", @@ -11719,6 +11932,14 @@ "react-lifecycles-compat": "^3.0.4" } }, + "reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "requires": { + "lodash": "^4.0.1" + } + }, "reactn": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reactn/-/reactn-0.2.2.tgz", @@ -13016,6 +13237,14 @@ } } }, + "shallowequal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz", + "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=", + "requires": { + "lodash.keys": "^3.1.2" + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -13819,6 +14048,11 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tinycolor2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", + "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -13960,6 +14194,11 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "ua-parser-js": { + "version": "0.7.19", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", + "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" + }, "uglify-js": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", diff --git a/webui/package.json b/webui/package.json index 50c3ccf..9b94c6e 100644 --- a/webui/package.json +++ b/webui/package.json @@ -3,14 +3,17 @@ "version": "0.1.0", "private": true, "dependencies": { + "@jaames/iro": "^4.0.1", "bootstrap": "^4.2.1", + "rc-color-picker": "^1.2.6", "react": "^16.8.1", + "react-color": "^2.17.0", "react-dom": "^16.8.1", + "react-router": "^4.3.1", + "react-router-dom": "^4.3.1", "react-scripts": "2.1.3", - "reactstrap": "^7.1.0", "reactn": "^0.2.2", - "react-router-dom": "^4.3.1", - "react-router": "^4.3.1" + "reactstrap": "^7.1.0" }, "devDependencies": { "@types/react": "^16.8.1", diff --git a/webui/src/App.css b/webui/src/App.css index c8143c2..ae77d2f 100755 --- a/webui/src/App.css +++ b/webui/src/App.css @@ -5,3 +5,12 @@ a, button { cursor: pointer; } + +.badge { + cursor: pointer; +} + +.loading { + margin: 2em 0; + text-align: center; +} \ No newline at end of file diff --git a/webui/src/App.js b/webui/src/App.js index 0734bff..b589145 100755 --- a/webui/src/App.js +++ b/webui/src/App.js @@ -1,13 +1,15 @@ import React, {useEffect, useState} from 'react'; import './App.css'; -import Header from "./Components/Header"; -import LoginForm from "./Components/LoginForm"; -import {Container, Spinner} from "reactstrap"; +import Header from "./Components/Structure/Header"; +import LoginForm from "./Components/Forms/LoginForm"; +import {Container} from "reactstrap"; import {BrowserRouter} from "react-router-dom"; import {Route} from "react-router"; import {setGlobal} from "reactn"; import useAuth from "./Hooks/auth"; -import IndexPage from "./Components/IndexPage"; +import IndexPage from "./Components/Pages/IndexPage"; +import GroupPage from "./Components/Pages/GroupPage"; +import Loading from "./Components/Loading"; setGlobal({ "auth/login": false, @@ -30,11 +32,12 @@ export default function App() { <>
- {!isChecked && } + {!isChecked && } {isChecked && !isLoggedIn && } {isChecked && isLoggedIn && ( <> - + + )} diff --git a/webui/src/Components/LoginForm.jsx b/webui/src/Components/Forms/LoginForm.jsx similarity index 98% rename from webui/src/Components/LoginForm.jsx rename to webui/src/Components/Forms/LoginForm.jsx index c6a27a5..75ad6ec 100644 --- a/webui/src/Components/LoginForm.jsx +++ b/webui/src/Components/Forms/LoginForm.jsx @@ -16,8 +16,8 @@ import { TabPane } from "reactstrap"; import TabContent from "reactstrap/es/TabContent"; -import useAuth from "../Hooks/auth"; -import {onEnter} from "../Helpers/keys"; +import useAuth from "../../Hooks/auth"; +import {onEnter} from "../../Helpers/keys"; export default function LoginForm() { const {login, register} = useAuth(); diff --git a/webui/src/Components/Group.jsx b/webui/src/Components/Group.jsx index 4b42052..29fbc53 100644 --- a/webui/src/Components/Group.jsx +++ b/webui/src/Components/Group.jsx @@ -1,13 +1,20 @@ import React from "react"; -import {Button, Card, CardFooter, CardHeader} from "reactstrap"; +import {Button, Card, CardBody, CardFooter, CardHeader, ListGroup} from "reactstrap"; import useLights from "../Hooks/light"; +import Light from "./Light"; +import Loading from "./Loading"; -function Group({id, name, permissions}) { +function Group({id, name}) { const lights = useLights({groupId: id}); return ( {name} + + {lights !== null + ? {lights.map(light => )} + : } + {" "} diff --git a/webui/src/Components/Groups.jsx b/webui/src/Components/Groups.jsx index 54681f0..7e8c180 100644 --- a/webui/src/Components/Groups.jsx +++ b/webui/src/Components/Groups.jsx @@ -1,22 +1,18 @@ import React from "react"; -import {Spinner} from "reactstrap"; import useGroups from "../Hooks/group"; import Group from "./Group"; +import Loading from "./Loading"; function Groups() { const groups = useGroups(); if (groups === null) { - return ( -
- -
- ); + return ; } return (
- {groups.map(group => )} + {groups.map(group => )}
); } diff --git a/webui/src/Components/Light.jsx b/webui/src/Components/Light.jsx new file mode 100644 index 0000000..4a62603 --- /dev/null +++ b/webui/src/Components/Light.jsx @@ -0,0 +1,40 @@ +import React, {useState} from "react"; +import {Badge, Col, ListGroupItem, Row} from "reactstrap"; +import {percentage} from "../Helpers/percentage"; +import ColorModal from "./Modals/ColorModal"; +import {changeColor} from "../Helpers/lights"; + +function Light({id, name, color, brightness}) { + const pc = percentage(brightness, 255); + + const [modal, setModal] = useState(false); + + return ( + + + + {name} + + + setModal(true)}> + {color.toUpperCase()} + + + + {pc} + + + {modal && ( + { + changeColor(id, newColor); + setModal(false); + }} + onCancel={() => setModal(false)} + /> + )} + + ); +} + +export default Light; diff --git a/webui/src/Components/Loading.jsx b/webui/src/Components/Loading.jsx new file mode 100644 index 0000000..199713b --- /dev/null +++ b/webui/src/Components/Loading.jsx @@ -0,0 +1,12 @@ +import React from "react"; +import {Spinner} from "reactstrap"; + +function Loading() { + return ( +
+ +
+ ); +} + +export default Loading; diff --git a/webui/src/Components/Misc/ColorPicker.jsx b/webui/src/Components/Misc/ColorPicker.jsx new file mode 100644 index 0000000..46a2021 --- /dev/null +++ b/webui/src/Components/Misc/ColorPicker.jsx @@ -0,0 +1,31 @@ +import React, {useLayoutEffect} from "react"; +import iro from '@jaames/iro'; +import {randId} from "../../Helpers/random"; + +function ColorPicker({color, onChange}) { + const random = randId(); + + useLayoutEffect(() => { + const colorPicker = new iro.ColorPicker("#color-picker-" + random, { + color: `#${color}`, + layout: [ + { + component: iro.ui.Wheel, + options: {} + } + ], + }); + + colorPicker.on("input:end", color => { + onChange(color.hexString.substr(1)); + }) + }, []); + + return ( +
+ +
+ ); +} + +export default ColorPicker; diff --git a/webui/src/Components/Modals/ColorModal.jsx b/webui/src/Components/Modals/ColorModal.jsx new file mode 100644 index 0000000..b016144 --- /dev/null +++ b/webui/src/Components/Modals/ColorModal.jsx @@ -0,0 +1,23 @@ +import React, {useState} from "react"; +import {Button, Modal, ModalBody, ModalFooter, ModalHeader} from "reactstrap"; +import ColorPicker from "../Misc/ColorPicker"; + +function ColorModal({value, onConfirm, onCancel}) { + const [color, setColor] = useState(value); + + return ( + + Fargevalg + + + + + + {" "} + + + + ); +} + +export default ColorModal; diff --git a/webui/src/Components/Pages/GroupPage.jsx b/webui/src/Components/Pages/GroupPage.jsx new file mode 100644 index 0000000..58b63d4 --- /dev/null +++ b/webui/src/Components/Pages/GroupPage.jsx @@ -0,0 +1,10 @@ +import React from "react"; +import Groups from "./IndexPage"; + +function GroupPage() { + return ( + + ); +} + +export default GroupPage; diff --git a/webui/src/Components/IndexPage.jsx b/webui/src/Components/Pages/IndexPage.jsx similarity index 77% rename from webui/src/Components/IndexPage.jsx rename to webui/src/Components/Pages/IndexPage.jsx index 801db8a..ada5b33 100644 --- a/webui/src/Components/IndexPage.jsx +++ b/webui/src/Components/Pages/IndexPage.jsx @@ -1,5 +1,5 @@ import React from "react"; -import Groups from "./Groups"; +import Groups from "../Groups"; function IndexPage() { return ( diff --git a/webui/src/Components/Header.jsx b/webui/src/Components/Structure/Header.jsx similarity index 93% rename from webui/src/Components/Header.jsx rename to webui/src/Components/Structure/Header.jsx index 322157b..1675a20 100644 --- a/webui/src/Components/Header.jsx +++ b/webui/src/Components/Structure/Header.jsx @@ -1,8 +1,8 @@ import React, {useState} from "react" import {Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink} from "reactstrap"; -import useAuth from "../Hooks/auth"; +import useAuth from "../../Hooks/auth"; import {Link} from "react-router-dom"; -import {onEnter} from "../Helpers/keys"; +import {onEnter} from "../../Helpers/keys"; export default function Header() { const [showMenu, setShowMenu] = useState(false); diff --git a/webui/src/Helpers/lights.js b/webui/src/Helpers/lights.js index 567b953..62da455 100644 --- a/webui/src/Helpers/lights.js +++ b/webui/src/Helpers/lights.js @@ -29,6 +29,30 @@ export function subscribeToLight(lightId, callback) { } } +export function unsubscribeFromLight(callbackId) { + const callback = callbacks.find(c => c !== null && c.callbackId === callbackId); + const index = callbacks.indexOf(callback); + callbacks[index] = null; +} + +export function changeColor(lightId, newColor) { + console.dir(localData); + + const light = localData[lightId]; + if (nullish(light)) { + return; + } + + localData[lightId].color = newColor; + dispatch(Object.values(localData)); + + // TODO: Send request +} + +export function changeBrightness(lightId, newBrightness) { + +} + function fetchAll() { fetchGet(`/light/`).then(({data, error}) => { if (error === null) { @@ -49,7 +73,7 @@ function handleLights(lights) { lights.forEach(l => handleLight(l)); for (let key in localData) { - if (localData.hasOwnProperty(key) && nullish(lights.find(l => l.id === key))) { + if (localData.hasOwnProperty(key) && nullish(lights.find(l => l.id === parseInt(key, 10)))) { delete localData[key]; } } diff --git a/webui/src/Helpers/percentage.js b/webui/src/Helpers/percentage.js new file mode 100644 index 0000000..b9a3d56 --- /dev/null +++ b/webui/src/Helpers/percentage.js @@ -0,0 +1,3 @@ +export function percentage(value, max) { + return (100 * value / max).toFixed(1) + " %"; +} \ No newline at end of file diff --git a/webui/src/Hooks/light.js b/webui/src/Hooks/light.js index 5da6cae..5ff5106 100644 --- a/webui/src/Hooks/light.js +++ b/webui/src/Hooks/light.js @@ -1,10 +1,10 @@ import {useEffect, useState} from "react"; -import {subscribeToLight} from "../Helpers/lights"; +import {subscribeToLight, unsubscribeFromLight} from "../Helpers/lights"; export default function useLights({groupId = -1, id = -1}) { const [light, setLight] = useState(null); - function onChange() { + function onChange(light) { setLight(light); } @@ -12,7 +12,7 @@ export default function useLights({groupId = -1, id = -1}) { const cbId = subscribeToLight(id, onChange); return () => { - subscribeToLight(cbId); + unsubscribeFromLight(cbId); }; }, []);