first draft

This commit is contained in:
cwilvx
2025-01-28 09:17:37 +03:00
parent 40a7ad084c
commit db93fd554e
14 changed files with 590 additions and 289 deletions

View File

@@ -0,0 +1,4 @@
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.42607 18.5857L16.593 5.42412L14.344 3.16546L1.1674 16.3366L0.0267015 19.0816C-0.10197 19.4303 0.258496 19.8049 0.592479 19.6708L3.42607 18.5857ZM17.715 4.32139L18.9829 3.07476C19.6122 2.44546 19.6378 1.7482 19.0703 1.16906L18.6128 0.709452C18.0454 0.139922 17.3439 0.200625 16.7125 0.808593L15.4467 2.06273L17.715 4.32139Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 439 B

View File

@@ -22,6 +22,12 @@
@hideModal="hideModal"
@setTitle="setTitle"
/>
<CrudPage
v-if="modal.component == modal.options.page"
@hideModal="hideModal"
@setTitle="setTitle"
v-bind="modal.props"
/>
<UpdatePlaylist
v-if="modal.component == modal.options.updatePlaylist"
v-bind="modal.props"
@@ -49,6 +55,7 @@ import { useRouter } from 'vue-router'
import AuthLogin from './modals/AuthLogin.vue'
import ConfirmModal from './modals/ConfirmModal.vue'
import CrudPage from './modals/CrudPage.vue'
import NewPlaylist from './modals/NewPlaylist.vue'
import RootDirsPrompt from './modals/RootDirsPrompt.vue'
import SetRootDirs from './modals/SetRootDirs.vue'

View File

@@ -0,0 +1,66 @@
<template>
<form class="playlist-modal" @submit.prevent="submit">
<label for="name">Page name</label>
<br />
<input type="search" class="rounded-sm" id="name" :value="page?.name" />
<br />
<label for="description">Description</label>
<br />
<input type="search" class="rounded-sm" id="description" :value="page?.extra.description" />
<br /><br />
<button type="submit">{{ page ? 'Update' : 'Create' }}</button>
</form>
</template>
<script setup lang="ts">
import { Page } from '@/interfaces'
import { createNewPage, updatePage } from '@/requests/pages'
import { NotifType, Notification } from '@/stores/notification'
const props = defineProps<{
page?: Page
hash?: string
type?: string
extra?: any
}>()
const emit = defineEmits<{
(e: 'hideModal'): void
(e: 'setTitle', title: string): void
}>()
emit('setTitle', props.page ? 'Update Page' : 'New Page')
async function submit(e: Event) {
e.preventDefault()
const name = (e.target as any).elements['name'].value
const description = (e.target as any).elements['description'].value
// If the page is null, we are creating a new page
if (props.page == null) {
const created = await createNewPage(name, description, [
{
hash: props.hash as string,
type: props.type as string,
extra: props.extra,
},
])
if (created) {
new Notification('New page created', NotifType.Success)
emit('hideModal')
}
} else {
const updatedPage = await updatePage(props.page, name, description)
if (updatedPage) {
props.page.name = updatedPage.name
props.page.extra.description = updatedPage.extra.description
new Notification('Page updated', NotifType.Success)
emit('hideModal')
}
}
// If the page is not null, we are updating the page
}
</script>

View File

