mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-07-28 13:41:42 +00:00
build artist page
+ connect artist page to backend ~ bugs introduced as there are hashing changes in the backend [will fix later]
This commit is contained in:
parent
fff2c53801
commit
075765088f
@ -15,7 +15,7 @@ $larger: 2rem;
|
||||
|
||||
$banner-height: 18rem;
|
||||
$song-item-height: 4rem;
|
||||
$content-padding-bottom: 4rem;
|
||||
$content-padding-bottom: 2rem;
|
||||
|
||||
// apple human design guideline colors
|
||||
$black: #181a1c;
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="albums-from-artist">
|
||||
<h3>
|
||||
<span>More from {{ artist.artist }} </span>
|
||||
<span>{{ title }} </span>
|
||||
<span class="see-more">SEE ALL</span>
|
||||
</h3>
|
||||
<div class="cards">
|
||||
<AlbumCard v-for="a in artist.albums" :album="a" />
|
||||
<AlbumCard v-for="a in albums" :album="a" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -13,26 +13,25 @@
|
||||
<script setup lang="ts">
|
||||
import AlbumCard from "../shared/AlbumCard.vue";
|
||||
|
||||
import { AlbumInfo } from "@/interfaces";
|
||||
import { Album } from "@/interfaces";
|
||||
|
||||
defineProps<{
|
||||
artist: {
|
||||
artist: string;
|
||||
albums: AlbumInfo[];
|
||||
};
|
||||
title: string;
|
||||
albums: Album[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.albums-from-artist {
|
||||
overflow: hidden;
|
||||
padding-top: 2rem;
|
||||
padding-top: 1rem;
|
||||
|
||||
h3 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr max-content;
|
||||
align-items: center;
|
||||
padding: 0 $medium;
|
||||
margin-bottom: $small;
|
||||
|
||||
.see-more {
|
||||
font-size: $medium;
|
||||
|
@ -53,14 +53,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="art" v-if="!albumHeaderSmall">
|
||||
<img
|
||||
<RouterLink
|
||||
v-for="a in album.albumartists"
|
||||
:src="imguri.artist + a.image"
|
||||
class="shadow-lg circular"
|
||||
loading="lazy"
|
||||
:title="a.name"
|
||||
:style="{ border: `solid 2px ${album.colors[0]}` }"
|
||||
/>
|
||||
:to="{
|
||||
name: Routes.artist,
|
||||
params: { hash: a.hash },
|
||||
}"
|
||||
>
|
||||
<img
|
||||
:src="imguri.artist + a.image"
|
||||
class="shadow-lg circular"
|
||||
loading="lazy"
|
||||
:title="a.name"
|
||||
:style="{ border: `solid 2px ${album.colors[0]}` }"
|
||||
/>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -69,20 +76,20 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
|
||||
import ArtistName from "@/components/shared/ArtistName.vue";
|
||||
import { paths } from "@/config";
|
||||
import { albumHeaderSmall } from "@/stores/content-width";
|
||||
import useNavStore from "@/stores/nav";
|
||||
import useAlbumStore from "@/stores/pages/album";
|
||||
import { formatSeconds, useVisibility } from "@/utils";
|
||||
import { isLight } from "../../composables/colors/album";
|
||||
import { playSources } from "../../composables/enums";
|
||||
import { AlbumInfo } from "../../interfaces";
|
||||
import ArtistName from "@/components/shared/ArtistName.vue";
|
||||
import { playSources, Routes } from "../../composables/enums";
|
||||
import { Album } from "../../interfaces";
|
||||
|
||||
import PlayBtnRect from "../shared/PlayBtnRect.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
album: AlbumInfo;
|
||||
album: Album;
|
||||
}>();
|
||||
|
||||
const albumheaderthing = ref<any>(null);
|
||||
|
53
src/components/ArtistView/Albums.vue
Normal file
53
src/components/ArtistView/Albums.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="albums-list">
|
||||
<div class="section-title">
|
||||
<b>
|
||||
{{ title }}
|
||||
</b>
|
||||
<div class="see-all"><b>SEE ALL</b></div>
|
||||
</div>
|
||||
<div class="cars">
|
||||
<AlbumCard
|
||||
v-for="album in search.albums.value.slice(0, 6)"
|
||||
:album="album"
|
||||
:key="Math.random()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import AlbumCard from "../shared/AlbumCard.vue";
|
||||
import useSearchStore from "@/stores/search";
|
||||
|
||||
defineProps<{
|
||||
// albums: Album[];
|
||||
title: string;
|
||||
}>();
|
||||
|
||||
const search = useSearchStore();
|
||||
|
||||
// TODO: use AlbumView's ArtistAlbums component instead of this
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.albums-list {
|
||||
.section-title {
|
||||
margin: 0;
|
||||
margin-bottom: -$small;
|
||||
|
||||
.see-all {
|
||||
float: right;
|
||||
font-size: small;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.cars {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||
// padding: 1rem 0;
|
||||
// gap: 2rem 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,9 +1,119 @@
|
||||
<template>
|
||||
<div class="artist-page-header">
|
||||
This is the header
|
||||
<div class="artist-page-header rounded no-scroll">
|
||||
<div
|
||||
class="artist-info"
|
||||
:class="{
|
||||
nocontrast: artist.info.colors ? isLight(artist.info.colors[0]) : false,
|
||||
}"
|
||||
>
|
||||
<section class="text">
|
||||
<div class="card-title">ARTIST</div>
|
||||
<div class="artist-name">{{ artist.info.name }}</div>
|
||||
<div class="stats">
|
||||
{{ artist.info.trackcount }} Tracks •
|
||||
{{ artist.info.albumcount }} Albums •
|
||||
{{ formatSeconds(artist.info.duration, true) }}
|
||||
</div>
|
||||
</section>
|
||||
<PlayBtnRect />
|
||||
</div>
|
||||
<div class="artist-img">
|
||||
<img :src="paths.images.artist + artist.info.image" />
|
||||
</div>
|
||||
<div
|
||||
class="gradient"
|
||||
:style="{
|
||||
backgroundImage: `linear-gradient(to left, transparent 10%,
|
||||
${artist.info.colors[0]} 50%,
|
||||
${artist.info.colors[0]} 100%)`,
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import useArtistPageStore from "@/stores/pages/artist";
|
||||
import PlayBtnRect from "../shared/PlayBtnRect.vue";
|
||||
import formatSeconds from "@/utils/useFormatSeconds";
|
||||
import { isLight } from "@/composables/colors/album";
|
||||
import { paths } from "@/config";
|
||||
|
||||
<style lang="scss"></style>
|
||||
const artist = useArtistPageStore();
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.artist-page-header {
|
||||
height: 18rem;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
position: relative;
|
||||
|
||||
.artist-img {
|
||||
height: 18rem;
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
object-position: 0% 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.gradient {
|
||||
position: absolute;
|
||||
background-image: linear-gradient(
|
||||
to left,
|
||||
transparent 10%,
|
||||
#434142 50%,
|
||||
#434142 100%
|
||||
);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.artist-info {
|
||||
z-index: 1;
|
||||
padding: 1rem;
|
||||
padding-right: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
|
||||
gap: 1rem;
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $small;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
opacity: 0.5;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.artist-name {
|
||||
font-size: 3rem;
|
||||
font-weight: bold;
|
||||
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.stats {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.playbtnrect {
|
||||
border-radius: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.artist-info.nocontrast {
|
||||
color: $black;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
33
src/components/ArtistView/TopTracks.vue
Normal file
33
src/components/ArtistView/TopTracks.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="artist-top-tracks">
|
||||
<h3 class="section-title">Tracks</h3>
|
||||
<div class="tracks">
|
||||
<SongItem
|
||||
v-for="(song, index) in artist.tracks"
|
||||
:track="song"
|
||||
:index="index + 1"
|
||||
:isCurrent="false"
|
||||
:isCurrentPlaying="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import useQueueStore from "@/stores/queue";
|
||||
import SongItem from "../shared/SongItem.vue";
|
||||
import useArtistPageStore from "@/stores/pages/artist";
|
||||
|
||||
const queue = useQueueStore();
|
||||
const artist = useArtistPageStore();
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.artist-top-tracks {
|
||||
// padding-bottom: 2rem;
|
||||
|
||||
.section-title {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -16,11 +16,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { paths } from "../../config";
|
||||
import { AlbumInfo } from "../../interfaces";
|
||||
import { Album } from "../../interfaces";
|
||||
|
||||
const imguri = paths.images.thumb.large;
|
||||
defineProps<{
|
||||
album: AlbumInfo;
|
||||
album: Album;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
|
@ -31,6 +31,7 @@ export enum Routes {
|
||||
playlists = "PlaylistList",
|
||||
playlist = "PlaylistView",
|
||||
albums = "AlbumsView",
|
||||
artist = "ArtistView",
|
||||
album = "AlbumView",
|
||||
artists = "ArtistsView",
|
||||
settings = "SettingsView",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { paths } from "@/config";
|
||||
import { NotifType, useNotifStore } from "@/stores/notification";
|
||||
import { AlbumInfo, Track } from "../../interfaces";
|
||||
import { Album, Track } from "../../interfaces";
|
||||
import useAxios from "./useAxios";
|
||||
|
||||
const {
|
||||
@ -12,7 +12,7 @@ const {
|
||||
|
||||
const getAlbumData = async (hash: string, ToastStore: typeof useNotifStore) => {
|
||||
interface AlbumData {
|
||||
info: AlbumInfo;
|
||||
info: Album;
|
||||
tracks: Track[];
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ const getAlbumData = async (hash: string, ToastStore: typeof useNotifStore) => {
|
||||
if (status == 204) {
|
||||
ToastStore().showNotification("Album not created yet!", NotifType.Error);
|
||||
return {
|
||||
info: {} as AlbumInfo,
|
||||
info: {} as Album,
|
||||
tracks: [],
|
||||
};
|
||||
}
|
||||
@ -88,9 +88,9 @@ const getAlbumsFromArtist = async (
|
||||
};
|
||||
|
||||
export {
|
||||
getAlbumData as getAlbumTracks,
|
||||
getAlbumArtists,
|
||||
getAlbumBio,
|
||||
getAlbumsFromArtist,
|
||||
getAlbumData as getAlbumTracks,
|
||||
getAlbumArtists,
|
||||
getAlbumBio,
|
||||
getAlbumsFromArtist,
|
||||
};
|
||||
|
||||
|
26
src/composables/fetch/artists.ts
Normal file
26
src/composables/fetch/artists.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { paths } from "@/config";
|
||||
import useAxios from "./useAxios";
|
||||
import { Artist, Track, Album } from "@/interfaces";
|
||||
|
||||
const getArtistData = async (hash: string) => {
|
||||
interface ArtistData {
|
||||
artist: Artist;
|
||||
albums: Album[];
|
||||
tracks: Track[];
|
||||
}
|
||||
|
||||
const { data, error } = await useAxios({
|
||||
get: true,
|
||||
url: paths.api.artist + `/${hash}`,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
console.log(data);
|
||||
|
||||
return data as ArtistData;
|
||||
};
|
||||
|
||||
export { getArtistData };
|
@ -38,14 +38,15 @@ const baseApiUrl = domain() + ports.api;
|
||||
const paths = {
|
||||
api: {
|
||||
album: baseApiUrl + "/album",
|
||||
artist: baseApiUrl + "/artist",
|
||||
get albumartists() {
|
||||
return this.album + "/artists";
|
||||
},
|
||||
get albumbio() {
|
||||
return this.album + "/bio";
|
||||
},
|
||||
get albumsByArtistUrl(){
|
||||
return this.album + "/from-artist"
|
||||
get albumsByArtistUrl() {
|
||||
return this.album + "/from-artist";
|
||||
},
|
||||
folder: baseApiUrl + "/folder",
|
||||
playlist: {
|
||||
|
@ -34,7 +34,7 @@ export interface Folder {
|
||||
is_sym: boolean;
|
||||
}
|
||||
|
||||
export interface AlbumInfo {
|
||||
export interface Album {
|
||||
albumid: string;
|
||||
title: string;
|
||||
albumartists: {
|
||||
@ -61,6 +61,11 @@ export interface AlbumInfo {
|
||||
export interface Artist {
|
||||
name: string;
|
||||
image: string;
|
||||
artisthash: string;
|
||||
trackcount: number;
|
||||
albumcount: number;
|
||||
duration: number;
|
||||
colors: string[];
|
||||
}
|
||||
|
||||
export interface Option {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import state from "@/composables/state";
|
||||
import useAStore from "@/stores/pages/album";
|
||||
import useFStore from "@/stores/pages/folder";
|
||||
import usePTrackStore from "@/stores/pages/playlist";
|
||||
import usePStore from "@/stores/pages/playlists";
|
||||
import useAlbumPageStore from "@/stores/pages/album";
|
||||
import useFolderPageStore from "@/stores/pages/folder";
|
||||
import usePlaylistPageStore from "@/stores/pages/playlist";
|
||||
import usePlaylistListPageStore from "@/stores/pages/playlists";
|
||||
import useArtistPageStore from "@/stores/pages/artist";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -16,7 +17,7 @@ const routes = [
|
||||
component: () => import("@/views/FolderView.vue"),
|
||||
beforeEnter: async (to: any) => {
|
||||
state.loading.value = true;
|
||||
await useFStore()
|
||||
await useFolderPageStore()
|
||||
.fetchAll(to.params.path)
|
||||
.then(() => {
|
||||
state.loading.value = false;
|
||||
@ -29,7 +30,7 @@ const routes = [
|
||||
component: () => import("@/views/PlaylistList.vue"),
|
||||
beforeEnter: async () => {
|
||||
state.loading.value = true;
|
||||
await usePStore()
|
||||
await usePlaylistListPageStore()
|
||||
.fetchAll()
|
||||
.then(() => {
|
||||
state.loading.value = false;
|
||||
@ -42,7 +43,7 @@ const routes = [
|
||||
component: () => import("@/views/PlaylistView/index.vue"),
|
||||
beforeEnter: async (to: any) => {
|
||||
state.loading.value = true;
|
||||
await usePTrackStore()
|
||||
await usePlaylistPageStore()
|
||||
.fetchAll(to.params.pid)
|
||||
.then(() => {
|
||||
state.loading.value = false;
|
||||
@ -60,7 +61,7 @@ const routes = [
|
||||
component: () => import("@/views/AlbumView/index.vue"),
|
||||
beforeEnter: async (to: any) => {
|
||||
state.loading.value = true;
|
||||
const store = useAStore();
|
||||
const store = useAlbumPageStore();
|
||||
|
||||
await store.fetchTracksAndArtists(to.params.hash).then(() => {
|
||||
state.loading.value = false;
|
||||
@ -76,6 +77,15 @@ const routes = [
|
||||
path: "/artists/:hash",
|
||||
name: "ArtistView",
|
||||
component: () => import("@/views/ArtistView"),
|
||||
beforeEnter: async (to: any) => {
|
||||
state.loading.value = true;
|
||||
|
||||
await useArtistPageStore()
|
||||
.getData(to.params.hash)
|
||||
.then(() => {
|
||||
state.loading.value = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/settings",
|
||||
|
@ -7,10 +7,10 @@ import { FuseTrackOptions } from "@/composables/enums";
|
||||
import { content_width } from "@/stores/content-width";
|
||||
|
||||
import {
|
||||
getAlbumsFromArtist,
|
||||
getAlbumTracks,
|
||||
getAlbumsFromArtist,
|
||||
getAlbumTracks
|
||||
} from "../../composables/fetch/album";
|
||||
import { AlbumInfo, Artist, FuseResult, Track } from "../../interfaces";
|
||||
import { Album, Artist, FuseResult, Track } from "../../interfaces";
|
||||
import { useNotifStore } from "../notification";
|
||||
|
||||
interface Disc {
|
||||
@ -27,7 +27,7 @@ function sortByTrackNumber(tracks: Track[]) {
|
||||
});
|
||||
}
|
||||
|
||||
function albumHasNoDiscs(album: AlbumInfo) {
|
||||
function albumHasNoDiscs(album: Album) {
|
||||
if (album.is_single) return true;
|
||||
|
||||
return false;
|
||||
@ -50,10 +50,10 @@ function createDiscs(tracks: Track[]) {
|
||||
export default defineStore("album", {
|
||||
state: () => ({
|
||||
query: "",
|
||||
info: <AlbumInfo>{},
|
||||
info: <Album>{},
|
||||
rawTracks: <Track[]>[],
|
||||
artists: <Artist[]>[],
|
||||
albumArtists: <{ artist: string; albums: AlbumInfo[] }[]>[],
|
||||
albumArtists: <{ artist: string; albums: Album[] }[]>[],
|
||||
bio: null,
|
||||
}),
|
||||
actions: {
|
||||
|
21
src/stores/pages/artist.ts
Normal file
21
src/stores/pages/artist.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
import { Artist, Album, Track } from "@/interfaces";
|
||||
import { getArtistData } from "@/composables/fetch/artists";
|
||||
|
||||
export default defineStore("artistPage", {
|
||||
state: () => ({
|
||||
info: <Artist>{},
|
||||
albums: <Album[]>[],
|
||||
tracks: <Track[]>[],
|
||||
}),
|
||||
actions: {
|
||||
async getData(hash: string) {
|
||||
const { artist, albums, tracks } = await getArtistData(hash);
|
||||
|
||||
this.info = artist;
|
||||
this.albums = albums;
|
||||
this.tracks = tracks;
|
||||
},
|
||||
},
|
||||
});
|
@ -1,20 +1,17 @@
|
||||
import { Routes } from "./../composables/enums";
|
||||
import { ref, reactive } from "@vue/reactivity";
|
||||
import { defineStore } from "pinia";
|
||||
import { AlbumInfo, Artist, Playlist, Track } from "../interfaces";
|
||||
import {
|
||||
searchTracks,
|
||||
searchAlbums,
|
||||
searchArtists,
|
||||
loadMoreTracks,
|
||||
loadMoreAlbums,
|
||||
loadMoreArtists,
|
||||
} from "../composables/fetch/searchMusic";
|
||||
import { watch } from "vue";
|
||||
import useTabStore from "./tabs";
|
||||
import useLoaderStore from "./loader";
|
||||
import { useRoute } from "vue-router";
|
||||
import { reactive, ref } from "@vue/reactivity";
|
||||
import { useDebounce } from "@vueuse/core";
|
||||
import { defineStore } from "pinia";
|
||||
import { watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import {
|
||||
loadMoreAlbums,
|
||||
loadMoreArtists, loadMoreTracks, searchAlbums,
|
||||
searchArtists, searchTracks
|
||||
} from "../composables/fetch/searchMusic";
|
||||
import { Album, Artist, Playlist, Track } from "../interfaces";
|
||||
import { Routes } from "./../composables/enums";
|
||||
import useLoaderStore from "./loader";
|
||||
import useTabStore from "./tabs";
|
||||
/**
|
||||
*
|
||||
* Scrolls on clicking the loadmore button
|
||||
@ -56,7 +53,7 @@ export default defineStore("search", () => {
|
||||
|
||||
const albums = reactive({
|
||||
query: "",
|
||||
value: <AlbumInfo[]>[],
|
||||
value: <Album[]>[],
|
||||
more: false,
|
||||
});
|
||||
|
||||
|
@ -4,16 +4,28 @@
|
||||
style="height: 100%"
|
||||
:class="{ isSmall, isMedium }"
|
||||
>
|
||||
<RecycleScroller
|
||||
class="scroller"
|
||||
<DynamicScroller
|
||||
:items="scrollerItems"
|
||||
:item-size="null"
|
||||
key-field="id"
|
||||
v-slot="{ item }"
|
||||
:min-item-size="64"
|
||||
class="scroller"
|
||||
style="height: 100%"
|
||||
>
|
||||
<component :is="item.component" v-bind="item.props" />
|
||||
</RecycleScroller>
|
||||
<template v-slot="{ item, index, active }">
|
||||
<DynamicScrollerItem
|
||||
:item="item"
|
||||
:active="active"
|
||||
:size-dependencies="[item.props]"
|
||||
:data-index="index"
|
||||
>
|
||||
<component
|
||||
:key="index"
|
||||
:is="item.component"
|
||||
v-bind="item.props"
|
||||
></component>
|
||||
<!-- @playThis="playFromPage(item.props.index - 1)" -->
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
</DynamicScroller>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -21,29 +33,54 @@
|
||||
import { isMedium, isSmall } from "@/stores/content-width";
|
||||
|
||||
import Header from "@/components/ArtistView/Header.vue";
|
||||
import TopTracks from "@/components/ArtistView/TopTracks.vue";
|
||||
// import Albums from "@/components/ArtistView/Albums.vue";
|
||||
import useArtistPageStore from "@/stores/pages/artist";
|
||||
import ArtistAlbums from "@/components/AlbumView/ArtistAlbums.vue";
|
||||
|
||||
import { computed } from "vue";
|
||||
import { onBeforeRouteUpdate } from "vue-router";
|
||||
|
||||
const artistStore = useArtistPageStore();
|
||||
|
||||
interface ScrollerItem {
|
||||
id: string | number;
|
||||
component: typeof Header;
|
||||
// props: Record<string, unknown>;
|
||||
size: number;
|
||||
component: any;
|
||||
props?: Record<string, unknown>;
|
||||
// size: number;
|
||||
}
|
||||
|
||||
const header: ScrollerItem = {
|
||||
id: "artist-header",
|
||||
component: Header,
|
||||
size: 19 * 16,
|
||||
// size: 16 * 19,
|
||||
};
|
||||
|
||||
const top_tracks: ScrollerItem = {
|
||||
id: "artist-top-tracks",
|
||||
component: TopTracks,
|
||||
// size: 16 * 25,
|
||||
};
|
||||
|
||||
const artistAlbums: ScrollerItem = {
|
||||
id: "artist-albums",
|
||||
component: ArtistAlbums,
|
||||
// size: 16 * 16,
|
||||
props: { title: "Albums", albums: artistStore.albums },
|
||||
};
|
||||
|
||||
const scrollerItems = computed(() => {
|
||||
return [header];
|
||||
return [header, top_tracks, artistAlbums];
|
||||
});
|
||||
|
||||
onBeforeRouteUpdate((to, from, next) => {
|
||||
artistStore.getData(to.params.hash as string);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.artist-page {
|
||||
border: solid 1px;
|
||||
|
||||
.section-title {
|
||||
margin: 1rem;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user