Use localStorage hook

This commit is contained in:
DrMint 2022-08-16 01:25:01 +02:00
parent 625f436163
commit 1bbf3b164a
9 changed files with 106 additions and 154 deletions

View File

@ -109,7 +109,7 @@ export const AppLayout = ({
onSwipedLeft: (SwipeEventData) => { onSwipedLeft: (SwipeEventData) => {
if (menuGestures) { if (menuGestures) {
if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return;
if (mainPanelOpen === true) { if (mainPanelOpen) {
setMainPanelOpen(false); setMainPanelOpen(false);
} else if (isDefined(subPanel) && isDefined(contentPanel)) { } else if (isDefined(subPanel) && isDefined(contentPanel)) {
setSubPanelOpen(true); setSubPanelOpen(true);
@ -119,7 +119,7 @@ export const AppLayout = ({
onSwipedRight: (SwipeEventData) => { onSwipedRight: (SwipeEventData) => {
if (menuGestures) { if (menuGestures) {
if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return;
if (subPanelOpen === true) { if (subPanelOpen) {
setSubPanelOpen(false); setSubPanelOpen(false);
} else { } else {
setMainPanelOpen(true); setMainPanelOpen(true);
@ -135,7 +135,7 @@ export const AppLayout = ({
useLayoutEffect(() => { useLayoutEffect(() => {
document.getElementsByTagName("html")[0].style.fontSize = `${ document.getElementsByTagName("html")[0].style.fontSize = `${
(fontSize ?? 1) * 100 fontSize * 100
}%`; }%`;
}, [fontSize]); }, [fontSize]);
@ -159,18 +159,16 @@ export const AppLayout = ({
}, [currencyOptions, currencySelect, setCurrency]); }, [currencyOptions, currencySelect, setCurrency]);
useEffect(() => { useEffect(() => {
if (preferredLanguages) { if (preferredLanguages.length === 0) {
if (preferredLanguages.length === 0) { if (isDefinedAndNotEmpty(router.locale) && router.locales) {
if (isDefinedAndNotEmpty(router.locale) && router.locales) { setPreferredLanguages(
setPreferredLanguages( getDefaultPreferredLanguages(router.locale, router.locales)
getDefaultPreferredLanguages(router.locale, router.locales) );
);
}
} else if (router.locale !== preferredLanguages[0]) {
router.replace(router.asPath, router.asPath, {
locale: preferredLanguages[0],
});
} }
} else if (router.locale !== preferredLanguages[0]) {
router.replace(router.asPath, router.asPath, {
locale: preferredLanguages[0],
});
} }
}, [ }, [
preferredLanguages, preferredLanguages,
@ -182,11 +180,11 @@ export const AppLayout = ({
const gridCol = useMemo(() => { const gridCol = useMemo(() => {
if (isDefined(subPanel)) { if (isDefined(subPanel)) {
if (mainPanelReduced === true) { if (mainPanelReduced) {
return "grid-cols-[6rem_20rem_1fr]"; return "grid-cols-[6rem_20rem_1fr]";
} }
return "grid-cols-[20rem_20rem_1fr]"; return "grid-cols-[20rem_20rem_1fr]";
} else if (mainPanelReduced === true) { } else if (mainPanelReduced) {
return "grid-cols-[6rem_0px_1fr]"; return "grid-cols-[6rem_0px_1fr]";
} }
return "grid-cols-[20rem_0px_1fr]"; return "grid-cols-[20rem_0px_1fr]";
@ -262,7 +260,7 @@ export const AppLayout = ({
`absolute inset-0 transition-[backdrop-filter] duration-500 [grid-area:content] `absolute inset-0 transition-[backdrop-filter] duration-500 [grid-area:content]
mobile:z-10`, mobile:z-10`,
cIf( cIf(
(mainPanelOpen === true || subPanelOpen === true) && isMobile, (mainPanelOpen || subPanelOpen) && isMobile,
"[backdrop-filter:blur(2px)]", "[backdrop-filter:blur(2px)]",
"pointer-events-none touch-none" "pointer-events-none touch-none"
) )
@ -272,7 +270,7 @@ export const AppLayout = ({
className={cJoin( className={cJoin(
"absolute inset-0 bg-shade transition-opacity duration-500", "absolute inset-0 bg-shade transition-opacity duration-500",
cIf( cIf(
(mainPanelOpen === true || subPanelOpen === true) && isMobile, (mainPanelOpen || subPanelOpen) && isMobile,
"opacity-60", "opacity-60",
"opacity-0" "opacity-0"
) )
@ -312,7 +310,7 @@ export const AppLayout = ({
mobile:border-r-0 mobile:border-l-[1px] mobile:[grid-area:content]`, mobile:border-r-0 mobile:border-l-[1px] mobile:[grid-area:content]`,
turnSubIntoContent turnSubIntoContent
? "mobile:w-full mobile:border-l-0" ? "mobile:w-full mobile:border-l-0"
: subPanelOpen === true : subPanelOpen
? "" ? ""
: "mobile:translate-x-[100vw]" : "mobile:translate-x-[100vw]"
)} )}
@ -328,7 +326,7 @@ export const AppLayout = ({
transition-transform duration-300 [grid-area:main] [scrollbar-width:none] transition-transform duration-300 [grid-area:main] [scrollbar-width:none]
webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%] mobile:justify-self-start webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%] mobile:justify-self-start
mobile:[grid-area:content]`, mobile:[grid-area:content]`,
cIf(mainPanelOpen === false, "mobile:-translate-x-full") cIf(!mainPanelOpen, "mobile:-translate-x-full")
)} )}
> >
<MainPanel langui={langui} /> <MainPanel langui={langui} />
@ -340,7 +338,7 @@ export const AppLayout = ({
border-t-[1px] border-dotted border-black bg-light [grid-area:navbar] desktop:hidden" border-t-[1px] border-dotted border-black bg-light [grid-area:navbar] desktop:hidden"
> >
<Ico <Ico
icon={mainPanelOpen === true ? Icon.Close : Icon.Menu} icon={mainPanelOpen ? Icon.Close : Icon.Menu}
className="mt-[.1em] cursor-pointer !text-2xl" className="mt-[.1em] cursor-pointer !text-2xl"
onClick={() => { onClick={() => {
toggleMainPanelOpen(); toggleMainPanelOpen();
@ -365,7 +363,7 @@ export const AppLayout = ({
</p> </p>
{isDefined(subPanel) && !turnSubIntoContent && ( {isDefined(subPanel) && !turnSubIntoContent && (
<Ico <Ico
icon={subPanelOpen === true ? Icon.Close : subPanelIcon} icon={subPanelOpen ? Icon.Close : subPanelIcon}
className="mt-[.1em] cursor-pointer !text-2xl" className="mt-[.1em] cursor-pointer !text-2xl"
onClick={() => { onClick={() => {
toggleSubPanelOpen(); toggleSubPanelOpen();
@ -404,7 +402,7 @@ export const AppLayout = ({
</Popup> </Popup>
<Popup <Popup
state={configPanelOpen ?? false} state={configPanelOpen}
onClose={() => setConfigPanelOpen(false)} onClose={() => setConfigPanelOpen(false)}
> >
<h2 className="text-2xl">{langui.settings}</h2> <h2 className="text-2xl">{langui.settings}</h2>
@ -416,7 +414,7 @@ export const AppLayout = ({
{router.locales && ( {router.locales && (
<div> <div>
<h3 className="text-xl">{langui.languages}</h3> <h3 className="text-xl">{langui.languages}</h3>
{preferredLanguages && preferredLanguages.length > 0 && ( {preferredLanguages.length > 0 && (
<OrderableList <OrderableList
items={ items={
new Map( new Map(
@ -453,14 +451,14 @@ export const AppLayout = ({
setDarkMode(false); setDarkMode(false);
setSelectedThemeMode(true); setSelectedThemeMode(true);
}, },
active: selectedThemeMode === true && darkMode === false, active: selectedThemeMode && darkMode,
text: langui.light, text: langui.light,
}, },
{ {
onClick: () => { onClick: () => {
setSelectedThemeMode(false); setSelectedThemeMode(false);
}, },
active: selectedThemeMode === false, active: selectedThemeMode,
text: langui.auto, text: langui.auto,
}, },
{ {
@ -468,7 +466,7 @@ export const AppLayout = ({
setDarkMode(true); setDarkMode(true);
setSelectedThemeMode(true); setSelectedThemeMode(true);
}, },
active: selectedThemeMode === true && darkMode === true, active: selectedThemeMode && darkMode,
text: langui.dark, text: langui.dark,
}, },
]} ]}
@ -492,20 +490,17 @@ export const AppLayout = ({
<ButtonGroup <ButtonGroup
buttonsProps={[ buttonsProps={[
{ {
onClick: () => setFontSize((fontSize ?? 1) / 1.05), onClick: () => setFontSize(fontSize / 1.05),
icon: Icon.TextDecrease, icon: Icon.TextDecrease,
}, },
{ {
onClick: () => setFontSize(1), onClick: () => setFontSize(1),
text: `${((fontSize ?? 1) * 100).toLocaleString( text: `${(fontSize * 100).toLocaleString(undefined, {
undefined, maximumFractionDigits: 0,
{ })}%`,
maximumFractionDigits: 0,
}
)}%`,
}, },
{ {
onClick: () => setFontSize((fontSize ?? 1) * 1.05), onClick: () => setFontSize(fontSize * 1.05),
icon: Icon.TextIncrease, icon: Icon.TextIncrease,
}, },
]} ]}
@ -516,13 +511,13 @@ export const AppLayout = ({
<h3 className="text-xl">{langui.font}</h3> <h3 className="text-xl">{langui.font}</h3>
<div className="grid gap-2"> <div className="grid gap-2">
<Button <Button
active={dyslexic === false} active={!dyslexic}
onClick={() => setDyslexic(false)} onClick={() => setDyslexic(false)}
className="font-zenMaruGothic" className="font-zenMaruGothic"
text="Zen Maru Gothic" text="Zen Maru Gothic"
/> />
<Button <Button
active={dyslexic === true} active={dyslexic}
onClick={() => setDyslexic(true)} onClick={() => setDyslexic(true)}
className="font-openDyslexic" className="font-openDyslexic"
text="OpenDyslexic" text="OpenDyslexic"
@ -535,7 +530,7 @@ export const AppLayout = ({
<TextInput <TextInput
placeholder="<player>" placeholder="<player>"
className="w-48" className="w-48"
value={playerName ?? ""} value={playerName}
onChange={setPlayerName} onChange={setPlayerName}
/> />
</div> </div>

View File

@ -1,5 +1,5 @@
import { Fragment, useCallback } from "react"; import { Fragment, useCallback, useRef } from "react";
import { useBoolean } from "usehooks-ts"; import { useBoolean, useOnClickOutside } from "usehooks-ts";
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { cIf, cJoin } from "helpers/className"; import { cIf, cJoin } from "helpers/className";
@ -37,11 +37,12 @@ export const Select = ({
if (optionCount > 1) toggleOpened(); if (optionCount > 1) toggleOpened();
}, [options.length, value, toggleOpened]); }, [options.length, value, toggleOpened]);
const ref = useRef<HTMLDivElement>(null);
useOnClickOutside(ref, setClosed);
return ( return (
<div <div
onClickCapture={() => { ref={ref}
setClosed();
}}
className={cJoin( className={cJoin(
"relative text-center transition-[filter]", "relative text-center transition-[filter]",
cIf(isOpened, "z-10 drop-shadow-shade-lg"), cIf(isOpened, "z-10 drop-shadow-shade-lg"),

View File

@ -35,7 +35,7 @@ export const PreviewCardCTAs = ({
<Button <Button
icon={Icon.Favorite} icon={Icon.Favorite}
text={expand ? langui.want_it : undefined} text={expand ? langui.want_it : undefined}
active={libraryItemUserStatus?.[id] === LibraryItemUserStatus.Want} active={libraryItemUserStatus[id] === LibraryItemUserStatus.Want}
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
setLibraryItemUserStatus((current) => { setLibraryItemUserStatus((current) => {
@ -53,7 +53,7 @@ export const PreviewCardCTAs = ({
<Button <Button
icon={Icon.BackHand} icon={Icon.BackHand}
text={expand ? langui.have_it : undefined} text={expand ? langui.have_it : undefined}
active={libraryItemUserStatus?.[id] === LibraryItemUserStatus.Have} active={libraryItemUserStatus[id] === LibraryItemUserStatus.Have}
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
setLibraryItemUserStatus((current) => { setLibraryItemUserStatus((current) => {

View File

@ -1,64 +1,77 @@
import React, { ReactNode, useContext, useState } from "react"; import React, { ReactNode, useContext, useState } from "react";
import { useLocalStorage } from "usehooks-ts";
import { isDefined } from "helpers/others"; import { isDefined } from "helpers/others";
import { LibraryItemUserStatus, RequiredNonNullable } from "helpers/types"; import { LibraryItemUserStatus, RequiredNonNullable } from "helpers/types";
import { useDarkMode } from "hooks/useDarkMode"; import { useDarkMode } from "hooks/useDarkMode";
import { useStateWithLocalStorage } from "hooks/useStateWithLocalStorage";
interface AppLayoutState { interface AppLayoutState {
subPanelOpen: boolean | undefined; subPanelOpen: boolean;
toggleSubPanelOpen: () => void; toggleSubPanelOpen: () => void;
setSubPanelOpen: React.Dispatch< setSubPanelOpen: React.Dispatch<
React.SetStateAction<AppLayoutState["subPanelOpen"]> React.SetStateAction<AppLayoutState["subPanelOpen"]>
>; >;
configPanelOpen: boolean | undefined;
configPanelOpen: boolean;
toggleConfigPanelOpen: () => void; toggleConfigPanelOpen: () => void;
setConfigPanelOpen: React.Dispatch< setConfigPanelOpen: React.Dispatch<
React.SetStateAction<AppLayoutState["configPanelOpen"]> React.SetStateAction<AppLayoutState["configPanelOpen"]>
>; >;
searchPanelOpen: boolean | undefined;
searchPanelOpen: boolean;
toggleSearchPanelOpen: () => void; toggleSearchPanelOpen: () => void;
setSearchPanelOpen: React.Dispatch< setSearchPanelOpen: React.Dispatch<
React.SetStateAction<AppLayoutState["searchPanelOpen"]> React.SetStateAction<AppLayoutState["searchPanelOpen"]>
>; >;
mainPanelReduced: boolean | undefined;
mainPanelReduced: boolean;
toggleMainPanelReduced: () => void; toggleMainPanelReduced: () => void;
setMainPanelReduced: React.Dispatch< setMainPanelReduced: React.Dispatch<
React.SetStateAction<AppLayoutState["mainPanelReduced"]> React.SetStateAction<AppLayoutState["mainPanelReduced"]>
>; >;
mainPanelOpen: boolean | undefined;
mainPanelOpen: boolean;
toggleMainPanelOpen: () => void; toggleMainPanelOpen: () => void;
setMainPanelOpen: React.Dispatch< setMainPanelOpen: React.Dispatch<
React.SetStateAction<AppLayoutState["mainPanelOpen"]> React.SetStateAction<AppLayoutState["mainPanelOpen"]>
>; >;
darkMode: boolean | undefined;
darkMode: boolean;
toggleDarkMode: () => void; toggleDarkMode: () => void;
setDarkMode: React.Dispatch<React.SetStateAction<AppLayoutState["darkMode"]>>; setDarkMode: React.Dispatch<React.SetStateAction<AppLayoutState["darkMode"]>>;
selectedThemeMode: boolean | undefined;
selectedThemeMode: boolean;
toggleSelectedThemeMode: () => void; toggleSelectedThemeMode: () => void;
setSelectedThemeMode: React.Dispatch< setSelectedThemeMode: React.Dispatch<
React.SetStateAction<AppLayoutState["selectedThemeMode"]> React.SetStateAction<AppLayoutState["selectedThemeMode"]>
>; >;
fontSize: number | undefined;
fontSize: number;
setFontSize: React.Dispatch<React.SetStateAction<AppLayoutState["fontSize"]>>; setFontSize: React.Dispatch<React.SetStateAction<AppLayoutState["fontSize"]>>;
dyslexic: boolean | undefined;
dyslexic: boolean;
toggleDyslexic: () => void; toggleDyslexic: () => void;
setDyslexic: React.Dispatch<React.SetStateAction<AppLayoutState["dyslexic"]>>; setDyslexic: React.Dispatch<React.SetStateAction<AppLayoutState["dyslexic"]>>;
currency: string | undefined;
currency: string;
setCurrency: React.Dispatch<React.SetStateAction<AppLayoutState["currency"]>>; setCurrency: React.Dispatch<React.SetStateAction<AppLayoutState["currency"]>>;
playerName: string | undefined;
playerName: string;
setPlayerName: React.Dispatch< setPlayerName: React.Dispatch<
React.SetStateAction<AppLayoutState["playerName"]> React.SetStateAction<AppLayoutState["playerName"]>
>; >;
preferredLanguages: string[] | undefined;
preferredLanguages: string[];
setPreferredLanguages: React.Dispatch< setPreferredLanguages: React.Dispatch<
React.SetStateAction<AppLayoutState["preferredLanguages"]> React.SetStateAction<AppLayoutState["preferredLanguages"]>
>; >;
menuGestures: boolean; menuGestures: boolean;
toggleMenuGestures: () => void; toggleMenuGestures: () => void;
setMenuGestures: React.Dispatch< setMenuGestures: React.Dispatch<
React.SetStateAction<AppLayoutState["menuGestures"]> React.SetStateAction<AppLayoutState["menuGestures"]>
>; >;
libraryItemUserStatus: Record<string, LibraryItemUserStatus> | undefined;
libraryItemUserStatus: Record<string, LibraryItemUserStatus>;
setLibraryItemUserStatus: React.Dispatch< setLibraryItemUserStatus: React.Dispatch<
React.SetStateAction<AppLayoutState["libraryItemUserStatus"]> React.SetStateAction<AppLayoutState["libraryItemUserStatus"]>
>; >;
@ -68,38 +81,51 @@ const initialState: RequiredNonNullable<AppLayoutState> = {
subPanelOpen: false, subPanelOpen: false,
toggleSubPanelOpen: () => null, toggleSubPanelOpen: () => null,
setSubPanelOpen: () => null, setSubPanelOpen: () => null,
configPanelOpen: false, configPanelOpen: false,
setConfigPanelOpen: () => null, setConfigPanelOpen: () => null,
toggleConfigPanelOpen: () => null, toggleConfigPanelOpen: () => null,
searchPanelOpen: false, searchPanelOpen: false,
setSearchPanelOpen: () => null, setSearchPanelOpen: () => null,
toggleSearchPanelOpen: () => null, toggleSearchPanelOpen: () => null,
mainPanelReduced: false, mainPanelReduced: false,
setMainPanelReduced: () => null, setMainPanelReduced: () => null,
toggleMainPanelReduced: () => null, toggleMainPanelReduced: () => null,
mainPanelOpen: false, mainPanelOpen: false,
toggleMainPanelOpen: () => null, toggleMainPanelOpen: () => null,
setMainPanelOpen: () => null, setMainPanelOpen: () => null,
darkMode: false, darkMode: false,
toggleDarkMode: () => null, toggleDarkMode: () => null,
setDarkMode: () => null, setDarkMode: () => null,
selectedThemeMode: false, selectedThemeMode: false,
toggleSelectedThemeMode: () => null, toggleSelectedThemeMode: () => null,
setSelectedThemeMode: () => null, setSelectedThemeMode: () => null,
fontSize: 1, fontSize: 1,
setFontSize: () => null, setFontSize: () => null,
dyslexic: false, dyslexic: false,
toggleDyslexic: () => null, toggleDyslexic: () => null,
setDyslexic: () => null, setDyslexic: () => null,
currency: "USD", currency: "USD",
setCurrency: () => null, setCurrency: () => null,
playerName: "", playerName: "",
setPlayerName: () => null, setPlayerName: () => null,
preferredLanguages: [], preferredLanguages: [],
setPreferredLanguages: () => null, setPreferredLanguages: () => null,
menuGestures: true, menuGestures: true,
toggleMenuGestures: () => null, toggleMenuGestures: () => null,
setMenuGestures: () => null, setMenuGestures: () => null,
libraryItemUserStatus: {}, libraryItemUserStatus: {},
setLibraryItemUserStatus: () => null, setLibraryItemUserStatus: () => null,
}; };
@ -113,22 +139,22 @@ interface Props {
} }
export const AppContextProvider = (props: Props): JSX.Element => { export const AppContextProvider = (props: Props): JSX.Element => {
const [subPanelOpen, setSubPanelOpen] = useStateWithLocalStorage( const [subPanelOpen, setSubPanelOpen] = useLocalStorage(
"subPanelOpen", "subPanelOpen",
initialState.subPanelOpen initialState.subPanelOpen
); );
const [configPanelOpen, setConfigPanelOpen] = useStateWithLocalStorage( const [configPanelOpen, setConfigPanelOpen] = useLocalStorage(
"configPanelOpen", "configPanelOpen",
initialState.configPanelOpen initialState.configPanelOpen
); );
const [mainPanelReduced, setMainPanelReduced] = useStateWithLocalStorage( const [mainPanelReduced, setMainPanelReduced] = useLocalStorage(
"mainPanelReduced", "mainPanelReduced",
initialState.mainPanelReduced initialState.mainPanelReduced
); );
const [mainPanelOpen, setMainPanelOpen] = useStateWithLocalStorage( const [mainPanelOpen, setMainPanelOpen] = useLocalStorage(
"mainPanelOpen", "mainPanelOpen",
initialState.mainPanelOpen initialState.mainPanelOpen
); );
@ -136,43 +162,42 @@ export const AppContextProvider = (props: Props): JSX.Element => {
const [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode] = const [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode] =
useDarkMode("darkMode", initialState.darkMode); useDarkMode("darkMode", initialState.darkMode);
const [fontSize, setFontSize] = useStateWithLocalStorage( const [fontSize, setFontSize] = useLocalStorage(
"fontSize", "fontSize",
initialState.fontSize initialState.fontSize
); );
const [dyslexic, setDyslexic] = useStateWithLocalStorage( const [dyslexic, setDyslexic] = useLocalStorage(
"dyslexic", "dyslexic",
initialState.dyslexic initialState.dyslexic
); );
const [currency, setCurrency] = useStateWithLocalStorage( const [currency, setCurrency] = useLocalStorage(
"currency", "currency",
initialState.currency initialState.currency
); );
const [playerName, setPlayerName] = useStateWithLocalStorage( const [playerName, setPlayerName] = useLocalStorage(
"playerName", "playerName",
initialState.playerName initialState.playerName
); );
const [preferredLanguages, setPreferredLanguages] = useStateWithLocalStorage( const [preferredLanguages, setPreferredLanguages] = useLocalStorage(
"preferredLanguages", "preferredLanguages",
initialState.preferredLanguages initialState.preferredLanguages
); );
const [menuGestures, setMenuGestures] = useState(false); const [menuGestures, setMenuGestures] = useState(false);
const [searchPanelOpen, setSearchPanelOpen] = useStateWithLocalStorage( const [searchPanelOpen, setSearchPanelOpen] = useLocalStorage(
"searchPanelOpen", "searchPanelOpen",
initialState.searchPanelOpen initialState.searchPanelOpen
); );
const [libraryItemUserStatus, setLibraryItemUserStatus] = const [libraryItemUserStatus, setLibraryItemUserStatus] = useLocalStorage(
useStateWithLocalStorage( "libraryItemUserStatus",
"libraryItemUserStatus", initialState.libraryItemUserStatus
initialState.libraryItemUserStatus );
);
const toggleSubPanelOpen = () => { const toggleSubPanelOpen = () => {
setSubPanelOpen((current) => (isDefined(current) ? !current : current)); setSubPanelOpen((current) => (isDefined(current) ? !current : current));

View File

@ -1,25 +1,25 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { useLocalStorage } from "usehooks-ts";
import { usePrefersDarkMode } from "./useMediaQuery"; import { usePrefersDarkMode } from "./useMediaQuery";
import { useStateWithLocalStorage } from "./useStateWithLocalStorage";
export const useDarkMode = ( export const useDarkMode = (
key: string, key: string,
initialValue: boolean | undefined initialValue: boolean
): [ ): [
boolean | undefined, boolean,
boolean | undefined, boolean,
React.Dispatch<React.SetStateAction<boolean | undefined>>, React.Dispatch<React.SetStateAction<boolean>>,
React.Dispatch<React.SetStateAction<boolean | undefined>> React.Dispatch<React.SetStateAction<boolean>>
] => { ] => {
const [darkMode, setDarkMode] = useStateWithLocalStorage(key, initialValue); const [darkMode, setDarkMode] = useLocalStorage(key, initialValue);
const prefersDarkMode = usePrefersDarkMode(); const prefersDarkMode = usePrefersDarkMode();
const [selectedThemeMode, setSelectedThemeMode] = useStateWithLocalStorage( const [selectedThemeMode, setSelectedThemeMode] = useLocalStorage(
"selectedThemeMode", "selectedThemeMode",
false false
); );
useEffect(() => { useEffect(() => {
if (selectedThemeMode === false) setDarkMode(prefersDarkMode); if (!selectedThemeMode) setDarkMode(prefersDarkMode);
}, [selectedThemeMode, prefersDarkMode, setDarkMode]); }, [selectedThemeMode, prefersDarkMode, setDarkMode]);
return [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode]; return [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode];

View File

@ -42,7 +42,7 @@ export const useSmartLanguage = <T>({
useEffect(() => { useEffect(() => {
setSelectedTranslationIndex( setSelectedTranslationIndex(
getPreferredLanguage( getPreferredLanguage(
preferredLanguages ?? [router.locale], preferredLanguages,
availableLocales availableLocales
) )
); );

View File

@ -1,31 +0,0 @@
import { useEffect, useState } from "react";
import { isDefined } from "helpers/others";
export const useStateWithLocalStorage = <T>(
key: string,
initialValue: T
): [T | undefined, React.Dispatch<React.SetStateAction<T | undefined>>] => {
const [value, setValue] = useState<T | undefined>(undefined);
const [, setFromLocaleStorage] = useState<boolean>(false);
useEffect(() => {
try {
const item = localStorage.getItem(key);
if (isDefined(item)) {
setValue(JSON.parse(item) as T);
} else {
setValue(initialValue);
}
setFromLocaleStorage(true);
} catch (error) {
console.warn(`Error reading localStorage key “${key}”:`, error);
setValue(initialValue);
}
}, [initialValue, key]);
useEffect(() => {
if (isDefined(value)) localStorage.setItem(key, JSON.stringify(value));
}, [value, key]);
return [value, setValue];
};

View File

@ -1,38 +0,0 @@
import { useMemo } from "react";
import { usePrefersDarkMode } from "./useMediaQuery";
import { useStateWithLocalStorage } from "./useStateWithLocalStorage";
export enum TernaryDarkMode {
Dark = "dark",
Auto = "auto",
Light = "light",
}
export const useTernaryDarkMode = (
key: string,
initialValue: TernaryDarkMode
): {
isDarkMode: boolean;
ternaryDarkMode: TernaryDarkMode | undefined;
setTernaryDarkMode: React.Dispatch<
React.SetStateAction<TernaryDarkMode | undefined>
>;
} => {
const [ternaryDarkMode, setTernaryDarkMode] = useStateWithLocalStorage(
key,
initialValue
);
const prefersDarkMode = usePrefersDarkMode();
const isDarkMode = useMemo(() => {
switch (ternaryDarkMode) {
case TernaryDarkMode.Light:
return false;
case TernaryDarkMode.Dark:
return true;
default:
return prefersDarkMode;
}
}, [prefersDarkMode, ternaryDarkMode]);
return { isDarkMode, ternaryDarkMode, setTernaryDarkMode };
};

View File

@ -120,7 +120,7 @@ const Library = ({
if (item.attributes.primary && !showPrimaryItems) return false; if (item.attributes.primary && !showPrimaryItems) return false;
if (!item.attributes.primary && !showSecondaryItems) return false; if (!item.attributes.primary && !showSecondaryItems) return false;
if (isDefined(filterUserStatus) && item.id && libraryItemUserStatus) { if (isDefined(filterUserStatus) && item.id) {
if (isUntangibleGroupItem(item.attributes.metadata?.[0])) { if (isUntangibleGroupItem(item.attributes.metadata?.[0])) {
return false; return false;
} }