shellphone.app/app/features/public-area/components/header.tsx
2022-05-14 12:22:06 +02:00

241 lines
7.0 KiB
TypeScript

import { Fragment, useState, useRef, useEffect } from "react";
import { Link, type LinkProps } from "@remix-run/react";
import { Dialog, Transition } from "@headlessui/react";
import { IoClose } from "react-icons/io5";
function Header() {
return (
<header className="absolute inset-x-0 top-0 z-10 w-full">
<div className="px-4 mx-auto sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16 lg:h-20">
<div className="hidden lg:flex lg:items-center lg:justify-center lg:ml-10 lg:mr-auto lg:space-x-10">
<a
href="#"
title=""
className="text-base text-black transition-all duration-200 hover:text-opacity-80"
>
{" "}
Features{" "}
</a>
<a
href="#"
title=""
className="text-base text-black transition-all duration-200 hover:text-opacity-80"
>
{" "}
Solutions{" "}
</a>
<a
href="#"
title=""
className="text-base text-black transition-all duration-200 hover:text-opacity-80"
>
{" "}
Resources{" "}
</a>
<a
href="#"
title=""
className="text-base text-black transition-all duration-200 hover:text-opacity-80"
>
{" "}
Pricing{" "}
</a>
</div>
</div>
</div>
</header>
);
}
function Headerold() {
return (
<header className="absolute w-full z-30 inset-x-0 top-0">
<div className="px-4 mx-auto sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-20">
<div className="flex-shrink-0 mr-5">
<Link to="/" className="block">
<img className="w-10 h-10" src="/shellphone.png" alt="Shellphone logo" />
</Link>
</div>
<nav className="hidden md:flex md:flex-grow">
<ul className="flex items-center justify-center ml-10 mr-auto space-x-10">
<li>
<DesktopNavLink to="/features" label="Features" />
</li>
<li>
<DesktopNavLink to="/roadmap" label="Roadmap" />
</li>
<li>
<DesktopNavLink to="/open" label="Open Metrics" />
</li>
<li>
<DesktopNavLink to="/pricing" label="Pricing" />
</li>
</ul>
</nav>
<MobileNav />
</div>
</div>
</header>
);
}
type NavLinkProps = {
to: LinkProps["to"];
label: string;
};
function DesktopNavLink({ to, label }: NavLinkProps) {
return (
<Link to={to} className="text-base text-gray-600 hover:text-gray-900 transition duration-150 ease-in-out">
{label}
</Link>
);
}
function MobileNav() {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
const trigger = useRef<HTMLButtonElement>(null);
const mobileNav = useRef<HTMLDivElement>(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 (
<div className="inline-flex md:hidden">
<button
ref={trigger}
className={`hamburger ${mobileNavOpen && "active"}`}
aria-controls="mobile-nav"
aria-expanded={mobileNavOpen}
onClick={() => setMobileNavOpen(!mobileNavOpen)}
>
<span className="sr-only">Menu</span>
<svg
className="w-6 h-6 fill-current text-gray-900 hover:text-gray-900 transition duration-150 ease-in-out"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<rect y="4" width="24" height="2" rx="1" />
<rect y="11" width="24" height="2" rx="1" />
<rect y="18" width="24" height="2" rx="1" />
</svg>
</button>
<Transition.Root show={mobileNavOpen} as={Fragment}>
<Dialog as="div" className="fixed z-40 inset-0 overflow-hidden" onClose={setMobileNavOpen}>
<div className="absolute inset-0 overflow-hidden">
<Transition.Child
as={Fragment}
enter="ease-in-out duration-500"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in-out duration-500"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="absolute inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
<div className="fixed inset-y-0 right-0 pl-10 max-w-full flex">
<Transition.Child
as={Fragment}
enter="transform transition ease-in-out duration-500 sm:duration-700"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transform transition ease-in-out duration-500 sm:duration-700"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<div ref={mobileNav} className="w-screen max-w-[16rem] sm:max-w-sm">
<div className="h-full flex flex-col py-6 bg-white shadow-xl overflow-y-scroll">
<div className="px-4 sm:px-6">
<div className="flex items-start justify-between">
<Dialog.Title className="text-lg font-medium text-gray-900">
Shellphone
</Dialog.Title>
<div className="ml-3 h-7 flex items-center">
<button
type="button"
className="bg-white rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rebeccapurple-500"
onClick={() => setMobileNavOpen(false)}
>
<span className="sr-only">Close panel</span>
<IoClose className="h-6 w-6" aria-hidden="true" />
</button>
</div>
</div>
</div>
<div className="mt-6 relative flex-1 px-4 sm:px-6">
<div className="absolute inset-0 px-4 sm:px-6">
<ul className="space-y-4">
<li>
<MobileNavLink to="/features" label="Features" />
</li>
<li>
<MobileNavLink to="/roadmap" label="Roadmap" />
</li>
<li>
<MobileNavLink to="open" label="Open Metrics" />
</li>
<li>
<MobileNavLink to="/pricing" label="Pricing" />
</li>
</ul>
</div>
</div>
</div>
</div>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
</div>
);
function MobileNavLink({ to, label }: NavLinkProps) {
return (
<Link to={to} onClick={() => setMobileNavOpen(false)} className="text-base flex text-gray-600 hover:text-gray-900">
{label}
</Link>
);
}
}
export default Headerold;