Browse Source

Accessibility improvements

jamesread 5 years ago
parent
commit
8584ea5a08
7 changed files with 124 additions and 115 deletions
  1. 1 0
      .gitignore
  2. 7 5
      webui/index.html
  3. 7 7
      webui/js/ActionButton.js
  4. 1 1
      webui/js/marshaller.js
  5. 13 18
      webui/main.js
  6. 2 4
      webui/package.json
  7. 93 80
      webui/style.css

+ 1 - 0
.gitignore

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

+ 7 - 5
webui/index.html

@@ -11,15 +11,17 @@
 	</head>
 
 	<body>
-		<main>
-			<div class = "group" id = "rootGroup" />
+		<main title = "main content">
+			<fieldset id = "rootGroup">
+				<legend>OliveTin Actions</legend>
+			</fieldset>
 		</main>
-		<footer>
-			<p><img src = "OliveTinLogo.png" height = "1em" class = "logo" /> <a href = "http://github.com/jamesread/OliveTin" target = "_new">OliveTin</a></p>
+		<footer title = "footer">
+			<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>
 
 		<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>
 		</template>
 

+ 7 - 7
webui/js/ActionButton.js

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

+ 1 - 1
webui/js/marshaller.js

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

+ 13 - 18
webui/main.js

@@ -2,34 +2,29 @@
 
 import { marshalActionButtonsJsonToHtml } from './js/marshaller.js'
 
-/**
- * Design choice; define this as a "global function" (on window) so that it can 
- * 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)
+function showBigError (type, friendlyType, message) {
+  console.error('Error ' + type + ': ', message)
 
-	var err = document.createElement("div")
-	err.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>";
+  const domErr = document.createElement('div')
+  domErr.classList.add('error')
+  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) {
-  window.restBaseUrl = res.Rest;
+function onInitialLoad (res) {
+  window.restBaseUrl = res.Rest
 
-  window.fetch(window.restBaseUrl + "GetButtons", {
-    cors: 'cors',
+  window.fetch(window.restBaseUrl + 'GetButtons', {
+    cors: 'cors'
     // No fetch options
   }).then(res => {
     return res.json()
   }).then(res => {
     marshalActionButtonsJsonToHtml(res)
   }).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 => {
@@ -37,5 +32,5 @@ window.fetch('webUiSettings.json').then(res => {
 }).then(res => {
   onInitialLoad(res)
 }).catch(err => {
-  showBigError("fetch-webui-settings", "getting webui settings", err);
+  showBigError('fetch-webui-settings', 'getting webui settings', err)
 })

+ 2 - 4
webui/package.json

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

+ 93 - 80
webui/style.css

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