Files
portifolio-evandrodevbr/app/components/Skills.tsx
T
Evandro Fonseca Junior 6ec67c8f5a feat(about): add story sections and core values to About component
Enhance the About page with new story sections detailing personal journey and core values, including icons and structured content for better user engagement and self-presentation.
2025-10-11 18:25:41 -03:00

142 lines
4.7 KiB
TypeScript

"use client";
import { motion } from "motion/react";
import { MagicCard } from "@/components/magicui/magic-card";
import {
Code,
Database,
Cloud,
Cpu,
Smartphone,
Zap,
GitBranch,
TestTube,
} from "lucide-react";
import { usePortfolioData } from "@/lib/usePortfolioData";
// Mapa de ícones para as categorias
const iconMap = {
Code: Code,
Database: Database,
Cloud: Cloud,
Cpu: Cpu,
Smartphone: Smartphone,
Zap: Zap,
GitBranch: GitBranch,
TestTube: TestTube,
};
// Mapa de cores para garantir que o Tailwind inclua as classes no bundle
const colorMap = {
"text-blue-440": "bg-blue-400",
"text-blue-400": "bg-blue-400",
"text-green-400": "bg-blue-400",
"text-purple-400": "bg-blue-400",
"text-red-400": "bg-blue-400",
"text-yellow-400": "bg-blue-400",
"text-pink-400": "bg-blue-400",
"text-indigo-400": "bg-blue-400",
};
export default function Skills() {
const { data, loading, error } = usePortfolioData();
if (loading) {
return (
<section id="skills" className="py-20 px-4">
<div className="max-w-6xl mx-auto text-center">
<div className="animate-pulse">
<div className="h-8 bg-gray-700 rounded w-1/3 mx-auto mb-4"></div>
<div className="h-4 bg-gray-700 rounded w-1/2 mx-auto"></div>
</div>
</div>
</section>
);
}
if (error || !data) {
return (
<section id="skills" className="py-20 px-4">
<div className="max-w-6xl mx-auto text-center">
<p className="text-red-400">Erro ao carregar dados de habilidades.</p>
</div>
</section>
);
}
const skillCategories = data.skills.technical;
return (
<section id="skills" className="py-20 px-4">
<div className="max-w-6xl mx-auto">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
viewport={{ once: true }}
className="text-center mb-16"
>
<div className="inline-flex items-center gap-2 bg-gradient-to-r from-cyan-400/10 to-blue-500/10 px-6 py-3 rounded-full mb-6 border border-cyan-400/20">
<div className="w-2 h-2 bg-cyan-400 rounded-full animate-pulse"></div>
<span className="text-sm font-medium text-cyan-300">
Tecnologias Dominadas
</span>
</div>
<h2 className="text-4xl md:text-5xl lg:text-6xl font-bold mb-6 bg-gradient-to-r from-cyan-400 to-blue-500 bg-clip-text text-transparent">
Habilidades Técnicas
</h2>
<p className="text-xl text-gray-300 max-w-2xl mx-auto">
Tecnologias e ferramentas que utilizo para criar soluções inovadoras
</p>
</motion.div>
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
{skillCategories.map((category, index) => {
const IconComponent =
iconMap[category.icon as keyof typeof iconMap] || Code;
return (
<motion.div
key={category.category}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: index * 0.1 }}
viewport={{ once: true }}
>
<div className="p-6 space-y-4 bg-white/5 backdrop-blur-sm border border-white/10 rounded-xl hover:border-cyan-500/30 transition-all duration-300 hover:scale-105">
{/* Header */}
<div className="flex items-center gap-3">
<div className={`p-3 rounded-lg ${category.bgColor}`}>
<IconComponent className={`w-6 h-6 ${category.color}`} />
</div>
<h3 className="text-xl font-semibold">
{category.category}
</h3>
</div>
{/* Skills List */}
<div className="space-y-2">
{category.skills.map((skill, skillIndex) => (
<div
key={skillIndex}
className="flex items-center gap-2 text-gray-300"
>
<div
className={`w-2 h-2 rounded-full ${
colorMap[category.color as keyof typeof colorMap] ||
"bg-gray-400"
}`}
/>
<span className="text-sm">{skill}</span>
</div>
))}
</div>
</div>
</motion.div>
);
})}
</div>
</div>
</section>
);
}