Files
portifolio-evandrodevbr/app/components/Skills.tsx
T
Evandro Fonseca Junior 8987d06eb4 feat(contact, experience, projects, skills, workModalities): enhance component structure and user experience
- Refactored the Contact component to improve form handling and user feedback, introducing a custom shimmer button and enhanced form validation.
- Updated the Experience component to optimize rendering and improve data handling with memoization, ensuring efficient performance.
- Enhanced the Projects component with a new layout and improved project filtering, utilizing memoization for better performance.
- Refined the Skills component to streamline the display of technical skills, incorporating a loading state and error handling for better user experience.
- Revamped the WorkModalities component to present service options more clearly, including a market comparison section for better user decision-making.
2026-01-12 16:05:02 -03:00

133 lines
5.1 KiB
TypeScript

"use client";
import React, { useMemo } from "react";
import { motion } from "motion/react";
import { MagicCard } from "@/components/magicui/magic-card";
import {
Code, Database, Cloud, Cpu, Smartphone,
Zap, GitBranch, TestTube, Terminal, Layers
} from "lucide-react";
import { usePortfolioData } from "@/lib/usePortfolioData";
const ICON_MAP: Record<string, React.ElementType> = {
Code, Database, Cloud, Cpu, Smartphone, Zap, GitBranch, TestTube, Terminal
};
// Refinamento do Pareto: Cores baseadas em variáveis CSS para evitar quebras no Tailwind
const getCategoryStyles = (color: string) => {
const base = color.replace("text-", "");
return {
icon: color,
bg: `bg-${base}/10`,
// Removido o hover:border daqui para evitar conflitos de transição
border: `border-slate-800/50`,
glow: `rgba(var(--${base}-rgb, 59, 130, 246), 0.15)` // Fallback para azul
};
};
export default function Skills() {
const { data, loading, error } = usePortfolioData();
if (loading) return <LoadingState />;
if (error || !data) return <ErrorState />;
return (
<section id="skills" className="relative py-32 px-6 bg-[#030712] overflow-hidden">
<div className="max-w-7xl mx-auto relative z-10">
{/* Header Header */}
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
className="flex flex-col md:flex-row justify-between items-end mb-20 gap-8"
>
<div className="text-left">
<h2 className="text-sm font-mono text-blue-500 uppercase tracking-[0.3em] mb-4 flex items-center gap-2 font-bold">
<Layers className="w-4 h-4" /> Stack de Engenharia
</h2>
<h3 className="text-4xl md:text-6xl font-black text-white">
Arsenal <span className="text-slate-700">Tecnológico</span>
</h3>
</div>
<p className="text-slate-400 max-w-md text-lg font-light leading-relaxed border-l border-slate-800 pl-6">
Sistemas resilientes construídos com precisão matemática e rigor arquitetural.
</p>
</motion.div>
{/* Grid de Habilidades */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{data.skills.technical.map((category, index) => {
const Icon = ICON_MAP[category.icon] || Code;
const styles = getCategoryStyles(category.color);
return (
<motion.div
key={category.category}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
// Previne que o card suma se o scroll for rápido
viewport={{ once: true, amount: 0.2 }}
transition={{
duration: 0.5,
delay: index * 0.05,
ease: "easeOut"
}}
>
<MagicCard
className="group p-8 flex flex-col h-full bg-slate-900/50 border-slate-800 transition-colors duration-300"
// DEFINIÇÃO EXPLÍCITA DO BRILHO (Corrige o glitch)
gradientColor="#262626"
gradientSize={250}
gradientOpacity={0.4}
>
<div className="flex items-start justify-between mb-8">
<div className={`p-4 rounded-2xl ${styles.bg} border border-white/5 transition-all duration-500 group-hover:scale-110 group-hover:rotate-3`}>
<Icon className={`w-8 h-8 ${styles.icon}`} />
</div>
<span className="text-[10px] font-mono text-slate-700 uppercase tracking-widest font-bold">
ID_0{index}
</span>
</div>
<h3 className="text-xl font-bold text-white mb-6">
{category.category}
</h3>
<div className="flex flex-wrap gap-2 mt-auto">
{category.skills.map((skill, sIdx) => (
<span
key={sIdx}
className="px-3 py-1 text-[11px] font-mono bg-slate-950/50 text-slate-400 rounded border border-slate-800 group-hover:border-blue-500/30 transition-all duration-300"
>
{skill}
</span>
))}
</div>
</MagicCard>
</motion.div>
);
})}
</div>
</div>
</section>
);
}
// --- Componentes de Suporte (Clean Code) ---
function LoadingState() {
return (
<div className="py-32 flex flex-col items-center justify-center space-y-4">
<div className="w-12 h-12 border-4 border-blue-500/20 border-t-blue-500 rounded-full animate-spin" />
<span className="text-slate-500 font-mono text-sm animate-pulse">Initializing Systems...</span>
</div>
);
}
function ErrorState() {
return (
<div className="py-32 text-center text-red-400 font-mono">
[FATAL_ERROR]: Failed to synchronize portfolio data.
</div>
);
}