Update:UI/UX improvements for playlists

This commit is contained in:
advplyr 2023-06-11 17:03:03 -05:00
parent 455af239a1
commit db3c5396e9
4 changed files with 127 additions and 45 deletions

View file

@ -0,0 +1,76 @@
<template>
<div ref="wrapper" class="modal modal-bg w-screen h-screen fixed top-0 left-0 flex items-center justify-center z-50">
<div ref="content" class="relative text-white bg-bg h-full w-full">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
value: Boolean,
processing: Boolean
},
data() {
return {
el: null,
content: null
}
},
watch: {
show(newVal) {
if (newVal) {
this.setShow()
} else {
this.setHide()
}
}
},
computed: {
show: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
},
methods: {
setShow() {
this.$store.commit('globals/setIsModalOpen', true)
document.body.appendChild(this.el)
setTimeout(() => {
this.content.style.transform = 'translateY(0)'
}, 10)
document.documentElement.classList.add('modal-open')
},
setHide() {
this.$store.commit('globals/setIsModalOpen', false)
this.content.style.transform = 'translateY(100vh)'
setTimeout(() => {
this.el.remove()
document.documentElement.classList.remove('modal-open')
}, 250)
},
closeModalEvt() {
console.log('Close modal event')
this.show = false
}
},
mounted() {
this.$eventBus.$on('close-modal', this.closeModalEvt)
this.el = this.$refs.wrapper
this.content = this.$refs.content
this.content.style.transform = 'translateY(100vh)'
this.content.style.transition = 'transform 0.25s cubic-bezier(0.16, 1, 0.3, 1)'
this.el.remove()
},
beforeDestroy() {
this.$eventBus.$off('close-modal', this.closeModalEvt)
}
}
</script>

View file

