Responsive navbar (#136)

* feature: responsive navbar

* style: nav links hover animatiosn
This commit is contained in:
!MAD! 2023-05-24 11:50:55 +05:30 committed by GitHub
parent b2ab0dfa4e
commit 380e264a2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 124 additions and 33 deletions

View File

@ -29,7 +29,7 @@ const DarkModeToggle: FC<DarkModeToggleProps> = ({}) => {
return (
<Button
aria-label="toggle dark mode"
className="focus:outline-none"
className="focus:outline-none text-3xl"
onClick={() => setDark((d) => !d)}
variant={"tertiary"}
>

View File

@ -0,0 +1,60 @@
import { FC, ReactNode, useState } from "react";
import * as Dialog from "@radix-ui/react-dialog";
import { MdClose, MdMenu } from "react-icons/md";
import { AnimatePresence, motion } from "framer-motion";
import Button from "../ui/Button";
import NavItems from "./NavItems";
interface MobileMenuProps {}
const MobileMenu: FC<MobileMenuProps> = ({}) => {
const [open, setOpen] = useState(false);
return (
<Dialog.Root onOpenChange={setOpen}>
<Dialog.Trigger asChild>
<button className="block sm:hidden" aria-label="open menu">
<MdMenu className="text-4xl" />
</button>
</Dialog.Trigger>
<AnimatePresence>
{open ? (
<Dialog.Portal forceMount>
<Dialog.Overlay asChild forceMount>
<motion.div
className="fixed inset-0 flex overflow-auto cursor-pointer z-50 shadow-xl dark:shadow-primary/25"
initial={{ opacity: 1, y: "-100%" }}
animate={{ opacity: 1, y: "0%" }}
exit={{ opacity: 1, y: "-100%" }}
transition={{ duration: 0.4, ease: "circOut" }}
>
<Dialog.Content asChild forceMount>
<div className="flex flex-col items-center justify-between py-24 flex-1 w-full bg-white dark:bg-black border border-black/10 dark:border-white/25 p-10 shadow-xl dark:shadow-primary/50 focus:outline-none cursor-auto z-50">
<NavItems className="text-3xl h-fit text-center flex-col items-center justify-center gap-10" />
<p className="">
Get a Second Brain with{" "}
<span className="text-primary dark:bg-white rounded-sm">
Quivr
</span>
</p>
<Dialog.Close asChild>
<button
className="absolute top-0 p-3 right-0 flex items-center justify-center gap-2 appearance-none rounded-full focus:shadow-sm focus:outline-none"
aria-label="close menu"
>
<MdClose className="text-4xl" />
</button>
</Dialog.Close>
</div>
</Dialog.Content>
</motion.div>
</Dialog.Overlay>
</Dialog.Portal>
) : null}
</AnimatePresence>
</Dialog.Root>
);
};
export default MobileMenu;

View File

@ -0,0 +1,56 @@
import { cn } from "@/lib/utils";
import Link from "next/link";
import { FC, HTMLAttributes, ReactNode } from "react";
import DarkModeToggle from "./DarkModeToggle";
import Button from "../ui/Button";
interface NavItemsProps extends HTMLAttributes<HTMLUListElement> {}
const NavItems: FC<NavItemsProps> = ({ className, ...props }) => {
return (
// <div className={cn("flex flex-1 items-center", className)} {...props}>
<ul
className={cn(
"flex flex-row items-center gap-4 text-sm flex-1",
className
)}
{...props}
>
{process.env.NEXT_PUBLIC_ENV === "local" ? (
<>
<NavLink to="/upload">Upload</NavLink>
<NavLink to="/chat">Chat</NavLink>
<NavLink to="/explore">Explore</NavLink>
</>
) : (
<>
<NavLink to="https://github.com/StanGirard/quivr">Github</NavLink>
<NavLink to="https://discord.gg/HUpRgp2HG8">Discord</NavLink>
</>
)}
<div className="flex sm:flex-1 sm:justify-end flex-col items-center justify-center sm:flex-row gap-5 sm:gap-2">
<Link href={"https://try-quivr.streamlit.app"}>
<Button variant={"secondary"}>Try Demo</Button>
</Link>
<DarkModeToggle />
</div>
</ul>
// </div>
);
};
interface NavLinkProps {
children: ReactNode;
to: string;
}
const NavLink: FC<NavLinkProps> = ({ children, to }) => {
return (
<li className="group relative">
<Link href={to}>{children}</Link>
<hr className="aboslute top-full border border-transparent border-b-primary dark:border-b-white scale-x-0 group-hover:scale-x-100 group-focus-within:scale-x-100 transition-transform" />
</li>
);
};
export default NavItems;

View File

@ -6,6 +6,8 @@ import Link from "next/link";
import Button from "../ui/Button";
import DarkModeToggle from "./DarkModeToggle";
import { motion } from "framer-motion";
import MobileMenu from "./MobileMenu";
import NavItems from "./NavItems";
interface NavBarProps {}
@ -34,9 +36,9 @@ const NavBar: FC<NavBarProps> = ({}) => {
y: hidden ? "-100%" : "0%",
transition: { ease: "circOut" },
}}
className="fixed top-0 w-full border-b border-b-black/10 dark:border-b-white/25 bg-white dark:bg-black z-50"
className="fixed top-0 w-full border-b border-b-black/10 dark:border-b-white/25 bg-white dark:bg-black z-20"
>
<nav className="max-w-screen-xl mx-auto py-1 flex items-center gap-8">
<nav className="max-w-screen-xl mx-auto py-1 flex items-center justify-between gap-8">
<Link href={"/"} className="flex items-center gap-4">
<Image
className="rounded-full"
@ -47,35 +49,8 @@ const NavBar: FC<NavBarProps> = ({}) => {
/>
<h1 className="font-bold">Quivr</h1>
</Link>
{process.env.NEXT_PUBLIC_ENV === "local" ? (
<ul className="flex gap-4 text-sm flex-1">
<li>
<Link href={"/upload"}>Upload</Link>
</li>
<li>
<Link href={"/chat"}>Chat</Link>
</li>
<li>
<Link href={"/explore"}>Explore</Link>
</li>
</ul>
) : (
<ul className="flex gap-4 text-sm flex-1">
<li>
<Link href={"https://github.com/StanGirard/quivr"}>Github</Link>
</li>
<li>
<Link href={"https://discord.gg/HUpRgp2HG8"}>Discord</Link>
</li>
</ul>
)}
<div className="flex">
<Link href={"https://try-quivr.streamlit.app"}>
<Button variant={"secondary"}>Try Demo</Button>
</Link>
<DarkModeToggle />
</div>
<NavItems className="hidden sm:flex" />
<MobileMenu />
</nav>
</motion.header>
);

View File

@ -18,7 +18,7 @@ const ButtonVariants = cva(
"bg-black disabled:bg-gray-500 disabled:hover:bg-gray-500 text-white dark:bg-white dark:text-black hover:bg-gray-700 dark:hover:bg-gray-200 transition-colors",
tertiary: "text-black dark:text-white bg-transparent py-2 px-4",
secondary:
"border border-black dark:border-white bg-white dark:bg-black text-black dark:text-white focus:bg-black dark:focus:bg-white hover:bg-black dark:hover:bg-white hover:text-white dark:hover:text-black focus:text-white transition-colors py-2 px-4 shadow-none",
"border border-black dark:border-white bg-white dark:bg-black text-black dark:text-white focus:bg-black dark:focus:bg-white hover:bg-black dark:hover:bg-white hover:text-white dark:hover:text-black focus:text-white dark:focus:text-black transition-colors py-2 px-4 shadow-none",
danger:
"border border-red-500 hover:bg-red-500 hover:text-white transition-colors",
},