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
</h3>
<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>
</div>
<div className="h-80">

View File

@@ -15,9 +15,13 @@ interface SkillsRadarChartProps {
}
export function SkillsRadarChart({ data }: SkillsRadarChartProps) {
// Transform data for the chart
// Transform data for the chart with abbreviated labels
const chartData = data.map((item) => ({
category: item.category,
shortLabel:
item.category.length > 8
? item.category.substring(0, 8) + "..."
: item.category,
score: item.score,
maxScore: item.maxScore,
}));
@@ -31,34 +35,105 @@ export function SkillsRadarChart({ data }: SkillsRadarChartProps) {
}
return (
<div className="w-full h-[400px]">
<div className="w-full h-[400px] relative">
<ResponsiveContainer width="100%" height="100%">
<RadarChart
data={chartData}
margin={{ top: 20, right: 30, bottom: 20, left: 30 }}
margin={{ top: 40, right: 60, bottom: 40, left: 60 }}
>
<PolarGrid gridType="polygon" />
<PolarAngleAxis
dataKey="category"
tick={{ fontSize: 12, fill: "hsl(var(--foreground))" }}
className="text-xs"
{/* Grid with better visibility */}
<PolarGrid
gridType="polygon"
stroke="rgba(255, 255, 255, 0.2)"
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
angle={90}
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}
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
name="Niveau"
dataKey="score"
stroke="hsl(var(--primary))"
fill="hsl(var(--primary))"
fillOpacity={0.2}
strokeWidth={2}
stroke="#3b82f6"
fill="url(#radarGradient)"
fillOpacity={0.3}
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>
</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>
);
}

View File

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

View File

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

View File

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