first commit

This commit is contained in:
Hydra 2024-04-14 04:20:27 +01:00
commit 992ec5ab49
No known key found for this signature in database
145 changed files with 37479 additions and 0 deletions

132
src/renderer/app.tsx Normal file
View file

@ -0,0 +1,132 @@
import { useCallback, useEffect, useRef } from "react";
import { Sidebar, BottomPanel, Header } from "@renderer/components";
import {
useAppDispatch,
useAppSelector,
useDownload,
useLibrary,
} from "@renderer/hooks";
import * as styles from "./app.css";
import { themeClass } from "./theme.css";
import debounce from "lodash/debounce";
import type { DebouncedFunc } from "lodash";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
import {
setSearch,
clearSearch,
setUserPreferences,
setRepackersFriendlyNames,
setSearchResults,
} from "@renderer/features";
document.body.classList.add(themeClass);
export function App() {
const contentRef = useRef<HTMLDivElement>(null);
const { updateLibrary } = useLibrary();
const { clearDownload, addPacket } = useDownload();
const dispatch = useAppDispatch();
const navigate = useNavigate();
const location = useLocation();
const debouncedFunc = useRef<DebouncedFunc<() => void | null>>(null);
const search = useAppSelector((state) => state.search.value);
useEffect(() => {
Promise.all([
window.electron.getUserPreferences(),
window.electron.getRepackersFriendlyNames(),
updateLibrary(),
]).then(([preferences, repackersFriendlyNames]) => {
dispatch(setUserPreferences(preferences));
dispatch(setRepackersFriendlyNames(repackersFriendlyNames));
});
}, [navigate, location.pathname, dispatch, updateLibrary]);
useEffect(() => {
const unsubscribe = window.electron.onDownloadProgress(
(downloadProgress) => {
if (downloadProgress.game.progress === 1) {
clearDownload();
updateLibrary();
return;
}
addPacket(downloadProgress);
}
);
return () => {
unsubscribe();
};
}, [clearDownload, addPacket, updateLibrary]);
const handleSearch = useCallback(
(query: string) => {
dispatch(setSearch(query));
if (debouncedFunc.current) debouncedFunc.current.cancel();
if (query === "") {
navigate(-1);
return;
}
if (location.pathname !== "/search") {
navigate("/search");
}
debouncedFunc.current = debounce(() => {
window.electron.searchGames(query).then((results) => {
dispatch(setSearchResults(results));
});
}, 300);
debouncedFunc.current();
},
[dispatch, location.pathname, navigate]
);
const handleClear = useCallback(() => {
dispatch(clearSearch());
navigate(-1);
}, [dispatch, navigate]);
useEffect(() => {
if (contentRef.current) contentRef.current.scrollTop = 0;
}, [location.pathname]);
return (
<>
{window.electron.platform === "win32" && (
<div className={styles.titleBar}>
<h4>Hydra</h4>
</div>
)}
<main>
<Sidebar />
<article className={styles.container}>
<Header
onSearch={handleSearch}
search={search}
onClear={handleClear}
/>
<section ref={contentRef} className={styles.content}>
<Outlet />
</section>
</article>
</main>
<BottomPanel />
</>
);
}