first commit
This commit is contained in:
191
src/components/Skills.tsx
Normal file
191
src/components/Skills.tsx
Normal file
@@ -0,0 +1,191 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user