fix: double click on tracks is now working

+ fix see all link not being shown in favorites and artist page
This commit is contained in:
cwilvx
2025-08-14 21:14:18 +03:00
parent 6f4a59f971
commit cf2d9537ff
5 changed files with 192 additions and 127 deletions

View File

@@ -1,5 +1,5 @@
<template>
<div class="statitem" :class="props.icon">
<div class="statitem" :class="props.icon" :style="dynamicBackgroundStyle">
<svg
class="noise"
xmlns="http://www.w3.org/2000/svg"
@@ -35,7 +35,7 @@
surfaceScale="21"
specularConstant="1.7"
specularExponent="20"
lighting-color="#7957A8"
lighting-color="transparent"
x="0%"
y="0%"
width="100%"
@@ -50,20 +50,20 @@
<rect width="700" height="700" fill="transparent"></rect>
<rect width="700" height="700" fill="#7957a8" filter="url(#nnnoise-filter)"></rect>
</svg>
<div class="itemcontent">
<div class="itemcontent" :style="{ color: textColor }">
<div class="count ellip2" :title="formattedValue">{{ formattedValue }}</div>
<div class="title">{{ text }}</div>
</div>
<component :is="icon" class="staticon" v-if="!props.icon.startsWith('top')" />
<component :is="icon" v-if="!props.icon.startsWith('top')" class="staticon" :style="{ color: textColor }" />
<router-link
v-if="props.icon.startsWith('top') && props.image"
:to="{
name: Routes.album,
params: {
albumhash: props.image?.replace('.webp', ''),
},
}"
v-if="props.icon.startsWith('top') && props.image"
>
<img class="staticon statimage shadow-sm" :src="paths.images.thumb.small + props.image" alt="" />
</router-link>
@@ -81,6 +81,11 @@ import SparklesSvg from '@/assets/icons/sparkles.svg'
import { paths } from '@/config'
import { Routes } from '@/router'
import useArtistStore from '@/stores/pages/artist'
import useAlbumStore from '@/stores/pages/album'
import { storeToRefs } from 'pinia'
import { useRoute } from 'vue-router'
import { getTextColor } from '@/utils/colortools/shift'
const props = defineProps<{
value: string
@@ -89,6 +94,13 @@ const props = defineProps<{
image?: string
}>()
// Get current route and colors from stores
const route = useRoute()
const artistStore = useArtistStore()
const albumStore = useAlbumStore()
const { colors: artistColors } = storeToRefs(artistStore)
const { colors: albumColors } = storeToRefs(albumStore)
const icon = computed(() => {
switch (props.icon) {
case 'streams':
@@ -110,6 +122,61 @@ const icon = computed(() => {
const formattedValue = computed(() => {
return props.value.toLocaleString()
})
// Determine which dynamic color to use based on current route
const dynamicColor = computed(() => {
switch (route.name) {
// Album-related pages should use album colors
case Routes.album:
return albumColors.value?.bg || null
// Artist-related pages should use artist colors
case Routes.artist:
return artistColors.value?.bg || null
// All other pages should use default colors
default:
return null
}
})
// Default hardcoded background styles
const defaultBackgroundStyles = computed(() => {
switch (props.icon) {
case 'streams':
return 'linear-gradient(to top, #c79081 0%, #dfa579 100%)'
case 'playtime':
return 'linear-gradient(-225deg, #3d4e81 0%, #5753c9 48%, #6e7ff3 100%)'
case 'trackcount':
return 'linear-gradient(to top, #6a66b9 0%, #7777db 52%, #7b7bd4 100%)'
case 'toptrack':
return 'linear-gradient(-225deg, #65379b 0%, #6750b3 53%, #6457c6 100%)'
default:
return 'linear-gradient(to top right, rgb(120, 76, 129), #9643da91, rgb(132, 80, 228))'
}
})
// Computed style that uses dynamic color or falls back to hardcoded
const dynamicBackgroundStyle = computed(() => {
if (dynamicColor.value) {
return {
backgroundColor: dynamicColor.value,
backgroundImage: 'none',
}
}
return {
backgroundImage: defaultBackgroundStyles.value,
}
})
// Computed text color based on background using the same logic as headers
const textColor = computed(() => {
if (dynamicColor.value) {
return getTextColor(dynamicColor.value)
}
// Return default white color when using gradients
return '#ffffff'
})
</script>
<style lang="scss">
@@ -121,25 +188,10 @@ const formattedValue = computed(() => {
aspect-ratio: 1;
overflow: hidden;
// Default background - will be overridden by dynamic styles
background-image: linear-gradient(to top right, rgb(120, 76, 129), #9643da91, rgb(132, 80, 228));
position: relative;
&.streams {
background-image: linear-gradient(to top, #c79081 0%, #dfa579 100%);
}
&.playtime {
background-image: linear-gradient(-225deg, #3d4e81 0%, #5753c9 48%, #6e7ff3 100%);
}
&.trackcount {
background-image: linear-gradient(to top, #6a66b9 0%, #7777db 52%, #7b7bd4 100%);
}
&.toptrack {
background-image: linear-gradient(-225deg, #65379b 0%, #6750b3 53%, #6457c6 100%);
}
.itemcontent {
position: relative;
z-index: 1;

View File

@@ -7,11 +7,18 @@
{{ title }}
</RouterLink>
</b>
<!-- INFO: This SEE ALL is shown when there's no description. Eg. in favorites page -->
<SeeAll
v-if="!description && route && itemlist.length >= maxAbumCards"
:route="route"
:text="seeAllText"
/>
</div>
<div v-if="description" class="rdesc">
<RouterLink :to="route || ''">
{{ description }}
</RouterLink>
<!-- INFO: This SEE ALL is shown when there's a description. Eg. in the home page -->
<SeeAll v-if="route && itemlist.length >= maxAbumCards" :route="route" :text="seeAllText" />
</div>
</div>
@@ -163,6 +170,9 @@ function getProps(item: { type: string; item?: any; with_helptext?: boolean }) {
.rtitle {
font-size: 1.15rem;
display: flex;
align-items: baseline;
justify-content: space-between;
}
.rdesc {

View File

@@ -2,14 +2,15 @@
<div
class="songlist-item rounded-sm"
:class="[{ current: isCurrent() }, { contexton: context_menu_showing }]"
@dblclick="emitUpdate"
@contextmenu.prevent="showMenu"
>
<TrackIndex
v-if="!isSmall"
:index="index"
:is_fav="is_fav"
@add-to-fav="addToFav(track.trackhash)"
:show-inline-fav-icon="settings.showInlineFavIcon"
@add-to-fav="addToFav(track.trackhash)"
/>
<TrackTitle
@@ -29,13 +30,13 @@
/>
<TrackDuration
:duration="track.duration || 0"
@showMenu="showMenu"
@toggleFav="addToFav(track.trackhash)"
:help_text="track.help_text"
:is_fav="is_fav"
:showFavIcon="!isFavoritesPage"
:showInlineFavIcon="settings.showInlineFavIcon"
:highlightFavoriteTracks="settings.highlightFavoriteTracks"
@showMenu="showMenu"
@toggleFav="addToFav(track.trackhash)"
/>
</div>
</template>

View File

@@ -10,7 +10,7 @@ import useTracklist from './queue/tracklist'
import useSettings from './settings'
import useTracker from './tracker'
import { paths } from '@/config'
import { getBaseUrl, paths } from '@/config'
import updateMediaNotif from '@/helpers/mediaNotification'
import { crossFade } from '@/utils/audio/crossFade'
@@ -127,9 +127,11 @@ export function getUrl(filepath: string, trackhash: string, use_legacy: boolean)
use_legacy = true
const { streaming_container, streaming_quality } = useSettings()
return `${paths.api.files}/${trackhash + (use_legacy ? '/legacy' : '')}?filepath=${encodeURIComponent(
const url = `${paths.api.files}/${trackhash + (use_legacy ? '/legacy' : '')}?filepath=${encodeURIComponent(
filepath
)}&container=${streaming_container}&quality=${streaming_quality}`
return getBaseUrl() + url
}
const audioSource = new AudioSource()

View File

@@ -1,128 +1,128 @@
<template>
<div class="content-page favorites-page">
<GenericHeader>
<template #name>Favorites</template>
<template #description
>{{ count.tracks }} Tracks {{ count.albums }} Albums {{ count.artists }} Artists</template
>
</GenericHeader>
<CardScroller
v-if="recentFavs.length"
class="recent-favs"
:items="recentFavs"
:title="'Recent'"
:play-source="playSources.favorite"
/>
<div v-if="favTracks.length" class="fav-tracks">
<TopTracks
:tracks="favTracks"
:route="'/favorites/tracks'"
:title="'Tracks'"
:play-handler="handlePlay"
:source="dropSources.favorite"
:total="count.tracks"
/>
<div class="content-page favorites-page">
<GenericHeader>
<template #name>Favorites</template>
<template #description
>{{ count.tracks }} Tracks {{ count.albums }} Albums {{ count.artists }} Artists</template
>
</GenericHeader>
<CardScroller
v-if="recentFavs.length"
class="recent-favs"
:items="recentFavs"
:title="'Recent'"
:play-source="playSources.favorite"
/>
<div v-if="favTracks.length" class="fav-tracks">
<TopTracks
:tracks="favTracks"
:route="'/favorites/tracks'"
:title="'Tracks'"
:play-handler="handlePlay"
:source="dropSources.favorite"
:total="count.tracks"
/>
</div>
<br />
<CardScroller
v-if="favAlbums.length"
:items="favAlbums.map(i => ({ type: 'album', item: i }))"
:title="'Albums'"
:route="'/favorites/albums'"
/>
<CardScroller
v-if="favArtists.length"
:items="favArtists.map(i => ({ type: 'artist', item: i }))"
:title="'Artists'"
:route="'/favorites/artists'"
/>
<NoItems :flag="noFavs" :icon="HeartSvg" :title="'No favorites found'" :description="description" />
</div>
<br />
<CardScroller
v-if="favAlbums.length"
:items="favAlbums.map((i) => ({ type: 'album', item: i }))"
:title="'Albums'"
:route="'/favorites/albums'"
/>
<CardScroller
v-if="favArtists.length"
:items="favArtists.map((i) => ({ type: 'artist', item: i }))"
:title="'Artists'"
:route="'/favorites/artists'"
/>
<NoItems :flag="noFavs" :icon="HeartSvg" :title="'No favorites found'" :description="description" />
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, Ref, ref } from "vue";
import { nextTick, onMounted, Ref, ref } from 'vue'
import { maxAbumCards, updateCardWidth } from "@/stores/content-width";
import { maxAbumCards, updateCardWidth } from '@/stores/content-width'
import { dropSources, playSources } from "@/enums";
import { playFromFavorites } from "@/helpers/usePlayFrom";
import { Album, Artist, RecentFavResult, Track } from "@/interfaces";
import { getAllFavs } from "@/requests/favorite";
import updatePageTitle from "@/utils/updatePageTitle";
import { dropSources, playSources } from '@/enums'
import { playFromFavorites } from '@/helpers/usePlayFrom'
import { Album, Artist, RecentFavResult, Track } from '@/interfaces'
import { getAllFavs } from '@/requests/favorite'
import updatePageTitle from '@/utils/updatePageTitle'
import HeartSvg from "@/assets/icons/heart-no-color.svg";
import TopTracks from "@/components/ArtistView/TopTracks.vue";
import CardScroller from "@/components/shared/CardScroller.vue";
import GenericHeader from "@/components/shared/GenericHeader.vue";
import NoItems from "@/components/shared/NoItems.vue";
import HeartSvg from '@/assets/icons/heart-no-color.svg'
import TopTracks from '@/components/ArtistView/TopTracks.vue'
import CardScroller from '@/components/shared/CardScroller.vue'
import GenericHeader from '@/components/shared/GenericHeader.vue'
import NoItems from '@/components/shared/NoItems.vue'
const description = `You can add tracks, albums and artists to your favorites by clicking the heart icon`;
const description = `You can add tracks, albums and artists to your favorites by clicking the heart icon`
const recentFavs: Ref<RecentFavResult[]> = ref([]);
const favAlbums: Ref<Album[]> = ref([]);
const favTracks: Ref<Track[]> = ref([]);
const favArtists: Ref<Artist[]> = ref([]);
const recentFavs: Ref<RecentFavResult[]> = ref([])
const favAlbums: Ref<Album[]> = ref([])
const favTracks: Ref<Track[]> = ref([])
const favArtists: Ref<Artist[]> = ref([])
const count = ref({
albums: 0,
tracks: 0,
artists: 0,
});
const noFavs = ref(false);
albums: 0,
tracks: 0,
artists: 0,
})
const noFavs = ref(false)
onMounted(() => {
updatePageTitle("Favorites");
const max = maxAbumCards.value;
updatePageTitle('Favorites')
const max = maxAbumCards.value
getAllFavs(6, max, max)
.then((favs) => {
recentFavs.value = favs.recents;
favAlbums.value = favs.albums;
favTracks.value = favs.tracks;
favArtists.value = favs.artists;
count.value = favs.count;
})
.then(() => {
noFavs.value = !favAlbums.value.length && !favTracks.value.length && !favArtists.value.length;
})
.then(async () => {
await nextTick();
updateCardWidth();
});
});
getAllFavs(6, max, max)
.then(favs => {
recentFavs.value = favs.recents
favAlbums.value = favs.albums
favTracks.value = favs.tracks
favArtists.value = favs.artists
count.value = favs.count
})
.then(() => {
noFavs.value = !favAlbums.value.length && !favTracks.value.length && !favArtists.value.length
})
.then(async () => {
await nextTick()
updateCardWidth()
})
})
function handlePlay(index: number) {
const track = favTracks.value[index];
if (!track) return;
playFromFavorites(track);
const track = favTracks.value[index]
if (!track) return
playFromFavorites(track)
}
</script>
<style lang="scss">
.favorites-page {
height: 100%;
overflow: auto;
height: 100%;
overflow: auto;
.recent-favs {
padding-top: 1rem;
}
.nothing h3 {
margin-top: 3rem;
}
.fav-tracks {
h3 {
margin-top: 0;
.recent-favs {
padding-top: 1rem;
}
.artist-top-tracks {
h3 {
padding-right: $small;
}
.nothing h3 {
margin-top: 3rem;
}
.fav-tracks {
h3 {
margin-top: 0;
}
.artist-top-tracks {
h3 {
padding-right: $small;
}
}
}
}
}
</style>