koel/resources/assets/js/components/screens/search/SearchExcerptsScreen.vue

153 lines
4.3 KiB
Vue
Raw Normal View History

2022-04-15 14:24:30 +00:00
<template>
<section id="searchExcerptsWrapper">
2022-07-16 15:44:45 +00:00
<ScreenHeader layout="collapsed">
<span v-if="q">Searching for <span class="text-thin">{{ q }}</span></span>
2022-04-15 14:24:30 +00:00
<span v-else>Search</span>
2022-04-15 17:00:08 +00:00
</ScreenHeader>
2022-04-15 14:24:30 +00:00
<div ref="wrapper" class="main-scroll-wrap">
<div v-if="q" class="results">
2022-04-15 14:24:30 +00:00
<section class="songs" data-testid="song-excerpts">
<h1>
Songs
2022-04-15 17:00:08 +00:00
<Btn
v-if="excerpt.songs.length && !searching"
data-testid="view-all-songs-btn"
2022-04-23 21:53:56 +00:00
orange
2022-04-15 14:24:30 +00:00
rounded
small
2022-04-23 21:53:56 +00:00
@click.prevent="goToSongResults"
2022-04-15 14:24:30 +00:00
>
View All
2022-04-15 17:00:08 +00:00
</Btn>
2022-04-15 14:24:30 +00:00
</h1>
<ul v-if="searching">
<li v-for="i in 6" :key="i">
2022-12-02 16:17:37 +00:00
<SongCardSkeleton />
</li>
2022-04-15 14:24:30 +00:00
</ul>
<template v-else>
<ul v-if="excerpt.songs.length">
<li v-for="song in excerpt.songs" :key="song.id">
2022-12-02 16:17:37 +00:00
<SongCard :song="song" />
</li>
</ul>
<p v-else>None found.</p>
</template>
2022-04-15 14:24:30 +00:00
</section>
<section class="artists" data-testid="artist-excerpts">
<h1>Artists</h1>
<ul v-if="searching">
<li v-for="i in 6" :key="i">
2022-12-02 16:17:37 +00:00
<ArtistAlbumCardSkeleton layout="compact" />
2022-04-15 14:24:30 +00:00
</li>
</ul>
<template v-else>
<ul v-if="excerpt.artists.length">
<li v-for="artist in excerpt.artists" :key="artist.id">
2022-12-02 16:17:37 +00:00
<ArtistCard :artist="artist" layout="compact" />
</li>
</ul>
<p v-else>None found.</p>
</template>
2022-04-15 14:24:30 +00:00
</section>
<section class="albums" data-testid="album-excerpts">
<h1>Albums</h1>
<ul v-if="searching">
<li v-for="i in 6" :key="i">
2022-12-02 16:17:37 +00:00
<ArtistAlbumCardSkeleton layout="compact" />
2022-04-15 14:24:30 +00:00
</li>
</ul>
<template v-else>
<ul v-if="excerpt.albums.length">
<li v-for="album in excerpt.albums" :key="album.id">
2022-12-02 16:17:37 +00:00
<AlbumCard :album="album" layout="compact" />
</li>
</ul>
<p v-else>None found.</p>
</template>
2022-04-15 14:24:30 +00:00
</section>
</div>
<ScreenEmptyState v-else>
2022-12-02 16:17:37 +00:00
<template #icon>
2023-11-10 13:16:06 +00:00
<Icon :icon="faSearch" />
2022-04-15 14:24:30 +00:00
</template>
Find songs, artists, and albums,
<span class="secondary d-block">all in one place.</span>
</ScreenEmptyState>
2022-04-15 14:24:30 +00:00
</div>
</section>
</template>
2022-04-15 17:00:08 +00:00
<script lang="ts" setup>
2022-07-15 07:23:55 +00:00
import { faSearch } from '@fortawesome/free-solid-svg-icons'
import { intersectionBy } from 'lodash'
import { ref, toRef } from 'vue'
2022-11-18 18:44:20 +00:00
import { eventBus } from '@/utils'
2022-04-15 14:24:30 +00:00
import { searchStore } from '@/stores'
2022-11-18 18:44:20 +00:00
import { useRouter } from '@/composables'
2022-04-15 14:24:30 +00:00
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
import ArtistCard from '@/components/artist/ArtistCard.vue'
import AlbumCard from '@/components/album/AlbumCard.vue'
import Btn from '@/components/ui/Btn.vue'
import SongCard from '@/components/song/SongCard.vue'
import SongCardSkeleton from '@/components/ui/skeletons/SongCardSkeleton.vue'
import ArtistAlbumCardSkeleton from '@/components/ui/skeletons/ArtistAlbumCardSkeleton.vue'
2022-04-15 14:24:30 +00:00
2022-11-18 18:44:20 +00:00
const { go } = useRouter()
const excerpt = toRef(searchStore.state, 'excerpt')
2022-04-15 17:00:08 +00:00
const q = ref('')
const searching = ref(false)
2022-04-15 14:24:30 +00:00
2022-11-18 18:44:20 +00:00
const goToSongResults = () => go(`search/songs/?q=${q.value}`)
2022-04-15 14:24:30 +00:00
const doSearch = async () => {
searching.value = true
await searchStore.excerptSearch(q.value)
searching.value = false
}
eventBus.on('SEARCH_KEYWORDS_CHANGED', async _q => {
q.value = _q
await doSearch()
}).on('SONGS_DELETED', async songs => {
if (intersectionBy(songs, excerpt.value.songs, 'id').length !== 0) {
await doSearch()
}
2022-04-15 14:24:30 +00:00
})
</script>
<style lang="scss" scoped>
.results > section {
margin-bottom: 3em;
}
h1 {
font-size: 1.4rem;
margin: 0 0 1.8rem;
font-weight: 100;
display: flex;
place-content: space-between;
}
section ul {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
grid-gap: .7em 1em;
2022-04-15 17:00:08 +00:00
@media only screen and (max-width: 667px) {
2022-04-15 14:24:30 +00:00
display: block;
> * + * {
margin-top: .7rem;
}
}
}
</style>