mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-04-30 01:15:24 +02:00
Use the proper multiplication symbol for the playback speed. The order of the number and symbol is reversed so it is read "times 1.0" instead of "1.0 times" (or previously "1.0 x"). Between the symbol and the number, a narrow no-break space ( ) is added for proper spacing. The classes of some spans are removed for better alignment.
124 lines
4.3 KiB
Vue
124 lines
4.3 KiB
Vue
<template>
|
||
<div ref="wrapper" class="relative ml-4 sm:ml-8" v-click-outside="clickOutside">
|
||
<div class="flex items-center justify-center text-gray-300 cursor-pointer h-full" @mousedown.prevent @mouseup.prevent @click="setShowMenu(true)">
|
||
<span class="text-gray-200 text-sm sm:text-base">× {{ playbackRateDisplay }}</span>
|
||
</div>
|
||
<div v-show="showMenu" class="absolute -top-[5.5rem] z-20 bg-bg border-black-200 border shadow-xl rounded-lg" :style="{ left: menuLeft + 'px' }">
|
||
<div class="absolute -bottom-1.5 right-0 w-full flex justify-center" :style="{ left: arrowLeft + 'px' }">
|
||
<div class="arrow-down" />
|
||
</div>
|
||
<div class="flex items-center h-9 relative overflow-hidden rounded-lg" style="width: 220px">
|
||
<template v-for="rate in rates">
|
||
<div :key="rate" class="h-full border-black-300 w-11 cursor-pointer border rounded-sm" :class="value === rate ? 'bg-black-100' : 'hover:bg-black hover:bg-opacity-10'" style="min-width: 44px; max-width: 44px" @click="set(rate)">
|
||
<div class="w-full h-full flex justify-center items-center">
|
||
<p class="text-xs text-center">× {{ rate }}</p>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
<div class="w-full py-1 px-1">
|
||
<div class="flex items-center justify-between">
|
||
<ui-icon-btn :disabled="!canDecrement" icon="remove" @click="decrement" />
|
||
<p class="px-2 text-2xl sm:text-3xl"><span class="text-2xl">× </span>{{ playbackRateDisplay }}</p>
|
||
<ui-icon-btn :disabled="!canIncrement" icon="add" @click="increment" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
props: {
|
||
value: {
|
||
type: [String, Number],
|
||
default: 1
|
||
},
|
||
playbackRateIncrementDecrement: {
|
||
type: Number,
|
||
default: 0.1
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
showMenu: false,
|
||
currentPlaybackRate: 0,
|
||
MIN_SPEED: 0.5,
|
||
MAX_SPEED: 10,
|
||
menuLeft: -96,
|
||
arrowLeft: 0
|
||
}
|
||
},
|
||
computed: {
|
||
playbackRate: {
|
||
get() {
|
||
return this.value
|
||
},
|
||
set(val) {
|
||
this.$emit('input', val)
|
||
}
|
||
},
|
||
rates() {
|
||
return [0.5, 1, 1.2, 1.5, 2]
|
||
},
|
||
canIncrement() {
|
||
return this.playbackRate + this.playbackRateIncrementDecrement <= this.MAX_SPEED
|
||
},
|
||
canDecrement() {
|
||
return this.playbackRate - this.playbackRateIncrementDecrement >= this.MIN_SPEED
|
||
},
|
||
playbackRateDisplay() {
|
||
if (this.playbackRateIncrementDecrement == 0.05) return this.playbackRate.toFixed(2)
|
||
// For 0.1 increment: Only show 2 decimal places if the playback rate is 2 decimals
|
||
const numDecimals = String(this.playbackRate).split('.')[1]?.length || 0
|
||
if (numDecimals <= 1) return this.playbackRate.toFixed(1)
|
||
return this.playbackRate.toFixed(2)
|
||
}
|
||
},
|
||
methods: {
|
||
clickOutside() {
|
||
this.setShowMenu(false)
|
||
},
|
||
set(rate) {
|
||
this.playbackRate = Number(rate)
|
||
this.$nextTick(() => this.setShowMenu(false))
|
||
},
|
||
increment() {
|
||
if (this.playbackRate + this.playbackRateIncrementDecrement > this.MAX_SPEED) return
|
||
var newPlaybackRate = this.playbackRate + this.playbackRateIncrementDecrement
|
||
this.playbackRate = Number(newPlaybackRate.toFixed(2))
|
||
},
|
||
decrement() {
|
||
if (this.playbackRate - this.playbackRateIncrementDecrement < this.MIN_SPEED) return
|
||
var newPlaybackRate = this.playbackRate - this.playbackRateIncrementDecrement
|
||
this.playbackRate = Number(newPlaybackRate.toFixed(2))
|
||
},
|
||
updateMenuPositions() {
|
||
if (!this.$refs.wrapper) return
|
||
const boundingBox = this.$refs.wrapper.getBoundingClientRect()
|
||
|
||
if (boundingBox.left + 110 > window.innerWidth - 10) {
|
||
this.menuLeft = window.innerWidth - 230 - boundingBox.left
|
||
|
||
this.arrowLeft = Math.abs(this.menuLeft) - 96
|
||
} else {
|
||
this.menuLeft = -96
|
||
this.arrowLeft = 0
|
||
}
|
||
},
|
||
setShowMenu(val) {
|
||
if (val) {
|
||
this.updateMenuPositions()
|
||
this.currentPlaybackRate = this.playbackRate
|
||
} else if (this.currentPlaybackRate !== this.playbackRate) {
|
||
this.$emit('change', this.playbackRate)
|
||
}
|
||
this.showMenu = val
|
||
}
|
||
},
|
||
mounted() {
|
||
this.currentPlaybackRate = this.playbackRate
|
||
}
|
||
}
|
||
</script>
|