@@ -1,36 +1,66 @@
<template>
<div v-if="type == 'album'" class="cardlistrow">
<AlbumCard v-for="item in items" :key="item.albumhash" class="hlistitem" :album="(item as Album)" />
</div>
<div v-else-if="type == 'artist'" class="cardlistrow">
<ArtistCard v-for="item in items" :key="item.artisthash" class="hlistitem" :artist="(item as Artist)" />
</div>
<div v-else-if="type == 'mix'" class="cardlistrow">
<MixCard v-for="item in items" :key="item.sourcehash" class="hlistitem" :mix="(item as Mix)" />
</div>
<div class="cardlistrow">
<component v-for="item in items" :key="item.key" :is="item.component" v-bind="item.props" />
</div>
</template>
<script setup lang="ts">
import { Album, Artist, Mix } from "@/interfaces";
import AlbumCard from "./AlbumCard.vue";
import ArtistCard from "./ArtistCard.vue";
import MixCard from "../Mixes/MixCard.vue";
import { Album, Artist, Mix } from '@/interfaces'
import AlbumCard from './AlbumCard.vue'
import ArtistCard from './ArtistCard.vue'
import MixCard from '../Mixes/MixCard.vue'
import { computed } from 'vue'
defineProps<{
type: string | "album" | "artist" | "mix";
items: Album[] | Artist[] | Mix[];
}>();
const props = defineProps<{
items: Album[] | Artist[] | Mix[]
}>()
const items = computed(() => {
return props.items.map((item: any) => {
const i = {
component: <any>null,
props: {},
key: '',
}
switch (item['type']) {
case 'album':
i.component = AlbumCard
i.key = item.albumhash
i.props = {
album: item,
}
break
case 'artist':
i.component = ArtistCard
i.key = item.artisthash
i.props = {
artist: item,
}
break
case 'mix':
i.component = MixCard
i.key = item.sourcehash
i.props = {
mix: item,
}
break
}
return i
})
})
</script>
<style lang="scss">
.cardlistrow {
display: grid;
grid-template-columns: repeat(auto-fill, minmax($cardwidth, 1fr));
padding-bottom: 2rem;
z-index: -1;
display: grid;
grid-template-columns: repeat(auto-fill, minmax($cardwidth, 1fr));
padding-bottom: 2rem;
z-index: -1;
@include mediumPhones {
grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
}
@include mediumPhones {
grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
}
}
</style>

View File

