Form, modal and player icon to add track to playlist
This commit is contained in:
parent
a34b1afd6c
commit
d6f2c7d4c4
|
@ -30,7 +30,12 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<track-favorite-icon :track="currentTrack"></track-favorite-icon>
|
<track-favorite-icon
|
||||||
|
v-if="$store.state.auth.authenticated"
|
||||||
|
:track="currentTrack"></track-favorite-icon>
|
||||||
|
<track-playlist-icon
|
||||||
|
v-if="$store.state.auth.authenticated"
|
||||||
|
:track="currentTrack"></track-playlist-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -140,11 +145,13 @@ import ColorThief from '@/vendor/color-thief'
|
||||||
import Track from '@/audio/track'
|
import Track from '@/audio/track'
|
||||||
import AudioTrack from '@/components/audio/Track'
|
import AudioTrack from '@/components/audio/Track'
|
||||||
import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
|
import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
|
||||||
|
import TrackPlaylistIcon from '@/components/playlists/TrackPlaylistIcon'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'player',
|
name: 'player',
|
||||||
components: {
|
components: {
|
||||||
TrackFavoriteIcon,
|
TrackFavoriteIcon,
|
||||||
|
TrackPlaylistIcon,
|
||||||
GlobalEvents,
|
GlobalEvents,
|
||||||
AudioTrack
|
AudioTrack
|
||||||
},
|
},
|
||||||
|
@ -281,6 +288,7 @@ export default {
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
}
|
}
|
||||||
.track-area {
|
.track-area {
|
||||||
|
margin-top: 0;
|
||||||
.header, .meta, .artist, .album {
|
.header, .meta, .artist, .album {
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
@ -384,4 +392,5 @@ export default {
|
||||||
.ui.feed.icon {
|
.ui.feed.icon {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
<template>
|
||||||
|
<form class="ui form" @submit.prevent="submit()">
|
||||||
|
<h4 class="ui header">Create a new playlist</h4>
|
||||||
|
<div v-if="success" class="ui positive message">
|
||||||
|
<div class="header">Playlist created</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="errors.length > 0" class="ui negative message">
|
||||||
|
<div class="header">We cannot create the playlist</div>
|
||||||
|
<ul class="list">
|
||||||
|
<li v-for="error in errors">{{ error }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="field">
|
||||||
|
<label>Playlist name</label>
|
||||||
|
<input v-model="name" required type="text" placeholder="My awesome playlist" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Playlist visibility</label>
|
||||||
|
<select class="ui dropdown" v-model="privacyLevel">
|
||||||
|
<option :value="c.value" v-for="c in privacyLevelChoices">{{ c.label }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button :class="['ui', {'loading': isLoading}, 'button']" type="submit">Create playlist</button>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import $ from 'jquery'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import logger from '@/logging'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted () {
|
||||||
|
$(this.$el).find('.dropdown').dropdown()
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
privacyLevel: this.$store.state.auth.profile.privacy_level,
|
||||||
|
name: '',
|
||||||
|
errors: [],
|
||||||
|
success: false,
|
||||||
|
isLoading: false,
|
||||||
|
privacyLevelChoices: [
|
||||||
|
{
|
||||||
|
value: 'me',
|
||||||
|
label: 'Nobody except me'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'instance',
|
||||||
|
label: 'Everyone on this instance'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'everyone',
|
||||||
|
label: 'Everyone'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit () {
|
||||||
|
this.isLoading = true
|
||||||
|
this.success = false
|
||||||
|
this.errors = []
|
||||||
|
let self = this
|
||||||
|
let payload = {
|
||||||
|
name: this.name,
|
||||||
|
privacy_level: this.privacyLevel
|
||||||
|
}
|
||||||
|
let url = `playlists/`
|
||||||
|
return axios.post(url, payload).then(response => {
|
||||||
|
logger.default.info('Successfully created playlist')
|
||||||
|
self.success = true
|
||||||
|
self.isLoading = false
|
||||||
|
self.$store.dispatch('playlists/fetchOwn')
|
||||||
|
}, error => {
|
||||||
|
logger.default.error('Error while creating playlist')
|
||||||
|
self.isLoading = false
|
||||||
|
self.errors = error.backendErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,91 @@
|
||||||
|
<template>
|
||||||
|
<modal @update:show="update" :show="show">
|
||||||
|
<div class="header">
|
||||||
|
Add track "{{ track.title }}" by {{ track.artist.name }} to playlist
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="description">
|
||||||
|
<playlist-form></playlist-form>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<div v-if="errors.length > 0" class="ui negative message">
|
||||||
|
<div class="header">We cannot add the track to a playlist</div>
|
||||||
|
<ul class="list">
|
||||||
|
<li v-for="error in errors">{{ error }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="ui items">
|
||||||
|
<div class="item" v-for="playlist in sortedPlaylists">
|
||||||
|
<div class="content">
|
||||||
|
<div class="header">{{ playlist.name }}</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span class="tracks">45 tracks</span>
|
||||||
|
</div>
|
||||||
|
<div class="extra">
|
||||||
|
<div class="ui basic green button" @click="addToPlaylist(playlist.id)">
|
||||||
|
Add to this playlist
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
|
import logger from '@/logging'
|
||||||
|
import Modal from '@/components/semantic/Modal'
|
||||||
|
import PlaylistForm from '@/components/playlists/Form'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Modal,
|
||||||
|
PlaylistForm
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
track: {type: Object},
|
||||||
|
show: {type: Boolean}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
errors: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
update (v) {
|
||||||
|
this.$emit('update:show', v)
|
||||||
|
},
|
||||||
|
addToPlaylist (playlistId) {
|
||||||
|
let self = this
|
||||||
|
let payload = {
|
||||||
|
track: this.track.id,
|
||||||
|
playlist: playlistId
|
||||||
|
}
|
||||||
|
return axios.post('playlist-tracks/', payload).then(response => {
|
||||||
|
logger.default.info('Successfully added track to playlist')
|
||||||
|
self.$emit('update:show', false)
|
||||||
|
self.$store.dispatch('playlists/fetchOwn')
|
||||||
|
}, error => {
|
||||||
|
logger.default.error('Error while adding track to playlist')
|
||||||
|
self.errors = error.backendErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
playlists: state => state.playlists.playlists
|
||||||
|
}),
|
||||||
|
sortedPlaylists () {
|
||||||
|
return this.playlists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
@click="showModal = true"
|
||||||
|
v-if="button"
|
||||||
|
:class="['ui', 'button']">
|
||||||
|
<i class="list icon"></i>
|
||||||
|
Add to playlist...
|
||||||
|
<playlist-modal :track="track" :show.sync="showModal"></playlist-modal>
|
||||||
|
</button>
|
||||||
|
<i
|
||||||
|
v-else
|
||||||
|
@click="showModal = true"
|
||||||
|
:class="['favorite-icon', 'list', 'link', 'icon']"
|
||||||
|
title="Add to playlist...">
|
||||||
|
<playlist-modal :track="track" :show.sync="showModal"></playlist-modal>
|
||||||
|
</i>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PlaylistModal from '@/components/playlists/PlaylistModal'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
PlaylistModal
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
track: {type: Object},
|
||||||
|
button: {type: Boolean, default: false}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showModal: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
Loading…
Reference in New Issue