Files
reui-blocks/blocks/navbar17.tsx
T

198 lines
6.3 KiB
TypeScript

"use client";
import { Menu, X } from "lucide-react";
import React, { useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
} from "@/components/ui/navigation-menu";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { cn } from "@/lib/utils";
const NAV_LOGO = {
url: "https://www.ShadcnBlocks",
src: "/block-media/shadcnblocks/block/logos/ShadcnBlockscom-icon.svg",
alt: "لوگو",
title: "وندوک",
};
const NAV_ITEMS = [
{ name: "خانه", link: "#" },
{ name: "درباره ما", link: "#" },
{ name: "قیمت‌گذاری", link: "#" },
{ name: "تماس", link: "#" },
];
interface Navbar17Props {
className?: string;
}
const Navbar17 = ({ className }: Navbar17Props) => {
const [activeItem, setActiveItem] = useState(NAV_ITEMS[0].name);
const indicatorRef = useRef<HTMLDivElement>(null);
const menuRef = useRef<HTMLUListElement>(null);
useEffect(() => {
const updateIndicator = () => {
const activeEl = document.querySelector(
`[data-nav-item="${activeItem}"]`,
) as HTMLElement;
if (activeEl && indicatorRef.current && menuRef.current) {
const menuRect = menuRef.current.getBoundingClientRect();
const itemRect = activeEl.getBoundingClientRect();
indicatorRef.current.style.width = `${itemRect.width}px`;
indicatorRef.current.style.insetInlineStart = `${itemRect.left - menuRect.left}px`;
indicatorRef.current.style.left = "auto";
}
};
updateIndicator();
window.addEventListener("resize", updateIndicator);
return () => window.removeEventListener("resize", updateIndicator);
}, [activeItem]);
return (
<section lang="fa" className={cn("py-4 text-start", className)}>
<nav className="container flex items-center justify-between">
<a href={NAV_LOGO.url} className="flex items-center gap-2">
<img src={NAV_LOGO.src} className="max-h-8 w-8" alt={NAV_LOGO.alt} />
<span className="text-lg font-semibold tracking-tighter">
{NAV_LOGO.title}
</span>
</a>
<NavigationMenu className="hidden lg:block" dir="rtl">
<NavigationMenuList
ref={menuRef}
className="relative flex items-center gap-6 rounded-4xl px-8 py-3"
>
{NAV_ITEMS.map((item) => (
<NavigationMenuItem key={item.name}>
<NavigationMenuLink
data-nav-item={item.name}
onClick={() => setActiveItem(item.name)}
className={cn(
"relative cursor-pointer text-start text-sm font-medium hover:bg-transparent",
activeItem === item.name
? "text-foreground"
: "text-muted-foreground",
)}
>
{item.name}
</NavigationMenuLink>
</NavigationMenuItem>
))}
<div
ref={indicatorRef}
className="absolute bottom-2 flex h-1 items-center justify-center px-2 transition-all duration-300"
>
<div className="h-0.5 w-full rounded-t-none bg-foreground transition-all duration-300" />
</div>
</NavigationMenuList>
</NavigationMenu>
<MobileNav activeItem={activeItem} setActiveItem={setActiveItem} />
<div className="hidden items-center gap-2 lg:flex">
<Button
variant="outline"
size="sm"
className="h-10 py-2.5 text-sm font-normal"
>
شروع رایگان
</Button>
</div>
</nav>
</section>
);
};
export { Navbar17 };
const AnimatedHamburger = ({ isOpen }: { isOpen: boolean }) => {
return (
<div className="group relative size-full">
<div className="absolute flex size-full items-center justify-center">
<Menu
className={cn(
"absolute size-6 text-muted-foreground transition-all duration-300 group-hover:text-foreground",
isOpen ? "rotate-90 opacity-0" : "rotate-0 opacity-100",
)}
/>
<X
className={cn(
"absolute size-6 text-muted-foreground transition-all duration-300 group-hover:text-foreground",
isOpen ? "rotate-0 opacity-100" : "-rotate-90 opacity-0",
)}
/>
</div>
</div>
);
};
const MobileNav = ({
activeItem,
setActiveItem,
}: {
activeItem: string;
setActiveItem: (item: string) => void;
}) => {
const [isOpen, setIsOpen] = useState(false);
return (
<div className="flex h-full items-center lg:hidden">
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger asChild>
<Button
variant="ghost"
size="icon"
aria-expanded={isOpen}
aria-label={isOpen ? "بستن منو" : "باز کردن منو"}
>
<AnimatedHamburger isOpen={isOpen} />
</Button>
</PopoverTrigger>
<PopoverContent
dir="rtl"
align="start"
className="relative top-4 -end-4 block w-[calc(100vw-32px)] overflow-hidden rounded-xl p-0 text-start start-auto end-0 sm:top-auto sm:end-auto sm:w-80 lg:hidden"
>
<ul className="w-full bg-background py-4 text-start text-foreground">
{NAV_ITEMS.map((navItem) => (
<li key={navItem.name}>
<a
href={navItem.link}
onClick={() => setActiveItem(navItem.name)}
className={cn(
"flex items-center border-s-[3px] px-6 py-4 text-start text-sm font-medium transition-all duration-75",
activeItem === navItem.name
? "border-foreground text-foreground"
: "border-transparent text-muted-foreground hover:text-foreground",
)}
>
{navItem.name}
</a>
</li>
))}
<li className="flex flex-col px-7 py-2">
<Button variant="outline">شروع رایگان</Button>
</li>
</ul>
</PopoverContent>
</Popover>
</div>
);
};