Added foundation for a minimizable navbar
This commit is contained in:
		
							parent
							
								
									290fa80b31
								
							
						
					
					
						commit
						bcb9e5fd7d
					
				| @ -6,6 +6,7 @@ import { useSwipeable } from "react-swipeable"; | ||||
| import { useRouter } from "next/router"; | ||||
| import Button from "components/Button"; | ||||
| import { prettyLanguage } from "queries/helpers"; | ||||
| import { useMediaDesktop, useMediaMobile } from "hooks/useMediaQuery"; | ||||
| 
 | ||||
| type AppLayoutProps = { | ||||
|   subPanel?: React.ReactNode; | ||||
| @ -22,6 +23,9 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|   const [mainPanelOpen, setMainPanelOpen] = useState(false); | ||||
|   const [subPanelOpen, setSubPanelOpen] = useState(false); | ||||
|   const [languagePanelOpen, setLanguagePanelOpen] = useState(false); | ||||
|   const [mainPanelReduced, setMainPanelReduced] = useState(false); | ||||
|   const isMobile = useMediaMobile(); | ||||
|   const isDesktop = useMediaDesktop(); | ||||
|   const sensibilitySwipe = 1.1; | ||||
| 
 | ||||
|   const handlers = useSwipeable({ | ||||
| @ -43,18 +47,22 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|     }, | ||||
|   }); | ||||
| 
 | ||||
|   const mainPanelClass = | ||||
|     "fixed desktop:left-0 desktop:top-0 desktop:bottom-0 desktop:w-[20rem]"; | ||||
|   const subPanelClass = | ||||
|     "fixed desktop:left-[20rem] desktop:top-0 desktop:bottom-0 desktop:w-[20rem]"; | ||||
|   const mainPanelClass = `fixed desktop:left-0 desktop:top-0 desktop:bottom-0 transition-all ${ | ||||
|     mainPanelReduced ? "desktop:w-[8rem]" : "desktop:w-[20rem]" | ||||
|   }`;
 | ||||
|   const subPanelClass = `fixed desktop:top-0 desktop:bottom-0 desktop:w-[20rem] transition-all ${ | ||||
|     mainPanelReduced ? " desktop:left-[8rem]" : "desktop:left-[20rem]" | ||||
|   }`;
 | ||||
|   let contentPanelClass = ""; | ||||
|   let turnSubIntoContent = false; | ||||
|   if (props.subPanel && props.contentPanel) { | ||||
|     contentPanelClass = | ||||
|       "fixed desktop:left-[40rem] desktop:top-0 desktop:bottom-0 desktop:right-0"; | ||||
|     contentPanelClass = `fixed desktop:top-0 desktop:bottom-0 desktop:right-0 transition-all ${ | ||||
|       mainPanelReduced ? "desktop:left-[28rem]" : "desktop:left-[40rem]" | ||||
|     }`;
 | ||||
|   } else if (props.contentPanel) { | ||||
|     contentPanelClass = | ||||
|       "fixed desktop:left-[20rem] desktop:top-0 desktop:bottom-0 desktop:right-0"; | ||||
|     contentPanelClass = `fixed desktop:top-0 desktop:bottom-0 desktop:right-0 transition-all ${ | ||||
|       mainPanelReduced ? "desktop:left-[8rem]" : "desktop:left-[20rem]" | ||||
|     }`;
 | ||||
|   } else if (props.subPanel) { | ||||
|     turnSubIntoContent = true; | ||||
|   } | ||||
| @ -114,7 +122,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|         className={`fixed bg-dark inset-0 transition-opacity duration-500 
 | ||||
|         ${turnSubIntoContent ? "z-10" : ""} | ||||
|         ${ | ||||
|           mainPanelOpen || subPanelOpen | ||||
|           (mainPanelOpen || subPanelOpen) && isMobile | ||||
|             ? "opacity-50" | ||||
|             : "opacity-0 pointer-events-none touch-none" | ||||
|         }`}
 | ||||
| @ -150,9 +158,22 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { | ||||
|         <MainPanel | ||||
|           langui={props.langui} | ||||
|           setLanguagePanelOpen={setLanguagePanelOpen} | ||||
|           reduced={mainPanelReduced && isDesktop} | ||||
|         /> | ||||
|       </div> | ||||
| 
 | ||||
|       {/* Main panel minimize button*/} | ||||
|       <div | ||||
|         className={`mobile:hidden translate-x-0 fixed top-1/2 z-20 ${ | ||||
|           mainPanelReduced ? "left-[6.65rem]" : "left-[18.65rem]" | ||||
|         }`}
 | ||||
|         onClick={() => setMainPanelReduced(!mainPanelReduced)} | ||||
|       > | ||||
|         <Button className="material-icons bg-light !px-2"> | ||||
|           {mainPanelReduced ? "chevron_right" : "chevron_left"} | ||||
|         </Button> | ||||
|       </div> | ||||
| 
 | ||||
|       {/* Language selection background */} | ||||
|       <div | ||||
|         className={`fixed bg-dark inset-0 transition-all duration-500 z-20 grid place-content-center ${ | ||||
|  | ||||
| @ -7,6 +7,7 @@ type NavOptionProps = { | ||||
|   title: string; | ||||
|   subtitle?: string; | ||||
|   border?: boolean; | ||||
|   reduced?: boolean; | ||||
| }; | ||||
| 
 | ||||
| export default function NavOption(props: NavOptionProps): JSX.Element { | ||||
| @ -20,15 +21,25 @@ export default function NavOption(props: NavOptionProps): JSX.Element { | ||||
|   } ${isActive ? divActive : ""}`;
 | ||||
| 
 | ||||
|   if (props.icon) { | ||||
|     return ( | ||||
|       <Link href={props.url} passHref> | ||||
|         <div className={`grid grid-cols-[auto_1fr] text-left ${divCommon}`}> | ||||
|           <span className="material-icons mt-[.1em]">{props.icon}</span> | ||||
|           <h3 className="text-2xl">{props.title}</h3> | ||||
|           {props.subtitle && <p className="col-start-2">{props.subtitle}</p>} | ||||
|         </div> | ||||
|       </Link> | ||||
|     ); | ||||
|     if (props.reduced) { | ||||
|       return ( | ||||
|         <Link href={props.url} passHref> | ||||
|           <div className={`grid ${divCommon}`}> | ||||
|             <span className="place-self-center material-icons mt-[.1em]">{props.icon}</span> | ||||
|           </div> | ||||
|         </Link> | ||||
|       ); | ||||
|     } else { | ||||
|       return ( | ||||
|         <Link href={props.url} passHref> | ||||
|           <div className={`grid grid-cols-[auto_1fr] text-left ${divCommon}`}> | ||||
|             <span className="material-icons mt-[.1em]">{props.icon}</span> | ||||
|             <h3 className="text-2xl">{props.title}</h3> | ||||
|             {props.subtitle && <p className="col-start-2">{props.subtitle}</p>} | ||||
|           </div> | ||||
|         </Link> | ||||
|       ); | ||||
|     } | ||||
|   } else { | ||||
|     return ( | ||||
|       <Link href={props.url} passHref> | ||||
|  | ||||
| @ -10,38 +10,64 @@ import Markdown from "markdown-to-jsx"; | ||||
| type MainPanelProps = { | ||||
|   langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]; | ||||
|   setLanguagePanelOpen: Function; | ||||
|   reduced: boolean; | ||||
| }; | ||||
| 
 | ||||
| export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|   const langui = props.langui; | ||||
|   const router = useRouter(); | ||||
|   const reduced = props.reduced; | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       id="mainPanel" | ||||
|       className="flex flex-col justify-center content-start p-8 gap-y-2 justify-items-center text-center" | ||||
|     > | ||||
|       <div className=""> | ||||
|         <div className="grid place-items-center"> | ||||
|       {reduced ? ( | ||||
|         <div className="grid place-items-center gap-4"> | ||||
|           <Link href="/" passHref> | ||||
|             <div className="w-1/2 cursor-pointer transition-[filter] hover:colorize-dark"> | ||||
|             <div className="w-8 cursor-pointer transition-[filter] hover:colorize-dark"> | ||||
|               <SVG | ||||
|                 src={"/icons/accords.svg"} | ||||
|                 alt={"Logo of Accord's Library"} | ||||
|               /> | ||||
|             </div> | ||||
|           </Link> | ||||
|           <div className="relative mt-5" onClick={() => props.setLanguagePanelOpen(true)}> | ||||
|             {router.locale ? ( | ||||
|               <Button className="absolute right-0 top-[-1.3em] text-xs !py-0.5 !px-2.5"> | ||||
|                 {router.locale.toUpperCase()} | ||||
|               </Button> | ||||
|             ) : ( | ||||
|               "" | ||||
|             )} | ||||
|             <h2 className="text-3xl">Accord’s Library</h2> | ||||
|           {router.locale ? ( | ||||
|             <div onClick={() => props.setLanguagePanelOpen(true)}> | ||||
|               <Button className="text-xs">{router.locale.toUpperCase()}</Button> | ||||
|             </div> | ||||
|           ) : ( | ||||
|             "" | ||||
|           )} | ||||
|         </div> | ||||
|       ) : ( | ||||
|         <div> | ||||
|           <div className="grid place-items-center"> | ||||
|             <Link href="/" passHref> | ||||
|               <div className="w-1/2 cursor-pointer transition-[filter] hover:colorize-dark"> | ||||
|                 <SVG | ||||
|                   src={"/icons/accords.svg"} | ||||
|                   alt={"Logo of Accord's Library"} | ||||
|                 /> | ||||
|               </div> | ||||
|             </Link> | ||||
|             <div | ||||
|               className="relative mt-5" | ||||
|               onClick={() => props.setLanguagePanelOpen(true)} | ||||
|             > | ||||
|               {router.locale ? ( | ||||
|                 <Button className="absolute right-0 top-[-1.3em] text-xs !py-0.5 !px-2.5"> | ||||
|                   {router.locale.toUpperCase()} | ||||
|                 </Button> | ||||
|               ) : ( | ||||
|                 "" | ||||
|               )} | ||||
|               <h2 className="text-3xl">Accord’s Library</h2> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       )} | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
| @ -50,6 +76,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         icon="library_books" | ||||
|         title={langui.main_library} | ||||
|         subtitle={langui.main_library_description} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
| @ -57,6 +84,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         icon="travel_explore" | ||||
|         title={langui.main_wiki} | ||||
|         subtitle={langui.main_wiki_description} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
| @ -64,27 +92,49 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { | ||||
|         icon="watch_later" | ||||
|         title={langui.main_chronicles} | ||||
|         subtitle={langui.main_chronicles_description} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
|       <NavOption url="/news" icon="feed" title={langui.main_news} /> | ||||
|       <NavOption url="/merch" icon="store" title={langui.main_merch} /> | ||||
|       <NavOption | ||||
|         url="/news" | ||||
|         icon="feed" | ||||
|         title={langui.main_news} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/merch" | ||||
|         icon="store" | ||||
|         title={langui.main_merch} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/gallery" | ||||
|         icon="collections" | ||||
|         title={langui.main_gallery} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/archives" | ||||
|         icon="inventory" | ||||
|         title={langui.main_archives} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
|       <NavOption url="/about-us" icon="info" title={langui.main_about_us} /> | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
|       <NavOption | ||||
|         url="/about-us" | ||||
|         icon="info" | ||||
|         title={langui.main_about_us} | ||||
|         reduced={reduced} | ||||
|       /> | ||||
| 
 | ||||
|       <div className="text-center"> | ||||
|       {reduced ? "" : <HorizontalLine />} | ||||
| 
 | ||||
|       <div className={`text-center ${reduced ? "hidden" : ""}`}> | ||||
|         <p> | ||||
|           {langui.main_licensing ? ( | ||||
|             <Markdown>{langui.main_licensing}</Markdown> | ||||
|  | ||||
							
								
								
									
										47
									
								
								src/hooks/useMediaQuery.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/hooks/useMediaQuery.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| import { useEffect, useState } from "react"; | ||||
| 
 | ||||
| export default function useMediaQuery(query: string): boolean { | ||||
|   const getMatches = (query: string): boolean => { | ||||
|     // Prevents SSR issues
 | ||||
|     if (typeof window !== "undefined") { | ||||
|       return window.matchMedia(query).matches; | ||||
|     } | ||||
|     return false; | ||||
|   }; | ||||
| 
 | ||||
|   const [matches, setMatches] = useState<boolean>(getMatches(query)); | ||||
| 
 | ||||
|   function handleChange() { | ||||
|     setMatches(getMatches(query)); | ||||
|   } | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const matchMedia = window.matchMedia(query); | ||||
| 
 | ||||
|     // Triggered at the first client-side load and if query changes
 | ||||
|     handleChange(); | ||||
| 
 | ||||
|     // Listen matchMedia
 | ||||
|     matchMedia.addEventListener("change", handleChange); | ||||
| 
 | ||||
|     return () => { | ||||
|       matchMedia.removeEventListener("change", handleChange); | ||||
|     }; | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||||
|   }, [query]); | ||||
| 
 | ||||
|   return matches; | ||||
| } | ||||
| 
 | ||||
| export function useMediaThin() { | ||||
|     return useMediaQuery("(max-width: 50ch)"); | ||||
| } | ||||
| 
 | ||||
| export function useMediaMobile() { | ||||
|     return useMediaQuery("(max-width: 150ch)"); | ||||
| } | ||||
| 
 | ||||
| export function useMediaDesktop() { | ||||
|     return useMediaQuery("(min-width: 150ch)"); | ||||
| } | ||||
| 
 | ||||
| @ -56,6 +56,18 @@ | ||||
| 
 | ||||
|   .prose { | ||||
|     --tw-prose-bullets: theme("colors.dark") !important; | ||||
|     --tw-prose-quote-borders: theme("colors.dark") !important; | ||||
|   } | ||||
| 
 | ||||
|   .prose footer { | ||||
|     @apply border-t-[3px] border-dotted pt-6; | ||||
|   } | ||||
| 
 | ||||
|   .prose footer > div { | ||||
|     @apply my-2 px-6 py-4 rounded-xl; | ||||
|   } | ||||
| 
 | ||||
|   .prose footer > div:target { | ||||
|     @apply bg-mid shadow-inner-sm shadow-dark; | ||||
|   } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint