rewrite search tabbing

This commit is contained in:
geoffrey45
2022-09-04 15:30:23 +03:00
parent 24bfa73ab6
commit b7c158a785
12 changed files with 172 additions and 108 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
@import "./app-grid.scss", "./controls.scss", "./inputs.scss", @import "./app-grid.scss", "./controls.scss", "./inputs.scss",
"./scrollbars.scss", "./state.scss", "./variants.scss", "./basic.scss"; "./scrollbars.scss", "./state.scss", "./variants.scss", "./basic.scss",
"./search-tabheaders.scss";
:root { :root {
--separator: #ffffff46; --separator: #ffffff46;
@@ -0,0 +1,34 @@
.tabheaders {
display: grid;
grid-template-columns: repeat(5, max-content);
justify-content: space-around;
margin: 1rem;
width: max-content;
background: linear-gradient(37deg, $gray1, $gray2, $gray1);
height: 2rem;
& > * {
border-left: solid 1px $gray3;
}
.tab {
display: flex;
align-items: center;
justify-content: center;
user-select: none;
cursor: pointer;
transition: all 0.3s ease;
padding: 0 $small;
&:first-child {
border-left: solid 1px transparent;
}
}
.activetab {
background-color: $darkblue;
transition: all 0.3s ease;
border-left: solid 1px transparent;
}
}
@@ -38,9 +38,11 @@ import LoadMore from "./LoadMore.vue";
const search = useSearchStore(); const search = useSearchStore();
defineProps<{ const props = defineProps<{
album_grid?: boolean; album_grid?: boolean;
}>(); }>();
console.log(search.albums);
</script> </script>
<style lang="scss"> <style lang="scss">
+21 -13
View File
@@ -1,28 +1,36 @@
<template> <template>
<div class="right-search"> <div class="right-search">
<TabsWrapper> <TabsWrapper
<Tab name="tracks"> :isOnSearchPage="isOnSearchPage"
<TracksGrid :isOnSearchPage="isOnSearchPage" /> :tabs="tabs"
</Tab> @switchTab="switchTab"
<Tab name="albums"> :currentTab="currentTab"
<ArtistGrid :album_grid="true" /> >
</Tab> <Tab :name="currentTab" :isOnSearchPage="isOnSearchPage" />
<Tab name="artists">
<ArtistGrid />
</Tab>
</TabsWrapper> </TabsWrapper>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import ArtistGrid from "./ArtistGrid.vue"; import { ref } from "vue";
import Tab from "./Tab.vue"; import Tab from "./Tab.vue";
import TabsWrapper from "./TabsWrapper.vue"; import TabsWrapper from "./TabsWrapper.vue";
import TracksGrid from "./TracksGrid.vue"; import useSearchStore from "@/stores/search";
const props = defineProps<{ const search = useSearchStore();
defineProps<{
isOnSearchPage?: boolean; isOnSearchPage?: boolean;
}>(); }>();
const tabs = ["tracks", "albums", "artists"];
const currentTab = ref("tracks");
function switchTab(tab: string) {
currentTab.value = tab;
search.switchTab(tab);
}
</script> </script>
<style lang="scss"> <style lang="scss">
+32 -6
View File
@@ -1,13 +1,39 @@
<template> <template>
<div v-show="name == s.currentTab"> <component :is="getComponent()?.component" v-bind="getComponent()?.props" />
<slot />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import useSearchStore from "@/stores/search"; import ArtistGrid from "./ArtistGrid.vue";
const s = useSearchStore(); import TracksGrid from "./TracksGrid.vue";
defineProps<{
const props = defineProps<{
name: string; name: string;
isOnSearchPage?: boolean;
}>(); }>();
function getComponent() {
switch (props.name) {
case "tracks":
return {
component: TracksGrid,
props: {
isOnSearchPage: props.isOnSearchPage,
},
};
case "albums":
return {
component: ArtistGrid,
props: {
album_grid: true,
},
};
case "artists":
return {
component: ArtistGrid,
props: {},
};
default:
return null;
}
}
</script> </script>
@@ -1,17 +1,19 @@
<template> <template>
<div id="right-tabs" class="rounded"> <div id="right-tabs" class="rounded">
<div class="tab-buttons-wrapper"> <div class="tab-buttons-wrapper">
<div id="tabheaders" class="rounded-sm noscroll"> <Teleport :disabled="!isOnSearchPage" to="#nav-tab-headers">
<div <div class="tabheaders rounded-sm noscroll">
class="tab" <div
v-for="slot in $slots.default()" class="tab"
:key="slot.key" v-for="tab in tabs"
@click="s.changeTab(slot.props.name)" :key="tab"
:class="{ activetab: slot.props.name === s.currentTab }" @click="switchTab(tab)"
> :class="{ activetab: tab === currentTab }"
{{ slot.props.name }} >
{{ tab }}
</div>
</div> </div>
</div> </Teleport>
</div> </div>
<div id="tab-content"> <div id="tab-content">
@@ -21,9 +23,19 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import useSearchStore from "@/stores/search"; defineProps<{
isOnSearchPage?: boolean;
tabs: string[];
currentTab: string;
}>();
const s = useSearchStore(); const emit = defineEmits<{
(e: "switchTab", tab: string): void;
}>();
function switchTab(tab: string) {
emit("switchTab", tab);
}
</script> </script>
<style lang="scss"> <style lang="scss">
@@ -38,44 +50,9 @@ const s = useSearchStore();
align-items: center; align-items: center;
} }
#tabheaders {
display: grid;
grid-template-columns: repeat(5, max-content);
justify-content: space-around;
margin: 1rem;
width: max-content;
background: linear-gradient(37deg, $gray1, $gray2, $gray1);
height: 2rem;
& > * {
border-left: solid 1px $gray3;
}
.tab {
display: flex;
align-items: center;
justify-content: center;
user-select: none;
cursor: pointer;
transition: all 0.3s ease;
padding: 0 $small;
&:first-child {
border-left: solid 1px transparent;
}
}
.activetab {
background-color: $darkblue;
transition: all 0.3s ease;
border-left: solid 1px transparent;
}
}
#tab-content { #tab-content {
height: 100%; height: 100%;
overflow: auto; overflow: scroll;
overflow-x: hidden; overflow-x: hidden;
padding-bottom: 1rem; padding-bottom: 1rem;
} }
@@ -1,17 +1,15 @@
<template> <template>
<div id="tracks-results"> <div id="tracks-results" class="noscroll">
<div v-if="search.tracks.value.length"> <div v-if="search.tracks.value.length">
<div> <TrackComponent
<TrackComponent v-for="(track, index) in search.tracks.value"
v-for="(track, index) in search.tracks.value" :key="track.trackid"
:key="track.trackid" :isCurrent="queue.currentid == track.trackid"
:isCurrent="queue.currentid == track.trackid" :isHighlighted="false"
:isHighlighted="false" :isPlaying="queue.playing"
:isPlaying="queue.playing" :track="track"
:track="track" @PlayThis="updateQueue(index)"
@PlayThis="updateQueue(index)" />
/>
</div>
</div> </div>
<div v-else class="t-center"><h5>🤷</h5></div> <div v-else class="t-center"><h5>🤷</h5></div>
<LoadMore v-if="search.tracks.more" :loader="search.loadTracks" /> <LoadMore v-if="search.tracks.more" :loader="search.loadTracks" />
@@ -52,10 +50,3 @@ if (props.isOnSearchPage) {
use_song_item = true; use_song_item = true;
} }
</script> </script>
<style lang="scss">
.right-search #tracks-results {
height: 100% !important;
overflow: hidden;
}
</style>
+11
View File
@@ -1,6 +1,7 @@
<template> <template>
<div class="nav-search-input"> <div class="nav-search-input">
<SearchInput /> <SearchInput />
<div id="nav-tab-headers"></div>
</div> </div>
</template> </template>
@@ -10,6 +11,12 @@ import SearchInput from "@/components/RightSideBar/SearchInput.vue";
<style lang="scss"> <style lang="scss">
.nav-search-input { .nav-search-input {
display: flex;
grid-template-columns: repeat(3, 1fr);
align-items: center;
justify-content: space-between;
height: 2rem;
#gsearch-input { #gsearch-input {
display: unset; display: unset;
@@ -22,5 +29,9 @@ import SearchInput from "@/components/RightSideBar/SearchInput.vue";
display: none; display: none;
} }
} }
.tabheaders {
margin: 0;
}
} }
</style> </style>
+2 -8
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="xartist" :class="{ _is_on_sidebar: alt }"> <div class="artist-card" :class="{ _is_on_sidebar: alt }">
<img <img
class="artist-image shadow-sm" class="artist-image shadow-sm"
:src="imguri + artist.image" :src="imguri + artist.image"
@@ -24,7 +24,7 @@ defineProps<{
</script> </script>
<style lang="scss"> <style lang="scss">
.xartist { .artist-card {
flex: 0 0 auto; flex: 0 0 auto;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
@@ -41,11 +41,5 @@ defineProps<{
transition: all 0.5s ease-in-out; transition: all 0.5s ease-in-out;
object-fit: cover; object-fit: cover;
} }
// &:hover {
// .artist-image {
// border-radius: 10%;
// }
// }
} }
</style> </style>
+11 -7
View File
@@ -1,18 +1,19 @@
import { Directive } from "vue"; import { Directive } from "vue";
import { createPopper } from "@popperjs/core"; import { createPopper } from "@popperjs/core";
let tooltip: HTMLElement;
export default { export default {
mounted(el, binding) { mounted(el, binding) {
let isHovered = false; let isHovered = false;
const tooltip = document.getElementById("tooltip") as HTMLElement; const tooltip = document.getElementById("tooltip") as HTMLElement;
el.addEventListener("mouseenter", () => { el.addEventListener("mouseover", () => {
isHovered = true; isHovered = true;
setTimeout(() => { setTimeout(() => {
tooltip.innerText = binding.value;
if (isHovered) { if (isHovered) {
tooltip.innerText = binding.value;
tooltip.style.display = "unset"; tooltip.style.display = "unset";
createPopper(el, tooltip, { createPopper(el, tooltip, {
@@ -27,16 +28,19 @@ export default {
], ],
}); });
} }
}, 1000); }, 1500);
}); });
el.addEventListener("mouseleave", () => { el.addEventListener("mouseout", () => {
isHovered = false; isHovered = false;
tooltip.style.display = "none"; tooltip.style.display = "none";
}); });
}, },
beforeUnmount(el: HTMLElement) { beforeUnmount(el: HTMLElement) {
el.removeEventListener("mouseenter", () => {}); const tooltip = document.getElementById("tooltip") as HTMLElement;
el.removeEventListener("mouseleave", () => {}); tooltip.style.display = "none";
el.removeEventListener("mouseover", () => {});
el.removeEventListener("mouseout", () => {});
}, },
} as Directive; } as Directive;
+6 -3
View File
@@ -1,3 +1,4 @@
import { Routes } from "./../composables/enums";
import { ref, reactive } from "@vue/reactivity"; import { ref, reactive } from "@vue/reactivity";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { AlbumInfo, Artist, Playlist, Track } from "../interfaces"; import { AlbumInfo, Artist, Playlist, Track } from "../interfaces";
@@ -13,6 +14,7 @@ import { watch } from "vue";
import useDebouncedRef from "../utils/useDebouncedRef"; import useDebouncedRef from "../utils/useDebouncedRef";
import useTabStore from "./tabs"; import useTabStore from "./tabs";
import useLoaderStore from "./loader"; import useLoaderStore from "./loader";
import { useRoute } from "vue-router";
/** /**
* *
* Scrolls on clicking the loadmore button * Scrolls on clicking the loadmore button
@@ -31,6 +33,7 @@ export default defineStore("search", () => {
// @ts-ignore // @ts-ignore
const query = useDebouncedRef(null, 600); const query = useDebouncedRef(null, 600);
const { startLoading, stopLoading } = useLoaderStore(); const { startLoading, stopLoading } = useLoaderStore();
const route = useRoute();
const currentTab = ref("tracks"); const currentTab = ref("tracks");
const RESULT_COUNT = 6; const RESULT_COUNT = 6;
@@ -154,7 +157,7 @@ export default defineStore("search", () => {
const tabs = useTabStore(); const tabs = useTabStore();
if (tabs.current !== "search") { if (route.name !== Routes.search && tabs.current !== "search") {
tabs.switchToSearch(); tabs.switchToSearch();
} }
@@ -202,7 +205,7 @@ export default defineStore("search", () => {
} }
); );
function changeTab(tab: string) { function switchTab(tab: string) {
currentTab.value = tab; currentTab.value = tab;
} }
@@ -217,6 +220,6 @@ export default defineStore("search", () => {
loadTracks, loadTracks,
loadAlbums, loadAlbums,
loadArtists, loadArtists,
changeTab, switchTab,
}; };
}); });
+15 -2
View File
@@ -13,7 +13,6 @@ import Main from "@/components/RightSideBar/Search/Main.vue";
<style lang="scss"> <style lang="scss">
.search-view { .search-view {
height: 100%; height: 100%;
// background-color: $black;
padding-top: 0; padding-top: 0;
margin-right: -1rem; margin-right: -1rem;
@@ -22,8 +21,22 @@ import Main from "@/components/RightSideBar/Search/Main.vue";
overflow: auto; overflow: auto;
} }
.artists-results {
margin-right: $small;
margin-left: -$small;
}
.search-results-grid { .search-results-grid {
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
.artist-card {
padding: 0 1rem;
}
}
#tracks-results {
margin-right: 1rem;
margin-left: -2.25rem;
} }
} }
</style> </style>