mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-07 11:45:35 +00:00
add functionality to adjust image position
This commit is contained in:
parent
4d4a276ed8
commit
ceedc22843
@ -5,6 +5,7 @@
|
||||
:style="[
|
||||
{
|
||||
backgroundImage: info.image ? `url(${imguri + info.image})` : undefined,
|
||||
backgroundPosition: `center ${bannerPos}%`,
|
||||
},
|
||||
]"
|
||||
:class="{ border: !info.image }"
|
||||
@ -28,7 +29,7 @@
|
||||
<span class="status"
|
||||
>Last updated {{ info.last_updated }}  |  </span
|
||||
>
|
||||
<span class="edit" @click="editPlaylist">Edit  |</span>
|
||||
<div class="edit" @click="editPlaylist">Edit  |</div>
|
||||
<DeleteSvg class="edit" @click="deletePlaylist" />
|
||||
</div>
|
||||
</div>
|
||||
@ -56,7 +57,7 @@ const playlist = usePStore();
|
||||
const imguri = paths.images.playlist;
|
||||
|
||||
const playlistheader = ref<HTMLElement | null>(null);
|
||||
const { info } = storeToRefs(playlist);
|
||||
const { info, bannerPos } = storeToRefs(playlist);
|
||||
|
||||
useVisibility(playlistheader, nav.toggleShowPlay);
|
||||
|
||||
@ -76,6 +77,7 @@ function deletePlaylist() {
|
||||
height: $banner-height;
|
||||
position: relative;
|
||||
background-color: $gray5;
|
||||
background-position: center 50%;
|
||||
|
||||
.gradient {
|
||||
position: absolute;
|
||||
|
@ -23,7 +23,7 @@
|
||||
@change="handleUpload"
|
||||
ref="dropZoneRef"
|
||||
/>
|
||||
<div id="upload" class="rounded-sm" @click="selectFiles">
|
||||
<div id="upload" class="boxed rounded-sm" @click="selectFiles">
|
||||
<div>Click to upload cover image</div>
|
||||
<div
|
||||
id="update-pl-img-preview"
|
||||
@ -35,6 +35,18 @@
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<div class="boxed banner-position-adjust rounded-sm">
|
||||
<div class="t-center">Adjust image position</div>
|
||||
<div class="buttons">
|
||||
<button @click.prevent="pStore.minusBannerPos">
|
||||
<ExpandSvg />
|
||||
</button>
|
||||
<button @click.prevent="pStore.plusBannerPos">
|
||||
<ExpandSvg />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="circular btn-active">
|
||||
{{ clicked ? "Updating" : "Update" }}
|
||||
</button>
|
||||
@ -45,12 +57,14 @@
|
||||
import { onMounted, ref } from "vue";
|
||||
// import { useDropZone } from "@vueuse/core";
|
||||
|
||||
import { updatePlaylist } from "@/composables/fetch/playlists";
|
||||
import { paths } from "@/config";
|
||||
import { Playlist } from "@/interfaces";
|
||||
import usePStore from "@/stores/pages/playlist";
|
||||
import { updatePlaylist } from "@/composables/fetch/playlists";
|
||||
|
||||
import ExpandSvg from "@/assets/icons/expand.svg";
|
||||
const pStore = usePStore();
|
||||
const bannerPos = ref(0);
|
||||
|
||||
const props = defineProps<{
|
||||
playlist: Playlist;
|
||||
@ -140,15 +154,18 @@ function update_playlist(e: Event) {
|
||||
|
||||
<style lang="scss">
|
||||
.new-p-form {
|
||||
.boxed {
|
||||
border: solid 2px $gray3;
|
||||
color: $gray1;
|
||||
place-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr max-content;
|
||||
margin-bottom: $small;
|
||||
}
|
||||
|
||||
#upload {
|
||||
width: 100%;
|
||||
padding: $small;
|
||||
border: solid 2px $gray3;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr max-content;
|
||||
place-items: center;
|
||||
color: $gray1;
|
||||
margin: $small 0;
|
||||
cursor: pointer;
|
||||
|
||||
#update-pl-img-preview {
|
||||
@ -159,5 +176,31 @@ function update_playlist(e: Event) {
|
||||
background-color: $gray4;
|
||||
}
|
||||
}
|
||||
|
||||
.banner-position-adjust {
|
||||
gap: 1rem;
|
||||
padding: $small 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.t-center {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
button {
|
||||
aspect-ratio: 1;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
button:last-child {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
button:first-child {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -32,7 +32,7 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="float-buttons flex" v-if="isQueueTrack">
|
||||
<div class="float-buttons flex">
|
||||
<div
|
||||
:title="is_fav ? 'Add to favorites' : 'Remove from favorites'"
|
||||
@click.stop="() => addToFav(track.trackhash)"
|
||||
@ -40,6 +40,7 @@
|
||||
<HeartSvg :state="is_fav" :no_emit="true" />
|
||||
</div>
|
||||
<div
|
||||
v-if="isQueueTrack"
|
||||
class="remove-track"
|
||||
title="remove from queue"
|
||||
@click.stop="queue.removeFromQueue(index)"
|
||||
|
@ -14,7 +14,7 @@ const {
|
||||
* Creates a new playlist on the server.
|
||||
* @param playlist_name The name of the playlist to create.
|
||||
*/
|
||||
async function createNewPlaylist(playlist_name: string, track?: Track) {
|
||||
export async function createNewPlaylist(playlist_name: string, track?: Track) {
|
||||
const { data, status } = await useAxios({
|
||||
url: newPlaylistUrl,
|
||||
props: {
|
||||
@ -37,7 +37,13 @@ async function createNewPlaylist(playlist_name: string, track?: Track) {
|
||||
};
|
||||
}
|
||||
|
||||
new Notification("That playlist already exists", NotifType.Error);
|
||||
let message = "Something went wrong";
|
||||
|
||||
if (status == 409) {
|
||||
message = "That playlist already exists";
|
||||
}
|
||||
|
||||
new Notification(message, NotifType.Error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@ -49,7 +55,7 @@ async function createNewPlaylist(playlist_name: string, track?: Track) {
|
||||
* Fetches all playlists from the server.
|
||||
* @returns {Promise<Playlist[]>} A promise that resolves to an array of playlists.
|
||||
*/
|
||||
async function getAllPlaylists(): Promise<Playlist[]> {
|
||||
export async function getAllPlaylists(): Promise<Playlist[]> {
|
||||
const { data, error } = await useAxios({
|
||||
url: allPlaylistsUrl,
|
||||
get: true,
|
||||
@ -64,7 +70,7 @@ async function getAllPlaylists(): Promise<Playlist[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async function addTrackToPlaylist(playlist: Playlist, track: Track) {
|
||||
export async function addTrackToPlaylist(playlist: Playlist, track: Track) {
|
||||
const uri = `${basePlaylistUrl}/${playlist.id}/add`;
|
||||
|
||||
const { status } = await useAxios({
|
||||
@ -85,7 +91,7 @@ async function addTrackToPlaylist(playlist: Playlist, track: Track) {
|
||||
);
|
||||
}
|
||||
|
||||
async function getPlaylist(pid: string) {
|
||||
export async function getPlaylist(pid: string) {
|
||||
const uri = `${basePlaylistUrl}/${pid}`;
|
||||
|
||||
interface PlaylistData {
|
||||
@ -109,7 +115,11 @@ async function getPlaylist(pid: string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
async function updatePlaylist(pid: string, playlist: FormData, pStore: any) {
|
||||
export async function updatePlaylist(
|
||||
pid: string,
|
||||
playlist: FormData,
|
||||
pStore: any
|
||||
) {
|
||||
const uri = `${basePlaylistUrl}/${pid}/update`;
|
||||
|
||||
const { data, status } = await useAxios({
|
||||
@ -157,7 +167,6 @@ export async function getPlaylistArtists(pid: string): Promise<Artist[]> {
|
||||
}
|
||||
|
||||
export async function deletePlaylist(pid: string) {
|
||||
console.log(pid);
|
||||
const { status } = await useAxios({
|
||||
url: paths.api.playlist.base + "/delete",
|
||||
props: {
|
||||
@ -170,10 +179,18 @@ export async function deletePlaylist(pid: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
createNewPlaylist,
|
||||
getAllPlaylists,
|
||||
addTrackToPlaylist,
|
||||
getPlaylist,
|
||||
updatePlaylist,
|
||||
};
|
||||
export async function updateBannerPos(pid: number, pos: number) {
|
||||
const { status } = await useAxios({
|
||||
url: paths.api.playlist.base + `/${pid}/set-image-pos`,
|
||||
props: {
|
||||
pos,
|
||||
},
|
||||
});
|
||||
|
||||
if (status === 200) {
|
||||
new Notification("Image position saved", NotifType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
new Notification("Unable to save image position", NotifType.Error);
|
||||
}
|
||||
|
@ -87,6 +87,8 @@ export interface Playlist {
|
||||
last_updated: string;
|
||||
thumb: string;
|
||||
duration: number;
|
||||
has_gif: boolean;
|
||||
banner_pos: number;
|
||||
}
|
||||
|
||||
export interface Notif {
|
||||
|
@ -11,6 +11,7 @@ export default defineStore("playlist-tracks", {
|
||||
state: () => ({
|
||||
info: <Playlist>{},
|
||||
query: "",
|
||||
bannerPos: 0,
|
||||
allTracks: <Track[]>[],
|
||||
artists: <Artist[]>[],
|
||||
}),
|
||||
@ -23,6 +24,7 @@ export default defineStore("playlist-tracks", {
|
||||
const playlist = await getPlaylist(id);
|
||||
|
||||
this.info = playlist?.info || ({} as Playlist);
|
||||
this.bannerPos = this.info.banner_pos;
|
||||
this.allTracks = playlist?.tracks || [];
|
||||
},
|
||||
|
||||
@ -42,6 +44,12 @@ export default defineStore("playlist-tracks", {
|
||||
|
||||
this.info = { ...this.info, duration, count };
|
||||
},
|
||||
plusBannerPos() {
|
||||
this.bannerPos !== 100 ? (this.bannerPos += 10) : null;
|
||||
},
|
||||
minusBannerPos() {
|
||||
this.bannerPos !== 0 ? (this.bannerPos -= 10) : null;
|
||||
},
|
||||
resetArtists() {
|
||||
this.artists = [];
|
||||
},
|
||||
@ -66,5 +74,8 @@ export default defineStore("playlist-tracks", {
|
||||
|
||||
return tracks;
|
||||
},
|
||||
bannerPosUpdated(): boolean {
|
||||
return this.info.banner_pos - this.bannerPos !== 0;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,11 +1,7 @@
|
||||
<template>
|
||||
<div id="p-view" class="content-page">
|
||||
<div class="grid">
|
||||
<PlaylistCard
|
||||
v-for="p in pStore.playlists"
|
||||
:key="p.id"
|
||||
:playlist="p"
|
||||
/>
|
||||
<PlaylistCard v-for="p in pStore.playlists" :key="p.id" :playlist="p" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -24,6 +20,7 @@ const pStore = usePStore();
|
||||
padding-bottom: $content-padding-bottom;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding-right: 1rem;
|
||||
|
||||
.grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(9.25rem, 1fr));
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "@vue/reactivity";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate } from "vue-router";
|
||||
|
||||
import { isMedium, isSmall } from "@/stores/content-width";
|
||||
import usePlaylistStore from "@/stores/pages/playlist";
|
||||
@ -31,6 +31,7 @@ import useQueueStore from "@/stores/queue";
|
||||
|
||||
import Header from "@/components/PlaylistView/Header.vue";
|
||||
import SongItem from "@/components/shared/SongItem.vue";
|
||||
import { updateBannerPos } from "@/composables/fetch/playlists";
|
||||
|
||||
const queue = useQueueStore();
|
||||
const playlist = usePlaylistStore();
|
||||
@ -70,9 +71,16 @@ function playFromPlaylistPage(index: number) {
|
||||
queue.play(index);
|
||||
}
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
[onBeforeRouteLeave, onBeforeRouteUpdate].forEach((guard) => {
|
||||
guard(() => {
|
||||
if (playlist.bannerPosUpdated) {
|
||||
console.log("Update banner pos in server");
|
||||
updateBannerPos(parseInt(playlist.info.id), playlist.bannerPos);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
playlist.resetQuery();
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
60
yarn.lock
60
yarn.lock
@ -2804,36 +2804,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"musicx-v@workspace:.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "musicx-v@workspace:."
|
||||
dependencies:
|
||||
"@formkit/auto-animate": ^1.0.0-beta.3
|
||||
"@popperjs/core": ^2.11.6
|
||||
"@vitejs/plugin-vue": ^3.2.0
|
||||
"@vueuse/components": ^9.2.0
|
||||
"@vueuse/core": ^8.5.0
|
||||
"@vueuse/integrations": ^9.2.0
|
||||
axios: ^0.26.1
|
||||
eslint: ^8.7.0
|
||||
eslint-plugin-vue: ^8.3.0
|
||||
fuse.js: ^6.6.2
|
||||
pinia: ^2.0.17
|
||||
pinia-plugin-persistedstate: ^2.1.1
|
||||
sass: ^1.56.1
|
||||
sass-loader: ^13.2.0
|
||||
vite: ^3.0.4
|
||||
vite-svg-loader: ^3.4.0
|
||||
vue: ^3.2.37
|
||||
vue-debounce: ^3.0.2
|
||||
vue-router: ^4.1.3
|
||||
vue-svg-loader: ^0.16.0
|
||||
vue-template-compiler: ^2.0.0
|
||||
vue-virtual-scroller: ^2.0.0-alpha.1
|
||||
webpack: ^5.74.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"nanoid@npm:^3.2.0":
|
||||
version: 3.2.0
|
||||
resolution: "nanoid@npm:3.2.0"
|
||||
@ -3639,6 +3609,36 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"swing_music_client@workspace:.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "swing_music_client@workspace:."
|
||||
dependencies:
|
||||
"@formkit/auto-animate": ^1.0.0-beta.3
|
||||
"@popperjs/core": ^2.11.6
|
||||
"@vitejs/plugin-vue": ^3.2.0
|
||||
"@vueuse/components": ^9.2.0
|
||||
"@vueuse/core": ^8.5.0
|
||||
"@vueuse/integrations": ^9.2.0
|
||||
axios: ^0.26.1
|
||||
eslint: ^8.7.0
|
||||
eslint-plugin-vue: ^8.3.0
|
||||
fuse.js: ^6.6.2
|
||||
pinia: ^2.0.17
|
||||
pinia-plugin-persistedstate: ^2.1.1
|
||||
sass: ^1.56.1
|
||||
sass-loader: ^13.2.0
|
||||
vite: ^3.0.4
|
||||
vite-svg-loader: ^3.4.0
|
||||
vue: ^3.2.37
|
||||
vue-debounce: ^3.0.2
|
||||
vue-router: ^4.1.3
|
||||
vue-svg-loader: ^0.16.0
|
||||
vue-template-compiler: ^2.0.0
|
||||
vue-virtual-scroller: ^2.0.0-alpha.1
|
||||
webpack: ^5.74.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"tapable@npm:^2.1.1, tapable@npm:^2.2.0":
|
||||
version: 2.2.1
|
||||
resolution: "tapable@npm:2.2.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user