feat: homepage and skills : sorting and coloring
This commit is contained in:
@@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { ChevronDown, ChevronRight, ExternalLink } from "lucide-react";
|
import { ChevronDown, ChevronRight, ExternalLink } from "lucide-react";
|
||||||
import { getCategoryIcon } from "@/lib/category-icons";
|
import { getCategoryIcon } from "@/lib/category-icons";
|
||||||
import { getScoreColors } from "@/lib/score-utils";
|
import { getScoreColors } from "@/lib/score-utils";
|
||||||
|
import { getImportanceColors } from "@/lib/tech-colors";
|
||||||
import { SkillProgress } from "./skill-progress";
|
import { SkillProgress } from "./skill-progress";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ interface CategoryCardProps {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
icon?: 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">
|
<div className="px-3 pb-3 border-t border-white/10 bg-white/5">
|
||||||
{categoryEval && skillCategory && skillsCount > 0 ? (
|
{categoryEval && skillCategory && skillsCount > 0 ? (
|
||||||
<div className="pt-3 space-y-2 max-h-60 overflow-y-auto">
|
<div className="pt-3 space-y-2 max-h-60 overflow-y-auto">
|
||||||
{categoryEval.selectedSkillIds.map((skillId) => {
|
{categoryEval.selectedSkillIds
|
||||||
const skill = skillCategory.skills.find(
|
.map((skillId) => {
|
||||||
(s) => s.id === skillId
|
const skill = skillCategory.skills.find(
|
||||||
);
|
(s) => s.id === skillId
|
||||||
if (!skill) return null;
|
);
|
||||||
|
return skill ? { ...skill, id: skillId } : null;
|
||||||
const skillEval = categoryEval.skills.find(
|
})
|
||||||
(s) => s.skillId === skillId
|
.filter(
|
||||||
);
|
(skill): skill is NonNullable<typeof skill> => skill !== null
|
||||||
return (
|
)
|
||||||
<SkillProgress
|
.sort((a, b) => {
|
||||||
key={skillId}
|
const importanceOrder = {
|
||||||
skill={skill}
|
incontournable: 2,
|
||||||
skillEval={skillEval}
|
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>
|
||||||
) : (
|
) : (
|
||||||
<div className="pt-3 pb-3 text-center">
|
<div className="pt-3 pb-3 text-center">
|
||||||
|
|||||||
@@ -13,6 +13,22 @@ export function MentorSection({
|
|||||||
userEvaluation,
|
userEvaluation,
|
||||||
skillCategories,
|
skillCategories,
|
||||||
}: MentorSectionProps) {
|
}: 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)
|
// Récupérer les compétences maîtrisées (expert uniquement)
|
||||||
const masteredSkills = userEvaluation.evaluations.flatMap((cat) => {
|
const masteredSkills = userEvaluation.evaluations.flatMap((cat) => {
|
||||||
const skillCategory = skillCategories.find(
|
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}`}
|
className={`bg-white/5 border border-white/10 rounded-xl p-6 backdrop-blur-sm ${className}`}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<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 */}
|
{/* Technologies maîtrisées */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
|
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
|
||||||
@@ -89,7 +139,7 @@ export function MentorSection({
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="flex flex-wrap gap-3">
|
<div className="flex flex-wrap gap-3">
|
||||||
{masteredSkills.length > 0 ? (
|
{masteredSkills.length > 0 ? (
|
||||||
masteredSkills.map((tech) => {
|
masteredSkills.sort(sortByImportance).map((tech) => {
|
||||||
const colors = getImportanceColors(tech.importance);
|
const colors = getImportanceColors(tech.importance);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -116,40 +166,6 @@ export function MentorSection({
|
|||||||
</div>
|
</div>
|
||||||
</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 */}
|
{/* Technologies à apprendre */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
|
<h3 className="text-lg font-semibold text-white mb-3 flex items-center gap-2">
|
||||||
@@ -158,7 +174,7 @@ export function MentorSection({
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="flex flex-wrap gap-3">
|
<div className="flex flex-wrap gap-3">
|
||||||
{learningSkills.length > 0 ? (
|
{learningSkills.length > 0 ? (
|
||||||
learningSkills.map((tech) => {
|
learningSkills.sort(sortByImportance).map((tech) => {
|
||||||
const colors = getImportanceColors(tech.importance);
|
const colors = getImportanceColors(tech.importance);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { TechIcon } from "@/components/icons/tech-icon";
|
import { TechIcon } from "@/components/icons/tech-icon";
|
||||||
import { getSkillLevelLabel } from "@/lib/score-utils";
|
import { getSkillLevelLabel } from "@/lib/score-utils";
|
||||||
|
import { getImportanceColors } from "@/lib/tech-colors";
|
||||||
|
|
||||||
interface SkillProgressProps {
|
interface SkillProgressProps {
|
||||||
skill: {
|
skill: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
importance: "incontournable" | "majeure" | "standard";
|
||||||
};
|
};
|
||||||
skillEval?: {
|
skillEval?: {
|
||||||
skillId: string;
|
skillId: string;
|
||||||
@@ -14,15 +16,19 @@ interface SkillProgressProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function SkillProgress({ skill, skillEval }: SkillProgressProps) {
|
export function SkillProgress({ skill, skillEval }: SkillProgressProps) {
|
||||||
|
const colors = getImportanceColors(skill.importance);
|
||||||
|
|
||||||
return (
|
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">
|
<div className="flex items-center gap-2">
|
||||||
<TechIcon
|
<TechIcon
|
||||||
iconName={skill.icon || ""}
|
iconName={skill.icon || ""}
|
||||||
className="w-4 h-4 text-blue-400"
|
className={`w-4 h-4 ${colors.text}`}
|
||||||
fallbackText={skill.name}
|
fallbackText={skill.name}
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-white">{skill.name}</span>
|
<span className={`text-sm ${colors.text}`}>{skill.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{skillEval?.level && (
|
{skillEval?.level && (
|
||||||
|
|||||||
Reference in New Issue
Block a user