feat(ui): admin-only root link and shared header navigation
CI / quality (push) Waiting to run

This commit is contained in:
MOH
2026-03-06 16:50:45 +01:00
parent 7a20cf5c75
commit ce63cd8b69
32 changed files with 1070 additions and 600 deletions
+43 -54
View File
@@ -7,6 +7,7 @@ import { useLocale, useTranslations } from "next-intl";
import { useState } from "react";
import { ThemeToggle } from "@/components/theme-toggle";
import { Button } from "@/src/components/ui/button";
const navItems = [
{ key: "home", path: "" },
@@ -14,21 +15,24 @@ const navItems = [
{ key: "products", path: "/products" },
{ key: "about", path: "/about" },
{ key: "contact", path: "/contact" },
{ key: "root", path: "/root" },
];
export function Navbar() {
type NavbarProps = {
isAdmin?: boolean;
};
export function Navbar({ isAdmin = false }: NavbarProps) {
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">
<header className="sticky top-0 z-40 border-b border-default bg-surface backdrop-blur">
<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"
className="inline-flex items-center rounded-md border border-input bg-card px-3 py-2 shadow-xs"
>
<Image
src="/logos/light-primary.svg"
@@ -49,80 +53,65 @@ export function Navbar() {
</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>
)
<Link
key={item.key}
href={`/${locale}${item.path}`}
className="text-sm text-muted transition hover:text-fg"
>
{t(item.key)}
</Link>
))}
{isAdmin ? (
<a href="/root" className="text-sm text-muted transition hover:text-fg">
{t("root")}
</a>
) : null}
</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"
>
<Button type="button" variant="outline" size="sm" className="text-xs">
{t("languagePlaceholder")}
</button>
</Button>
</div>
<button
<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"
variant="outline"
size="icon"
className="md:hidden"
aria-label={isOpen ? t("closeMenu") : t("openMenu")}
>
{isOpen ? <X className="h-4 w-4" /> : <Menu className="h-4 w-4" />}
</button>
</Button>
</div>
{isOpen ? (
<div className="border-t border-zinc-200 px-4 py-4 md:hidden dark:border-zinc-800">
<div className="border-t border-default px-4 py-4 md:hidden">
<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>
)
<Link
key={item.key}
href={`/${locale}${item.path}`}
className="text-sm text-muted"
onClick={() => setIsOpen(false)}
>
{t(item.key)}
</Link>
))}
{isAdmin ? (
<a href="/root" className="text-sm text-muted" onClick={() => setIsOpen(false)}>
{t("root")}
</a>
) : null}
</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"
>
<Button type="button" variant="outline" size="sm" className="text-xs">
{t("languagePlaceholder")}
</button>
</Button>
</div>
</div>
) : null}