From f3d8e5c31e00bc63133ad49c1802db519cfb69c3 Mon Sep 17 00:00:00 2001 From: jamesread Date: Fri, 7 May 2021 18:07:09 +0100 Subject: [PATCH] webui, gitignore --- .gitignore | 6 +++ web/.eslintrc.json | 15 ++++++ web/.stylelintrc.json | 3 ++ web/OliveTinLogo.png | Bin 0 -> 13877 bytes web/OliveTinLogo.svg | 106 ++++++++++++++++++++++++++++++++++++++++++ web/index.htm | 28 +++++++++++ web/js/classes.js | 92 ++++++++++++++++++++++++++++++++++++ web/js/loader.js | 10 ++++ web/main.js | 9 ++++ web/package.json | 22 +++++++++ web/style.css | 91 ++++++++++++++++++++++++++++++++++++ 11 files changed, 382 insertions(+) create mode 100644 .gitignore create mode 100644 web/.eslintrc.json create mode 100644 web/.stylelintrc.json create mode 100644 web/OliveTinLogo.png create mode 100644 web/OliveTinLogo.svg create mode 100644 web/index.htm create mode 100644 web/js/classes.js create mode 100644 web/js/loader.js create mode 100644 web/main.js create mode 100644 web/package.json create mode 100644 web/style.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92b8a41 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +web/package-lock.json +web/node_modules +**/*.swp +**/*.swo +gen/ +go.sum diff --git a/web/.eslintrc.json b/web/.eslintrc.json new file mode 100644 index 0000000..67b9be6 --- /dev/null +++ b/web/.eslintrc.json @@ -0,0 +1,15 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "standard" + ], + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "rules": { + } +} diff --git a/web/.stylelintrc.json b/web/.stylelintrc.json new file mode 100644 index 0000000..a446433 --- /dev/null +++ b/web/.stylelintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "stylelint-config-standard" +} diff --git a/web/OliveTinLogo.png b/web/OliveTinLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..64efd1ecd58f383dba0fa45d4486ee98c7b10a80 GIT binary patch literal 13877 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 + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/web/index.htm b/web/index.htm new file mode 100644 index 0000000..eefa134 --- /dev/null +++ b/web/index.htm @@ -0,0 +1,28 @@ + + + + + + + + OliveTin + + + + + +
+
+
+ + + + + + + diff --git a/web/js/classes.js b/web/js/classes.js new file mode 100644 index 0000000..5a1a2ae --- /dev/null +++ b/web/js/classes.js @@ -0,0 +1,92 @@ +class ActionButton extends window.HTMLButtonElement { + constructFromJson (json) { + this.title = json.title + this.states = [] + this.stateLabels = [] + this.currentState = 0 + this.isWaiting = false + this.actionCallUrl = 'http://mindstorm4:1339/StartAction?actionName=' + this.title + + if (json.icon !== undefined) { + this.unicodeIcon = unescape(json.icon) + } else { + this.unicodeIcon = '💩' + } + + this.onclick = () => { this.startAction() } + + this.constructTemplate() + this.updateHtml() + } + + startAction () { + this.disabled = true + this.isWaiting = true + this.updateHtml() + this.classList = [] // Removes old animation classes + + window.fetch(this.actionCallUrl).then(res => { + if (!res.ok) { + return res.json() + } + }).then(json => { + this.onActionResult() + }).catch(err => { + this.onActionError(err) + }) + } + + onActionResult (json) { + this.disabled = false + this.isWaiting = false + this.updateHtml() + this.classList.add('actionSuccess') + } + + onActionError (err) { + console.log('callback error', err) + this.disabled = false + this.isWaiting = false + this.updateHtml() + this.classList.add('actionFailed') + } + + constructTemplate () { + const tpl = document.getElementById('tplActionButton') + const content = tpl.content.cloneNode(true) + + /* + * FIXME: Should probably be using a shadowdom here, but seem to + * get an error when combined with custom elements. + */ + + this.appendChild(content) + + this.domTitle = this.querySelector('.title') + this.domIcon = this.querySelector('.icon') + } + + updateHtml () { + if (this.isWaiting) { + this.domTitle.innerText = 'Waiting...' + } else { + this.domTitle.innerText = this.title + } + + this.domIcon.innerHTML = this.unicodeIcon + } + + getCurrentStateLabel (useLabels = true) { + if (useLabels) { + return this.stateLabels[this.currentState] + } else { + return this.states[this.currentState] + } + } + + getNextStateLabel () { + return this.stateLabels[this.currentState + 1] + } +} + +window.customElements.define('action-button', ActionButton, { extends: 'button' }) diff --git a/web/js/loader.js b/web/js/loader.js new file mode 100644 index 0000000..bc5cf8d --- /dev/null +++ b/web/js/loader.js @@ -0,0 +1,10 @@ +import './classes.js' // To define action-button + +export function loadContents (json) { + for (const jsonButton of json.actions) { + const a = document.createElement('button', { is: 'action-button' }) + a.constructFromJson(jsonButton) + + document.getElementById('rootGroup').appendChild(a) + } +} diff --git a/web/main.js b/web/main.js new file mode 100644 index 0000000..b26b686 --- /dev/null +++ b/web/main.js @@ -0,0 +1,9 @@ +'use strict' + +import { loadContents } from './js/loader.js' + +window.fetch('http://mindstorm4:1339/GetButtons').then(res => { + return res.json() +}).then(res => { + loadContents(res) +}) diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..8398a0c --- /dev/null +++ b/web/package.json @@ -0,0 +1,22 @@ +{ + "name": "olivetin", + "version": "1.0.0", + "description": "", + "main": "main.js", + "dependencies": { + "stylelint": "^13.13.0", + "stylelint-config-standard": "^22.0.0" + }, + "devDependencies": { + "eslint": "^7.25.0", + "eslint-config-standard": "^16.0.2", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.3.1" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/web/style.css b/web/style.css new file mode 100644 index 0000000..1e78793 --- /dev/null +++ b/web/style.css @@ -0,0 +1,91 @@ +body { + background-color: #333; + color: white; + text-align: center; + font-family: sans-serif; + padding: 0; + margin: 0; +} + +.group { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + grid-template-rows: auto auto auto auto; + padding: 1em; + grid-gap: 1em; + text-align: center; +} + +div.entity { + background-color: #222; + box-shadow: 0 0 10px 0 #444; + display: grid; + grid-column: auto / span 2; + grid-row: auto / span 2; + grid-template-rows: auto min-content; + grid-template-columns: minmax(min-content, auto); +} + +div.entity h2 { + grid-column: 1 / span all; +} + +button { + padding: 1em; + color: white; + display: table-cell; + text-align: center; + border: 1px solid #666; + background-color: #222; + box-shadow: 0 0 10px 0 #444; + user-select: none; +} + +button.good { + background-color: limegreen; +} + +button:hover { + box-shadow: 0 0 10px 0 #666; + cursor: pointer; +} + +button:disabled { + color: gray; + background-color: black; + cursor: not-allowed; +} + +span.icon { + font-size: 3em; +} + +.actionFailed { + animation: kfActionFailed 1s; +} + +@keyframes kfActionFailed { + 0% { background-color: black; } + 20% { background-color: red; } + 0% { background-color: inherit; } +} + +.actionSuccess { + animation: kfActionSuccess 1s; +} + +@keyframes kfActionSuccess { + 0% { background-color: black; } + 20% { background-color: green; } + 0% { background-color: inherit; } +} + +footer, footer a { + color: gray; +} + +img.logo { + width: 1em; + height: 1em; + vertical-align: middle; +}