544 lines
21 KiB
TypeScript
544 lines
21 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
Award,
|
|
BarChart3,
|
|
Bell,
|
|
Book,
|
|
BookOpen,
|
|
Brain,
|
|
ChevronRight,
|
|
FileCode,
|
|
FileText,
|
|
GraduationCap,
|
|
MessageSquare,
|
|
Users,
|
|
Video,
|
|
} from "lucide-react";
|
|
import { type LucideIcon } from "lucide-react";
|
|
import { useState } from "react";
|
|
|
|
import {
|
|
Accordion,
|
|
AccordionContent,
|
|
AccordionItem,
|
|
AccordionTrigger,
|
|
} from "@/components/ui/accordion";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
NavigationMenu,
|
|
NavigationMenuContent,
|
|
NavigationMenuItem,
|
|
NavigationMenuLink,
|
|
NavigationMenuList,
|
|
NavigationMenuTrigger,
|
|
navigationMenuTriggerStyle,
|
|
} from "@/components/ui/navigation-menu";
|
|
import { Separator } from "@/components/ui/separator";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface MenuItem {
|
|
title: string;
|
|
href: string;
|
|
description?: string;
|
|
icon: LucideIcon;
|
|
}
|
|
|
|
interface FeaturedContent {
|
|
title: string;
|
|
description: string;
|
|
href: string;
|
|
image: {
|
|
src: string;
|
|
alt: string;
|
|
};
|
|
}
|
|
|
|
interface MenuSection {
|
|
label: string;
|
|
items: MenuItem[];
|
|
}
|
|
|
|
interface MegaMenu {
|
|
label: string;
|
|
sections: MenuSection[];
|
|
featured?: FeaturedContent;
|
|
}
|
|
|
|
interface Navbar14Props {
|
|
logo?: {
|
|
src: string;
|
|
alt: string;
|
|
href?: string;
|
|
title?: string;
|
|
};
|
|
menus?: MegaMenu[];
|
|
links?: { label: string; href: string }[];
|
|
auth?: {
|
|
login: { label: string; href: string };
|
|
signup: { label: string; href: string };
|
|
};
|
|
className?: string;
|
|
}
|
|
|
|
const Navbar14 = ({
|
|
logo = {
|
|
src: "/block-media/shadcnblocks/block/logos/ShadcnBlocks-logo.svg",
|
|
alt: "لوگو",
|
|
href: "#",
|
|
title: "آکادمی سیگنا",
|
|
},
|
|
menus = [
|
|
{
|
|
label: "محصولات",
|
|
sections: [
|
|
{
|
|
label: "ابزارها",
|
|
items: [
|
|
{
|
|
title: "مدیریت مسیر یادگیری فروش",
|
|
description: "ساخت، سازماندهی و ارائه دورههای فروش",
|
|
icon: GraduationCap,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "تحلیل پیشرفت نمایندگان",
|
|
description: "پیگیری پیشرفت و عملکرد تیم فروش",
|
|
icon: BarChart3,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "تمرین تعاملی",
|
|
description: "تمرین مکالمه با سناریوهای واقعی",
|
|
icon: Video,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "کوچینگ هوشمند",
|
|
description: "مسیر یادگیری شخصی بر اساس نقش فروش",
|
|
icon: Brain,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "همکاری و بازخورد",
|
|
description: "ارتباط نماینده و مربی بدون اصطکاک",
|
|
icon: MessageSquare,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "ارزیابی و گواهی",
|
|
description: "سنجش آمادگی با آزمون نقش و مهارت",
|
|
icon: Award,
|
|
href: "#",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: "شروع سریع",
|
|
items: [
|
|
{
|
|
title: "آنبوردینگ نماینده",
|
|
icon: BookOpen,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "یافتن مربی",
|
|
icon: Users,
|
|
href: "#",
|
|
},
|
|
],
|
|
},
|
|
],
|
|
featured: {
|
|
title: "یک پلتفرم. هر نماینده.",
|
|
description: "مسیر یادگیری شخصی برای هر نقش فروش.",
|
|
href: "#",
|
|
image: {
|
|
src: "/block-media/shadcnblocks/block/placeholder-1.svg",
|
|
alt: "محتوای ویژه",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
label: "پشتیبانی",
|
|
sections: [
|
|
{
|
|
label: "راهنماها",
|
|
items: [
|
|
{
|
|
title: "مرکز یادگیری",
|
|
description: "نحوه استفاده مؤثر از آکادمی سیگنا",
|
|
icon: Book,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "فهرست دورهها",
|
|
description: "مرور کتابخانه دورههای فروش",
|
|
icon: BookOpen,
|
|
href: "#",
|
|
},
|
|
{
|
|
title: "مستندات API",
|
|
description: "یکپارچهسازی با CRM شما",
|
|
icon: FileCode,
|
|
href: "#",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: "درباره ما",
|
|
items: [
|
|
{ title: "بهروزرسانی پلتفرم", icon: FileText, href: "#" },
|
|
{ title: "اخبار و رویدادها", icon: Bell, href: "#" },
|
|
{ title: "وبلاگ توانمندسازی فروش", icon: Book, href: "#" },
|
|
{ title: "همکاری با ما", icon: Users, href: "#" },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
links = [{ label: "درباره ما", href: "#" }],
|
|
auth = {
|
|
login: { label: "ورود", href: "#" },
|
|
signup: { label: "درخواست دمو", href: "#" },
|
|
},
|
|
className,
|
|
}: Navbar14Props) => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
const hasDescription = (items: MenuItem[]) =>
|
|
items.some((item) => item.description);
|
|
|
|
return (
|
|
<section
|
|
lang="fa"
|
|
className={cn(
|
|
"border-b border-border bg-background text-start lg:border-b",
|
|
isOpen && "fixed inset-0 z-50 flex h-dvh flex-col border-b-0",
|
|
className,
|
|
)}
|
|
>
|
|
<div className="container mx-auto">
|
|
<nav className="flex items-center justify-between py-4">
|
|
<div className="flex flex-1 items-center gap-9">
|
|
<a href={logo.href} className="flex items-center gap-2">
|
|
<img src={logo.src} alt={logo.alt} className="h-8 dark:invert" />
|
|
{logo.title && (
|
|
<span className="text-lg font-semibold">{logo.title}</span>
|
|
)}
|
|
</a>
|
|
<div className="hidden items-center gap-1.5 lg:flex">
|
|
<NavigationMenu
|
|
dir="rtl"
|
|
viewport={false}
|
|
className="relative z-50"
|
|
>
|
|
<NavigationMenuList>
|
|
{menus.map((menu) => (
|
|
<NavigationMenuItem key={menu.label}>
|
|
<NavigationMenuTrigger className="text-start [&_svg]:ms-1 [&_svg]:!ml-0">
|
|
{menu.label}
|
|
</NavigationMenuTrigger>
|
|
<NavigationMenuContent
|
|
dir="rtl"
|
|
className="start-0 end-auto left-auto z-50 p-0 text-start"
|
|
>
|
|
<div className="flex flex-row-reverse">
|
|
<div className="p-4 text-start">
|
|
{menu.sections
|
|
.filter((s) => hasDescription(s.items))
|
|
.map((section, i) => (
|
|
<div key={section.label}>
|
|
{i > 0 && <Separator className="my-3" />}
|
|
<p className="mb-3 text-start text-[10px] text-muted-foreground uppercase">
|
|
{section.label}
|
|
</p>
|
|
{section.items.map((item) => (
|
|
<NavigationMenuLink
|
|
key={item.title}
|
|
asChild
|
|
>
|
|
<a
|
|
href={item.href}
|
|
className="group flex cursor-pointer flex-row gap-3 text-start"
|
|
>
|
|
<span className="flex size-10 shrink-0 items-center justify-center rounded-md border border-border bg-background">
|
|
<item.icon className="size-5!" />
|
|
</span>
|
|
<div className="flex min-w-0 flex-col text-start">
|
|
<span className="flex items-center gap-0.5 text-sm font-medium">
|
|
{item.title}
|
|
<ChevronRight className="size-4 text-primary! opacity-0 transition-all duration-200 group-hover:opacity-100 group-hover:translate-x-0.5 rtl:rotate-180 rtl:group-hover:-translate-x-0.5" />
|
|
</span>
|
|
{item.description && (
|
|
<p className="text-xs text-muted-foreground">
|
|
{item.description}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</a>
|
|
</NavigationMenuLink>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
<Separator
|
|
orientation="vertical"
|
|
className="data-[orientation=vertical]:h-auto"
|
|
/>
|
|
<div
|
|
className={cn(
|
|
"p-4 text-start",
|
|
menu.featured && "w-64 shrink-0",
|
|
)}
|
|
>
|
|
{menu.sections
|
|
.filter((s) => !hasDescription(s.items))
|
|
.map((section, i) => (
|
|
<div key={section.label}>
|
|
{i > 0 && (
|
|
<p className="mt-5 mb-3 text-start text-[10px] text-muted-foreground uppercase">
|
|
{section.label}
|
|
</p>
|
|
)}
|
|
{i === 0 && (
|
|
<p className="mb-3 text-start text-[10px] text-muted-foreground uppercase">
|
|
{section.label}
|
|
</p>
|
|
)}
|
|
<div>
|
|
{section.items.map((item) => (
|
|
<NavigationMenuLink
|
|
key={item.title}
|
|
asChild
|
|
>
|
|
<a
|
|
href={item.href}
|
|
className="flex flex-row items-center gap-3 text-start"
|
|
>
|
|
<item.icon className="size-4!" />
|
|
<span className="text-sm font-medium">
|
|
{item.title}
|
|
</span>
|
|
</a>
|
|
</NavigationMenuLink>
|
|
))}
|
|
</div>
|
|
</div>
|
|
))}
|
|
{menu.featured && (
|
|
<>
|
|
<p className="mt-5 mb-3 text-start text-[10px] text-muted-foreground uppercase">
|
|
آخرین بهروزرسانیها
|
|
</p>
|
|
<NavigationMenuLink asChild>
|
|
<a href={menu.featured.href}>
|
|
<div className="rounded-lg bg-primary p-3">
|
|
<img
|
|
src={menu.featured.image.src}
|
|
alt={menu.featured.image.alt}
|
|
className="aspect-video w-full rounded-md object-cover"
|
|
/>
|
|
</div>
|
|
</a>
|
|
</NavigationMenuLink>
|
|
<div className="mt-2 flex flex-col gap-1 px-1 text-start">
|
|
<p className="text-start text-xs font-medium">
|
|
{menu.featured.title}
|
|
</p>
|
|
<p className="text-start text-xs text-muted-foreground">
|
|
{menu.featured.description}
|
|
</p>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</NavigationMenuContent>
|
|
</NavigationMenuItem>
|
|
))}
|
|
{links.map((link) => (
|
|
<NavigationMenuItem key={link.label}>
|
|
<NavigationMenuLink
|
|
asChild
|
|
className={cn(
|
|
navigationMenuTriggerStyle(),
|
|
"text-start",
|
|
)}
|
|
>
|
|
<a href={link.href}>{link.label}</a>
|
|
</NavigationMenuLink>
|
|
</NavigationMenuItem>
|
|
))}
|
|
</NavigationMenuList>
|
|
</NavigationMenu>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="hidden items-center gap-2 lg:flex">
|
|
<Button variant="outline" asChild>
|
|
<a href={auth.login.href}>{auth.login.label}</a>
|
|
</Button>
|
|
<Button asChild>
|
|
<a href={auth.signup.href}>{auth.signup.label}</a>
|
|
</Button>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
className="flex size-10 items-center justify-center rounded-md border lg:hidden"
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
aria-expanded={isOpen}
|
|
aria-label={isOpen ? "بستن منو" : "باز کردن منو"}
|
|
>
|
|
<div className="flex w-3.5 flex-col gap-1">
|
|
<span
|
|
className={cn(
|
|
"h-[1.5px] w-full origin-center rounded-full bg-foreground transition-all duration-300",
|
|
isOpen && "translate-y-[5.5px] rotate-45",
|
|
)}
|
|
/>
|
|
<span
|
|
className={cn(
|
|
"h-[1.5px] w-full origin-center rounded-full bg-foreground transition-all duration-300",
|
|
isOpen && "scale-x-0 opacity-0",
|
|
)}
|
|
/>
|
|
<span
|
|
className={cn(
|
|
"h-[1.5px] w-full origin-center rounded-full bg-foreground transition-all duration-300",
|
|
isOpen && "-translate-y-[5.5px] -rotate-45",
|
|
)}
|
|
/>
|
|
</div>
|
|
</button>
|
|
</nav>
|
|
</div>
|
|
|
|
{isOpen && (
|
|
<div className="flex min-h-0 flex-1 animate-in flex-col overflow-y-auto border-t bg-background text-start duration-200 fade-in slide-in-from-top-2 lg:hidden">
|
|
<Accordion
|
|
type="single"
|
|
collapsible
|
|
dir="rtl"
|
|
className="w-full text-start"
|
|
>
|
|
{menus.map((menu) => (
|
|
<AccordionItem
|
|
key={menu.label}
|
|
value={menu.label}
|
|
className="border-b"
|
|
>
|
|
<AccordionTrigger className="container mx-auto items-center justify-start pe-10 text-start text-base font-medium hover:no-underline [&>svg]:ms-auto [&>svg]:me-0">
|
|
{menu.label}
|
|
</AccordionTrigger>
|
|
<AccordionContent className="container mx-auto text-start [&_a]:no-underline">
|
|
<div className="space-y-5">
|
|
{menu.sections.map((section, i) => (
|
|
<div key={section.label}>
|
|
{i > 0 && <Separator className="mb-5" />}
|
|
<p className="mb-3 text-start text-[10px] text-muted-foreground uppercase">
|
|
{section.label}
|
|
</p>
|
|
<div className="space-y-5">
|
|
{section.items.map((item) => (
|
|
<a
|
|
key={item.title}
|
|
href={item.href}
|
|
className={cn(
|
|
"flex cursor-pointer flex-row gap-3 rounded-md text-start transition-colors",
|
|
!item.description && "items-center",
|
|
)}
|
|
onClick={() => setIsOpen(false)}
|
|
>
|
|
{item.description ? (
|
|
<>
|
|
<span className="flex size-8 shrink-0 items-center justify-center rounded-md border border-border bg-background">
|
|
<item.icon className="size-4" />
|
|
</span>
|
|
<div className="flex min-w-0 flex-col text-start">
|
|
<span className="text-sm leading-tight font-medium">
|
|
{item.title}
|
|
</span>
|
|
<p className="text-xs leading-tight text-muted-foreground">
|
|
{item.description}
|
|
</p>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
<item.icon className="size-4" />
|
|
<span className="text-sm font-medium">
|
|
{item.title}
|
|
</span>
|
|
</>
|
|
)}
|
|
</a>
|
|
))}
|
|
</div>
|
|
</div>
|
|
))}
|
|
{menu.featured && (
|
|
<>
|
|
<Separator />
|
|
<div className="text-start">
|
|
<p className="mb-3 text-start text-[10px] text-muted-foreground uppercase">
|
|
آخرین بهروزرسانیها
|
|
</p>
|
|
<a
|
|
href={menu.featured.href}
|
|
onClick={() => setIsOpen(false)}
|
|
>
|
|
<div className="rounded-lg bg-primary p-3">
|
|
<img
|
|
src={menu.featured.image.src}
|
|
alt={menu.featured.image.alt}
|
|
className="aspect-video w-full rounded-md object-cover"
|
|
/>
|
|
</div>
|
|
</a>
|
|
<div className="mt-2 flex flex-col gap-1 px-1 text-start">
|
|
<span className="text-xs font-medium">
|
|
{menu.featured.title}
|
|
</span>
|
|
<span className="text-xs text-muted-foreground">
|
|
{menu.featured.description}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
))}
|
|
</Accordion>
|
|
|
|
{links.map((link) => (
|
|
<a
|
|
key={link.label}
|
|
href={link.href}
|
|
className="block border-b border-border py-4 text-start text-base font-medium transition-colors"
|
|
>
|
|
<span className="container mx-auto block text-start">
|
|
{link.label}
|
|
</span>
|
|
</a>
|
|
))}
|
|
|
|
<div className="container mx-auto mt-auto flex flex-col gap-2 py-8">
|
|
<Button variant="outline" className="w-full" asChild>
|
|
<a href={auth.login.href}>{auth.login.label}</a>
|
|
</Button>
|
|
<Button className="w-full" asChild>
|
|
<a href={auth.signup.href}>{auth.signup.label}</a>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { Navbar14 };
|