@@ -30,6 +30,12 @@
grid-template-columns: 1fr max-content;
}
.right {
display: flex;
align-items: center;
height: 100%;
}
.after {
margin-top: 2rem;
margin-left: -$medium;

View File

@@ -85,6 +85,9 @@ export const paths = {
return this.base + '/artists'
},
},
pages: {
base: base_url + '/pages',
},
search: {
base: base_url + '/search',
get top() {

View File

@@ -1,56 +1,66 @@
import useModal from "@/stores/modal";
import useAlbum from "@/stores/pages/album";
import useTracklist from "@/stores/queue/tracklist";
import useModal from '@/stores/modal'
import useAlbum from '@/stores/pages/album'
import useTracklist from '@/stores/queue/tracklist'
import { Option, Playlist } from "@/interfaces";
import { addAlbumToPlaylist } from "@/requests/playlists";
import { getAddToPlaylistOptions, get_find_on_social } from "./utils";
import { AddToQueueIcon, PlayNextIcon, PlaylistIcon, PlusIcon } from "@/icons";
import { Option, Page, Playlist } from '@/interfaces'
import { addAlbumToPlaylist } from '@/requests/playlists'
import { getAddToPageOptions, getAddToPlaylistOptions, get_find_on_social } from './utils'
import { AddToQueueIcon, PlayNextIcon, PlaylistIcon, PlusIcon } from '@/icons'
import { addItemToPage } from '@/requests/pages'
export default async () => {
const album = useAlbum();
const album = useAlbum()
const play_next = <Option>{
label: "Play next",
action: () => {
const tracks = album.tracks.filter(
(track) => !track.is_album_disc_number
);
useTracklist().insertAfterCurrent(tracks);
},
icon: PlayNextIcon,
};
const play_next = <Option>{
label: 'Play next',
action: () => {
const tracks = album.tracks.filter(track => !track.is_album_disc_number)
useTracklist().insertAfterCurrent(tracks)
},
icon: PlayNextIcon,
}
const add_to_queue = <Option>{
label: "Add to queue",
action: () => {
const tracks = album.tracks.filter(
(track) => !track.is_album_disc_number
);
useTracklist().addTracks(tracks);
},
icon: AddToQueueIcon,
};
const add_to_queue = <Option>{
label: 'Add to queue',
action: () => {
const tracks = album.tracks.filter(track => !track.is_album_disc_number)
useTracklist().addTracks(tracks)
},
icon: AddToQueueIcon,
}
// Action for each playlist option
const AddToPlaylistAction = (playlist: Playlist) => {
const store = album;
addAlbumToPlaylist(playlist, store.info.albumhash);
};
// Action for each playlist option
const AddToPlaylistAction = (playlist: Playlist) => {
const store = album
addAlbumToPlaylist(playlist, store.info.albumhash)
}
const add_to_playlist: Option = {
label: "Add to Playlist",
children: () => getAddToPlaylistOptions(AddToPlaylistAction, {
albumhash: album.info.albumhash,
playlist_name: album.info.title,
}),
icon: PlusIcon,
};
const add_to_playlist: Option = {
label: 'Add to Playlist',
children: () =>
getAddToPlaylistOptions(AddToPlaylistAction, {
albumhash: album.info.albumhash,
playlist_name: album.info.title,
}),
icon: PlusIcon,
}
return [
play_next,
add_to_queue,
add_to_playlist,
get_find_on_social(),
];
};
const addToPageAction = (page: Page) => {
const store = album
addItemToPage(page, store.info, 'album')
}
const add_to_page: Option = {
label: 'Add to Page',
children: () =>
getAddToPageOptions(addToPageAction, {
page: null,
hash: album.info.albumhash,
type: 'album',
extra: {},
}),
icon: PlusIcon,
}
return [play_next, add_to_queue, add_to_playlist, add_to_page, get_find_on_social()]
}

View File

@@ -3,16 +3,15 @@ import useAlbum from '@/stores/pages/album'
import useArtist from '@/stores/pages/artist'
import { SearchIcon } from '@/icons'
import { Option, Playlist } from '@/interfaces'
import { Option, Page, Playlist } from '@/interfaces'
import { getAllPlaylists } from '@/requests/playlists'
import { getAllPages } from '@/requests/pages'
export const separator: Option = {
type: 'separator',
}
export function get_new_playlist_option(
new_playlist_modal_props: any = {}
): Option {
export function get_new_playlist_option(new_playlist_modal_props: any = {}): Option {
return {
label: 'New playlist',
action: () => {
@@ -21,6 +20,15 @@ export function get_new_playlist_option(
}
}
export function get_new_page_option(new_playlist_modal_props: any = {}): Option {
return {
label: 'New page',
action: () => {
modal().showNewPageModal(new_playlist_modal_props)
},
}
}
type action = (playlist: Playlist) => void
/**
@@ -29,10 +37,7 @@ type action = (playlist: Playlist) => void
* @param new_playlist_modal_props Props to be passed to the modal when creating a new playlist
* @returns A list of options to be used in a context menu
*/
export async function getAddToPlaylistOptions(
addToPlaylist: action,
new_playlist_modal_props: any = {}
) {
export async function getAddToPlaylistOptions(addToPlaylist: action, new_playlist_modal_props: any = {}) {
const new_playlist = get_new_playlist_option(new_playlist_modal_props)
const p = await getAllPlaylists(true)
@@ -44,7 +49,7 @@ export async function getAddToPlaylistOptions(
let playlists = <Option[]>[]
playlists = p.map((playlist) => {
playlists = p.map(playlist => {
return <Option>{
label: playlist.name,
action: () => {
@@ -56,20 +61,44 @@ export async function getAddToPlaylistOptions(
return [...items, separator, ...playlists]
}
/**
*
* @param addToPlaylist Function to be called when a playlist is selected
* @param new_playlist_modal_props Props to be passed to the modal when creating a new playlist
* @returns A list of options to be used in a context menu
*/
export async function getAddToPageOptions(addToPage: (page: Page) => void, new_page_modal_props: any = {}) {
const new_page = get_new_page_option(new_page_modal_props)
const p = await getAllPages()
let items = [new_page]
if (p.length === 0) {
return items
}
let pages = <Option[]>[]
pages = p.map(playlist => {
return <Option>{
label: playlist.name,
action: () => {
addToPage(playlist)
},
}
})
return [...items, separator, ...pages]
}
export const get_find_on_social = (page = 'album', query = '') => {
const is_album = page === 'album'
const getAlbumSearchTerm = () => {
const store = useAlbum()
return `${store.info.title} - ${store.info.albumartists
.map((a) => a.name)
.join(', ')}`
return `${store.info.title} - ${store.info.albumartists.map(a => a.name).join(', ')}`
}
const search_term = query
? query
: is_album
? getAlbumSearchTerm()
: useArtist().info.name
const search_term = query ? query : is_album ? getAlbumSearchTerm() : useArtist().info.name
return <Option>{
label: 'Search on',
@@ -77,67 +106,36 @@ export const get_find_on_social = (page = 'album', query = '') => {
children: async () => [
{
label: 'Google',
action: () =>
window.open(
`https://www.google.com/search?q=${search_term}`,
'_blank'
),
action: () => window.open(`https://www.google.com/search?q=${search_term}`, '_blank'),
},
{
label: 'YouTube',
action: () =>
window.open(
`https://www.youtube.com/results?search_query=${search_term}`,
'_blank'
),
action: () => window.open(`https://www.youtube.com/results?search_query=${search_term}`, '_blank'),
},
{
label: 'Spotify',
action: () =>
window.open(
`https://open.spotify.com/search/${search_term}/${page}s`,
'_blank'
),
action: () => window.open(`https://open.spotify.com/search/${search_term}/${page}s`, '_blank'),
},
{
label: 'Tidal',
action: () =>
window.open(
`https://listen.tidal.com/search/${page}s?q=${search_term}`,
'_blank'
),
action: () => window.open(`https://listen.tidal.com/search/${page}s?q=${search_term}`, '_blank'),
},
{
label: 'Apple Music',
action: () =>
window.open(
`https://music.apple.com/search?term=${search_term}`,
'_blank'
),
action: () => window.open(`https://music.apple.com/search?term=${search_term}`, '_blank'),
},
{
label: 'Deezer',
action: () =>
window.open(
`https://www.deezer.com/search/${search_term}/${page}`,
'_blank'
),
action: () => window.open(`https://www.deezer.com/search/${search_term}/${page}`, '_blank'),
},
{
label: 'Wikipedia',
action: () =>
window.open(
`https://en.wikipedia.org/wiki/Special:Search?search=${search_term}`,
'_blank'
),
window.open(`https://en.wikipedia.org/wiki/Special:Search?search=${search_term}`, '_blank'),
},
{
label: 'Last.fm',
action: () =>
window.open(
`https://www.last.fm/search/${page}s?q=${search_term}`,
'_blank'
),
action: () => window.open(`https://www.last.fm/search/${page}s?q=${search_term}`, '_blank'),
},
],
}

View File

@@ -179,6 +179,15 @@ export interface Playlist {
}[]
}
export interface Page {
id: number
name: string
items: (Album | Artist | Mix | Playlist)[]
extra: {
description: string
}
}
export interface Radio {
name: string
image: string

107
src/requests/pages.ts Normal file
View File

@@ -0,0 +1,107 @@
import { Album, Artist, Mix, Page, Playlist } from '@/interfaces'
import useAxios from './useAxios'
import { paths } from '@/config'
const { base: basePageUrl } = paths.api.pages
export async function getAllPages() {
const { data, status } = await useAxios({
url: basePageUrl,
method: 'GET',
})
if (status == 200) {
return data as Page[]
}
return []
}
export async function getPage(page_id: string) {
const { data, status } = await useAxios({
url: basePageUrl + `/${page_id}`,
method: 'GET',
})
return data as Page
}
export async function createNewPage(
name: string,
description: string,
items?: { hash: string; type: string; extra: any }[]
) {
const { data, status } = await useAxios({
url: basePageUrl,
props: {
name,
description,
items,
},
method: 'POST',
})
if (status == 201) {
return true
}
return false
}
export async function updatePage(page: Page, name: string, description: string) {
const { data, status } = await useAxios({
url: basePageUrl + `/${page.id}`,
props: {
name,
description,
},
method: 'PUT',
})
if (status == 200) {
return data.page as Page
}
return null
}
export async function addItemToPage(page: Page, item: Album | Artist | Mix | Playlist, type: string) {
const payload = {
type: type,
hash: '',
extra: {},
}
switch (type) {
case 'album':
payload.hash = (item as Album).albumhash
break
case 'artist':
payload.hash = (item as Artist).artisthash
break
case 'mix':
payload.hash = (item as Mix).sourcehash
break
case 'playlist':
payload.hash = (item as Playlist).id.toString()
break
}
if (payload.hash === '') {
throw new Error('Invalid item type. Item not added to page.')
}
const { data, status } = await useAxios({
url: basePageUrl + `/${page.id}/items`,
props: {
items: [payload],
},
method: 'POST',
})
if (status == 200) {
return true
}
return false
}

View File

@@ -28,6 +28,7 @@ const FavoriteCardScroller = () => import("@/views/FavoriteCardScroller.vue");
const StatsView = () => import("@/views/Stats/main.vue");
const MixView = () => import("@/views/MixView.vue");
const MixListView = () => import("@/views/MixListView.vue");
const Page = () => import("@/views/Pages/Page.vue");
const folder = {
path: "/folder/:path",
@@ -202,6 +203,12 @@ const MixList = {
component: MixListView,
};
const PageView = {
path: "/pages/:page",
name: "Page",
component: Page,
};
const routes = [
folder,
playlists,
@@ -225,6 +232,7 @@ const routes = [
Stats,
Mix,
MixList,
PageView,
];
const Routes = {
@@ -250,6 +258,7 @@ const Routes = {
Stats: Stats.name,
Mix: Mix.name,
MixList: MixList.name,
Page: PageView.name,
};
const router = createRouter({

View File

@@ -1,86 +1,90 @@
import { defineStore } from "pinia";
import { defineStore } from 'pinia'
export enum ModalOptions {
newPlaylist,
updatePlaylist,
deletePlaylist,
SetIP,
rootDirsPrompt,
setRootDirs,
saveFolderAsPlaylist,
login,
settings
newPlaylist,
page,
updatePlaylist,
deletePlaylist,
SetIP,
rootDirsPrompt,
setRootDirs,
saveFolderAsPlaylist,
login,
settings,
}
export default defineStore("newModal", {
state: () => ({
title: "",
options: ModalOptions,
component: <any>null,
props: <any>{},
visible: false,
}),
actions: {
showModal(modalOption: ModalOptions, props: any = {}) {
this.component = modalOption;
this.visible = true;
this.props = props;
export default defineStore('newModal', {
state: () => ({
title: '',
options: ModalOptions,
component: <any>null,
props: <any>{},
visible: false,
}),
actions: {
showModal(modalOption: ModalOptions, props: any = {}) {
this.component = modalOption
this.visible = true
this.props = props
},
showNewPlaylistModal(props: any = {}) {
this.showModal(ModalOptions.newPlaylist, props)
},
showNewPageModal(props: any = {}) {
this.showModal(ModalOptions.page, props)
},
showSaveFolderAsPlaylistModal(path: string) {
const playlist_name = path.split('/').pop()
const props = {
playlist_name,
path,
}
this.showModal(ModalOptions.newPlaylist, props)
},
showSaveArtistAsPlaylistModal(name: string, artisthash: string) {
const props = {
artisthash,
playlist_name: `This is ${name}`,
}
this.showModal(ModalOptions.newPlaylist, props)
},
showSaveQueueAsPlaylistModal(name: string) {
const props = {
is_queue: true,
playlist_name: name,
}
this.showModal(ModalOptions.newPlaylist, props)
},
showEditPlaylistModal() {
this.showModal(ModalOptions.updatePlaylist)
},
showDeletePlaylistModal(pid: number) {
const props = {
pid: pid,
}
this.showModal(ModalOptions.deletePlaylist, props)
},
showSetIPModal() {
this.showModal(ModalOptions.SetIP)
},
showRootDirsPromptModal() {
this.showModal(ModalOptions.rootDirsPrompt)
},
showSetRootDirsModal() {
this.showModal(ModalOptions.setRootDirs)
},
showLoginModal() {
this.showModal(ModalOptions.login)
},
showSettingsModal() {
this.showModal(ModalOptions.settings)
},
hideModal() {
this.visible = false
this.setTitle('')
},
setTitle(new_title: string) {
this.title = new_title
},
},
showNewPlaylistModal(props: any = {}) {
this.showModal(ModalOptions.newPlaylist, props);
},
showSaveFolderAsPlaylistModal(path: string) {
const playlist_name = path.split("/").pop();
const props = {
playlist_name,
path,
};
this.showModal(ModalOptions.newPlaylist, props);
},
showSaveArtistAsPlaylistModal(name: string, artisthash: string) {
const props = {
artisthash,
playlist_name: `This is ${name}`,
};
this.showModal(ModalOptions.newPlaylist, props);
},
showSaveQueueAsPlaylistModal(name: string) {
const props = {
is_queue: true,
playlist_name: name,
};
this.showModal(ModalOptions.newPlaylist, props);
},
showEditPlaylistModal() {
this.showModal(ModalOptions.updatePlaylist);
},
showDeletePlaylistModal(pid: number) {
const props = {
pid: pid,
};
this.showModal(ModalOptions.deletePlaylist, props);
},
showSetIPModal() {
this.showModal(ModalOptions.SetIP);
},
showRootDirsPromptModal() {
this.showModal(ModalOptions.rootDirsPrompt);
},
showSetRootDirsModal() {
this.showModal(ModalOptions.setRootDirs);
},
showLoginModal(){
this.showModal(ModalOptions.login);
},
showSettingsModal(){
this.showModal(ModalOptions.settings);
},
hideModal() {
this.visible = false;
this.setTitle("");
},
setTitle(new_title: string) {
this.title = new_title;
},
},
});
})

58
src/views/Pages/Page.vue Normal file
View File

@@ -0,0 +1,58 @@
<template>
<CardGridPage :items="page?.items || []">
<template #header>
<GenericHeader>
<template #name>
<span @click="updatePage">
{{ page?.name }} <span><PencilSvg height="0.8rem" width="0.8rem" /></span
></span>
</template>
<template #description v-if="page?.extra.description">
<span @click="updatePage"> {{ page?.extra.description }} </span>
</template>
</GenericHeader>
</template>
</CardGridPage>
</template>
<script setup lang="ts">
import { Page } from '@/interfaces'
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import { getPage } from '@/requests/pages'
import CardGridPage from '@/views/SearchView/CardGridPage.vue'
import GenericHeader from '@/components/shared/GenericHeader.vue'
import PencilSvg from '@/assets/icons/pencil.svg'
import useModal from '@/stores/modal'
const modal = useModal()
const page = ref<Page | null>(null)
onMounted(async () => {
const route = useRoute()
const page_id = route.params.page as string
page.value = await getPage(page_id)
console.log(page.value)
})
function updatePage() {
console.log('update page')
modal.showNewPageModal({
page: page.value,
})
}
</script>
<style scoped lang="scss">
span {
cursor: text;
margin-right: $smaller;
}
.generichead {
margin-top: 2rem
}
</style>

View File

@@ -1,100 +1,90 @@
<template>
<NoItems
:title="`No ${page} results`"
:description="desc"
:icon="SearchSvg"
:flag="!items.length"
v-if="showNoItemsComponent"
/>
<div class="v-scroll-page" style="height: 100%">
<DynamicScroller
style="height: 100%"
class="scroller"
:min-item-size="64"
:items="scrollerItems"
>
<template #before>
<slot name="header"></slot>
</template>
<template #default="{ item, index, active }">
<DynamicScrollerItem
:item="item"
:active="active"
:size-dependencies="[item.props]"
:data-index="index"
>
<component
:is="item.component"
:key="index"
v-bind="item.props"
></component>
</DynamicScrollerItem>
</template>
</DynamicScroller>
</div>
<NoItems
:title="`No ${page} results`"
:description="desc"
:icon="SearchSvg"
:flag="!items.length"
v-if="showNoItemsComponent"
/>
<div class="v-scroll-page" style="height: 100%">
<DynamicScroller style="height: 100%" class="scroller" :min-item-size="64" :items="scrollerItems">
<template #before>
<slot name="header"></slot>
</template>
<template #default="{ item, index, active }">
<DynamicScrollerItem
:item="item"
:active="active"
:size-dependencies="[item.props]"
:data-index="index"
>
<component :is="item.component" :key="index" v-bind="item.props"></component>
</DynamicScrollerItem>
</template>
</DynamicScroller>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { computed } from 'vue'
import useSearchStore from "@/stores/search";
import { maxAbumCards } from "@/stores/content-width";
import useSearchStore from '@/stores/search'
import { maxAbumCards } from '@/stores/content-width'
import SearchSvg from "@/assets/icons/search.svg";
import NoItems from "@/components/shared/NoItems.vue";
import CardRow from "@/components/shared/CardRow.vue";
import AlbumsFetcher from "@/components/ArtistView/AlbumsFetcher.vue";
import SearchSvg from '@/assets/icons/search.svg'
import NoItems from '@/components/shared/NoItems.vue'
import CardRow from '@/components/shared/CardRow.vue'
import AlbumsFetcher from '@/components/ArtistView/AlbumsFetcher.vue'
const props = defineProps<{
page: "album" | "artist" | "mix";
fetch_callback?: () => Promise<void>;
items: any[];
outside_route?: boolean;
showNoItemsComponent?: boolean;
}>();
page?: 'album' | 'artist' | 'mix'
fetch_callback?: () => Promise<void>
items: any[]
outside_route?: boolean
showNoItemsComponent?: boolean
}>()
const search = useSearchStore();
const search = useSearchStore()
const desc = computed(() =>
search.query === ""
? `Start typing to search for ${props.page}s`
: `Results for '${search.query}' should appear here`
);
search.query === ''
? `Start typing to search for ${props.page}s`
: `Results for '${search.query}' should appear here`
)
const scrollerItems = computed(() => {
let maxCards = maxAbumCards.value;
let maxCards = maxAbumCards.value
if (props.outside_route) {
maxCards = 6;
}
if (props.outside_route) {
maxCards = 6
}
const groups = Math.ceil(props.items.length / maxCards);
const items = [];
const groups = Math.ceil(props.items.length / maxCards)
const items = []
for (let i = 0; i < groups; i++) {
items.push({
id: i,
component: CardRow,
props: {
type: props.page,
items: props.items.slice(i * maxCards, (i + 1) * maxCards),
},
});
}
for (let i = 0; i < groups; i++) {
items.push({
id: i,
component: CardRow,
props: {
items: props.items.slice(i * maxCards, (i + 1) * maxCards),
},
})
}
const moreItems = props.page === 'album' ? search.albums.more : search.artists.more
const moreItems = props.page === 'album' ? search.albums.more : search.artists.more
if (props.fetch_callback && moreItems) {
items.push({
id: Math.random(),
component: AlbumsFetcher,
props: {
fetch_callback: props.fetch_callback,
outside_route: props.outside_route,
},
});
}
if (props.fetch_callback && moreItems) {
items.push({
id: Math.random(),
component: AlbumsFetcher,
props: {
fetch_callback: props.fetch_callback,
outside_route: props.outside_route,
},
})
}
return items;
});
return items
})
</script>