feat: all project setup

This commit is contained in:
ivannoskov
2025-11-10 12:07:24 +03:00
parent fbfd7719bb
commit b0a9934220
99 changed files with 19597 additions and 0 deletions

159
components/nav-main.tsx Normal file
View File

@@ -0,0 +1,159 @@
"use client";
import { ChevronRight, type LucideIcon } from "lucide-react";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import {
SidebarGroup,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
useSidebar,
} from "@/components/ui/sidebar";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { usePathname } from "next/navigation";
import Link from "next/link";
import * as React from "react";
export function NavMain({
items,
}: {
items: {
title: string;
url: string;
icon?: LucideIcon;
isActive?: boolean;
items?: {
title: string;
url: string;
}[];
}[];
}) {
const pathname = usePathname();
const { state } = useSidebar();
const isCollapsed = state === "collapsed";
return (
<SidebarGroup>
<SidebarMenu>
{items.map((item) => {
const hasSubmenu = item.items && item.items.length > 0;
const isActive = pathname === item.url;
const hasActiveSubmenu =
hasSubmenu && item.items!.some((sub) => pathname === sub.url);
// В свернутом состоянии показываем DropdownMenu для элементов с подменю
if (isCollapsed && hasSubmenu) {
return (
<SidebarMenuItem key={item.title}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton
tooltip={item.title}
isActive={isActive || hasActiveSubmenu}
>
{item.icon && <item.icon />}
<span>{item.title}</span>
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
side="right"
align="start"
className="min-w-[200px]"
>
{item.items!.map((subItem) => {
const isSubActive = pathname === subItem.url;
return (
<DropdownMenuItem key={subItem.title} asChild>
<Link
href={subItem.url}
className={
isSubActive
? "bg-accent text-accent-foreground"
: ""
}
>
{subItem.title}
</Link>
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
);
}
// Обычное отображение для развернутого состояния
return (
<Collapsible
key={item.title}
asChild
defaultOpen={isActive || hasActiveSubmenu}
className="group/collapsible"
>
<SidebarMenuItem>
{hasSubmenu ? (
<>
<CollapsibleTrigger asChild>
<SidebarMenuButton
tooltip={item.title}
isActive={isActive || hasActiveSubmenu}
>
{item.icon && <item.icon />}
<span>{item.title}</span>
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
</SidebarMenuButton>
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{item.items!.map((subItem) => {
const isSubActive = pathname === subItem.url;
return (
<SidebarMenuSubItem key={subItem.title}>
<SidebarMenuSubButton
asChild
isActive={isSubActive}
>
<Link href={subItem.url}>
<span>{subItem.title}</span>
</Link>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
);
})}
</SidebarMenuSub>
</CollapsibleContent>
</>
) : (
<SidebarMenuButton
asChild
tooltip={item.title}
isActive={isActive}
>
<Link href={item.url}>
{item.icon && <item.icon />}
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
)}
</SidebarMenuItem>
</Collapsible>
);
})}
</SidebarMenu>
</SidebarGroup>
);
}