Refactor radar chart and improve UI elements

- Updated radar chart to use abbreviated category labels for better readability.
- Enhanced chart visibility with improved grid and axis styling.
- Added a gradient background to the radar area for a more polished look.
- Simplified links in JSON files for backend, cloud, and devops skills.
- Adjusted HomePage text for clarity and consistency.
This commit is contained in:
Julien Froidefond
2025-08-20 16:10:28 +02:00
parent 5c510ebd07
commit e6d4bbe13d
5 changed files with 114 additions and 108 deletions

View File

@@ -124,7 +124,7 @@ export default function HomePage() {
Vue d'ensemble de vos compétences Vue d'ensemble de vos compétences
</h3> </h3>
<p className="text-slate-400 text-sm"> <p className="text-slate-400 text-sm">
Graphique radar représentant votre niveau moyen par catégorie Radar chart représentant votre niveau par catégorie
</p> </p>
</div> </div>
<div className="h-80"> <div className="h-80">

View File

@@ -15,9 +15,13 @@ interface SkillsRadarChartProps {
} }
export function SkillsRadarChart({ data }: SkillsRadarChartProps) { export function SkillsRadarChart({ data }: SkillsRadarChartProps) {
// Transform data for the chart // Transform data for the chart with abbreviated labels
const chartData = data.map((item) => ({ const chartData = data.map((item) => ({
category: item.category, category: item.category,
shortLabel:
item.category.length > 8
? item.category.substring(0, 8) + "..."
: item.category,
score: item.score, score: item.score,
maxScore: item.maxScore, maxScore: item.maxScore,
})); }));
@@ -31,34 +35,105 @@ export function SkillsRadarChart({ data }: SkillsRadarChartProps) {
} }
return ( return (
<div className="w-full h-[400px]"> <div className="w-full h-[400px] relative">
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<RadarChart <RadarChart
data={chartData} data={chartData}
margin={{ top: 20, right: 30, bottom: 20, left: 30 }} margin={{ top: 40, right: 60, bottom: 40, left: 60 }}
> >
<PolarGrid gridType="polygon" /> {/* Grid with better visibility */}
<PolarAngleAxis <PolarGrid
dataKey="category" gridType="polygon"
tick={{ fontSize: 12, fill: "hsl(var(--foreground))" }} stroke="rgba(255, 255, 255, 0.2)"
className="text-xs" strokeWidth={1}
/> />
{/* Category labels with better positioning */}
<PolarAngleAxis
dataKey="shortLabel"
tick={{
fontSize: 13,
fill: "rgba(255, 255, 255, 0.9)",
fontWeight: 500,
}}
tickFormatter={(value, index) => {
return chartData[index]?.category || value;
}}
/>
{/* Radial axis with custom ticks */}
<PolarRadiusAxis <PolarRadiusAxis
angle={90} angle={90}
domain={[0, 3]} domain={[0, 3]}
tick={{ fontSize: 10, fill: "hsl(var(--muted-foreground))" }} tick={{
fontSize: 11,
fill: "rgba(255, 255, 255, 0.6)",
fontWeight: 400,
}}
tickCount={4} tickCount={4}
tickFormatter={(value) => {
if (value === 0) return "";
if (value === 1) return "Débutant";
if (value === 2) return "Autonome";
if (value === 3) return "Expert";
return value.toString();
}}
/> />
{/* Main radar area with gradient */}
<Radar <Radar
name="Niveau" name="Niveau"
dataKey="score" dataKey="score"
stroke="hsl(var(--primary))" stroke="#3b82f6"
fill="hsl(var(--primary))" fill="url(#radarGradient)"
fillOpacity={0.2} fillOpacity={0.3}
strokeWidth={2} strokeWidth={3}
dot={{
fill: "#3b82f6",
strokeWidth: 2,
stroke: "#ffffff",
r: 6,
}}
/> />
{/* Background reference radar for max score */}
<Radar
name="Maximum"
dataKey="maxScore"
stroke="rgba(255, 255, 255, 0.2)"
fill="transparent"
strokeWidth={1}
strokeDasharray="5 5"
dot={false}
/>
{/* Gradient definition */}
<defs>
<linearGradient
id="radarGradient"
x1="0%"
y1="0%"
x2="100%"
y2="100%"
>
<stop offset="0%" stopColor="#3b82f6" stopOpacity={0.4} />
<stop offset="100%" stopColor="#1d4ed8" stopOpacity={0.1} />
</linearGradient>
</defs>
</RadarChart> </RadarChart>
</ResponsiveContainer> </ResponsiveContainer>
{/* Legend */}
<div className="absolute bottom-2 right-2 text-xs text-slate-400 space-y-1">
<div className="flex items-center gap-2">
<div className="w-3 h-0.5 bg-blue-500"></div>
<span>Votre niveau</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-0.5 border-t border-dashed border-white/40"></div>
<span>Maximum</span>
</div>
</div>
</div> </div>
); );
} }

