mirror of
https://github.com/ivabus/gui
synced 2025-04-23 14:07:14 +03:00
preserver infinite scroll positions (#615)
This commit is contained in:
parent
87dd224f9a
commit
c0c2472b12
3 changed files with 71 additions and 4 deletions
|
@ -10,7 +10,8 @@
|
|||
import Package from "./package.svelte";
|
||||
import NoInstalls from "./no-installs.svelte";
|
||||
import NoUpdates from "./no-updates.svelte";
|
||||
import { packagesStore } from "$libs/stores";
|
||||
import { packagesStore, scrollStore } from "$libs/stores";
|
||||
import { afterUpdate, beforeUpdate } from "svelte";
|
||||
|
||||
const { packageList: allPackages } = packagesStore;
|
||||
export let packageFilter: SideMenuOptions = SideMenuOptions.all;
|
||||
|
@ -20,6 +21,11 @@
|
|||
let loadMore = 9;
|
||||
let limit = loadMore + 9;
|
||||
|
||||
const updateLimit = (value: number) => {
|
||||
limit += value;
|
||||
scrollStore.setLimit(packageFilter, limit);
|
||||
};
|
||||
|
||||
// TODO: figure out a better type strategy here so that this breaks if SideMenuOptions is updated
|
||||
const pkgFilters: { [key: string]: (pkg: GUIPackage) => boolean } = {
|
||||
[SideMenuOptions.all]: (_pkg: GUIPackage) => true,
|
||||
|
@ -46,6 +52,7 @@
|
|||
const onScroll = (e: Event) => {
|
||||
const target = e.target as HTMLInputElement;
|
||||
scrollY = target.scrollTop || 0;
|
||||
scrollStore.setScrollPosition(packageFilter, scrollY);
|
||||
};
|
||||
|
||||
$: packages = $allPackages.filter(pkgFilters[packageFilter] || pkgFilters.all);
|
||||
|
@ -56,13 +63,37 @@
|
|||
const minCardRows = Math.floor(node.scrollHeight / assumedCardHeight);
|
||||
if (cardRows < minCardRows) {
|
||||
const addLimit = 3 * (minCardRows - cardRows);
|
||||
limit += addLimit;
|
||||
updateLimit(addLimit);
|
||||
}
|
||||
};
|
||||
|
||||
let scrollElement: any = null;
|
||||
let prevFilter: SideMenuOptions | null;
|
||||
|
||||
// Restore the limit before the update...
|
||||
beforeUpdate(() => {
|
||||
if (prevFilter !== packageFilter) {
|
||||
limit = scrollStore.getLimit(packageFilter);
|
||||
}
|
||||
});
|
||||
|
||||
// ...and scroll position after the update
|
||||
afterUpdate(() => {
|
||||
if (prevFilter !== packageFilter && scrollElement) {
|
||||
prevFilter = packageFilter;
|
||||
const scrollPosition = scrollStore.getScrollPosition(packageFilter);
|
||||
scrollElement.scrollTop = scrollPosition;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="relative h-full w-full">
|
||||
<ul class="flex flex-wrap content-start bg-black" use:watchResize={onResize} on:scroll={onScroll}>
|
||||
<ul
|
||||
bind:this={scrollElement}
|
||||
class="flex flex-wrap content-start bg-black"
|
||||
use:watchResize={onResize}
|
||||
on:scroll={onScroll}
|
||||
>
|
||||
{#if packages.length > 0}
|
||||
{#each packages as pkg, index}
|
||||
{#if index < limit}
|
||||
|
@ -84,7 +115,7 @@
|
|||
</section>
|
||||
{/each}
|
||||
{/if}
|
||||
<InfiniteScroll threshold={100} on:loadMore={() => (limit += loadMore)} />
|
||||
<InfiniteScroll threshold={100} on:loadMore={() => updateLimit(loadMore)} />
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import pkgStore from "./stores/pkgs";
|
|||
import initNotificationStore from "./stores/notifications";
|
||||
import initAppUpdateStore from "./stores/update";
|
||||
import { trackSearch } from "./analytics";
|
||||
import initScrollStore from "./stores/scroll";
|
||||
|
||||
export const featuredPackages = writable<Package[]>([]);
|
||||
|
||||
|
@ -140,3 +141,5 @@ export const navStore = initNavStore();
|
|||
export const notificationStore = initNotificationStore();
|
||||
|
||||
export const appUpdateStore = initAppUpdateStore();
|
||||
|
||||
export const scrollStore = initScrollStore();
|
||||
|
|
33
modules/desktop/src/libs/stores/scroll.ts
Normal file
33
modules/desktop/src/libs/stores/scroll.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import type { SideMenuOptions } from "$libs/types";
|
||||
import { get, writable } from "svelte/store";
|
||||
|
||||
type ScrollValue = Record<SideMenuOptions, number>;
|
||||
|
||||
const defaultLimit = 18;
|
||||
|
||||
// keep track of the scroll position of each side menu filter so it's not lost after navigation
|
||||
export default function initScrollStore() {
|
||||
const scrollPositions = writable<ScrollValue>({} as ScrollValue);
|
||||
const limits = writable<ScrollValue>({} as ScrollValue);
|
||||
|
||||
return {
|
||||
setScrollPosition: (filter: SideMenuOptions, pos: number) => {
|
||||
scrollPositions.update((prev) => {
|
||||
prev[filter] = pos;
|
||||
return prev;
|
||||
});
|
||||
},
|
||||
getScrollPosition: (filter: SideMenuOptions) => {
|
||||
return get(scrollPositions)[filter] || 0;
|
||||
},
|
||||
setLimit: (filter: SideMenuOptions, limit: number) => {
|
||||
limits.update((prev) => {
|
||||
prev[filter] = limit;
|
||||
return prev;
|
||||
});
|
||||
},
|
||||
getLimit: (filter: SideMenuOptions) => {
|
||||
return get(limits)[filter] || defaultLimit;
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue