192 lines
6.4 KiB
TypeScript
192 lines
6.4 KiB
TypeScript
"use client";
|
||
|
||
import { AnimatePresence, motion } from "framer-motion";
|
||
import { ArrowUpRight } from "lucide-react";
|
||
import { useState } from "react";
|
||
|
||
import { cn } from "@/lib/utils";
|
||
|
||
const NAV_ITEMS = [
|
||
{ label: "خانه", href: "#" },
|
||
{ label: "ماژولها", href: "#" },
|
||
{ label: "تغییرات نسخه", href: "#" },
|
||
{ label: "تماس", href: "#" },
|
||
];
|
||
|
||
const MEGA_MENU_ITEMS = [
|
||
[
|
||
{ label: "خانه", href: "#" },
|
||
{ label: "درباره ما", href: "#" },
|
||
{ label: "راهحلها", href: "#" },
|
||
{ label: "مطالعات موردی", href: "#" },
|
||
{ label: "وبلاگ", href: "#" },
|
||
{ label: "تماس", href: "#" },
|
||
],
|
||
[
|
||
{ label: "ویژگیها", href: "#" },
|
||
{ label: "ماژول", href: "#" },
|
||
{ label: "قالب کمپین", href: "#" },
|
||
{ label: "نمونههای جریان", href: "#" },
|
||
{ label: "منابع", href: "#" },
|
||
{ label: "پشتیبانی", href: "#" },
|
||
],
|
||
[
|
||
{ label: "قیمتگذاری", href: "#" },
|
||
{ label: "سازمانی", href: "#" },
|
||
{ label: "شراکتها", href: "#" },
|
||
{ label: "فرصتهای شغلی", href: "#" },
|
||
{ label: "مطبوعات", href: "#" },
|
||
{ label: "حقوقی", href: "#" },
|
||
],
|
||
[
|
||
{ label: "توییتر", href: "#" },
|
||
{ label: "وضعیت سرویس", href: "#" },
|
||
{ label: "انجمن", href: "#" },
|
||
{ label: "لینکدین", href: "#" },
|
||
{ label: "یوتیوب", href: "#" },
|
||
{ label: "خبرنامه", href: "#" },
|
||
],
|
||
];
|
||
|
||
const MOBILE_NAV_ITEMS = [
|
||
{ label: "خانه", href: "#" },
|
||
{ label: "درباره ما", href: "#" },
|
||
{ label: "راهحلها", href: "#" },
|
||
{ label: "مطالعات موردی", href: "#" },
|
||
{ label: "وبلاگ", href: "#" },
|
||
{ label: "تماس", href: "#" },
|
||
{ label: "ورود", href: "#" },
|
||
{ label: "قیمتگذاری", href: "#" },
|
||
];
|
||
|
||
const FOOTER_LINKS = [
|
||
{ label: "حریم خصوصی", href: "#" },
|
||
{ label: "شرایط استفاده", href: "#" },
|
||
];
|
||
|
||
const COMPANY_LINKS = [
|
||
{ label: "+۱ (۱۲۰) ۲۳۳-۱۲۳۱", href: "#" },
|
||
{ label: "۱۴۰۴© برندلینک", href: "#" },
|
||
];
|
||
|
||
interface Navbar29Props {
|
||
className?: string;
|
||
}
|
||
|
||
const Navbar29 = ({ className }: Navbar29Props) => {
|
||
const [isOpen, setIsOpen] = useState(false);
|
||
|
||
return (
|
||
<section dir="rtl" lang="fa" className={cn("text-right", className)}>
|
||
<nav className="relative overflow-visible">
|
||
<ul className="relative z-1 flex w-full items-center justify-between gap-4 p-6 text-lg font-semibold tracking-tight">
|
||
<li className="w-35">برندلینک</li>
|
||
{NAV_ITEMS.map((item) => (
|
||
<li key={item.label} className="hidden w-32 lg:block">
|
||
<a
|
||
href={item.href}
|
||
className="transition-colors hover:text-foreground/70"
|
||
>
|
||
{item.label}
|
||
</a>
|
||
</li>
|
||
))}
|
||
<li className="lg:w-14">
|
||
<Menu setIsOpen={setIsOpen} isOpen={isOpen} />
|
||
</li>
|
||
</ul>
|
||
|
||
<AnimatePresence mode="popLayout">
|
||
{isOpen && (
|
||
<motion.div
|
||
className="absolute top-0 w-full bg-muted px-6 pt-30 pb-10 text-right"
|
||
initial={{ clipPath: "inset(0 0 100% 0)" }}
|
||
animate={{ clipPath: "inset(0% 0 0 0)" }}
|
||
exit={{ clipPath: "inset(0 0 100% 0)" }}
|
||
transition={{
|
||
duration: 0.35,
|
||
ease: [0.4, 0.0, 0.2, 1],
|
||
}}
|
||
>
|
||
<div className="flex lg:hidden">
|
||
<ul className="flex w-full flex-col gap-5 text-xl font-semibold tracking-tight">
|
||
{MOBILE_NAV_ITEMS.map((item) => (
|
||
<li key={item.label}>
|
||
<a href={item.href}>{item.label}</a>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
<div className="hidden w-full items-center justify-between gap-4 lg:flex">
|
||
<div className="w-35 opacity-0">برندلینک</div>
|
||
{MEGA_MENU_ITEMS.map((section, sectionIndex) => (
|
||
<ul key={sectionIndex} className="space-y-5">
|
||
{section.map((item) => (
|
||
<li
|
||
key={item.label}
|
||
className={cn(
|
||
"group flex w-32 items-center gap-1 text-foreground/40 hover:text-foreground",
|
||
)}
|
||
>
|
||
<a href={item.href}>{item.label}</a>
|
||
<ArrowUpRight className="size-4 translate-y-2 opacity-0 transition-all ease-out group-hover:translate-y-0 group-hover:opacity-100 rtl:rotate-180" />
|
||
</li>
|
||
))}
|
||
</ul>
|
||
))}
|
||
<div className="w-14" />
|
||
</div>
|
||
<div className="mt-40 flex w-full flex-col items-center justify-between gap-2 text-sm lg:flex-row lg:gap-4 lg:text-base">
|
||
<div className="flex items-center gap-4 lg:gap-10">
|
||
{COMPANY_LINKS.map((item) => (
|
||
<p key={item.label}>{item.label}</p>
|
||
))}
|
||
</div>
|
||
<div className="flex items-center gap-4 lg:gap-10">
|
||
{FOOTER_LINKS.map((item) => (
|
||
<p key={item.label}>{item.label}</p>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
)}
|
||
</AnimatePresence>
|
||
</nav>
|
||
</section>
|
||
);
|
||
};
|
||
|
||
export { Navbar29 };
|
||
|
||
const Menu = ({
|
||
className,
|
||
setIsOpen,
|
||
isOpen,
|
||
}: {
|
||
className?: string;
|
||
setIsOpen: (value: boolean | ((prev: boolean) => boolean)) => void;
|
||
isOpen: boolean;
|
||
}) => {
|
||
return (
|
||
<button
|
||
type="button"
|
||
className={cn(
|
||
"relative flex h-2 w-8 flex-col items-center justify-center gap-2 after:absolute after:h-12 after:w-full lg:w-14",
|
||
className,
|
||
)}
|
||
onClick={() => setIsOpen((x: boolean) => !x)}
|
||
aria-expanded={isOpen}
|
||
aria-label={isOpen ? "بستن منو" : "باز کردن منو"}
|
||
>
|
||
<motion.div
|
||
animate={{ y: isOpen ? 0 : 5, rotate: isOpen ? 45 : 0 }}
|
||
className="absolute h-0.5 w-full bg-foreground"
|
||
/>
|
||
<motion.div
|
||
animate={{ y: isOpen ? 0 : -5, rotate: isOpen ? -45 : 0 }}
|
||
className="absolute h-0.5 w-full bg-foreground"
|
||
/>
|
||
</button>
|
||
);
|
||
};
|