View File

@@ -66,28 +66,19 @@
"id": "golang", "id": "golang",
"name": "Go", "name": "Go",
"description": "Langage de programmation développé par Google", "description": "Langage de programmation développé par Google",
"links": [ "links": ["https://golang.org/", "https://golang.org/doc/"]
"https://golang.org/",
"https://golang.org/doc/"
]
}, },
{ {
"id": "rust", "id": "rust",
"name": "Rust", "name": "Rust",
"description": "Langage de programmation système sûr et performant", "description": "Langage de programmation système sûr et performant",
"links": [ "links": ["https://www.rust-lang.org/", "https://doc.rust-lang.org/"]
"https://www.rust-lang.org/",
"https://doc.rust-lang.org/"
]
}, },
{ {
"id": "java-spring", "id": "java-spring",
"name": "Java Spring", "name": "Java Spring",
"description": "Framework Java pour applications d'entreprise", "description": "Framework Java pour applications d'entreprise",
"links": [ "links": ["https://spring.io/", "https://docs.spring.io/"]
"https://spring.io/",
"https://docs.spring.io/"
]
}, },
{ {
"id": "csharp-dotnet", "id": "csharp-dotnet",
@@ -102,64 +93,43 @@
"id": "php-laravel", "id": "php-laravel",
"name": "PHP Laravel", "name": "PHP Laravel",
"description": "Framework PHP moderne pour applications web", "description": "Framework PHP moderne pour applications web",
"links": [ "links": ["https://laravel.com/", "https://laravel.com/docs"]
"https://laravel.com/",
"https://laravel.com/docs"
]
}, },
{ {
"id": "ruby-rails", "id": "ruby-rails",
"name": "Ruby on Rails", "name": "Ruby on Rails",
"description": "Framework web en Ruby", "description": "Framework web en Ruby",
"links": [ "links": ["https://rubyonrails.org/", "https://guides.rubyonrails.org/"]
"https://rubyonrails.org/",
"https://guides.rubyonrails.org/"
]
}, },
{ {
"id": "graphql", "id": "graphql",
"name": "GraphQL", "name": "GraphQL",
"description": "Langage de requête pour APIs", "description": "Langage de requête pour APIs",
"links": [ "links": ["https://graphql.org/", "https://graphql.org/learn/"]
"https://graphql.org/",
"https://graphql.org/learn/"
]
}, },
{ {
"id": "prisma", "id": "prisma",
"name": "Prisma", "name": "Prisma",
"description": "ORM moderne pour Node.js et TypeScript", "description": "ORM moderne pour Node.js et TypeScript",
"links": [ "links": ["https://www.prisma.io/", "https://www.prisma.io/docs"]
"https://www.prisma.io/",
"https://www.prisma.io/docs"
]
}, },
{ {
"id": "trpc", "id": "trpc",
"name": "tRPC", "name": "tRPC",
"description": "Framework TypeScript pour APIs type-safe", "description": "Framework TypeScript pour APIs type-safe",
"links": [ "links": ["https://trpc.io/", "https://trpc.io/docs"]
"https://trpc.io/",
"https://trpc.io/docs"
]
}, },
{ {
"id": "nest-js", "id": "nest-js",
"name": "NestJS", "name": "NestJS",
"description": "Framework Node.js pour applications scalables", "description": "Framework Node.js pour applications scalables",
"links": [ "links": ["https://nestjs.com/", "https://docs.nestjs.com/"]
"https://nestjs.com/",
"https://docs.nestjs.com/"
]
}, },
{ {
"id": "fastify", "id": "fastify",
"name": "Fastify", "name": "Fastify",
"description": "Framework web rapide pour Node.js", "description": "Framework web rapide pour Node.js",
"links": [ "links": ["https://www.fastify.io/", "https://www.fastify.io/docs/"]
"https://www.fastify.io/",
"https://www.fastify.io/docs/"
]
}, },
{ {
"id": "rabbitmq", "id": "rabbitmq",

View File

@@ -6,10 +6,7 @@
"id": "aws", "id": "aws",
"name": "Amazon Web Services", "name": "Amazon Web Services",
"description": "Plateforme de services cloud d'Amazon", "description": "Plateforme de services cloud d'Amazon",
"links": [ "links": ["https://aws.amazon.com/", "https://docs.aws.amazon.com/"]
"https://aws.amazon.com/",
"https://docs.aws.amazon.com/"
]
}, },
{ {
"id": "azure", "id": "azure",
@@ -24,10 +21,7 @@
"id": "gcp", "id": "gcp",
"name": "Google Cloud Platform", "name": "Google Cloud Platform",
"description": "Services cloud de Google", "description": "Services cloud de Google",
"links": [ "links": ["https://cloud.google.com/", "https://cloud.google.com/docs"]
"https://cloud.google.com/",
"https://cloud.google.com/docs"
]
}, },
{ {
"id": "terraform", "id": "terraform",
@@ -69,10 +63,7 @@
"id": "s3", "id": "s3",
"name": "Amazon S3", "name": "Amazon S3",
"description": "Service de stockage d'objets d'AWS", "description": "Service de stockage d'objets d'AWS",
"links": [ "links": ["https://aws.amazon.com/s3/", "https://docs.aws.amazon.com/s3/"]
"https://aws.amazon.com/s3/",
"https://docs.aws.amazon.com/s3/"
]
}, },
{ {
"id": "ec2", "id": "ec2",

View File

@@ -66,19 +66,13 @@
"id": "ansible", "id": "ansible",
"name": "Ansible", "name": "Ansible",
"description": "Outil d'automatisation IT et de gestion de configuration", "description": "Outil d'automatisation IT et de gestion de configuration",
"links": [ "links": ["https://www.ansible.com/", "https://docs.ansible.com/"]
"https://www.ansible.com/",
"https://docs.ansible.com/"
]
}, },
{ {
"id": "jenkins", "id": "jenkins",
"name": "Jenkins", "name": "Jenkins",
"description": "Serveur d'automatisation open source", "description": "Serveur d'automatisation open source",
"links": [ "links": ["https://www.jenkins.io/", "https://www.jenkins.io/doc/"]
"https://www.jenkins.io/",
"https://www.jenkins.io/doc/"
]
}, },
{ {
"id": "gitlab-ci", "id": "gitlab-ci",
@@ -93,19 +87,13 @@
"id": "prometheus", "id": "prometheus",
"name": "Prometheus", "name": "Prometheus",
"description": "Système de monitoring et d'alerting", "description": "Système de monitoring et d'alerting",
"links": [ "links": ["https://prometheus.io/", "https://prometheus.io/docs/"]
"https://prometheus.io/",
"https://prometheus.io/docs/"
]
}, },
{ {
"id": "grafana", "id": "grafana",
"name": "Grafana", "name": "Grafana",
"description": "Plateforme de visualisation et monitoring", "description": "Plateforme de visualisation et monitoring",
"links": [ "links": ["https://grafana.com/", "https://grafana.com/docs/"]
"https://grafana.com/",
"https://grafana.com/docs/"
]
}, },
{ {
"id": "elk-stack", "id": "elk-stack",
@@ -120,46 +108,31 @@
"id": "nginx", "id": "nginx",
"name": "Nginx", "name": "Nginx",
"description": "Serveur web et proxy inverse", "description": "Serveur web et proxy inverse",
"links": [ "links": ["https://nginx.org/", "https://nginx.org/en/docs/"]
"https://nginx.org/",
"https://nginx.org/en/docs/"
]
}, },
{ {
"id": "apache", "id": "apache",
"name": "Apache HTTP Server", "name": "Apache HTTP Server",
"description": "Serveur web open source", "description": "Serveur web open source",
"links": [ "links": ["https://httpd.apache.org/", "https://httpd.apache.org/docs/"]
"https://httpd.apache.org/",
"https://httpd.apache.org/docs/"
]
}, },
{ {
"id": "traefik", "id": "traefik",
"name": "Traefik", "name": "Traefik",
"description": "Proxy inverse moderne et load balancer", "description": "Proxy inverse moderne et load balancer",
"links": [ "links": ["https://traefik.io/", "https://doc.traefik.io/"]
"https://traefik.io/",
"https://doc.traefik.io/"
]
}, },
{ {
"id": "helm", "id": "helm",
"name": "Helm", "name": "Helm",
"description": "Gestionnaire de packages pour Kubernetes", "description": "Gestionnaire de packages pour Kubernetes",
"links": [ "links": ["https://helm.sh/", "https://helm.sh/docs/"]
"https://helm.sh/",
"https://helm.sh/docs/"
]
}, },
{ {
"id": "istio", "id": "istio",
"name": "Istio", "name": "Istio",
"description": "Service mesh pour microservices", "description": "Service mesh pour microservices",
"links": [ "links": ["https://istio.io/", "https://istio.io/latest/docs/"]
"https://istio.io/",
"https://istio.io/latest/docs/"
]
}, },
{ {
"id": "vault", "id": "vault",
@@ -174,10 +147,7 @@
"id": "consul", "id": "consul",
"name": "HashiCorp Consul", "name": "HashiCorp Consul",
"description": "Service discovery et configuration", "description": "Service discovery et configuration",
"links": [ "links": ["https://www.consul.io/", "https://learn.hashicorp.com/consul"]
"https://www.consul.io/",
"https://learn.hashicorp.com/consul"
]
}, },
{ {
"id": "nomad", "id": "nomad",