Use localStorage hook
This commit is contained in:
		
							parent
							
								
									625f436163
								
							
						
					
					
						commit
						1bbf3b164a
					
				| @ -109,7 +109,7 @@ export const AppLayout = ({ | ||||
|     onSwipedLeft: (SwipeEventData) => { | ||||
|       if (menuGestures) { | ||||
|         if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; | ||||
|         if (mainPanelOpen === true) { | ||||
|         if (mainPanelOpen) { | ||||
|           setMainPanelOpen(false); | ||||
|         } else if (isDefined(subPanel) && isDefined(contentPanel)) { | ||||
|           setSubPanelOpen(true); | ||||
| @ -119,7 +119,7 @@ export const AppLayout = ({ | ||||
|     onSwipedRight: (SwipeEventData) => { | ||||
|       if (menuGestures) { | ||||
|         if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; | ||||
|         if (subPanelOpen === true) { | ||||
|         if (subPanelOpen) { | ||||
|           setSubPanelOpen(false); | ||||
|         } else { | ||||
|           setMainPanelOpen(true); | ||||
| @ -135,7 +135,7 @@ export const AppLayout = ({ | ||||
| 
 | ||||
|   useLayoutEffect(() => { | ||||
|     document.getElementsByTagName("html")[0].style.fontSize = `${ | ||||
|       (fontSize ?? 1) * 100 | ||||
|       fontSize * 100 | ||||
|     }%`;
 | ||||
|   }, [fontSize]); | ||||
| 
 | ||||
| @ -159,7 +159,6 @@ export const AppLayout = ({ | ||||
|   }, [currencyOptions, currencySelect, setCurrency]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (preferredLanguages) { | ||||
|     if (preferredLanguages.length === 0) { | ||||
|       if (isDefinedAndNotEmpty(router.locale) && router.locales) { | ||||
|         setPreferredLanguages( | ||||
| @ -171,7 +170,6 @@ export const AppLayout = ({ | ||||
|         locale: preferredLanguages[0], | ||||
|       }); | ||||
|     } | ||||
|     } | ||||
|   }, [ | ||||
|     preferredLanguages, | ||||
|     router, | ||||
| @ -182,11 +180,11 @@ export const AppLayout = ({ | ||||
| 
 | ||||
|   const gridCol = useMemo(() => { | ||||
|     if (isDefined(subPanel)) { | ||||
|       if (mainPanelReduced === true) { | ||||
|       if (mainPanelReduced) { | ||||
|         return "grid-cols-[6rem_20rem_1fr]"; | ||||
|       } | ||||
|       return "grid-cols-[20rem_20rem_1fr]"; | ||||
|     } else if (mainPanelReduced === true) { | ||||
|     } else if (mainPanelReduced) { | ||||
|       return "grid-cols-[6rem_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]
 | ||||
|             mobile:z-10`,
 | ||||
|             cIf( | ||||
|               (mainPanelOpen === true || subPanelOpen === true) && isMobile, | ||||
|               (mainPanelOpen || subPanelOpen) && isMobile, | ||||
|               "[backdrop-filter:blur(2px)]", | ||||
|               "pointer-events-none touch-none" | ||||
|             ) | ||||
| @ -272,7 +270,7 @@ export const AppLayout = ({ | ||||
|             className={cJoin( | ||||
|               "absolute inset-0 bg-shade transition-opacity duration-500", | ||||
|               cIf( | ||||
|                 (mainPanelOpen === true || subPanelOpen === true) && isMobile, | ||||
|                 (mainPanelOpen || subPanelOpen) && isMobile, | ||||
|                 "opacity-60", | ||||
|                 "opacity-0" | ||||
|               ) | ||||
| @ -312,7 +310,7 @@ export const AppLayout = ({ | ||||
|               mobile:border-r-0 mobile:border-l-[1px] mobile:[grid-area:content]`,
 | ||||
|               turnSubIntoContent | ||||
|                 ? "mobile:w-full mobile:border-l-0" | ||||
|                 : subPanelOpen === true | ||||
|                 : subPanelOpen | ||||
|                 ? "" | ||||
|                 : "mobile:translate-x-[100vw]" | ||||
|             )} | ||||
| @ -328,7 +326,7 @@ export const AppLayout = ({ | ||||
|             transition-transform duration-300 [grid-area:main] [scrollbar-width:none] | ||||
|             webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%] mobile:justify-self-start | ||||
|             mobile:[grid-area:content]`,
 | ||||
|             cIf(mainPanelOpen === false, "mobile:-translate-x-full") | ||||
|             cIf(!mainPanelOpen, "mobile:-translate-x-full") | ||||
|           )} | ||||
|         > | ||||
|           <MainPanel langui={langui} /> | ||||
| @ -340,7 +338,7 @@ export const AppLayout = ({ | ||||
|           border-t-[1px] border-dotted border-black bg-light [grid-area:navbar] desktop:hidden" | ||||
|         > | ||||
|           <Ico | ||||
|             icon={mainPanelOpen === true ? Icon.Close : Icon.Menu} | ||||
|             icon={mainPanelOpen ? Icon.Close : Icon.Menu} | ||||
|             className="mt-[.1em] cursor-pointer !text-2xl" | ||||
|             onClick={() => { | ||||
|               toggleMainPanelOpen(); | ||||
| @ -365,7 +363,7 @@ export const AppLayout = ({ | ||||
|           </p> | ||||
|           {isDefined(subPanel) && !turnSubIntoContent && ( | ||||
|             <Ico | ||||
|               icon={subPanelOpen === true ? Icon.Close : subPanelIcon} | ||||
|               icon={subPanelOpen ? Icon.Close : subPanelIcon} | ||||
|               className="mt-[.1em] cursor-pointer !text-2xl" | ||||
|               onClick={() => { | ||||
|                 toggleSubPanelOpen(); | ||||
| @ -404,7 +402,7 @@ export const AppLayout = ({ | ||||
|         </Popup> | ||||
| 
 | ||||
|         <Popup | ||||
|           state={configPanelOpen ?? false} | ||||
|           state={configPanelOpen} | ||||
|           onClose={() => setConfigPanelOpen(false)} | ||||
|         > | ||||
|           <h2 className="text-2xl">{langui.settings}</h2> | ||||
| @ -416,7 +414,7 @@ export const AppLayout = ({ | ||||
|             {router.locales && ( | ||||
|               <div> | ||||
|                 <h3 className="text-xl">{langui.languages}</h3> | ||||
|                 {preferredLanguages && preferredLanguages.length > 0 && ( | ||||
|                 {preferredLanguages.length > 0 && ( | ||||
|                   <OrderableList | ||||
|                     items={ | ||||
|                       new Map( | ||||
| @ -453,14 +451,14 @@ export const AppLayout = ({ | ||||
|                         setDarkMode(false); | ||||
|                         setSelectedThemeMode(true); | ||||
|                       }, | ||||
|                       active: selectedThemeMode === true && darkMode === false, | ||||
|                       active: selectedThemeMode && darkMode, | ||||
|                       text: langui.light, | ||||
|                     }, | ||||
|                     { | ||||
|                       onClick: () => { | ||||
|                         setSelectedThemeMode(false); | ||||
|                       }, | ||||
|                       active: selectedThemeMode === false, | ||||
|                       active: selectedThemeMode, | ||||
|                       text: langui.auto, | ||||
|                     }, | ||||
|                     { | ||||
| @ -468,7 +466,7 @@ export const AppLayout = ({ | ||||
|                         setDarkMode(true); | ||||
|                         setSelectedThemeMode(true); | ||||
|                       }, | ||||
|                       active: selectedThemeMode === true && darkMode === true, | ||||
|                       active: selectedThemeMode && darkMode, | ||||
|                       text: langui.dark, | ||||
|                     }, | ||||
|                   ]} | ||||
| @ -492,20 +490,17 @@ export const AppLayout = ({ | ||||
|                 <ButtonGroup | ||||
|                   buttonsProps={[ | ||||
|                     { | ||||
|                       onClick: () => setFontSize((fontSize ?? 1) / 1.05), | ||||
|                       onClick: () => setFontSize(fontSize / 1.05), | ||||
|                       icon: Icon.TextDecrease, | ||||
|                     }, | ||||
|                     { | ||||
|                       onClick: () => setFontSize(1), | ||||
|                       text: `${((fontSize ?? 1) * 100).toLocaleString( | ||||
|                         undefined, | ||||
|                         { | ||||
|                       text: `${(fontSize * 100).toLocaleString(undefined, { | ||||
|                         maximumFractionDigits: 0, | ||||
|                         } | ||||
|                       )}%`,
 | ||||
|                       })}%`,
 | ||||
|                     }, | ||||
|                     { | ||||
|                       onClick: () => setFontSize((fontSize ?? 1) * 1.05), | ||||
|                       onClick: () => setFontSize(fontSize * 1.05), | ||||
|                       icon: Icon.TextIncrease, | ||||
|                     }, | ||||
|                   ]} | ||||
| @ -516,13 +511,13 @@ export const AppLayout = ({ | ||||
|                 <h3 className="text-xl">{langui.font}</h3> | ||||
|                 <div className="grid gap-2"> | ||||
|                   <Button | ||||
|                     active={dyslexic === false} | ||||
|                     active={!dyslexic} | ||||
|                     onClick={() => setDyslexic(false)} | ||||
|                     className="font-zenMaruGothic" | ||||
|                     text="Zen Maru Gothic" | ||||
|                   /> | ||||
|                   <Button | ||||
|                     active={dyslexic === true} | ||||
|                     active={dyslexic} | ||||
|                     onClick={() => setDyslexic(true)} | ||||
|                     className="font-openDyslexic" | ||||
|                     text="OpenDyslexic" | ||||
| @ -535,7 +530,7 @@ export const AppLayout = ({ | ||||
|                 <TextInput | ||||
|                   placeholder="<player>" | ||||
|                   className="w-48" | ||||
|                   value={playerName ?? ""} | ||||
|                   value={playerName} | ||||
|                   onChange={setPlayerName} | ||||
|                 /> | ||||
|               </div> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { Fragment, useCallback } from "react"; | ||||
| import { useBoolean } from "usehooks-ts"; | ||||
| import { Fragment, useCallback, useRef } from "react"; | ||||
| import { useBoolean, useOnClickOutside } from "usehooks-ts"; | ||||
| import { Ico, Icon } from "components/Ico"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| 
 | ||||
| @ -37,11 +37,12 @@ export const Select = ({ | ||||
|     if (optionCount > 1) toggleOpened(); | ||||
|   }, [options.length, value, toggleOpened]); | ||||
| 
 | ||||
|   const ref = useRef<HTMLDivElement>(null); | ||||
|   useOnClickOutside(ref, setClosed); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       onClickCapture={() => { | ||||
|         setClosed(); | ||||
|       }} | ||||
|       ref={ref} | ||||
|       className={cJoin( | ||||
|         "relative text-center transition-[filter]", | ||||
|         cIf(isOpened, "z-10 drop-shadow-shade-lg"), | ||||
|  | ||||
| @ -35,7 +35,7 @@ export const PreviewCardCTAs = ({ | ||||
|           <Button | ||||
|             icon={Icon.Favorite} | ||||
|             text={expand ? langui.want_it : undefined} | ||||
|             active={libraryItemUserStatus?.[id] === LibraryItemUserStatus.Want} | ||||
|             active={libraryItemUserStatus[id] === LibraryItemUserStatus.Want} | ||||
|             onClick={(event) => { | ||||
|               event.preventDefault(); | ||||
|               setLibraryItemUserStatus((current) => { | ||||
| @ -53,7 +53,7 @@ export const PreviewCardCTAs = ({ | ||||
|           <Button | ||||
|             icon={Icon.BackHand} | ||||
|             text={expand ? langui.have_it : undefined} | ||||
|             active={libraryItemUserStatus?.[id] === LibraryItemUserStatus.Have} | ||||
|             active={libraryItemUserStatus[id] === LibraryItemUserStatus.Have} | ||||
|             onClick={(event) => { | ||||
|               event.preventDefault(); | ||||
|               setLibraryItemUserStatus((current) => { | ||||
|  | ||||
| @ -1,64 +1,77 @@ | ||||
| import React, { ReactNode, useContext, useState } from "react"; | ||||
| import { useLocalStorage } from "usehooks-ts"; | ||||
| import { isDefined } from "helpers/others"; | ||||
| import { LibraryItemUserStatus, RequiredNonNullable } from "helpers/types"; | ||||
| import { useDarkMode } from "hooks/useDarkMode"; | ||||
| import { useStateWithLocalStorage } from "hooks/useStateWithLocalStorage"; | ||||
| 
 | ||||
| interface AppLayoutState { | ||||
|   subPanelOpen: boolean | undefined; | ||||
|   subPanelOpen: boolean; | ||||
|   toggleSubPanelOpen: () => void; | ||||
|   setSubPanelOpen: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["subPanelOpen"]> | ||||
|   >; | ||||
|   configPanelOpen: boolean | undefined; | ||||
| 
 | ||||
|   configPanelOpen: boolean; | ||||
|   toggleConfigPanelOpen: () => void; | ||||
|   setConfigPanelOpen: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["configPanelOpen"]> | ||||
|   >; | ||||
|   searchPanelOpen: boolean | undefined; | ||||
| 
 | ||||
|   searchPanelOpen: boolean; | ||||
|   toggleSearchPanelOpen: () => void; | ||||
|   setSearchPanelOpen: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["searchPanelOpen"]> | ||||
|   >; | ||||
|   mainPanelReduced: boolean | undefined; | ||||
| 
 | ||||
|   mainPanelReduced: boolean; | ||||
|   toggleMainPanelReduced: () => void; | ||||
|   setMainPanelReduced: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["mainPanelReduced"]> | ||||
|   >; | ||||
|   mainPanelOpen: boolean | undefined; | ||||
| 
 | ||||
|   mainPanelOpen: boolean; | ||||
|   toggleMainPanelOpen: () => void; | ||||
|   setMainPanelOpen: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["mainPanelOpen"]> | ||||
|   >; | ||||
|   darkMode: boolean | undefined; | ||||
| 
 | ||||
|   darkMode: boolean; | ||||
|   toggleDarkMode: () => void; | ||||
|   setDarkMode: React.Dispatch<React.SetStateAction<AppLayoutState["darkMode"]>>; | ||||
|   selectedThemeMode: boolean | undefined; | ||||
| 
 | ||||
|   selectedThemeMode: boolean; | ||||
|   toggleSelectedThemeMode: () => void; | ||||
|   setSelectedThemeMode: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["selectedThemeMode"]> | ||||
|   >; | ||||
|   fontSize: number | undefined; | ||||
| 
 | ||||
|   fontSize: number; | ||||
|   setFontSize: React.Dispatch<React.SetStateAction<AppLayoutState["fontSize"]>>; | ||||
|   dyslexic: boolean | undefined; | ||||
| 
 | ||||
|   dyslexic: boolean; | ||||
|   toggleDyslexic: () => void; | ||||
|   setDyslexic: React.Dispatch<React.SetStateAction<AppLayoutState["dyslexic"]>>; | ||||
|   currency: string | undefined; | ||||
| 
 | ||||
|   currency: string; | ||||
|   setCurrency: React.Dispatch<React.SetStateAction<AppLayoutState["currency"]>>; | ||||
|   playerName: string | undefined; | ||||
| 
 | ||||
|   playerName: string; | ||||
|   setPlayerName: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["playerName"]> | ||||
|   >; | ||||
|   preferredLanguages: string[] | undefined; | ||||
| 
 | ||||
|   preferredLanguages: string[]; | ||||
|   setPreferredLanguages: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["preferredLanguages"]> | ||||
|   >; | ||||
| 
 | ||||
|   menuGestures: boolean; | ||||
|   toggleMenuGestures: () => void; | ||||
|   setMenuGestures: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["menuGestures"]> | ||||
|   >; | ||||
|   libraryItemUserStatus: Record<string, LibraryItemUserStatus> | undefined; | ||||
| 
 | ||||
|   libraryItemUserStatus: Record<string, LibraryItemUserStatus>; | ||||
|   setLibraryItemUserStatus: React.Dispatch< | ||||
|     React.SetStateAction<AppLayoutState["libraryItemUserStatus"]> | ||||
|   >; | ||||
| @ -68,38 +81,51 @@ const initialState: RequiredNonNullable<AppLayoutState> = { | ||||
|   subPanelOpen: false, | ||||
|   toggleSubPanelOpen: () => null, | ||||
|   setSubPanelOpen: () => null, | ||||
| 
 | ||||
|   configPanelOpen: false, | ||||
|   setConfigPanelOpen: () => null, | ||||
|   toggleConfigPanelOpen: () => null, | ||||
| 
 | ||||
|   searchPanelOpen: false, | ||||
|   setSearchPanelOpen: () => null, | ||||
|   toggleSearchPanelOpen: () => null, | ||||
| 
 | ||||
|   mainPanelReduced: false, | ||||
|   setMainPanelReduced: () => null, | ||||
|   toggleMainPanelReduced: () => null, | ||||
| 
 | ||||
|   mainPanelOpen: false, | ||||
|   toggleMainPanelOpen: () => null, | ||||
|   setMainPanelOpen: () => null, | ||||
| 
 | ||||
|   darkMode: false, | ||||
|   toggleDarkMode: () => null, | ||||
|   setDarkMode: () => null, | ||||
| 
 | ||||
|   selectedThemeMode: false, | ||||
|   toggleSelectedThemeMode: () => null, | ||||
|   setSelectedThemeMode: () => null, | ||||
| 
 | ||||
|   fontSize: 1, | ||||
|   setFontSize: () => null, | ||||
| 
 | ||||
|   dyslexic: false, | ||||
|   toggleDyslexic: () => null, | ||||
|   setDyslexic: () => null, | ||||
| 
 | ||||
|   currency: "USD", | ||||
|   setCurrency: () => null, | ||||
| 
 | ||||
|   playerName: "", | ||||
|   setPlayerName: () => null, | ||||
| 
 | ||||
|   preferredLanguages: [], | ||||
|   setPreferredLanguages: () => null, | ||||
| 
 | ||||
|   menuGestures: true, | ||||
|   toggleMenuGestures: () => null, | ||||
|   setMenuGestures: () => null, | ||||
| 
 | ||||
|   libraryItemUserStatus: {}, | ||||
|   setLibraryItemUserStatus: () => null, | ||||
| }; | ||||
| @ -113,22 +139,22 @@ interface Props { | ||||
| } | ||||
| 
 | ||||
| export const AppContextProvider = (props: Props): JSX.Element => { | ||||
|   const [subPanelOpen, setSubPanelOpen] = useStateWithLocalStorage( | ||||
|   const [subPanelOpen, setSubPanelOpen] = useLocalStorage( | ||||
|     "subPanelOpen", | ||||
|     initialState.subPanelOpen | ||||
|   ); | ||||
| 
 | ||||
|   const [configPanelOpen, setConfigPanelOpen] = useStateWithLocalStorage( | ||||
|   const [configPanelOpen, setConfigPanelOpen] = useLocalStorage( | ||||
|     "configPanelOpen", | ||||
|     initialState.configPanelOpen | ||||
|   ); | ||||
| 
 | ||||
|   const [mainPanelReduced, setMainPanelReduced] = useStateWithLocalStorage( | ||||
|   const [mainPanelReduced, setMainPanelReduced] = useLocalStorage( | ||||
|     "mainPanelReduced", | ||||
|     initialState.mainPanelReduced | ||||
|   ); | ||||
| 
 | ||||
|   const [mainPanelOpen, setMainPanelOpen] = useStateWithLocalStorage( | ||||
|   const [mainPanelOpen, setMainPanelOpen] = useLocalStorage( | ||||
|     "mainPanelOpen", | ||||
|     initialState.mainPanelOpen | ||||
|   ); | ||||
| @ -136,40 +162,39 @@ export const AppContextProvider = (props: Props): JSX.Element => { | ||||
|   const [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode] = | ||||
|     useDarkMode("darkMode", initialState.darkMode); | ||||
| 
 | ||||
|   const [fontSize, setFontSize] = useStateWithLocalStorage( | ||||
|   const [fontSize, setFontSize] = useLocalStorage( | ||||
|     "fontSize", | ||||
|     initialState.fontSize | ||||
|   ); | ||||
| 
 | ||||
|   const [dyslexic, setDyslexic] = useStateWithLocalStorage( | ||||
|   const [dyslexic, setDyslexic] = useLocalStorage( | ||||
|     "dyslexic", | ||||
|     initialState.dyslexic | ||||
|   ); | ||||
| 
 | ||||
|   const [currency, setCurrency] = useStateWithLocalStorage( | ||||
|   const [currency, setCurrency] = useLocalStorage( | ||||
|     "currency", | ||||
|     initialState.currency | ||||
|   ); | ||||
| 
 | ||||
|   const [playerName, setPlayerName] = useStateWithLocalStorage( | ||||
|   const [playerName, setPlayerName] = useLocalStorage( | ||||
|     "playerName", | ||||
|     initialState.playerName | ||||
|   ); | ||||
| 
 | ||||
|   const [preferredLanguages, setPreferredLanguages] = useStateWithLocalStorage( | ||||
|   const [preferredLanguages, setPreferredLanguages] = useLocalStorage( | ||||
|     "preferredLanguages", | ||||
|     initialState.preferredLanguages | ||||
|   ); | ||||
| 
 | ||||
|   const [menuGestures, setMenuGestures] = useState(false); | ||||
| 
 | ||||
|   const [searchPanelOpen, setSearchPanelOpen] = useStateWithLocalStorage( | ||||
|   const [searchPanelOpen, setSearchPanelOpen] = useLocalStorage( | ||||
|     "searchPanelOpen", | ||||
|     initialState.searchPanelOpen | ||||
|   ); | ||||
| 
 | ||||
|   const [libraryItemUserStatus, setLibraryItemUserStatus] = | ||||
|     useStateWithLocalStorage( | ||||
|   const [libraryItemUserStatus, setLibraryItemUserStatus] = useLocalStorage( | ||||
|     "libraryItemUserStatus", | ||||
|     initialState.libraryItemUserStatus | ||||
|   ); | ||||
|  | ||||
| @ -1,25 +1,25 @@ | ||||
| import { useEffect } from "react"; | ||||
| import { useLocalStorage } from "usehooks-ts"; | ||||
| import { usePrefersDarkMode } from "./useMediaQuery"; | ||||
| import { useStateWithLocalStorage } from "./useStateWithLocalStorage"; | ||||
| 
 | ||||
| export const useDarkMode = ( | ||||
|   key: string, | ||||
|   initialValue: boolean | undefined | ||||
|   initialValue: boolean | ||||
| ): [ | ||||
|   boolean | undefined, | ||||
|   boolean | undefined, | ||||
|   React.Dispatch<React.SetStateAction<boolean | undefined>>, | ||||
|   React.Dispatch<React.SetStateAction<boolean | undefined>> | ||||
|   boolean, | ||||
|   boolean, | ||||
|   React.Dispatch<React.SetStateAction<boolean>>, | ||||
|   React.Dispatch<React.SetStateAction<boolean>> | ||||
| ] => { | ||||
|   const [darkMode, setDarkMode] = useStateWithLocalStorage(key, initialValue); | ||||
|   const [darkMode, setDarkMode] = useLocalStorage(key, initialValue); | ||||
|   const prefersDarkMode = usePrefersDarkMode(); | ||||
|   const [selectedThemeMode, setSelectedThemeMode] = useStateWithLocalStorage( | ||||
|   const [selectedThemeMode, setSelectedThemeMode] = useLocalStorage( | ||||
|     "selectedThemeMode", | ||||
|     false | ||||
|   ); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (selectedThemeMode === false) setDarkMode(prefersDarkMode); | ||||
|     if (!selectedThemeMode) setDarkMode(prefersDarkMode); | ||||
|   }, [selectedThemeMode, prefersDarkMode, setDarkMode]); | ||||
| 
 | ||||
|   return [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode]; | ||||
|  | ||||
| @ -42,7 +42,7 @@ export const useSmartLanguage = <T>({ | ||||
|   useEffect(() => { | ||||
|     setSelectedTranslationIndex( | ||||
|       getPreferredLanguage( | ||||
|         preferredLanguages ?? [router.locale], | ||||
|         preferredLanguages, | ||||
|         availableLocales | ||||
|       ) | ||||
|     ); | ||||
|  | ||||
| @ -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]; | ||||
| }; | ||||
| @ -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 }; | ||||
| }; | ||||
| @ -120,7 +120,7 @@ const Library = ({ | ||||
|       if (item.attributes.primary && !showPrimaryItems) 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])) { | ||||
|           return false; | ||||
|         } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint