Merge branch 'theme-updates' into 'labthings-070'
Theme updates See merge request openflexure/openflexure-microscope-server!68
This commit is contained in:
commit
6d1d3016d1
12 changed files with 240 additions and 130 deletions
|
|
@ -10,21 +10,11 @@ To prevent the editor from interfering with ESLint, add to your project `setting
|
|||
{
|
||||
"editor.tabSize": 2,
|
||||
"cSpell.enabled": false,
|
||||
"eslint.validate": [{
|
||||
"language": "vue",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "javascript",
|
||||
"autoFix": true
|
||||
},
|
||||
{
|
||||
"language": "javascriptreact",
|
||||
"autoFix": true
|
||||
}
|
||||
],
|
||||
"eslint.autoFixOnSave": true,
|
||||
"eslint.validate": ["vue","javascript", "javascriptreact"],
|
||||
"editor.formatOnSave": false,
|
||||
"vetur.validation.template": false
|
||||
"vetur.validation.template": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -9210,6 +9210,11 @@
|
|||
"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": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@
|
|||
"serve": "vue-cli-service serve --mode development"
|
||||
},
|
||||
"dependencies": {
|
||||
"material-design-icons": "^3.0.1"
|
||||
"material-design-icons": "^3.0.1",
|
||||
"mousetrap": "^1.6.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.12.1",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,26 @@
|
|||
<loadingContent v-if="!$store.getters.ready" />
|
||||
<div v-if="$store.getters.ready" id="tour-header"></div>
|
||||
<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-show="$store.getters.ready"
|
||||
name="guidedTour"
|
||||
|
|
@ -23,20 +43,26 @@ import appContent from "./components/appContent.vue";
|
|||
import loadingContent from "./components/loadingContent.vue";
|
||||
|
||||
import axios from "axios";
|
||||
var Mousetrap = require("mousetrap");
|
||||
|
||||
// Key Codes
|
||||
const keyCodes = {
|
||||
pgup: 33,
|
||||
pgdn: 34,
|
||||
left: 37,
|
||||
up: 38,
|
||||
right: 39,
|
||||
down: 40,
|
||||
enter: 13,
|
||||
esc: 27,
|
||||
shift: 16,
|
||||
alt: 18,
|
||||
t: 84
|
||||
Mousetrap.prototype.stopCallback = function(e, element, combo) {
|
||||
// if the element has the class "mousetrap" then no need to stop
|
||||
if ((" " + element.className + " ").indexOf(" mousetrap ") > -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if we're in a lightbox, stop mousetrap
|
||||
if (element.classList.contains("lightbox-link")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// stop for input, select, and textarea
|
||||
return (
|
||||
element.tagName == "INPUT" ||
|
||||
element.tagName == "SELECT" ||
|
||||
element.tagName == "TEXTAREA" ||
|
||||
(element.contentEditable && element.contentEditable == "true")
|
||||
);
|
||||
};
|
||||
|
||||
// Export main app
|
||||
|
|
@ -51,7 +77,8 @@ export default {
|
|||
data: function() {
|
||||
return {
|
||||
appAvailable: false,
|
||||
keysDown: {},
|
||||
arrowKeysDown: {},
|
||||
keyboardManual: [],
|
||||
systemDark: undefined,
|
||||
themeObserver: undefined,
|
||||
tourCallbacks: {
|
||||
|
|
@ -166,9 +193,7 @@ export default {
|
|||
|
||||
created: function() {
|
||||
window.addEventListener("beforeunload", this.handleExit);
|
||||
// Key events
|
||||
window.addEventListener("keydown", this.keyDownMonitor);
|
||||
window.addEventListener("keyup", this.keyUpMonitor);
|
||||
// Scrollwheel listener
|
||||
window.addEventListener("wheel", this.wheelMonitor);
|
||||
// Watch for origin changes
|
||||
this.unwatchOriginFunction = this.$store.watch(
|
||||
|
|
@ -180,6 +205,82 @@ export default {
|
|||
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() {
|
||||
|
|
@ -187,12 +288,13 @@ export default {
|
|||
if (this.themeObserver) {
|
||||
this.themeObserver.disconnect();
|
||||
}
|
||||
// Remove key listeners
|
||||
window.removeEventListener("keydown", this.keyDownMonitor);
|
||||
window.removeEventListener("keyup", this.keyUpMonitor);
|
||||
// Remove scrollwheel listener
|
||||
window.removeEventListener("wheel", this.wheelMonitor);
|
||||
// Remove origin watcher
|
||||
this.unwatchOriginFunction();
|
||||
// Remove key listeners
|
||||
console.log("Resetting Mousetrap");
|
||||
Mousetrap.reset();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
@ -231,84 +333,26 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
// Handle global key press events to be associated with navigation
|
||||
keyDownMonitor: function(event) {
|
||||
this.keysDown[event.keyCode] = true; //Add key to array
|
||||
|
||||
// Convert keyCode dict into a list of key codes
|
||||
var keyCodeList = Object.keys(keyCodes).map(function(key) {
|
||||
return keyCodes[key];
|
||||
});
|
||||
|
||||
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);
|
||||
navigateKeyHandler: function() {
|
||||
// Calculate movement array
|
||||
var x_rel = 0;
|
||||
var y_rel = 0;
|
||||
var z_rel = 0;
|
||||
if (37 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 (39 in this.arrowKeysDown) {
|
||||
x_rel = x_rel - 1;
|
||||
}
|
||||
},
|
||||
|
||||
captureKeyHandler: function(keyCodes) {
|
||||
if (keyCodes.shift in this.keysDown && keyCodes.enter in this.keysDown) {
|
||||
console.log("Capturing");
|
||||
this.$root.$emit("globalCaptureEvent");
|
||||
if (38 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();
|
||||
if (40 in this.arrowKeysDown) {
|
||||
y_rel = y_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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@
|
|||
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
|
||||
//
|
||||
|
|
@ -148,6 +154,7 @@
|
|||
// Paper
|
||||
//
|
||||
@paper-border-radius: 4px;
|
||||
@button-border-radius: 3px;
|
||||
|
||||
|
||||
/* ========================================================================
|
||||
|
|
@ -187,9 +194,8 @@
|
|||
|
||||
.uk-card {
|
||||
border-radius: @paper-border-radius;
|
||||
border: 1px solid rgba(180, 180, 180, 0.25);
|
||||
box-shadow: none;
|
||||
-webkit-box-shabox-shadow: none;
|
||||
//border: 1px solid rgba(180, 180, 180, 0.25);
|
||||
box-shadow: @small-shadow;
|
||||
}
|
||||
|
||||
.uk-card-media-top img {
|
||||
|
|
@ -228,7 +234,7 @@
|
|||
*/
|
||||
.uk-modal-dialog {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +251,7 @@
|
|||
*/
|
||||
.uk-notification-message {
|
||||
border-radius: @paper-border-radius;
|
||||
box-shadow: 0 14px 25px rgba(0, 0, 0, 0.16);
|
||||
box-shadow: @big-shadow;
|
||||
}
|
||||
|
||||
.uk-notification-message-danger {
|
||||
|
|
@ -287,7 +293,7 @@ a:hover {
|
|||
* Buttons
|
||||
*/
|
||||
.uk-button {
|
||||
border-radius: 2px;
|
||||
border-radius: @button-border-radius;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
|
|
@ -296,6 +302,12 @@ a:hover {
|
|||
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 {
|
||||
background-color: transparent;
|
||||
color: #f0506e;
|
||||
|
|
|
|||
|
|
@ -218,6 +218,18 @@ export default {
|
|||
}
|
||||
}
|
||||
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.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() {
|
||||
|
|
@ -274,6 +294,14 @@ export default {
|
|||
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() {
|
||||
this.$refs["calibrationModal"].show();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@
|
|||
:submit-url="fastAutofocusUri"
|
||||
:submit-data="{ dz: 2000 }"
|
||||
:submit-label="'Fast'"
|
||||
:button-primary="false"
|
||||
:submit-on-event="'globalFastAutofocusEvent'"
|
||||
@taskStarted="isAutofocusing = 1"
|
||||
@finished="isAutofocusing = 0"
|
||||
></taskSubmitter>
|
||||
|
|
@ -122,6 +124,7 @@
|
|||
:submit-url="normalAutofocusUri"
|
||||
:submit-data="{ dz: [-60, -30, 0, 30, 60] }"
|
||||
:submit-label="'Medium'"
|
||||
:button-primary="false"
|
||||
@taskStarted="isAutofocusing = 2"
|
||||
@finished="isAutofocusing = 0"
|
||||
></taskSubmitter>
|
||||
|
|
@ -133,6 +136,7 @@
|
|||
:submit-url="normalAutofocusUri"
|
||||
:submit-data="{ dz: [-20, -10, 0, 10, 20] }"
|
||||
:submit-label="'Fine'"
|
||||
:button-primary="false"
|
||||
@taskStarted="isAutofocusing = 3"
|
||||
@finished="isAutofocusing = 0"
|
||||
></taskSubmitter>
|
||||
|
|
@ -201,6 +205,7 @@ export default {
|
|||
this.$root.$on("globalMoveInImageCoordinatesEvent", (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.moveRequest(
|
||||
x_steps * this.stepXy,
|
||||
|
|
@ -219,6 +224,8 @@ export default {
|
|||
beforeDestroy() {
|
||||
// Remove global signal listener to perform a move action
|
||||
this.$root.$off("globalMoveEvent");
|
||||
this.$root.$off("globalMoveInImageCoordinatesEvent");
|
||||
this.$root.$off("globalMoveStepEvent");
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -93,13 +93,9 @@ export default {
|
|||
@import "../../assets/less/theme.less";
|
||||
|
||||
.tabicon-active {
|
||||
color: @global-primary-background !important;
|
||||
}
|
||||
|
||||
.hook-inverse() {
|
||||
.tabicon-active {
|
||||
color: @inverse-primary-muted-color !important;
|
||||
}
|
||||
color: #fff !important;
|
||||
background-color: @global-primary-background !important;
|
||||
box-shadow: @small-shadow;
|
||||
}
|
||||
|
||||
.tabtitle {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,12 @@ export default {
|
|||
buttonPrimary: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
default: true
|
||||
},
|
||||
submitOnEvent: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -101,7 +106,20 @@ export default {
|
|||
|
||||
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: {
|
||||
bootstrapTask: function() {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<a
|
||||
class="uk-link"
|
||||
target="_blank"
|
||||
href="https://gitlab.com/openflexure/openflexure-microscope-jsclient/-/issues"
|
||||
href="https://gitlab.com/openflexure/openflexure-microscope-server/-/issues"
|
||||
>Report an issue</a
|
||||
>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -153,11 +153,11 @@ export default {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
<style lang="less" scoped>
|
||||
// Custom UIkit CSS modifications
|
||||
@import "../../assets/less/theme.less";
|
||||
|
||||
.settings-pane {
|
||||
border-width: 0 1px 0 0;
|
||||
border-style: solid;
|
||||
border-color: rgba(180, 180, 180, 0.25);
|
||||
}
|
||||
|
||||
.settings-nav {
|
||||
|
|
@ -170,4 +170,9 @@ export default {
|
|||
border-style: solid;
|
||||
border-color: rgba(180, 180, 180, 0.25);
|
||||
}
|
||||
|
||||
.settings-nav li > a {
|
||||
padding-left: 6px !important;
|
||||
border-radius: @button-border-radius;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -129,6 +129,10 @@ Vue.mixin({
|
|||
UIkit.modal(element).hide();
|
||||
},
|
||||
|
||||
toggleModalElement: function(element) {
|
||||
UIkit.modal(element).toggle();
|
||||
},
|
||||
|
||||
getLocalStorageObj: function(keyName) {
|
||||
if (localStorage.getItem(keyName)) {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue