130 lines
5.7 KiB
TypeScript
130 lines
5.7 KiB
TypeScript
import { Link } from '@inertiajs/react';
|
|
import { useState } from 'react';
|
|
import Brand from '@/components/site/brand';
|
|
import { ButtonLink } from '@/components/site/button';
|
|
import Container from '@/components/site/container';
|
|
import Icon from '@/components/site/icon';
|
|
import LanguageToggle from '@/components/site/language-toggle';
|
|
import ThemeToggle from '@/components/site/theme-toggle';
|
|
import { common } from '@/content/common';
|
|
import { consultationUrl, navigation } from '@/data/site';
|
|
import { useCurrentUrl } from '@/hooks/use-current-url';
|
|
import { useContent } from '@/hooks/use-locale';
|
|
import { useSiteInfo } from '@/hooks/use-site-info';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
export default function SiteHeader() {
|
|
const site = useSiteInfo();
|
|
const t = useContent(common);
|
|
const { isCurrentUrl } = useCurrentUrl();
|
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
const closeMenu = () => setMenuOpen(false);
|
|
|
|
return (
|
|
<header className="border-outline-variant/40 bg-surface/85 fixed inset-x-0 top-0 z-50 border-b backdrop-blur-md">
|
|
<Container className="flex h-20 items-center justify-between gap-4">
|
|
<Brand />
|
|
|
|
<nav
|
|
aria-label={t.header.mainNav}
|
|
className="hidden items-center gap-8 lg:flex"
|
|
>
|
|
{navigation.map((item) => (
|
|
<Link
|
|
key={item.key}
|
|
href={item.href}
|
|
className={cn(
|
|
'hover:border-primary hover:text-on-surface border-b-2 pb-1 text-sm font-medium transition-all',
|
|
isCurrentUrl(item.href)
|
|
? 'border-primary text-on-surface font-semibold'
|
|
: 'text-on-surface-variant border-transparent',
|
|
)}
|
|
>
|
|
{t.nav[item.key]}
|
|
</Link>
|
|
))}
|
|
</nav>
|
|
|
|
<div className="flex items-center gap-2 sm:gap-3">
|
|
<div className="text-on-surface-variant hidden flex-col text-right font-mono text-[11px] 2xl:flex">
|
|
<a
|
|
href={site.phone.href}
|
|
className="text-on-surface hover:text-primary flex items-center justify-end gap-1 font-semibold"
|
|
>
|
|
<Icon
|
|
name="call"
|
|
className="text-primary text-xs"
|
|
/>
|
|
{site.phone.label}
|
|
</a>
|
|
<a
|
|
href={`mailto:${site.email.busdev}`}
|
|
className="hover:text-primary"
|
|
>
|
|
{site.email.busdev}
|
|
</a>
|
|
</div>
|
|
<LanguageToggle />
|
|
<ThemeToggle />
|
|
<ButtonLink
|
|
href={consultationUrl}
|
|
size="sm"
|
|
icon="support_agent"
|
|
className="hidden md:inline-flex"
|
|
>
|
|
{t.header.consult}
|
|
</ButtonLink>
|
|
<button
|
|
type="button"
|
|
aria-label={
|
|
menuOpen ? t.header.closeMenu : t.header.openMenu
|
|
}
|
|
aria-expanded={menuOpen}
|
|
onClick={() => setMenuOpen((open) => !open)}
|
|
className="border-outline-variant/50 bg-surface-container-low text-on-surface inline-flex h-10 w-10 cursor-pointer items-center justify-center rounded-xl border lg:hidden"
|
|
>
|
|
<Icon
|
|
name={menuOpen ? 'close' : 'menu'}
|
|
className="text-2xl"
|
|
/>
|
|
</button>
|
|
</div>
|
|
</Container>
|
|
|
|
{menuOpen && (
|
|
<nav
|
|
aria-label={t.header.mainNav}
|
|
className="border-outline-variant/40 bg-surface border-t lg:hidden"
|
|
>
|
|
<Container className="flex flex-col gap-1 py-4">
|
|
{navigation.map((item) => (
|
|
<Link
|
|
key={item.key}
|
|
href={item.href}
|
|
onClick={closeMenu}
|
|
className={cn(
|
|
'rounded-lg px-3 py-2.5 text-sm font-medium transition-colors',
|
|
isCurrentUrl(item.href)
|
|
? 'bg-surface-container-high text-on-surface'
|
|
: 'text-on-surface-variant hover:bg-surface-container hover:text-on-surface',
|
|
)}
|
|
>
|
|
{t.nav[item.key]}
|
|
</Link>
|
|
))}
|
|
<ButtonLink
|
|
href={consultationUrl}
|
|
size="sm"
|
|
icon="support_agent"
|
|
onClick={closeMenu}
|
|
className="mt-2 md:hidden"
|
|
>
|
|
{t.header.consult}
|
|
</ButtonLink>
|
|
</Container>
|
|
</nav>
|
|
)}
|
|
</header>
|
|
);
|
|
}
|