add functionality to adjust image position

This commit is contained in:
geoffrey45 2023-01-13 15:53:36 +03:00 committed by Mungai Njoroge
parent 4d4a276ed8
commit ceedc22843
9 changed files with 146 additions and 65 deletions

View File

@ -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 }} &#160;|&#160;&#160;</span
>
<span class="edit" @click="editPlaylist">Edit&#160;&#160;|</span>
<div class="edit" @click="editPlaylist">Edit&#160;&#160;|</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;

View File

@ -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>

View File

@ -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)"

View File

@ -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);
}

View File

@ -87,6 +87,8 @@ export interface Playlist {
last_updated: string;
thumb: string;
duration: number;
has_gif: boolean;
banner_pos: number;
}
export interface Notif {

View File

@ -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;
},
},
});

View File

@ -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));

View File

@ -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>

View File

@ -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"