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

181 lines
5.2 KiB
Vue
Raw Normal View History

2022-04-15 14:24:30 +00:00
<template>
2022-04-15 17:00:08 +00:00
<div class="song-list-controls" data-test="song-list-controls" ref="el">
<BtnGroup uppercased>
2022-04-15 14:24:30 +00:00
<template v-if="mergedConfig.play">
<template v-if="altPressed">
2022-04-15 17:00:08 +00:00
<Btn
2022-04-21 16:06:45 +00:00
v-if="selectedSongs.length < 2 && songs.length"
2022-04-15 14:24:30 +00:00
class="btn-play-all"
2022-04-21 16:06:45 +00:00
data-test="btn-play-all"
2022-04-15 14:24:30 +00:00
orange
title="Play all songs"
2022-04-21 16:06:45 +00:00
@click.prevent="playAll"
2022-04-15 14:24:30 +00:00
>
<i class="fa fa-play"></i> All
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
<Btn
2022-04-21 16:06:45 +00:00
v-if="selectedSongs.length > 1"
2022-04-15 14:24:30 +00:00
class="btn-play-selected"
2022-04-21 16:06:45 +00:00
data-test="btn-play-selected"
2022-04-15 14:24:30 +00:00
orange
title="Play selected songs"
2022-04-21 16:06:45 +00:00
@click.prevent="playSelected"
2022-04-15 14:24:30 +00:00
>
<i class="fa fa-play"></i> Selected
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
</template>
<template v-else>
2022-04-15 17:00:08 +00:00
<Btn
2022-04-21 16:06:45 +00:00
v-if="selectedSongs.length < 2 && songs.length"
2022-04-15 14:24:30 +00:00
class="btn-shuffle-all"
2022-04-21 16:06:45 +00:00
data-test="btn-shuffle-all"
2022-04-15 14:24:30 +00:00
orange
title="Shuffle all songs"
2022-04-21 16:06:45 +00:00
@click.prevent="shuffle"
2022-04-15 14:24:30 +00:00
>
<i class="fa fa-random"></i> All
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
<Btn
2022-04-21 16:06:45 +00:00
v-if="selectedSongs.length > 1"
2022-04-15 14:24:30 +00:00
class="btn-shuffle-selected"
2022-04-21 16:06:45 +00:00
data-test="btn-shuffle-selected"
2022-04-15 14:24:30 +00:00
orange
title="Shuffle selected songs"
2022-04-21 16:06:45 +00:00
@click.prevent="shuffleSelected"
2022-04-15 14:24:30 +00:00
>
<i class="fa fa-random"></i> Selected
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
</template>
</template>
2022-04-15 17:00:08 +00:00
<Btn
2022-04-15 14:24:30 +00:00
:title="`${showingAddToMenu ? 'Cancel' : 'Add selected songs to…'}`"
@click.prevent.stop="toggleAddToMenu"
class="btn-add-to"
green
v-if="selectedSongs.length"
data-test="add-to-btn"
>
{{ showingAddToMenu ? 'Cancel' : 'Add To…' }}
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
<Btn
2022-04-21 16:06:45 +00:00
v-if="showClearQueueButton"
2022-04-15 14:24:30 +00:00
class="btn-clear-queue"
red
title="Clear current queue"
2022-04-21 16:06:45 +00:00
@click.prevent="clearQueue"
2022-04-15 14:24:30 +00:00
>
Clear
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
<Btn
2022-04-21 16:06:45 +00:00
v-if="showDeletePlaylistButton"
2022-04-15 14:24:30 +00:00
class="del btn-delete-playlist"
red
title="Delete this playlist"
2022-04-21 16:06:45 +00:00
@click.prevent="deletePlaylist"
2022-04-15 14:24:30 +00:00
>
<i class="fa fa-times"></i> Playlist
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
</BtnGroup>
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
<AddToMenu
2022-04-21 16:06:45 +00:00
v-koel-clickaway="closeAddToMenu"
2022-04-15 14:24:30 +00:00
:config="mergedConfig.addTo"
:showing="showingAddToMenu"
2022-04-21 16:06:45 +00:00
:songs="selectedSongs"
@closing="closeAddToMenu"
2022-04-15 14:24:30 +00:00
/>
</div>
</template>
2022-04-15 17:00:08 +00:00
<script lang="ts" setup>
import { computed, defineAsyncComponent, nextTick, onMounted, onUnmounted, ref, toRefs } from 'vue'
2022-04-15 14:24:30 +00:00
2022-04-20 10:20:09 +00:00
const AddToMenu = defineAsyncComponent(() => import('./AddToMenu.vue'))
2022-04-15 17:00:08 +00:00
const Btn = defineAsyncComponent(() => import('@/components/ui/btn.vue'))
2022-04-21 16:06:45 +00:00
const BtnGroup = defineAsyncComponent(() => import('@/components/ui/BtnGroup.vue'))
const props = withDefaults(
defineProps<{ songs: Song[], selectedSongs: Song[], config: Partial<SongListControlsConfig> }>(),
{
songs: () => [],
selectedSongs: () => [],
config: () => ({})
}
)
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
const { config, songs, selectedSongs } = toRefs(props)
2022-04-15 14:24:30 +00:00
2022-04-21 16:06:45 +00:00
const el = ref<HTMLElement>()
2022-04-15 17:00:08 +00:00
const showingAddToMenu = ref(false)
const numberOfQueuedSongs = ref(0)
const altPressed = ref(false)
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
const mergedConfig = computed((): SongListControlsConfig => Object.assign({
play: true,
addTo: {
queue: true,
favorites: true,
playlists: true,
newPlaylist: true
2022-04-15 14:24:30 +00:00
},
2022-04-15 17:00:08 +00:00
clearQueue: false,
deletePlaylist: false
2022-04-21 16:06:45 +00:00
}, config.value)
2022-04-15 17:00:08 +00:00
)
const showClearQueueButton = computed(() => mergedConfig.value.clearQueue)
const showDeletePlaylistButton = computed(() => mergedConfig.value.deletePlaylist)
const emit = defineEmits(['playAll', 'playSelected', 'clearQueue', 'deletePlaylist'])
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 closeAddToMenu = () => (showingAddToMenu.value = false)
const registerKeydown = (event: KeyboardEvent) => event.altKey && (altPressed.value = true)
const registerKeyup = (event: KeyboardEvent) => event.altKey && (altPressed.value = false)
const toggleAddToMenu = async () => {
showingAddToMenu.value = !showingAddToMenu.value
if (!showingAddToMenu.value) {
return
}
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
await nextTick()
2022-04-15 14:24:30 +00:00
2022-04-21 16:06:45 +00:00
const btnAddTo = el.value?.querySelector<HTMLButtonElement>('.btn-add-to')!
2022-04-15 17:00:08 +00:00
const { left: btnLeft, bottom: btnBottom, width: btnWidth } = btnAddTo.getBoundingClientRect()
2022-04-21 16:06:45 +00:00
const contextMenu = el.value?.querySelector<HTMLElement>('.add-to')!
2022-04-15 17:00:08 +00:00
const menuWidth = contextMenu.getBoundingClientRect().width
contextMenu.style.top = `${btnBottom + 10}px`
contextMenu.style.left = `${btnLeft + btnWidth / 2 - menuWidth / 2}px`
}
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
2022-04-15 17:00:08 +00:00
onUnmounted(() => {
window.removeEventListener('keydown', registerKeydown)
window.removeEventListener('keyup', registerKeyup)
2022-04-15 14:24:30 +00:00
})
</script>
<style lang="scss" scoped>
.song-list-controls {
position: relative;
}
</style>