diff --git a/modules/desktop/src/components/packages/packages.svelte b/modules/desktop/src/components/packages/packages.svelte index a017589..4ddd9e3 100644 --- a/modules/desktop/src/components/packages/packages.svelte +++ b/modules/desktop/src/components/packages/packages.svelte @@ -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; + } + });
-
diff --git a/modules/desktop/src/libs/stores.ts b/modules/desktop/src/libs/stores.ts index a9b3aa2..1c50235 100644 --- a/modules/desktop/src/libs/stores.ts +++ b/modules/desktop/src/libs/stores.ts @@ -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([]); @@ -140,3 +141,5 @@ export const navStore = initNavStore(); export const notificationStore = initNotificationStore(); export const appUpdateStore = initAppUpdateStore(); + +export const scrollStore = initScrollStore(); diff --git a/modules/desktop/src/libs/stores/scroll.ts b/modules/desktop/src/libs/stores/scroll.ts new file mode 100644 index 0000000..d985996 --- /dev/null +++ b/modules/desktop/src/libs/stores/scroll.ts @@ -0,0 +1,33 @@ +import type { SideMenuOptions } from "$libs/types"; +import { get, writable } from "svelte/store"; + +type ScrollValue = Record; + +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({} as ScrollValue); + const limits = writable({} 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; + } + }; +}