Browse Source

feat(AddToPlaylistDropdown): songs can be added to playlist from queue or within another playlist

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan 4 năm trước cách đây
mục cha
commit
c46b4ad8dc

+ 28 - 1
frontend/src/components/modals/EditPlaylist/components/PlaylistSongItem.vue

@@ -1,5 +1,6 @@
 <template>
 	<div class="universal-item playlist-song-item">
+		<add-to-playlist-dropdown v-if="showPlaylistDropdown" :song="song" />
 		<div id="thumbnail-and-info">
 			<img
 				v-if="song.thumbnail"
@@ -30,17 +31,30 @@
 		</div>
 		<div class="universal-item-actions">
 			<slot name="actions" />
+			<i
+				class="material-icons"
+				@click="showPlaylistDropdown = !showPlaylistDropdown"
+				>queue</i
+			>
 		</div>
 	</div>
 </template>
 
 <script>
+import AddToPlaylistDropdown from "../../../ui/AddToPlaylistDropdown.vue";
+
 export default {
+	components: { AddToPlaylistDropdown },
 	props: {
 		song: {
 			type: Object,
 			default: () => {}
 		}
+	},
+	data() {
+		return {
+			showPlaylistDropdown: false
+		};
 	}
 };
 </script>
@@ -53,6 +67,15 @@ export default {
 	}
 }
 
