/* ------------------------------------------------------------------ * * Shared components for Aqua Signature * ------------------------------------------------------------------ */ const { useState, useEffect, useRef, useMemo, useCallback } = React; // ---------- Reveal-on-scroll ---------- function useReveal() { const ref = useRef(null); useEffect(() => { if (!ref.current) return; const el = ref.current; const io = new IntersectionObserver( (entries) => { entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("is-in"); io.unobserve(e.target); } }); }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" } ); io.observe(el); return () => io.disconnect(); }, []); return ref; } function Reveal({ as = "div", className = "", variant = "", children, ...rest }) { const ref = useReveal(); const Tag = as; const cls = ["reveal", variant && `reveal--${variant}`, className].filter(Boolean).join(" "); return {children}; } function RevealStagger({ as = "div", className = "", children, ...rest }) { const ref = useReveal(); const Tag = as; return {children}; } // ---------- Logo ---------- // To swap in the real logo: drop a file at `assets/logo.svg` (or .png). // The falls back to a CSS-drawn droplet if the file is missing. function Droplet({ className = "" }) { const [imgFailed, setImgFailed] = React.useState(false); if (!imgFailed) { return ( setImgFailed(true)} /> ); } return ( ); } function Logo({ size = "sm", variant = "", stack = false, className = "" }) { const { t } = useLang(); const cls = [ "logo", size === "lg" && "logo--lg", size === "xl" && "logo--xl", stack && "logo--stack", variant && `logo--${variant}`, className, ].filter(Boolean).join(" "); return ( AQUA Signature {t("logo.country")} ); } // ---------- Nav ---------- function Nav({ route, navigate, dark }) { const [scrolled, setScrolled] = useState(false); const { t } = useLang(); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 30); onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); const items = [ { id: "collection", label: t("nav.collection") }, { id: "story", label: t("nav.story") }, { id: "materials", label: t("nav.materials") }, { id: "contact", label: t("nav.contact") }, ]; return ( ); } // ---------- LangSwitch — sits below the Request Quote CTA, centered ---------- function LangSwitch() { const { lang, setLang } = useLang(); return (
); } // ---------- Footer ---------- function Footer({ navigate, onTradeLogin }) { const { t } = useLang(); return ( ); } // ---------- Placeholder media ---------- function Media({ tone = "sand", label = "image", note = "", center = "", src, alt = "", className = "", style }) { const t = tone === "ocean" ? "media--ocean" : tone === "teal" ? "media--teal" : tone === "pale" ? "media--pale" : "media--sand"; return (
{src ? {alt} :
} {center && !src &&
{center}
} {(label || note) && (
{label} {note}
)}
); } // ---------- Marquee ---------- function Marquee({ items }) { return (
{[...items, ...items, ...items].map((it, i) => ( {it} ))}
); } // ---------- Toast ---------- function Toast({ message, show }) { return
{message}
; } // ---------- Section head ---------- function SectionHead({ eyebrow, title, kicker, count }) { return (
{eyebrow &&
{eyebrow}
}

{title}

{kicker &&

{kicker}

}
{count && {count}}
); } // Expose to other Babel scripts Object.assign(window, { Reveal, RevealStagger, useReveal, Logo, Nav, LangSwitch, Footer, Media, Marquee, Toast, SectionHead });