pronounsfu/frontend/components/Navigation.tsx

124 lines
3.9 KiB
TypeScript
Raw Normal View History

2022-05-12 07:41:32 -07:00
import { useEffect, useState } from "react";
2022-05-10 07:33:29 -07:00
import { MoonStars, Sun, List } from "react-bootstrap-icons";
import Link from "next/link";
2022-05-10 13:24:20 -07:00
import NavItem from "./NavItem";
import Logo from "./logo";
2022-05-12 07:41:32 -07:00
import { useRecoilState } from "recoil";
import { themeState, userState } from "../lib/state";
import { fetchAPI, APIError, ErrorCode, MeUser } from "../lib/api-fetch";
2022-05-10 13:24:20 -07:00
export default function Navigation() {
2022-05-12 07:41:32 -07:00
const [user, setUser] = useRecoilState(userState);
const [darkTheme, setDarkTheme] = useRecoilState(themeState);
2022-05-12 07:41:32 -07:00
useEffect(() => {
if (user) return;
fetchAPI<MeUser>("/users/@me").then(
(res) => setUser(res),
(err) => {
console.log("fetching /users/@me", err);
if (
(err as APIError).code == ErrorCode.InvalidToken ||
(err as APIError).code == ErrorCode.Forbidden
) {
localStorage.removeItem("pronouns-token");
}
}
2022-05-12 07:41:32 -07:00
);
}, [user, setUser]);
2022-05-10 07:33:29 -07:00
const [showMenu, setShowMenu] = useState(false);
useEffect(() => {
setDarkTheme(
localStorage.theme === "dark" ||
(!("theme" in localStorage) &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
);
if (darkTheme) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}, [darkTheme]);
2022-05-10 07:33:29 -07:00
2022-05-10 13:24:20 -07:00
const storeTheme = (useDarkTheme: boolean | null) => {
if (useDarkTheme === null) {
2022-05-10 07:33:29 -07:00
localStorage.removeItem("theme");
} else {
2022-05-10 13:24:20 -07:00
localStorage.setItem("theme", useDarkTheme ? "dark" : "light");
2022-05-10 07:33:29 -07:00
}
};
2022-05-12 07:41:32 -07:00
const nav = user ? (
<>
<NavItem href={`/u/${user.name}`}>@{user.name}</NavItem>
<NavItem href="/settings">Settings</NavItem>
<NavItem href="/logout">Log out</NavItem>
2022-05-12 07:41:32 -07:00
</>
) : (
<>
<NavItem href="/login">Log in</NavItem>
2022-05-12 07:41:32 -07:00
</>
);
2022-05-10 07:33:29 -07:00
return (
2022-05-10 13:24:20 -07:00
<>
<div className="bg-white/75 dark:bg-slate-800/75 w-full backdrop-blur border-slate-200 dark:border-slate-700 border-b">
<div className="max-w-8xl mx-auto">
<div className="py-4 mx-4">
<div className="flex items-center">
2022-08-16 18:04:06 -07:00
<Link href="/" passHref>
2022-11-19 07:52:52 -08:00
<Logo />
2022-05-10 13:24:20 -07:00
</Link>
<div className="ml-auto flex items-center">
<nav className="hidden lg:flex">
2022-05-12 07:41:32 -07:00
<ul className="flex space-x-4 font-bold">{nav}</ul>
2022-05-10 13:24:20 -07:00
</nav>
<div className="flex border-l border-slate-200 ml-4 pl-4 lg:ml-6 lg:pl-6 lg:mr-2 dark:border-slate-700 space-x-2 lg:space-x-4">
<div
onClick={() => {
setDarkTheme(!darkTheme);
storeTheme(!darkTheme);
}}
title={
darkTheme ? "Switch to light mode" : "Switch to dark mode"
}
className="cursor-pointer"
>
{darkTheme ? (
<Sun className="hover:text-sky-400" size={24} />
) : (
<MoonStars size={24} className="hover:text-sky-500" />
)}
</div>
2022-05-12 07:41:32 -07:00
<div
onClick={() => setShowMenu(!showMenu)}
title="Show menu"
className="cursor-pointer flex lg:hidden"
>
<List
className="dark:hover:text-sky-400 hover:text-sky-500"
size={24}
/>
2022-05-10 13:24:20 -07:00
</div>
2022-05-10 07:33:29 -07:00
</div>
</div>
</div>
</div>
</div>
</div>
2022-05-12 07:41:32 -07:00
<nav
className={`lg:hidden p-4 border-slate-200 dark:border-slate-700 border-b ${
showMenu ? "flex" : "hidden"
}`}
>
<ul className="flex flex-col space-y-4 font-bold">{nav}</ul>
2022-05-10 13:24:20 -07:00
</nav>
</>
2022-05-10 07:33:29 -07:00
);
}