feat: homepage and skills : sorting and coloring

This commit is contained in:
Julien Froidefond
2025-08-27 15:02:06 +02:00
parent 84979501fa
commit 725a368b7e
3 changed files with 96 additions and 56 deletions

View File

@@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
import { ChevronDown, ChevronRight, ExternalLink } from "lucide-react";
import { getCategoryIcon } from "@/lib/category-icons";
import { getScoreColors } from "@/lib/score-utils";
import { getImportanceColors } from "@/lib/tech-colors";
import { SkillProgress } from "./skill-progress";
import Link from "next/link";
@@ -29,6 +30,7 @@ interface CategoryCardProps {
id: string;
name: string;
icon?: string;
importance: "incontournable" | "majeure" | "standard";
}>;
};
}
@@ -114,23 +116,39 @@ export function CategoryCard({
<div className="px-3 pb-3 border-t border-white/10 bg-white/5">
{categoryEval && skillCategory && skillsCount > 0 ? (
<div className="pt-3 space-y-2 max-h-60 overflow-y-auto">
{categoryEval.selectedSkillIds.map((skillId) => {
const skill = skillCategory.skills.find(
(s) => s.id === skillId
);
if (!skill) return null;
const skillEval = categoryEval.skills.find(
(s) => s.skillId === skillId
);
return (
<SkillProgress
key={skillId}
skill={skill}
skillEval={skillEval}
/>
);
})}
{categoryEval.selectedSkillIds
.map((skillId) => {
const skill = skillCategory.skills.find(
(s) => s.id === skillId
);
return skill ? { ...skill, id: skillId } : null;
})
.filter(
(skill): skill is NonNullable<typeof skill> => skill !== null
)
.sort((a, b) => {
const importanceOrder = {
incontournable: 2,
majeure: 1,
standard: 0,
};
return (
importanceOrder[b.importance] -
importanceOrder[a.importance]
);
})
.map((skill) => {
const skillEval = categoryEval.skills.find(
(s) => s.skillId === skill.id
);
return (
<SkillProgress
key={skill.id}
skill={skill}
skillEval={skillEval}
/>
);
})}
</div>
) : (
<div className="pt-3 pb-3 text-center">

View File

@@ -13,6 +13,22 @@ export function MentorSection({
userEvaluation,
skillCategories,
}: MentorSectionProps) {
// Fonction de tri par importance
const sortByImportance = (
a: { importance: string },
b: { importance: string }
) => {
const importanceOrder = {
incontournable: 2,
majeure: 1,
standard: 0,
};
return (
importanceOrder[b.importance as keyof typeof importanceOrder] -
importanceOrder[a.importance as keyof typeof importanceOrder]
);
};
// Récupérer les compétences maîtrisées (expert uniquement)
const masteredSkills = userEvaluation.evaluations.flatMap((cat) => {
const skillCategory = skillCategories.find(
@@ -81,6 +97,40 @@ export function MentorSection({
className={`bg-white/5 border border-white/10 rounded-xl p-6 backdrop-blur-sm ${className}`}
>
<div className="space-y-6">
{/* Peut mentorer */}
<div>
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
<span className="w-2 h-2 bg-blue-400 rounded-full"></span>
Peut mentorer
</h3>
<div className="flex flex-wrap gap-3">
{mentorSkills.length > 0 ? (
mentorSkills.sort(sortByImportance).map((tech) => {
const colors = getImportanceColors(tech.importance);
return (
<div
key={tech.id}
className={`flex items-center gap-2 px-3 py-2 rounded-lg ${colors.bg} ${colors.border} border transition-all hover:scale-105`}
>
<TechIcon
iconName={tech.icon}
className="w-4 h-4"
fallbackText={tech.name}
/>
<span className={`text-sm font-medium ${colors.text}`}>
{tech.name}
</span>
</div>
);
})
) : (
<p className="text-slate-400 text-sm">
Aucune compétence mentor configurée
</p>
)}
</div>
</div>
{/* Technologies maîtrisées */}
<div>
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
@@ -89,7 +139,7 @@ export function MentorSection({
</h3>
<div className="flex flex-wrap gap-3">
{masteredSkills.length > 0 ? (
masteredSkills.map((tech) => {
masteredSkills.sort(sortByImportance).map((tech) => {
const colors = getImportanceColors(tech.importance);
return (
<div
@@ -116,40 +166,6 @@ export function MentorSection({
</div>
</div>
{/* Peut mentorer */}
<div>
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
<span className="w-2 h-2 bg-blue-400 rounded-full"></span>
Peut mentorer
</h3>
<div className="flex flex-wrap gap-3">
{mentorSkills.length > 0 ? (
mentorSkills.map((tech) => {
const colors = getImportanceColors(tech.importance);
return (
<div
key={tech.id}
className={`flex items-center gap-2 px-3 py-2 rounded-lg ${colors.bg} ${colors.border} border transition-all hover:scale-105`}
>
<TechIcon
iconName={tech.icon}
className="w-4 h-4"
fallbackText={tech.name}
/>
<span className={`text-sm font-medium ${colors.text}`}>
{tech.name}
</span>
</div>
);
})
) : (
<p className="text-slate-400 text-sm">
Aucune compétence mentor configurée
</p>
)}
</div>
</div>
{/* Technologies à apprendre */}
<div>
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
@@ -158,7 +174,7 @@ export function MentorSection({
</h3>
<div className="flex flex-wrap gap-3">
{learningSkills.length > 0 ? (
learningSkills.map((tech) => {
learningSkills.sort(sortByImportance).map((tech) => {
const colors = getImportanceColors(tech.importance);
return (
<div

View File

@@ -1,11 +1,13 @@
import { TechIcon } from "@/components/icons/tech-icon";
import { getSkillLevelLabel } from "@/lib/score-utils";
import { getImportanceColors } from "@/lib/tech-colors";
interface SkillProgressProps {
skill: {
id: string;
name: string;
icon?: string;
importance: "incontournable" | "majeure" | "standard";
};
skillEval?: {
skillId: string;
@@ -14,15 +16,19 @@ interface SkillProgressProps {
}
export function SkillProgress({ skill, skillEval }: SkillProgressProps) {
const colors = getImportanceColors(skill.importance);
return (
<div className="flex items-center justify-between p-2 bg-white/5 border border-white/10 rounded-lg">
<div
className={`flex items-center justify-between p-2 ${colors.bg} border ${colors.border} rounded-lg`}
>
<div className="flex items-center gap-2">
<TechIcon
iconName={skill.icon || ""}
className="w-4 h-4 text-blue-400"
className={`w-4 h-4 ${colors.text}`}
fallbackText={skill.name}
/>
<span className="text-sm text-white">{skill.name}</span>
<span className={`text-sm ${colors.text}`}>{skill.name}</span>
</div>
<div className="flex items-center gap-2">
{skillEval?.level && (