2020-11-25 13:31:34 +01:00
|
|
|
<template>
|
2023-05-15 22:19:33 +02:00
|
|
|
<label class="timctyfi" :class="{ disabled, easing }">
|
2023-04-08 02:01:42 +02:00
|
|
|
<div class="label"><slot name="label"></slot></div>
|
|
|
|
<div v-adaptive-border class="body">
|
2023-05-15 22:19:33 +02:00
|
|
|
<div class="container">
|
|
|
|
<input
|
|
|
|
ref="inputEl"
|
|
|
|
type="range"
|
|
|
|
:min="min"
|
|
|
|
:max="max"
|
|
|
|
:step="step"
|
|
|
|
:list="id"
|
|
|
|
:value="modelValue"
|
|
|
|
:disabled="disabled"
|
|
|
|
v-on:change="(x) => onChange(x)"
|
|
|
|
@focus="tooltipShow"
|
|
|
|
@blur="tooltipHide"
|
2023-05-17 18:53:00 +02:00
|
|
|
@touchstart="tooltipShow"
|
|
|
|
@touchend="tooltipHide"
|
2023-05-15 22:19:33 +02:00
|
|
|
@mouseenter="tooltipShow"
|
|
|
|
@mouseleave="tooltipHide"
|
2023-05-17 05:31:13 +02:00
|
|
|
@input="(x) => (inputVal = x.target.value)"
|
2023-05-15 22:19:33 +02:00
|
|
|
/>
|
2023-05-17 05:31:13 +02:00
|
|
|
<datalist v-if="showTicks && steps" :id="id">
|
|
|
|
<option
|
2023-06-13 20:42:18 +02:00
|
|
|
v-for="i in steps"
|
|
|
|
:value="i + min"
|
|
|
|
:label="(i + min).toString()"
|
2023-05-15 22:19:33 +02:00
|
|
|
></option>
|
|
|
|
</datalist>
|
2021-11-28 12:07:37 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
2023-04-08 02:01:42 +02:00
|
|
|
<div class="caption"><slot name="caption"></slot></div>
|
2023-05-15 22:19:33 +02:00
|
|
|
</label>
|
2020-11-25 13:31:34 +01:00
|
|
|
</template>
|
|
|
|
|
2022-06-30 05:48:42 +02:00
|
|
|
<script lang="ts" setup>
|
2023-05-15 22:19:33 +02:00
|
|
|
import { ref, computed, defineAsyncComponent } from "vue";
|
2023-04-08 02:01:42 +02:00
|
|
|
import * as os from "@/os";
|
|
|
|
|
2023-05-15 22:19:33 +02:00
|
|
|
const id = os.getUniqueId();
|
|
|
|
|
2023-04-08 02:01:42 +02:00
|
|
|
const props = withDefaults(
|
|
|
|
defineProps<{
|
|
|
|
modelValue: number;
|
|
|
|
disabled?: boolean;
|
|
|
|
min: number;
|
|
|
|
max: number;
|
|
|
|
step?: number;
|
|
|
|
textConverter?: (value: number) => string;
|
|
|
|
showTicks?: boolean;
|
|
|
|
easing?: boolean;
|
|
|
|
}>(),
|
|
|
|
{
|
|
|
|
step: 1,
|
|
|
|
textConverter: (v) => v.toString(),
|
|
|
|
easing: false,
|
2023-07-06 03:28:27 +02:00
|
|
|
},
|
2023-04-08 02:01:42 +02:00
|
|
|
);
|
2022-06-30 05:48:42 +02:00
|
|
|
|
2023-05-15 22:19:33 +02:00
|
|
|
const inputEl = ref<HTMLElement>();
|
|
|
|
let inputVal = $ref(props.modelValue);
|
|
|
|
|
2022-06-30 05:48:42 +02:00
|
|
|
const emit = defineEmits<{
|
2023-04-08 02:01:42 +02:00
|
|
|
(ev: "update:modelValue", value: number): void;
|
2022-06-30 05:48:42 +02:00
|
|
|
}>();
|
|
|
|
|
|
|
|
const steps = computed(() => {
|
|
|
|
if (props.step) {
|
|
|
|
return (props.max - props.min) / props.step;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-05-15 22:19:33 +02:00
|
|
|
function onChange(x) {
|
|
|
|
emit("update:modelValue", inputVal);
|
|
|
|
}
|
2022-06-30 05:48:42 +02:00
|
|
|
|
2023-05-15 22:19:33 +02:00
|
|
|
const tooltipShowing = ref(false);
|
|
|
|
function tooltipShow() {
|
|
|
|
tooltipShowing.value = true;
|
2023-04-08 02:01:42 +02:00
|
|
|
os.popup(
|
|
|
|
defineAsyncComponent(() => import("@/components/MkTooltip.vue")),
|
|
|
|
{
|
|
|
|
showing: tooltipShowing,
|
|
|
|
text: computed(() => {
|
2023-05-15 22:19:33 +02:00
|
|
|
return props.textConverter(inputVal);
|
2023-04-08 02:01:42 +02:00
|
|
|
}),
|
2023-05-15 22:19:33 +02:00
|
|
|
targetElement: inputEl,
|
2023-04-08 02:01:42 +02:00
|
|
|
},
|
|
|
|
{},
|
2023-07-06 03:28:27 +02:00
|
|
|
"closed",
|
2023-04-08 02:01:42 +02:00
|
|
|
);
|
2023-05-15 22:19:33 +02:00
|
|
|
}
|
|
|
|
function tooltipHide() {
|
|
|
|
tooltipShowing.value = false;
|
|
|
|
}
|
2020-11-25 13:31:34 +01:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2021-11-28 12:07:37 +01:00
|
|
|
@use "sass:math";
|
|
|
|
|
2021-09-29 17:50:45 +02:00
|
|
|
.timctyfi {
|
2020-11-25 13:31:34 +01:00
|
|
|
position: relative;
|
|
|
|
|
2021-11-28 12:07:37 +01:00
|
|
|
> .label {
|
|
|
|
font-size: 0.85em;
|
|
|
|
padding: 0 0 8px 0;
|
|
|
|
user-select: none;
|
2020-11-25 13:31:34 +01:00
|
|
|
|
2021-11-28 12:07:37 +01:00
|
|
|
&:empty {
|
|
|
|
display: none;
|
|
|
|
}
|
2021-09-29 17:50:45 +02:00
|
|
|
}
|
2020-11-25 13:31:34 +01:00
|
|
|
|
2021-11-28 12:07:37 +01:00
|
|
|
> .caption {
|
|
|
|
font-size: 0.85em;
|
|
|
|
padding: 8px 0 0 0;
|
|
|
|
color: var(--fgTransparentWeak);
|
2020-11-25 13:31:34 +01:00
|
|
|
|
2021-11-28 12:07:37 +01:00
|
|
|
&:empty {
|
|
|
|
display: none;
|
2021-09-29 17:50:45 +02:00
|
|
|
}
|
2021-11-28 12:07:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$thumbHeight: 20px;
|
|
|
|
$thumbWidth: 20px;
|
|
|
|
|
|
|
|
> .body {
|
2022-06-28 11:41:37 +02:00
|
|
|
padding: 10px 12px;
|
2022-06-17 06:20:33 +02:00
|
|
|
background: var(--panel);
|
|
|
|
border: solid 1px var(--panel);
|
2021-11-28 12:07:37 +01:00
|
|
|
border-radius: 6px;
|
|
|
|
|
|
|
|
> .container {
|
|
|
|
position: relative;
|
|
|
|
height: $thumbHeight;
|
|
|
|
|
2023-05-15 22:19:33 +02:00
|
|
|
@mixin track {
|
2021-11-28 12:07:37 +01:00
|
|
|
height: 3px;
|
|
|
|
background: rgba(0, 0, 0, 0.1);
|
|
|
|
border-radius: 999px;
|
|
|
|
}
|
|
|
|
|
2023-05-15 22:19:33 +02:00
|
|
|
@mixin fill {
|
|
|
|
background-color: var(--accent);
|
2021-11-28 12:07:37 +01:00
|
|
|
}
|
|
|
|
|
2023-05-15 22:19:33 +02:00
|
|
|
@mixin thumb {
|
2021-11-28 12:07:37 +01:00
|
|
|
width: $thumbWidth;
|
|
|
|
height: $thumbHeight;
|
|
|
|
background: var(--accent);
|
|
|
|
border-radius: 999px;
|
2021-09-29 17:50:45 +02:00
|
|
|
|
2021-11-28 12:07:37 +01:00
|
|
|
&:hover {
|
|
|
|
background: var(--accentLighten);
|
|
|
|
}
|
|
|
|
}
|
2023-05-15 22:19:33 +02:00
|
|
|
> input {
|
|
|
|
width: 100%;
|
|
|
|
background: none;
|
|
|
|
|
2023-05-17 05:31:13 +02:00
|
|
|
&::-webkit-slider-runnable-track {
|
|
|
|
@include track;
|
|
|
|
}
|
|
|
|
&::-moz-range-track {
|
|
|
|
@include track;
|
|
|
|
}
|
|
|
|
&::-ms-track {
|
|
|
|
@include track;
|
|
|
|
}
|
2023-05-15 22:19:33 +02:00
|
|
|
|
2023-05-17 05:31:13 +02:00
|
|
|
&::-moz-range-progress {
|
|
|
|
@include fill;
|
|
|
|
}
|
|
|
|
&::-ms-fill-lower {
|
|
|
|
@include fill;
|
|
|
|
}
|
2023-05-15 22:19:33 +02:00
|
|
|
|
|
|
|
&::-webkit-slider-thumb {
|
|
|
|
margin-top: -6.5px;
|
2023-05-17 05:31:13 +02:00
|
|
|
@include thumb;
|
|
|
|
}
|
|
|
|
&::-moz-range-thumb {
|
|
|
|
@include thumb;
|
|
|
|
}
|
|
|
|
&::-ms-thumb {
|
|
|
|
@include thumb;
|
2023-05-15 22:19:33 +02:00
|
|
|
}
|
|
|
|
}
|
2020-11-25 13:31:34 +01:00
|
|
|
}
|
|
|
|
}
|
2022-09-10 09:28:59 +02:00
|
|
|
|
|
|
|
&.easing {
|
|
|
|
> .body {
|
|
|
|
> .container {
|
|
|
|
> .track {
|
|
|
|
> .highlight {
|
2023-04-08 02:01:42 +02:00
|
|
|
transition: width 0.2s cubic-bezier(0, 0, 0, 1);
|
2022-09-10 09:28:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
> .thumb {
|
2023-04-08 02:01:42 +02:00
|
|
|
transition: left 0.2s cubic-bezier(0, 0, 0, 1);
|
2022-09-10 09:28:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-25 13:31:34 +01:00
|
|
|
}
|
|
|
|
</style>
|