ldc-qualimaine/resources/ts/front/Components/Layout/Navbar.tsx
2026-07-24 17:19:24 +02:00

182 lines
6 KiB
TypeScript

import { Link, usePage } from "@inertiajs/react";
import { ChevronDown, Menu, X } from "lucide-react";
import { useState } from "react";
import logo from "&/images/global/logo-qualimaine-RVB-defaut.png";
import useTrans from "@/hooks/use-translations";
import { GetTranslation } from "@/lib/utils";
interface NavLinkResolved {
label: string;
href: string;
resolvedHref: string;
}
const NAV_LINKS = [
{ label: "front.menus.about_us", href: "front.whoAreWeSection.slug" },
{ label: "front.menus.engagements", href: "front.engagements.slug" },
{ label: "front.menus.normes", href: "norms.slug" },
{ label: "front.menus.contact", href: "footer.contactSlug" },
];
function useSectionHref(slugKey: string) {
const { url, props } = usePage() as unknown as {
url: string;
props: { appEnv: { locales: string[] } };
};
const slug = useTrans(slugKey);
const isHome =
url === "/" || props.appEnv.locales.some((locale) => url === `/${locale}`);
if (isHome) return `#${slug}`;
return `${route("front.homepage")}#${slug}`;
}
function LanguageDropdown() {
const { appEnv, localizedUrls } = usePage().props as unknown as {
appEnv: { locale: string; locales: string[] };
localizedUrls: Record<string, string>;
};
const [open, setOpen] = useState(false);
const otherLocales = appEnv.locales.filter(
(locale) => locale !== appEnv.locale,
);
return (
<div className="relative w-16">
<button
onClick={() => {
setOpen((v) => !v);
}}
className={`relative flex w-full items-center justify-center border border-neutral-700 bg-white/10 pl-4 pr-3 py-1 font-sans text-[16px] font-bold text-neutral-700 backdrop-blur-sm transition-colors hover:bg-white/10 ${
open ? "rounded-t-3xl border-b-0" : "rounded-3xl"
}`}
>
<span className="invisible w-3.5" aria-hidden="true" />
<span className="flex-1 text-center">
{appEnv.locale.toUpperCase()}
</span>
<ChevronDown
size={28}
className={`w-64 transition-transform ${open ? "rotate-180" : ""}`}
/>
</button>
{open && (
<div className="absolute inset-x-0 top-full z-50 overflow-hidden rounded-b-3xl border border-t-0 border-neutral-700 bg-white/10 backdrop-blur-sm">
{otherLocales.map((locale) => (
<a
key={locale}
href={localizedUrls[locale]}
className="flex items-center justify-end px-3 py-1.5 font-sans text-[16px] font-bold text-neutral-700"
>
<span className="rounded-full px-2.5 py-1 transition-colors hover:bg-white/60">
{locale.toUpperCase()}
</span>
</a>
))}
</div>
)}
</div>
);
}
export default function Navbar() {
const [mobileOpen, setMobileOpen] = useState(false);
const navLinks: NavLinkResolved[] = [
{ ...NAV_LINKS[0], resolvedHref: useSectionHref(NAV_LINKS[0].href) },
{ ...NAV_LINKS[1], resolvedHref: useSectionHref(NAV_LINKS[1].href) },
{ ...NAV_LINKS[2], resolvedHref: useSectionHref(NAV_LINKS[2].href) },
{ ...NAV_LINKS[3], resolvedHref: useSectionHref(NAV_LINKS[3].href) },
];
return (
<div className="relative z-20 w-full">
<div className="flex w-full items-center justify-between px-6 py-5 md:px-10">
<Link href={route("front.homepage")}>
<img
src={logo}
alt={useTrans("front.logo_alt")}
title={useTrans("front.logo_title")}
className="h-18 w-auto md:h-26 mt-4"
/>
</Link>
<nav className="hidden items-center gap-7 md:flex">
{navLinks.map((link) => (
<Link
key={GetTranslation(link.href)}
href={link.resolvedHref}
className="rounded-3xl px-2 py-1.5 font-sans text-lg font-bold text-neutral-800 transition-colors hover:bg-band"
>
{GetTranslation(link.label)}
</Link>
))}
<LanguageDropdown />
</nav>
<div className="flex items-center gap-3 md:hidden">
<LanguageDropdown />
<button
onClick={() => {
setMobileOpen((v) => !v);
}}
aria-label="Menu"
className="p-2"
>
{mobileOpen ? <X size={28} /> : <Menu size={28} />}
</button>
</div>
</div>
{mobileOpen && (
<div className="fixed inset-0 z-2000 flex flex-col bg-band md:hidden">
<div className="flex items-center justify-between px-6 py-5">
<Link
href="/"
onClick={() => {
setMobileOpen(false);
}}
>
<img
src={logo}
alt={GetTranslation("front.logo_alt")}
title={GetTranslation("front.logo_title")}
className="h-18 w-auto"
/>
</Link>
<div className="flex items-center gap-3">
<button
onClick={() => {
setMobileOpen(false);
}}
aria-label=""
className="p-2"
>
<X size={28} className="text-neutral-800" />
</button>
<LanguageDropdown />
</div>
</div>
<nav className="mt-[25%] flex flex-1 flex-col items-center justify-start gap-5 px-8">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.resolvedHref}
className="w-full max-w-[280px] rounded-full bg-[#4b4b45] py-3 text-center font-sans text-[18px] font-bold text-white shadow-md transition-colors hover:bg-[#FFD41F] hover:text-black"
onClick={() => {
setMobileOpen(false);
}}
>
{GetTranslation(link.label)}
</Link>
))}
</nav>
</div>
)}
</div>
);
}