+/deep/ #nav-dropdown {
+	margin-top: 36px;
+
+	/deep/ .nav-dropdown-items {
+		position: absolute;
+		right: 20px;
+	}
+}
+
 .playlist-song-item {
 	width: 100%;
 
@@ -64,6 +87,10 @@ export default {
 
 	.universal-item-actions {
 		margin-left: 5px;
+
+		i {
+			margin-left: 5px;
+		}
 	}
 
 	.item-thumbnail {
@@ -72,7 +99,7 @@ export default {
 	}
 
 	#thumbnail-and-info {
-		width: calc(100% - 160px);
+		width: calc(100% - 120px);
 	}
 
 	#song-info {

+ 18 - 19
frontend/src/pages/Station/components/AddToPlaylistDropdown.vue → frontend/src/components/ui/AddToPlaylistDropdown.vue

@@ -1,6 +1,10 @@
 <template>
 	<div id="nav-dropdown">
-		<div class="nav-dropdown-items" v-if="playlists.length > 0">
+		<div
+			class="nav-dropdown-items"
+			v-if="playlists.length > 0"
+			v-click-outside="() => (this.$parent.showPlaylistDropdown = false)"
+		>
 			<!-- <a class="nav-item" id="nightmode-toggle">
 				<span>Nightmode</span>
 				<label class="switch">
@@ -37,22 +41,21 @@
 </template>
 
 <script>
-import { mapState } from "vuex";
-
 import Toast from "toasters";
-import io from "../../../io";
+import io from "../../io";
 
 export default {
+	props: {
+		song: {
+			type: Object,
+			default: () => {}
+		}
+	},
 	data() {
 		return {
 			playlists: []
 		};
 	},
-	computed: {
-		...mapState("station", {
-			currentSong: state => state.currentSong
-		})
-	},
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
@@ -95,13 +98,13 @@ export default {
 				this.socket.emit(
 					"playlists.addSongToPlaylist",
 					false,
-					this.currentSong.songId,
+					this.song.songId,
 					playlistId,
 					res => {
 						new Toast({ content: res.message, timeout: 4000 });
 
 						if (res.status === "success") {
-							this.playlists[index].songs.push(this.currentSong);
+							this.playlists[index].songs.push(this.song);
 							this.playlists[index].hasSong = true;
 						}
 					}
@@ -109,7 +112,7 @@ export default {
 			} else {
 				this.socket.emit(
 					"playlists.removeSongFromPlaylist",
-					this.currentSong.songId,
+					this.song.songId,
 					playlistId,
 					res => {
 						new Toast({ content: res.message, timeout: 4000 });
@@ -117,7 +120,7 @@ export default {
 						if (res.status === "success") {
 							this.playlists[index].songs.forEach(
 								(song, index) => {
-									if (song.songId === this.currentSong.songId)
+									if (song.songId === this.song.songId)
 										this.playlists[index].songs.splice(
 											index,
 											1
@@ -136,7 +139,7 @@ export default {
 				let hasSong = false;
 
 				for (let song = 0; song < playlist.songs.length; song += 1) {
-					if (playlist.songs[song].songId === this.currentSong.songId)
+					if (playlist.songs[song].songId === this.song.songId)
 						hasSong = true;
 				}
 
@@ -172,10 +175,7 @@ export default {
 }
 
 #nav-dropdown {
-	position: absolute;
-	margin-left: 4px;
 	z-index: 1;
-	margin-bottom: 36px;
 }
 
 #nav-dropdown-triangle {
@@ -190,8 +190,7 @@ export default {
 	background-color: var(--white);
 	padding: 5px;
 	border-radius: 5px;
-	position: relative;
-	right: calc(100% - 110px);
+	z-index: 1;
 
 	.nav-item {
 		width: 100%;

+ 27 - 4
frontend/src/pages/Station/components/Sidebar/Queue/QueueItem.vue

@@ -1,5 +1,6 @@
 <template>
 	<div class="universal-item queue-item">
+		<add-to-playlist-dropdown v-if="showPlaylistDropdown" :song="song" />
 		<div id="thumbnail-and-info">
 			<img
 				class="item-thumbnail"
@@ -63,7 +64,13 @@
 					"
 					class="material-icons report-icon"
 					@click="reportQueueSong(song)"
-					>flag</i
+				>
+					flag
+				</i>
+				<i
+					class="material-icons"
+					@click="showPlaylistDropdown = !showPlaylistDropdown"
+					>queue</i
 				>
 				<i
 					v-if="
@@ -74,8 +81,9 @@
 					"
 					class="material-icons edit-icon"
 					@click="$parent.$parent.$parent.editSong(song)"
-					>edit</i
 				>
+					edit
+				</i>
 				<i
 					v-if="
 						station.type === 'community' &&
@@ -94,11 +102,12 @@
 import { mapActions } from "vuex";
 import { formatDistance, parseISO } from "date-fns";
 
+import AddToPlaylistDropdown from "../../../../../components/ui/AddToPlaylistDropdown.vue";
 import UserIdToUsername from "../../../../../components/common/UserIdToUsername.vue";
 import utils from "../../../../../../js/utils";
 
 export default {
-	components: { UserIdToUsername },
+	components: { UserIdToUsername, AddToPlaylistDropdown },
 	props: {
 		song: {
 			type: Object,
@@ -113,7 +122,8 @@ export default {
 	},
 	data() {
 		return {
-			utils
+			utils,
+			showPlaylistDropdown: false
 		};
 	},
 	methods: {
@@ -137,6 +147,15 @@ export default {
 	}
 }
 
+/deep/ #nav-dropdown {
+	margin-top: 36px;
+
+	/deep/ .nav-dropdown-items {
+		position: absolute;
+		right: 0;
+	}
+}
+
 .queue-item {
 	#thumbnail-and-info,
 	#duration-and-actions {
@@ -146,6 +165,10 @@ export default {
 
 	#duration-and-actions {
 		margin-left: 5px;
+
+		.universal-item-actions div i {
+			margin-left: 5px;
+		}
 	}
 
 	#thumbnail-and-info {

+ 13 - 1
frontend/src/pages/Station/index.vue

@@ -247,6 +247,7 @@
 										</div>
 										<add-to-playlist-dropdown
 											v-if="showPlaylistDropdown"
+											:song="currentSong"
 										/>
 									</div>
 								</div>
@@ -504,7 +505,7 @@ import MainFooter from "../../components/layout/MainFooter.vue";
 import Z404 from "../404.vue";
 
 import FloatingBox from "../../components/ui/FloatingBox.vue";
-import AddToPlaylistDropdown from "./components/AddToPlaylistDropdown.vue";
+import AddToPlaylistDropdown from "../../components/ui/AddToPlaylistDropdown.vue";
 
 import io from "../../io";
 import keyboardShortcuts from "../../keyboardShortcuts";
@@ -2113,6 +2114,17 @@ export default {
 						display: flex;
 						flex-direction: column-reverse;
 
+						#nav-dropdown {
+							position: absolute;
+							margin-left: 4px;
+							margin-bottom: 36px;
+
+							.nav-dropdown-items {
+								position: relative;
+								right: calc(100% - 110px);
+							}
+						}
+
 						.control {
 							width: fit-content;
 							margin-bottom: 0 !important;