Skip to content

Commit

Permalink
mobile top nav menu
Browse files Browse the repository at this point in the history
  • Loading branch information
webdevcody committed Feb 2, 2024
1 parent 0a16486 commit c73224a
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 16 deletions.
49 changes: 49 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"convex": "^1.7.1",
"convex-helpers": "^0.1.14",
"date-fns": "^3.2.0",
"framer-motion": "^11.0.3",
"lodash": "^4.17.21",
"lucide-react": "^0.311.0",
"next": "14.0.4",
Expand All @@ -40,6 +41,7 @@
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.49.3",
"react-spinners": "^0.13.8",
"stripe": "^14.13.0",
"svix": "^1.15.0",
"tailwind-merge": "^2.2.0",
Expand Down
33 changes: 19 additions & 14 deletions src/app/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,33 @@ import { SignInButton, UserButton } from "@clerk/nextjs";
import { ModeToggle } from "./mode-toggle";
import Link from "next/link";
import { useSession } from "@/lib/utils";
import MobileNav, { useMobileNavState } from "./mobile-nav";
import Image from "next/image";

export function Header() {
const { isLoading, isAuthenticated } = useSession();

const { isOpen, toggleOpen } = useMobileNavState();

return (
<div className="border-b dark:bg-gray-900">
<div className="h-16 container flex justify-between items-center">
<Link href="/">ThumbnailCritique.com</Link>
<Link href="/" className="flex gap-2 items-center">
<Image
className="rounded"
src="/hero.jpeg"
width="40"
height="40"
alt="logo"
/>
<span className="hidden sm:block text-xs md:text-md">
ThumbnailCritique
</span>
</Link>

<MobileNav isOpen={isOpen} toggleOpen={toggleOpen} />

<div className="flex gap-8">
<div className="gap-4 md:gap-8 hidden sm:flex text-xs md:text-base">
{!isLoading && (
<>
{isAuthenticated && (
Expand All @@ -35,17 +52,6 @@ export function Header() {
</Link>
</>
)}

{/* {!isAuthenticated && (
<>
<Link href="/pricing" className="link">
Pricing
</Link>
<Link href="/about" className="link">
About
</Link>
</>
)} */}
</>
)}
</div>
Expand All @@ -55,7 +61,6 @@ export function Header() {
<>
{isAuthenticated && (
<>
{/* {!isSubscriped && <UpgradeButton />} */}
<UserButton />
</>
)}
Expand Down
212 changes: 212 additions & 0 deletions src/app/mobile-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
"use client";

import React, { ReactNode, useEffect, useRef } from "react";

import Link from "next/link";

import { useClerk } from "@clerk/nextjs";
import { motion, useCycle } from "framer-motion";
import { MenuIcon } from "lucide-react";

const sidebar = {
open: {
clipPath: `inset(0% 0% 0% 0%)`,
transition: {
type: "tween",
duration: 0.3,
},
},
closed: {
clipPath: "inset(0% 0% 100% 0%)",
transition: {
type: "spring",
stiffness: 500,
damping: 30,
},
},
};

export default function MobileNav({
isOpen,
toggleOpen,
}: {
isOpen: any;
toggleOpen: any;
}) {
const containerRef = useRef(null);
const { height } = useDimensions(containerRef);
const { signOut } = useClerk();

return (
<>
<motion.nav
initial={false}
animate={isOpen ? "open" : "closed"}
custom={height}
className={`flex justify-end w-full sm:hidden ${
isOpen ? "" : "pointer-events-none"
}`}
ref={containerRef}
>
<motion.div
className="absolute inset-0 top-16 left-0 w-full dark:bg-gray-900 bg-white z-50"
variants={sidebar}
/>
<motion.ul
variants={variants}
className="absolute inset-0 grid w-full gap-3 py-16 z-50 "
>
<div className="dark:text-white text-black flex flex-col items-center">
<MenuItem className="my-3 h-px w-full bg-gray-300" />
<MenuItem key="Dashboard">
<Link
href="/dashboard"
onClick={() => toggleOpen()}
className="flex w-full font-semibold capitalize"
>
Dashboard
</Link>
</MenuItem>
<MenuItem className="my-3 h-px w-full bg-gray-300" />
<MenuItem key="Create">
<Link
href="/create"
onClick={() => toggleOpen()}
className="flex w-full font-semibold capitalize"
>
Create
</Link>
</MenuItem>
<MenuItem className="my-3 h-px w-full bg-gray-300" />
<MenuItem key="Explore">
<Link
href="/explore"
onClick={() => toggleOpen()}
className="flex w-full font-semibold capitalize"
>
Explore
</Link>
</MenuItem>
<MenuItem className="my-3 h-px w-full bg-gray-300" />

<MenuItem key="Following">
<Link
href="/following"
onClick={() => toggleOpen()}
className="flex w-full font-semibold capitalize"
>
Following
</Link>
</MenuItem>
<MenuItem className="my-3 h-px w-full bg-gray-300" />

<MenuItem key="Account">
<Link
href="/account"
onClick={() => toggleOpen()}
className="flex w-full font-semibold capitalize"
>
Account
</Link>
</MenuItem>
<MenuItem className="my-3 h-px w-full bg-gray-300" />

<MenuItem key="SignOut">
<Link
href="/"
onClick={() => {
signOut();
toggleOpen();
}}
className="flex w-full font-semibold capitalize"
>
Sign Out
</Link>
</MenuItem>
</div>
</motion.ul>
<MenuToggle toggle={toggleOpen} />
</motion.nav>
</>
);
}

const useDimensions = (ref: any) => {
const dimensions = useRef({ width: 0, height: 0 });

useEffect(() => {
if (ref.current) {
dimensions.current.width = ref.current.offsetWidth;
dimensions.current.height = ref.current.offsetHeight;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref]);

return dimensions.current;
};

const MenuToggle = ({ toggle }: { toggle: any }) => (
<button
onClick={toggle}
className="pointer-events-auto flex z-50 dark:text-white text-black mr-3"
>
<MenuIcon />
</button>
);

const Path = (props: any) => (
<motion.path
fill="transparent"
strokeWidth="2"
stroke="hsl(0, 0%, 18%)"
strokeLinecap="round"
{...props}
/>
);

const MenuItem = ({
className,
children,
}: {
className?: string;
children?: ReactNode;
}) => {
return (
<motion.li variants={MenuItemVariants} className={className}>
{children}
</motion.li>
);
};

const MenuItemVariants = {
open: {
y: 0,
opacity: 1,
transition: {
y: { stiffness: 1000, velocity: -100 },
},
},
closed: {
y: 50,
opacity: 0,
transition: {
y: { stiffness: 1000 },
duration: 0.02,
},
},
};

const variants = {
open: {
transition: { staggerChildren: 0.02, delayChildren: 0.15 },
},
closed: {
transition: { staggerChildren: 0.01, staggerDirection: -1 },
},
};

export function useMobileNavState() {
const [isOpen, toggleOpen] = useCycle(false, true);

return { isOpen, toggleOpen };
}
4 changes: 2 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export default function Home() {
The easiest way to get feedback on your thumbnails
</h1>
<p className="text-center text-gray-700 dark:text-gray-300 text-xl max-w-lg mx-auto">
Upload your two thumbnails and send links to your friends to help you
hone in your best design skills.
Upload your thumbnails variations and send links to your friends to
help you hone in your design skills.
</p>
<Button asChild>
<Link href="/create">Get Started</Link>
Expand Down

0 comments on commit c73224a

Please sign in to comment.