reformat, add data refresh button

This commit is contained in:
2026-03-12 22:57:40 +01:00
parent 894799e34d
commit 484e4604bd
9 changed files with 101 additions and 94 deletions

View File

@@ -28,7 +28,6 @@ function highlightText(text: string, searchterm: string) {
<template> <template>
<div class="w-full h-full text-xs"> <div class="w-full h-full text-xs">
<div v-if="props.artist && props.artist.length > 0" class="mb-4"> <div v-if="props.artist && props.artist.length > 0" class="mb-4">
<h2 class="px-4 py-2 font-semibold text-lg uppercase tracking-wider action">Artists</h2> <h2 class="px-4 py-2 font-semibold text-lg uppercase tracking-wider action">Artists</h2>
<ul class="space-y-1 px-2"> <ul class="space-y-1 px-2">
@@ -48,15 +47,18 @@ function highlightText(text: string, searchterm: string) {
<div v-if="props.songs && props.songs.length > 0"> <div v-if="props.songs && props.songs.length > 0">
<h2 class="px-4 py-2 font-semibold text-lg uppercase tracking-wider action">Songs</h2> <h2 class="px-4 py-2 font-semibold text-lg uppercase tracking-wider action">Songs</h2>
<ul class="space-y-1 px-2 pb-20"> <li v-for="(song, index) in props.songs" :key="index"> <ul class="space-y-1 px-2 pb-20">
<li v-for="(song, index) in props.songs" :key="index">
<button <button
@click="playSong(song.hash)" @click="playSong(song.hash)"
class="flex items-center p-2 rounded-xl w-full text-left transition-colors" class="flex items-center p-2 rounded-xl w-full text-left transition-colors"
> >
<img <img
:src="song.previewimage :src="
song.previewimage
? `${userStore.cloudflareUrl.value}${song.previewimage}?h=120&w=120` ? `${userStore.cloudflareUrl.value}${song.previewimage}?h=120&w=120`
: '/default-bg.png'" : '/default-bg.png'
"
class="rounded-lg w-12 h-12 object-cover shrink-0" class="rounded-lg w-12 h-12 object-cover shrink-0"
loading="lazy" loading="lazy"
/> />

View File

@@ -1,6 +1,5 @@
<template> <template>
<div class="w-full h-full text-xs animate-pulse"> <div class="w-full h-full text-xs animate-pulse">
<div class="mb-4"> <div class="mb-4">
<div class="my-2 ml-4 rounded w-24 h-6 action"></div> <div class="my-2 ml-4 rounded w-24 h-6 action"></div>
<ul class="space-y-1 px-2"> <ul class="space-y-1 px-2">
@@ -28,7 +27,6 @@
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</template> </template>
@@ -38,10 +36,21 @@
} }
@keyframes pulse { @keyframes pulse {
0%, 100% { opacity: 1; } 0%,
50% { opacity: 0.4; } 100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
} }
.info { background-color: currentColor; opacity: 0.1; } .info {
.action { background-color: currentColor; opacity: 0.05; } background-color: currentColor;
opacity: 0.1;
}
.action {
background-color: currentColor;
opacity: 0.05;
}
</style> </style>

View File

@@ -85,7 +85,9 @@ onBeforeUnmount(() => {
<hr /> <hr />
</div> </div>
</header> </header>
<div class="gap-2 grid grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 p-2 overflow-y-auto collection-container song-item-wrapper coll-container"> <div
class="gap-2 grid grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 p-2 overflow-y-auto collection-container song-item-wrapper coll-container"
>
<SongItem v-for="(song, index) in songs" :key="index" :song="song" /> <SongItem v-for="(song, index) in songs" :key="index" :song="song" />
<template v-if="loading"> <template v-if="loading">

View File

@@ -8,7 +8,8 @@ const props = defineProps<{ collection: CollectionPreview }>();
<template> <template>
<RouterLink :to="'/collection/' + props.collection.index" class="w-full"> <RouterLink :to="'/collection/' + props.collection.index" class="w-full">
<div class="flex items-center border rounded-lg h-24 overflow-hidden bordercolor"> <img <div class="flex items-center border rounded-lg h-24 overflow-hidden bordercolor">
<img
class="p-1 rounded-lg w-24 h-24" class="p-1 rounded-lg w-24 h-24"
:src="encodeURI(`${userStore.cloudflareUrl.value}${props.collection.previewimage}`)" :src="encodeURI(`${userStore.cloudflareUrl.value}${props.collection.previewimage}`)"
loading="lazy" loading="lazy"

View File

@@ -25,9 +25,11 @@ function updateSong() {
> >
<img <img
class="p-1 rounded-lg w-14 md:w-24 h-16 md:h-24 object-cover shrink-0" class="p-1 rounded-lg w-14 md:w-24 h-16 md:h-24 object-cover shrink-0"
:src="props.song?.previewimage :src="
props.song?.previewimage
? encodeURI(`${userStore.cloudflareUrl.value}${props.song.previewimage}?h=56&w=56`) ? encodeURI(`${userStore.cloudflareUrl.value}${props.song.previewimage}?h=56&w=56`)
: '/default-bg.png'" : '/default-bg.png'
"
loading="lazy" loading="lazy"
/> />

View File

@@ -66,17 +66,12 @@ onMounted(async () => {
<template> <template>
<main class="flex flex-col w-full h-full overflow-hidden"> <main class="flex flex-col w-full h-full overflow-hidden">
<div <div
ref="containerRef" ref="containerRef"
class="flex-1 content-start gap-2 grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 p-2 overflow-y-auto" class="flex-1 content-start gap-2 grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 p-2 overflow-y-auto"
style="min-height: 0;" style="min-height: 0"
> >
<CollectionListItem <CollectionListItem v-for="(collection, index) in collections" :key="index" :collection="collection" />
v-for="(collection, index) in collections"
:key="index"
:collection="collection"
/>
<template v-if="isLoading"> <template v-if="isLoading">
<CollectionListItemSkeleton v-for="i in 12" :key="'skeleton-' + i" /> <CollectionListItemSkeleton v-for="i in 12" :key="'skeleton-' + i" />

View File

@@ -120,15 +120,18 @@ function reset() {
<button @click="copyToClipboard" class="bg-white/5 hover:bg-white/10 p-2 border bordercolor" title="Copy URL"> <button @click="copyToClipboard" class="bg-white/5 hover:bg-white/10 p-2 border bordercolor" title="Copy URL">
<i class="fa-solid fa-copy"></i> <i class="fa-solid fa-copy"></i>
</button> </button>
<button @click="pasteFromClipboard" class="bg-white/5 hover:bg-white/10 p-2 border rounded-r-lg text-yellow-500 bordercolor" title="Paste URL"> <button
@click="pasteFromClipboard"
class="bg-white/5 hover:bg-white/10 p-2 border rounded-r-lg text-yellow-500 bordercolor"
title="Paste URL"
>
<i class="fa-solid fa-paste"></i> <i class="fa-solid fa-paste"></i>
</button> </button>
<div <div
v-if="isHealthy !== null" v-if="isHealthy !== null"
class="self-center rounded-full w-2 h-2" class="self-center rounded-full w-2 h-2"
:class="isHealthy ? 'bg-green-500 shadow-[0_0_8px_green]' : 'bg-red-500 shadow-[0_0_8px_red]'" :class="isHealthy ? 'bg-green-500 shadow-[0_0_8px_green]' : 'bg-red-500 shadow-[0_0_8px_red]'"
> ></div>
</div>
</div> </div>
</div> </div>
@@ -137,6 +140,7 @@ function reset() {
<button v-if="!userStore.user.value" @click="getMe" class="mx-4 p-0.5 border rounded-lg bordercolor"> <button v-if="!userStore.user.value" @click="getMe" class="mx-4 p-0.5 border rounded-lg bordercolor">
{{ loginStatus }} {{ loginStatus }}
</button> </button>
<button v-else @click="getMe" class="mx-4 p-0.5 border rounded-lg bordercolor">Refresh</button>
<div class="flex flex-col justify-around p-10 w-full"> <div class="flex flex-col justify-around p-10 w-full">
<div class="flex flex-1 justify-between"> <div class="flex flex-1 justify-between">

View File

@@ -60,7 +60,7 @@ async function fetchSearchArtist(artist: string) {
songs.value = data.map((song: Song) => ({ songs.value = data.map((song: Song) => ({
...song, ...song,
previewimage: `${userStore.cloudflareUrl.value}/api/v1/images/${song.previewimage}`, previewimage: `${userStore.cloudflareUrl.value}/api/v1/images/${song.previewimage}`,
url: `${userStore.cloudflareUrl.value}/api/v1/audio/${song.url}` url: `${userStore.cloudflareUrl.value}/api/v1/audio/${song.url}`,
})); }));
router.replace({ query: { ...route.query, a: artist } }); router.replace({ query: { ...route.query, a: artist } });
@@ -88,9 +88,12 @@ watch(searchInput, (val) => {
} }
}); });
watch(() => route.query.a, (newArtist) => { watch(
() => route.query.a,
(newArtist) => {
if (newArtist) fetchSearchArtist(newArtist as string); if (newArtist) fetchSearchArtist(newArtist as string);
}); },
);
onMounted(() => { onMounted(() => {
if (route.query.a) fetchSearchArtist(route.query.a as string); if (route.query.a) fetchSearchArtist(route.query.a as string);
@@ -128,28 +131,17 @@ onMounted(() => {
</div> </div>
<div class="relative flex-1 overflow-y-auto"> <div class="relative flex-1 overflow-y-auto">
<div <div
v-if="showSearch && (activesongs.length || artists.length || isLoading)" v-if="showSearch && (activesongs.length || artists.length || isLoading)"
class="z-20 absolute backdrop-blur-xl w-full min-h-full" class="z-20 absolute backdrop-blur-xl w-full min-h-full"
> >
<ActiveSearchSkeleton v-if="isLoading" /> <ActiveSearchSkeleton v-if="isLoading" />
<ActiveSearchList <ActiveSearchList v-else :songs="activesongs" :artist="artists" :search="searchInput" />
v-else
:songs="activesongs"
:artist="artists"
:search="searchInput"
/>
</div> </div>
<template v-else> <template v-else>
<SongItem <SongItem v-for="(song, index) in songs" :key="song.hash || index" :song="song" class="song-render-node" />
v-for="(song, index) in songs"
:key="song.hash || index"
:song="song"
class="song-render-node"
/>
</template> </template>
<div v-if="!isLoading && songs.length === 0 && !showSearch" class="col-span-full opacity-30 py-20 text-center"> <div v-if="!isLoading && songs.length === 0 && !showSearch" class="col-span-full opacity-30 py-20 text-center">