Potion/web/src/components/Navigation.tsx
2025-11-14 22:33:54 -07:00

117 lines
4.2 KiB
TypeScript

import { useState } from "react";
import ROUTE_CONSTANTS from "../types/routes.ts";
import { useLocation } from "react-router-dom";
import ShoppingListIcon from "./icons/ShoppingListIcon.tsx";
export default function Navigation() {
const [displayHamburgerMenu, setDisplayHamburgerMenu] = useState<boolean>(false);
const location = useLocation();
return (
<>
<nav className="block md:fixed w-full z-20">
<div
className="relative w-full px-8 md:px-44 p-4 border-b border-gray-300 shadow-sm shadow-gray-300 bg-white flex justify-between items-center"
>
<div>
<a href={ROUTE_CONSTANTS.Home}>
<p className="select-none">Potion</p>
</a>
</div>
<div className="hidden md:flex lg:flex items-center gap-8 select-none">
<NavigationLink name="Home" url={ROUTE_CONSTANTS.Home} current={location.pathname === ROUTE_CONSTANTS.Home} />
<NavigationLink name="Favorites" url={ROUTE_CONSTANTS.Favorites} current={location.pathname === ROUTE_CONSTANTS.Favorites} />
<NavigationLink name="Create" url={ROUTE_CONSTANTS.Create} current={location.pathname === ROUTE_CONSTANTS.Create} />
<NavigationLink name="Profile" url={ROUTE_CONSTANTS.Profile} current={location.pathname === ROUTE_CONSTANTS.Profile} />
<IconNavigationLink icon={<ShoppingListIcon current={location.pathname === ROUTE_CONSTANTS.ShoppingList} />} url={ROUTE_CONSTANTS.ShoppingList} />
</div>
<div className="md:hidden grid place-content-center">
<button onClick={() => setDisplayHamburgerMenu(!displayHamburgerMenu)} className="p-2">
<svg
className={`${displayHamburgerMenu ? "flex" : "hidden"} size-5`}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 320 512"
>
<path
d="M182.6 137.4c-12.5-12.5-32.8-12.5-45.3 0l-128 128c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8l256 0c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-128-128z"
></path>
</svg>
<svg
className={`${displayHamburgerMenu ? "hidden" : "flex"} size-5`}
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
fill="currentColor"
d="M0 96C0 78.3 14.3 64 32 64l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32L32 448c-17.7 0-32-14.3-32-32s14.3-32 32-32l384 0c17.7 0 32 14.3 32 32z"
></path>
</svg>
</button>
</div>
<HamburgerMenu show={displayHamburgerMenu} />
</div>
</nav>
</>
);
}
interface HamburgerMenuProps {
show: boolean;
};
function HamburgerMenu({ show }: HamburgerMenuProps) {
return (
<div className={`${show ? "flex" : "hidden"} w-full flex-col items-center absolute top-[100%] left-0 py-2 bg-white border-b border-gray-300 shadow-sm shadow-gray-300 z-20`}>
<DropdownLink name="Home" url={ROUTE_CONSTANTS.Home} />
<DropdownLink name="Favorites" url={ROUTE_CONSTANTS.Favorites} />
<DropdownLink name="Create" url={ROUTE_CONSTANTS.Create} />
<DropdownLink name="Profile" url={ROUTE_CONSTANTS.Profile} />
<DropdownLink name="Shopping List" url={ROUTE_CONSTANTS.ShoppingList} />
</div>
);
}
interface DropdownLinkProps {
name: string;
url: string;
}
function DropdownLink({ name, url }: DropdownLinkProps) {
return (
<a className="py-2" href={url}>
{name}
</a>
);
};
interface NavigationLinkProps {
name: string;
url: string;
current: boolean;
}
function NavigationLink({ name, url, current }: NavigationLinkProps) {
return (
<a href={url} className={`${current ? "border-blue-500" : "hover:border-blue-400 border-white"} duration-150 text-gray-700 border-b-2 px-1 cursor-pointer`}>
{name}
</a>
);
}
interface IconNavigationLinkProps {
icon: React.ReactElement;
url: string;
}
function IconNavigationLink({ icon, url }: IconNavigationLinkProps) {
return (
<a href={url} className="px-1 cursor-pointer">
{icon}
</a>
);
}