From 9681bd97a75f4986fa2c461c2b46acb534f88e1a Mon Sep 17 00:00:00 2001 From: Jared Schoeny Date: Mon, 27 Oct 2025 15:10:46 -1000 Subject: [PATCH] Add loading state to `DiscoverBrowser` --- src/components/Discover/DiscoverBrowser.tsx | 133 ++++++++++++++------ 1 file changed, 96 insertions(+), 37 deletions(-) diff --git a/src/components/Discover/DiscoverBrowser.tsx b/src/components/Discover/DiscoverBrowser.tsx index 40516bb..50b1d8a 100644 --- a/src/components/Discover/DiscoverBrowser.tsx +++ b/src/components/Discover/DiscoverBrowser.tsx @@ -21,9 +21,13 @@ export default function DiscoverBrowser() { const [hacks, setHacks] = React.useState([]); const [tagGroups, setTagGroups] = React.useState>({}); const [ungroupedTags, setUngroupedTags] = React.useState([]); + const [loadingHacks, setLoadingHacks] = React.useState(true); + const [loadingTags, setLoadingTags] = React.useState(true); React.useEffect(() => { const run = async () => { + setLoadingHacks(true); + setLoadingTags(true); let orderBy: string | undefined = undefined; if (sort === "popular") { orderBy = "downloads"; @@ -115,6 +119,7 @@ export default function DiscoverBrowser() { })); setHacks(mapped); + setLoadingHacks(false); if (allTagRows) { const groups: Record = {}; const ungrouped: string[] = []; @@ -138,6 +143,8 @@ export default function DiscoverBrowser() { setTagGroups(groups); setUngroupedTags(ungrouped); } + // Ensure loadingTags is cleared even if no rows were returned + setLoadingTags(false); }; run(); }, [sort]); @@ -210,38 +217,50 @@ export default function DiscoverBrowser() { values={selectedBaseRoms} onChange={setSelectedBaseRoms} /> - {Object.keys(tagGroups) - .sort((a, b) => a.localeCompare(b)) - .map((cat) => ( - ({ id: t, name: t }))} - values={selectedTags.filter((t) => tagGroups[cat].includes(t))} - onChange={(vals) => { - // Replace selections for this category while keeping others - setSelectedTags((prev) => { - const others = prev.filter((t) => !tagGroups[cat].includes(t)); - return [...others, ...vals]; - }); - }} - /> - ))} - {/* Advanced dropdown for ungrouped tags at the end */} - {ungroupedTags.length > 0 && ( - ({ id: t, name: t }))} - values={selectedTags.filter((t) => ungroupedTags.includes(t))} - onChange={(vals) => { - setSelectedTags((prev) => { - const others = prev.filter((t) => !ungroupedTags.includes(t)); - return [...others, ...vals]; - }); - }} - /> + {loadingTags ? ( + <> + {[ + "w-28","w-36","w-32","w-24","w-24","w-28","w-36","w-36" + ].map((w, i) => ( +
+ ))} + + ) : ( + <> + {Object.keys(tagGroups) + .sort((a, b) => a.localeCompare(b)) + .map((cat) => ( + ({ id: t, name: t }))} + values={selectedTags.filter((t) => tagGroups[cat].includes(t))} + onChange={(vals) => { + // Replace selections for this category while keeping others + setSelectedTags((prev) => { + const others = prev.filter((t) => !tagGroups[cat].includes(t)); + return [...others, ...vals]; + }); + }} + /> + ))} + {/* Advanced dropdown for ungrouped tags at the end */} + {ungroupedTags.length > 0 && ( + ({ id: t, name: t }))} + values={selectedTags.filter((t) => ungroupedTags.includes(t))} + onChange={(vals) => { + setSelectedTags((prev) => { + const others = prev.filter((t) => !ungroupedTags.includes(t)); + return [...others, ...vals]; + }); + }} + /> + )} + )} {(selectedTags.length > 0 || selectedBaseRoms.length > 0) && (
); } @@ -361,3 +393,30 @@ function MultiSelectDropdown({ } +function HackCardSkeleton() { + return ( +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ); +} + +