forked from platypush/platypush
[UI] Full restyle of Slider
component.
The component has been rewritten using only CSS 3 and no JS.
This commit is contained in:
parent
b785609eda
commit
80c2f0d8dd
10 changed files with 128 additions and 96 deletions
|
@ -67,7 +67,7 @@
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
<Slider :range="colorConverter.ranges.hue" :disabled="loading"
|
<Slider :range="colorConverter.ranges.hue" :disabled="loading"
|
||||||
:value="animations.color_transition.hue_step"
|
:value="animations.color_transition.hue_step"
|
||||||
@mouseup="animations.color_transition.hue_step = parseFloat($event.target.value)" />
|
@change="animations.color_transition.hue_step = parseFloat($event.target.value)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
<Slider :range="colorConverter.ranges.sat" :disabled="loading"
|
<Slider :range="colorConverter.ranges.sat" :disabled="loading"
|
||||||
:value="animations.color_transition.sat_step"
|
:value="animations.color_transition.sat_step"
|
||||||
@mouseup="animations.color_transition.sat_step = parseFloat($event.target.value)" />
|
@change="animations.color_transition.sat_step = parseFloat($event.target.value)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
<Slider :range="colorConverter.ranges.bri" :disabled="loading"
|
<Slider :range="colorConverter.ranges.bri" :disabled="loading"
|
||||||
:value="animations.color_transition.bri_step"
|
:value="animations.color_transition.bri_step"
|
||||||
@mouseup="animations.color_transition.bri_step = parseFloat($event.target.value)" />
|
@change="animations.color_transition.bri_step = parseFloat($event.target.value)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-11 control">
|
<div class="col-11 control">
|
||||||
<Slider :range="colorConverter.ranges.bri" :disabled="loading" :value="state.bri"
|
<Slider :range="colorConverter.ranges.bri" :disabled="loading" :value="state.bri"
|
||||||
@mouseup.stop="$emit(light ? 'set-light' : 'set-group', {brightness: parseInt($event.target.value)})" />
|
@change.stop="$emit(light ? 'set-light' : 'set-group', {brightness: parseInt($event.target.value)})" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-11 control">
|
<div class="col-11 control">
|
||||||
<Slider :range="colorConverter.ranges.ct" :disabled="loading" :value="state.ct"
|
<Slider :range="colorConverter.ranges.ct" :disabled="loading" :value="state.ct"
|
||||||
@mouseup.stop="$emit(light ? 'set-light' : 'set-group', {temperature: parseInt($event.target.value)})" />
|
@change.stop="$emit(light ? 'set-light' : 'set-group', {temperature: parseInt($event.target.value)})" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-s-8 col-m-10 time-bar">
|
<div class="col-s-8 col-m-10 time-bar">
|
||||||
<Slider :value="elapsed" :range="[0, duration]" :disabled="!duration || status.state === 'stop'"
|
<Slider :value="elapsed" :range="[0, duration]" :disabled="!duration || status.state === 'stop'"
|
||||||
@input="$emit('seek', $event.target.value)" />
|
@change="$emit('seek', $event.target.value)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-s-2 col-m-1 time">
|
<div class="col-s-2 col-m-1 time">
|
||||||
<span class="total-time"
|
<span class="total-time"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
<div class="col-11 volume-slider">
|
<div class="col-11 volume-slider">
|
||||||
<Slider :value="status.volume" :range="volumeRange" :disabled="status.volume == null"
|
<Slider :value="status.volume" :range="volumeRange" :disabled="status.volume == null"
|
||||||
@input="$emit('set-volume', $event.target.value)" />
|
@change="$emit('set-volume', $event.target.value)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -15,13 +15,9 @@
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:value="value"
|
:value="value"
|
||||||
ref="range"
|
ref="range"
|
||||||
@input.stop="onUpdate"
|
@input.stop="$emit('input', $event)"
|
||||||
@change.stop="onUpdate">
|
@change.stop="$emit('change', $event)">
|
||||||
|
|
||||||
<div class="track" :class="{'with-label': withLabel}">
|
|
||||||
<div class="track-inner" ref="track"></div>
|
|
||||||
</div>
|
|
||||||
<div class="thumb" ref="thumb"></div>
|
|
||||||
<span class="label" v-if="withLabel" v-text="value" ref="label"></span>
|
<span class="label" v-if="withLabel" v-text="value" ref="label"></span>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
@ -29,8 +25,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "Slider",
|
emits: ['input', 'change'],
|
||||||
emits: ['input', 'change', 'mouseup', 'mousedown', 'touchstart', 'touchend', 'keyup', 'keydown'],
|
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -61,41 +56,13 @@ export default {
|
||||||
default: false,
|
default: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
onUpdate(event) {
|
|
||||||
this.update(event.target.value)
|
|
||||||
this.$emit(event.type, {
|
|
||||||
...event,
|
|
||||||
target: {
|
|
||||||
...event.target,
|
|
||||||
value: this.$refs.range.value,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
update(value) {
|
|
||||||
const sliderWidth = this.$refs.range.clientWidth
|
|
||||||
const percent = (value - this.range[0]) / (this.range[1] - this.range[0])
|
|
||||||
const innerWidth = percent * sliderWidth
|
|
||||||
const thumb = this.$refs.thumb
|
|
||||||
|
|
||||||
thumb.style.left = `${innerWidth - thumb.clientWidth / 2}px`
|
|
||||||
this.$refs.thumb.style.transform = `translate(-${percent}%, -50%)`
|
|
||||||
this.$refs.track.style.width = `${innerWidth}px`
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
if (this.value != null)
|
|
||||||
this.update(this.value)
|
|
||||||
this.$watch(() => this.value, (newValue) => this.update(newValue))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$label-width: 3em;
|
$label-width: 3em;
|
||||||
|
$thumb-height: 1em;
|
||||||
|
$slider-height: 0.5em;
|
||||||
|
|
||||||
.slider-wrapper {
|
.slider-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -109,13 +76,114 @@ $label-width: 3em;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slider {
|
input.slider {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
background: none;
|
||||||
|
height: 1.5em;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 0.5em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0;
|
outline: none;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all ease 100ms;
|
||||||
|
@include appearance(none);
|
||||||
|
|
||||||
&::-ms-tooltip {
|
&:active {
|
||||||
display: none;
|
filter: brightness(80%);
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: saturate(130%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
filter: grayscale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chrome and friends */
|
||||||
|
&::-webkit-slider-runnable-track {
|
||||||
|
position: relative;
|
||||||
|
border-radius: $slider-height;
|
||||||
|
background: linear-gradient($slider-bg 0 0) scroll no-repeat center /
|
||||||
|
100% calc(#{$slider-height} + 1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-slider-runnable-track,
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
transition: all ease 100ms;
|
||||||
|
height: $thumb-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
--clip-top: calc((#{$thumb-height} - #{$slider-height}) * 0.5);
|
||||||
|
--clip-bottom: calc(#{$thumb-height} - var(--clip-top));
|
||||||
|
--clip-further: calc(100% + 1px);
|
||||||
|
|
||||||
|
width: $thumb-height;
|
||||||
|
background: $slider-progress-bg;
|
||||||
|
box-shadow: calc(-100vmax - #{$thumb-height} + 2.5px) #{$slider-height} #{$slider-height} 100vmax #{$slider-progress-bg};
|
||||||
|
border-radius: $thumb-height;
|
||||||
|
cursor: grab;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(130%) blur(1px);
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
clip-path: polygon(
|
||||||
|
100% -1px,
|
||||||
|
#{$slider-height} -1px,
|
||||||
|
0 var(--clip-top),
|
||||||
|
-100vmax var(--clip-top),
|
||||||
|
-100vmax var(--clip-bottom),
|
||||||
|
0 var(--clip-bottom),
|
||||||
|
#{$slider-height} 100%,
|
||||||
|
var(--clip-further) var(--clip-further)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox */
|
||||||
|
&::-moz-range-track {
|
||||||
|
background: $slider-bg;
|
||||||
|
position: relative;
|
||||||
|
height: $slider-height;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
box-shadow: inset 1px 0px 3px 0 $slider-track-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-moz-range-thumb {
|
||||||
|
$thumb-height: 1.125em;
|
||||||
|
width: $thumb-height;
|
||||||
|
height: $thumb-height;
|
||||||
|
position: relative;
|
||||||
|
background: $slider-thumb-bg;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: none;
|
||||||
|
cursor: grabbing;
|
||||||
|
transition: all ease 100ms;
|
||||||
|
@include appearance(none);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(130%) blur(1px);
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background: $slider-thumb-disabled-bg;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-moz-range-progress {
|
||||||
|
width: 100%;
|
||||||
|
height: $slider-height;
|
||||||
|
cursor: pointer;
|
||||||
|
background: $slider-progress-bg;
|
||||||
|
border-radius: 0.5em 0 0 0.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,10 +191,6 @@ $label-width: 3em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
&.with-label {
|
|
||||||
width: calc(100% - $label-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
@ -137,47 +201,15 @@ $label-width: 3em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.track {
|
|
||||||
width: 100%;
|
|
||||||
height: 0.75em;
|
|
||||||
background: $slider-bg;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
border-radius: 0.5em;
|
|
||||||
box-shadow: inset 1px 0px 3px 0 $slider-track-shadow;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
.track-inner {
|
|
||||||
width: 0;
|
|
||||||
height: 100%;
|
|
||||||
background: $slider-progress-bg;
|
|
||||||
border-radius: 0.5em 0 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.with-label {
|
|
||||||
width: calc(100% - $label-width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumb {
|
|
||||||
width: 1.25em;
|
|
||||||
height: 1.25em;
|
|
||||||
background: $slider-thumb-bg;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 0;
|
|
||||||
transform: translate(0%, -50%);
|
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: 1px 0px 2px 0 $slider-thumb-shadow;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
width: $label-width;
|
width: $label-width;
|
||||||
position: relative;
|
position: relative;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.with-label {
|
||||||
|
width: calc(100% - $label-width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
|
|
||||||
<div class="value">
|
<div class="value">
|
||||||
<Slider :value="audioVolume" :range="[0, 100]"
|
<Slider :value="audioVolume" :range="[0, 100]"
|
||||||
@input="onVolumeChange" />
|
@change="onVolumeChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<div class="input" v-if="value?.min != null && value?.max != null">
|
<div class="input" v-if="value?.min != null && value?.max != null">
|
||||||
<div class="col-10">
|
<div class="col-10">
|
||||||
<Slider :range="[value.min, value.max]" with-range
|
<Slider :range="[value.min, value.max]" with-range
|
||||||
:value="value.value" @input="setValue" />
|
:value="value.value" @change="setValue" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2 value">
|
<div class="col-2 value">
|
||||||
<input type="number" :value="value.value" @change="setValue">
|
<input type="number" :value="value.value" @change="setValue">
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<Slider :range="[value.brightness_min, value.brightness_max]"
|
<Slider :range="[value.brightness_min, value.brightness_max]"
|
||||||
:value="value.brightness" @input="setLight({brightness: $event.target.value})" />
|
:value="value.brightness" @change="setLight({brightness: $event.target.value})" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<Slider :range="[value.saturation_min, value.saturation_max]"
|
<Slider :range="[value.saturation_min, value.saturation_max]"
|
||||||
:value="value.saturation" @input="setLight({saturation: $event.target.value})" />
|
:value="value.saturation" @change="setLight({saturation: $event.target.value})" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<Slider :range="[value.temperature_min, value.temperature_max]"
|
<Slider :range="[value.temperature_min, value.temperature_max]"
|
||||||
:value="value.temperature" @input="setLight({temperature: $event.target.value})"/>
|
:value="value.temperature" @change="setLight({temperature: $event.target.value})"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<div class="col-s-12 col-m-9 controls">
|
<div class="col-s-12 col-m-9 controls">
|
||||||
<div class="col-10 slider-container">
|
<div class="col-10 slider-container">
|
||||||
<Slider :range="[0, 100]" :value="config.volume.percent"
|
<Slider :range="[0, 100]" :value="config.volume.percent"
|
||||||
@mouseup="$emit('volume-change', {host: server.name, client: id, volume: $event.target.value})" />
|
@change="$emit('volume-change', {host: server.name, client: id, volume: $event.target.value})" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-2 switch pull-right">
|
<div class="col-2 switch pull-right">
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<div :class="{'col-6': hasIcon, 'col-7': !hasIcon}" v-text="name" />
|
<div :class="{'col-6': hasIcon, 'col-7': !hasIcon}" v-text="name" />
|
||||||
<div class="col-5 slider-container">
|
<div class="col-5 slider-container">
|
||||||
<div class="slider">
|
<div class="slider">
|
||||||
<SliderElement :value="value" :range="[parseFloat(min), parseFloat(max)]" @mouseup="run" />
|
<SliderElement :value="value" :range="[parseFloat(min), parseFloat(max)]" @change="run" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue