Skip to content

Commit f7c7410

Browse files
committed
Add MonoSlicer internal component
1 parent 3c8344d commit f7c7410

File tree

1 file changed

+234
-0
lines changed

1 file changed

+234
-0
lines changed

src/atoms/MonoSlicer.vue

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
<script setup>
2+
import { computed } from "vue";
3+
import BaseIcon from "./BaseIcon.vue";
4+
5+
const props = defineProps({
6+
min: {
7+
type: Number,
8+
default: 0
9+
},
10+
max: {
11+
type: Number,
12+
default: 0
13+
},
14+
inputColor: {
15+
type: String,
16+
default: '#1A1A1A'
17+
},
18+
background: {
19+
type: String,
20+
default: '#FFFFFF'
21+
},
22+
borderColor: {
23+
type: String,
24+
default: '#FFFFFF'
25+
},
26+
selectColor: {
27+
type: String,
28+
default: '#4A4A4A'
29+
},
30+
textColor: {
31+
type: String,
32+
default: '#1A1A1A'
33+
},
34+
useResetSlot: {
35+
type: Boolean,
36+
default: false
37+
},
38+
value: {
39+
type: Number,
40+
default: 0
41+
},
42+
source: {
43+
type: Number,
44+
default: 0,
45+
}
46+
})
47+
48+
const slicerColor = computed(() => props.inputColor);
49+
const backgroundColor = computed(() => props.background);
50+
const selectColorOpaque = computed(() => `${props.selectColor}33`);
51+
const borderColor = computed(() => props.borderColor);
52+
53+
const emit = defineEmits(['update:value', 'reset']);
54+
55+
function reset() {
56+
emit('reset');
57+
}
58+
59+
const highlightStyle = computed(() => {
60+
const range = props.max - props.min;
61+
const startPercent = 0;
62+
const endPercent = ((props.value - props.min) / range) * 100;
63+
return {
64+
left: `${startPercent}%`,
65+
width: `${endPercent - startPercent}%`,
66+
background: props.selectColor
67+
};
68+
});
69+
70+
</script>
71+
72+
<template>
73+
<div data-html2canvas-ignore>
74+
<div v-if="value !== source" class="reset-wrapper">
75+
<button v-if="!useResetSlot" data-cy-reset tabindex="0" role="button" class="vue-data-ui-refresh-button"
76+
@click="reset">
77+
<BaseIcon name="refresh" :stroke="textColor" />
78+
</button>
79+
<slot v-else name="reset-action" :reset="reset" />
80+
</div>
81+
<div v-else class="reset-wrapper"/>
82+
<div class="mono-slicer">
83+
<div class="slider-track"></div>
84+
<div class="range-highlight" :style="highlightStyle"></div>
85+
<input type="range" :min="min" :max="max" :value="Number(value)" @input="emit('update:value', Number($event.target.value))" />
86+
</div>
87+
</div>
88+
</template>
89+
90+
<style scoped lang="scss">
91+
.mono-slicer {
92+
position: relative !important;
93+
width: calc(100% - 48px);
94+
height: 40px;
95+
margin: 0 auto;
96+
}
97+
98+
.reset-wrapper {
99+
display: flex;
100+
flex-direction: row;
101+
align-items: center;
102+
justify-content: center;
103+
padding: 0 24px;
104+
height: 40px;
105+
}
106+
107+
input[type="range"] {
108+
position: absolute;
109+
left: 0;
110+
width: 100%;
111+
appearance: none;
112+
background: transparent;
113+
pointer-events: none;
114+
z-index: 3;
115+
}
116+
117+
input[type="range"]::-webkit-slider-thumb {
118+
-webkit-appearance: none;
119+
pointer-events: auto;
120+
width: 20px;
121+
height: 20px;
122+
background-color: v-bind(slicerColor);
123+
border-radius: 50%;
124+
cursor: pointer;
125+
position: relative;
126+
z-index: 2;
127+
outline: 2px solid v-bind(borderColor);
128+
transition: all 0.2s ease-in-out;
129+
&:active,
130+
&:hover {
131+
box-shadow: 0 0 0 10px v-bind(selectColorOpaque);
132+
background-color: v-bind(selectColor);
133+
}
134+
}
135+
136+
input[type="range"]::-moz-range-thumb {
137+
pointer-events: auto;
138+
width: 20px;
139+
height: 20px;
140+
background-color: v-bind(slicerColor);
141+
border-radius: 50%;
142+
cursor: pointer;
143+
position: relative;
144+
z-index: 2;
145+
outline: 2px solid v-bind(borderColor);
146+
transition: all 0.2s ease-in-out;
147+
&:active,
148+
&:hover {
149+
box-shadow: 0 0 0 10px v-bind(selectColorOpaque);
150+
background-color: v-bind(selectColor);
151+
}
152+
}
153+
154+
input[type="range"]::-ms-thumb {
155+
pointer-events: auto;
156+
width: 20px;
157+
height: 20px;
158+
background-color: v-bind(slicerColor);
159+
border-radius: 50%;
160+
cursor: pointer;
161+
position: relative;
162+
z-index: 2;
163+
outline: 2px solid v-bind(borderColor);
164+
transition: all 0.2s ease-in-out;
165+
&:active,
166+
&:hover {
167+
box-shadow: 0 0 0 10px v-bind(selectColorOpaque);
168+
background-color: v-bind(selectColor);
169+
}
170+
}
171+
172+
.slider-track {
173+
position: absolute;
174+
width: 99%;
175+
height: 8px;
176+
border-radius: 4px;
177+
background: v-bind(backgroundColor);
178+
top: 8px;
179+
z-index: 1;
180+
left: 50%;
181+
transform: translateX(-50%);
182+
-webkit-transform: translateX(-50%);
183+
}
184+
185+
.range-highlight {
186+
position: absolute;
187+
height: 8px;
188+
top: 8px;
189+
z-index: 1;
190+
border-radius: 4px;
191+
}
192+
193+
.vue-data-ui-refresh-button {
194+
outline: none;
195+
border: none;
196+
background: transparent;
197+
height: 36px;
198+
width: 36px;
199+
display: flex;
200+
align-items: center;
201+
justify-content: center;
202+
border-radius: 50%;
203+
cursor: pointer;
204+
transition: transform 0.2s ease-in-out;
205+
transform-origin: center;
206+
&:focus {
207+
outline: 1px solid v-bind(slicerColor);
208+
}
209+
&:hover {
210+
transform: rotate(-90deg)
211+
}
212+
}
213+
214+
.vue-data-ui-slicer-labels {
215+
display: flex;
216+
flex-direction: row;
217+
align-items: center;
218+
padding: 0 24px;
219+
height: 40px;
220+
}
221+
222+
.vue-data-ui-slicer-label-left,
223+
.vue-data-ui-slicer-label-right {
224+
width: 100%;
225+
}
226+
227+
.vue-data-ui-slicer-label-left {
228+
text-align: left;
229+
}
230+
231+
.vue-data-ui-slicer-label-right {
232+
text-align: right;
233+
}
234+
</style>

0 commit comments

Comments
 (0)