diff --git a/package-lock.json b/package-lock.json index 107647e..0deef39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,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", @@ -34,6 +35,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", @@ -3483,6 +3485,21 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "optional": true + }, "node_modules/@envelop/core": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@envelop/core/-/core-3.0.6.tgz", @@ -10632,6 +10649,29 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.3.tgz", + "integrity": "sha512-6x2poQpIWBdbZwLd73w6cKZ1I9IEPIU94C6/Swp1Zt3LJ+sB5bPe1E2wC6EH5hSISXNkMJ4afH7AdwS7MrtkWw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -13865,6 +13905,15 @@ } } }, + "node_modules/react-spinners": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", + "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", diff --git a/package.json b/package.json index d434426..5f76df0 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", diff --git a/src/app/header.tsx b/src/app/header.tsx index 62240cc..0c1c26b 100644 --- a/src/app/header.tsx +++ b/src/app/header.tsx @@ -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 (
- ThumbnailCritique.com + + logo + + ThumbnailCritique + + + + -
+
{!isLoading && ( <> {isAuthenticated && ( @@ -35,17 +52,6 @@ export function Header() { )} - - {/* {!isAuthenticated && ( - <> - - Pricing - - - About - - - )} */} )}
@@ -55,7 +61,6 @@ export function Header() { <> {isAuthenticated && ( <> - {/* {!isSubscriped && } */} )} diff --git a/src/app/mobile-nav.tsx b/src/app/mobile-nav.tsx new file mode 100644 index 0000000..1930bad --- /dev/null +++ b/src/app/mobile-nav.tsx @@ -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 ( + <> + + + +
+ + + toggleOpen()} + className="flex w-full font-semibold capitalize" + > + Dashboard + + + + + toggleOpen()} + className="flex w-full font-semibold capitalize" + > + Create + + + + + toggleOpen()} + className="flex w-full font-semibold capitalize" + > + Explore + + + + + + toggleOpen()} + className="flex w-full font-semibold capitalize" + > + Following + + + + + + toggleOpen()} + className="flex w-full font-semibold capitalize" + > + Account + + + + + + { + signOut(); + toggleOpen(); + }} + className="flex w-full font-semibold capitalize" + > + Sign Out + + +
+
+ +
+ + ); +} + +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 }) => ( + +); + +const Path = (props: any) => ( + +); + +const MenuItem = ({ + className, + children, +}: { + className?: string; + children?: ReactNode; +}) => { + return ( + + {children} + + ); +}; + +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 }; +} diff --git a/src/app/page.tsx b/src/app/page.tsx index a1f3b02..914b999 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -19,8 +19,8 @@ export default function Home() { The easiest way to get feedback on your thumbnails

- 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.