meh
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
|||||||
HeadContent,
|
HeadContent,
|
||||||
Scripts,
|
Scripts,
|
||||||
} from "@tanstack/react-router";
|
} 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 { Menu, X, Phone, ChevronDown } from "lucide-react";
|
||||||
import { ScrollToTop } from "@/components/scroll-to-top";
|
import { ScrollToTop } from "@/components/scroll-to-top";
|
||||||
import { QuickContact } from "@/components/quick-contact";
|
import { QuickContact } from "@/components/quick-contact";
|
||||||
@@ -173,49 +173,124 @@ function Header() {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
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">
|
<header className="sticky top-0 z-50 bg-background/95 backdrop-blur border-b">
|
||||||
<Link to="/" className="flex items-center shrink-0">
|
<div className="container-page flex items-center justify-between gap-6 h-20 lg:justify-center">
|
||||||
<img src="/promist-logo.png" alt="Promist" className="h-10 w-auto" />
|
{/* Mobile: hamburger left, Promist beside it, Profen pushed right.
|
||||||
</Link>
|
Desktop: lg:justify-center restores the original centered layout. */}
|
||||||
<nav className="hidden lg:flex items-center gap-6 text-sm font-medium">
|
<div className="flex items-center gap-3">
|
||||||
{NAV_ITEMS.map((item) =>
|
<button
|
||||||
"children" in item && item.children ? (
|
onClick={() => setOpen((v) => !v)}
|
||||||
<DesktopNavItem key={item.label} item={item} />
|
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"}
|
||||||
<Link
|
aria-expanded={open}
|
||||||
key={item.to}
|
aria-controls="mobile-menu"
|
||||||
to={item.to as any}
|
>
|
||||||
className="text-foreground/80 hover:text-brand-red transition-colors whitespace-nowrap"
|
{open ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
|
||||||
activeProps={{ className: "text-brand-red" }}
|
</button>
|
||||||
activeOptions={{ exact: item.to === "/" }}
|
<Link to="/" className="flex items-center shrink-0">
|
||||||
>
|
<img src="/promist-logo.png" alt="Promist" className="h-10 w-auto" />
|
||||||
{item.label}
|
</Link>
|
||||||
</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)} />
|
|
||||||
))}
|
|
||||||
</div>
|
</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>
|
</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 */}
|
{/* Arrows */}
|
||||||
<button
|
<button
|
||||||
onClick={() => emblaApi?.scrollPrev()}
|
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"
|
aria-label="Previous slide"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
@@ -162,7 +162,7 @@ function HeroSlider() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => emblaApi?.scrollNext()}
|
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"
|
aria-label="Next slide"
|
||||||
>
|
>
|
||||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
|||||||
Reference in New Issue
Block a user