implement artist tracks page

This commit is contained in:
geoffrey45
2022-12-24 16:20:40 +03:00
committed by Mungai Njoroge
parent 58d4317ab8
commit 7f0fe88c43
10 changed files with 143 additions and 22 deletions
+2 -2
View File
@@ -111,7 +111,7 @@ $g-border: solid 1px $gray5;
.v-scroll-page.isSmall {
.songlist-item {
grid-template-columns: 1.5rem 2fr 2.5rem 2.5rem;
grid-template-columns: 1.75rem 2fr 2.5rem 2.5rem;
}
.song-artists,
@@ -130,7 +130,7 @@ $g-border: solid 1px $gray5;
.v-scroll-page.isMedium {
// hide album column
.songlist-item {
grid-template-columns: 1.5rem 1.5fr 1fr 2.5rem 2.5rem;
grid-template-columns: 1.75rem 1.5fr 1fr 2.5rem 2.5rem;
}
.song-album {
+4 -4
View File
@@ -3,9 +3,9 @@
class="artist-header-ambient rounded"
style="height: 100%; width: 100%"
:style="{
boxShadow: artist.info.colors
boxShadow: artist.info.colors.length
? `0 .5rem 2rem ${artist.info.colors[0]}`
: '',
: undefined,
}"
></div>
<div class="artist-page-header rounded no-scroll">
@@ -88,8 +88,8 @@ const artist = useArtistPageStore();
background-image: linear-gradient(
to left,
transparent 10%,
$gray2 50%,
$gray2 100%
$gray 50%,
$gray 100%
);
height: 100%;
width: 100%;
+32 -1
View File
@@ -1,6 +1,22 @@
<template>
<div class="artist-top-tracks">
<h3 class="section-title">Tracks</h3>
<h3 class="section-title">
Tracks
<span class="see-more">
<RouterLink
:to="{
name: Routes.artistTracks,
params: {
hash: artist.info.artisthash,
},
query: {
artist: artist.info.name,
},
}"
>SEE ALL</RouterLink
>
</span>
</h3>
<div class="tracks">
<SongItem
v-for="(song, index) in artist.tracks"
@@ -20,6 +36,7 @@ import useQueueStore from "@/stores/queue";
import { FromOptions, playSources } from "@/composables/enums";
import { getArtistTracks } from "@/composables/fetch/artists";
import { Routes } from "@/router/routes";
const artist = useArtistPageStore();
const queue = useQueueStore();
@@ -51,5 +68,19 @@ async function playFromPage(index: number) {
padding-left: 1rem;
color: $red;
}
h3 {
display: flex;
justify-content: space-between;
}
.see-more {
font-size: $medium;
a:hover {
text-decoration: underline;
cursor: pointer !important;
}
}
}
</style>
+2
View File
@@ -19,6 +19,7 @@
<ArtistDiscographyTitle
v-if="$route.name == Routes.artistDiscography"
/>
<ArtistTracksTitle v-if="$route.name == Routes.artistTracks" />
</div>
</div>
</div>
@@ -42,6 +43,7 @@ import QueueTitle from "./Titles/QueueTitle.vue";
import SearchTitle from "./Titles/SearchTitle.vue";
import SettingsTitle from "./Titles/SettingsTitle.vue";
import ArtistDiscographyTitle from "./Titles/ArtistDiscographyTitle.vue";
import ArtistTracksTitle from "./Titles/ArtistTracksTitle.vue";
const route = useRoute();
const nav = useNavStore();
@@ -0,0 +1,5 @@
<template>
<div class="artist-tracks-nav">
<h2 style="margin: 0">{{ $route.query.artist }}</h2>
</div>
</template>
+13 -13
View File
@@ -1,14 +1,13 @@
<template>
<div class="nav-queue-title">
<div class="first no-scroll">
<router-link :to="(location as RouteLocationRaw)">
<button class="btn-active">Go to source</button>
</router-link>
<div class="playing-from">
<div class="border rounded-sm pad-sm">
<SourceIcon v-if="SourceIcon" />
<b class="ellip">{{ name }}</b>
</div>
<router-link :to="(location as RouteLocationRaw)">
<div class="border rounded-sm pad-sm">
<SourceIcon v-if="SourceIcon" />
<b class="ellip">{{ name }}</b>
</div>
</router-link>
</div>
</div>
<QueueActions />
@@ -19,7 +18,7 @@
import QueueActions from "@/components/RightSideBar/Queue/QueueActions.vue";
import { FromOptions } from "@/composables/enums";
import useQueueStore from "@/stores/queue";
import {Routes} from "@/router/routes";
import { Routes } from "@/router/routes";
import AlbumSvg from "@/assets/icons/album.svg";
import FolderSvg from "@/assets/icons/folder.svg";
@@ -112,11 +111,6 @@ const { name, icon: SourceIcon, location } = getSource();
align-items: center;
.first {
width: 100%;
display: grid;
grid-template-columns: max-content 1fr;
gap: 1rem;
.playing-from {
display: flex;
align-items: center;
@@ -124,11 +118,17 @@ const { name, icon: SourceIcon, location } = getSource();
opacity: 0.75;
.border {
cursor: pointer;
display: grid;
grid-template-columns: max-content 1fr;
align-items: center;
padding: $smaller $small;
height: 100%;
&:hover {
background-color: $darkestblue;
border: solid 1px $darkestblue;
}
}
svg {
+2 -1
View File
@@ -144,7 +144,7 @@ async function addToFav(trackhash: string) {
<style lang="scss">
.songlist-item {
display: grid;
grid-template-columns: 1.5rem 2fr 1fr 1.5fr 2.5rem 2.5rem;
grid-template-columns: 1.75rem 2fr 1fr 1.5fr 2.5rem 2.5rem;
align-items: center;
justify-content: flex-start;
height: $song-item-height;
@@ -169,6 +169,7 @@ async function addToFav(trackhash: string) {
background-color: $gray5;
.index {
.text {
transition-delay: 500ms;
+8
View File
@@ -94,6 +94,12 @@ const artistView = {
},
};
const ArtistTracks = {
path: "/artists/:hash/tracks",
name: "ArtistTracks",
component: () => import("@/views/ArtistTracks.vue"),
};
const artistDiscography = {
path: "/artists/:hash/discography",
name: "ArtistDiscographyView",
@@ -138,6 +144,7 @@ const routes = [
search,
queue,
notFound,
ArtistTracks,
];
const Routes = {
@@ -154,6 +161,7 @@ const Routes = {
search: search.name,
queue: queue.name,
notFound: notFound.name,
artistTracks: ArtistTracks.name,
};
export { routes, Routes };
+2 -1
View File
@@ -146,8 +146,9 @@ onBeforeRouteLeave(() => {
.album-virtual-scroller {
height: 100%;
overflow: visible;
.songlist-item {
grid-template-columns: 1.5rem 1.5fr 1fr 2.5rem 2.5rem;
grid-template-columns: 1.75rem 1.5fr 1fr 2.5rem 2.5rem;
}
}
</style>
+73
View File
@@ -0,0 +1,73 @@
<template>
<div
class="v-scroll-page"
:class="{ isSmall, isMedium }"
style="height: 100%"
>
<RecycleScroller
class="scroller"
style="height: 100%"
:items="scrollerItems"
:item-size="itemHeight"
key-field="id"
v-slot="{ item, index }"
>
<SongItem
:track="item.track"
:index="index + 1"
@playThis="playFromPage(index)"
/>
</RecycleScroller>
</div>
</template>
<script setup lang="ts">
import { useRoute } from "vue-router";
import { computed, onMounted, Ref, ref } from "vue";
import { Track } from "@/interfaces";
import { createTrackProps } from "@/utils";
import { isMedium, isSmall } from "@/stores/content-width";
import { getArtistTracks } from "@/composables/fetch/artists";
import useQueueStore from "@/stores/queue";
import SongItem from "@/components/shared/SongItem.vue";
import { FromOptions } from "@/composables/enums";
const itemHeight = 64;
const route = useRoute();
const queue = useQueueStore();
const tracks: Ref<Track[]> = ref([]);
onMounted(() => {
const hash = route.params.hash as string;
getArtistTracks(hash).then((t) => {
tracks.value = t;
});
});
const scrollerItems = computed(() => {
return tracks.value.map((track) => {
return {
track,
id: Math.random(),
props: createTrackProps(track),
};
});
});
async function playFromPage(index: number) {
const hash = route.params.hash as string;
const artist = route.query.artist as string;
if (queue.from.type == FromOptions.artist && queue.from.artisthash == hash) {
queue.play(index);
return;
}
queue.playFromArtist(hash, artist, tracks.value);
queue.play(index);
}
</script>