meh
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
HeadContent,
|
||||
Scripts,
|
||||
} from "@tanstack/react-router";
|
||||
import { useState, type ReactNode } from "react";
|
||||
import { useEffect, useRef, useState, type ReactNode } from "react";
|
||||
import { Menu, X, Phone, ChevronDown } from "lucide-react";
|
||||
import { ScrollToTop } from "@/components/scroll-to-top";
|
||||
import { QuickContact } from "@/components/quick-contact";
|
||||
@@ -173,49 +173,124 @@ function Header() {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-50 bg-background/95 backdrop-blur border-b">
|
||||
<div className="container-page flex items-center justify-center gap-6 h-20">
|
||||
<Link to="/" className="flex items-center shrink-0">
|
||||
<img src="/promist-logo.png" alt="Promist" className="h-10 w-auto" />
|
||||
</Link>
|
||||
<nav className="hidden lg:flex items-center gap-6 text-sm font-medium">
|
||||
{NAV_ITEMS.map((item) =>
|
||||
"children" in item && item.children ? (
|
||||
<DesktopNavItem key={item.label} item={item} />
|
||||
) : (
|
||||
<Link
|
||||
key={item.to}
|
||||
to={item.to as any}
|
||||
className="text-foreground/80 hover:text-brand-red transition-colors whitespace-nowrap"
|
||||
activeProps={{ className: "text-brand-red" }}
|
||||
activeOptions={{ exact: item.to === "/" }}
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
),
|
||||
)}
|
||||
</nav>
|
||||
<a href="https://profen.openexplorer.xyz" target="_blank" rel="noopener noreferrer" className="hidden lg:block shrink-0" aria-label="Profen Engineering">
|
||||
<img src="/profen-logo.png" alt="Profen Engineering" className="h-9 w-auto" />
|
||||
</a>
|
||||
<button
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
className="lg:hidden inline-flex items-center justify-center h-10 w-10 rounded-md border"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
{open ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
|
||||
</button>
|
||||
</div>
|
||||
{open && (
|
||||
<div className="lg:hidden border-t">
|
||||
<div className="container-page py-4 flex flex-col gap-3">
|
||||
{NAV_ITEMS.map((item) => (
|
||||
<MobileSubMenu key={item.label} item={item} onLinkClick={() => setOpen(false)} />
|
||||
))}
|
||||
<>
|
||||
<header className="sticky top-0 z-50 bg-background/95 backdrop-blur border-b">
|
||||
<div className="container-page flex items-center justify-between gap-6 h-20 lg:justify-center">
|
||||
{/* Mobile: hamburger left, Promist beside it, Profen pushed right.
|
||||
Desktop: lg:justify-center restores the original centered layout. */}
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
className="lg:hidden inline-flex items-center justify-center h-10 w-10 rounded-md border shrink-0"
|
||||
aria-label={open ? "Close menu" : "Open menu"}
|
||||
aria-expanded={open}
|
||||
aria-controls="mobile-menu"
|
||||
>
|
||||
{open ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
|
||||
</button>
|
||||
<Link to="/" className="flex items-center shrink-0">
|
||||
<img src="/promist-logo.png" alt="Promist" className="h-10 w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
<span aria-hidden="true" className="hidden lg:block h-6 w-px bg-border" />
|
||||
<nav className="hidden lg:flex items-center gap-6 text-sm font-medium">
|
||||
{NAV_ITEMS.map((item) =>
|
||||
"children" in item && item.children ? (
|
||||
<DesktopNavItem key={item.label} item={item} />
|
||||
) : (
|
||||
<Link
|
||||
key={item.to}
|
||||
to={item.to as any}
|
||||
className="text-foreground/80 hover:text-brand-red transition-colors whitespace-nowrap"
|
||||
activeProps={{ className: "text-brand-red" }}
|
||||
activeOptions={{ exact: item.to === "/" }}
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
),
|
||||
)}
|
||||
</nav>
|
||||
<span aria-hidden="true" className="hidden lg:block h-6 w-px bg-border" />
|
||||
<a href="https://profen.openexplorer.xyz" target="_blank" rel="noopener noreferrer" className="shrink-0" aria-label="Profen Engineering">
|
||||
<img src="/profen-logo.png" alt="Profen Engineering" className="h-9 w-auto" />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
</header>
|
||||
{/* Drawer must be a sibling of <header>: the header's backdrop-blur creates a
|
||||
containing block, which would trap a fixed-position drawer inside the 80px bar. */}
|
||||
<MobileDrawer open={open} onClose={() => setOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function MobileDrawer({ open, onClose }: { open: boolean; onClose: () => void }) {
|
||||
const closeButtonRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
// Lock body scroll while the drawer is open
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const previous = document.body.style.overflow;
|
||||
document.body.style.overflow = "hidden";
|
||||
return () => {
|
||||
document.body.style.overflow = previous;
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
// Close on Escape; move focus into the drawer when it opens
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
closeButtonRef.current?.focus();
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === "Escape") onClose();
|
||||
};
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
return () => document.removeEventListener("keydown", onKeyDown);
|
||||
}, [open, onClose]);
|
||||
|
||||
return (
|
||||
<div
|
||||
id="mobile-menu"
|
||||
aria-hidden={!open}
|
||||
inert={!open}
|
||||
className={`fixed inset-0 z-[60] lg:hidden ${open ? "" : "pointer-events-none"}`}
|
||||
>
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
onClick={onClose}
|
||||
aria-hidden="true"
|
||||
className={`absolute inset-0 bg-black/50 transition-opacity duration-300 ${
|
||||
open ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
/>
|
||||
{/* Panel */}
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Mobile navigation"
|
||||
className={`absolute inset-y-0 left-0 flex w-80 max-w-[85vw] flex-col bg-background border-r shadow-xl transition-transform duration-300 ease-out ${
|
||||
open ? "translate-x-0" : "-translate-x-full"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between border-b px-5 h-16 shrink-0">
|
||||
<Link to="/" onClick={onClose} className="flex items-center">
|
||||
<img src="/promist-logo.png" alt="Promist" className="h-9 w-auto" />
|
||||
</Link>
|
||||
<button
|
||||
ref={closeButtonRef}
|
||||
onClick={onClose}
|
||||
className="inline-flex items-center justify-center h-9 w-9 rounded-md border hover:bg-muted transition-colors"
|
||||
aria-label="Close menu"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<nav className="flex-1 overflow-y-auto px-5 py-5 flex flex-col gap-4 text-base font-medium">
|
||||
{NAV_ITEMS.map((item) => (
|
||||
<MobileSubMenu key={item.label} item={item} onLinkClick={onClose} />
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ function HeroSlider() {
|
||||
{/* Arrows */}
|
||||
<button
|
||||
onClick={() => emblaApi?.scrollPrev()}
|
||||
className="absolute left-4 top-1/2 -translate-y-1/2 w-11 h-11 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 flex items-center justify-center text-white hover:bg-white/20 transition-colors"
|
||||
className="hidden sm:flex absolute left-4 top-1/2 -translate-y-1/2 w-11 h-11 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 items-center justify-center text-white hover:bg-white/20 transition-colors"
|
||||
aria-label="Previous slide"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@@ -162,7 +162,7 @@ function HeroSlider() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => emblaApi?.scrollNext()}
|
||||
className="absolute right-4 top-1/2 -translate-y-1/2 w-11 h-11 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 flex items-center justify-center text-white hover:bg-white/20 transition-colors"
|
||||
className="hidden sm:flex absolute right-4 top-1/2 -translate-y-1/2 w-11 h-11 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 items-center justify-center text-white hover:bg-white/20 transition-colors"
|
||||
aria-label="Next slide"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
|
||||
Reference in New Issue
Block a user