add functionality to play button on artist page

This commit is contained in:
geoffrey45
2022-12-06 23:29:14 +03:00
committed by Mungai Njoroge
parent bb95011dff
commit 90dd1a1fe8
12 changed files with 145 additions and 43 deletions
+6 -5
View File
@@ -1,20 +1,21 @@
<template> <template>
<div class="albums-from-artist"> <div class="artist-albums">
<h3> <h3>
<span>{{ title }} </span> <span>{{ title }} </span>
<span class="see-more">SEE ALL</span> <span class="see-more">SEE ALL</span>
</h3> </h3>
<div class="cards"> <div class="cards">
<AlbumCard v-for="a in albums" :album="a" /> <AlbumCard v-for="a in albums.slice(0, maxAbumCards)" :album="a" />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import AlbumCard from "../shared/AlbumCard.vue"; import AlbumCard from "../shared/AlbumCard.vue";
import { Album } from "@/interfaces"; import { Album } from "@/interfaces";
import { maxAbumCards } from "@/stores/content-width";
defineProps<{ defineProps<{
title: string; title: string;
albums: Album[]; albums: Album[];
@@ -22,7 +23,7 @@ defineProps<{
</script> </script>
<style lang="scss"> <style lang="scss">
.albums-from-artist { .artist-albums {
overflow: hidden; overflow: hidden;
h3 { h3 {
@@ -40,7 +41,7 @@ defineProps<{
.cards { .cards {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
gap: 2rem 0; gap: 5rem 0;
} }
} }
</style> </style>
+5 -2
View File
@@ -20,7 +20,7 @@
{{ formatSeconds(artist.info.duration, true) }} {{ formatSeconds(artist.info.duration, true) }}
</div> </div>
</section> </section>
<PlayBtnRect /> <PlayBtnRect :source="playSources.artist" :store="useArtistPageStore" />
</div> </div>
<div class="artist-img no-select"> <div class="artist-img no-select">
<img :src="paths.images.artist.large + artist.info.image" /> <img :src="paths.images.artist.large + artist.info.image" />
@@ -28,7 +28,7 @@
<div <div
class="gradient" class="gradient"
:style="{ :style="{
backgroundImage: `linear-gradient(to left, transparent 10%, backgroundImage: `linear-gradient(to left, transparent 40%,
${artist.info.colors[0]} 50%, ${artist.info.colors[0]} 50%,
${artist.info.colors[0]} 100%)`, ${artist.info.colors[0]} 100%)`,
}" }"
@@ -42,6 +42,7 @@ import PlayBtnRect from "../shared/PlayBtnRect.vue";
import formatSeconds from "@/utils/useFormatSeconds"; import formatSeconds from "@/utils/useFormatSeconds";
import { isLight } from "@/composables/colors/album"; import { isLight } from "@/composables/colors/album";
import { paths } from "@/config"; import { paths } from "@/config";
import { playSources } from "@/composables/enums";
const artist = useArtistPageStore(); const artist = useArtistPageStore();
</script> </script>
@@ -55,9 +56,11 @@ const artist = useArtistPageStore();
.artist-img { .artist-img {
height: 18rem; height: 18rem;
img { img {
height: 100%; height: 100%;
width: 100%; width: 100%;
aspect-ratio: 1;
object-fit: cover; object-fit: cover;
object-position: 0% 20%; object-position: 0% 20%;
} }
+1 -1
View File
@@ -23,8 +23,8 @@ const artist = useArtistPageStore();
<style lang="scss"> <style lang="scss">
.artist-top-tracks { .artist-top-tracks {
margin-bottom: 1rem;
margin-top: 2rem; margin-top: 2rem;
.section-title { .section-title {
margin-left: 0; margin-left: 0;
} }
+13
View File
@@ -24,6 +24,7 @@ import AlbumSvg from "@/assets/icons/album.svg";
import FolderSvg from "@/assets/icons/folder.svg"; import FolderSvg from "@/assets/icons/folder.svg";
import PlaylistSvg from "@/assets/icons/playlist.svg"; import PlaylistSvg from "@/assets/icons/playlist.svg";
import SearchSvg from "@/assets/icons/search.svg"; import SearchSvg from "@/assets/icons/search.svg";
import ArtistSvg from "@/assets/icons/artist.svg";
import { RouteLocationRaw } from "vue-router"; import { RouteLocationRaw } from "vue-router";
@@ -82,6 +83,18 @@ function getSource() {
}, },
}; };
case FromOptions.artist:
return {
name: source.artistname,
icon: ArtistSvg,
location: {
name: Routes.artist,
params: {
hash: source.artisthash,
},
},
};
default: default:
return { name: "👻 No source", location: {} }; return { name: "👻 No source", location: {} };
} }
+4 -9
View File
@@ -1,8 +1,5 @@
<template> <template>
<button <button class="playbtnrect" @click="usePlayFrom(source, useQStore, store)">
class="playbtnrect"
@click="usePlayFrom(source, useQStore, store)"
>
<playBtnSvg /> <playBtnSvg />
<div class="text">Play</div> <div class="text">Play</div>
</button> </button>
@@ -14,20 +11,18 @@ import usePlayFrom from "@/composables/usePlayFrom";
import useFStore from "@/stores/pages/folder"; import useFStore from "@/stores/pages/folder";
import useAStore from "@/stores/pages/album"; import useAStore from "@/stores/pages/album";
import usePStore from "@/stores/pages/playlist"; import usePStore from "@/stores/pages/playlist";
import useArtistPageStore from "@/stores/pages/artist";
import useQStore from "@/stores/queue"; import useQStore from "@/stores/queue";
import playBtnSvg from "@/assets/icons/play.svg"; import playBtnSvg from "@/assets/icons/play.svg";
defineProps<{ defineProps<{
source: playSources; source: playSources;
background?: {
color: string;
isDark?: boolean;
};
store: store:
| typeof useQStore | typeof useQStore
| typeof useFStore | typeof useFStore
| typeof useAStore | typeof useAStore
| typeof usePStore; | typeof usePStore
| typeof useArtistPageStore;
}>(); }>();
</script> </script>
+2
View File
@@ -3,6 +3,7 @@ export enum playSources {
album, album,
search, search,
folder, folder,
artist,
} }
export enum NotifType { export enum NotifType {
@@ -16,6 +17,7 @@ export enum FromOptions {
folder = "folder", folder = "folder",
album = "album", album = "album",
search = "search", search = "search",
artist = "artist",
} }
export enum ContextSrc { export enum ContextSrc {
+21 -2
View File
@@ -21,6 +21,12 @@ const getArtistData = async (hash: string) => {
}; };
const getArtistAlbums = async (hash: string, limit = 6) => { const getArtistAlbums = async (hash: string, limit = 6) => {
interface ArtistAlbums {
albums: Album[];
eps: Album[];
singles: Album[];
}
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}`,
@@ -30,7 +36,20 @@ const getArtistAlbums = async (hash: string, limit = 6) => {
console.error(error); console.error(error);
} }
return data.albums as Album[]; return data as ArtistAlbums;
}; };
export { getArtistData, getArtistAlbums }; const getArtistTracks = async (hash: string, offset: number = 0, limit = 6) => {
const { data, error } = await useAxios({
get: true,
url: paths.api.artist + `/${hash}/tracks?offset=${offset}&limit=${limit}`,
});
if (error) {
console.error(error);
}
return data.tracks as Track[];
};
export { getArtistData, getArtistAlbums, getArtistTracks };
+25 -8
View File
@@ -2,16 +2,24 @@ import { playSources } from "@/composables/enums";
import useAStore from "@/stores/pages/album"; import useAStore from "@/stores/pages/album";
import useFStore from "@/stores/pages/folder"; import useFStore from "@/stores/pages/folder";
import usePStore from "@/stores/pages/playlist"; import usePStore from "@/stores/pages/playlist";
import useArtistPageStore from "@/stores/pages/artist";
import { getArtistTracks } from "./fetch/artists";
import useQStore from "@/stores/queue"; import useQStore from "@/stores/queue";
const queue = useQStore; const queue = useQStore;
const folder = useFStore; const folder = useFStore;
const album = useAStore; const album = useAStore;
const playlist = usePStore; const playlist = usePStore;
const artist = useArtistPageStore;
type store = typeof queue | typeof folder | typeof album | typeof playlist; type store =
| typeof queue
| typeof folder
| typeof album
| typeof playlist
| typeof artist;
export default function play( export default async function play(
source: playSources, source: playSources,
aqueue: typeof queue, aqueue: typeof queue,
store: store store: store
@@ -20,13 +28,13 @@ export default function play(
switch (source) { switch (source) {
// check which route the play request come from // check which route the play request come from
case playSources.folder: // case playSources.folder:
store = store as typeof folder; // store = store as typeof folder;
const f = store(); // const f = store();
useQueue.playFromFolder(f.path, f.allTracks); // useQueue.playFromFolder(f.path, f.tracks);
useQueue.play(); // useQueue.play();
break; // break;
case playSources.album: case playSources.album:
store = store as typeof album; store = store as typeof album;
const a_store = store(); const a_store = store();
@@ -47,5 +55,14 @@ export default function play(
useQueue.playFromPlaylist(p.info.name, p.info.id, p.tracks); useQueue.playFromPlaylist(p.info.name, p.info.id, p.tracks);
useQueue.play(); useQueue.play();
break; break;
case playSources.artist:
store = store as typeof artist;
const ar = store();
const tracks = await getArtistTracks(ar.info.artisthash);
useQueue.playFromArtist(ar.info.artisthash, ar.info.name, tracks);
useQueue.play();
} }
} }
+6
View File
@@ -110,6 +110,12 @@ export interface fromSearch {
query: string; query: string;
} }
export interface fromArtist {
type: FromOptions.artist;
artisthash: string;
artistname: string;
}
export interface subPath { export interface subPath {
name: string; name: string;
path: string; path: string;
+18 -5
View File
@@ -7,8 +7,10 @@ import { maxAbumCards } from "@/stores/content-width";
export default defineStore("artistPage", { export default defineStore("artistPage", {
state: () => ({ state: () => ({
info: <Artist>{}, info: <Artist>{},
albums: <Album[]>[],
tracks: <Track[]>[], tracks: <Track[]>[],
albums: <Album[]>[],
eps: <Album[]>[],
singles: <Album[]>[],
}), }),
actions: { actions: {
async getData(hash: string) { async getData(hash: string) {
@@ -18,17 +20,28 @@ export default defineStore("artistPage", {
this.tracks = tracks; this.tracks = tracks;
}, },
async getArtistAlbums() { async getArtistAlbums() {
const albums = await getArtistAlbums( const { albums, eps, singles } = await getArtistAlbums(
this.info.artisthash, this.info.artisthash,
maxAbumCards.value maxAbumCards.value
); );
if (albums.length > 0) { this.albums = albums;
this.albums = albums; this.eps = eps;
} this.singles = singles;
// if (albums.length > 0) {
// }
// if (eps.length > 0) {
// }
// if (singles.length > 0) {
// }
}, },
resetAlbums() { resetAlbums() {
this.albums = []; this.albums = [];
this.eps = [];
this.singles = [];
}, },
}, },
}); });
+12 -2
View File
@@ -8,6 +8,7 @@ import updateMediaNotif from "../composables/mediaNotification";
import { import {
fromAlbum, fromAlbum,
fromArtist,
fromFolder, fromFolder,
fromPlaylist, fromPlaylist,
fromSearch, fromSearch,
@@ -23,7 +24,7 @@ function shuffle(tracks: Track[]) {
return shuffled; return shuffled;
} }
type From = fromFolder | fromAlbum | fromPlaylist | fromSearch; type From = fromFolder | fromAlbum | fromPlaylist | fromSearch | fromArtist;
let audio = new Audio(); let audio = new Audio();
audio.autoplay = false; audio.autoplay = false;
@@ -150,7 +151,7 @@ export default defineStore("Queue", {
this.from = <fromFolder>{ this.from = <fromFolder>{
type: FromOptions.folder, type: FromOptions.folder,
path: fpath, path: fpath,
name: fpath?.split("/").splice(-1).join(""), name: "Folder",
}; };
this.setNewQueue(tracks); this.setNewQueue(tracks);
}, },
@@ -180,6 +181,15 @@ export default defineStore("Queue", {
this.setNewQueue(tracks); this.setNewQueue(tracks);
}, },
playFromArtist(artisthash: string, artistname: string, tracks: Track[]) {
this.from = <fromArtist>{
type: FromOptions.artist,
artisthash: artisthash,
artistname: artistname,
};
this.setNewQueue(tracks);
},
addTrackToQueue(track: Track) { addTrackToQueue(track: Track) {
this.tracklist.push(track); this.tracklist.push(track);
}, },
+32 -9
View File
@@ -39,6 +39,7 @@ 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 } from "vue-router";
import { Album } from "@/interfaces";
const store = useArtistPageStore(); const store = useArtistPageStore();
@@ -63,6 +64,17 @@ const artist_albums_fetcher: ScrollerItem = {
component: ArtistAlbumsFetcher, component: ArtistAlbumsFetcher,
}; };
function createAbumComponent(title: string, albums: Album[]) {
return {
id: title,
component: ArtistAlbums,
props: {
title,
albums,
},
};
}
const scrollerItems = computed(() => { const scrollerItems = computed(() => {
let components = [header]; let components = [header];
@@ -73,13 +85,18 @@ const scrollerItems = computed(() => {
components = [...components, artist_albums_fetcher]; components = [...components, artist_albums_fetcher];
if (store.albums.length > 0) { if (store.albums.length > 0) {
const artistAlbums: ScrollerItem = { const albums = createAbumComponent("Albums", store.albums);
id: "artist-albums", components.push(albums);
component: ArtistAlbums, }
props: { title: "Albums", albums: store.albums },
};
components.push(artistAlbums); if (store.eps.length > 0) {
const eps = createAbumComponent("EPs", store.eps);
components.push(eps);
}
if (store.singles.length > 0) {
const singles = createAbumComponent("Singles", store.singles);
components.push(singles);
} }
return components; return components;
@@ -97,8 +114,14 @@ onBeforeRouteLeave(async () => {
</script> </script>
<style lang="scss"> <style lang="scss">
.section-title { .artist-page {
margin: 1rem; .artist-albums {
padding-left: 1rem; margin-top: 2rem;
}
.section-title {
margin: 1rem;
padding-left: 1rem;
}
} }
</style> </style>