audiobookshelf/client/components/ui/LibrariesDropdown.vue
Lars Kiesow 4b0c59b174
Highlight items when navigating via keyboard
This patch highlights items in the app bar if a user uses the keyboard
to navigate in audiobookshelf. This ensures that users actually know
which item they have selected.

This also modifies the text for the library selector, so that users
which are using a screen reader understand that it is a selector for
libraries and not only a button related to the current library.
2022-12-28 22:59:27 +01:00

96 lines
3.4 KiB
Vue

<template>
<div v-if="currentLibrary" class="relative h-8 max-w-52 md:min-w-32" v-click-outside="clickOutsideObj">
<button type="button" :disabled="disabled" class="w-10 sm:w-full relative h-full border border-white border-opacity-10 hover:border-opacity-20 rounded shadow-sm px-2 text-left text-sm cursor-pointer bg-black bg-opacity-20 text-gray-400 hover:text-gray-200" aria-haspopup="listbox" :aria-expanded="showMenu" :aria-label="$strings.ButtonLibrary + ': ' + currentLibrary.name" @click.stop.prevent="clickShowMenu">
<div class="flex items-center justify-center sm:justify-start">
<ui-library-icon :icon="currentLibraryIcon" class="sm:mr-1.5" />
<span class="hidden sm:block truncate">{{ currentLibrary.name }}</span>
</div>
</button>
<transition name="menu">
<ul v-show="showMenu" class="absolute z-10 -mt-px min-w-48 w-full bg-primary border border-black-200 shadow-lg max-h-56 rounded-b-md py-1 overflow-auto focus:outline-none sm:text-sm" tabindex="-1" role="listbox">
<template v-for="library in librariesFiltered">
<li :key="library.id" class="text-gray-400 hover:text-white select-none relative py-2 cursor-pointer hover:bg-black-400" role="option" @click="selectLibrary(library)">
<div class="flex items-center px-2">
<ui-library-icon :icon="library.icon" class="mr-1.5" />
<span class="font-normal block truncate font-sans text-sm">{{ library.name }}</span>
</div>
</li>
</template>
</ul>
</transition>
</div>
</template>
<script>
export default {
data() {
return {
clickOutsideObj: {
handler: this.clickedOutside,
events: ['mousedown'],
isActive: true
},
showMenu: false,
disabled: false
}
},
computed: {
currentLibraryId() {
return this.$store.state.libraries.currentLibraryId
},
currentLibrary() {
return this.libraries.find((lib) => lib.id === this.currentLibraryId)
},
currentLibraryIcon() {
return this.currentLibrary ? this.currentLibrary.icon || 'database' : 'database'
},
libraries() {
return this.$store.getters['libraries/getSortedLibraries']()
},
canUserAccessAllLibraries() {
return this.$store.getters['user/getUserCanAccessAllLibraries']
},
userLibrariesAccessible() {
return this.$store.getters['user/getLibrariesAccessible']
},
librariesFiltered() {
if (this.canUserAccessAllLibraries) return this.libraries
return this.libraries.filter((lib) => {
return this.userLibrariesAccessible.includes(lib.id)
})
}
},
methods: {
clickShowMenu() {
if (this.disabled) return
this.showMenu = !this.showMenu
},
clickedOutside() {
this.showMenu = false
},
selectLibrary(library) {
this.updateLibrary(library)
this.showMenu = false
},
async updateLibrary(library) {
var currLibraryId = this.currentLibraryId
this.disabled = true
await this.$store.dispatch('libraries/fetch', library.id)
if (this.$route.name.startsWith('config')) {
// No need to refresh
} else if (this.$route.name.startsWith('library')) {
var newRoute = this.$route.path.replace(currLibraryId, library.id)
this.$router.push(newRoute)
} else {
this.$router.push(`/library/${library.id}`)
}
this.disabled = false
}
},
mounted() {}
}
</script>