@ -1,13 +1,15 @@
<template> <template>
<modals-modal v-model="show" :width="360" height="100%" :processing="processing"> <modals-fullscreen-modal v-model="show" :processing="processing">
<template #outer> <div class="flex items-end justify-between h-16 px-4 pb-2">
<div class="absolute top-8 left-4 z-40"> <h1 class="text-lg">Add to Playlist</h1>
<p class="text-white text-2xl truncate">Add to Playlist</p> <button class="flex" @click="show = false">
<span class="material-icons">close</span>
</button>
</div> </div>
</template>
<div class="w-full h-full overflow-hidden absolute top-0 left-0 flex items-center justify-center" @click="show = false"> <!-- create new playlist form -->
<div ref="container" class="w-full rounded-lg bg-primary border border-white border-opacity-20 overflow-y-auto overflow-x-hidden" style="max-height: 80vh" @click.stop.prevent> <div v-if="showPlaylistNameInput" class="w-full h-full max-h-[calc(100vh-128px)] flex items-center">
<div class="w-full h-full p-4" v-show="showPlaylistNameInput"> <div class="w-full px-4">
<div class="flex mb-4 items-center"> <div class="flex mb-4 items-center">
<div class="w-9 h-9 flex items-center justify-center rounded-full hover:bg-white hover:bg-opacity-10 cursor-pointer" @click.stop="showPlaylistNameInput = false"> <div class="w-9 h-9 flex items-center justify-center rounded-full hover:bg-white hover:bg-opacity-10 cursor-pointer" @click.stop="showPlaylistNameInput = false">
<span class="material-icons text-3xl">arrow_back</span> <span class="material-icons text-3xl">arrow_back</span>
@ -21,21 +23,27 @@
<ui-btn color="success" :loading="processing" class="w-full" @click.stop="submitCreatePlaylist">Create</ui-btn> <ui-btn color="success" :loading="processing" class="w-full" @click.stop="submitCreatePlaylist">Create</ui-btn>
</div> </div>
</div> </div>
</div>
<!-- playlists list -->
<div v-if="!showPlaylistNameInput" class="w-full overflow-y-auto overflow-x-hidden h-full max-h-[calc(100vh-128px)]">
<div class="w-full h-full" v-show="!showPlaylistNameInput"> <div class="w-full h-full" v-show="!showPlaylistNameInput">
<template v-for="playlist in sortedPlaylists"> <template v-for="playlist in sortedPlaylists">
<modals-playlists-playlist-row :key="playlist.id" :in-playlist="playlist.isItemIncluded" :playlist="playlist" @click="clickPlaylist" /> <modals-playlists-playlist-row :key="playlist.id" :in-playlist="playlist.isItemIncluded" :playlist="playlist" @click="clickPlaylist" @close="show = false" />
</template> </template>
<div v-if="!playlists.length" class="flex h-32 items-center justify-center"> <div v-if="!playlists.length" class="flex h-full items-center justify-center">
<p class="text-xl">{{ loading ? 'Loading..' : 'No Playlists' }}</p> <p class="text-xl">{{ loading ? 'Loading..' : 'No Playlists' }}</p>
</div> </div>
<ui-btn :loading="processing" color="success" class="w-full flex items-center justify-center" @click.stop="createPlaylist"> </div>
<span class="material-icons text-xl">add</span> </div>
<p class="text-base pl-2">New Playlist</p>
<!-- create playlist btn -->
<div v-if="!showPlaylistNameInput" class="flex items-start justify-between h-16 pt-2 absolute bottom-0 left-0 w-full">
<ui-btn :loading="processing" color="success" class="w-full h-full flex items-center justify-center" @click.stop="createPlaylist">
<p class="text-base">Create New Playlist</p>
</ui-btn> </ui-btn>
</div> </div>
</div> </modals-fullscreen-modal>
</div>
</modals-modal>
</template> </template>
<script> <script>
@ -131,7 +139,6 @@ export default {
.$post(`/api/playlists/${playlist.id}/batch/remove`, { items: itemObjects }) .$post(`/api/playlists/${playlist.id}/batch/remove`, { items: itemObjects })
.then((updatedPlaylist) => { .then((updatedPlaylist) => {
console.log(`Items removed from playlist`, updatedPlaylist) console.log(`Items removed from playlist`, updatedPlaylist)
this.$toast.success('Playlist item(s) removed')
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to remove items from playlist', error) console.error('Failed to remove items from playlist', error)
@ -150,7 +157,6 @@ export default {
.$post(`/api/playlists/${playlist.id}/batch/add`, { items: itemObjects }) .$post(`/api/playlists/${playlist.id}/batch/add`, { items: itemObjects })
.then((updatedPlaylist) => { .then((updatedPlaylist) => {
console.log(`Items added to playlist`, updatedPlaylist) console.log(`Items added to playlist`, updatedPlaylist)
this.$toast.success('Items added to playlist')
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to add items to playlist', error) console.error('Failed to add items to playlist', error)
@ -182,7 +188,6 @@ export default {
.$post('/api/playlists', newPlaylist) .$post('/api/playlists', newPlaylist)
.then((data) => { .then((data) => {
console.log('New playlist created', data) console.log('New playlist created', data)
this.$toast.success(`Playlist "${data.name}" created`)
this.newPlaylistName = '' this.newPlaylistName = ''
this.showPlaylistNameInput = false this.showPlaylistNameInput = false
}) })

View file

@ -1,16 +1,15 @@
<template> <template>
<div :key="playlist.id" :id="`playlist-row-${playlist.id}`" class="flex items-center px-3 py-2 justify-start cursor-pointer relative" :class="inPlaylist ? 'bg-bg bg-opacity-60' : 'bg-opacity-20'"> <div :key="playlist.id" :id="`playlist-row-${playlist.id}`" class="flex items-center px-3 py-2 justify-start relative border-y border-white/5" :class="inPlaylist ? 'bg-primary/20' : ''">
<div v-if="inPlaylist" class="absolute top-0 left-0 h-full w-1 bg-success z-10" /> <div v-if="inPlaylist" class="absolute top-0 left-0 h-full w-1 bg-success z-10" />
<div class="w-16 max-w-16 text-center"> <div class="w-14 min-w-[56px] text-center" @click.stop="clickCover">
<covers-playlist-cover :items="items" :width="52" :height="52" /> <covers-playlist-cover :items="items" :width="52" :height="52" />
</div> </div>
<div class="flex-grow overflow-hidden"> <div class="flex-grow overflow-hidden">
<p class="pl-1 pr-2 truncate text-sm">{{ playlist.name }}</p> <p class="px-2 truncate text-sm">{{ playlist.name }}</p>
</div> </div>
<div class="w-24 min-w-[96px] px-1">
<div class="absolute top-0 right-0 h-full flex items-center px-3" @click.stop="click"> <ui-btn v-if="inPlaylist" small class="w-full" @click.stop="click">Remove</ui-btn>
<span v-if="inPlaylist" class="material-icons text-error">remove</span> <ui-btn v-else small class="w-full" @click.stop="click">Add</ui-btn>
<span v-else class="material-icons text-success">add</span>
</div> </div>
</div> </div>
</template> </template>
@ -35,6 +34,10 @@ export default {
methods: { methods: {
click() { click() {
this.$emit('click', this.playlist) this.$emit('click', this.playlist)
},
clickCover() {
this.$emit('close')
this.$router.push(`/playlist/${this.playlist.id}`)
} }
}, },
mounted() {} mounted() {}

View file

@ -1,10 +1,8 @@
<template> <template>
<div class="w-full h-full"> <div class="w-full h-full">
<div class="w-full h-full overflow-y-auto px-2 py-6 md:p-8"> <div class="w-full h-full overflow-y-auto px-2 py-6 md:p-8">
<div class="w-full flex justify-center md:block sm:w-32 md:w-52" style="min-width: 240px"> <div class="w-full flex justify-center">
<div class="relative" style="height: fit-content"> <covers-playlist-cover :items="playlistItems" :width="180" :height="180" />
<covers-playlist-cover :items="playlistItems" :width="240" :height="120 * bookCoverAspectRatio" :book-cover-aspect-ratio="bookCoverAspectRatio" />
</div>
</div> </div>
<div class="flex-grow py-6"> <div class="flex-grow py-6">
<div class="flex items-center px-2"> <div class="flex items-center px-2">