132 lines
4.5 KiB
TypeScript
132 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import { Menu, X } from "lucide-react";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { useLocale, useTranslations } from "next-intl";
|
|
import { useState } from "react";
|
|
|
|
import { ThemeToggle } from "@/components/theme-toggle";
|
|
|
|
const navItems = [
|
|
{ key: "home", path: "" },
|
|
{ key: "portfolio", path: "/portfolio" },
|
|
{ key: "products", path: "/products" },
|
|
{ key: "about", path: "/about" },
|
|
{ key: "contact", path: "/contact" },
|
|
{ key: "root", path: "/root" },
|
|
];
|
|
|
|
export function Navbar() {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const locale = useLocale();
|
|
const t = useTranslations("navigation");
|
|
|
|
return (
|
|
<header className="sticky top-0 z-40 border-b border-zinc-200 bg-white/95 backdrop-blur dark:border-zinc-800 dark:bg-zinc-950/95">
|
|
<div className="mx-auto flex w-full max-w-6xl items-center justify-between gap-4 px-4 py-3 sm:px-6 lg:px-8">
|
|
<div className="flex items-center gap-3">
|
|
<Link
|
|
href={`/${locale}`}
|
|
className="inline-flex items-center rounded-md border border-zinc-300 bg-white px-3 py-2 dark:border-zinc-700 dark:bg-zinc-950"
|
|
>
|
|
<Image
|
|
src="/logos/light-primary.svg"
|
|
alt="mohfarawati logo"
|
|
width={140}
|
|
height={24}
|
|
className="block h-6 w-auto dark:hidden"
|
|
priority
|
|
/>
|
|
<Image
|
|
src="/logos/dark-primary.svg"
|
|
alt="mohfarawati logo"
|
|
width={140}
|
|
height={24}
|
|
className="hidden h-6 w-auto dark:block"
|
|
priority
|
|
/>
|
|
</Link>
|
|
<nav className="hidden items-center gap-5 md:flex">
|
|
{navItems.map((item) => (
|
|
item.key === "root" ? (
|
|
<a
|
|
key={item.key}
|
|
href="/root"
|
|
className="text-sm text-zinc-700 transition hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-zinc-100"
|
|
>
|
|
{t(item.key)}
|
|
</a>
|
|
) : (
|
|
<Link
|
|
key={item.key}
|
|
href={`/${locale}${item.path}`}
|
|
className="text-sm text-zinc-700 transition hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-zinc-100"
|
|
>
|
|
{t(item.key)}
|
|
</Link>
|
|
)
|
|
))}
|
|
</nav>
|
|
</div>
|
|
|
|
<div className="hidden items-center gap-2 md:flex">
|
|
<ThemeToggle />
|
|
<button
|
|
type="button"
|
|
className="rounded-md border border-zinc-300 px-3 py-2 text-xs font-medium text-zinc-600 dark:border-zinc-700 dark:text-zinc-300"
|
|
>
|
|
{t("languagePlaceholder")}
|
|
</button>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={() => setIsOpen((open) => !open)}
|
|
className="inline-flex h-9 w-9 items-center justify-center rounded-md border border-zinc-300 text-zinc-700 md:hidden dark:border-zinc-700 dark:text-zinc-200"
|
|
aria-label={isOpen ? t("closeMenu") : t("openMenu")}
|
|
>
|
|
{isOpen ? <X className="h-4 w-4" /> : <Menu className="h-4 w-4" />}
|
|
</button>
|
|
</div>
|
|
|
|
{isOpen ? (
|
|
<div className="border-t border-zinc-200 px-4 py-4 md:hidden dark:border-zinc-800">
|
|
<nav className="flex flex-col gap-3">
|
|
{navItems.map((item) => (
|
|
item.key === "root" ? (
|
|
<a
|
|
key={item.key}
|
|
href="/root"
|
|
className="text-sm text-zinc-700 dark:text-zinc-300"
|
|
onClick={() => setIsOpen(false)}
|
|
>
|
|
{t(item.key)}
|
|
</a>
|
|
) : (
|
|
<Link
|
|
key={item.key}
|
|
href={`/${locale}${item.path}`}
|
|
className="text-sm text-zinc-700 dark:text-zinc-300"
|
|
onClick={() => setIsOpen(false)}
|
|
>
|
|
{t(item.key)}
|
|
</Link>
|
|
)
|
|
))}
|
|
</nav>
|
|
<div className="mt-4 flex items-center gap-2">
|
|
<ThemeToggle />
|
|
<button
|
|
type="button"
|
|
className="rounded-md border border-zinc-300 px-3 py-2 text-xs font-medium text-zinc-600 dark:border-zinc-700 dark:text-zinc-300"
|
|
>
|
|
{t("languagePlaceholder")}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</header>
|
|
);
|
|
}
|