replace bootstrap-vue progress bar with vue-slider-component
better hit area, drag support
This commit is contained in:
parent
e1dc32060b
commit
73b2b493a4
@ -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))
|
||||
},
|
||||
|
62
src/player/ProgressBar.vue
Normal file
62
src/player/ProgressBar.vue
Normal 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>
|
@ -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 }) {
|
||||
|
@ -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">
|
||||
|
@ -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
15
src/style/_variables.scss
Normal 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;
|
@ -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};
|
||||
|
Loading…
x
Reference in New Issue
Block a user