191 lines
6.0 KiB
TypeScript
191 lines
6.0 KiB
TypeScript
import { motion } from 'framer-motion';
|
|
import { Code, Database, Smartphone, Globe, Server, Wrench } from 'lucide-react';
|
|
|
|
const Skills = () => {
|
|
const skillCategories = [
|
|
{
|
|
icon: <Smartphone size={32} />,
|
|
title: "Mobile",
|
|
color: "#4FC3F7",
|
|
skills: [
|
|
{ name: "Dart", level: 85, color: "#0175C2" },
|
|
{ name: "Flutter", level: 80, color: "#02569B" }
|
|
]
|
|
},
|
|
{
|
|
icon: <Globe size={32} />,
|
|
title: "Frontend",
|
|
color: "#42A5F5",
|
|
skills: [
|
|
{ name: "React", level: 75, color: "#61DAFB" },
|
|
{ name: "TypeScript", level: 70, color: "#3178C6" },
|
|
{ name: "JavaScript", level: 80, color: "#F7DF1E" }
|
|
]
|
|
},
|
|
{
|
|
icon: <Server size={32} />,
|
|
title: "Backend",
|
|
color: "#66BB6A",
|
|
skills: [
|
|
{ name: "Java", level: 75, color: "#ED8B00" },
|
|
{ name: "C#", level: 65, color: "#239120" }
|
|
]
|
|
},
|
|
{
|
|
icon: <Database size={32} />,
|
|
title: "Outils & Autres",
|
|
color: "#AB47BC",
|
|
skills: [
|
|
{ name: "Git", level: 70, color: "#F05032" },
|
|
{ name: "VS Code", level: 90, color: "#007ACC" },
|
|
{ name: "Android Studio", level: 75, color: "#3DDC84" }
|
|
]
|
|
}
|
|
];
|
|
|
|
const containerVariants = {
|
|
hidden: { opacity: 0 },
|
|
visible: {
|
|
opacity: 1,
|
|
transition: {
|
|
staggerChildren: 0.2,
|
|
delayChildren: 0.3
|
|
}
|
|
}
|
|
};
|
|
|
|
const categoryVariants = {
|
|
hidden: { opacity: 0, y: 50 },
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 0.6,
|
|
ease: [0.25, 0.1, 0.25, 1] as const
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<section id="skills" className="skills">
|
|
<div className="container">
|
|
<motion.div
|
|
className="section-header"
|
|
initial={{ opacity: 0, y: 50 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8 }}
|
|
viewport={{ once: true }}
|
|
>
|
|
<h2 className="section-title">Compétences & Technologies</h2>
|
|
<p className="section-subtitle">
|
|
Les technologies que je maîtrise et avec lesquelles j'aime travailler
|
|
</p>
|
|
</motion.div>
|
|
|
|
<motion.div
|
|
className="skills-grid"
|
|
variants={containerVariants}
|
|
initial="hidden"
|
|
whileInView="visible"
|
|
viewport={{ once: true }}
|
|
>
|
|
{skillCategories.map((category, categoryIndex) => (
|
|
<motion.div
|
|
key={category.title}
|
|
className="skill-category"
|
|
variants={categoryVariants}
|
|
whileHover={{
|
|
scale: 1.02,
|
|
y: -5,
|
|
transition: { duration: 0.3 }
|
|
}}
|
|
>
|
|
<div className="category-header">
|
|
<div
|
|
className="category-icon"
|
|
style={{ backgroundColor: `${category.color}20`, color: category.color }}
|
|
>
|
|
{category.icon}
|
|
</div>
|
|
<h3 className="category-title">{category.title}</h3>
|
|
</div>
|
|
|
|
<div className="skills-list">
|
|
{category.skills.map((skill, skillIndex) => (
|
|
<motion.div
|
|
key={skill.name}
|
|
className="skill-item"
|
|
initial={{ opacity: 0, x: -30 }}
|
|
whileInView={{ opacity: 1, x: 0 }}
|
|
transition={{
|
|
duration: 0.5,
|
|
delay: (categoryIndex * 0.2) + (skillIndex * 0.1)
|
|
}}
|
|
viewport={{ once: true }}
|
|
>
|
|
<div className="skill-header">
|
|
<span className="skill-name">{skill.name}</span>
|
|
<span className="skill-percentage">{skill.level}%</span>
|
|
</div>
|
|
|
|
<div className="skill-bar">
|
|
<motion.div
|
|
className="skill-progress"
|
|
style={{ backgroundColor: skill.color }}
|
|
initial={{ width: 0 }}
|
|
whileInView={{ width: `${skill.level}%` }}
|
|
transition={{
|
|
duration: 1.5,
|
|
delay: (categoryIndex * 0.2) + (skillIndex * 0.1) + 0.5,
|
|
ease: [0.25, 0.1, 0.25, 1] as const
|
|
}}
|
|
viewport={{ once: true }}
|
|
/>
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
|
|
{/* Section des soft skills */}
|
|
<motion.div
|
|
className="soft-skills"
|
|
initial={{ opacity: 0, y: 50 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.3 }}
|
|
viewport={{ once: true }}
|
|
>
|
|
<h3 className="soft-skills-title">Autres compétences</h3>
|
|
<div className="soft-skills-grid">
|
|
{[
|
|
{ name: "Résolution de problèmes", icon: <Wrench size={20} /> },
|
|
{ name: "Travail en équipe", icon: <Code size={20} /> },
|
|
{ name: "Apprentissage continu", icon: <Database size={20} /> },
|
|
{ name: "Communication", icon: <Globe size={20} /> }
|
|
].map((softSkill, index) => (
|
|
<motion.div
|
|
key={softSkill.name}
|
|
className="soft-skill-tag"
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
|
whileInView={{ opacity: 1, scale: 1 }}
|
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
|
whileHover={{
|
|
scale: 1.05,
|
|
transition: { duration: 0.2 }
|
|
}}
|
|
viewport={{ once: true }}
|
|
>
|
|
{softSkill.icon}
|
|
<span>{softSkill.name}</span>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default Skills; |