Add a mini menu, make sync button a generic button, and allow reseting properties
This commit is contained in:
parent
ace42bcf2e
commit
a2ebed1006
6 changed files with 343 additions and 93 deletions
|
|
@ -278,6 +278,15 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduing the ui-kit mergins from 20px to 5px
|
||||||
|
.ofm-close-pars p{
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ofm-close-pars * + p{
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.hook-inverse() {
|
.hook-inverse() {
|
||||||
.ofm-highlighted-label{
|
.ofm-highlighted-label{
|
||||||
color: @very-light-primary-color;
|
color: @very-light-primary-color;
|
||||||
|
|
@ -300,6 +309,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For links that shouldn't look style like links (such as in menus)
|
||||||
|
.ofm-hidden-link {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: @global-color;
|
||||||
|
}
|
||||||
|
.hook-inverse() {
|
||||||
|
.ofm-hidden-link{
|
||||||
|
color: @inverse-global-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buttons
|
* Buttons
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
64
webapp/src/components/genericComponents/iconButton.vue
Normal file
64
webapp/src/components/genericComponents/iconButton.vue
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
<template>
|
||||||
|
<a class="sync-button" @click.prevent="$emit('click')">
|
||||||
|
<span class="material-symbols-outlined sync-icon">
|
||||||
|
{{ icon }}
|
||||||
|
</span>
|
||||||
|
<span v-if="showLabel" class="icon-label ofm-hidden-link">
|
||||||
|
{{ label }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "IconButton",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: "sync",
|
||||||
|
},
|
||||||
|
showLabel: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ["click"],
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.sync-button {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-grow: 0;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-symbols-outlined.sync-icon {
|
||||||
|
color: #888;
|
||||||
|
transition:
|
||||||
|
transform 0.3s ease,
|
||||||
|
color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-symbols-outlined.sync-icon:hover {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
color: #c5247f;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-label {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
73
webapp/src/components/genericComponents/miniMenu.vue
Normal file
73
webapp/src/components/genericComponents/miniMenu.vue
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<div ref="mini-menu" class="mini-menu">
|
||||||
|
<a class="icon" @click.prevent="isOpen = !isOpen">
|
||||||
|
<span class="material-symbols-outlined"> more_vert </span>
|
||||||
|
</a>
|
||||||
|
<div v-if="isOpen" class="dropdown-menu ofm-close-pars ofm-opaque-element">
|
||||||
|
<slot :close="close"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "MiniMenu",
|
||||||
|
|
||||||
|
props: {},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isOpen: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
window.addEventListener("click", this.handleClickOutside);
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeUnmount() {
|
||||||
|
window.removeEventListener("click", this.handleClickOutside);
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleClickOutside(event) {
|
||||||
|
if (!this.$refs["mini-menu"].contains(event.target)) {
|
||||||
|
this.isOpen = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.isOpen = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import url("../../assets/less/variables.less");
|
||||||
|
|
||||||
|
.mini-menu {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 25px;
|
||||||
|
right: 0;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
max-height: 250px;
|
||||||
|
width: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 1000;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
user-select: none;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon:hover {
|
||||||
|
color: #c5247f;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label v-if="useDropdown">
|
||||||
v-if="useDropdown"
|
<span class="uk-form-label" :class="{ 'ofm-highlighted-label': isChangedFomDefault }">
|
||||||
class="uk-form-label"
|
{{ label }}
|
||||||
:class="{ 'ofm-highlighted-label': isChangedFomDefault }"
|
</span>
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
<div class="input-and-buttons-container">
|
<div class="input-and-buttons-container">
|
||||||
<select
|
<select
|
||||||
v-model="internalValue"
|
v-model="internalValue"
|
||||||
|
|
@ -16,15 +14,36 @@
|
||||||
{{ display }}
|
{{ display }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<sync-property-button @click="requestUpdate" />
|
<mini-menu v-slot="{ close }">
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="refresh"
|
||||||
|
:show-label="true"
|
||||||
|
label="Reset to default"
|
||||||
|
@click="
|
||||||
|
resetDefault();
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="sync"
|
||||||
|
:show-label="true"
|
||||||
|
label="Re-sync value"
|
||||||
|
@click="
|
||||||
|
requestUpdate;
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</mini-menu>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label v-if="!useDropdown && dataType == 'number'">
|
||||||
v-if="!useDropdown && dataType == 'number'"
|
<span class="uk-form-label" :class="{ 'ofm-highlighted-label': isChangedFomDefault }">
|
||||||
class="uk-form-label"
|
{{ label }}
|
||||||
:class="{ 'ofm-highlighted-label': isChangedFomDefault }"
|
</span>
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
<div class="input-and-buttons-container">
|
<div class="input-and-buttons-container">
|
||||||
<div class="uk-inline number-wrapper">
|
<div class="uk-inline number-wrapper">
|
||||||
<input
|
<input
|
||||||
|
|
@ -50,14 +69,34 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<sync-property-button @click="requestUpdate" />
|
<mini-menu v-slot="{ close }">
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="refresh"
|
||||||
|
:show-label="true"
|
||||||
|
label="Reset to default"
|
||||||
|
@click="
|
||||||
|
resetDefault();
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="sync"
|
||||||
|
:show-label="true"
|
||||||
|
label="Re-sync value"
|
||||||
|
@click="
|
||||||
|
requestUpdate;
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</mini-menu>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<div v-if="!useDropdown && dataType == 'boolean'" class="input-and-buttons-container">
|
<div v-if="!useDropdown && dataType == 'boolean'" class="input-and-buttons-container">
|
||||||
<label
|
<label class="property-input">
|
||||||
class="uk-form-label property-input"
|
|
||||||
:class="{ 'ofm-highlighted-label': isChangedFomDefault }"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
ref="checkbox"
|
ref="checkbox"
|
||||||
v-model="internalValue"
|
v-model="internalValue"
|
||||||
|
|
@ -66,16 +105,39 @@
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@change="sendValue"
|
@change="sendValue"
|
||||||
/>
|
/>
|
||||||
{{ label }}
|
<span class="uk-form-label" :class="{ 'ofm-highlighted-label': isChangedFomDefault }">
|
||||||
|
{{ label }}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<sync-property-button @click="requestUpdate" />
|
<mini-menu v-slot="{ close }">
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="refresh"
|
||||||
|
:show-label="true"
|
||||||
|
label="Reset to default"
|
||||||
|
@click="
|
||||||
|
resetDefault();
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="sync"
|
||||||
|
:show-label="true"
|
||||||
|
label="Re-sync value"
|
||||||
|
@click="
|
||||||
|
requestUpdate;
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</mini-menu>
|
||||||
</div>
|
</div>
|
||||||
<label
|
<label v-if="!useDropdown && dataType == 'number_array'">
|
||||||
v-if="!useDropdown && dataType == 'number_array'"
|
<span class="uk-form-label" :class="{ 'ofm-highlighted-label': isChangedFomDefault }">
|
||||||
class="uk-form-label"
|
{{ label }}
|
||||||
:class="{ 'ofm-highlighted-label': isChangedFomDefault }"
|
</span>
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
<div class="input-and-buttons-container">
|
<div class="input-and-buttons-container">
|
||||||
<input
|
<input
|
||||||
v-for="i in valueLength"
|
v-for="i in valueLength"
|
||||||
|
|
@ -90,15 +152,36 @@
|
||||||
@keydown="keyDown"
|
@keydown="keyDown"
|
||||||
@animationend="animationEnd"
|
@animationend="animationEnd"
|
||||||
/>
|
/>
|
||||||
<sync-property-button @click="requestUpdate" />
|
<mini-menu v-slot="{ close }">
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="refresh"
|
||||||
|
:show-label="true"
|
||||||
|
label="Reset to default"
|
||||||
|
@click="
|
||||||
|
resetDefault();
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="sync"
|
||||||
|
:show-label="true"
|
||||||
|
label="Re-sync value"
|
||||||
|
@click="
|
||||||
|
requestUpdate;
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</mini-menu>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label v-if="!useDropdown && dataType == 'number_object'">
|
||||||
v-if="!useDropdown && dataType == 'number_object'"
|
<span class="uk-form-label" :class="{ 'ofm-highlighted-label': isChangedFomDefault }">
|
||||||
class="uk-form-label"
|
{{ label }}
|
||||||
:class="{ 'ofm-highlighted-label': isChangedFomDefault }"
|
</span>
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
<div v-for="(val, key) in modelValue" :key="key">
|
<div v-for="(val, key) in modelValue" :key="key">
|
||||||
<label>{{ internalLabels[key] }}</label>
|
<label>{{ internalLabels[key] }}</label>
|
||||||
<div class="input-and-buttons-container">
|
<div class="input-and-buttons-container">
|
||||||
|
|
@ -113,16 +196,37 @@
|
||||||
@keydown="keyDown"
|
@keydown="keyDown"
|
||||||
@animationend="animationEnd"
|
@animationend="animationEnd"
|
||||||
/>
|
/>
|
||||||
<sync-property-button @click="requestUpdate" />
|
<mini-menu v-slot="{ close }">
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="refresh"
|
||||||
|
:show-label="true"
|
||||||
|
label="Reset to default"
|
||||||
|
@click="
|
||||||
|
resetDefault();
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="sync"
|
||||||
|
:show-label="true"
|
||||||
|
label="Re-sync value"
|
||||||
|
@click="
|
||||||
|
requestUpdate;
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</mini-menu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label v-if="!useDropdown && dataType == 'string'">
|
||||||
v-if="!useDropdown && dataType == 'string'"
|
<span class="uk-form-label" :class="{ 'ofm-highlighted-label': isChangedFomDefault }">
|
||||||
class="uk-form-label"
|
{{ label }}
|
||||||
:class="{ 'ofm-highlighted-label': isChangedFomDefault }"
|
</span>
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
<div class="input-and-buttons-container">
|
<div class="input-and-buttons-container">
|
||||||
<input
|
<input
|
||||||
v-model="internalValue"
|
v-model="internalValue"
|
||||||
|
|
@ -134,15 +238,36 @@
|
||||||
@keydown="keyDown"
|
@keydown="keyDown"
|
||||||
@animationend="animationEnd"
|
@animationend="animationEnd"
|
||||||
/>
|
/>
|
||||||
<sync-property-button @click="requestUpdate" />
|
<mini-menu v-slot="{ close }">
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="refresh"
|
||||||
|
:show-label="true"
|
||||||
|
label="Reset to default"
|
||||||
|
@click="
|
||||||
|
resetDefault();
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<icon-button
|
||||||
|
icon="sync"
|
||||||
|
:show-label="true"
|
||||||
|
label="Re-sync value"
|
||||||
|
@click="
|
||||||
|
requestUpdate;
|
||||||
|
close();
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</mini-menu>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label v-if="!useDropdown && dataType == 'other'">
|
||||||
v-if="!useDropdown && dataType == 'other'"
|
<span class="uk-form-label" :class="{ 'ofm-highlighted-label': isChangedFomDefault }">
|
||||||
class="uk-form-label"
|
{{ label }}
|
||||||
:class="{ 'ofm-highlighted-label': isChangedFomDefault }"
|
</span>
|
||||||
>
|
|
||||||
{{ label }}
|
|
||||||
<div class="input-and-buttons-container">
|
<div class="input-and-buttons-container">
|
||||||
<input
|
<input
|
||||||
v-model="internalValue"
|
v-model="internalValue"
|
||||||
|
|
@ -156,13 +281,15 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import syncPropertyButton from "./syncPropertyButton.vue";
|
import iconButton from "@/components/genericComponents/iconButton.vue";
|
||||||
|
import MiniMenu from "@/components/genericComponents/miniMenu.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "InputFromSchema",
|
name: "InputFromSchema",
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
syncPropertyButton,
|
iconButton,
|
||||||
|
MiniMenu,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
dataSchema: {
|
dataSchema: {
|
||||||
|
|
@ -195,7 +322,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ["requestUpdate", "sendValue", "animationShown"],
|
emits: ["requestUpdate", "resetDefault", "sendValue", "animationShown"],
|
||||||
|
|
||||||
compatConfig: { COMPONENT_V_MODEL: false },
|
compatConfig: { COMPONENT_V_MODEL: false },
|
||||||
|
|
||||||
|
|
@ -355,6 +482,11 @@ export default {
|
||||||
this.internalValue = this.modelValue;
|
this.internalValue = this.modelValue;
|
||||||
this.$emit("requestUpdate");
|
this.$emit("requestUpdate");
|
||||||
},
|
},
|
||||||
|
resetDefault: async function () {
|
||||||
|
if (this.isChangedFomDefault) {
|
||||||
|
this.$emit("sendValue", this.dataSchema.default);
|
||||||
|
}
|
||||||
|
},
|
||||||
sendValue: async function () {
|
sendValue: async function () {
|
||||||
this.$emit("sendValue", this.internalValue);
|
this.$emit("sendValue", this.internalValue);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<template>
|
|
||||||
<a class="sync-button" @click.prevent="$emit('click')">
|
|
||||||
<span
|
|
||||||
class="material-symbols-outlined sync-icon"
|
|
||||||
title="Reread value from microscope. Required if microscope is updated externally"
|
|
||||||
>
|
|
||||||
sync
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "SyncPropertyButton",
|
|
||||||
|
|
||||||
emits: ["click"],
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.sync-button {
|
|
||||||
flex-grow: 0;
|
|
||||||
padding-left: 5px;
|
|
||||||
padding-right: 5px;
|
|
||||||
vertical-align: middle;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.material-symbols-outlined.sync-icon {
|
|
||||||
color: #888;
|
|
||||||
transition:
|
|
||||||
transform 0.3s ease,
|
|
||||||
color 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.material-symbols-outlined.sync-icon:hover {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
color: #c5247f;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -22,7 +22,7 @@ and zero position buttons. It also includes the d-pad.
|
||||||
type="number"
|
type="number"
|
||||||
@keyup.enter="startMoveTask"
|
@keyup.enter="startMoveTask"
|
||||||
/>
|
/>
|
||||||
<sync-property-button @click="updatePosition" />
|
<icon-button icon="sync" @click="updatePosition" />
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<action-button
|
<action-button
|
||||||
|
|
@ -59,7 +59,7 @@ and zero position buttons. It also includes the d-pad.
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
||||||
import syncPropertyButton from "../../labThingsComponents/syncPropertyButton.vue";
|
import iconButton from "@/components/genericComponents/iconButton.vue";
|
||||||
import stageControlButtons from "./stageControlButtons.vue";
|
import stageControlButtons from "./stageControlButtons.vue";
|
||||||
import { eventBus } from "../../../eventBus.js";
|
import { eventBus } from "../../../eventBus.js";
|
||||||
|
|
||||||
|
|
@ -68,7 +68,7 @@ export default {
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ActionButton,
|
ActionButton,
|
||||||
syncPropertyButton,
|
iconButton,
|
||||||
stageControlButtons,
|
stageControlButtons,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue