koel/resources/assets/js/components/song/SongListControls.vue

180 lines
5.8 KiB
Vue
Raw Normal View History

2022-04-15 14:24:30 +00:00
<template>
2024-04-04 22:20:42 +00:00
<div class="relative" data-testid="song-list-controls">
<div class="flex gap-2 flex-wrap">
2024-05-19 05:49:42 +00:00
<BtnGroup uppercase>
<template v-if="altPressed">
<Btn
2024-05-19 05:49:42 +00:00
v-if="selectedPlayables.length < 2 && playables.length"
2024-03-19 22:48:12 +00:00
v-koel-tooltip.bottom
class="btn-play-all"
2024-04-04 22:20:42 +00:00
highlight
title="Play all. Press Alt/⌥ to change mode."
@click.prevent="playAll"
>
2023-11-10 13:16:06 +00:00
<Icon :icon="faPlay" fixed-width />
All
</Btn>
<Btn
2024-05-19 05:49:42 +00:00
v-if="selectedPlayables.length > 1"
2024-03-19 22:48:12 +00:00
v-koel-tooltip.bottom
class="btn-play-selected"
2024-04-04 22:20:42 +00:00
highlight
title="Play selected. Press Alt/⌥ to change mode."
@click.prevent="playSelected"
>
2023-11-10 13:16:06 +00:00
<Icon :icon="faPlay" fixed-width />
Selected
</Btn>
2022-04-15 14:24:30 +00:00
</template>
<template v-else>
<Btn
2024-05-19 05:49:42 +00:00
v-if="selectedPlayables.length < 2 && playables.length"
2024-03-19 22:48:12 +00:00
v-koel-tooltip.bottom
class="btn-shuffle-all"
data-testid="btn-shuffle-all"
2024-04-04 22:20:42 +00:00
highlight
title="Shuffle all. Press Alt/⌥ to change mode."
@click.prevent="shuffle"
>
2023-11-10 13:16:06 +00:00
<Icon :icon="faRandom" fixed-width />
All
</Btn>
<Btn
2024-05-19 05:49:42 +00:00
v-if="selectedPlayables.length > 1"
2024-03-19 22:48:12 +00:00
v-koel-tooltip.bottom
class="btn-shuffle-selected"
data-testid="btn-shuffle-selected"
2024-04-04 22:20:42 +00:00
highlight
title="Shuffle selected. Press Alt/⌥ to change mode."
@click.prevent="shuffleSelected"
>
2023-11-10 13:16:06 +00:00
<Icon :icon="faRandom" fixed-width />
Selected
</Btn>
</template>
<Btn
v-if="showAddToButton"
ref="addToButton"
2024-04-04 22:20:42 +00:00
success
@click.prevent.stop="toggleAddToMenu"
>
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
</Btn>
2024-04-04 22:20:42 +00:00
<Btn v-if="config.clearQueue" danger title="Clear current queue" @click.prevent="clearQueue">Clear</Btn>
</BtnGroup>
<BtnGroup v-if="config.refresh || config.deletePlaylist">
2024-04-04 22:20:42 +00:00
<Btn v-if="config.refresh" v-koel-tooltip success title="Refresh" @click.prevent="refresh">
2023-11-10 13:16:06 +00:00
<Icon :icon="faRotateRight" fixed-width />
</Btn>
<Btn
v-if="config.deletePlaylist"
v-koel-tooltip
class="del btn-delete-playlist"
2024-04-04 22:20:42 +00:00
danger
title="Delete this playlist"
@click.prevent="deletePlaylist"
>
2023-11-10 13:16:06 +00:00
<Icon :icon="faTrashCan" />
</Btn>
</BtnGroup>
2024-05-19 05:49:42 +00:00
<BtnGroup v-if="config.filter && playables.length">
<SongListFilter @change="filter" />
</BtnGroup>
</div>
2022-04-15 14:24:30 +00:00
2024-05-08 09:11:32 +00:00
<OnClickOutside @trigger="closeAddToMenu">
<div ref="addToMenu" class="context-menu p-0 hidden">
2024-05-19 05:49:42 +00:00
<AddToMenu :config="config.addTo" :playables="selectedPlayables" @closing="closeAddToMenu" />
2024-05-08 09:11:32 +00:00
</div>
</OnClickOutside>
2022-04-15 14:24:30 +00:00
</div>
</template>
2022-04-15 17:00:08 +00:00
<script lang="ts" setup>
import { faPlay, faRandom, faRotateRight, faTrashCan } from '@fortawesome/free-solid-svg-icons'
2024-01-18 11:13:05 +00:00
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, Ref, ref, toRef, watch } from 'vue'
2024-05-08 09:11:32 +00:00
import { OnClickOutside } from '@vueuse/components'
2024-05-19 05:49:42 +00:00
import { SelectedPlayablesKey, PlayablesKey } from '@/symbols'
2022-07-20 08:00:02 +00:00
import { requireInjection } from '@/utils'
2024-01-18 11:13:05 +00:00
import { useFloatingUi } from '@/composables'
2022-04-15 14:24:30 +00:00
import AddToMenu from '@/components/song/AddToMenu.vue'
2024-04-04 22:20:42 +00:00
import Btn from '@/components/ui/form/Btn.vue'
import BtnGroup from '@/components/ui/form/BtnGroup.vue'
2022-04-21 16:06:45 +00:00
const SongListFilter = defineAsyncComponent(() => import('@/components/song/SongListFilter.vue'))
2024-01-18 11:13:05 +00:00
const props = defineProps<{ config: SongListControlsConfig }>()
const config = toRef(props, 'config')
2022-04-15 14:24:30 +00:00
2024-05-19 05:49:42 +00:00
const [playables] = requireInjection<[Ref<Playable[]>]>(PlayablesKey)
const [selectedPlayables] = requireInjection(SelectedPlayablesKey)
2022-04-15 14:24:30 +00:00
2022-12-02 16:17:37 +00:00
const addToButton = ref<InstanceType<typeof Btn>>()
const addToMenu = ref<HTMLDivElement>()
2022-04-15 17:00:08 +00:00
const showingAddToMenu = ref(false)
const altPressed = ref(false)
2022-04-15 14:24:30 +00:00
2024-05-19 05:49:42 +00:00
const showAddToButton = computed(() => Boolean(selectedPlayables.value.length))
2022-04-15 17:00:08 +00:00
const emit = defineEmits<{
(e: 'playAll' | 'playSelected', shuffle: boolean): void,
(e: 'filter', keywords: string): void,
(e: 'clearQueue' | 'deletePlaylist' | 'refresh'): void,
}>()
2022-04-15 17:00:08 +00:00
const shuffle = () => emit('playAll', true)
const shuffleSelected = () => emit('playSelected', true)
const playAll = () => emit('playAll', false)
const playSelected = () => emit('playSelected', false)
const clearQueue = () => emit('clearQueue')
const deletePlaylist = () => emit('deletePlaylist')
const refresh = () => emit('refresh')
const filter = (keywords: string) => emit('filter', keywords)
const registerKeydown = (event: KeyboardEvent) => event.key === 'Alt' && (altPressed.value = true)
const registerKeyup = (event: KeyboardEvent) => event.key === 'Alt' && (altPressed.value = false)
2022-04-15 17:00:08 +00:00
let usedFloatingUi: ReturnType<typeof useFloatingUi>
2022-04-15 17:00:08 +00:00
watch(showAddToButton, async showingButton => {
await nextTick()
if (showingButton) {
2022-12-02 16:17:37 +00:00
usedFloatingUi = useFloatingUi(addToButton.value!.button!, addToMenu, { autoTrigger: false })
usedFloatingUi.setup()
} else {
usedFloatingUi?.teardown()
2022-04-15 17:00:08 +00:00
}
}, { immediate: true })
2022-04-15 14:24:30 +00:00
const closeAddToMenu = () => {
usedFloatingUi?.hide()
showingAddToMenu.value = false
}
2022-04-15 14:24:30 +00:00
const toggleAddToMenu = () => {
showingAddToMenu.value ? usedFloatingUi?.hide() : usedFloatingUi?.show()
showingAddToMenu.value = !showingAddToMenu.value
2022-04-15 17:00:08 +00:00
}
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
onMounted(() => {
window.addEventListener('keydown', registerKeydown)
window.addEventListener('keyup', registerKeyup)
})
2022-04-15 14:24:30 +00:00
onBeforeUnmount(() => {
2022-04-15 17:00:08 +00:00
window.removeEventListener('keydown', registerKeydown)
window.removeEventListener('keyup', registerKeyup)
usedFloatingUi?.teardown()
2022-04-15 14:24:30 +00:00
})
</script>