setup artist discography page

This commit is contained in:
geoffrey45
2022-12-12 13:18:05 +03:00
committed by Mungai Njoroge
parent fd863d188c
commit 35a8446f8b
10 changed files with 189 additions and 45 deletions
+17 -2
View File
@@ -2,8 +2,16 @@
<div class="artist-albums"> <div class="artist-albums">
<h3> <h3>
<span>{{ title }} </span> <span>{{ title }} </span>
<span class="see-more" v-if="maxAbumCards <= albums.length"> <span
<RouterLink :to="{ name: Routes.artistDiscography }" class="see-more"
v-if="maxAbumCards <= albums.length"
@click="store.setPage(albumType)"
>
<RouterLink
:to="{
name: Routes.artistDiscography,
params: { hash: artisthash },
}"
>SEE ALL</RouterLink >SEE ALL</RouterLink
> >
</span> </span>
@@ -21,9 +29,16 @@ import { Album } from "@/interfaces";
import { maxAbumCards } from "@/stores/content-width"; import { maxAbumCards } from "@/stores/content-width";
import { Routes } from "@/router/routes"; import { Routes } from "@/router/routes";
import { discographyAlbumTypes } from "@/composables/enums";
import useArtistDiscographyStore from "@/stores/pages/artistDiscog";
const store = useArtistDiscographyStore();
defineProps<{ defineProps<{
title: string; title: string;
artisthash: string;
albums: Album[]; albums: Album[];
albumType: discographyAlbumTypes;
}>(); }>();
</script> </script>
+4 -3
View File
@@ -81,9 +81,10 @@ import { albumHeaderSmall } from "@/stores/content-width";
import useNavStore from "@/stores/nav"; import useNavStore from "@/stores/nav";
import useAlbumStore from "@/stores/pages/album"; import useAlbumStore from "@/stores/pages/album";
import { formatSeconds, useVisibility } from "@/utils"; import { formatSeconds, useVisibility } from "@/utils";
import { isLight } from "../../composables/colors/album"; import { isLight } from "@/composables/colors/album";
import { playSources, Routes } from "../../composables/enums"; import { playSources } from "@/composables/enums";
import { Album } from "../../interfaces"; import { Album } from "@/interfaces";
import { Routes } from "@/router/routes";
import PlayBtnRect from "../shared/PlayBtnRect.vue"; import PlayBtnRect from "../shared/PlayBtnRect.vue";
@@ -2,20 +2,23 @@
<div class="artist-discography-nav"> <div class="artist-discography-nav">
<h1 class="ellip">Creedence Clearwater Revival</h1> <h1 class="ellip">Creedence Clearwater Revival</h1>
<div class="buttons"> <div class="buttons">
<!-- create dropdown --> <div class="select rounded-sm" v-auto-animate="{ duration: 10 }">
<div class="select rounded-sm" v-auto-animate="{ duration: 100 }">
<button class="selected" @click.prevent="showDropDown = !showDropDown"> <button class="selected" @click.prevent="showDropDown = !showDropDown">
<span class="ellip">Albums and appearances</span> <span class="ellip">{{ store.page }}</span>
<ArrowSvg /> <ArrowSvg />
</button> </button>
<div <div
ref="dropOptionsRef" ref="dropOptionsRef"
class="options rounded-sm" class="options rounded-sm shadow-lg"
v-if="showDropDown" v-if="showDropDown"
> >
<div class="option selected" value="1">Albums</div> <div
<div class="option" value="2">Singles & EPs</div> class="option"
<div class="option" value="3">Appearances</div> v-for="a in albums"
@click.prevent="switchView(a)"
>
{{ a }}
</div>
</div> </div>
</div> </div>
<button class="rounded-sm"><GridSvg /></button> <button class="rounded-sm"><GridSvg /></button>
@@ -29,6 +32,11 @@ import { onClickOutside } from "@vueuse/core";
import ArrowSvg from "@/assets/icons/expand.svg"; import ArrowSvg from "@/assets/icons/expand.svg";
import GridSvg from "@/assets/icons/grid.svg"; import GridSvg from "@/assets/icons/grid.svg";
import { Ref, ref } from "vue"; import { Ref, ref } from "vue";
import { discographyAlbumTypes as albums } from "@/composables/enums";
import useArtistDiscogStore from "@/stores/pages/artistDiscog";
const store = useArtistDiscogStore();
const showDropDown = ref(false); const showDropDown = ref(false);
const dropOptionsRef: Ref<HTMLElement | undefined> = ref(); const dropOptionsRef: Ref<HTMLElement | undefined> = ref();
@@ -37,6 +45,11 @@ function hideDropDown() {
showDropDown.value = false; showDropDown.value = false;
} }
function switchView(album: albums) {
store.setAlbums(album);
hideDropDown();
}
onClickOutside(dropOptionsRef, (e) => { onClickOutside(dropOptionsRef, (e) => {
e.stopImmediatePropagation(); e.stopImmediatePropagation();
hideDropDown(); hideDropDown();
+1 -1
View File
@@ -34,7 +34,7 @@ import { Routes } from "@/router/routes";
const props = defineProps<{ const props = defineProps<{
artists: Artist[] | null; artists: Artist[] | null;
albumartists: Artist[] | null; albumartists: Artist[] | string | null;
small?: boolean; small?: boolean;
smaller?: boolean; smaller?: boolean;
}>(); }>();
+9 -1
View File
@@ -20,7 +20,7 @@ export enum FromOptions {
album = "album", album = "album",
search = "search", search = "search",
artist = "artist", artist = "artist",
albumCard = "albumCard" albumCard = "albumCard",
} }
export enum ContextSrc { export enum ContextSrc {
@@ -43,3 +43,11 @@ export enum contextChildrenShowMode {
click = "click", click = "click",
hover = "hover", hover = "hover",
} }
export enum discographyAlbumTypes {
all = "All",
albums = "Albums",
singles = "Singles",
eps = "EPs",
appearances = "Appearances",
}
+2 -2
View File
@@ -20,7 +20,7 @@ const getArtistData = async (hash: string, limit: number = 5) => {
return data as ArtistData; return data as ArtistData;
}; };
const getArtistAlbums = async (hash: string, limit = 6) => { const getArtistAlbums = async (hash: string, all = false, limit = 6) => {
interface ArtistAlbums { interface ArtistAlbums {
albums: Album[]; albums: Album[];
eps: Album[]; eps: Album[];
@@ -30,7 +30,7 @@ const getArtistAlbums = async (hash: string, limit = 6) => {
const { data, error } = await useAxios({ const { data, error } = await useAxios({
get: true, get: true,
url: paths.api.artist + `/${hash}/albums?limit=${limit}`, url: paths.api.artist + `/${hash}/albums?limit=${limit}&all=${all}`,
}); });
if (error) { if (error) {
+63
View File
@@ -0,0 +1,63 @@
import { defineStore } from "pinia";
import { discographyAlbumTypes } from "@/composables/enums";
import { Album } from "@/interfaces";
import { getArtistAlbums } from "@/composables/fetch/artists";
export default defineStore("artistDiscography", {
state: () => ({
artist: <string>"",
page: discographyAlbumTypes.all,
toShow: <Album[]>[],
albums: <Album[]>[],
eps: <Album[]>[],
singles: <Album[]>[],
appearances: <Album[]>[],
}),
actions: {
setAlbums(page: discographyAlbumTypes) {
switch (page) {
case discographyAlbumTypes.albums:
this.toShow = this.albums;
break;
case discographyAlbumTypes.eps:
this.toShow = this.eps;
break;
case discographyAlbumTypes.singles:
this.toShow = this.singles;
break;
case discographyAlbumTypes.appearances:
this.toShow = this.appearances;
break;
default:
this.toShow = this.albums.concat(
this.eps,
this.singles,
this.appearances
);
}
},
setPage(page: discographyAlbumTypes) {
this.page = page;
},
fetchAlbums(artisthash: string) {
getArtistAlbums(artisthash, true)
.then((data) => {
this.albums = data.albums;
this.eps = data.eps;
this.singles = data.singles;
this.appearances = data.appearances;
})
.then(() => this.setAlbums(this.page));
},
resetAlbums() {
this.albums = [];
this.eps = [];
this.singles = [];
this.appearances = [];
this.toShow = [];
},
},
});
+14 -5
View File
@@ -37,6 +37,7 @@ import Header from "@/components/AlbumView/Header.vue";
import SongItem from "@/components/shared/SongItem.vue"; import SongItem from "@/components/shared/SongItem.vue";
import { isSmall } from "@/stores/content-width"; import { isSmall } from "@/stores/content-width";
import { discographyAlbumTypes } from "@/composables/enums";
const album = useAlbumStore(); const album = useAlbumStore();
const queue = useQueueStore(); const queue = useQueueStore();
@@ -80,14 +81,22 @@ function getSongItems() {
} }
function getArtistAlbumComponents(): ScrollerItem[] { function getArtistAlbumComponents(): ScrollerItem[] {
return album.albumArtists.map((artist) => { return album.albumArtists.map((ar) => {
const artist_name = album.info.albumartists.find( const artist = album.info.albumartists.find(
(a) => a.artisthash === artist.artisthash (a) => a.artisthash === ar.artisthash
)?.name; );
const artistname = artist?.name;
const artisthash = artist?.artisthash;
return { return {
id: Math.random().toString(), id: Math.random().toString(),
component: ArtistAlbums, component: ArtistAlbums,
props: { title: `More from ${artist_name}`, albums: artist.albums }, props: {
artisthash,
albums: ar.albums,
title: `More from ${artistname}`,
albumType: discographyAlbumTypes.all,
},
size: 20 * 16, size: 20 * 16,
}; };
}); });
+18 -15
View File
@@ -1,43 +1,46 @@
<template> <template>
<div class="album-grid-view v-scroll-page"> <div class="album-grid-view v-scroll-page">
<div class="scrollable"> <div class="scrollable" v-auto-animate="{ duration: 100 }">
<AlbumCard v-for="album in albums" :album="album" :key="Math.random()" /> <AlbumCard
v-for="album in artist.toShow"
:album="album"
:key="album.albumhash"
/>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import useArtistPageStore from "@/stores/pages/artist"; import useArtistDiscographyStore from "@/stores/pages/artistDiscog";
import AlbumCard from "@/components/shared/AlbumCard.vue"; import AlbumCard from "@/components/shared/AlbumCard.vue";
import { getArtistAlbums } from "@/composables/fetch/artists";
import { onMounted, ref } from "vue"; import { onMounted } from "vue";
import { useRoute } from "vue-router"; import { onBeforeRouteLeave, useRoute } from "vue-router";
import { Album } from "@/interfaces";
const artist = useArtistPageStore(); const artist = useArtistDiscographyStore();
const route = useRoute(); const route = useRoute();
const albums = ref(<Album[]>[]);
onMounted(() => { onMounted(() => {
// artist.getArtistAlbums(route.params.hash); artist.fetchAlbums(route.params.hash as string);
getArtistAlbums(route.params.hash as string).then((res) => {
albums.value = res.appearances;
// console.log(albums.value);
}); });
onBeforeRouteLeave(() => {
artist.resetAlbums();
}); });
</script> </script>
<style lang="scss"> <style lang="scss">
.album-grid-view { .album-grid-view {
// border: solid; height: 100%;
.scrollable { .scrollable {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
grid-gap: $small; grid-gap: $small;
padding: 0 1rem; padding: 0 1rem;
padding-bottom: 4rem;
overflow: auto;
max-height: 100%;
} }
} }
</style> </style>
+40 -8
View File
@@ -22,7 +22,6 @@
:is="item.component" :is="item.component"
v-bind="item.props" v-bind="item.props"
></component> ></component>
<!-- @playThis="playFromPage(item.props.index - 1)" -->
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
@@ -38,10 +37,12 @@ import useArtistPageStore from "@/stores/pages/artist";
import ArtistAlbums from "@/components/AlbumView/ArtistAlbums.vue"; import ArtistAlbums from "@/components/AlbumView/ArtistAlbums.vue";
import ArtistAlbumsFetcher from "@/components/ArtistView/ArtistAlbumsFetcher.vue"; import ArtistAlbumsFetcher from "@/components/ArtistView/ArtistAlbumsFetcher.vue";
import { computed } from "vue"; import { computed } from "vue";
import { onBeforeRouteLeave, onBeforeRouteUpdate } from "vue-router"; import { onBeforeRouteLeave, onBeforeRouteUpdate, useRoute } from "vue-router";
import { Album } from "@/interfaces"; import { Album } from "@/interfaces";
import { discographyAlbumTypes } from "@/composables/enums";
const store = useArtistPageStore(); const store = useArtistPageStore();
const route = useRoute();
interface ScrollerItem { interface ScrollerItem {
id: string | number; id: string | number;
@@ -64,13 +65,41 @@ const artist_albums_fetcher: ScrollerItem = {
component: ArtistAlbumsFetcher, component: ArtistAlbumsFetcher,
}; };
function createAbumComponent(title: string, albums: Album[]) { enum AlbumType {
ALBUMS = "Albums",
EPS = "EPs",
SINGLES = "Singles",
APPEARANCES = "Appearances",
}
function createAbumComponent(title: AlbumType, albums: Album[]) {
let albumType = null;
switch (title) {
case AlbumType.ALBUMS:
albumType = discographyAlbumTypes.albums;
break;
case AlbumType.EPS:
albumType = discographyAlbumTypes.eps;
break;
case AlbumType.SINGLES:
albumType = discographyAlbumTypes.singles;
break;
case AlbumType.APPEARANCES:
albumType = discographyAlbumTypes.appearances;
break;
default:
break;
}
return { return {
id: title, id: title,
component: ArtistAlbums, component: ArtistAlbums,
props: { props: {
title, albumType,
albums, albums,
title,
artisthash: route.params.hash,
}, },
}; };
} }
@@ -85,22 +114,25 @@ const scrollerItems = computed(() => {
components = [...components, artist_albums_fetcher]; components = [...components, artist_albums_fetcher];
if (store.albums.length > 0) { if (store.albums.length > 0) {
const albums = createAbumComponent("Albums", store.albums); const albums = createAbumComponent(AlbumType.ALBUMS, store.albums);
components.push(albums); components.push(albums);
} }
if (store.eps.length > 0) { if (store.eps.length > 0) {
const eps = createAbumComponent("EPs", store.eps); const eps = createAbumComponent(AlbumType.EPS, store.eps);
components.push(eps); components.push(eps);
} }
if (store.singles.length > 0) { if (store.singles.length > 0) {
const singles = createAbumComponent("Singles", store.singles); const singles = createAbumComponent(AlbumType.SINGLES, store.singles);
components.push(singles); components.push(singles);
} }
if (store.appearances.length > 0) { if (store.appearances.length > 0) {
const appearances = createAbumComponent("Appearances", store.appearances); const appearances = createAbumComponent(
AlbumType.APPEARANCES,
store.appearances
);
components.push(appearances); components.push(appearances);
} }