Accessibility improvements

This commit is contained in:
jamesread 2021-05-18 00:28:35 +01:00
parent 66c7bddb2e
commit 8584ea5a08
7 changed files with 122 additions and 113 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ webui/node_modules
gen/ gen/
go.sum go.sum
OliveTin OliveTin
reports

View File

@ -11,15 +11,17 @@
</head> </head>
<body> <body>
<main> <main title = "main content">
<div class = "group" id = "rootGroup" /> <fieldset id = "rootGroup">
<legend>OliveTin Actions</legend>
</fieldset>
</main> </main>
<footer> <footer title = "footer">
<p><img src = "OliveTinLogo.png" height = "1em" class = "logo" /> <a href = "http://github.com/jamesread/OliveTin" target = "_new">OliveTin</a></p> <p><img title = "application icon" src = "OliveTinLogo.png" height = "1em" class = "logo" /> <a href = "http://github.com/jamesread/OliveTin" target = "_new">OliveTin</a></p>
</footer> </footer>
<template id = "tplActionButton"> <template id = "tplActionButton">
<p><span class = "icon">&#x1f4a9;</span></p> <span role = "img" title = "button icon" class = "icon">&#x1f4a9;</span>
<p role = "title" class = "title">Untitled Button</p> <p role = "title" class = "title">Untitled Button</p>
</template> </template>

View File

