Use localStorage hook
This commit is contained in:
		
							parent
							
								
									625f436163
								
							
						
					
					
						commit
						1bbf3b164a
					
				| @ -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,7 +159,6 @@ 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( | ||||||
| @ -171,7 +170,6 @@ export const AppLayout = ({ | |||||||
|         locale: preferredLanguages[0], |         locale: preferredLanguages[0], | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|     } |  | ||||||
|   }, [ |   }, [ | ||||||
|     preferredLanguages, |     preferredLanguages, | ||||||
|     router, |     router, | ||||||
| @ -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> | ||||||
|  | |||||||
| @ -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"), | ||||||
|  | |||||||
| @ -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) => { | ||||||
|  | |||||||
| @ -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,40 +162,39 @@ 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 | ||||||
|   ); |   ); | ||||||
|  | |||||||
| @ -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]; | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ export const useSmartLanguage = <T>({ | |||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     setSelectedTranslationIndex( |     setSelectedTranslationIndex( | ||||||
|       getPreferredLanguage( |       getPreferredLanguage( | ||||||
|         preferredLanguages ?? [router.locale], |         preferredLanguages, | ||||||
|         availableLocales |         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 && !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; | ||||||
|         } |         } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint