feat: Adiciona a estrutura inicial do portfólio com componentes para experiência, hero, sobre, habilidades, projetos, modalidades de trabalho e contato.

This commit is contained in:
Evandro Fonseca Junior committed 2026-02-14 02:20:54 -03:00
1 parent 65dd049963
commit 77956223b3
12 files changed
+576 -470

No files matched your search

+126 -87
View File
@@ -1,18 +1,21 @@
"use client";
import React, { useMemo } from "react";
import { motion, AnimatePresence } from "motion/react";
import {
Calendar, MapPin, Briefcase, Zap,
Award, Users, Terminal, ChevronRight
import { motion } from "framer-motion";
import {
ChevronRight,
Terminal,
Cpu,
Network,
Code2
} from "lucide-react";
import { usePortfolioData } from "@/lib/usePortfolioData";
// --- Tipagem e Configuração (Otimização Pareto 80/20) ---
const CONFIG = {
"innovo-tecnologia": { color: "text-blue-400", bg: "bg-blue-400/10", border: "border-blue-400/20" },
"apolo-energia": { color: "text-emerald-400", bg: "bg-emerald-400/10", border: "border-emerald-400/20" },
default: { color: "text-slate-400", bg: "bg-slate-400/10", border: "border-slate-400/20" }
"innovo-tecnologia": { color: "text-blue-400", bg: "bg-blue-400/10", border: "border-blue-400/20", icon: Cpu },
"apolo-energia": { color: "text-emerald-400", bg: "bg-emerald-400/10", border: "border-emerald-400/20", icon: Network },
default: { color: "text-slate-400", bg: "bg-slate-400/10", border: "border-slate-400/20", icon: Code2 }
};
export default function Experience() {
@@ -33,33 +36,46 @@ export default function Experience() {
if (loading) return <ExperienceSkeleton />;
return (
<section id="experience" className="relative py-32 bg-[#030712] overflow-hidden">
<div className="max-w-6xl mx-auto px-6 relative">
<section id="experience" className="relative py-32">
{/* Background Gradients */}
<div className="absolute top-0 left-0 w-full h-full pointer-events-none">
<div className="absolute top-[20%] left-[-10%] w-[500px] h-[500px] bg-blue-900/10 rounded-full blur-[100px]" />
<div className="absolute bottom-[20%] right-[-10%] w-[500px] h-[500px] bg-indigo-900/10 rounded-full blur-[100px]" />
</div>
<div className="max-w-6xl mx-auto px-6 relative z-10">
{/* Header com Identidade Visual */}
<div className="mb-24">
<motion.span
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
className="text-blue-500 font-mono text-sm tracking-[0.4em] uppercase"
<div className="mb-24 text-center md:text-left">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-blue-950/30 border border-blue-500/20 text-blue-400 font-mono text-xs tracking-wider mb-6"
>
System_History
</motion.span>
<h2 className="text-5xl md:text-7xl font-black text-white mt-4 tracking-tighter">
Trajetória <br />
<span className="text-slate-700">Profissional</span>
</h2>
<Terminal className="w-3 h-3" />
<span>SYSTEM_LOGS.history</span>
</motion.div>
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.1 }}
className="text-4xl md:text-6xl font-black text-white tracking-tighter"
>
Trajetória <span className="bg-gradient-to-r from-blue-500 to-indigo-500 bg-clip-text text-transparent">Profissional</span>
</motion.h2>
</div>
{/* Timeline Desktop (Linha Central) */}
<div className="absolute left-[50%] top-[400px] bottom-0 w-[1px] bg-gradient-to-b from-blue-500/50 via-slate-800 to-transparent hidden lg:block" />
<div className="relative">
{/* Timeline Desktop (Linha Central com Gradiente) */}
<div className="absolute left-[50%] top-0 bottom-0 w-[2px] bg-gradient-to-b from-blue-500/50 via-indigo-500/20 to-transparent hidden lg:block translate-x-[-50%]" />
<div className="space-y-12">
<AnimatePresence>
<div className="space-y-24">
{sortedExperiences.map((exp, index) => (
<ExperienceCard key={exp.id} exp={exp} index={index} />
))}
</AnimatePresence>
</div>
</div>
</div>
</section>
@@ -70,86 +86,109 @@ export default function Experience() {
function ExperienceCard({ exp, index }: { exp: any, index: number }) {
const isEven = index % 2 === 0;
const config = (CONFIG as any)[exp.company.toLowerCase().replace(/\s+/g, "-")] || CONFIG.default;
const Icon = config.icon;
return (
<motion.div
// CORREÇÃO DO BUG: viewport com margin e once garante que a animação termine
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3, margin: "0px 0px -100px 0px" }}
transition={{
duration: 0.8,
delay: index * 0.1,
ease: [0.16, 1, 0.3, 1] // Custom Ease-Out para suavidade premium
}}
className={`relative flex flex-col ${isEven ? 'lg:flex-row' : 'lg:flex-row-reverse'} items-center gap-8 lg:gap-16`}
>
<div className={`relative flex flex-col ${isEven ? 'lg:flex-row' : 'lg:flex-row-reverse'} items-center gap-8 lg:gap-16`}>
{/* Node Central (O "Ponto" da Timeline) */}
<motion.div
initial={{ scale: 0, opacity: 0 }}
whileInView={{ scale: 1, opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.2, duration: 0.5 }}
className="hidden lg:flex absolute left-[50%] top-0 translate-x-[-50%] w-4 h-4 rounded-full bg-blue-500 shadow-[0_0_20px_rgba(59,130,246,0.5)] z-20 items-center justify-center"
>
<div className="w-2 h-2 rounded-full bg-white animate-pulse" />
</motion.div>
{/* Indicador de Data na Timeline */}
<div className="hidden lg:flex flex-1 justify-end items-center">
<div className={`${isEven ? 'text-right' : 'text-left'} flex-1`}>
<span className="text-2xl font-mono font-bold text-slate-800 tracking-tighter group-hover:text-blue-500 transition-colors">
<div className="hidden lg:flex flex-1 justify-end items-start pt-2">
<motion.div
initial={{ opacity: 0, x: isEven ? -20 : 20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.3 }}
className={`${isEven ? 'text-right' : 'text-left'} flex-1`}
>
<span className="text-4xl font-black text-transparent bg-clip-text bg-gradient-to-b from-slate-700 to-slate-800 tracking-tighter opacity-50 select-none">
{exp.period.split(' ')[0]}
</span>
</div>
</motion.div>
</div>
{/* Card Principal */}
<div className="flex-1 w-full">
<motion.div
whileHover={{ y: -5 }} // Hover sutil sem quebrar o layout
className={`p-8 rounded-3xl bg-slate-900/40 border ${config.border} backdrop-blur-xl relative overflow-hidden group transition-all`}
<div className="flex-1 w-full relative group perspective-1000">
<motion.div
initial={{ opacity: 0, x: isEven ? 50 : -50 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.6, delay: 0.1 * index }}
whileHover={{ y: -5, transition: { duration: 0.2 } }}
className={`p-8 rounded-3xl bg-zinc-900/40 border border-white/5 backdrop-blur-md relative overflow-hidden transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.1)] hover:border-blue-500/20`}
>
{/* Badge de Empresa */}
<div className="flex flex-wrap justify-between items-start gap-4 mb-6">
<div className="space-y-1">
<h3 className="text-2xl font-bold text-white group-hover:text-blue-400 transition-colors">
{exp.title}
</h3>
<div className="flex items-center gap-2">
<span className={`text-sm font-bold uppercase tracking-widest ${config.color}`}>
{exp.company}
{/* Background Glow Effect on Hover */}
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
{/* Badge de Empresa & Header */}
<div className="relative z-10">
<div className="flex flex-wrap justify-between items-start gap-4 mb-6">
<div className="space-y-2">
<div className="flex items-center gap-3">
<div className={`p-2 rounded-lg ${config.bg} ${config.color}`}>
<Icon className="w-5 h-5" />
</div>
<span className={`text-xs font-bold uppercase tracking-widest ${config.color}`}>
{exp.company}
</span>
</div>
<h3 className="text-2xl font-bold text-white group-hover:text-blue-400 transition-colors">
{exp.title}
</h3>
</div>
<div className="px-3 py-1 rounded-full bg-white/5 border border-white/10 text-[10px] font-mono font-bold text-slate-400 uppercase tracking-wide">
{exp.period}
</div>
</div>
<p className="text-slate-400 leading-relaxed mb-8 text-sm">
{exp.description}
</p>
{/* Conquistas (Checklist Técnico) */}
<div className="grid grid-cols-1 gap-3 mb-8">
{exp.achievements?.map((ach: string, i: number) => (
<div key={i} className="flex gap-3 text-sm text-slate-300 items-start">
<div className="mt-1.5 w-1.5 h-1.5 rounded-full bg-blue-500 flex-shrink-0" />
<span>{ach}</span>
</div>
))}
</div>
{/* Tags de Tech */}
<div className="flex flex-wrap gap-2 pt-6 border-t border-white/5">
{exp.technologies?.map((tech: string) => (
<span key={tech} className="px-3 py-1 bg-black/20 border border-white/5 text-slate-500 text-[10px] rounded-full font-mono hover:text-blue-400 hover:border-blue-400/30 transition-all cursor-default">
{tech}
</span>
<span className="text-slate-600">•</span>
<span className="text-xs text-slate-500 font-mono">{exp.type}</span>
</div>
))}
</div>
<div className={`px-4 py-1.5 rounded-full ${config.bg} border ${config.border} text-[10px] font-bold text-white uppercase`}>
{exp.period}
</div>
</div>
<p className="text-slate-400 leading-relaxed mb-8 text-sm">
{exp.description}
</p>
{/* Conquistas (Técnica de Checklist de Engenharia) */}
<div className="grid grid-cols-1 gap-3 mb-8">
{exp.achievements?.map((ach: string, i: number) => (
<div key={i} className="flex gap-3 text-sm text-slate-300 group/item">
<ChevronRight className={`w-4 h-4 mt-0.5 flex-shrink-0 transition-transform group-hover/item:translate-x-1 ${config.color}`} />
<span>{ach}</span>
</div>
))}
</div>
{/* Tags de Tech (Aparência de Chip de Hardware) */}
<div className="flex flex-wrap gap-2 pt-6 border-t border-slate-800/50">
{exp.technologies?.map((tech: string) => (
<span key={tech} className="px-3 py-1 bg-slate-950 border border-slate-800 text-slate-500 text-[10px] rounded-md font-mono hover:text-blue-400 hover:border-blue-400/30 transition-all">
{tech}
</span>
))}
</div>
</motion.div>
</div>
{/* Spacer para Timeline Desktop */}
<div className="hidden lg:block flex-1" />
</motion.div>
</div>
);
}
function ExperienceSkeleton() {
return <div className="h-96 flex items-center justify-center text-slate-600 font-mono animate-pulse">Loading_System_Nodes...</div>;
return (
<div className="h-96 flex flex-col items-center justify-center gap-4 text-slate-600 font-mono animate-pulse">
<Cpu className="w-8 h-8 animate-spin" />
<span>BOOTING_SYSTEM_HISTORY...</span>
</div>
);
}