diff --git a/app/public-area/components/header.tsx b/app/public-area/components/header.tsx index d06d50f..1e8d83a 100644 --- a/app/public-area/components/header.tsx +++ b/app/public-area/components/header.tsx @@ -1,23 +1,188 @@ -import { Link } from "blitz"; +import { Fragment, useState, useRef, useEffect } from "react"; +import type { LinkProps } from "next/link"; +import { Link, Routes } from "blitz"; +import { Dialog, Transition } from "@headlessui/react"; +import { XIcon } from "@heroicons/react/outline"; function Header() { return ( - {/* Site branding */} - {/* Logo */} + + + + + + + + + + + + + ); } +type NavLinkProps = { + href: LinkProps["href"]; + label: string; +}; + +function DesktopNavLink({ href, label }: NavLinkProps) { + return ( + + + {label} + + + ); +} + +function MobileNavLink({ href, label }: NavLinkProps) { + return ( + + {label} + + ); +} + +function MobileNav() { + const [mobileNavOpen, setMobileNavOpen] = useState(false); + + const trigger = useRef(null); + const mobileNav = useRef(null); + + // close the mobile menu on click outside + useEffect(() => { + const clickHandler = ({ target }: MouseEvent) => { + if (!mobileNav.current || !trigger.current) { + return; + } + console.log(mobileNav.current.contains(target as Node)); + if ( + !mobileNavOpen || + mobileNav.current.contains(target as Node) || + trigger.current.contains(target as Node) + ) { + return; + } + setMobileNavOpen(false); + }; + document.addEventListener("click", clickHandler); + return () => document.removeEventListener("click", clickHandler); + }); + + // close the mobile menu if the esc key is pressed + useEffect(() => { + const keyHandler = ({ keyCode }: KeyboardEvent) => { + if (!mobileNavOpen || keyCode !== 27) return; + setMobileNavOpen(false); + }; + document.addEventListener("keydown", keyHandler); + return () => document.removeEventListener("keydown", keyHandler); + }); + + return ( + + setMobileNavOpen(!mobileNavOpen)} + > + Menu + + + + + + + + + + + + + + + + + + + + + + Shellphone + + + setMobileNavOpen(false)} + > + Close panel + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} + export default Header; diff --git a/app/public-area/pages/open-metrics.tsx b/app/public-area/pages/open-metrics.tsx new file mode 100644 index 0000000..de57ebc --- /dev/null +++ b/app/public-area/pages/open-metrics.tsx @@ -0,0 +1,38 @@ +import type { BlitzPage } from "blitz"; +import { Head } from "blitz"; + +import Header from "../components/header"; + +const OpenMetrics: BlitzPage = () => { + return ( + <> + + Shellphone: Your Personal Cloud Phone + + + + + + + + + + Open Metrics + + + + + + > + ); +}; + +OpenMetrics.suppressFirstRenderFlicker = true; + +export default OpenMetrics; diff --git a/app/public-area/pages/roadmap.tsx b/app/public-area/pages/roadmap.tsx new file mode 100644 index 0000000..3a10fe0 --- /dev/null +++ b/app/public-area/pages/roadmap.tsx @@ -0,0 +1,38 @@ +import type { BlitzPage } from "blitz"; +import { Head } from "blitz"; + +import Header from "../components/header"; + +const Roadmap: BlitzPage = () => { + return ( + <> + + Shellphone: Your Personal Cloud Phone + + + + + + + + + + Roadmap + + + + + + > + ); +}; + +Roadmap.suppressFirstRenderFlicker = true; + +export default Roadmap;