@ -8,7 +8,7 @@ class ActionButton extends window.HTMLButtonElement {
this.isWaiting = false this.isWaiting = false
this.actionCallUrl = window.restBaseUrl + 'StartAction?actionName=' + this.title this.actionCallUrl = window.restBaseUrl + 'StartAction?actionName=' + this.title
if (json.icon == "") { if (json.icon === '') {
this.unicodeIcon = '&#x1f4a9' this.unicodeIcon = '&#x1f4a9'
} else { } else {
this.unicodeIcon = unescape(json.icon) this.unicodeIcon = unescape(json.icon)
@ -29,11 +29,11 @@ class ActionButton extends window.HTMLButtonElement {
window.fetch(this.actionCallUrl).then(res => res.json() window.fetch(this.actionCallUrl).then(res => res.json()
).then((json) => { ).then((json) => {
if (json.timedOut) { if (json.timedOut) {
this.onActionResult('actionTimeout', "Timed out") this.onActionResult('actionTimeout', 'Timed out')
} else if (json.exitCode != 0) { } else if (json.exitCode !== 0) {
this.onActionResult('actionNonZeroExit', "Exit code " + json.exitCode) this.onActionResult('actionNonZeroExit', 'Exit code ' + json.exitCode)
} else { } else {
this.onActionResult('actionSuccess', "Success!") this.onActionResult('actionSuccess', 'Success!')
} }
}).catch(err => { }).catch(err => {
this.onActionError(err) this.onActionError(err)

View File

@ -1,6 +1,6 @@
import './ActionButton.js' // To define action-button import './ActionButton.js' // To define action-button
export function marshalActionButtonsJsonToHtml(json) { export function marshalActionButtonsJsonToHtml (json) {
for (const jsonButton of json.actions) { for (const jsonButton of json.actions) {
const a = document.createElement('button', { is: 'action-button' }) const a = document.createElement('button', { is: 'action-button' })
a.constructFromJson(jsonButton) a.constructFromJson(jsonButton)

View File

@ -2,34 +2,29 @@
import { marshalActionButtonsJsonToHtml } from './js/marshaller.js' import { marshalActionButtonsJsonToHtml } from './js/marshaller.js'
/** function showBigError (type, friendlyType, message) {
* Design choice; define this as a "global function" (on window) so that it can console.error('Error ' + type + ': ', message)
* easily be used anywhere without needing to import it, as it's a pretty
* fundemental thing.
*/
window.showBigError = (type, friendlyType, message) => {
console.error("Error " + type + ": ", err)
var err = document.createElement("div") const domErr = document.createElement('div')
err.classList.add("error") domErr.classList.add('error')
err.innerHTML = "<h1>Error " + friendlyType + "</h1><p>" + message + "</p><p><a href = 'http://github.com/jamesread/OliveTin' target = 'blank'/>OliveTin Documentation</a></p>"; domErr.innerHTML = '<h1>Error ' + friendlyType + '</h1><p>' + message + "</p><p><a href = 'http://github.com/jamesread/OliveTin' target = 'blank'/>OliveTin Documentation</a></p>"
document.getElementById('rootGroup').appendChild(err) document.getElementById('rootGroup').appendChild(domErr)
} }
function onInitialLoad(res) { function onInitialLoad (res) {
window.restBaseUrl = res.Rest; window.restBaseUrl = res.Rest
window.fetch(window.restBaseUrl + "GetButtons", { window.fetch(window.restBaseUrl + 'GetButtons', {
cors: 'cors', cors: 'cors'
// No fetch options // No fetch options
}).then(res => { }).then(res => {
return res.json() return res.json()
}).then(res => { }).then(res => {
marshalActionButtonsJsonToHtml(res) marshalActionButtonsJsonToHtml(res)
}).catch(err => { }).catch(err => {
showBigError("fetch-initial-buttons", "getting initial buttons", err, "blat") showBigError('fetch-initial-buttons', 'getting initial buttons', err, 'blat')
}); })
} }
window.fetch('webUiSettings.json').then(res => { window.fetch('webUiSettings.json').then(res => {
@ -37,5 +32,5 @@ window.fetch('webUiSettings.json').then(res => {
}).then(res => { }).then(res => {
onInitialLoad(res) onInitialLoad(res)
}).catch(err => { }).catch(err => {
showBigError("fetch-webui-settings", "getting webui settings", err); showBigError('fetch-webui-settings', 'getting webui settings', err)
}) })

View File

@ -3,11 +3,9 @@
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "main.js", "main": "main.js",
"dependencies": {
"stylelint": "^13.13.0",
"stylelint-config-standard": "^22.0.0"
},
"devDependencies": { "devDependencies": {
"stylelint": "^13.13.0",
"stylelint-config-standard": "^22.0.0",
"eslint": "^7.25.0", "eslint": "^7.25.0",
"eslint-config-standard": "^16.0.2", "eslint-config-standard": "^16.0.2",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.22.1",

View File

@ -1,143 +1,156 @@
body { body {
background-color: #dee3e7; background-color: #dee3e7;
color: black; color: black;
text-align: center; text-align: center;
font-family: sans-serif; font-family: sans-serif;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.group { fieldset {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
grid-template-rows: auto auto auto auto; grid-template-rows: auto auto auto auto;
padding: 1em; padding: 1em;
grid-gap: 1em; grid-gap: 1em;
text-align: center; text-align: center;
border: 0;
}
legend {
padding-top: 1em;
}
span[role="icon"] {
display: block;
} }
.error { .error {
background-color: salmon; background-color: salmon;
padding: 1em; padding: 1em;
} }
.title.temporaryStatusMessage { .title.temporaryStatusMessage {
color: gray; color: gray;
} }
div.entity { div.entity {
background-color: white; background-color: white;
box-shadow: 0 0 10px 0 #444; box-shadow: 0 0 10px 0 #444;
display: grid; display: grid;
grid-column: auto / span 2; grid-column: auto / span 2;
grid-row: auto / span 2; grid-row: auto / span 2;
grid-template-rows: auto min-content; grid-template-rows: auto min-content;
grid-template-columns: minmax(min-content, auto); grid-template-columns: minmax(min-content, auto);
} }
div.entity h2 { div.entity h2 {
grid-column: 1 / span all; grid-column: 1 / span all;
} }
button { button {
padding: 1em; padding: 1em;
color: black; color: black;
display: table-cell; display: table-cell;
text-align: center; text-align: center;
border: 1px solid #999; border: 1px solid #999;
background-color: white; background-color: white;
box-shadow: 0 0 6px 0 #aaa; box-shadow: 0 0 6px 0 #aaa;
user-select: none; user-select: none;
} }
button:hover { button:hover {
box-shadow: 0 0 10px 0 #666; box-shadow: 0 0 10px 0 #666;
cursor: pointer; cursor: pointer;
}
button:focus {
outline: 1px solid black;
} }
button:disabled { button:disabled {
color: gray; color: gray;
background-color: #333; background-color: #333;
cursor: not-allowed; cursor: not-allowed;
} }
span.icon { span.icon {
font-size: 3em; font-size: 3em;
} }
.actionFailed { .actionFailed {
animation: kfActionFailed 1s; animation: kfActionFailed 1s;
} }
@keyframes kfActionFailed { @keyframes kfActionFailed {
0% { background-color: black; } 0% { background-color: black; }
20% { background-color: red; } 20% { background-color: red; }
0% { background-color: inherit; } 0% { background-color: inherit; }
} }
.actionSuccess { .actionSuccess {
animation: kfActionSuccess 1s; animation: kfActionSuccess 1s;
} }
@keyframes kfActionSuccess { @keyframes kfActionSuccess {
0% { background-color: black; } 0% { background-color: black; }
20% { background-color: limegreen; } 20% { background-color: limegreen; }
0% { background-color: inherit; } 0% { background-color: inherit; }
} }
.actionNonZeroExit { .actionNonZeroExit {
animation: kfActionNonZeroExit 1s; animation: kfActionNonZeroExit 1s;
} }
@keyframes kfActionNonZeroExit { @keyframes kfActionNonZeroExit {
0% { background-color: black; } 0% { background-color: black; }
20% { background-color: orange; } 20% { background-color: orange; }
0% { background-color: inherit; } 0% { background-color: inherit; }
} }
.actionTimeout { .actionTimeout {
animation: kfActionTimeout 1s; animation: kfActionTimeout 1s;
} }
@keyframes kfActionTimeout { @keyframes kfActionTimeout {
0% { background-color: black; } 0% { background-color: black; }
20% { background-color: cyan; } 20% { background-color: cyan; }
0% { background-color: inherit; } 0% { background-color: inherit; }
} }
footer,
footer, footer a { footer a {
color: gray; color: black;
} }
img.logo { img.logo {
width: 1em; width: 1em;
height: 1em; height: 1em;
vertical-align: middle; vertical-align: middle;
} }
@media (max-width: 320px) { @media (max-width: 320px) {
.group { fieldset {
grid-template-columns: auto; grid-template-columns: auto;
grid-gap: 0; grid-gap: 0;
padding: 0; padding: 0;
} }
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
body { body {
background-color: #333; background-color: #333;
color: white; color: white;
} }
button { button {
border: 1px solid #666; border: 1px solid #666;
background-color: #222; background-color: #222;
box-shadow: 0 0 6px 0 #444; box-shadow: 0 0 6px 0 #444;
color: white; color: white;
} }
button:disabled { button:disabled {
background-color: black; background-color: black;
} }
} }