-
- {virtualizer.getVirtualItems().map((virtualRow) => {
- const rowStartIndex = virtualRow.index * columnCount;
- const rowItems = items.slice(rowStartIndex, rowStartIndex + columnCount);
-
- return (
-
-
- {rowItems.map((item, colIdx) => {
- const idx = rowStartIndex + colIdx;
- const libraryGame =
- (item.steamAppId ? libraryGamesMap.get(String(item.steamAppId)) : undefined) ??
- libraryGamesMap.get(item.name.toLowerCase());
+
+ {items.map((item, idx) => {
+ const libraryGame =
+ (item.steamAppId ? libraryGamesMap.get(String(item.steamAppId)) : undefined) ??
+ libraryGamesMap.get(item.name.toLowerCase());
- const uniqueKey = item.steamAppId ? `steam-${item.steamAppId}` : `${item.name}-${idx}`;
+ const uniqueKey = item.steamAppId ? `steam-${item.steamAppId}` : `${item.name}-${idx}`;
- return (
-
- );
- })}
-
-
- );
- })}
-
+ return (
+
+
+
+ );
+ })}
);
});
diff --git a/apps/desktop/src/features/steam-catalog/hooks/useCatalogScrollRestoration.ts b/apps/desktop/src/features/steam-catalog/hooks/useCatalogScrollRestoration.ts
deleted file mode 100644
index df54dbde..00000000
--- a/apps/desktop/src/features/steam-catalog/hooks/useCatalogScrollRestoration.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { useEffect, useLayoutEffect, useRef } from "react";
-
-const SCROLL_STORAGE_KEY = "savecloud_catalog_scroll_y";
-
-export function useCatalogScrollRestoration(itemsLength: number, isReady: boolean) {
- const restoredRef = useRef(false);
-
- useEffect(() => {
- const handleScroll = () => {
- if (window.scrollY > 0) {
- sessionStorage.setItem(SCROLL_STORAGE_KEY, String(window.scrollY));
- }
- };
-
- window.addEventListener("scroll", handleScroll, { passive: true });
- return () => window.removeEventListener("scroll", handleScroll);
- }, []);
-
- useLayoutEffect(() => {
- if (restoredRef.current || !isReady || itemsLength === 0) return;
-
- const savedY = sessionStorage.getItem(SCROLL_STORAGE_KEY);
- if (savedY) {
- const scrollY = parseInt(savedY, 10);
- if (!isNaN(scrollY) && scrollY > 0) {
- window.scrollTo({ top: scrollY, behavior: "instant" });
-
- requestAnimationFrame(() => {
- window.scrollTo({ top: scrollY, behavior: "instant" });
- });
- }
- }
- restoredRef.current = true;
- }, [itemsLength, isReady]);
-
- const clearSavedScroll = () => {
- sessionStorage.removeItem(SCROLL_STORAGE_KEY);
- restoredRef.current = true;
- };
-
- return { clearSavedScroll };
-}
diff --git a/apps/desktop/src/features/steam-catalog/pages/SteamCatalogPage.tsx b/apps/desktop/src/features/steam-catalog/pages/SteamCatalogPage.tsx
index e330b8e7..2b37faef 100644
--- a/apps/desktop/src/features/steam-catalog/pages/SteamCatalogPage.tsx
+++ b/apps/desktop/src/features/steam-catalog/pages/SteamCatalogPage.tsx
@@ -28,7 +28,10 @@ export function SteamCatalogPage() {
const catalogScrollPosition = useShellUiStore((state) => state.catalogScrollPosition);
const setCatalogScrollPosition = useShellUiStore((state) => state.setCatalogScrollPosition);
+ const initialScrollTargetRef = useRef(catalogScrollPosition);
+ const currentScrollYRef = useRef(catalogScrollPosition);
const hasRestored = useRef(false);
+ const isRestoringRef = useRef(false);
const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false);
const bigPictureConsole = useMemo(
@@ -162,25 +165,25 @@ export function SteamCatalogPage() {
error: heroError,
} = useSteamCatalogTrendingHero(showTrendingHero);
- const isRestoringRef = useRef(false);
const prevFiltersRef = useRef({ debouncedSearch, filterSignature, sortOption });
useLayoutEffect(() => {
- if (catalogScrollPosition > 0 && isReady && !hasRestored.current) {
- void document.body.offsetHeight;
+ if (hasRestored.current || !isReady) return;
+ const targetY = initialScrollTargetRef.current;
+ if (targetY > 0) {
isRestoringRef.current = true;
- window.scrollTo({ top: catalogScrollPosition, behavior: "instant" });
+ window.scrollTo({ top: targetY, behavior: "instant" });
+ hasRestored.current = true;
const timer = setTimeout(() => {
- void document.body.offsetHeight;
- window.scrollTo({ top: catalogScrollPosition, behavior: "instant" });
- hasRestored.current = true;
isRestoringRef.current = false;
- }, 100);
+ }, 200);
return () => clearTimeout(timer);
+ } else {
+ hasRestored.current = true;
}
- }, [isReady, catalogScrollPosition, activeItems.length]);
+ }, [isReady]);
useEffect(() => {
const prev = prevFiltersRef.current;
@@ -191,8 +194,11 @@ export function SteamCatalogPage() {
prevFiltersRef.current = { debouncedSearch, filterSignature, sortOption };
- if (hasChanged && hasRestored.current) {
+ if (hasChanged) {
setCatalogScrollPosition(0);
+ initialScrollTargetRef.current = 0;
+ currentScrollYRef.current = 0;
+ window.scrollTo({ top: 0, behavior: "instant" });
}
}, [debouncedSearch, filterSignature, sortOption, setCatalogScrollPosition]);
@@ -200,23 +206,25 @@ export function SteamCatalogPage() {
let scrollTimeout: ReturnType
;
const handleScroll = () => {
- if (isRestoringRef.current) return;
+ if (!hasRestored.current || isRestoringRef.current) return;
+ const currentY = window.scrollY || document.documentElement.scrollTop;
+ if (currentY > 0) {
+ currentScrollYRef.current = currentY;
+ }
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
- const currentY = window.scrollY || document.documentElement.scrollTop;
- if (currentY > 0) {
- setCatalogScrollPosition(currentY);
+ if (currentScrollYRef.current > 0) {
+ setCatalogScrollPosition(currentScrollYRef.current);
}
- }, 200);
+ }, 150);
};
window.addEventListener("scroll", handleScroll, { passive: true });
return () => {
window.removeEventListener("scroll", handleScroll);
clearTimeout(scrollTimeout);
- const currentY = window.scrollY || document.documentElement.scrollTop;
- if (currentY > 0 && !isRestoringRef.current) {
- setCatalogScrollPosition(currentY);
+ if (hasRestored.current && !isRestoringRef.current && currentScrollYRef.current > 0) {
+ setCatalogScrollPosition(currentScrollYRef.current);
}
};
}, [setCatalogScrollPosition]);
@@ -364,9 +372,6 @@ export function SteamCatalogPage() {
) : (
<>
- {activeIsMatchingPending ? (
-