diff --git a/src/components/main-menu.tsx b/src/components/main-menu.tsx deleted file mode 100644 index 016c60b..0000000 --- a/src/components/main-menu.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { observer } from "mobx-react-lite"; -import { useAccountStore } from "@/contexts/AccountContext"; -import { Button } from "./ui/button"; - -export const MainMenu = observer(() => { - const { isMainMenuOpen, setIsMainMenuOpen } = useAccountStore(); - return ( -
- -
- ); -}); diff --git a/src/components/main-menu/collapsed-menu.tsx b/src/components/main-menu/collapsed-menu.tsx new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/components/main-menu/collapsed-menu.tsx @@ -0,0 +1 @@ + diff --git a/src/components/main-menu/main-menu.tsx b/src/components/main-menu/main-menu.tsx new file mode 100644 index 0000000..f3682e2 --- /dev/null +++ b/src/components/main-menu/main-menu.tsx @@ -0,0 +1,199 @@ +import { observer } from "mobx-react-lite"; +import { useAccountStore } from "@/contexts/AccountContext"; +import Plus from "@/icons/plus.svg?react"; +import Books from "@/icons/books.svg?react"; +import Discord from "@/icons/discord.svg?react"; +import Profile from "@/icons/profile.svg?react"; + +import { LINKS } from "@/lib/constants"; +import { useEffect, useRef, useState, type ReactNode } from "react"; +import { Button, type ButtonVariantType } from "../ui/button"; +import { Link } from "@tanstack/react-router"; + +import Logo from "@/icons/logo.svg?react"; +import LogoWithText from "@/icons/logo-with-text.svg?react"; +import Sidebar from "@/icons/sidebar.svg?react"; + +interface MenuItemType extends ButtonVariantType { + name: string; + icon: ReactNode; + path: string; +} + +const MENU_ITEMS: MenuItemType[] = [ + { + name: "New Chat", + icon: , + path: "/", + variant: "primary", + }, + { + name: "All chats", + icon: , + path: "/all-chats", + variant: "secondary", + }, + { + name: "Support", + icon: , + path: LINKS.discord, + variant: "secondary", + }, +]; + +const MenuItem = ({ item }: { item: MenuItemType }) => { + const { isMainMenuOpen } = useAccountStore(); + + return ( + + +
+ {item.name} +
+ + ); +}; + +const MainMenu = observer(() => { + const { isMainMenuOpen } = useAccountStore(); + + return ( +
+ +
+ ); +}); + +const MOCK_CHATS = Array.from({ length: 20 }, (_, i) => ({ + id: i, + title: `Chat ${i + 1}`, + subtitle: `Last message preview...`, +})); + +const MainMenuContent = observer(() => { + const { isMainMenuOpen, setIsMainMenuOpen } = useAccountStore(); + const containerRef = useRef(null); + const [hasScrolled, setHasScrolled] = useState(false); + + useEffect(() => { + const container = containerRef.current; + if (!container) return; + + const handleScroll = () => { + setHasScrolled(container.scrollTop > 0); + }; + + container.addEventListener("scroll", handleScroll); + handleScroll(); + + return () => { + container.removeEventListener("scroll", handleScroll); + }; + }, []); + + return ( +
+
+
+ {isMainMenuOpen ? ( +
+ + +
+ ) : ( +
+ + +
+ )} +
+ +
+ {MENU_ITEMS.map((item) => ( + + ))} +
+
+ +
+

+ Recent +

+ +
    + {MOCK_CHATS.map((chat) => ( +
  • +

    + {chat.title} +

    +

    + {chat.subtitle} +

    +
  • + ))} +
+
+ +
+ +
+
+ ); +}); + +export { MainMenu, MenuItem, MENU_ITEMS, MainMenuContent }; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 4aeeaf0..d7540f2 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -3,6 +3,8 @@ import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; import { cn } from "@/lib/utils"; +type ButtonVariantType = VariantProps; + const buttonVariants = cva( "h-[52px] inline-flex items-center justify-center gap-2 font-medium whitespace-nowrap rounded-[8px] px-4 text-[14px] leading-[130%] tracking-[0.01em] transition-colors hover:cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:*:fill-text-secondary [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", { @@ -45,4 +47,4 @@ const Button = React.forwardRef( ); Button.displayName = "Button"; -export { Button, buttonVariants }; +export { Button, buttonVariants, type ButtonVariantType }; diff --git a/src/components/ui/toaster.tsx b/src/components/ui/toaster.tsx index 19acb44..5661e0f 100644 --- a/src/components/ui/toaster.tsx +++ b/src/components/ui/toaster.tsx @@ -16,6 +16,7 @@ import { useToast } from "@/lib/hooks/use-toast"; import Discord from "@/icons/discord.svg?react"; import Copy from "@/icons/copy.svg?react"; import { TextLink } from "./text-link"; +import { LINKS } from "@/lib/constants"; const ToastProvider = ToastPrimitives.Provider; @@ -308,10 +309,7 @@ const TOASTER_DESCRIPTION_PATTERNS = { Error code ] - + [ Support ] diff --git a/src/icons/books.svg b/src/icons/books.svg new file mode 100644 index 0000000..6f6cb14 --- /dev/null +++ b/src/icons/books.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/icons/plus.svg b/src/icons/plus.svg new file mode 100644 index 0000000..206f28c --- /dev/null +++ b/src/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/icons/profile.svg b/src/icons/profile.svg new file mode 100644 index 0000000..4d9b524 --- /dev/null +++ b/src/icons/profile.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/icons/sidebar.svg b/src/icons/sidebar.svg new file mode 100644 index 0000000..bb13921 --- /dev/null +++ b/src/icons/sidebar.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 589bc33..62406c9 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -2,3 +2,7 @@ export const LS_TOKENS = { isMainMenuOpen: "isMainMenuOpen", userId: "userId", }; + +export const LINKS = { + discord: "https://discord.gg/cytonic", +}; diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 23c47d7..094d416 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -2,7 +2,7 @@ import { Outlet, createRootRoute } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import { useAccountStore } from "@/contexts/AccountContext"; -import { MainMenu } from "@/components/main-menu"; +import { MainMenu } from "@/components/main-menu/main-menu"; export const Route = createRootRoute({ component: RootLayout, @@ -21,7 +21,7 @@ function RootLayout() { - + {/* */} ); } diff --git a/src/routes/index.tsx b/src/routes/index.tsx index e9bdda5..1db4189 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -2,22 +2,27 @@ import { Chat } from "@/components/interaction-panel/chat"; import { createFileRoute, Link } from "@tanstack/react-router"; import LogoWithText from "@/icons/logo-with-text.svg?react"; import { Button } from "@/components/ui/button"; +import { useAccountStore } from "@/contexts/AccountContext"; export const Route = createFileRoute("/")({ component: App, }); function App() { + const { userId } = useAccountStore(); + return (
-
- - - - -
+ {!userId && ( +
+ + + + +
+ )}
); diff --git a/src/routes/magic-link/$magic-link.tsx b/src/routes/magic-link/$magic-link.tsx index 3cebf86..96a833c 100644 --- a/src/routes/magic-link/$magic-link.tsx +++ b/src/routes/magic-link/$magic-link.tsx @@ -115,6 +115,7 @@ function RouteComponent() { }; const handleConfirm = (fullCode: string) => { + console.log(fullCode); navigate({ to: "/auth/username", viewTransition: { types: ["warp"] },