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="[
|
:style="[
|
||||||
{
|
{
|
||||||
backgroundImage: info.image ? `url(${imguri + info.image})` : undefined,
|
backgroundImage: info.image ? `url(${imguri + info.image})` : undefined,
|
||||||
|
backgroundPosition: `center ${bannerPos}%`,
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
:class="{ border: !info.image }"
|
:class="{ border: !info.image }"
|
||||||
@ -28,7 +29,7 @@
|
|||||||
<span class="status"
|
<span class="status"
|
||||||
>Last updated {{ info.last_updated }}  |  </span
|
>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" />
|
<DeleteSvg class="edit" @click="deletePlaylist" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -56,7 +57,7 @@ const playlist = usePStore();
|
|||||||
const imguri = paths.images.playlist;
|
const imguri = paths.images.playlist;
|
||||||
|
|
||||||
const playlistheader = ref<HTMLElement | null>(null);
|
const playlistheader = ref<HTMLElement | null>(null);
|
||||||
const { info } = storeToRefs(playlist);
|
const { info, bannerPos } = storeToRefs(playlist);
|
||||||
|
|
||||||
useVisibility(playlistheader, nav.toggleShowPlay);
|
useVisibility(playlistheader, nav.toggleShowPlay);
|
||||||
|
|
||||||
@ -76,6 +77,7 @@ function deletePlaylist() {
|
|||||||
height: $banner-height;
|
height: $banner-height;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: $gray5;
|
background-color: $gray5;
|
||||||
|
background-position: center 50%;
|
||||||
|
|
||||||
.gradient {
|
.gradient {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
@change="handleUpload"
|
@change="handleUpload"
|
||||||
ref="dropZoneRef"
|
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>Click to upload cover image</div>
|
||||||
<div
|
<div
|
||||||
id="update-pl-img-preview"
|
id="update-pl-img-preview"
|
||||||
@ -35,6 +35,18 @@
|
|||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<button class="circular btn-active">
|
||||||
{{ clicked ? "Updating" : "Update" }}
|
{{ clicked ? "Updating" : "Update" }}
|
||||||
</button>
|
</button>
|
||||||
@ -45,12 +57,14 @@
|
|||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
// import { useDropZone } from "@vueuse/core";
|
// import { useDropZone } from "@vueuse/core";
|
||||||
|
|
||||||
import { updatePlaylist } from "@/composables/fetch/playlists";
|
|
||||||
import { paths } from "@/config";
|
import { paths } from "@/config";
|
||||||
import { Playlist } from "@/interfaces";
|
import { Playlist } from "@/interfaces";
|
||||||
import usePStore from "@/stores/pages/playlist";
|
import usePStore from "@/stores/pages/playlist";
|
||||||
|
import { updatePlaylist } from "@/composables/fetch/playlists";
|
||||||
|
|
||||||
|
import ExpandSvg from "@/assets/icons/expand.svg";
|
||||||
const pStore = usePStore();
|
const pStore = usePStore();
|
||||||
|
const bannerPos = ref(0);
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
playlist: Playlist;
|
playlist: Playlist;
|
||||||
@ -140,15 +154,18 @@ function update_playlist(e: Event) {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.new-p-form {
|
.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 {
|
#upload {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: $small;
|
padding: $small;
|
||||||
border: solid 2px $gray3;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr max-content;
|
|
||||||
place-items: center;
|
|
||||||
color: $gray1;
|
|
||||||
margin: $small 0;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
#update-pl-img-preview {
|
#update-pl-img-preview {
|
||||||
@ -159,5 +176,31 @@ function update_playlist(e: Event) {
|
|||||||
background-color: $gray4;
|
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>
|
</style>
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="float-buttons flex" v-if="isQueueTrack">
|
<div class="float-buttons flex">
|
||||||
<div
|
<div
|
||||||
:title="is_fav ? 'Add to favorites' : 'Remove from favorites'"
|
:title="is_fav ? 'Add to favorites' : 'Remove from favorites'"
|
||||||
@click.stop="() => addToFav(track.trackhash)"
|
@click.stop="() => addToFav(track.trackhash)"
|
||||||
@ -40,6 +40,7 @@
|
|||||||
<HeartSvg :state="is_fav" :no_emit="true" />
|
<HeartSvg :state="is_fav" :no_emit="true" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
v-if="isQueueTrack"
|
||||||
class="remove-track"
|
class="remove-track"
|
||||||
title="remove from queue"
|
title="remove from queue"
|
||||||
@click.stop="queue.removeFromQueue(index)"
|
@click.stop="queue.removeFromQueue(index)"
|
||||||
|
@ -14,7 +14,7 @@ const {
|
|||||||
* Creates a new playlist on the server.
|
* Creates a new playlist on the server.
|
||||||
* @param playlist_name The name of the playlist to create.
|
* @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({
|
const { data, status } = await useAxios({
|
||||||
url: newPlaylistUrl,
|
url: newPlaylistUrl,
|
||||||
props: {
|
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 {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
@ -49,7 +55,7 @@ async function createNewPlaylist(playlist_name: string, track?: Track) {
|
|||||||
* Fetches all playlists from the server.
|
* Fetches all playlists from the server.
|
||||||
* @returns {Promise<Playlist[]>} A promise that resolves to an array of playlists.
|
* @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({
|
const { data, error } = await useAxios({
|
||||||
url: allPlaylistsUrl,
|
url: allPlaylistsUrl,
|
||||||
get: true,
|
get: true,
|
||||||
@ -64,7 +70,7 @@ async function getAllPlaylists(): Promise<Playlist[]> {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addTrackToPlaylist(playlist: Playlist, track: Track) {
|
export async function addTrackToPlaylist(playlist: Playlist, track: Track) {
|
||||||
const uri = `${basePlaylistUrl}/${playlist.id}/add`;
|
const uri = `${basePlaylistUrl}/${playlist.id}/add`;
|
||||||
|
|
||||||
const { status } = await useAxios({
|
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}`;
|
const uri = `${basePlaylistUrl}/${pid}`;
|
||||||
|
|
||||||
interface PlaylistData {
|
interface PlaylistData {
|
||||||
@ -109,7 +115,11 @@ async function getPlaylist(pid: string) {
|
|||||||
return null;
|
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 uri = `${basePlaylistUrl}/${pid}/update`;
|
||||||
|
|
||||||
const { data, status } = await useAxios({
|
const { data, status } = await useAxios({
|
||||||
@ -157,7 +167,6 @@ export async function getPlaylistArtists(pid: string): Promise<Artist[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function deletePlaylist(pid: string) {
|
export async function deletePlaylist(pid: string) {
|
||||||
console.log(pid);
|
|
||||||
const { status } = await useAxios({
|
const { status } = await useAxios({
|
||||||
url: paths.api.playlist.base + "/delete",
|
url: paths.api.playlist.base + "/delete",
|
||||||
props: {
|
props: {
|
||||||
@ -170,10 +179,18 @@ export async function deletePlaylist(pid: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export async function updateBannerPos(pid: number, pos: number) {
|
||||||
createNewPlaylist,
|
const { status } = await useAxios({
|
||||||
getAllPlaylists,
|
url: paths.api.playlist.base + `/${pid}/set-image-pos`,
|
||||||
addTrackToPlaylist,
|
props: {
|
||||||
getPlaylist,
|
pos,
|
||||||
updatePlaylist,
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
|
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;
|
last_updated: string;
|
||||||
thumb: string;
|
thumb: string;
|
||||||
duration: number;
|
duration: number;
|
||||||
|
has_gif: boolean;
|
||||||
|
banner_pos: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Notif {
|
export interface Notif {
|
||||||
|
@ -11,6 +11,7 @@ export default defineStore("playlist-tracks", {
|
|||||||
state: () => ({
|
state: () => ({
|
||||||
info: <Playlist>{},
|
info: <Playlist>{},
|
||||||
query: "",
|
query: "",
|
||||||
|
bannerPos: 0,
|
||||||
allTracks: <Track[]>[],
|
allTracks: <Track[]>[],
|
||||||
artists: <Artist[]>[],
|
artists: <Artist[]>[],
|
||||||
}),
|
}),
|
||||||
@ -23,6 +24,7 @@ export default defineStore("playlist-tracks", {
|
|||||||
const playlist = await getPlaylist(id);
|
const playlist = await getPlaylist(id);
|
||||||
|
|
||||||
this.info = playlist?.info || ({} as Playlist);
|
this.info = playlist?.info || ({} as Playlist);
|
||||||
|
this.bannerPos = this.info.banner_pos;
|
||||||
this.allTracks = playlist?.tracks || [];
|
this.allTracks = playlist?.tracks || [];
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -42,6 +44,12 @@ export default defineStore("playlist-tracks", {
|
|||||||
|
|
||||||
this.info = { ...this.info, duration, count };
|
this.info = { ...this.info, duration, count };
|
||||||
},
|
},
|
||||||
|
plusBannerPos() {
|
||||||
|
this.bannerPos !== 100 ? (this.bannerPos += 10) : null;
|
||||||
|
},
|
||||||
|
minusBannerPos() {
|
||||||
|
this.bannerPos !== 0 ? (this.bannerPos -= 10) : null;
|
||||||
|
},
|
||||||
resetArtists() {
|
resetArtists() {
|
||||||
this.artists = [];
|
this.artists = [];
|
||||||
},
|
},
|
||||||
@ -66,5 +74,8 @@ export default defineStore("playlist-tracks", {
|
|||||||
|
|
||||||
return tracks;
|
return tracks;
|
||||||
},
|
},
|
||||||
|
bannerPosUpdated(): boolean {
|
||||||
|
return this.info.banner_pos - this.bannerPos !== 0;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="p-view" class="content-page">
|
<div id="p-view" class="content-page">
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<PlaylistCard
|
<PlaylistCard v-for="p in pStore.playlists" :key="p.id" :playlist="p" />
|
||||||
v-for="p in pStore.playlists"
|
|
||||||
:key="p.id"
|
|
||||||
:playlist="p"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -24,6 +20,7 @@ const pStore = usePStore();
|
|||||||
padding-bottom: $content-padding-bottom;
|
padding-bottom: $content-padding-bottom;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
padding-right: 1rem;
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(9.25rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(9.25rem, 1fr));
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "@vue/reactivity";
|
import { computed } from "@vue/reactivity";
|
||||||
import { onBeforeRouteLeave } from "vue-router";
|
import { onBeforeRouteLeave, onBeforeRouteUpdate } from "vue-router";
|
||||||
|
|
||||||
import { isMedium, isSmall } from "@/stores/content-width";
|
import { isMedium, isSmall } from "@/stores/content-width";
|
||||||
import usePlaylistStore from "@/stores/pages/playlist";
|
import usePlaylistStore from "@/stores/pages/playlist";
|
||||||
@ -31,6 +31,7 @@ import useQueueStore from "@/stores/queue";
|
|||||||
|
|
||||||
import Header from "@/components/PlaylistView/Header.vue";
|
import Header from "@/components/PlaylistView/Header.vue";
|
||||||
import SongItem from "@/components/shared/SongItem.vue";
|
import SongItem from "@/components/shared/SongItem.vue";
|
||||||
|
import { updateBannerPos } from "@/composables/fetch/playlists";
|
||||||
|
|
||||||
const queue = useQueueStore();
|
const queue = useQueueStore();
|
||||||
const playlist = usePlaylistStore();
|
const playlist = usePlaylistStore();
|
||||||
@ -70,9 +71,16 @@ function playFromPlaylistPage(index: number) {
|
|||||||
queue.play(index);
|
queue.play(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeRouteLeave(() => {
|
[onBeforeRouteLeave, onBeforeRouteUpdate].forEach((guard) => {
|
||||||
setTimeout(() => {
|
guard(() => {
|
||||||
playlist.resetQuery();
|
if (playlist.bannerPosUpdated) {
|
||||||
}, 500);
|
console.log("Update banner pos in server");
|
||||||
|
updateBannerPos(parseInt(playlist.info.id), playlist.bannerPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
playlist.resetQuery();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
60
yarn.lock
60
yarn.lock
@ -2804,36 +2804,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"nanoid@npm:^3.2.0":
|
||||||
version: 3.2.0
|
version: 3.2.0
|
||||||
resolution: "nanoid@npm:3.2.0"
|
resolution: "nanoid@npm:3.2.0"
|
||||||
@ -3639,6 +3609,36 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"tapable@npm:^2.1.1, tapable@npm:^2.2.0":
|
||||||
version: 2.2.1
|
version: 2.2.1
|
||||||
resolution: "tapable@npm:2.2.1"
|
resolution: "tapable@npm:2.2.1"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user