create main menu and dropdown menu

This commit is contained in:
yzned
2025-07-20 19:53:42 +03:00
committed by yzned
parent bba27be7e2
commit 0ce3c0307f
10 changed files with 240 additions and 66 deletions

View File

@@ -4,16 +4,19 @@ 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 ThreeDots from "@/icons/three-dots.svg?react";
import Settings from "@/icons/settings.svg?react";
import SignOut from "@/icons/sign-out.svg?react";
import { LINKS } from "@/lib/constants";
import { useEffect, useRef, useState, type ReactNode } from "react";
import { Button, type ButtonVariantType } from "../ui/button";
import { Link, useMatchRoute, useParams } from "@tanstack/react-router";
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";
import { ChatCell } from "./chat-cell";
import { Dropdown } from "../ui/dropdown";
interface MenuItemType extends ButtonVariantType {
name: string;
@@ -21,27 +24,6 @@ interface MenuItemType extends ButtonVariantType {
path: string;
}
const MENU_ITEMS: MenuItemType[] = [
{
name: "New Chat",
icon: <Plus className="scale-80" />,
path: "/",
variant: "primary",
},
{
name: "All chats",
icon: <Books className="scale-90" />,
path: "/all-chats",
variant: "secondary",
},
{
name: "Support",
icon: <Discord width={12} height={12} className="text-[#5865F2]" />,
path: LINKS.discord,
variant: "secondary",
},
];
const MainMenu = observer(() => {
const { isMainMenuOpen } = useAccountStore();
@@ -61,6 +43,8 @@ const MOCK_CHATS = Array.from({ length: 20 }, (_, i) => ({
}));
const MainMenuContent = observer(() => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const { isMainMenuOpen, setIsMainMenuOpen } = useAccountStore();
const containerRef = useRef<HTMLDivElement>(null);
const [hasScrolled, setHasScrolled] = useState(false);
@@ -81,6 +65,25 @@ const MainMenuContent = observer(() => {
};
}, []);
const DROPDOWN_OPTIONS = [
{
name: "user-mail",
icon: <Profile />,
onClick: () => console.log("1"),
className: "text-text-light-500",
},
{
name: "Settings",
icon: <Settings />,
onClick: () => console.log("2"),
},
{
name: "Sigh out",
icon: <SignOut />,
onClick: () => console.log("3"),
},
];
return (
<div
data-open={isMainMenuOpen}
@@ -145,20 +148,28 @@ const MainMenuContent = observer(() => {
</ul>
</div>
<footer className="sticky bottom-0 z-10 bg-white w-full p-4 border-t border-fill-150">
<Button
data-open={isMainMenuOpen}
className="w-8 h-8 p-2 transition-all data-[open=true]:w-full data-[open=true]:h-10 items-center justify-start data-[open=true]:py-2 data-[open=true]:px-4"
variant="secondary"
<footer className="sticky bottom-0 z-10 bg-white w-full p-4 border-t border-fill-150 w-full">
<Dropdown
options={DROPDOWN_OPTIONS}
isOpen={isDropdownOpen}
onToggle={() => setIsDropdownOpen(!isDropdownOpen)}
classNameContent="min-w-[200px]"
classNameTrigger="w-[195px]"
>
<Profile />
<div
<Button
data-open={isMainMenuOpen}
className="data-[open=true]:opacity-100 opacity-0 transition-opacity duration-200 font-[500] text-[14px]"
className="w-8 h-8 p-2 transition-all data-[open=true]:w-full data-[open=true]:h-10 items-center justify-start data-[open=true]:py-2 data-[open=true]:px-4"
variant="secondary"
>
username
</div>
</Button>
<Profile />
<div
data-open={isMainMenuOpen}
className="data-[open=true]:opacity-100 opacity-0 transition-opacity duration-200 font-[500] text-[14px]"
>
username
</div>
</Button>
</Dropdown>
</footer>
</div>
);
@@ -190,37 +201,25 @@ const MenuItem = ({ item }: { item: MenuItemType }) => {
);
};
const ChatCell = ({ chat }: { chat: { id: string; title: string } }) => {
const matchRoute = useMatchRoute();
const match = matchRoute({ to: "/interaction-panel/$id", fuzzy: true });
const activeChatId = match ? match.id : undefined;
return (
<div
data-active={activeChatId === chat.id}
className="data-[active=true]:bg-fill-150 block rounded-md h-10 hover:bg-fill-100 cursor-pointer transition-colors group flex items-center"
>
<Link
to="/interaction-panel/$id"
params={{ id: chat.id }}
viewTransition={{ types: ["warp"] }}
key={chat.id}
className="flex-1 h-full items-center flex pl-3"
>
<div className="text-sm font-medium text-text-light-900 truncate">
{chat.title}
</div>
</Link>
<button
className="opacity-0 group-hover:opacity-100 duration-300 cursor-pointer flex items-center pr-3 justify-end w-5 h-full"
type="button"
>
<ThreeDots />
</button>
</div>
);
};
const MENU_ITEMS: MenuItemType[] = [
{
name: "New Chat",
icon: <Plus className="scale-80" />,
path: "/",
variant: "primary",
},
{
name: "All chats",
icon: <Books className="scale-90" />,
path: "/all-chats",
variant: "secondary",
},
{
name: "Support",
icon: <Discord width={12} height={12} className="text-[#5865F2]" />,
path: LINKS.discord,
variant: "secondary",
},
];
export { MainMenu, MenuItem, MENU_ITEMS, MainMenuContent };