Skip to content

Commit

Permalink
Merge pull request #2294 from quantified-uncertainty/mobile
Browse files Browse the repository at this point in the history
Mobile page menu
  • Loading branch information
berekuk authored Sep 26, 2023
2 parents 5a3c70d + 47a96a9 commit 6bc9941
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ const Mutation = graphql`
`;

export const ChooseUsername: FC = () => {
const toast = useToast();

type FormShape = {
username: string;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { signIn, useSession } from "next-auth/react";
import { FC } from "react";

import { Button, Dropdown, DropdownMenu } from "@quri/ui";

import { DropdownWithArrow } from "./DropdownWithArrow";
import { UserControlsMenu } from "./UserControlsMenu";
import { useUsername } from "@/hooks/useUsername";

export const DesktopUserControls: FC = () => {
const username = useUsername();

return username ? (
<div className="flex items-center gap-2">
<Dropdown
render={({ close }) => (
<DropdownMenu>
<UserControlsMenu
mode="desktop"
close={close}
username={username}
/>
</DropdownMenu>
)}
>
<DropdownWithArrow text={username} />
</Dropdown>
</div>
) : (
<Button onClick={() => signIn()}>Sign In</Button>
);
};
156 changes: 128 additions & 28 deletions packages/hub/src/components/layout/RootLayout/PageMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,144 @@
import { FC } from "react";
import { useSession } from "next-auth/react";
import { signIn, useSession } from "next-auth/react";
import Link from "next/link";
import { FC, useState } from "react";
import { FaPlus } from "react-icons/fa";

import { BookOpenIcon, CodeBracketIcon } from "@quri/ui";
import {
BookOpenIcon,
DotsHorizontalIcon,
DropdownMenu,
DropdownMenuAsyncActionItem,
DropdownMenuHeader,
DropdownMenuSeparator,
SignOutIcon,
UserCircleIcon,
} from "@quri/ui";

import { UserControls } from "./UserControls";
import { PageMenuLink } from "./PageMenuLink";
import { aboutRoute, newModelRoute } from "@/routes";
import { useUsername } from "@/hooks/useUsername";
import { SQUIGGLE_DOCS_URL } from "@/lib/common";
import { FaPlus } from "react-icons/fa";
import { aboutRoute, newModelRoute } from "@/routes";
import { DesktopUserControls } from "./DesktopUserControls";
import { MenuLinkModeProps, PageMenuLink } from "./PageMenuLink";
import { UserControlsMenu } from "./UserControlsMenu";
import { useForceChooseUsername } from "./useForceChooseUsername";

export const PageMenu: FC = () => {
const AboutMenuLink: FC<MenuLinkModeProps> = (props) => {
const { data: session } = useSession();
if (session) {
return null;
}
return <PageMenuLink {...props} href={aboutRoute()} title="About" />;
};

const DocsMenuLink: FC<MenuLinkModeProps> = (props) => (
<PageMenuLink
{...props}
href={SQUIGGLE_DOCS_URL}
icon={BookOpenIcon}
title="Docs"
external
/>
);

const NewModelMenuLink: FC<MenuLinkModeProps> = (props) => {
const { data: session } = useSession();
if (!session) {
return null;
}
return (
<PageMenuLink
{...props}
href={newModelRoute()}
icon={FaPlus}
title="New Model"
/>
);
};

const DesktopMenu: FC = () => {
return (
<div className="flex gap-6 items-baseline">
<AboutMenuLink mode="desktop" />
<DocsMenuLink mode="desktop" />
<NewModelMenuLink mode="desktop" />
<DesktopUserControls />
</div>
);
};

const MobileMenu: FC = () => {
const username = useUsername();
const [open, setOpen] = useState(false);

const Icon = username ? UserCircleIcon : DotsHorizontalIcon;

const close = () => setOpen(false);
return (
<div>
<div className="p-2 cursor-pointer">
<Icon
size={20}
className="text-slate-100"
onClick={() => setOpen(true)}
/>
</div>
{open && (
<>
{/* overlay */}
<div
className="absolute inset-0 z-10 bg-black opacity-10"
onClick={close}
/>
{/* sidebar panel */}
<div className="absolute inset-y-0 right-0 z-20 bg-white shadow-xl">
<DropdownMenu>
<DropdownMenuHeader>Menu</DropdownMenuHeader>
<DropdownMenuSeparator />
<NewModelMenuLink mode="mobile" close={close} />
<AboutMenuLink mode="mobile" close={close} />
<DocsMenuLink mode="mobile" close={close} />
<DropdownMenuSeparator />
{username ? (
<UserControlsMenu
mode="mobile"
username={username}
close={close}
/>
) : (
<>
<DropdownMenuHeader>User Actions</DropdownMenuHeader>
<DropdownMenuSeparator />
<DropdownMenuAsyncActionItem
title="Sign In"
icon={SignOutIcon}
onClick={signIn}
close={close}
/>
</>
)}
</DropdownMenu>
</div>
</>
)}
</div>
);
};

export const PageMenu: FC = () => {
useForceChooseUsername();

return (
<div className="border-slate-200 h-10 flex items-center justify-between px-8 bg-gray-800">
<div className="flex gap-6 items-baseline">
<Link
className="text-slate-300 hover:text-slate-300 font-semibold"
href="/"
>
<Link className="text-slate-300 font-semibold" href="/">
Squiggle Hub
</Link>
</div>
<div className="flex gap-6 items-baseline">
{!session && <PageMenuLink href={aboutRoute()} title="About" />}
<PageMenuLink
href={SQUIGGLE_DOCS_URL}
icon={BookOpenIcon}
title="Docs"
external
/>
{session && (
<PageMenuLink
href={newModelRoute()}
icon={FaPlus}
title="New Model"
/>
)}
<UserControls session={session} />
<div className="hidden md:block">
<DesktopMenu />
</div>
<div className="block md:hidden">
<MobileMenu />
</div>
</div>
);
Expand Down
34 changes: 31 additions & 3 deletions packages/hub/src/components/layout/RootLayout/PageMenuLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,36 @@ import Link from "next/link";
import { FC } from "react";

import { IconProps } from "@/relative-values/components/ui/icons/Icon";
import { DropdownMenuLinkItem } from "@/components/ui/DropdownMenuLinkItem";
import { EmptyIcon } from "@quri/ui";

export const PageMenuLink: FC<{
export type MenuLinkModeProps =
| {
mode: "desktop";
close?: undefined;
}
| {
mode: "mobile";
close: () => void;
};

type Props = {
title: string;
href: string;
icon?: FC<IconProps>;
external?: boolean;
}> = ({ title, icon, href, external }) => {
} & MenuLinkModeProps;

export const PageMenuLink: FC<Props> = ({
mode,
close,
title,
icon,
href,
external,
}) => {
const Icon = icon;
return (
return mode === "desktop" ? (
<Link
className="text-white text-sm hover:bg-slate-700 px-2 py-1 rounded-md select-none"
href={href}
Expand All @@ -19,5 +40,12 @@ export const PageMenuLink: FC<{
{Icon && <Icon className="inline-block mr-1 text-slate-400" size={14} />}
{title}
</Link>
) : (
<DropdownMenuLinkItem
href={href}
icon={icon ?? EmptyIcon}
title={title}
close={close}
/>
);
};
106 changes: 0 additions & 106 deletions packages/hub/src/components/layout/RootLayout/UserControls.tsx

This file was deleted.

Loading

1 comment on commit 6bc9941

@vercel
Copy link

@vercel vercel bot commented on 6bc9941 Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.