adminforth 2.26.0-next.31 → 2.26.0-next.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
>
|
|
20
20
|
|
|
21
21
|
<div v-if="min && max" class="w-full px-2.5">
|
|
22
|
-
<
|
|
23
|
-
class="custom-slider"
|
|
22
|
+
<RangePicker
|
|
24
23
|
:dot-size="20"
|
|
25
24
|
height="7.99px"
|
|
26
25
|
:min="minFormatted"
|
|
@@ -32,10 +31,9 @@
|
|
|
32
31
|
</div>
|
|
33
32
|
</template>
|
|
34
33
|
<script setup lang="ts">
|
|
35
|
-
import VueSlider from 'vue-slider-component';
|
|
36
|
-
import 'vue-slider-component/theme/antd.css'
|
|
37
34
|
import {computed, onMounted, ref, watch} from "vue";
|
|
38
35
|
import debounce from 'debounce'
|
|
36
|
+
import RangePicker from './RangePicker.vue';
|
|
39
37
|
|
|
40
38
|
const props = defineProps({
|
|
41
39
|
valueStart: {
|
|
@@ -57,7 +55,19 @@ const maxFormatted = computed(() => Math.ceil(<number>props.max));
|
|
|
57
55
|
const start = ref<string | number>(props.valueStart);
|
|
58
56
|
const end = ref<string | number>(props.valueEnd);
|
|
59
57
|
|
|
60
|
-
const sliderValue = ref([minFormatted.value, maxFormatted.value]);
|
|
58
|
+
const sliderValue = ref<[number, number]>([minFormatted.value, maxFormatted.value]);
|
|
59
|
+
|
|
60
|
+
watch([start, end], () => {
|
|
61
|
+
if ( !start.value && end.value ) {
|
|
62
|
+
setSliderValues(minFormatted.value, end.value);
|
|
63
|
+
} else if ( start.value && !end.value ) {
|
|
64
|
+
setSliderValues(start.value, maxFormatted.value);
|
|
65
|
+
} else if ( !start.value && !end.value ) {
|
|
66
|
+
setSliderValues(minFormatted.value, maxFormatted.value);
|
|
67
|
+
} else {
|
|
68
|
+
setSliderValues(start.value, end.value);
|
|
69
|
+
}
|
|
70
|
+
})
|
|
61
71
|
|
|
62
72
|
const updateFromSlider =
|
|
63
73
|
debounce((value: [number, number]) => {
|
|
@@ -111,65 +121,4 @@ watch([minFormatted,maxFormatted], () => {
|
|
|
111
121
|
function setSliderValues(start: any, end: any) {
|
|
112
122
|
sliderValue.value = [start || minFormatted.value, end || maxFormatted.value];
|
|
113
123
|
}
|
|
114
|
-
</script>
|
|
115
|
-
|
|
116
|
-
<style lang="scss" scoped>
|
|
117
|
-
.custom-slider {
|
|
118
|
-
&:deep(.vue-slider-rail) {
|
|
119
|
-
background-color: rgb(229 231 235);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
&:deep(.vue-slider-dot-handle) {
|
|
123
|
-
// apply bg-blue-500 to the handle when active
|
|
124
|
-
@apply bg-lightPrimary;
|
|
125
|
-
border: none;
|
|
126
|
-
box-shadow: none;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
&:deep(.vue-slider-dot-handle:hover) {
|
|
130
|
-
@apply bg-lightPrimary;
|
|
131
|
-
filter: brightness(1.1);
|
|
132
|
-
border: none;
|
|
133
|
-
box-shadow: none;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
&:deep(.vue-slider-process) {
|
|
137
|
-
@apply bg-lightPrimaryOpacity;
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
&:deep(.vue-slider-process:hover) {
|
|
142
|
-
filter: brightness(1.1);
|
|
143
|
-
@apply bg-lightPrimaryOpacity;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
.dark .custom-slider {
|
|
148
|
-
&:deep(.vue-slider-rail) {
|
|
149
|
-
background-color: rgb(55 65 81); // gray-700
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
&:deep(.vue-slider-dot-handle) {
|
|
153
|
-
@apply bg-darkPrimary;
|
|
154
|
-
border: none;
|
|
155
|
-
box-shadow: none;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
&:deep(.vue-slider-dot-handle:hover) {
|
|
159
|
-
@apply bg-darkPrimary;
|
|
160
|
-
filter: brightness(1.1);
|
|
161
|
-
border: none;
|
|
162
|
-
box-shadow: none;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
&:deep(.vue-slider-process) {
|
|
166
|
-
@apply bg-darkPrimaryOpacity;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
&:deep(.vue-slider-process:hover) {
|
|
170
|
-
filter: brightness(1.1);
|
|
171
|
-
@apply bg-darkPrimaryOpacity;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
</style>
|
|
124
|
+
</script>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="range-slider" ref="trackRef" @mousedown="onTrackMouseDown">
|
|
3
|
+
<div class="track"></div>
|
|
4
|
+
<div class="range bg-lightPrimary/30" :style="rangeStyle"></div>
|
|
5
|
+
|
|
6
|
+
<div
|
|
7
|
+
class="bg-lightPrimary thumb"
|
|
8
|
+
:style="minThumbStyle"
|
|
9
|
+
@mousedown.stop.prevent="startDrag('min', $event)"
|
|
10
|
+
@mouseenter="minHovered = true"
|
|
11
|
+
@mouseleave="minHovered = false"
|
|
12
|
+
></div>
|
|
13
|
+
<div v-if="minHovered || activeThumb === 'min'" class="thumb-tooltip" :style="minTooltipStyle">{{ minVal }}</div>
|
|
14
|
+
|
|
15
|
+
<div
|
|
16
|
+
class="bg-lightPrimary thumb"
|
|
17
|
+
:style="maxThumbStyle"
|
|
18
|
+
@mousedown.stop.prevent="startDrag('max', $event)"
|
|
19
|
+
@mouseenter="maxHovered = true"
|
|
20
|
+
@mouseleave="maxHovered = false"
|
|
21
|
+
></div>
|
|
22
|
+
<div v-if="maxHovered || activeThumb === 'max'" class="thumb-tooltip" :style="maxTooltipStyle">{{ maxVal }}</div>
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup lang="ts">
|
|
28
|
+
import { computed, ref, watch, onBeforeUnmount } from 'vue'
|
|
29
|
+
|
|
30
|
+
const props = defineProps({
|
|
31
|
+
modelValue: {
|
|
32
|
+
type: Array as unknown as () => [number, number],
|
|
33
|
+
default: () => [0, 100]
|
|
34
|
+
},
|
|
35
|
+
min: { type: Number, default: 0 },
|
|
36
|
+
max: { type: Number, default: 100 },
|
|
37
|
+
dotSize: { type: Number, default: 20 },
|
|
38
|
+
height: { type: String, default: '8px' }
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const emit = defineEmits(['update:modelValue'])
|
|
42
|
+
|
|
43
|
+
const trackRef = ref<HTMLElement | null>(null)
|
|
44
|
+
|
|
45
|
+
const minVal = ref(props.modelValue[0])
|
|
46
|
+
const maxVal = ref(props.modelValue[1])
|
|
47
|
+
|
|
48
|
+
watch(() => props.modelValue, (val) => {
|
|
49
|
+
if (!val) return
|
|
50
|
+
minVal.value = val[0]
|
|
51
|
+
maxVal.value = val[1]
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
function clamp(val: number) {
|
|
55
|
+
return Math.min(props.max, Math.max(props.min, val))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function valueToPercent(val: number) {
|
|
59
|
+
return ((val - props.min) / (props.max - props.min)) * 100
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function percentToValue(percent: number) {
|
|
63
|
+
return props.min + ((props.max - props.min) * percent) / 100
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const minPercent = computed(() => valueToPercent(minVal.value))
|
|
67
|
+
const maxPercent = computed(() => valueToPercent(maxVal.value))
|
|
68
|
+
|
|
69
|
+
const rangeStyle = computed(() => ({
|
|
70
|
+
left: `${minPercent.value}%`,
|
|
71
|
+
width: `${maxPercent.value - minPercent.value}%`,
|
|
72
|
+
transition: isAnimating.value ? 'left 0.18s ease, width 0.18s ease' : 'none'
|
|
73
|
+
}))
|
|
74
|
+
|
|
75
|
+
const minThumbStyle = computed(() => ({
|
|
76
|
+
left: `calc(${minPercent.value}% - ${props.dotSize / 2}px)`,
|
|
77
|
+
width: `${props.dotSize}px`,
|
|
78
|
+
height: `${props.dotSize}px`,
|
|
79
|
+
transition: isAnimating.value ? 'left 0.18s ease' : 'none',
|
|
80
|
+
zIndex: activeThumb.value === 'min' ? 3 : 2
|
|
81
|
+
}))
|
|
82
|
+
|
|
83
|
+
const maxThumbStyle = computed(() => ({
|
|
84
|
+
left: `calc(${maxPercent.value}% - ${props.dotSize / 2}px)`,
|
|
85
|
+
width: `${props.dotSize}px`,
|
|
86
|
+
height: `${props.dotSize}px`,
|
|
87
|
+
transition: isAnimating.value ? 'left 0.18s ease' : 'none',
|
|
88
|
+
zIndex: activeThumb.value === 'max' ? 3 : 2
|
|
89
|
+
}))
|
|
90
|
+
|
|
91
|
+
const minTooltipStyle = computed(() => ({
|
|
92
|
+
left: `${minPercent.value}%`,
|
|
93
|
+
transition: isAnimating.value ? 'left 0.18s ease' : 'none'
|
|
94
|
+
}))
|
|
95
|
+
|
|
96
|
+
const maxTooltipStyle = computed(() => ({
|
|
97
|
+
left: `${maxPercent.value}%`,
|
|
98
|
+
transition: isAnimating.value ? 'left 0.18s ease' : 'none'
|
|
99
|
+
}))
|
|
100
|
+
|
|
101
|
+
const activeThumb = ref<'min' | 'max' | null>(null)
|
|
102
|
+
const isAnimating = ref(false)
|
|
103
|
+
const minHovered = ref(false)
|
|
104
|
+
const maxHovered = ref(false)
|
|
105
|
+
|
|
106
|
+
function startDrag(type: 'min' | 'max', e: MouseEvent) {
|
|
107
|
+
activeThumb.value = type
|
|
108
|
+
document.addEventListener('mousemove', onMouseMove)
|
|
109
|
+
document.addEventListener('mouseup', stopDrag)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function onMouseMove(e: MouseEvent) {
|
|
113
|
+
if (!trackRef.value || !activeThumb.value) return
|
|
114
|
+
|
|
115
|
+
const rect = trackRef.value.getBoundingClientRect()
|
|
116
|
+
const percent = ((e.clientX - rect.left) / rect.width) * 100
|
|
117
|
+
const value = Math.round(clamp(percentToValue(percent)))
|
|
118
|
+
|
|
119
|
+
if (activeThumb.value === 'min') {
|
|
120
|
+
if (value > maxVal.value) {
|
|
121
|
+
// cross over: become the max thumb
|
|
122
|
+
minVal.value = maxVal.value
|
|
123
|
+
maxVal.value = value
|
|
124
|
+
activeThumb.value = 'max'
|
|
125
|
+
} else {
|
|
126
|
+
minVal.value = value
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
if (value < minVal.value) {
|
|
130
|
+
// cross over: become the min thumb
|
|
131
|
+
maxVal.value = minVal.value
|
|
132
|
+
minVal.value = value
|
|
133
|
+
activeThumb.value = 'min'
|
|
134
|
+
} else {
|
|
135
|
+
maxVal.value = value
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
emit('update:modelValue', [minVal.value, maxVal.value])
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function stopDrag() {
|
|
143
|
+
document.removeEventListener('mousemove', onMouseMove)
|
|
144
|
+
document.removeEventListener('mouseup', stopDrag)
|
|
145
|
+
activeThumb.value = null
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function onTrackMouseDown(e: MouseEvent) {
|
|
149
|
+
if (!trackRef.value) return
|
|
150
|
+
|
|
151
|
+
const rect = trackRef.value.getBoundingClientRect()
|
|
152
|
+
const percent = ((e.clientX - rect.left) / rect.width) * 100
|
|
153
|
+
const value = percentToValue(percent)
|
|
154
|
+
|
|
155
|
+
const distToMin = Math.abs(value - minVal.value)
|
|
156
|
+
const distToMax = Math.abs(value - maxVal.value)
|
|
157
|
+
|
|
158
|
+
isAnimating.value = true
|
|
159
|
+
if (distToMin < distToMax) {
|
|
160
|
+
minVal.value = Math.round(Math.min(clamp(value), maxVal.value))
|
|
161
|
+
} else {
|
|
162
|
+
maxVal.value = Math.round(Math.max(clamp(value), minVal.value))
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
emit('update:modelValue', [minVal.value, maxVal.value])
|
|
166
|
+
|
|
167
|
+
setTimeout(() => { isAnimating.value = false }, 200)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
onBeforeUnmount(() => {
|
|
171
|
+
stopDrag()
|
|
172
|
+
})
|
|
173
|
+
</script>
|
|
174
|
+
|
|
175
|
+
<style scoped>
|
|
176
|
+
.range-slider {
|
|
177
|
+
position: relative;
|
|
178
|
+
width: 100%;
|
|
179
|
+
height: 20px;
|
|
180
|
+
display: flex;
|
|
181
|
+
align-items: center;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.track {
|
|
185
|
+
position: absolute;
|
|
186
|
+
width: 100%;
|
|
187
|
+
height: 8px;
|
|
188
|
+
background: #e5e7eb;
|
|
189
|
+
border-radius: 9999px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.range {
|
|
193
|
+
position: absolute;
|
|
194
|
+
height: 8px;
|
|
195
|
+
border-radius: 9999px;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.thumb {
|
|
199
|
+
position: absolute;
|
|
200
|
+
top: 50%;
|
|
201
|
+
transform: translateY(-50%);
|
|
202
|
+
border-radius: 9999px;
|
|
203
|
+
cursor: pointer;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.thumb-tooltip {
|
|
207
|
+
position: absolute;
|
|
208
|
+
top: -28px;
|
|
209
|
+
transform: translateX(-50%);
|
|
210
|
+
background: rgba(0, 0, 0, 0.75);
|
|
211
|
+
color: #fff;
|
|
212
|
+
font-size: 14px;
|
|
213
|
+
font-weight: 500;
|
|
214
|
+
line-height: 1;
|
|
215
|
+
padding: 6px 6px;
|
|
216
|
+
border-radius: 4px;
|
|
217
|
+
white-space: nowrap;
|
|
218
|
+
pointer-events: none;
|
|
219
|
+
animation: tooltip-in 0.12s ease;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.thumb-tooltip::after {
|
|
223
|
+
content: '';
|
|
224
|
+
position: absolute;
|
|
225
|
+
top: 100%;
|
|
226
|
+
left: 50%;
|
|
227
|
+
transform: translateX(-50%);
|
|
228
|
+
border: 4px solid transparent;
|
|
229
|
+
border-top-color: rgba(0, 0, 0, 0.75);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@keyframes tooltip-in {
|
|
233
|
+
from { opacity: 0; transform: translateX(-50%) translateY(4px); }
|
|
234
|
+
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
|
235
|
+
}
|
|
236
|
+
</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adminforth",
|
|
3
|
-
"version": "2.26.0-next.
|
|
3
|
+
"version": "2.26.0-next.32",
|
|
4
4
|
"description": "OpenSource Vue3 powered forth-generation admin panel",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"filewatcher": "^3.0.1",
|
|
82
82
|
"fs-extra": "^11.2.0",
|
|
83
83
|
"fuse.js": "^7.0.0",
|
|
84
|
-
"handlebars": "^4.7.
|
|
84
|
+
"handlebars": "^4.7.9",
|
|
85
85
|
"inquirer": "^12.3.0",
|
|
86
86
|
"jiti": "^2.4.2",
|
|
87
87
|
"jsonwebtoken": "^9.0.2",
|