mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-07-02 13:34:53 +02:00
WIP: Add adjustable skip amount (#3113)
* Add playback settings string to en-us * Add playback settings UI for jump forwards and jump backwards * Remove jump forwards and jump backwards settings * Remove jump forwards and jump backwards en-us strings * Update player UI to include player settings button * Add label view player settings string * Add PlayerSettingsModal component Includes a toggle switch for enabling/disabling the chapter track feature. * Add player settings modal component to MediaPlayerContainer * Handle useChapterTrack changes in PlayerUI * Add jump forwards and jump backwards settings to user store * Add jump forwards and jump backwards label strings * Add jump forwards and jump backwards settings to PlayerSettingsModal * Update jump forwards and jump backwards to handle user state values in PlayerHandler * Update jump backwards icon in PlayerPlaybackControls * Add playback settings string to en-us * Add playback settings UI for jump forwards and jump backwards * Remove jump forwards and jump backwards settings * Remove jump forwards and jump backwards en-us strings * Update player UI to include player settings button * Add label view player settings string * Add PlayerSettingsModal component Includes a toggle switch for enabling/disabling the chapter track feature. * Add player settings modal component to MediaPlayerContainer * Handle useChapterTrack changes in PlayerUI * Add jump forwards and jump backwards settings to user store * Add jump forwards and jump backwards label strings * Add jump forwards and jump backwards settings to PlayerSettingsModal * Update jump forwards and jump backwards to handle user state values in PlayerHandler * Update jump backwards icon in PlayerPlaybackControls * Add jump amounts to playback controls tooltips * Fix merge issues and add new Material Symbols to player ui * Alphabetize strings in en-us.json * Update dropdown component with SelectInput to support menu overflowing modal * Update localization for player settings * Update en-us strings order --------- Co-authored-by: advplyr <advplyr@protonmail.com>
This commit is contained in:
parent
b6875a44cf
commit
43b7ccd61a
8 changed files with 283 additions and 18 deletions
151
client/components/ui/SelectInput.vue
Normal file
151
client/components/ui/SelectInput.vue
Normal file
|
@ -0,0 +1,151 @@
|
|||
<template>
|
||||
<div class="relative w-full">
|
||||
<p v-if="label" class="text-sm font-semibold px-1" :class="disabled ? 'text-gray-300' : ''">{{ label }}</p>
|
||||
<button ref="buttonWrapper" type="button" :aria-label="longLabel" :disabled="disabled" class="relative w-full border rounded shadow-sm pl-3 pr-8 py-2 text-left sm:text-sm" :class="buttonClass" aria-haspopup="listbox" aria-expanded="true" @click.stop.prevent="clickShowMenu">
|
||||
<span class="flex items-center">
|
||||
<span class="block truncate font-sans" :class="{ 'font-semibold': selectedSubtext, 'text-sm': small }">{{ selectedText }}</span>
|
||||
<span v-if="selectedSubtext">: </span>
|
||||
<span v-if="selectedSubtext" class="font-normal block truncate font-sans text-sm text-gray-400">{{ selectedSubtext }}</span>
|
||||
</span>
|
||||
<span class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||
<span class="material-symbols text-2xl">expand_more</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<transition name="menu">
|
||||
<ul ref="menu" v-show="showMenu" class="absolute z-60 -mt-px w-full bg-primary border border-black-200 shadow-lg rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto sm:text-sm" tabindex="-1" role="listbox" :style="{ maxHeight: menuMaxHeight }" v-click-outside="clickOutsideObj">
|
||||
<template v-for="item in itemsToShow">
|
||||
<li :key="item.value" class="text-gray-100 relative py-2 cursor-pointer hover:bg-black-400" :id="'listbox-option-' + item.value" role="option" tabindex="0" @keyup.enter="clickedOption(item.value)" @click.stop.prevent="clickedOption(item.value)">
|
||||
<div class="flex items-center">
|
||||
<span class="ml-3 block truncate font-sans text-sm" :class="{ 'font-semibold': item.subtext }">{{ item.text }}</span>
|
||||
<span v-if="item.subtext">: </span>
|
||||
<span v-if="item.subtext" class="font-normal block truncate font-sans text-sm text-gray-400">{{ item.subtext }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: [String, Number],
|
||||
label: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
disabled: Boolean,
|
||||
small: Boolean,
|
||||
menuMaxHeight: {
|
||||
type: String,
|
||||
default: '224px'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
clickOutsideObj: {
|
||||
handler: this.clickedOutside,
|
||||
events: ['click'],
|
||||
isActive: true
|
||||
},
|
||||
menu: null,
|
||||
showMenu: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selected: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
},
|
||||
itemsToShow() {
|
||||
return this.items.map((i) => {
|
||||
if (typeof i === 'string' || typeof i === 'number') {
|
||||
return {
|
||||
text: i,
|
||||
value: i
|
||||
}
|
||||
}
|
||||
return i
|
||||
})
|
||||
},
|
||||
selectedItem() {
|
||||
return this.itemsToShow.find((i) => i.value === this.selected)
|
||||
},
|
||||
selectedText() {
|
||||
return this.selectedItem ? this.selectedItem.text : ''
|
||||
},
|
||||
selectedSubtext() {
|
||||
return this.selectedItem ? this.selectedItem.subtext : ''
|
||||
},
|
||||
buttonClass() {
|
||||
var classes = []
|
||||
if (this.small) classes.push('h-9')
|
||||
else classes.push('h-10')
|
||||
|
||||
if (this.disabled) classes.push('cursor-not-allowed border-gray-600 bg-primary bg-opacity-70 border-opacity-70 text-gray-400')
|
||||
else classes.push('cursor-pointer border-gray-600 bg-primary text-gray-100')
|
||||
|
||||
return classes.join(' ')
|
||||
},
|
||||
longLabel() {
|
||||
let result = ''
|
||||
if (this.label) result += this.label + ': '
|
||||
if (this.selectedText) result += this.selectedText
|
||||
if (this.selectedSubtext) result += ' ' + this.selectedSubtext
|
||||
return result
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
recalcMenuPos() {
|
||||
if (!this.menu || !this.$refs.buttonWrapper) return
|
||||
const boundingBox = this.$refs.buttonWrapper.getBoundingClientRect()
|
||||
this.menu.style.top = boundingBox.y + boundingBox.height - 4 + 'px'
|
||||
this.menu.style.left = boundingBox.x + 'px'
|
||||
this.menu.style.width = boundingBox.width + 'px'
|
||||
},
|
||||
unmountMountMenu() {
|
||||
if (!this.$refs.menu || !this.$refs.buttonWrapper) return
|
||||
this.menu = this.$refs.menu
|
||||
this.menu.remove()
|
||||
},
|
||||
clickShowMenu() {
|
||||
if (this.disabled) return
|
||||
if (!this.showMenu) this.handleShowMenu()
|
||||
else this.handleCloseMenu()
|
||||
},
|
||||
handleShowMenu() {
|
||||
if (!this.menu) {
|
||||
this.unmountMountMenu()
|
||||
}
|
||||
document.body.appendChild(this.menu)
|
||||
this.recalcMenuPos()
|
||||
this.showMenu = true
|
||||
},
|
||||
handleCloseMenu() {
|
||||
this.showMenu = false
|
||||
if (this.menu) this.menu.remove()
|
||||
},
|
||||
clickedOutside() {
|
||||
this.handleCloseMenu()
|
||||
},
|
||||
clickedOption(itemValue) {
|
||||
this.selected = itemValue
|
||||
this.handleCloseMenu()
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
beforeDestroy() {
|
||||
if (this.menu) this.menu.remove()
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue