Added foundation for a minimizable navbar

This commit is contained in:
DrMint 2022-02-20 13:49:44 +01:00
parent 290fa80b31
commit bcb9e5fd7d
5 changed files with 177 additions and 36 deletions

View File

@ -6,6 +6,7 @@ import { useSwipeable } from "react-swipeable";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import Button from "components/Button"; import Button from "components/Button";
import { prettyLanguage } from "queries/helpers"; import { prettyLanguage } from "queries/helpers";
import { useMediaDesktop, useMediaMobile } from "hooks/useMediaQuery";
type AppLayoutProps = { type AppLayoutProps = {
subPanel?: React.ReactNode; subPanel?: React.ReactNode;
@ -22,6 +23,9 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
const [mainPanelOpen, setMainPanelOpen] = useState(false); const [mainPanelOpen, setMainPanelOpen] = useState(false);
const [subPanelOpen, setSubPanelOpen] = useState(false); const [subPanelOpen, setSubPanelOpen] = useState(false);
const [languagePanelOpen, setLanguagePanelOpen] = useState(false); const [languagePanelOpen, setLanguagePanelOpen] = useState(false);
const [mainPanelReduced, setMainPanelReduced] = useState(false);
const isMobile = useMediaMobile();
const isDesktop = useMediaDesktop();
const sensibilitySwipe = 1.1; const sensibilitySwipe = 1.1;
const handlers = useSwipeable({ const handlers = useSwipeable({
@ -43,18 +47,22 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
}, },
}); });
const mainPanelClass = const mainPanelClass = `fixed desktop:left-0 desktop:top-0 desktop:bottom-0 transition-all ${
"fixed desktop:left-0 desktop:top-0 desktop:bottom-0 desktop:w-[20rem]"; mainPanelReduced ? "desktop:w-[8rem]" : "desktop:w-[20rem]"
const subPanelClass = }`;
"fixed desktop:left-[20rem] desktop:top-0 desktop:bottom-0 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 contentPanelClass = "";
let turnSubIntoContent = false; let turnSubIntoContent = false;
if (props.subPanel && props.contentPanel) { if (props.subPanel && props.contentPanel) {
contentPanelClass = contentPanelClass = `fixed desktop:top-0 desktop:bottom-0 desktop:right-0 transition-all ${
"fixed desktop:left-[40rem] desktop:top-0 desktop:bottom-0 desktop:right-0"; mainPanelReduced ? "desktop:left-[28rem]" : "desktop:left-[40rem]"
}`;
} else if (props.contentPanel) { } else if (props.contentPanel) {
contentPanelClass = contentPanelClass = `fixed desktop:top-0 desktop:bottom-0 desktop:right-0 transition-all ${
"fixed desktop:left-[20rem] desktop:top-0 desktop:bottom-0 desktop:right-0"; mainPanelReduced ? "desktop:left-[8rem]" : "desktop:left-[20rem]"
}`;
} else if (props.subPanel) { } else if (props.subPanel) {
turnSubIntoContent = true; turnSubIntoContent = true;
} }
@ -114,7 +122,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
className={`fixed bg-dark inset-0 transition-opacity duration-500 className={`fixed bg-dark inset-0 transition-opacity duration-500
${turnSubIntoContent ? "z-10" : ""} ${turnSubIntoContent ? "z-10" : ""}
${ ${
mainPanelOpen || subPanelOpen (mainPanelOpen || subPanelOpen) && isMobile
? "opacity-50" ? "opacity-50"
: "opacity-0 pointer-events-none touch-none" : "opacity-0 pointer-events-none touch-none"
}`} }`}
@ -150,9 +158,22 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
<MainPanel <MainPanel
langui={props.langui} langui={props.langui}
setLanguagePanelOpen={setLanguagePanelOpen} setLanguagePanelOpen={setLanguagePanelOpen}
reduced={mainPanelReduced && isDesktop}
/> />
</div> </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 */} {/* Language selection background */}
<div <div
className={`fixed bg-dark inset-0 transition-all duration-500 z-20 grid place-content-center ${ className={`fixed bg-dark inset-0 transition-all duration-500 z-20 grid place-content-center ${

View File

@ -7,6 +7,7 @@ type NavOptionProps = {
title: string; title: string;
subtitle?: string; subtitle?: string;
border?: boolean; border?: boolean;
reduced?: boolean;
}; };
export default function NavOption(props: NavOptionProps): JSX.Element { export default function NavOption(props: NavOptionProps): JSX.Element {
@ -20,6 +21,15 @@ export default function NavOption(props: NavOptionProps): JSX.Element {
} ${isActive ? divActive : ""}`; } ${isActive ? divActive : ""}`;
if (props.icon) { if (props.icon) {
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 ( return (
<Link href={props.url} passHref> <Link href={props.url} passHref>
<div className={`grid grid-cols-[auto_1fr] text-left ${divCommon}`}> <div className={`grid grid-cols-[auto_1fr] text-left ${divCommon}`}>
@ -29,6 +39,7 @@ export default function NavOption(props: NavOptionProps): JSX.Element {
</div> </div>
</Link> </Link>
); );
}
} else { } else {
return ( return (
<Link href={props.url} passHref> <Link href={props.url} passHref>

View File

@ -10,17 +10,39 @@ import Markdown from "markdown-to-jsx";
type MainPanelProps = { type MainPanelProps = {
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]; langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
setLanguagePanelOpen: Function; setLanguagePanelOpen: Function;
reduced: boolean;
}; };
export default function MainPanel(props: MainPanelProps): JSX.Element { export default function MainPanel(props: MainPanelProps): JSX.Element {
const langui = props.langui; const langui = props.langui;
const router = useRouter(); const router = useRouter();
const reduced = props.reduced;
return ( return (
<div <div
id="mainPanel" id="mainPanel"
className="flex flex-col justify-center content-start p-8 gap-y-2 justify-items-center text-center" className="flex flex-col justify-center content-start p-8 gap-y-2 justify-items-center text-center"
> >
<div className=""> {reduced ? (
<div className="grid place-items-center gap-4">
<Link href="/" passHref>
<div className="w-8 cursor-pointer transition-[filter] hover:colorize-dark">
<SVG
src={"/icons/accords.svg"}
alt={"Logo of Accord's Library"}
/>
</div>
</Link>
{router.locale ? (
<div onClick={() => props.setLanguagePanelOpen(true)}>
<Button className="text-xs">{router.locale.toUpperCase()}</Button>
</div>
) : (
""
)}
</div>
) : (
<div>
<div className="grid place-items-center"> <div className="grid place-items-center">
<Link href="/" passHref> <Link href="/" passHref>
<div className="w-1/2 cursor-pointer transition-[filter] hover:colorize-dark"> <div className="w-1/2 cursor-pointer transition-[filter] hover:colorize-dark">
@ -30,7 +52,10 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
/> />
</div> </div>
</Link> </Link>
<div className="relative mt-5" onClick={() => props.setLanguagePanelOpen(true)}> <div
className="relative mt-5"
onClick={() => props.setLanguagePanelOpen(true)}
>
{router.locale ? ( {router.locale ? (
<Button className="absolute right-0 top-[-1.3em] text-xs !py-0.5 !px-2.5"> <Button className="absolute right-0 top-[-1.3em] text-xs !py-0.5 !px-2.5">
{router.locale.toUpperCase()} {router.locale.toUpperCase()}
@ -42,6 +67,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
</div> </div>
</div> </div>
</div> </div>
)}
<HorizontalLine /> <HorizontalLine />
@ -50,6 +76,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
icon="library_books" icon="library_books"
title={langui.main_library} title={langui.main_library}
subtitle={langui.main_library_description} subtitle={langui.main_library_description}
reduced={reduced}
/> />
<NavOption <NavOption
@ -57,6 +84,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
icon="travel_explore" icon="travel_explore"
title={langui.main_wiki} title={langui.main_wiki}
subtitle={langui.main_wiki_description} subtitle={langui.main_wiki_description}
reduced={reduced}
/> />
<NavOption <NavOption
@ -64,27 +92,49 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
icon="watch_later" icon="watch_later"
title={langui.main_chronicles} title={langui.main_chronicles}
subtitle={langui.main_chronicles_description} subtitle={langui.main_chronicles_description}
reduced={reduced}
/> />
<HorizontalLine /> <HorizontalLine />
<NavOption url="/news" icon="feed" title={langui.main_news} /> <NavOption
<NavOption url="/merch" icon="store" title={langui.main_merch} /> url="/news"
icon="feed"
title={langui.main_news}
reduced={reduced}
/>
<NavOption
url="/merch"
icon="store"
title={langui.main_merch}
reduced={reduced}
/>
<NavOption <NavOption
url="/gallery" url="/gallery"
icon="collections" icon="collections"
title={langui.main_gallery} title={langui.main_gallery}
reduced={reduced}
/> />
<NavOption <NavOption
url="/archives" url="/archives"
icon="inventory" icon="inventory"
title={langui.main_archives} 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> <p>
{langui.main_licensing ? ( {langui.main_licensing ? (
<Markdown>{langui.main_licensing}</Markdown> <Markdown>{langui.main_licensing}</Markdown>

View 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)");
}

View File

@ -56,6 +56,18 @@
.prose { .prose {
--tw-prose-bullets: theme("colors.dark") !important; --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;
}
} }