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