"use client"; import { motion, useReducedMotion, type Variants } from "motion/react"; import dynamic from "next/dynamic"; import { useEffect, useRef, useState } from "react"; import { shouldLoadHeroScene } from "@/app/lib/should-load-hero-scene"; import { CV_URL } from "@/lib/site-navigation"; import { buildWhatsAppUrl } from "@/lib/whatsapp"; import { ControlRoomGlobe } from "./cinematic/ControlRoomGlobe"; import { HeroStarfield } from "./cinematic/HeroStarfield"; import MagneticButton from "./cinematic/MagneticButton"; import { TelemetryStrip } from "./cinematic/TelemetryStrip"; const HeroScene = dynamic(() => import("./cinematic/HeroScene"), { ssr: false, }); const SOCIAL_LINKS = [ { href: "https://github.com/evandrodevbr", label: "GitHub", icon: ( ), }, { href: "https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/", label: "LinkedIn", icon: ( ), }, { href: "mailto:evandrofonsecajunior@gmail.com", label: "Email", icon: ( <> ), stroke: true, }, ]; const HERO_CONTENT = { status: "Disponível para novas oportunidades", chip: "Garuva · Joinville · Curitiba · Remoto", eyebrow: "Evandro Fonseca Junior | Engenheiro da Computação e Desenvolvedor de Software", headline: "Engenharia de software para sistemas que precisam operar de verdade.", subtitle: "Profissional disponível para oportunidades CLT e PJ em Garuva, Joinville, Norte de Santa Catarina e Curitiba; também atuo em consultoria para produtos, integrações e sistemas críticos.", cta: "Conversar sobre uma oportunidade", whatsappMessage: "Olá! Quero conversar sobre uma oportunidade profissional em engenharia de software.", sideLabel: "Contato profissional direto", sideTitle: "Procurando um engenheiro da computação para o seu time?", sideText: "Vamos conversar sobre o contexto técnico, o desafio da vaga e como posso contribuir da arquitetura à entrega.", points: [ "Engenharia full-stack com base em sistemas e integrações.", "Next.js, TypeScript, Rust, IoT e arquitetura de software.", "Disponível para times do Norte de SC, Curitiba e atuação remota.", ], proof: [ { label: "Operação", value: "Fluxo pensado para discovery, build, deploy e sustentação.", }, { label: "Clareza", value: "Menos ruído entre produto, engenharia e decisão técnica.", }, { label: "Resultado", value: "Base pronta para operar, evoluir e receber próximo ciclo.", }, ], } as const; function getGreeting(message: string) { const hour = new Date().getHours(); if (hour >= 8 && hour < 12) return `Bom dia! ${message}`; if (hour >= 13 && hour < 18) return `Boa tarde! ${message}`; return message; } export default function Hero() { const heroRef = useRef(null); const shouldReduceMotion = useReducedMotion() ?? true; const [shouldRenderHeroScene, setShouldRenderHeroScene] = useState(false); const [isHeroVisible, setIsHeroVisible] = useState(true); useEffect(() => { const reducedMotion = window.matchMedia( "(prefers-reduced-motion: reduce)", ).matches; const coarsePointer = window.matchMedia("(pointer: coarse)").matches; if ( !shouldLoadHeroScene({ reducedMotion, coarsePointer, width: window.innerWidth, }) ) { return; } const timer = window.setTimeout(() => setShouldRenderHeroScene(true), 1500); return () => window.clearTimeout(timer); }, []); useEffect(() => { const hero = heroRef.current; if (!hero || !("IntersectionObserver" in window)) return undefined; const observer = new IntersectionObserver( ([entry]) => setIsHeroVisible(entry?.isIntersecting ?? false), { threshold: 0 }, ); observer.observe(hero); return () => observer.disconnect(); }, []); const handleWhatsAppClick = () => { window.open( buildWhatsAppUrl(getGreeting(HERO_CONTENT.whatsappMessage)), "_blank", "noopener,noreferrer", ); }; const heroContainer: Variants = { hidden: shouldReduceMotion ? { opacity: 1 } : { opacity: 0 }, visible: { opacity: 1, transition: shouldReduceMotion ? { duration: 0 } : { staggerChildren: 0.1, delayChildren: 0.3 }, }, }; const easeOut: [number, number, number, number] = [0.16, 1, 0.3, 1]; const heroItem: Variants = { hidden: shouldReduceMotion ? { opacity: 1, y: 0, filter: "blur(0px)" } : { opacity: 0, y: 40, filter: "blur(10px)" }, visible: { opacity: 1, y: 0, filter: "blur(0px)", transition: shouldReduceMotion ? { duration: 0 } : { duration: 1, ease: easeOut }, }, }; const heroItemSlow: Variants = { hidden: shouldReduceMotion ? { opacity: 1, y: 0, filter: "blur(0px)" } : { opacity: 0, y: 60, filter: "blur(12px)" }, visible: { opacity: 1, y: 0, filter: "blur(0px)", transition: shouldReduceMotion ? { duration: 0 } : { duration: 1.2, ease: easeOut }, }, }; return (
{shouldRenderHeroScene && }
{/* pt >= altura do header fixo (52px): conteúdo do hero nunca nasce sob a barra */}
{HERO_CONTENT.status}
{HERO_CONTENT.chip}
{HERO_CONTENT.eyebrow} {HERO_CONTENT.headline} {HERO_CONTENT.subtitle} {HERO_CONTENT.points.map((point, i) => ( {point} ))} {HERO_CONTENT.cta} Ver casos selecionados Download CV
Garuva, SC / Brasil
Next.js, Tauri, Rust, Node.js
{SOCIAL_LINKS.map((link) => ( ))}
{HERO_CONTENT.sideLabel}

{HERO_CONTENT.sideTitle}

{HERO_CONTENT.sideText}

{HERO_CONTENT.proof.map((item, index) => (
{item.label}

{item.value}

))}
{shouldReduceMotion ? (
); }