mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-05 04:53:01 +00:00
setup artist discography page
This commit is contained in:
committed by
Mungai Njoroge
parent
fd863d188c
commit
35a8446f8b
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}>();
|
}>();
|
||||||
|
|||||||
@@ -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",
|
||||||
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 = [];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -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,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
+19
-16
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user