Merge branch 'theme-updates' into 'labthings-070'

Theme updates

See merge request openflexure/openflexure-microscope-server!68
This commit is contained in:
Joel Collins 2020-07-06 10:32:54 +00:00
commit 6d1d3016d1
12 changed files with 240 additions and 130 deletions

View file

@ -10,21 +10,11 @@ To prevent the editor from interfering with ESLint, add to your project `setting
{ {
"editor.tabSize": 2, "editor.tabSize": 2,
"cSpell.enabled": false, "cSpell.enabled": false,
"eslint.validate": [{ "eslint.validate": ["vue","javascript", "javascriptreact"],
"language": "vue",
"autoFix": true
},
{
"language": "javascript",
"autoFix": true
},
{
"language": "javascriptreact",
"autoFix": true
}
],
"eslint.autoFixOnSave": true,
"editor.formatOnSave": false, "editor.formatOnSave": false,
"vetur.validation.template": false "vetur.validation.template": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
} }
``` ```

View file

@ -9210,6 +9210,11 @@
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
}, },
"mousetrap": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.5.tgz",
"integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",

View file

@ -13,7 +13,8 @@
"serve": "vue-cli-service serve --mode development" "serve": "vue-cli-service serve --mode development"
}, },
"dependencies": { "dependencies": {
"material-design-icons": "^3.0.1" "material-design-icons": "^3.0.1",
"mousetrap": "^1.6.5"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^3.12.1", "@vue/cli-plugin-babel": "^3.12.1",

View file

@ -7,6 +7,26 @@
<loadingContent v-if="!$store.getters.ready" /> <loadingContent v-if="!$store.getters.ready" />
<div v-if="$store.getters.ready" id="tour-header"></div> <div v-if="$store.getters.ready" id="tour-header"></div>
<appContent v-if="$store.getters.ready" /> <appContent v-if="$store.getters.ready" />
<!-- Runtime modals -->
<div
id="modal-center"
ref="keyboardManualModal"
class="uk-flex-top"
uk-modal
>
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical">
<button class="uk-modal-close-default" type="button" uk-close></button>
<div
v-for="shortcut in keyboardManual"
:key="shortcut.shortcut"
class="uk-margin-small"
uk-grid
>
<div class="uk-width-small">{{ shortcut.shortcut }}</div>
<div class="uk-width-expand">{{ shortcut.description }}</div>
</div>
</div>
</div>
<v-tour <v-tour
v-show="$store.getters.ready" v-show="$store.getters.ready"
name="guidedTour" name="guidedTour"
@ -23,20 +43,26 @@ import appContent from "./components/appContent.vue";
import loadingContent from "./components/loadingContent.vue"; import loadingContent from "./components/loadingContent.vue";
import axios from "axios"; import axios from "axios";
var Mousetrap = require("mousetrap");
// Key Codes Mousetrap.prototype.stopCallback = function(e, element, combo) {
const keyCodes = { // if the element has the class "mousetrap" then no need to stop
pgup: 33, if ((" " + element.className + " ").indexOf(" mousetrap ") > -1) {
pgdn: 34, return false;
left: 37, }
up: 38,
right: 39, // if we're in a lightbox, stop mousetrap
down: 40, if (element.classList.contains("lightbox-link")) {
enter: 13, return true;
esc: 27, }
shift: 16,
alt: 18, // stop for input, select, and textarea
t: 84 return (
element.tagName == "INPUT" ||
element.tagName == "SELECT" ||
element.tagName == "TEXTAREA" ||
(element.contentEditable && element.contentEditable == "true")
);
}; };
// Export main app // Export main app
@ -51,7 +77,8 @@ export default {
data: function() { data: function() {
return { return {
appAvailable: false, appAvailable: false,
keysDown: {}, arrowKeysDown: {},
keyboardManual: [],
systemDark: undefined, systemDark: undefined,
themeObserver: undefined, themeObserver: undefined,
tourCallbacks: { tourCallbacks: {
@ -166,9 +193,7 @@ export default {
created: function() { created: function() {
window.addEventListener("beforeunload", this.handleExit); window.addEventListener("beforeunload", this.handleExit);
// Key events // Scrollwheel listener
window.addEventListener("keydown", this.keyDownMonitor);
window.addEventListener("keyup", this.keyUpMonitor);
window.addEventListener("wheel", this.wheelMonitor); window.addEventListener("wheel", this.wheelMonitor);
// Watch for origin changes // Watch for origin changes
this.unwatchOriginFunction = this.$store.watch( this.unwatchOriginFunction = this.$store.watch(
@ -180,6 +205,82 @@ export default {
console.log(uriV2); console.log(uriV2);
} }
); );
// Keyboard shortcuts
// TODO: Shortcut guide
Mousetrap.bind("?", () => {
console.log(this.keyboardManual);
this.toggleModalElement(this.$refs["keyboardManualModal"]); // Calls the mixin
});
// Arrow keys
Mousetrap.bind(
["up", "down", "left", "right"],
event => {
this.arrowKeysDown[event.keyCode] = true; //Add key to array
this.navigateKeyHandler();
},
"keydown"
);
Mousetrap.bind(
["up", "down", "left", "right"],
event => {
delete this.arrowKeysDown[event.keyCode]; //Remove key from array
},
"keyup"
);
this.keyboardManual.push({
shortcut: "←↑→↓",
description: "Move the microscope stage"
});
// Focus keys
Mousetrap.bind("pageup", () => {
this.$root.$emit("globalMoveStepEvent", 0, 0, 1);
});
Mousetrap.bind("pagedown", () => {
this.$root.$emit("globalMoveStepEvent", 0, 0, -1);
});
this.keyboardManual.push({
shortcut: "pgup / pgdn",
description: "Move the microscope focus"
});
// Capture
Mousetrap.bind("c", () => {
this.$root.$emit("globalCaptureEvent");
});
this.keyboardManual.push({
shortcut: "c",
description: "Take a capture"
});
// Autofocus
Mousetrap.bind("a", () => {
this.$root.$emit("globalFastAutofocusEvent");
});
this.keyboardManual.push({
shortcut: "a",
description: "Fast autofocus"
});
// Increment/decrement tab
Mousetrap.bind("shift+down", () => {
this.$root.$emit("globalIncrementTab");
});
Mousetrap.bind("shift+up", () => {
this.$root.$emit("globalDecrementTab");
});
this.keyboardManual.push({
shortcut: "shift+↑ / shift+↓",
description: "Switch tab"
});
// Re-run tour
Mousetrap.bind("alt+t", () => {
this.$tours["guidedTour"].start();
});
}, },
beforeDestroy: function() { beforeDestroy: function() {
@ -187,12 +288,13 @@ export default {
if (this.themeObserver) { if (this.themeObserver) {
this.themeObserver.disconnect(); this.themeObserver.disconnect();
} }
// Remove key listeners // Remove scrollwheel listener
window.removeEventListener("keydown", this.keyDownMonitor);
window.removeEventListener("keyup", this.keyUpMonitor);
window.removeEventListener("wheel", this.wheelMonitor); window.removeEventListener("wheel", this.wheelMonitor);
// Remove origin watcher // Remove origin watcher
this.unwatchOriginFunction(); this.unwatchOriginFunction();
// Remove key listeners
console.log("Resetting Mousetrap");
Mousetrap.reset();
}, },
methods: { methods: {
@ -231,84 +333,26 @@ export default {
} }
}, },
// Handle global key press events to be associated with navigation navigateKeyHandler: function() {
keyDownMonitor: function(event) { // Calculate movement array
this.keysDown[event.keyCode] = true; //Add key to array var x_rel = 0;
var y_rel = 0;
// Convert keyCode dict into a list of key codes var z_rel = 0;
var keyCodeList = Object.keys(keyCodes).map(function(key) { if (37 in this.arrowKeysDown) {
return keyCodes[key]; x_rel = x_rel + 1;
});
if (
// If not inside an element we want to ignore
!(event.target instanceof HTMLInputElement) &&
!event.target.classList.contains("lightbox-link") &&
// If it's a recognised key
keyCodeList.includes(event.keyCode)
) {
this.navigateKeyHandler(keyCodes);
this.captureKeyHandler(keyCodes);
this.letterKeyHandler(keyCodes);
} }
}, if (39 in this.arrowKeysDown) {
x_rel = x_rel - 1;
keyUpMonitor: function(event) {
delete this.keysDown[event.keyCode]; //Remove key from array
},
navigateKeyHandler: function(keyCodes) {
const moveKeys = [
keyCodes.left,
keyCodes.right,
keyCodes.up,
keyCodes.down,
keyCodes.pgup,
keyCodes.pgdn
];
if (
moveKeys.some(r => Object.keys(this.keysDown).includes(r.toString()))
) {
// Calculate movement array
var x_rel = 0;
var y_rel = 0;
var z_rel = 0;
if (keyCodes.left in this.keysDown) {
x_rel = x_rel + 1;
}
if (keyCodes.right in this.keysDown) {
x_rel = x_rel - 1;
}
if (keyCodes.up in this.keysDown) {
y_rel = y_rel + 1;
}
if (keyCodes.down in this.keysDown) {
y_rel = y_rel - 1;
}
if (keyCodes.pgup in this.keysDown) {
z_rel = z_rel - 1;
}
if (keyCodes.pgdn in this.keysDown) {
z_rel = z_rel + 1;
}
// Make a position request
// Emit a signal to move, acted on by panelNavigate.vue
this.$root.$emit("globalMoveStepEvent", x_rel, y_rel, z_rel);
} }
}, if (38 in this.arrowKeysDown) {
y_rel = y_rel + 1;
captureKeyHandler: function(keyCodes) {
if (keyCodes.shift in this.keysDown && keyCodes.enter in this.keysDown) {
console.log("Capturing");
this.$root.$emit("globalCaptureEvent");
} }
}, if (40 in this.arrowKeysDown) {
y_rel = y_rel - 1;
letterKeyHandler: function(keyCodes) {
if (keyCodes.alt in this.keysDown && keyCodes.t in this.keysDown) {
this.$tours["guidedTour"].start();
} }
// Make a position request
// Emit a signal to move, acted on by panelNavigate.vue
this.$root.$emit("globalMoveStepEvent", x_rel, y_rel, z_rel);
} }
} }
}; };

View file

@ -59,6 +59,12 @@
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
//
// Decorations
//
@small-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
@big-shadow: 0 14px 25px rgba(0, 0, 0, 0.16);
// //
// Container // Container
// //
@ -148,6 +154,7 @@
// Paper // Paper
// //
@paper-border-radius: 4px; @paper-border-radius: 4px;
@button-border-radius: 3px;
/* ======================================================================== /* ========================================================================
@ -187,9 +194,8 @@
.uk-card { .uk-card {
border-radius: @paper-border-radius; border-radius: @paper-border-radius;
border: 1px solid rgba(180, 180, 180, 0.25); //border: 1px solid rgba(180, 180, 180, 0.25);
box-shadow: none; box-shadow: @small-shadow;
-webkit-box-shabox-shadow: none;
} }
.uk-card-media-top img { .uk-card-media-top img {
@ -228,7 +234,7 @@
*/ */
.uk-modal-dialog { .uk-modal-dialog {
border-radius: @paper-border-radius; border-radius: @paper-border-radius;
box-shadow: 0 14px 25px rgba(0, 0, 0, 0.16); box-shadow: @big-shadow;
transition: 0.3s ease !important; transition: 0.3s ease !important;
} }
@ -245,7 +251,7 @@
*/ */
.uk-notification-message { .uk-notification-message {
border-radius: @paper-border-radius; border-radius: @paper-border-radius;
box-shadow: 0 14px 25px rgba(0, 0, 0, 0.16); box-shadow: @big-shadow;
} }
.uk-notification-message-danger { .uk-notification-message-danger {
@ -287,7 +293,7 @@ a:hover {
* Buttons * Buttons
*/ */
.uk-button { .uk-button {
border-radius: 2px; border-radius: @button-border-radius;
padding: 0 8px; padding: 0 8px;
} }
@ -296,6 +302,12 @@ a:hover {
border-color: @global-border; border-color: @global-border;
} }
.uk-button-primary {
background-color: rgba(180, 180, 180, 0.10);
border-color: @global-primary-background;
color: @button-text-color;
}
.uk-button-danger { .uk-button-danger {
background-color: transparent; background-color: transparent;
color: #f0506e; color: #f0506e;

View file

@ -218,6 +218,18 @@ export default {
} }
} }
return pluginGuis; return pluginGuis;
},
tabOrder: function() {
// TODO: There must be a better way to do this, somehow reading the order of the HTML elements?
var ind = ["view", "gallery", "navigate", "capture", "settings"];
for (const plugin of this.pluginsGuiList) {
ind.push(plugin.id);
}
ind.push("about");
return ind;
},
currentTabIndex: function() {
return this.tabOrder.indexOf(this.currentTab);
} }
}, },
@ -246,6 +258,14 @@ export default {
this.$root.$on("globalSwitchTab", tabID => { this.$root.$on("globalSwitchTab", tabID => {
this.currentTab = tabID; this.currentTab = tabID;
}); });
// A global signal listener to increment tab
this.$root.$on("globalIncrementTab", () => {
this.incrementTabBy(1);
});
// A global signal listener to decrement tab
this.$root.$on("globalDecrementTab", () => {
this.incrementTabBy(-1);
});
}, },
beforeDestroy() { beforeDestroy() {
@ -274,6 +294,14 @@ export default {
this.currentTab = tab; this.currentTab = tab;
} }
}, },
incrementTabBy: function(n) {
const newIndex =
(((this.currentTabIndex + n) % this.tabOrder.length) +
this.tabOrder.length) %
this.tabOrder.length;
const newId = this.tabOrder[newIndex];
this.currentTab = newId;
},
startModals: function() { startModals: function() {
this.$refs["calibrationModal"].show(); this.$refs["calibrationModal"].show();
}, },

View file

@ -111,6 +111,8 @@
:submit-url="fastAutofocusUri" :submit-url="fastAutofocusUri"
:submit-data="{ dz: 2000 }" :submit-data="{ dz: 2000 }"
:submit-label="'Fast'" :submit-label="'Fast'"
:button-primary="false"
:submit-on-event="'globalFastAutofocusEvent'"
@taskStarted="isAutofocusing = 1" @taskStarted="isAutofocusing = 1"
@finished="isAutofocusing = 0" @finished="isAutofocusing = 0"
></taskSubmitter> ></taskSubmitter>
@ -122,6 +124,7 @@
:submit-url="normalAutofocusUri" :submit-url="normalAutofocusUri"
:submit-data="{ dz: [-60, -30, 0, 30, 60] }" :submit-data="{ dz: [-60, -30, 0, 30, 60] }"
:submit-label="'Medium'" :submit-label="'Medium'"
:button-primary="false"
@taskStarted="isAutofocusing = 2" @taskStarted="isAutofocusing = 2"
@finished="isAutofocusing = 0" @finished="isAutofocusing = 0"
></taskSubmitter> ></taskSubmitter>
@ -133,6 +136,7 @@
:submit-url="normalAutofocusUri" :submit-url="normalAutofocusUri"
:submit-data="{ dz: [-20, -10, 0, 10, 20] }" :submit-data="{ dz: [-20, -10, 0, 10, 20] }"
:submit-label="'Fine'" :submit-label="'Fine'"
:button-primary="false"
@taskStarted="isAutofocusing = 3" @taskStarted="isAutofocusing = 3"
@finished="isAutofocusing = 0" @finished="isAutofocusing = 0"
></taskSubmitter> ></taskSubmitter>
@ -201,6 +205,7 @@ export default {
this.$root.$on("globalMoveInImageCoordinatesEvent", (x, y, absolute) => { this.$root.$on("globalMoveInImageCoordinatesEvent", (x, y, absolute) => {
this.moveInImageCoordinatesRequest(x, y, absolute); this.moveInImageCoordinatesRequest(x, y, absolute);
}); });
// A global signal listener to perform a move in multiples of a step size
this.$root.$on("globalMoveStepEvent", (x_steps, y_steps, z_steps) => { this.$root.$on("globalMoveStepEvent", (x_steps, y_steps, z_steps) => {
this.moveRequest( this.moveRequest(
x_steps * this.stepXy, x_steps * this.stepXy,
@ -219,6 +224,8 @@ export default {
beforeDestroy() { beforeDestroy() {
// Remove global signal listener to perform a move action // Remove global signal listener to perform a move action
this.$root.$off("globalMoveEvent"); this.$root.$off("globalMoveEvent");
this.$root.$off("globalMoveInImageCoordinatesEvent");
this.$root.$off("globalMoveStepEvent");
}, },
methods: { methods: {

View file

@ -93,13 +93,9 @@ export default {
@import "../../assets/less/theme.less"; @import "../../assets/less/theme.less";
.tabicon-active { .tabicon-active {
color: @global-primary-background !important; color: #fff !important;
} background-color: @global-primary-background !important;
box-shadow: @small-shadow;
.hook-inverse() {
.tabicon-active {
color: @inverse-primary-muted-color !important;
}
} }
.tabtitle { .tabtitle {

View file

@ -78,7 +78,12 @@ export default {
buttonPrimary: { buttonPrimary: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: true
},
submitOnEvent: {
type: String,
required: false,
default: null
} }
}, },
@ -101,7 +106,20 @@ export default {
created() {}, created() {},
beforeDestroy() {}, mounted() {
// A global signal listener to perform a move action
if (this.submitOnEvent) {
this.$root.$on(this.submitOnEvent, () => {
this.bootstrapTask();
});
}
},
beforeDestroy() {
if (this.submitOnEvent) {
this.$root.$off(this.submitOnEvent);
}
},
methods: { methods: {
bootstrapTask: function() { bootstrapTask: function() {

View file

@ -9,7 +9,7 @@
<a <a
class="uk-link" class="uk-link"
target="_blank" target="_blank"
href="https://gitlab.com/openflexure/openflexure-microscope-jsclient/-/issues" href="https://gitlab.com/openflexure/openflexure-microscope-server/-/issues"
>Report an issue</a >Report an issue</a
> >
</div> </div>

View file

@ -153,11 +153,11 @@ export default {
}; };
</script> </script>
<style lang="less"> <style lang="less" scoped>
// Custom UIkit CSS modifications
@import "../../assets/less/theme.less";
.settings-pane { .settings-pane {
border-width: 0 1px 0 0;
border-style: solid;
border-color: rgba(180, 180, 180, 0.25);
} }
.settings-nav { .settings-nav {
@ -170,4 +170,9 @@ export default {
border-style: solid; border-style: solid;
border-color: rgba(180, 180, 180, 0.25); border-color: rgba(180, 180, 180, 0.25);
} }
.settings-nav li > a {
padding-left: 6px !important;
border-radius: @button-border-radius;
}
</style> </style>

View file

@ -129,6 +129,10 @@ Vue.mixin({
UIkit.modal(element).hide(); UIkit.modal(element).hide();
}, },
toggleModalElement: function(element) {
UIkit.modal(element).toggle();
},
getLocalStorageObj: function(keyName) { getLocalStorageObj: function(keyName) {
if (localStorage.getItem(keyName)) { if (localStorage.getItem(keyName)) {
try { try {