break down search component into smaler components

This commit is contained in:
geoffrey45
2022-01-23 10:27:39 +03:00
parent 7945c04a06
commit 7689f13fdc
16 changed files with 596 additions and 469 deletions
+4 -3
View File
@@ -50,7 +50,7 @@ def search_by_title():
for song in albums:
album_obj = {
"name": song["album"],
"artists": song["artists"],
"artist": song["album_artist"],
}
if album_obj not in albums_dicts:
@@ -67,6 +67,7 @@ def search_by_title():
artist_obj = {
"name": artist,
"image": "http://0.0.0.0:8900/images/artists/webp/" + artist.replace("/", "::") + ".webp"
}
if artist_obj not in artists_dicts:
@@ -91,8 +92,8 @@ def search_by_title():
return {'data': [
{'tracks': tracks[:5], 'more': more_tracks},
{'albums': albums_dicts[:10], 'more': more_albums},
{'artists': artists_dicts[:10], 'more': more_artists}
{'albums': albums_dicts[:5], 'more': more_albums},
{'artists': artists_dicts[:5], 'more': more_artists}
]}
@bp.route('/populate')
+118
View File
@@ -0,0 +1,118 @@
.right-search .v0 {
max-height: 0em;
transition: max-height 0.5s ease;
}
.right-search .v1 {
max-height: 25rem;
transition: max-height 0.5s ease;
}
.right-search {
position: relative;
border-radius: $small;
margin: 0.5rem 0 0 0;
padding: 1rem $small 0 0;
background-color: #03000eab;
overflow: hidden;
width: auto;
.no-res {
text-align: center;
height: calc(100% - 1rem);
display: grid;
.highlight {
padding: $small;
background-color: rgb(29, 26, 26);
}
}
.heading {
margin-left: $small;
background-color: rgb(3, 54, 112);
width: 6rem;
padding: $small;
border-radius: $small;
margin-bottom: $small;
}
.input {
display: flex;
align-items: center;
position: relative;
}
.search-icon {
position: absolute;
height: 2.5rem;
width: 2.5rem;
background-image: url(../../icons/search.svg);
background-size: 70%;
}
.v11 {
opacity: 0;
transform: translateY(-4rem);
transition: all 0.2s ease-in;
}
.v00 {
opacity: 1;
transition: all 0.2s ease-in;
}
.suggestions {
display: flex;
gap: 0.5rem;
margin-left: 1rem;
position: absolute;
right: 2.5rem;
.item::before {
content: "#";
color: grey;
}
}
}
.right-search .scrollable {
width: 100%;
height: 26rem;
overflow-y: auto;
scroll-behavior: smooth;
padding: 0 $small 0 0;
margin-bottom: 0.5rem;
}
.right-search {
.input-loader {
width: 100%;
border-radius: 0.4rem;
position: relative;
input {
width: calc(100% - 6rem);
border: none;
line-height: 2.5rem;
background-color: transparent;
color: rgb(255, 255, 255);
font-size: 1rem;
outline: none;
transition: all 0.5s ease;
padding-left: $small;
&:focus {
transition: all 0.5s ease;
color: rgb(255, 255, 255);
outline: none;
&::placeholder {
display: none;
}
}
}
}
}
+15 -1
View File
@@ -142,7 +142,6 @@ button {
}
}
.image {
background-position: center;
background-repeat: no-repeat;
@@ -248,4 +247,19 @@ button {
transition: all 0.3s ease-in-out;
}
.item {
position: relative;
background-color: rgba(34, 33, 33, 0.637);
padding: 0.5rem;
border-radius: 0.5rem;
cursor: pointer;
margin: 0 $small 0 0;
display: flex;
align-items: center;
font-size: 0.9rem;
color: rgb(250, 250, 250);
&:hover {
background-color: rgb(170, 50, 50);
}
}
@@ -10,7 +10,7 @@
<div class="s2"></div>
<p>Featured Artists</p>
</div>
<ArtistCard v-for="artist in artists" :key="artist" :artist="artist" />
<ArtistCard v-for="artist in artists" :key="artist" :artist="artist" :color="232452" />
</div>
</div>
</template>
+76 -456
View File
@@ -2,16 +2,7 @@
<div class="right-search border" ref="searchComponent">
<div class="input">
<div class="search-icon image"></div>
<div class="filter">
<div
class="item"
v-for="filter in filters"
:key="filter"
@click="removeFilter(filter)"
>
{{ filter }}<span class="cancel image"></span>
</div>
</div>
<Filters :filters="filters" @removeFilter="removeFilter" />
<div class="input-loader border">
<input
type="search"
@@ -22,7 +13,7 @@
placeholder="find your music"
v-model="query"
/>
<div class="loader" v-if="loading"></div>
<Loader />
</div>
<div
class="suggestions v00"
@@ -35,127 +26,87 @@
</div>
</div>
<div class="separator no-border"></div>
<div class="options" v-if="magic_flag">
<div class="item info">Filter by:</div>
<div
class="item"
v-for="option in options"
:key="option"
@click="addFilter(option.icon)"
>
{{ option.title }}
</div>
</div>
<Options :magic_flag="magic_flag" @addFilter="addFilter" />
<div class="scrollable" :class="{ v0: !is_hidden, v1: is_hidden }">
<div class="tracks-results border" v-if="songs.tracks">
<div class="heading">TRACKS</div>
<div class="items">
<table>
<tbody>
<SongItem v-for="song in songs.tracks" :key="song" :song="song" />
</tbody>
</table>
<div class="more" v-if="songs.more">
<button>
<div class="text">Load All</div>
</button>
</div>
</div>
</div>
<!-- -->
<div class="albums-results border">
<div class="heading">ALBUMS <span class="more">SEE ALL</span></div>
<div class="grid">
<div
class="result-item border"
v-for="album in albums.albums"
:key="album"
>
<div
class="album-art image"
:style="{
backgroundImage: `url('${album.image}')`,
}"
></div>
<div class="title ellip">{{ album.name }}</div>
<div class="artistsx ellipsis">
<span v-for="artist in putCommas(album.artists)" :key="artist">{{
artist
}}</span>
</div>
</div>
</div>
</div>
<TracksGrid
:tracks="tracks.tracks"
:more="tracks.more"
v-if="tracks.tracks.length"
/>
<AlbumGrid
v-if="albums.albums.length"
:albums="albums.albums"
:more="albums.more"
/>
<div class="separator no-border"></div>
<!-- -->
<!-- <div class="artists-results border" v-if="artists">
<div class="heading">ARTISTS <span class="more">SEE ALL</span></div>
<div class="grid">
<div
class="result-item border"
v-for="artist in artists.artists"
:key="artist"
>
<div
class="image"
:style="{
backgroundImage: `url(${artist.image})`,
}"
></div>
<div class="title ellip">{{ artist.name }}</div>
</div>
<ArtistGrid
v-if="artists.artists.length"
:artists="artists.artists"
:more="artists.more"
/>
<div
class="no-res"
v-if="
!artists.artists.length &&
!tracks.tracks.length &&
!albums.albums.length
"
>
<div class="no-res-icon image"></div>
<div class="no-res-text">
No results for <span class="highlight rounded">{{ query }}</span>
</div>
</div> -->
</div>
</div>
</div>
</template>
<script>
import { ref, toRefs } from "@vue/reactivity";
import { reactive, ref, toRefs } from "@vue/reactivity";
import { onMounted, watch } from "@vue/runtime-core";
import state from "@/composables/state.js";
import searchMusic from "@/composables/searchMusic.js";
import useDebouncedRef from "@/composables/useDebouncedRef";
import SongItem from "@/components/shared/SongItem.vue";
import perks from "@/composables/perks.js";
import AlbumGrid from "@/components/Search/AlbumGrid.vue";
import ArtistGrid from "@/components/Search/ArtistGrid.vue";
import TracksGrid from "@/components/Search/TracksGrid.vue";
import Loader from "@/components/Search/Loader.vue";
import Options from "@/components/Search/Options.vue";
import Filters from "@/components/Search/Filters.vue";
import "@/assets/css/Search/Search.scss";
export default {
emits: ["expandSearch", "collapseSearch"],
props: ["search"],
components: {
SongItem,
AlbumGrid,
ArtistGrid,
TracksGrid,
Loader,
Options,
Filters,
},
setup(props, { emit }) {
const options = [
{
title: "🎵 Track",
icon: "🎵",
},
{
title: "💿 Album",
icon: "💿",
},
{
title: "🙄 Artist",
icon: "🙄",
},
{
title: "😍 Playlist",
icon: "😍",
},
{
title: "📁 Folder",
icon: "📁",
},
];
setup(props, { emit }) {
const loading = ref(state.loading);
const searchComponent = ref(null);
const filters = ref([]);
const albums = ref([]);
const artists = ref([]);
const tracks = reactive({
tracks: [],
more: false,
});
let albums = reactive({
albums: [],
more: false,
});
const artists = reactive({
artists: [],
more: false,
});
const query = useDebouncedRef("", 400);
const magic_flag = ref(state.magic_flag);
@@ -202,10 +153,14 @@ export default {
watch(query, (new_query) => {
searchMusic(new_query).then((res) => {
albums.value = res.albums;
artists.value = res.artists;
state.search_tracks.value = res.tracks;
// console.log(albums.value)
albums.albums = res.albums.albums;
albums.more = res.albums.more;
artists.artists = res.artists.artists;
artists.more = res.artists.more;
tracks.tracks = res.tracks.tracks;
tracks.more = res.tracks.more;
});
state.search_query.value = new_query;
@@ -218,13 +173,14 @@ export default {
});
onMounted(() => {
// const dom = document.getElementsByClassName("right-search")[0];
// document.addEventListener("click", (e) => {
// var isClickedInside = dom.contains(e.target);
// if (!isClickedInside) {
// emit("collapseSearch");
// }
// });
const dom = document.getElementsByClassName("right-search")[0];
document.addEventListener("click", (e) => {
var isClickedInside = dom.contains(e.target);
if (!isClickedInside) {
emit("collapseSearch");
}
});
});
return {
@@ -233,353 +189,17 @@ export default {
removeMagicFlag,
removeFilter,
removeLastFilter,
songs: state.search_tracks,
tracks,
albums,
artists,
query,
is_hidden,
magic_flag,
options,
filters,
searchComponent,
loading,
searchMusic,
putCommas: perks.putCommas,
};
},
};
</script>
<style lang="scss">
.loader {
position: absolute;
right: 0.65rem;
top: 0.65rem;
width: 1.5rem;
height: 1.5rem;
border: dotted $blue;
border-radius: 50%;
animation: spin 0.25s linear infinite;
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}
.right-search .v0 {
max-height: 0em;
transition: max-height 0.5s ease;
}
.right-search .v1 {
max-height: 25rem;
transition: max-height 0.5s ease;
}
.right-search {
position: relative;
border-radius: $small;
margin: 0.5rem 0 0 0;
padding: 1rem $small 0 0;
background-color: $card-dark;
overflow: hidden;
width: auto;
.item {
position: relative;
background-color: rgba(34, 33, 33, 0.637);
padding: 0.5rem;
border-radius: 0.5rem;
cursor: pointer;
margin: 0 $small 0 0;
display: flex;
align-items: center;
font-size: 0.9rem;
color: rgb(250, 250, 250);
&:hover {
background-color: rgb(170, 50, 50);
}
}
.input {
display: flex;
align-items: center;
position: relative;
.filter {
display: flex;
margin-left: 3rem;
height: 2rem;
// border: solid;
.item {
&:hover {
width: 4rem;
.cancel {
position: absolute;
right: 0.5rem;
width: 1.5rem;
height: 1.5rem;
background-image: url(../assets/icons/a.svg);
background-size: 70%;
}
}
}
}
}
.search-icon {
position: absolute;
height: 2.5rem;
width: 2.5rem;
background-image: url(../assets/icons/search.svg);
background-size: 70%;
}
.v11 {
opacity: 0;
transform: translateY(-4rem);
transition: all 0.2s ease-in;
}
.v00 {
opacity: 1;
transition: all 0.2s ease-in;
}
.suggestions {
display: flex;
gap: 0.5rem;
margin-left: 1rem;
position: absolute;
right: 2.5rem;
.item::before {
content: "#";
color: grey;
}
}
}
.right-search .options {
display: flex;
.item {
margin: $small;
}
}
.right-search .scrollable {
height: 26rem;
overflow-y: auto;
scroll-behavior: smooth;
padding: 0 $small 0 0;
margin-bottom: 0.5rem;
}
.right-search .heading {
font-size: small;
position: relative;
padding: $small;
display: flex;
align-items: center;
.more {
position: absolute;
right: $small;
padding: 0.5rem;
user-select: none;
}
.more:hover {
cursor: pointer;
}
}
.right-search {
.input-loader {
width: 100%;
border-radius: 0.4rem;
position: relative;
input {
width: calc(100% - 6rem);
border: none;
line-height: 2.5rem;
background-color: transparent;
color: rgb(255, 255, 255);
font-size: 1rem;
outline: none;
transition: all 0.5s ease;
padding-left: $small;
&:focus {
transition: all 0.5s ease;
color: rgb(255, 255, 255);
outline: none;
&::placeholder {
display: none;
}
}
}
}
}
/* tracks */
.right-search .tracks-results {
border-radius: 0.5rem;
margin-left: $small;
padding: $small;
.more {
display: grid;
place-items: center;
margin-top: $small;
button {
height: 2.5rem;
width: 10rem;
display: grid;
}
}
.items {
border-radius: $small;
background-color: $card-dark;
}
.result-item {
display: flex;
align-items: center;
height: 4.5rem;
width: 100%;
.album-art {
width: 3.5rem;
height: 3.5rem;
background-color: rgb(27, 150, 74);
border-radius: 0.5rem;
margin: 0 $small 0 $small;
background-image: url(../assets/images/null.webp);
}
.tags .artist {
font-size: small;
color: rgba(255, 255, 255, 0.63);
}
&:hover {
background-color: $blue;
border-radius: $small;
}
}
}
.right-search hr {
margin: 0.1rem;
border: none;
}
/* albums */
.right-search .albums-results {
width: calc(100% - $small);
border-radius: 0.5rem;
background: #0f131b44;
margin-left: $small;
margin-top: $small;
.grid {
display: flex;
flex-wrap: wrap;
padding: 0 0 0 $small;
gap: $small;
.result-item {
display: flex;
flex-direction: column;
align-items: center;
padding: $small;
border-radius: $small;
text-align: left !important;
margin-bottom: 1rem;
width: 9rem;
.album-art {
height: 7rem;
width: 7rem;
border-radius: 0.5rem;
margin-bottom: 0.5rem;
background-image: url("../assets/images/null.webp");
}
.title {
width: 7rem;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
.artistsx {
width: 7rem;
display: flex;
font-size: 0.8rem;
text-align: left;
color: rgba(40, 116, 216, 0.767);
}
}
}
}
/* artits */
.right-search .artists-results {
width: calc(100% - $small);
border-radius: 0.5rem;
background: #1214178c;
margin: 0 0 0 $small;
.grid {
padding: 0 0 0 $small;
display: flex;
gap: 1rem;
.result-item {
display: flex;
flex-direction: column;
align-items: center;
padding: $small;
border-radius: $small;
background-color: $card-dark;
margin-bottom: 1rem;
.image {
height: 7rem;
width: 7rem;
border-radius: 50%;
margin-bottom: 0.5rem;
background-size: 50%;
background-image: url("../assets/images/null.webp");
background-size: cover;
}
.title {
width: 7rem;
text-align: center;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
}
}
}
</style>
+49
View File
@@ -0,0 +1,49 @@
<template>
<div class="albums-results border">
<div class="heading">💿 ALBUMS</div>
<div class="grid">
<AlbumCard v-for="album in albums" :key="album" :album="album" />
</div>
<LoadMore v-if="more" @loadMore="loadMore" />
</div>
</template>
<script>
import AlbumCard from "@/components/shared/AlbumCard.vue";
import LoadMore from "./LoadMore.vue";
export default {
props: ["albums", "more"],
components: {
AlbumCard,
LoadMore,
},
setup(props, { emit }) {
function loadMore() {
emit("loadMore");
}
return {
loadMore,
};
},
};
</script>
<style lang="scss">
.right-search .albums-results {
border-radius: 0.5rem;
background: #0f131b44;
margin-left: $small;
margin-top: $small;
padding: $small 0;
.grid {
display: flex;
flex-wrap: wrap;
padding: 0 0 0 $small;
gap: $small;
}
}
</style>
+50
View File
@@ -0,0 +1,50 @@
<template>
<div class="artists-results border">
<div class="heading">😳 ARTISTS</div>
<div class="grid">
<ArtistCard
v-for="artist in artists"
:key="artist"
:artist="artist"
/>
</div>
<LoadMore v-if="more" @loadMore="loadMore" />
</div>
</template>
<script>
import ArtistCard from "@/components/shared/ArtistCard.vue";
import LoadMore from "./LoadMore.vue";
export default {
props: ["artists", "more"],
components: {
ArtistCard,
LoadMore,
},
setup(props, { emit }) {
function loadMore() {
emit("loadMore");
}
return {
loadMore,
};
},
};
</script>
<style lang="scss">
.right-search .artists-results {
border-radius: 0.5rem;
background: #1214178c;
margin: 0 0 0 $small;
padding: $small 0;
.grid {
padding: 0 0 0 $small;
display: flex;
flex-wrap: wrap;
}
}
</style>
+50
View File
@@ -0,0 +1,50 @@
<template>
<div class="filter">
<div
class="item"
v-for="filter in filters"
:key="filter"
@click="removeFilter(filter)"
>
{{ filter }}<span class="cancel image"></span>
</div>
</div>
</template>
<script>
export default {
props: ["filters"],
setup(props, { emit }) {
const removeFilter = (filter) => {
emit("removeFilter", filter);
};
return {
removeFilter,
};
},
};
</script>
<style lang="scss">
.right-search .filter {
display: flex;
margin-left: 3rem;
height: 2rem;
.item {
&:hover {
width: 4rem;
.cancel {
position: absolute;
right: 0.5rem;
width: 1.5rem;
height: 1.5rem;
background-image: url(../../assets/icons/a.svg);
background-size: 70%;
}
}
}
}
</style>
+35
View File
@@ -0,0 +1,35 @@
<template>
<div class="morexx">
<button @click="loadMore">
<div class="text">Load All</div>
</button>
</div>
</template>
<script>
export default {
setup(props, { emit }) {
function loadMore() {
emit("loadMore");
}
return {
loadMore,
};
},
};
</script>
<style lang="scss">
.morexx {
display: grid;
place-items: center;
margin-top: $small;
button {
height: 2.5rem;
width: 10rem;
display: grid;
}
}
</style>
+36
View File
@@ -0,0 +1,36 @@
<template>
<div class="loader" v-if="loading"></div>
</template>
<script>
import state from "@/composables/state.js";
export default {
setup() {
return {
loading: state.loading,
};
},
};
</script>
<style lang="scss">
.loader {
position: absolute;
right: 0.65rem;
top: 0.65rem;
width: 1.5rem;
height: 1.5rem;
border: dotted $blue;
border-radius: 50%;
animation: spin 0.25s linear infinite;
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}
</style>
+62
View File
@@ -0,0 +1,62 @@
<template>
<div class="options" v-if="magic_flag">
<div class="item info">Filter by:</div>
<div
class="item"
v-for="option in options"
:key="option"
@click="addFilter(option.icon)"
>
{{ option.title }}
</div>
</div>
</template>
<script>
export default {
props: ["magic_flag"],
setup(props, { emit }) {
const options = [
{
title: "🎵 Track",
icon: "🎵",
},
{
title: "💿 Album",
icon: "💿",
},
{
title: "🙄 Artist",
icon: "🙄",
},
{
title: "😍 Playlist",
icon: "😍",
},
{
title: "📁 Folder",
icon: "📁",
},
];
function addFilter(value) {
emit("addFilter", value);
}
return {
options,
addFilter,
};
},
};
</script>
<style lang="scss">
.right-search .options {
display: flex;
.item {
margin: $small;
}
}
</style>
+43
View File
@@ -0,0 +1,43 @@
<template>
<div class="tracks-results border" v-if="tracks">
<div class="heading">🎵 TRACKS</div>
<div class="items">
<table>
<tbody>
<SongItem v-for="track in tracks" :key="track" :song="track" />
</tbody>
</table>
<LoadMore v-if="more" @loadMore="loadMore" />
</div>
</div>
</template>
<script>
import SongItem from "@/components/shared/SongItem.vue";
import LoadMore from "./LoadMore.vue";
export default {
props: ["tracks", "more"],
components: {
SongItem,
LoadMore,
},
setup(props, { emit }) {
function loadMore() {
emit("loadMore", "tracks");
}
return {
loadMore,
};
},
};
</script>
<style lang="scss">
.right-search .tracks-results {
border-radius: 0.5rem;
margin-left: $small;
padding: $small;
}
</style>
+51
View File
@@ -0,0 +1,51 @@
<template>
<div class="result-item border">
<div
class="album-art image"
:style="{
backgroundImage: `url(&quot;${album.image}&quot;)`,
}"
></div>
<div class="title ellip">{{ album.name }}</div>
<div class="artistsx ellipsis">{{ album.artist }}</div>
</div>
</template>
<script>
export default {
props: ["album"],
};
</script>
<style lang="scss">
.result-item {
display: flex;
flex-direction: column;
align-items: center;
padding: $small;
border-radius: $small;
text-align: left !important;
width: 9rem;
.album-art {
height: 7rem;
width: 7rem;
border-radius: 0.5rem;
margin-bottom: 0.5rem;
}
.title {
width: 7rem;
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
.artistsx {
width: 7rem;
display: flex;
font-size: 0.8rem;
text-align: left;
color: rgba(40, 116, 216, 0.767);
}
}
</style>
+5 -6
View File
@@ -1,19 +1,18 @@
<template>
<div class="xartist border">
<div class="xartist border" :style="{ backgroundColor: `#${color}` }">
<div
class="artist-image image"
:style="{ backgroundImage: `url('${artist.image}')` }"
></div>
<div>
<p class="artist-name ellipsis">{{ artist.name }}</p>
<p class="artist-name ellipsis">{{ artist.name }}</p>
</div>
<!-- <div class="a-circle"></div> -->
</div>
</template>
<script>
export default {
props: ["artist"],
props: ["artist", "color"],
};
</script>
@@ -22,11 +21,11 @@ export default {
flex: 0 0 auto;
overflow: hidden;
position: relative;
margin: 0 $smaller 0 $smaller;
margin: 0 $small 0 0;
width: 9em;
height: 11em;
border-radius: $small;
background-color: #232452;
display: flex;
flex-direction: column;
align-items: center;
+1 -1
View File
@@ -1,8 +1,8 @@
<template>
<tr
class="songlist-item"
:class="{ current: current._id.$oid == song._id.$oid }"
>
<!-- :class="{ current: current._id.$oid == song._id.$oid }" -->
<td class="flex" @click="emitUpdate(song)">
<div
class="album-art rounded image"
-1
View File
@@ -14,7 +14,6 @@ async function search(query) {
}
const data = await res.json();
console.log(data.data[1]);
state.loading.value = false;