Fixed tracks on artist page

This commit is contained in:
lucast committed 2026-06-02 10:34:15 +02:00
1 parent 603620a418
commit db86529219
2 files changed
+79 -180

No files matched your search

-150
View File
@@ -1,150 +0,0 @@
<script setup lang="ts">
const route = useRoute()
const id = computed(() => route.params.id)
const { data: artistData } = await useApiFetch<Album>(`/artists/${id.value}`)
const { data: albumsData } = await useApiFetch<Album[]>(
`/artists/${id.value}/albums`,
)
const { data: tracksData } = await useApiFetch<Track[]>(
`/artists/${id.value}/tracks`,
)
const chunkedTracks = computed(() => {
const SIZE = 3
const chunks = []
for (let i = 0; i < tracksData.value.length; i += SIZE) {
chunks.push(tracksData.value.slice(i, i + SIZE))
}
return chunks
})
const slider = useTemplateRef("slider")
const scrollWidth = () => {
if (!slider.value) return 0
const el = Array.isArray(slider.value) ? slider.value[0] : slider.value
if (!el) return 0
return el.offsetWidth
}
const { playAlbum, playShuffledAlbum, playAlbumAtIndex } = usePlayer()
</script>
<template>
<section class="info" v-if="artistData">
<NuxtImg
:src="GET_FILE(artistData.file)"
width="300"
height="300"
placeholder
/>
<div class="details">
<h1>{{ artistData.name }}</h1>
<div class="buttons">
<Button
icon-name="lucide:play"
@click="() => playAlbum(tracksData)"
>Play</Button
>
<Button
icon-name="lucide:shuffle"
@click="() => playShuffledAlbum(tracksData)"
>Shuffle</Button
>
</div>
</div>
</section>
<Slider slider-class="slider" :scroll-width="scrollWidth" title="Tracks">
<section
class="tracks"
v-for="(chunk, pI) in chunkedTracks"
:key="`chunk-${pI}`"
ref="slider"
>
<TrackRow
v-for="(track, i) in chunk"
:key="`track-${track._id}`"
:track="track"
:index="i + pI * 3"
@play-album-at-index="
() => playAlbumAtIndex(tracksData, i + pI * 3)
"
/>
</section>
</Slider>
<Slider title="Albums">
<AlbumCard
v-for="album in albumsData"
:key="album._id"
:name="album.name"
:file="`${BACKEND_SERVE}${album.file}`"
:artists="album.artists"
:_id="album._id"
/>
</Slider>
</template>
<style lang="scss" scoped>
@use "@/styles/variables" as *;
@use "@/styles/util";
.info {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
& img {
border-radius: $border-radius-standard;
}
.details {
padding-top: 3.5rem;
display: flex;
flex-direction: column;
gap: 0.2rem;
& h1 {
@include util.fontSize(32px);
font-weight: 700;
line-height: 2.4rem;
}
.artist {
@include util.fontSize(18px);
}
.buttons {
margin-top: auto;
display: flex;
gap: 1rem;
}
}
}
$gap: 12px;
:deep(.slider) {
gap: $gap;
}
.tracks {
display: grid;
grid-template-rows: repeat(3, 1fr);
gap: 0.4rem;
flex: 0 0 calc((100% - 3 * $gap) / 4);
}
</style>
+79 -30
View File
@@ -2,12 +2,40 @@
const route = useRoute() const route = useRoute()
const id = computed(() => route.params.id) const id = computed(() => route.params.id)
const { data: artistData } = await useApiFetch<Artist>(`/artists/${id.value}`) const { data: artistData } = await useApiFetch<Album>(`/artists/${id.value}`)
const { data: albumsData } = await useApiFetch<Album[]>(
`/artists/${id.value}/albums`,
)
const { data: tracksData } = await useApiFetch<Track[]>( const { data: tracksData } = await useApiFetch<Track[]>(
`/artists/${id.value}/tracks`, `/artists/${id.value}/tracks`,
) )
const { playAlbum, playAlbumAtIndex } = usePlayer() const chunkedTracks = computed(() => {
const SIZE = 3
const chunks = []
for (let i = 0; i < tracksData.value.length; i += SIZE) {
chunks.push(tracksData.value.slice(i, i + SIZE))
}
return chunks
})
const slider = useTemplateRef("slider")
const scrollWidth = () => {
if (!slider.value) return 0
const el = Array.isArray(slider.value) ? slider.value[0] : slider.value
if (!el) return 0
return el.offsetWidth
}
const { playAlbum, playShuffledAlbum, playAlbumAtIndex } = usePlayer()
</script> </script>
<template> <template>
@@ -28,34 +56,45 @@ const { playAlbum, playAlbumAtIndex } = usePlayer()
@click="() => playAlbum(tracksData)" @click="() => playAlbum(tracksData)"
>Play</Button >Play</Button
> >
<Button
icon-name="lucide:shuffle"
@click="() => playShuffledAlbum(tracksData)"
>Shuffle</Button
>
</div> </div>
</div> </div>
</section> </section>
<section class="tracks-container"> <Slider slider-class="slider" :scroll-width="scrollWidth" title="Tracks">
<NuxtLink :to="`/artist/${id}/tracks`"> <section
Tracks class="tracks"
<Icon name="lucide:chevron-right" /> :class="[`tracks-${chunkedTracks[0]?.length ?? 1}`]"
</NuxtLink> v-for="(chunk, pI) in chunkedTracks"
:key="`chunk-${pI}`"
<Slider> ref="slider"
<div class="tracks"> >
<template v-for="j in 25"> <TrackRow
<TrackImageRow v-for="(track, i) in chunk"
v-for="(track, i) in tracksData" :key="`track-${track._id}`"
:key="track._id"
:track="track" :track="track"
:index="i" :index="i + pI * 3"
@play-album-at-index=" @play-album-at-index="
() => playAlbumAtIndex(tracksData, i) () => playAlbumAtIndex(tracksData, i + pI * 3)
" "
/> />
</template>
</div>
</Slider>
</section> </section>
</Slider>
<section class="albums"></section> <Slider title="Albums">
<AlbumCard
v-for="album in albumsData"
:key="album._id"
:name="album.name"
:file="`${BACKEND_SERVE}${album.file}`"
:artists="album.artists"
:_id="album._id"
/>
</Slider>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -67,7 +106,7 @@ const { playAlbum, playAlbumAtIndex } = usePlayer()
gap: 1rem; gap: 1rem;
margin-bottom: 2rem; margin-bottom: 2rem;
img { & img {
border-radius: $border-radius-standard; border-radius: $border-radius-standard;
} }
@@ -76,6 +115,7 @@ const { playAlbum, playAlbumAtIndex } = usePlayer()
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.2rem;
& h1 { & h1 {
@include util.fontSize(32px); @include util.fontSize(32px);
@@ -83,26 +123,35 @@ const { playAlbum, playAlbumAtIndex } = usePlayer()
line-height: 2.4rem; line-height: 2.4rem;
} }
.artist {
@include util.fontSize(18px);
}
.buttons { .buttons {
margin-top: auto; margin-top: auto;
display: flex;
gap: 1rem;
} }
} }
} }
.tracks-container { $gap: 12px;
a {
display: inline-flex;
align-items: center;
@include util.fontSize(24px); :deep(.slider) {
font-weight: 600; gap: $gap;
margin-bottom: 1rem;
} }
.tracks { .tracks {
display: grid; display: grid;
grid-template-rows: repeat(3, 1fr); gap: 0.4rem;
grid-template-columns: repeat(auto-fit, minmax(300px, 350px));
grid-auto-flow: column; flex: 0 0 calc((100% - 3 * $gap) / 4);
@for $i from 1 through 3 {
&-#{$i} {
grid-template-rows: repeat(#{$i}, 1fr);
}
} }
} }
</style> </style>