replace bootstrap-vue progress bar with vue-slider-component

better hit area, drag support
This commit is contained in:
Thomas Amland 2021-07-17 13:25:05 +02:00
parent e1dc32060b
commit 73b2b493a4
7 changed files with 118 additions and 46 deletions

View File

@ -2,10 +2,11 @@
<div :class="{'visible': visible}" class="player elevated d-flex">
<div class="flex-fill">
<!-- Progress --->
<div class="progress2" @click="seek">
<b-progress :value="progress" :max="100" height="4px" />
</div>
<div class="row align-items-center m-0">
<ProgressBar
style="margin-bottom: -5px; margin-top: -9px"
:value="progress" @input="seek"
/>
<div class="row align-items-center m-0" style="padding-top: -10px">
<!-- Track info --->
<div class="col p-0 d-flex flex-nowrap align-items-center justify-content-start" style="width: 0; min-width: 0">
<template v-if="track">
@ -96,9 +97,6 @@
</div>
</template>
<style scoped>
.progress2 {
cursor: pointer;
}
.player {
position: fixed;
bottom: 0;
@ -120,8 +118,12 @@
<script lang="ts">
import Vue from 'vue'
import { mapState, mapGetters, mapActions } from 'vuex'
import ProgressBar from '@/player/ProgressBar.vue'
export default Vue.extend({
components: {
ProgressBar,
},
computed: {
...mapState('player', {
isPlaying: (state: any) => state.isPlaying,
@ -154,14 +156,8 @@
'toggleRepeat',
'toggleShuffle',
'toggleMute',
'seek',
]),
seek(event: any) {
if (event.target) {
const width = event.currentTarget.clientWidth
const value = event.offsetX / width
return this.$store.dispatch('player/seek', value)
}
},
setVolume(volume: any) {
return this.$store.dispatch('player/setVolume', parseFloat(volume))
},

View File

@ -0,0 +1,62 @@
<template>
<VueSlider
v-bind="$attrs"
:value="value"
:min="0"
:max="100"
:interval="0.001"
:lazy="true"
:contained="true"
:dot-options="{tooltip: 'none'}"
@change="onInput"
/>
</template>
<style lang="scss" scoped>
@import '/src/style/variables';
@import '~vue-slider-component/theme/material.css';
.vue-slider {
height: 4px !important;
padding: 5px 0 !important;
cursor: pointer;
}
::v-deep .vue-slider-rail {
background-color: $secondary;
border-radius: 0;
}
::v-deep .vue-slider-process {
background-color: $primary;
border-radius: 0;
}
::v-deep .vue-slider-dot-handle {
background-color: $primary;
}
::v-deep .vue-slider-dot-handle::after {
background-color: rgba($primary, 0.32);
transform: translate(-50%, -50%) scale(1);
}
.vue-slider:not(:hover) ::v-deep .vue-slider-dot-handle {
display: none;
}
.vue-slider:hover ::v-deep .vue-slider-dot-handle {
display: block;
}
</style>
<script lang="ts">
import Vue from 'vue'
import VueSlider from 'vue-slider-component'
export default Vue.extend({
components: {
VueSlider,
},
props: {
value: { type: Number, required: true },
},
methods: {
onInput(value: number) {
this.$emit('input', value)
},
}
})
</script>

View File

@ -187,7 +187,7 @@ export const playerModule: Module<State, any> = {
},
seek({ state }, value) {
if (isFinite(state.duration)) {
audio.seek(state.duration * value)
audio.seek(state.duration * (value / 100.0))
}
},
async resetQueue({ commit, getters }) {

View File

@ -9,20 +9,38 @@
@change="onInput"
/>
</template>
<style>
@import '~vue-slider-component/theme/default.css';
.vue-slider-rail {
background-color: var(--secondary) !important;
<style lang="scss" scoped>
@import '/src/style/_variables';
@import '~vue-slider-component/theme/material.css';
.vue-slider {
cursor: pointer;
}
.vue-slider-process {
background-color: var(--primary) !important;
::v-deep .vue-slider-rail {
background-color: $secondary;
border-radius: 0;
}
.vue-slider-dot-tooltip-inner {
background-color: var(--primary);
border-color: var(--primary);
::v-deep .vue-slider-process {
background-color: $primary;
border-radius: 0;
}
.vue-slider-dot-handle {
background-color: var(--text-body);
::v-deep .vue-slider-dot-handle {
background-color: $primary;
}
::v-deep .vue-slider-dot-handle::after {
background-color: rgba($primary, 0.32);
transform: translate(-50%, -50%) scale(1);
}
::v-deep .vue-slider-dot-handle:hover .vue-slider-dot-tooltip {
visibility: visible;
}
::v-deep .vue-slider-dot-tooltip-inner {
background-color: $primary;
border-color: $primary;
}
::v-deep .vue-slider-dot-tooltip-text {
width: 40px;
height: 40px;
}
</style>
<script lang="ts">

View File

@ -18,7 +18,6 @@ import {
BModal,
BOverlay,
BPopover,
BProgress,
BSidebar,
DropdownPlugin,
} from 'bootstrap-vue'
@ -33,7 +32,6 @@ Vue.component('BFormCheckbox', BFormCheckbox)
Vue.component('BFormTextarea', BFormTextarea)
Vue.component('BButton', BButton)
Vue.component('BPopover', BPopover)
Vue.component('BProgress', BProgress)
Vue.component('BOverlay', BOverlay)
Vue.use(DropdownPlugin)

15
src/style/_variables.scss Normal file
View File

@ -0,0 +1,15 @@
$theme-elevation-0: hsl(0, 0%, 0%);
$theme-elevation-1: hsl(0, 0%, 10%);
$theme-elevation-2: hsl(0, 0%, 20%);
$theme-text: #ccc;
$theme-text-muted: #999;
$primary: #09f;
$danger: #ff4141;
$secondary: $theme-elevation-2;
$body-bg: $theme-elevation-0;
$body-color: $theme-text;
$link-color: $theme-text;
$text-muted: $theme-text-muted;
$border-color: $theme-elevation-2;

View File

@ -1,18 +1,4 @@
$theme-elevation-0: hsl(0, 0%, 0%);
$theme-elevation-1: hsl(0, 0%, 10%);
$theme-elevation-2: hsl(0, 0%, 20%);
$theme-text: #ccc;
$theme-text-muted: #999;
$primary: #09f;
$danger: #ff4141;
$secondary: $theme-elevation-2;
$body-bg: $theme-elevation-0;
$body-color: $theme-text;
$link-color: $theme-text;
$text-muted: $theme-text-muted;
$border-color: $theme-elevation-2;
@import "./variables";
// Card
$card-bg: $theme-elevation-1;
@ -42,9 +28,6 @@ $custom-range-track-height: 0.1rem;
$custom-range-thumb-bg: $theme-text;
$custom-range-track-bg: $theme-text-muted;
// Other
$progress-bg: rgb(35, 35, 35);
:root {
--text-body: #{$theme-text};
--text-muted: #{$theme-text-muted};