"use client"; import { useState, useRef, useEffect } from "react"; import { Switch } from "@/components/ui/switch"; import { motion, Variants } from "framer-motion"; import { Shield, EyeOff } from "lucide-react"; import { Dictionary } from "@/lib/IDict"; import { CyberButton } from "../ui/cyber-button"; import { NetrunnerMatrix } from "../graphics/NetrunnerMatrix"; import { useTheme } from "next-themes"; function CyberEye({ isClosed, vpnOn, gaze, }: { isClosed: boolean; vpnOn: boolean; gaze: { x: number; y: number; dir: string }; }) { const eyeVariants: Variants = { open: { height: 72, width: 120, borderRadius: 36, borderWidth: 4, transition: { type: "spring", stiffness: 400, damping: 15 }, }, closed: { height: 6, width: 140, borderRadius: 8, borderWidth: 3, transition: { type: "spring", stiffness: 500, damping: 15 }, }, }; const borderColor = vpnOn ? "border-purple-600 dark:border-primary shadow-[0_0_15px_rgba(139,61,255,0.3)]" : "border-cyan-600 dark:border-secondary shadow-[0_0_15px_rgba(0,229,242,0.3)]"; return ( {/* Лазерная полоса при закрытом глазе */} ); } function CyberWatcherEyes({ vpnOn }: { vpnOn: boolean }) { const wrapperRef = useRef(null); const [isBlinking, setIsBlinking] = useState(false); const [gaze, setGaze] = useState({ x: 0, y: 0, dir: "center" }); const timerRef = useRef(null); const lastInteraction = useRef(0); // Классическое случайное моргание useEffect(() => { const schedule = () => { timerRef.current = setTimeout( () => { setIsBlinking(true); setTimeout(() => { setIsBlinking(false); schedule(); }, 120); // Чуть ускорили моргание }, Math.random() * 4000 + 1000, ); }; if (!vpnOn) schedule(); return () => clearTimeout(timerRef.current); }, [vpnOn]); // Единая логика взгляда (Unified Gaze Vector) useEffect(() => { const updateGaze = (targetX: number, targetY: number) => { if (!wrapperRef.current) return; // Вычисляем центр относительно "переносицы" (контейнера), а не каждого глаза const rect = wrapperRef.current.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; const dx = targetX - centerX; const dy = targetY - centerY; let dir = "center"; // Увеличили мертвую зону, чтобы взгляд чаще казался "сосредоточенным" if (Math.abs(dx) < 60 && Math.abs(dy) < 60) { dir = "center"; } else if (Math.abs(dx) > Math.abs(dy)) { dir = dx > 0 ? "right" : "left"; } else { dir = dy > 0 ? "down" : "up"; } const angle = Math.atan2(dy, dx); const maxRadius = 20; // Небольшой коэффициент, чтобы глаза не бились о края орбиты слишком быстро const distance = Math.min(maxRadius, Math.hypot(dx, dy) * 0.1); setGaze({ x: Math.cos(angle) * distance, y: Math.sin(angle) * distance, dir, }); }; const handleInteract = (e: MouseEvent | TouchEvent) => { lastInteraction.current = Date.now(); let clientX, clientY; if ("touches" in e && e.touches.length > 0) { clientX = e.touches[0].clientX; clientY = e.touches[0].clientY; } else { clientX = (e as MouseEvent).clientX; clientY = (e as MouseEvent).clientY; } updateGaze(clientX, clientY); }; window.addEventListener("mousemove", handleInteract); window.addEventListener("touchstart", handleInteract, { passive: true }); window.addEventListener("pointerdown", handleInteract); // Логика "живого" блуждания для мобилок const randomLookInterval = setInterval(() => { const isMobile = window.innerWidth <= 768 || "ontouchstart" in window; if (isMobile && Date.now() - lastInteraction.current > 2500) { if (Math.random() > 0.2) { // Выбираем новую точку const rx = window.innerWidth * 0.1 + Math.random() * (window.innerWidth * 0.8); const ry = window.innerHeight * 0.1 + Math.random() * (window.innerHeight * 0.8); updateGaze(rx, ry); // Микро-моргание при скачке взгляда (очень органичный эффект) if (Math.random() > 0.6) { setIsBlinking(true); setTimeout(() => setIsBlinking(false), 80); } } else { // Иногда смотрим прямо updateGaze(window.innerWidth / 2, window.innerHeight / 2); } } }, 1800); // Чуть чаще меняем взгляд на телефоне return () => { window.removeEventListener("mousemove", handleInteract); window.removeEventListener("touchstart", handleInteract); window.removeEventListener("pointerdown", handleInteract); clearInterval(randomLookInterval); }; }, []); const shouldBeClosed = vpnOn || isBlinking; return (
{/* Теперь оба глаза получают абсолютно одинаковое смещение */}
); } export function Hero({ dict, lang, }: { dict: Dictionary["hero"]; lang: string; }) { const [isVpnOn, setIsVpnOn] = useState(false); const { resolvedTheme } = useTheme(); return (
{/* --- RUST BACKGROUND --- */}
{isVpnOn ? ( ) : ( )} {isVpnOn ? dict.badgeSecure : dict.badge} {/* НАШИ ИДЕАЛЬНЫЕ ГЛАЗА */}

{dict.titleStart}{" "} {dict.titleHighlight}

{dict.subtitle}

Netrunner VPN
{dict.ctaPrimary} {dict.ctaSecondary}
); }