mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-07 03:35:35 +00:00
fix layout shift caused by scrollbar
+ append search query to url (to support reload) + fix right sidebar search tabs bug + redesign the load more button on the search page
This commit is contained in:
parent
68f990aada
commit
c1fb05e2a0
@ -32,9 +32,7 @@ $g-border: solid 1px $gray5;
|
||||
|
||||
.vue-recycle-scroller {
|
||||
padding-left: 1.25rem;
|
||||
// padding-right: 1rem;
|
||||
|
||||
// margin-right: 1rem;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
.r-sidebar {
|
||||
@ -62,8 +60,9 @@ $g-border: solid 1px $gray5;
|
||||
|
||||
.content-page {
|
||||
margin-left: 1.25rem;
|
||||
// margin-right: -$medium;
|
||||
padding-right: 1.25rem;
|
||||
margin-right: -$medium;
|
||||
padding-right: $medium;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
// ====== MODIFIERS =======
|
||||
|
@ -3,7 +3,11 @@
|
||||
<router-link
|
||||
v-for="menu in menus"
|
||||
:key="menu.name"
|
||||
:to="{ name: menu.route_name, params: menu?.params }"
|
||||
:to="{
|
||||
name: menu.route_name,
|
||||
params: menu?.params,
|
||||
query: menu.query && menu.query(),
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-if="menu.separator"
|
||||
@ -34,6 +38,7 @@ import QueueSvg from "../../assets/icons/queue.svg";
|
||||
import SearchSvg from "../../assets/icons/search.svg";
|
||||
import SettingsSvg from "../../assets/icons/settings.svg";
|
||||
import HeartSvg from "../../assets/icons/heart.svg";
|
||||
import useSearchStore from "@/stores/search";
|
||||
|
||||
const menus = [
|
||||
{
|
||||
@ -65,6 +70,7 @@ const menus = [
|
||||
name: "search",
|
||||
route_name: Routes.search,
|
||||
params: { page: "tracks" },
|
||||
query: () => ({ q: useSearchStore().query }),
|
||||
icon: SearchSvg,
|
||||
},
|
||||
{
|
||||
|
@ -40,6 +40,8 @@ function switchTab(tab: string) {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: max-content 1fr;
|
||||
|
||||
.heading {
|
||||
padding: $medium;
|
||||
|
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<div class="nav-search-input">
|
||||
<SearchInput :on_nav="true" />
|
||||
<TabsWrapper
|
||||
<Tabs
|
||||
:tabs="tabs"
|
||||
:currentTab="($route.params.page as string)"
|
||||
@switchTab="(tab: string) => {
|
||||
$router.push({ name: Routes.search, params: { page: tab } });
|
||||
$router.replace({ name: Routes.search, params: { page: tab }, query: {
|
||||
q: search.query,
|
||||
} });
|
||||
search.switchTab(tab);
|
||||
}"
|
||||
/>
|
||||
@ -13,7 +15,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import TabsWrapper from "@/components/RightSideBar/Search/TabsWrapper.vue";
|
||||
import Tabs from "@/components/RightSideBar/Search/TabsWrapper.vue";
|
||||
import SearchInput from "@/components/RightSideBar/SearchInput.vue";
|
||||
import { Routes } from "@/router/routes";
|
||||
|
||||
|
@ -49,12 +49,11 @@ async function loadMoreTracks(index: number) {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function loadMoreAlbums(index: number, count: number) {
|
||||
async function loadMoreAlbums(index: number) {
|
||||
const response = await axios.get(loadMoreUrl, {
|
||||
params: {
|
||||
type: "albums",
|
||||
index: index,
|
||||
count: count,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { defineStore } from "pinia";
|
||||
import { watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { Routes } from "@/router/routes";
|
||||
import router from "@/router";
|
||||
|
||||
import {
|
||||
loadMoreAlbums,
|
||||
@ -128,11 +129,11 @@ export default defineStore("search", () => {
|
||||
.then(() => scrollOnLoad());
|
||||
}
|
||||
|
||||
function loadAlbums(count = 6) {
|
||||
loadCounter.albums += count;
|
||||
function loadAlbums() {
|
||||
loadCounter.albums += RESULT_COUNT;
|
||||
|
||||
startLoading();
|
||||
loadMoreAlbums(loadCounter.albums, count)
|
||||
loadMoreAlbums(loadCounter.albums)
|
||||
.then((res) => {
|
||||
albums.value = [...albums.value, ...res.albums];
|
||||
albums.more = res.more;
|
||||
@ -165,6 +166,15 @@ export default defineStore("search", () => {
|
||||
watch(
|
||||
() => debouncedQuery.value,
|
||||
(newQuery) => {
|
||||
if (route.name === Routes.search) {
|
||||
router.replace({
|
||||
name: Routes.search,
|
||||
params: {
|
||||
page: route.params.page,
|
||||
},
|
||||
query: { q: newQuery },
|
||||
});
|
||||
}
|
||||
// reset all counters
|
||||
for (const key in loadCounter) {
|
||||
// @ts-ignore
|
||||
|
@ -60,8 +60,9 @@ async function handlePlay(index: number) {
|
||||
<style lang="scss">
|
||||
.favorites-page {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
padding-bottom: 4rem;
|
||||
padding-right: 1rem;
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="search-albums-view grid-page" v-auto-animate>
|
||||
<div class="search-albums-view grid-page">
|
||||
<AlbumCard
|
||||
v-for="album in search.albums.value"
|
||||
:key="album.albumhash"
|
||||
:key="Math.random()"
|
||||
:album="album"
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-auto-animate class="search-artists-view grid-page">
|
||||
<div class="grid-page">
|
||||
<ArtistCard
|
||||
v-for="artist in search.artists.value"
|
||||
:key="artist.image"
|
||||
|
@ -1,12 +1,13 @@
|
||||
<template>
|
||||
<div class="search-view content-page" style="padding-right: 0;">
|
||||
<div class="search-view content-page" style="padding-right: 0">
|
||||
<div ref="page" class="page no-scroll" v-auto-animate>
|
||||
<component :is="component" />
|
||||
</div>
|
||||
<button
|
||||
v-if="$route.params.page !== 'tracks'"
|
||||
class="load-more"
|
||||
:class="{ 'btn-disabled': !canLoadMore }"
|
||||
@click="loadMore"
|
||||
@click="canLoadMore && loadMore()"
|
||||
>
|
||||
Load more
|
||||
</button>
|
||||
@ -14,20 +15,15 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Routes } from "@/router/routes";
|
||||
import { useRoute } from "vue-router";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
|
||||
import { focusElemByClass } from "@/utils";
|
||||
import useSearchStore from "@/stores/search";
|
||||
|
||||
import AlbumPage from "./albums.vue";
|
||||
import ArtistPage from "./artists.vue";
|
||||
import TracksPage from "./tracks.vue";
|
||||
|
||||
// width of album and artist cards
|
||||
const defaultItemCount = 6;
|
||||
const gridItemWidth = 160;
|
||||
const page = ref<HTMLElement>();
|
||||
|
||||
const search = useSearchStore();
|
||||
@ -57,44 +53,24 @@ const component = computed(() => {
|
||||
|
||||
function loadTracks() {
|
||||
search.loadTracks();
|
||||
focusElemByClass("track-11", 100);
|
||||
}
|
||||
|
||||
function getGridRowItemCount() {
|
||||
if (page.value?.offsetWidth === undefined) return defaultItemCount;
|
||||
const page_width = page.value?.offsetWidth - 16;
|
||||
return Math.floor(page_width / gridItemWidth);
|
||||
}
|
||||
|
||||
function scrollToGridPageBottom() {
|
||||
const elem = document.getElementsByClassName("grid-page")[0] as HTMLElement;
|
||||
setTimeout(() => {
|
||||
elem.scrollTo(0, elem.scrollHeight);
|
||||
elem.scroll({
|
||||
top: elem.scrollHeight,
|
||||
behavior: "smooth",
|
||||
});
|
||||
}, 250);
|
||||
|
||||
// const elemWidth = elem.offsetWidth;
|
||||
// console.log(Math.floor(elemWidth / 160));
|
||||
// elem.scroll({
|
||||
// top: elem.scrollHeight,
|
||||
// behavior: "smooth",
|
||||
// });
|
||||
}
|
||||
|
||||
function loadAlbums() {
|
||||
search.loadAlbums();
|
||||
scrollToGridPageBottom();
|
||||
|
||||
setTimeout(() => {
|
||||
// search.loadAlbums();
|
||||
const itemCount = getGridRowItemCount();
|
||||
search.loadAlbums(itemCount);
|
||||
|
||||
scrollToGridPageBottom();
|
||||
}, 250);
|
||||
|
||||
}
|
||||
|
||||
function loadArtists() {
|
||||
// const itemCount = getGridRowItemCount();
|
||||
search.loadArtists();
|
||||
|
||||
scrollToGridPageBottom();
|
||||
@ -132,17 +108,16 @@ const canLoadMore = computed(() => {
|
||||
|
||||
onMounted(() => {
|
||||
search.switchTab(route.params.page as string);
|
||||
search.query = route.query.q as string;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.search-view {
|
||||
height: calc(100% - 1rem);
|
||||
height: calc(100%);
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-rows: 1fr max-content;
|
||||
|
||||
margin-right: -0.75rem;
|
||||
position: relative;
|
||||
|
||||
.page.no-scroll {
|
||||
overflow-x: visible;
|
||||
@ -151,17 +126,31 @@ onMounted(() => {
|
||||
.grid-page {
|
||||
max-height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||
gap: 1.75rem 0;
|
||||
|
||||
padding-bottom: 4rem;
|
||||
overflow: auto;
|
||||
padding-right: $medium;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
button.load-more {
|
||||
width: 10rem;
|
||||
margin: 0 auto;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 3rem;
|
||||
left: -1.25rem;
|
||||
width: calc(100% + 1.25rem);
|
||||
border-radius: 0;
|
||||
background: $darkestblue;
|
||||
// margin: 0 auto;
|
||||
// margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.btn-disabled {
|
||||
pointer-events: all;
|
||||
background: $gray !important;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="settingspage content-page">
|
||||
<div class="settingspage content-page" style="height: 100%; overflow: auto">
|
||||
<Content :current="0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Content from "../components/SettingsView/Content.vue";
|
||||
</script>z
|
||||
</script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user