/* global React */ const { useState, useEffect, useRef } = React; // ============================================ // LOGO // ============================================ window.Logo = function Logo({ size = 26 }) { return ( AICO Agency ); }; // ============================================ // MAGNETIC CURSOR // ============================================ window.MagnetCursor = function MagnetCursor() { const dotRef = useRef(null); const ringRef = useRef(null); useEffect(() => { if (window.matchMedia("(max-width: 720px)").matches) return; let mouseX = window.innerWidth / 2, mouseY = window.innerHeight / 2; let ringX = mouseX, ringY = mouseY; let raf; const onMove = (e) => { mouseX = e.clientX; mouseY = e.clientY; if (dotRef.current) { dotRef.current.style.left = mouseX + "px"; dotRef.current.style.top = mouseY + "px"; } const el = document.elementFromPoint(mouseX, mouseY); const interactive = el && el.closest && el.closest("a, button, .cta, .svc-card, .stack-cell, [data-magnet]"); const textArea = el && el.closest && el.closest("input, textarea, [contenteditable]"); if (dotRef.current && ringRef.current) { dotRef.current.classList.toggle("large", !!interactive); dotRef.current.classList.toggle("text", !!textArea); ringRef.current.classList.toggle("hidden", !!interactive); } }; const tick = () => { ringX += (mouseX - ringX) * 0.18; ringY += (mouseY - ringY) * 0.18; if (ringRef.current) { ringRef.current.style.left = ringX + "px"; ringRef.current.style.top = ringY + "px"; } raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); window.addEventListener("mousemove", onMove); return () => { window.removeEventListener("mousemove", onMove); cancelAnimationFrame(raf); }; }, []); return ( <>
); }; // ============================================ // REVEAL ON SCROLL // ============================================ window.useReveal = function useReveal() { useEffect(() => { const els = document.querySelectorAll(".reveal"); const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } }); }, { threshold: 0.12, rootMargin: "0px 0px -80px 0px" }); els.forEach(el => io.observe(el)); return () => io.disconnect(); }); }; // ============================================ // ANIMATED COUNTER // ============================================ window.Counter = function Counter({ value, suffix = "", duration = 1600 }) { const [current, setCurrent] = useState(0); const ref = useRef(null); const startedRef = useRef(false); useEffect(() => { const node = ref.current; if (!node) return; const io = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting && !startedRef.current) { startedRef.current = true; const start = performance.now(); const animate = (t) => { const p = Math.min(1, (t - start) / duration); const eased = 1 - Math.pow(1 - p, 3); setCurrent(Math.round(eased * value)); if (p < 1) requestAnimationFrame(animate); }; requestAnimationFrame(animate); } }); }, { threshold: 0.4 }); io.observe(node); return () => io.disconnect(); }, [value, duration]); return ( {current} {suffix} ); }; // ============================================ // LANGUAGE TOGGLE // ============================================ window.LangToggle = function LangToggle({ lang, setLang }) { return (
); }; // ============================================ // STATUS BAR + NAV // ============================================ window.StatusBar = function StatusBar({ t }) { const [time, setTime] = useState(""); useEffect(() => { const update = () => { const d = new Date(); const h = String(d.getUTCHours()).padStart(2, "0"); const m = String(d.getUTCMinutes()).padStart(2, "0"); const s = String(d.getUTCSeconds()).padStart(2, "0"); setTime(`${h}:${m}:${s} UTC`); }; update(); const i = setInterval(update, 1000); return () => clearInterval(i); }, []); return (
{t.status.label} {t.status.loc}
{t.status.uptime} {time}
); }; window.Footer = function Footer({ t }) { return (
{t.footer.left} {t.footer.mid} {t.footer.right}
); }; window.Nav = function Nav({ t, lang, setLang, direction, setDirection, navLinks, navCtaHref }) { const [menuOpen, setMenuOpen] = useState(false); const links = navLinks || [ { href: "#services", idx: "01", label: t.nav.services }, { href: "#process", idx: "02", label: t.nav.process }, { href: "#stack", idx: "03", label: t.nav.stack }, { href: "#contact", idx: "04", label: t.nav.contact }, ]; useEffect(() => { const onKey = (e) => { if (e.key === "Escape") setMenuOpen(false); }; document.addEventListener("keydown", onKey); return () => document.removeEventListener("keydown", onKey); }, []); useEffect(() => { document.body.style.overflow = menuOpen ? "hidden" : ""; return () => { document.body.style.overflow = ""; }; }, [menuOpen]); const close = () => setMenuOpen(false); return ( ); };