Pārlūkot izejas kodu

Merge branch 'polishing' into dependabot/npm_and_yarn/backend/axios-0.21.2

Kristian Vos 3 gadi atpakaļ
vecāks
revīzija
14fb97ddeb

+ 3 - 3
frontend/package-lock.json

@@ -6214,9 +6214,9 @@
       }
     },
     "nth-check": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
-      "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
+      "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
       "requires": {
         "boolbase": "^1.0.0"
       }

+ 16 - 2
frontend/src/App.vue

@@ -1092,7 +1092,7 @@ h4.section-title {
 	transition: all 0.3s ease;
 }
 
-.steps-fade-enter,
+.steps-fade-enter-from,
 .steps-fade-leave-to {
 	opacity: 0;
 }
@@ -1123,7 +1123,7 @@ h4.section-title {
 		min-height: 50px;
 		background-color: var(--white);
 		font-size: 30px;
-		cursor: pointer;
+		user-select: none;
 
 		&.selected {
 			background-color: var(--primary-color);
@@ -1141,6 +1141,20 @@ h4.section-title {
 	}
 }
 
+/* This class is used for content-box in ResetPassword, but not in RemoveAccount. This is because ResetPassword uses transitions and RemoveAccount does not */
+.content-box-wrapper {
+	position: relative;
+	width: 100%;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	min-height: 200px;
+
+	.content-box {
+		position: absolute;
+	}
+}
+
 .content-box {
 	margin-top: 90px;
 	border-radius: 3px;

+ 2 - 1
frontend/src/components/FloatingBox.vue

@@ -174,8 +174,9 @@ export default {
 	.box-body {
 		display: flex;
 		flex-wrap: wrap;
-		justify-content: space-evenly;
 		padding: 10px;
+		height: calc(100% - 24px); /* 24px is the height of the box-header */
+		overflow: auto;
 
 		span {
 			padding: 3px 6px;

+ 12 - 4
frontend/src/components/SearchQueryItem.vue

@@ -46,20 +46,28 @@ export default {
 </script>
 
 <style lang="scss">
-.search-query-actions-enter-active {
+.search-query-actions-enter-active,
+.musare-search-query-actions-enter-active,
+.youtube-search-query-actions-enter-active {
 	transition: all 0.2s ease;
 }
 
-.search-query-actions-leave-active {
+.search-query-actions-leave-active,
+.musare-search-query-actions-leave-active,
+.youtube-search-query-actions-leave-active {
 	transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
 }
 
-.search-query-actions-enter {
+.search-query-actions-enter,
+.musare-search-query-actions-enter,
+.youtube-search-query-actions-enter {
 	transform: translateX(-20px);
 	opacity: 0;
 }
 
-.search-query-actions-leave-to {
+.search-query-actions-leave-to,
+.musare-search-query-actions-leave-to,
+.youtube-search-query-actions-leave-to {
 	transform: translateX(20px);
 	opacity: 0;
 }

+ 5 - 1
frontend/src/components/modals/EditPlaylist/index.vue

@@ -585,7 +585,9 @@ export default {
 		},
 		...mapActions({
 			showTab(dispatch, payload) {
-				this.$refs[`${payload}-tab`].scrollIntoView();
+				this.$refs[`${payload}-tab`].scrollIntoView({
+					block: "nearest"
+				});
 				return dispatch("modals/editPlaylist/showTab", payload);
 			}
 		}),
@@ -605,6 +607,8 @@ export default {
 .edit-playlist-modal {
 	.modal-card {
 		width: 1300px;
+		height: 100%;
+		overflow: auto;
 
 		.modal-card-body {
 			padding: 16px;

+ 1 - 1
frontend/src/components/modals/EditSong/Tabs/Reports.vue

@@ -279,7 +279,7 @@ export default {
 	},
 	methods: {
 		showTab(tab) {
-			this.$refs[`${tab}-tab`].scrollIntoView();
+			this.$refs[`${tab}-tab`].scrollIntoView({ block: "nearest" });
 			this.tab = tab;
 		},
 		resolve(reportId) {

+ 3 - 1
frontend/src/components/modals/EditSong/index.vue

@@ -1566,7 +1566,9 @@ export default {
 		]),
 		...mapActions({
 			showTab(dispatch, payload) {
-				this.$refs[`${payload}-tab`].scrollIntoView();
+				this.$refs[`${payload}-tab`].scrollIntoView({
+					block: "nearest"
+				});
 				return dispatch("modals/editSong/showTab", payload);
 			}
 		}),

+ 2 - 2
frontend/src/components/modals/Login.vue

@@ -70,12 +70,12 @@
 							<router-link to="/terms" @click="closeLoginModal()">
 								Terms of Service
 							</router-link>
-							&nbsp;and
+							and
 							<router-link
 								to="/privacy"
 								@click="closeLoginModal()"
 							>
-								Privacy Policy </router-link
+								Privacy Policy</router-link
 							>.
 						</p>
 					</form>

+ 2 - 2
frontend/src/components/modals/ManageStation/Tabs/Playlists.vue

@@ -740,7 +740,7 @@ export default {
 			);
 		},
 		showTab(tab) {
-			this.$refs[`${tab}-tab`].scrollIntoView();
+			this.$refs[`${tab}-tab`].scrollIntoView({ block: "nearest" });
 			this.tab = tab;
 		},
 		isOwner() {
@@ -885,8 +885,8 @@ export default {
 			this.search.searchedQuery = this.search.query;
 			this.socket.dispatch(action, query, page, res => {
 				const { data } = res;
-				const { count, pageSize, playlists } = data;
 				if (res.status === "success") {
+					const { count, pageSize, playlists } = data;
 					this.search.results = [
 						...this.search.results,
 						...playlists

+ 53 - 34
frontend/src/components/modals/ManageStation/Tabs/Songs.vue

@@ -65,14 +65,33 @@
 							:song="song"
 						>
 							<template #actions>
-								<i
-									class="material-icons add-to-queue-icon"
-									v-if="station.partyMode && !station.locked"
-									@click="addSongToQueue(song.youtubeId)"
-									content="Add Song to Queue"
-									v-tippy
-									>queue</i
+								<transition
+									name="musare-search-query-actions"
+									mode="out-in"
 								>
+									<i
+										v-if="
+											songsInQueue.indexOf(
+												song.youtubeId
+											) !== -1
+										"
+										class="
+											material-icons
+											added-to-playlist-icon
+										"
+										content="Song is already in queue"
+										v-tippy
+										>done</i
+									>
+									<i
+										v-else
+										class="material-icons add-to-queue-icon"
+										@click="addSongToQueue(song.youtubeId)"
+										content="Add Song to Queue"
+										v-tippy
+										>queue</i
+									>
+								</transition>
 							</template>
 						</song-item>
 						<button
@@ -121,40 +140,32 @@
 						>
 							<template #actions>
 								<transition
-									name="search-query-actions"
+									name="youtube-search-query-actions"
 									mode="out-in"
 								>
-									<a
-										class="button is-success"
-										v-if="result.isAddedToQueue"
-										key="added-to-queue"
+									<i
+										v-if="
+											songsInQueue.indexOf(result.id) !==
+											-1
+										"
+										class="
+											material-icons
+											added-to-playlist-icon
+										"
+										content="Song is already in queue"
+										v-tippy
+										>done</i
 									>
-										<i
-											class="
-												material-icons
-												icon-with-button
-											"
-											>done</i
-										>
-										Added to queue
-									</a>
-									<a
-										class="button is-dark"
+									<i
 										v-else
-										@click.prevent="
+										class="material-icons add-to-queue-icon"
+										@click="
 											addSongToQueue(result.id, index)
 										"
-										key="add-to-queue"
+										content="Add Song to Queue"
+										v-tippy
+										>queue</i
 									>
-										<i
-											class="
-												material-icons
-												icon-with-button
-											"
-											>add</i
-										>
-										Add to queue
-									</a>
 								</transition>
 							</template>
 						</search-query-item>
@@ -252,6 +263,13 @@ export default {
 		excludedSongIds() {
 			return this.excludedSongs.map(excludedSong => excludedSong._id);
 		},
+		songsInQueue() {
+			if (this.station.currentSong)
+				return this.songsList
+					.map(song => song.youtubeId)
+					.concat(this.station.currentSong.youtubeId);
+			return this.songsList.map(song => song.youtubeId);
+		},
 		...mapState({
 			loggedIn: state => state.user.auth.loggedIn,
 			userId: state => state.user.auth.userId,
@@ -261,6 +279,7 @@ export default {
 			parentTab: state => state.tab,
 			station: state => state.station,
 			originalStation: state => state.originalStation,
+			songsList: state => state.songsList,
 			excludedPlaylists: state => state.excludedPlaylists,
 			stationPlaylist: state => state.stationPlaylist
 		}),

+ 3 - 1
frontend/src/components/modals/ManageStation/index.vue

@@ -644,7 +644,9 @@ export default {
 		...mapActions({
 			showTab(dispatch, payload) {
 				if (this.$refs[`${payload}-tab`])
-					this.$refs[`${payload}-tab`].scrollIntoView(); // Only works if the ref exists, which it doesn't always
+					this.$refs[`${payload}-tab`].scrollIntoView({
+						block: "nearest"
+					}); // Only works if the ref exists, which it doesn't always
 				return dispatch("modals/manageStation/showTab", payload);
 			}
 		}),

+ 2 - 2
frontend/src/components/modals/Register.vue

@@ -104,12 +104,12 @@
 						<router-link to="/terms" @click="closeRegisterModal()">
 							Terms of Service
 						</router-link>
-						&nbsp;and
+						and
 						<router-link
 							to="/privacy"
 							@click="closeRegisterModal()"
 						>
-							Privacy Policy </router-link
+							Privacy Policy</router-link
 						>.
 					</p>
 				</section>

+ 2 - 1
frontend/src/pages/Admin/index.vue

@@ -218,7 +218,8 @@ export default {
 		showTab(tab) {
 			if (this.$refs[`${tab}-tab`])
 				this.$refs[`${tab}-tab`].scrollIntoView({
-					inline: "center"
+					inline: "center",
+					block: "nearest"
 				});
 			this.currentTab = tab;
 		}

+ 242 - 221
frontend/src/pages/ResetPassword.vue

@@ -18,252 +18,267 @@
 					<p class="step" :class="{ selected: step === 3 }">3</p>
 				</div>
 
-				<transition-group name="steps-fade" mode="out-in">
-					<!-- Step 1 -- Enter email address -->
-					<div class="content-box" v-if="step === 1" :key="step">
-						<h2 class="content-box-title">
-							Enter your email address
-						</h2>
-						<p class="content-box-description">
-							We will send a code to your email address to verify
-							your identity.
-						</p>
-
-						<p class="content-box-optional-helper">
-							<a href="#" @click="step = 2"
-								>Already have a code?</a
-							>
-						</p>
+				<div class="content-box-wrapper">
+					<transition-group name="steps-fade" mode="out-in">
+						<!-- Step 1 -- Enter email address -->
+						<div class="content-box" v-if="step === 1" key="1">
+							<h2 class="content-box-title">
+								Enter your email address
+							</h2>
+							<p class="content-box-description">
+								We will send a code to your email address to
+								verify your identity.
+							</p>
 
-						<div class="content-box-inputs">
-							<div class="control is-grouped input-with-button">
-								<p class="control is-expanded">
-									<input
-										class="input"
-										type="email"
-										placeholder="Enter email address here..."
-										autofocus
-										v-model="email.value"
-										@keyup.enter="submitEmail()"
-										@keypress="onInput('email')"
-										@paste="onInput('email')"
+							<p class="content-box-optional-helper">
+								<a href="#" @click="step = 2"
+									>Already have a code?</a
+								>
+							</p>
+
+							<div class="content-box-inputs">
+								<div
+									class="control is-grouped input-with-button"
+								>
+									<p class="control is-expanded">
+										<input
+											class="input"
+											type="email"
+											placeholder="Enter email address here..."
+											autofocus
+											v-model="email.value"
+											@keyup.enter="submitEmail()"
+											@keypress="onInput('email')"
+											@paste="onInput('email')"
+										/>
+									</p>
+									<p class="control">
+										<a
+											class="button is-info"
+											href="#"
+											@click="submitEmail()"
+											><i
+												class="
+													material-icons
+													icon-with-button
+												"
+												>mail</i
+											>Request</a
+										>
+									</p>
+								</div>
+								<transition name="fadein-helpbox">
+									<input-help-box
+										:entered="email.entered"
+										:valid="email.valid"
+										:message="email.message"
 									/>
-								</p>
-								<p class="control">
-									<a
-										class="button is-info"
-										href="#"
-										@click="submitEmail()"
-										><i
-											class="
-												material-icons
-												icon-with-button
-											"
-											>mail</i
-										>Request</a
-									>
-								</p>
+								</transition>
 							</div>
-							<transition name="fadein-helpbox">
-								<input-help-box
-									:entered="email.entered"
-									:valid="email.valid"
-									:message="email.message"
-								/>
-							</transition>
 						</div>
-					</div>
-
-					<!-- Step 2 -- Enter code -->
-					<div class="content-box" v-if="step === 2" :key="step">
-						<h2 class="content-box-title">
-							Enter the code sent to your email
-						</h2>
-						<p
-							class="content-box-description"
-							v-if="!email.hasBeenSentAlready"
-						>
-							A code has been sent to
-							<strong>{{ email.value }}.</strong>
-						</p>
 
-						<p class="content-box-optional-helper">
-							<a
-								href="#"
-								@click="
-									email.value ? submitEmail() : (step = 1)
-								"
-								>Request another code</a
+						<!-- Step 2 -- Enter code -->
+						<div class="content-box" v-if="step === 2" key="2">
+							<h2 class="content-box-title">
+								Enter the code sent to your email
+							</h2>
+							<p
+								class="content-box-description"
+								v-if="!email.hasBeenSentAlready"
 							>
-						</p>
-
-						<div class="content-box-inputs">
-							<div class="control is-grouped input-with-button">
-								<p class="control is-expanded">
-									<input
-										class="input"
-										type="text"
-										placeholder="Enter code here..."
-										autofocus
-										v-model="code"
-										@keyup.enter="verifyCode()"
-									/>
-								</p>
-								<p class="control">
-									<a
-										class="button is-info"
-										href="#"
-										@click="verifyCode()"
-										><i
-											class="
-												material-icons
-												icon-with-button
-											"
-											>vpn_key</i
-										>Verify</a
-									>
-								</p>
-							</div>
-						</div>
-					</div>
-
-					<!-- Step 3 -- Set new password -->
-					<div class="content-box" v-if="step === 3" :key="step">
-						<h2 class="content-box-title">Set a new password</h2>
-						<p class="content-box-description">
-							Create a new password for your account.
-						</p>
-
-						<div class="content-box-inputs">
-							<p class="control is-expanded">
-								<label for="new-password">New password</label>
+								A code has been sent to
+								<strong>{{ email.value }}.</strong>
 							</p>
 
-							<div id="password-visibility-container">
-								<input
-									class="input"
-									id="new-password"
-									type="password"
-									ref="password"
-									placeholder="Enter password here..."
-									v-model="password.value"
-									@keypress="onInput('password')"
-									@paste="onInput('password')"
-								/>
+							<p class="content-box-optional-helper">
 								<a
+									href="#"
 									@click="
-										togglePasswordVisibility('password')
+										email.value ? submitEmail() : (step = 1)
 									"
+									>Request another code</a
 								>
-									<i class="material-icons">
-										{{
-											!password.visible
-												? "visibility"
-												: "visibility_off"
-										}}
-									</i>
-								</a>
+							</p>
+
+							<div class="content-box-inputs">
+								<div
+									class="control is-grouped input-with-button"
+								>
+									<p class="control is-expanded">
+										<input
+											class="input"
+											type="text"
+											placeholder="Enter code here..."
+											autofocus
+											v-model="code"
+											@keyup.enter="verifyCode()"
+										/>
+									</p>
+									<p class="control">
+										<a
+											class="button is-info"
+											href="#"
+											@click="verifyCode()"
+											><i
+												class="
+													material-icons
+													icon-with-button
+												"
+												>vpn_key</i
+											>Verify</a
+										>
+									</p>
+								</div>
 							</div>
+						</div>
 
-							<transition name="fadein-helpbox">
-								<input-help-box
-									:entered="password.entered"
-									:valid="password.valid"
-									:message="password.message"
-								/>
-							</transition>
+						<!-- Step 3 -- Set new password -->
+						<div class="content-box" v-if="step === 3" key="3">
+							<h2 class="content-box-title">
+								Set a new password
+							</h2>
+							<p class="content-box-description">
+								Create a new password for your account.
+							</p>
 
-							<p
-								id="new-password-again-input"
-								class="control is-expanded"
-							>
-								<label for="new-password-again"
-									>New password again</label
+							<div class="content-box-inputs">
+								<p class="control is-expanded">
+									<label for="new-password"
+										>New password</label
+									>
+								</p>
+
+								<div id="password-visibility-container">
+									<input
+										class="input"
+										id="new-password"
+										type="password"
+										ref="password"
+										placeholder="Enter password here..."
+										v-model="password.value"
+										@keypress="onInput('password')"
+										@paste="onInput('password')"
+									/>
+									<a
+										@click="
+											togglePasswordVisibility('password')
+										"
+									>
+										<i class="material-icons">
+											{{
+												!password.visible
+													? "visibility"
+													: "visibility_off"
+											}}
+										</i>
+									</a>
+								</div>
+
+								<transition name="fadein-helpbox">
+									<input-help-box
+										:entered="password.entered"
+										:valid="password.valid"
+										:message="password.message"
+									/>
+								</transition>
+
+								<p
+									id="new-password-again-input"
+									class="control is-expanded"
 								>
-							</p>
+									<label for="new-password-again"
+										>New password again</label
+									>
+								</p>
+
+								<div id="password-visibility-container">
+									<input
+										class="input"
+										id="new-password-again"
+										type="password"
+										ref="passwordAgain"
+										placeholder="Enter password here..."
+										v-model="passwordAgain.value"
+										@keyup.enter="changePassword()"
+										@keypress="onInput('passwordAgain')"
+										@paste="onInput('passwordAgain')"
+									/>
+									<a
+										@click="
+											togglePasswordVisibility(
+												'passwordAgain'
+											)
+										"
+									>
+										<i class="material-icons">
+											{{
+												!passwordAgain.visible
+													? "visibility"
+													: "visibility_off"
+											}}
+										</i>
+									</a>
+								</div>
+
+								<transition name="fadein-helpbox">
+									<input-help-box
+										:entered="passwordAgain.entered"
+										:valid="passwordAgain.valid"
+										:message="passwordAgain.message"
+									/>
+								</transition>
 
-							<div id="password-visibility-container">
-								<input
-									class="input"
-									id="new-password-again"
-									type="password"
-									ref="passwordAgain"
-									placeholder="Enter password here..."
-									v-model="passwordAgain.value"
-									@keyup.enter="changePassword()"
-									@keypress="onInput('passwordAgain')"
-									@paste="onInput('passwordAgain')"
-								/>
 								<a
-									@click="
-										togglePasswordVisibility(
-											'passwordAgain'
-										)
-									"
+									id="change-password-button"
+									class="button is-success"
+									href="#"
+									@click="changePassword()"
+								>
+									Change password</a
 								>
-									<i class="material-icons">
-										{{
-											!passwordAgain.visible
-												? "visibility"
-												: "visibility_off"
-										}}
-									</i>
-								</a>
 							</div>
+						</div>
 
-							<transition name="fadein-helpbox">
-								<input-help-box
-									:entered="passwordAgain.entered"
-									:valid="passwordAgain.valid"
-									:message="passwordAgain.message"
-								/>
-							</transition>
-
-							<a
-								id="change-password-button"
-								class="button is-success"
-								href="#"
-								@click="changePassword()"
+						<div
+							class="content-box reset-status-box"
+							v-if="step === 4"
+							key="4"
+						>
+							<i class="material-icons success-icon"
+								>check_circle</i
 							>
-								Change password</a
+							<h2>Password successfully {{ mode }}</h2>
+							<router-link
+								class="button is-dark"
+								href="#"
+								to="/settings"
+								><i class="material-icons icon-with-button"
+									>undo</i
+								>Return to Settings</router-link
 							>
 						</div>
-					</div>
-
-					<div
-						class="content-box reset-status-box"
-						v-if="step === 4"
-						:key="step"
-					>
-						<i class="material-icons success-icon">check_circle</i>
-						<h2>Password successfully {{ mode }}</h2>
-						<router-link
-							class="button is-dark"
-							href="#"
-							to="/settings"
-							><i class="material-icons icon-with-button">undo</i
-							>Return to Settings</router-link
-						>
-					</div>
-
-					<div
-						class="content-box reset-status-box"
-						v-if="step === 5"
-						:key="step"
-					>
-						<i class="material-icons error-icon">error</i>
-						<h2>
-							Password {{ mode }} failed, please try again later
-						</h2>
-						<router-link
-							class="button is-dark"
-							href="#"
-							to="/settings"
-							><i class="material-icons icon-with-button">undo</i
-							>Return to Settings</router-link
+
+						<div
+							class="content-box reset-status-box"
+							v-if="step === 5"
+							key="5"
 						>
-					</div>
-				</transition-group>
+							<i class="material-icons error-icon">error</i>
+							<h2>
+								Password {{ mode }} failed, please try again
+								later
+							</h2>
+							<router-link
+								class="button is-dark"
+								href="#"
+								to="/settings"
+								><i class="material-icons icon-with-button"
+									>undo</i
+								>Return to Settings</router-link
+							>
+						</div>
+					</transition-group>
+				</div>
 			</div>
 		</div>
 		<main-footer />
@@ -475,6 +490,12 @@ p {
 	margin: 0;
 }
 
+.content-wrapper {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+}
+
 .container {
 	padding: 25px;