mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-22 01:11:40 +00:00
[PhotonClient] Vite and Typescript complete refactor (#884)
This commit is contained in:
@@ -1,18 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(defineProps<{
|
||||
iconName: string,
|
||||
color?: string,
|
||||
tooltip?: string,
|
||||
right?: boolean,
|
||||
hover?: boolean
|
||||
}>(), {
|
||||
right: false,
|
||||
hover: false
|
||||
});
|
||||
|
||||
const hoverClass = props.hover ? "hover" : "";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-tooltip
|
||||
:right="right"
|
||||
:bottom="!right"
|
||||
nudge-right="10"
|
||||
:disabled="tooltip === undefined"
|
||||
>
|
||||
<template v-slot:activator="{ on }">
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-icon
|
||||
:class="hoverClass"
|
||||
:color="color"
|
||||
@click="handleClick"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
{{ text }}
|
||||
{{ iconName }}
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>{{ tooltip }}</span>
|
||||
@@ -20,33 +37,6 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Icon',
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['color', 'tooltip', 'text', 'right', 'hover'],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
hoverClass: {
|
||||
get() {
|
||||
if (this.hover !== undefined) {
|
||||
return "hover";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.$emit('click');
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hover:hover {
|
||||
color: white !important;
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
<template>
|
||||
<img
|
||||
:id="id"
|
||||
crossOrigin="anonymous"
|
||||
:style="styleObject"
|
||||
:src="src"
|
||||
:alt="alt"
|
||||
@click="clickHandler"
|
||||
@error="loadErrHandler"
|
||||
>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "CvImage",
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['address', 'scale', 'maxHeight', 'maxHeightMd', 'maxHeightLg', 'maxHeightXl', 'colorPicking', 'id', 'disconnected', 'alt'],
|
||||
data() {
|
||||
return {
|
||||
seed: 1.0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
styleObject: {
|
||||
get() {
|
||||
let ret = {
|
||||
"border-radius": "3px",
|
||||
"display": "block",
|
||||
"object-fit": "contain",
|
||||
"background-size:": "contain",
|
||||
"object-position": "50% 50%",
|
||||
"max-width": "100%",
|
||||
"margin-left": "auto",
|
||||
"margin-right": "auto",
|
||||
"max-height": this.maxHeight,
|
||||
height: `${this.scale}%`,
|
||||
cursor: (this.colorPicking ? `url(${require("../../assets/icons/eyedropper.svg")}),` : "pointer") + "default",
|
||||
};
|
||||
|
||||
if (this.$vuetify.breakpoint.xl) {
|
||||
ret["max-height"] = this.maxHeightXl;
|
||||
} else if (this.$vuetify.breakpoint.lg) {
|
||||
ret["max-height"] = this.maxHeightLg;
|
||||
} else if (this.$vuetify.breakpoint.md) {
|
||||
ret["max-height"] = this.maxHeightMd;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
},
|
||||
src: {
|
||||
get() {
|
||||
const port = this.getCurPort();
|
||||
if(port <= 0){
|
||||
//Invalid port, keep it spiny
|
||||
return require("../../../public/loading.svg");
|
||||
} else {
|
||||
//Valid port, connect
|
||||
return this.getSrcURLFromPort(port);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.reload(); // Force reload image on creation
|
||||
},
|
||||
methods: {
|
||||
getCurPort(){
|
||||
let port = -1;
|
||||
if(this.disconnected){
|
||||
//Disconnected, port is unknown.
|
||||
port = -1;
|
||||
} else {
|
||||
//Connected - get the port
|
||||
if(this.id === 'raw-stream'){
|
||||
port = this.$store.state.cameraSettings[this.$store.state.currentCameraIndex].inputStreamPort
|
||||
} else {
|
||||
port = this.$store.state.cameraSettings[this.$store.state.currentCameraIndex].outputStreamPort
|
||||
}
|
||||
}
|
||||
return port;
|
||||
},
|
||||
getSrcURLFromPort(port){
|
||||
return "http://" + location.hostname + ":" + port + "/stream.mjpg" + "?" + this.seed;
|
||||
},
|
||||
loadErrHandler(event) {
|
||||
console.log(event);
|
||||
console.log("Error loading image, attempting to do it again...");
|
||||
this.reload();
|
||||
},
|
||||
clickHandler(event) {
|
||||
if(this.colorPicking){
|
||||
this.$emit('click', event);
|
||||
} else {
|
||||
const port = this.getCurPort();
|
||||
if(port <= 0){
|
||||
console.log("No valid port, ignoring click.");
|
||||
} else {
|
||||
//Valid port, connect
|
||||
window.open(this.getSrcURLFromPort(port), '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
reload() {
|
||||
this.seed = new Date().getTime();
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1,64 +1,77 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import TooltippedLabel from "@/components/common/cv-tooltipped-label.vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string,
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: string,
|
||||
disabled?: boolean,
|
||||
errorMessage?: string,
|
||||
placeholder?: string,
|
||||
labelCols?: number,
|
||||
inputCols?: number,
|
||||
rules?: ((v: string) => boolean | string)[]
|
||||
}>(), {
|
||||
disabled: false,
|
||||
inputCols: 8
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: string): void
|
||||
(e: "onEnter", value: string): void
|
||||
(e: "onEscape"): void
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
get: () => props.value,
|
||||
set: v => emit("input", v)
|
||||
});
|
||||
|
||||
|
||||
const handleKeydown = ({ key }) => {
|
||||
switch (key) {
|
||||
case "Enter":
|
||||
if(!(props.rules || []).some(v => v(localValue.value) === false || typeof v(localValue.value) === "string")) {
|
||||
emit("onEnter", localValue.value);
|
||||
}
|
||||
break;
|
||||
case "Escape":
|
||||
emit("onEscape");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
dense
|
||||
align="center"
|
||||
>
|
||||
<v-col :cols="labelCols || (12 - (inputCols || 8))">
|
||||
<v-col :cols="labelCols || (12 - inputCols)">
|
||||
<tooltipped-label
|
||||
:tooltip="tooltip"
|
||||
:text="name"
|
||||
:label="label"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col :cols="inputCols || 8">
|
||||
|
||||
<v-col :cols="inputCols">
|
||||
<v-text-field
|
||||
v-model="localValue"
|
||||
dark
|
||||
dense
|
||||
color="accent"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:error-messages="errorMessage"
|
||||
:rules="rules"
|
||||
class="mt-1 pt-2"
|
||||
@keydown="handleKeyboard"
|
||||
@keydown="handleKeydown"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TooltippedLabel from "./cv-tooltipped-label";
|
||||
|
||||
export default {
|
||||
name: 'Input',
|
||||
components: {
|
||||
TooltippedLabel
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['name', 'value', 'disabled', 'errorMessage', 'inputCols', 'labelCols', 'rules', 'tooltip'],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleKeyboard(event) {
|
||||
if (event.key === "Enter") {
|
||||
this.$emit("Enter");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import TooltippedLabel from "@/components/common/cv-tooltipped-label.vue";
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string,
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: number,
|
||||
disabled?: boolean,
|
||||
labelCols?: number,
|
||||
rules?: ((v: number) => boolean | string)[],
|
||||
step?: number
|
||||
}>(), {
|
||||
disabled: false,
|
||||
labelCols: 2,
|
||||
step: 1
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: number): void
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
get: () => props.value,
|
||||
set: v => emit("input", parseFloat(v as unknown as string))
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
dense
|
||||
align="center"
|
||||
>
|
||||
<v-col :cols="labelCols || 2">
|
||||
<v-col :cols="labelCols">
|
||||
<tooltipped-label
|
||||
:tooltip="tooltip"
|
||||
:text="name"
|
||||
:label="label"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
@@ -28,30 +57,3 @@
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TooltippedLabel from "./cv-tooltipped-label";
|
||||
|
||||
export default {
|
||||
name: 'NumberInput',
|
||||
components: {
|
||||
TooltippedLabel,
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['name', 'value', 'step', 'labelCols', 'rules', 'tooltip', 'disabled'],
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', parseFloat(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,16 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import TooltippedLabel from "@/components/common/cv-tooltipped-label.vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string,
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: number,
|
||||
disabled?: boolean,
|
||||
inputCols?: number,
|
||||
list: string[]
|
||||
}>(), {
|
||||
disabled: false,
|
||||
inputCols: 8
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: number): void
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
get: () => props.value,
|
||||
set: v => emit("input", v)
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
dense
|
||||
align="center"
|
||||
>
|
||||
<v-col :cols="12 - (inputCols || 8)">
|
||||
<v-col :cols="12 - inputCols">
|
||||
<tooltipped-label
|
||||
:tooltip="tooltip"
|
||||
:text="name"
|
||||
:label="label"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col :cols="inputCols || 8">
|
||||
<v-col :cols="inputCols">
|
||||
<v-radio-group
|
||||
v-model="localValue"
|
||||
row
|
||||
@@ -18,7 +45,7 @@
|
||||
:mandatory="true"
|
||||
>
|
||||
<v-radio
|
||||
v-for="(radioName,index) in list"
|
||||
v-for="(radioName, index) in list"
|
||||
:key="index"
|
||||
color="#ffd843"
|
||||
:label="radioName"
|
||||
@@ -30,33 +57,3 @@
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TooltippedLabel from "./cv-tooltipped-label";
|
||||
|
||||
export default {
|
||||
name: 'Radio',
|
||||
components: {
|
||||
TooltippedLabel
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['name', 'value', 'list', 'disabled', 'inputCols', 'tooltip'],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,18 +1,60 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import TooltippedLabel from "@/components/common/cv-tooltipped-label.vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string,
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
// value: [number, number] | WebsocketNumberPair, // Vue doesnt like Union types for the value prop for some reason.
|
||||
value: [number, number],
|
||||
min: number,
|
||||
max: number,
|
||||
step?: number,
|
||||
sliderCols?: number,
|
||||
disabled?: boolean,
|
||||
inverted?: boolean,
|
||||
}>(), {
|
||||
step: 1,
|
||||
disabled: false,
|
||||
inverted: false,
|
||||
sliderCols: 10
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: [number, number]): void
|
||||
}>();
|
||||
|
||||
const localValue = computed<[number, number]>({
|
||||
get: ():[number, number] => {
|
||||
return Object.values(props.value) as [number, number];
|
||||
},
|
||||
set: v => emit("input", v)
|
||||
});
|
||||
|
||||
const changeFromSlot = (v: number, i: number) => {
|
||||
// localValue.value must be replaced for a reactive change to take place
|
||||
const temp = localValue.value;
|
||||
temp[i] = v;
|
||||
localValue.value = temp;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
dense
|
||||
align="center"
|
||||
>
|
||||
<v-col cols="2">
|
||||
<v-col :cols="12 - sliderCols">
|
||||
<tooltipped-label
|
||||
:tooltip="tooltip"
|
||||
:text="name"
|
||||
:label="label"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="10">
|
||||
<v-col :cols="sliderCols">
|
||||
<v-range-slider
|
||||
:value="localValue"
|
||||
v-model="localValue"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:disabled="disabled"
|
||||
@@ -23,44 +65,37 @@
|
||||
:track-color="inverted ? 'accent' : undefined"
|
||||
thumb-color="accent"
|
||||
:step="step"
|
||||
@input="handleInput"
|
||||
@mousedown="$emit('rollback', localValue)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<template #prepend>
|
||||
<v-text-field
|
||||
:value="localValue[0]"
|
||||
dark
|
||||
color="accent"
|
||||
:value="localValue[0]"
|
||||
:max="max"
|
||||
:min="min"
|
||||
class="mt-0 pt-0"
|
||||
hide-details
|
||||
single-line
|
||||
:max="max"
|
||||
:min="min"
|
||||
:step="step"
|
||||
type="number"
|
||||
style="width: 60px"
|
||||
:step="step"
|
||||
@input="handleChange"
|
||||
@focus="prependFocused = true"
|
||||
@blur="prependFocused = false"
|
||||
@input="v => changeFromSlot(v, 0)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-slot:append>
|
||||
<template #append>
|
||||
<v-text-field
|
||||
:value="localValue[1]"
|
||||
dark
|
||||
color="accent"
|
||||
:value="localValue[1]"
|
||||
:max="max"
|
||||
:min="min"
|
||||
class="mt-0 pt-0"
|
||||
hide-details
|
||||
single-line
|
||||
:max="max"
|
||||
:min="min"
|
||||
:step="step"
|
||||
type="number"
|
||||
style="width: 60px"
|
||||
:step="step"
|
||||
@input="handleChange"
|
||||
@focus="appendFocused = true"
|
||||
@blur="appendFocused = false"
|
||||
@input="v => changeFromSlot(v, 1)"
|
||||
/>
|
||||
</template>
|
||||
</v-range-slider>
|
||||
@@ -68,67 +103,3 @@
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TooltippedLabel from "./cv-tooltipped-label";
|
||||
|
||||
export default {
|
||||
name: "RangeSlider",
|
||||
components: {
|
||||
TooltippedLabel,
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ["name", "min", "max", "value", "step", "tooltip", "disabled", "inverted"],
|
||||
data() {
|
||||
return {
|
||||
prependFocused: false,
|
||||
appendFocused: false,
|
||||
currentTempVal: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return Object.values(this.value || [0, 0]);
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("input", value);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
delay(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
},
|
||||
|
||||
async handleChange(val) {
|
||||
this.currentTempVal = val;
|
||||
|
||||
await this.delay(200).then(() => {
|
||||
let i = 0;
|
||||
if (!this.prependFocused && this.appendFocused) {
|
||||
i = 1;
|
||||
}
|
||||
|
||||
// will get empty string if entry is not a number
|
||||
if (this.currentTempVal !== val || val === "") return;
|
||||
|
||||
let parsed = parseFloat(val);
|
||||
let tmp = this.localValue;
|
||||
tmp[i] = Math.max(this.min, Math.min(parsed, this.max));
|
||||
this.localValue = tmp;
|
||||
|
||||
this.$emit("rollback", this.localValue);
|
||||
});
|
||||
},
|
||||
handleInput(val) {
|
||||
if (!this.prependFocused || !this.appendFocused) {
|
||||
this.localValue = val;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="" scoped>
|
||||
</style>
|
||||
|
||||
@@ -1,66 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import TooltippedLabel from "@/components/common/cv-tooltipped-label.vue";
|
||||
|
||||
interface SelectItem {
|
||||
name: string | number,
|
||||
value: string | number,
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string,
|
||||
selectCols?: number,
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: number,
|
||||
disabled?: boolean,
|
||||
items: string[] | number[] | SelectItem[]
|
||||
}>(), {
|
||||
selectCols: 9,
|
||||
disabled: false
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: number): void
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
get: () => props.value,
|
||||
set: v => emit("input", v)
|
||||
});
|
||||
|
||||
// Computed in case items changes
|
||||
const items = computed<SelectItem[]>(() => {
|
||||
// Check if the prop exists on the object to infer object type
|
||||
if((props.items[0] as SelectItem).name) {
|
||||
return props.items as SelectItem[];
|
||||
}
|
||||
return props.items.map((v, i) => ({ name: v, value: i }));
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
dense
|
||||
align="center"
|
||||
>
|
||||
<v-col :cols="12 - (selectCols || 9)">
|
||||
<v-col :cols="12 - selectCols">
|
||||
<tooltipped-label
|
||||
:tooltip="tooltip"
|
||||
:text="name"
|
||||
:label="label"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col :cols="selectCols || 9">
|
||||
<v-col :cols="selectCols">
|
||||
<v-select
|
||||
v-model="localValue"
|
||||
:items="indexList"
|
||||
:items="items"
|
||||
item-text="name"
|
||||
item-value="index"
|
||||
item-value="value"
|
||||
item-disabled="disabled"
|
||||
dark
|
||||
color="accent"
|
||||
item-color="secondary"
|
||||
:disabled="disabled"
|
||||
:rules="rules"
|
||||
@change="$emit('rollback', localValue)"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TooltippedLabel from "./cv-tooltipped-label";
|
||||
|
||||
export default {
|
||||
name: 'Select',
|
||||
components: {
|
||||
TooltippedLabel,
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['list', 'name', 'value', 'disabled', 'filteredIndices', 'selectCols', 'rules', 'tooltip'],
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
indexList() {
|
||||
let list = [];
|
||||
for (let i = 0; i < this.list.length; i++) {
|
||||
if (this.filteredIndices instanceof Set && this.filteredIndices.has(i)) continue;
|
||||
list.push({
|
||||
name: this.list[i],
|
||||
index: i
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
@@ -1,18 +1,48 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import TooltippedLabel from "@/components/common/cv-tooltipped-label.vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string,
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: number,
|
||||
min: number,
|
||||
max: number,
|
||||
step?: number
|
||||
disabled?: boolean,
|
||||
sliderCols?: number,
|
||||
}>(), {
|
||||
step: 1,
|
||||
disabled: false,
|
||||
sliderCols: 8
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: number): void
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
get: () => props.value,
|
||||
set: v => emit("input", v)
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
dense
|
||||
align="center"
|
||||
>
|
||||
<v-col :cols="12 - (sliderCols || 8)">
|
||||
<v-col :cols="12 - sliderCols">
|
||||
<tooltipped-label
|
||||
:tooltip="tooltip"
|
||||
:text="name"
|
||||
:label="label"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col :cols="sliderCols || 8">
|
||||
<v-col :cols="sliderCols">
|
||||
<v-slider
|
||||
:value="localValue"
|
||||
v-model="localValue"
|
||||
dark
|
||||
class="align-center"
|
||||
:max="max"
|
||||
@@ -21,29 +51,21 @@
|
||||
color="accent"
|
||||
:disabled="disabled"
|
||||
:step="step"
|
||||
@start="isClicked = true"
|
||||
@end="isClicked = false"
|
||||
@change="handleClick"
|
||||
@input="handleInput"
|
||||
@mousedown="$emit('rollback', localValue)"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<template #append>
|
||||
<v-text-field
|
||||
v-model="localValue"
|
||||
dark
|
||||
color="accent"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:disabled="disabled"
|
||||
:value="localValue"
|
||||
class="mt-0 pt-0"
|
||||
hide-details
|
||||
single-line
|
||||
type="number"
|
||||
style="width: 50px"
|
||||
:step="step"
|
||||
@input="handleChange"
|
||||
@focus="isFocused = true"
|
||||
@blur="isFocused = false"
|
||||
/>
|
||||
</template>
|
||||
</v-slider>
|
||||
@@ -51,58 +73,3 @@
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TooltippedLabel from "./cv-tooltipped-label";
|
||||
|
||||
export default {
|
||||
name: "Slider",
|
||||
components: {
|
||||
TooltippedLabel,
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ["min", "max", "name", "value", "step", "sliderCols", "disabled", "tooltip"],
|
||||
data() {
|
||||
return {
|
||||
isFocused: false,
|
||||
isClicked: false,
|
||||
currentBoxVal: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("input", value);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleChange(val) {
|
||||
this.currentBoxVal = val;
|
||||
setTimeout(() => {
|
||||
if (this.currentBoxVal !== val) return;
|
||||
// if (this.isFocused) {
|
||||
this.localValue = parseFloat(val);
|
||||
this.$emit("rollback", this.localValue);
|
||||
// }
|
||||
}, 200);
|
||||
},
|
||||
handleInput(val) {
|
||||
if (!this.isFocused && this.isClicked) {
|
||||
this.localValue = val;
|
||||
}
|
||||
},
|
||||
handleClick(val) {
|
||||
if (!this.isFocused) {
|
||||
this.localValue = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="" scoped>
|
||||
</style>
|
||||
|
||||
@@ -1,51 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import TooltippedLabel from "@/components/common/cv-tooltipped-label.vue";
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string,
|
||||
// TODO fully update v-model usage in custom components on Vue3 update
|
||||
value: boolean,
|
||||
disabled?: boolean,
|
||||
labelCols?: number,
|
||||
switchCols?: number
|
||||
}>(), {
|
||||
disabled: false,
|
||||
labelCols: 2
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "input", value: boolean): void
|
||||
}>();
|
||||
|
||||
const localValue = computed({
|
||||
get: () => props.value,
|
||||
set: v => emit("input", v)
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
dense
|
||||
align="center"
|
||||
>
|
||||
<v-col :cols="textCols || 2">
|
||||
<v-col :cols="(12 - switchCols) || labelCols">
|
||||
<tooltipped-label
|
||||
:tooltip="tooltip"
|
||||
:text="name"
|
||||
:label="label"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col :cols="12 - (textCols || 2)">
|
||||
<v-col :cols="switchCols || (12 - labelCols)">
|
||||
<v-switch
|
||||
v-model="localValue"
|
||||
dark
|
||||
:disabled="disabled"
|
||||
color="#ffd843"
|
||||
@change="$emit('rollback', localValue)"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TooltippedLabel from "./cv-tooltipped-label";
|
||||
|
||||
export default {
|
||||
name: 'CVSwitch',
|
||||
components: {
|
||||
TooltippedLabel,
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['name', 'value', 'disabled', 'textCols', 'tooltip'],
|
||||
computed: {
|
||||
localValue: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
label?: string,
|
||||
tooltip?: string
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-tooltip
|
||||
@@ -5,23 +12,15 @@
|
||||
right
|
||||
open-delay="300"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<template #activator="{ on, attrs }">
|
||||
<span
|
||||
style="cursor: text !important;"
|
||||
class="white--text"
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
>{{ text }}</span>
|
||||
>{{ label }}</span>
|
||||
</template>
|
||||
<span>{{ tooltip }}</span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TooltippedLabel',
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['text', 'tooltip'],
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user