feat(parcours): intégration des sections de la page Parcours conforme à Figma

- Prise en charge du thème sombre du Header sur la route /parcours
- Ajout de la section Hero et présentation des chiffres clés
- Grille des profils 'Qui peut rejoindre' avec méthode map() et icônes
- Intégration de la timeline verticale des étapes d'intégration
- Ajout du bandeau 'Learning by Doing'
- Restructuration des composants par dossier
This commit is contained in:
MohamedLoum1001
2026-09-30 15:38:26 +02:00
parent f66e39ab09
commit bb1393e9ef
44 changed files with 1366 additions and 140 deletions

View File

@ -0,0 +1,175 @@
import React, { useState } from 'react';
import bannerBg from '../../img/homepageactuality.png';
const CATEGORIES = ['Tout', 'Actualités', 'Publications', 'Évènements', 'Projets'];
const NEWS_ITEMS = [
{ id: 1, tag: 'En ce moment' },
{ id: 2, tag: 'En ce moment' },
{ id: 3, tag: 'En ce moment' },
{ id: 4, tag: 'En ce moment' },
];
export default function ActualitySection() {
const [activeCategory, setActiveCategory] = useState('Tout');
const [email, setEmail] = useState('');
const handleSubmitNewsletter = (e) => {
e.preventDefault();
if (email) {
alert(`Inscription enregistrée pour : ${email}`);
setEmail('');
}
};
return (
<section className="w-full bg-white">
{/* 1. BANNIÈRE SUPÉRIEURE PLEINE LARGEUR */}
<div
className="relative w-full min-h-[460px] lg:min-h-[500px] bg-cover bg-right bg-no-repeat flex items-center overflow-hidden"
style={{ backgroundImage: `url("${bannerBg}")` }}
>
{/* Dégradé Figma : Blanc pur à gauche avec transition douce vers le paysage */}
<div
className="absolute inset-0 pointer-events-none"
style={{
background:
'linear-gradient(90deg, #ffffff 0%, #ffffff 38%, rgba(255,255,255,0.85) 48%, rgba(255,255,255,0) 68%)',
}}
/>
<div className="relative z-10 max-w-[1440px] w-full mx-auto px-6 sm:px-12 lg:px-16 py-12 flex flex-col lg:flex-row lg:items-center justify-between gap-10">
{/* Bloc Texte & CTA Gauche */}
<div className="max-w-md lg:max-w-lg shrink-0">
<span className="text-[0.72rem] font-bold tracking-[0.2em] text-[#8c8f3e] uppercase block mb-3">
ACTUALITÉ
</span>
<h2 className="text-3xl sm:text-4xl lg:text-[2.65rem] font-extrabold text-[#0b1320] leading-[1.18] tracking-tight mb-4">
Restez informé, <br />
Inspirer le changement
</h2>
<p className="text-xs sm:text-sm text-slate-500 mb-6 max-w-sm leading-relaxed">
Découvrez nos dernières actualités, publications, événements et initiatives sur le terrain
</p>
<a
href="#actualites"
className="inline-block bg-[#798334] hover:bg-[#656d2b] text-white text-xs sm:text-sm font-semibold px-6 py-2.5 rounded-full transition-colors shadow-sm"
>
Voir toute les actualité
</a>
</div>
{/* Carte Blanche Flottante "En ce moment" */}
<div className="bg-white rounded-3xl p-6 sm:p-8 shadow-[0_12px_36px_rgba(0,0,0,0.1)] border border-slate-100/60 w-full lg:max-w-[460px] h-[210px] sm:h-[230px] flex flex-col justify-between shrink-0">
<span className="text-xs font-semibold text-[#8c8f3e]">
En ce moment
</span>
<div className="text-slate-300 text-xs italic">
{/* Espace prévu pour le résumé de l'article à la une */}
</div>
<div className="h-2 w-14 bg-[#edf0db] rounded-full"></div>
</div>
</div>
</div>
{/* 2. ONGLETS DE FILTRES + GRILLE D'ACTUALITÉS */}
<div className="max-w-[1440px] mx-auto px-6 sm:px-12 lg:px-16 pt-10 pb-16">
{/* Menu épuré avec soulignement */}
<nav className="flex items-center gap-8 sm:gap-12 mb-10 overflow-x-auto no-scrollbar">
{CATEGORIES.map((cat) => {
const isActive = activeCategory === cat;
return (
<button
key={cat}
type="button"
onClick={() => setActiveCategory(cat)}
className={`text-sm tracking-tight transition-colors pb-1.5 relative whitespace-nowrap bg-transparent border-none cursor-pointer p-0 ${isActive
? 'text-slate-900 font-bold'
: 'text-slate-600 hover:text-slate-900 font-medium'
}`}
>
{cat}
{isActive && (
<span className="absolute bottom-0 left-0 w-full h-[2px] bg-slate-900 rounded-full" />
)}
</button>
);
})}
</nav>
{/* Grille des 4 cartes d'articles */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 mb-16">
{NEWS_ITEMS.map((item) => (
<div
key={item.id}
className="bg-[#edf0db] rounded-2xl h-[300px] p-6 flex flex-col justify-between border border-[#e2e6cb] hover:shadow-md transition-shadow cursor-pointer"
>
<span className="text-xs font-semibold text-[#798334]">
{item.tag}
</span>
<div className="space-y-2.5">
<div className="h-3 w-4/5 bg-white/80 rounded-full"></div>
<div className="h-3 w-3/5 bg-white/80 rounded-full"></div>
</div>
</div>
))}
</div>
{/* 3. BANDEAU NEWSLETTER AUX COULEURS DE FIGMA */}
<div className="bg-[#C3A569] rounded-2xl p-6 sm:p-10 flex flex-col lg:flex-row items-center justify-between gap-6 shadow-sm">
{/* Icône enveloppe + Textes */}
<div className="flex items-center gap-6 max-w-xl">
{/* Cercle d'arrière-plan #D9D9D9 */}
<div className="w-16 h-16 rounded-full bg-[#D9D9D9] flex items-center justify-center shrink-0 shadow-inner">
{/* Icône violette #6568B9 */}
<svg
className="w-8 h-8 text-[#6568B9]"
fill="none"
stroke="currentColor"
strokeWidth="1.9"
strokeLinecap="round"
strokeLinejoin="round"
viewBox="0 0 24 24"
>
<rect x="3" y="5" width="18" height="14" rx="2" />
<polyline points="3 7 12 13 21 7" />
</svg>
</div>
<div>
<h3 className="text-lg sm:text-xl font-bold text-white leading-tight">
Ne manquez rien de nos actualités
</h3>
<p className="text-xs sm:text-sm text-white/90 mt-1 leading-relaxed">
Abonnez-vous à notre Newsletter pour recevoir nos dernières nouvelles et publications.
</p>
</div>
</div>
{/* Formulaire d'inscription */}
<form onSubmit={handleSubmitNewsletter} className="w-full lg:w-auto flex-1 max-w-md">
<div className="relative flex items-center">
<input
type="email"
required
placeholder="Votre adresse e-mail"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full bg-white/20 text-white placeholder-white/80 border border-white/50 rounded-full px-5 py-3 text-xs sm:text-sm focus:outline-none focus:ring-2 focus:ring-white pr-32"
/>
<button
type="submit"
className="absolute right-1.5 bg-[#8c8f3e] hover:bg-[#737630] text-white text-xs font-semibold px-5 py-2 rounded-full transition-colors shadow-sm"
>
S'abonner
</button>
</div>
<span className="text-[0.68rem] text-white/80 block mt-2 ml-4">
Nous respectons votre vie privée. Désinscription possible à tout moment.
</span>
</form>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,300 @@
import React from 'react';
import carreerBg from '../../img/carreer.png';
export default function CareersSection() {
const parcours = [
{
label: 'Insertion professionnelle',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
</svg>
),
},
{
label: 'Développement de compétences',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H8V4h12v12z" />
</svg>
),
},
{
label: 'Leadership & coordination',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z" />
</svg>
),
},
{
label: 'Entrepreneuriat & innovation',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7z" />
</svg>
),
},
{
label: 'Recherche appliquée',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7" />
<path strokeLinecap="round" strokeLinejoin="round" d="m20 20-3.5-3.5" />
</svg>
),
},
{
label: 'Alumni & réseau',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 3 1 9l11 6 9-4.91V17h2V9L12 3z M5 13.18v4L12 21l7-3.82v-4L12 17l-7-3.82z" />
</svg>
),
},
];
const competencesCol1 = [
{
label: 'Autonomie',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
</svg>
),
},
{
label: 'Gestion de projet',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z" />
</svg>
),
},
{
label: 'Coordination',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<circle cx="9" cy="9" r="4" />
<path d="M9 15c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4zm7.76-9.64-1.41 1.41 1.41 1.41-1.41 1.42 1.41 1.41 1.42-1.41 1.41 1.41 1.41-1.41-1.41-1.42 1.41-1.41-1.41-1.41-1.42 1.41z" />
</svg>
),
},
{
label: 'Communication',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z" />
</svg>
),
},
{
label: 'Stratégie',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="9" />
<circle cx="12" cy="12" r="5" />
<circle cx="12" cy="12" r="1" />
</svg>
),
},
];
const competencesCol2 = [
{
label: 'Leadership',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
</svg>
),
},
{
label: 'Compétences opérationnelles',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="m14.7 6.3 3 3-9.4 9.4H5.3v-3l9.4-9.4z" />
</svg>
),
},
{
label: 'Stabilité professionnelle',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 1 3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z" />
</svg>
),
},
{
label: 'Capacité d’adaptation',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" />
</svg>
),
},
{
label: 'Intelligence systémique',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
</svg>
),
},
];
const opportunites = [
{
label: 'Stages',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z" />
</svg>
),
},
{
label: 'Mandats',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z" />
</svg>
),
},
{
label: 'Bénévolats',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="m12 21.35-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />
</svg>
),
},
{
label: 'Collaborations',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z" />
</svg>
),
},
{
label: 'Projets entrepreneuriaux',
icon: (
<svg className="w-4 h-4 text-[#88ACE3]" fill="currentColor" viewBox="0 0 24 24">
<path d="M13.13 2.51c.37-.47.96-.71 1.57-.64.81.1 1.41.81 1.35 1.63L15.6 9h4.4c.73 0 1.35.52 1.48 1.24.13.72-.25 1.44-.9 1.74l-9 4.15c-.48.22-1.04.14-1.45-.2-.41-.34-.58-.88-.44-1.39L10.8 11H6.5c-.71 0-1.33-.5-1.47-1.2-.14-.7.22-1.41.86-1.72l7.24-5.57z" />
</svg>
),
},
];
return (
<section className="w-full bg-white pb-20">
{/* 1. BANNIÈRE SUPÉRIEURE PLEINE LARGEUR */}
<div
className="relative w-full min-h-[460px] lg:min-h-[500px] bg-cover bg-right bg-no-repeat flex items-center overflow-hidden"
style={{ backgroundImage: `url("${carreerBg}")` }}
>
{/* Dégradé Figma : Sombre à gauche avec fondu vers les personnes à droite */}
<div
className="absolute inset-0 pointer-events-none"
style={{
background:
'linear-gradient(90deg, #000000 0%, rgba(0,0,0,0.92) 34%, rgba(0,0,0,0.68) 52%, rgba(0,0,0,0) 75%)',
}}
/>
<div className="relative z-10 max-w-[1440px] w-full mx-auto px-6 sm:px-12 lg:px-16 py-12">
<div className="max-w-xl text-white">
<span className="text-[0.72rem] font-bold tracking-[0.2em] text-[#C3A569] uppercase block mb-3">
CAREERS & DEVELOPMENT
</span>
<h2 className="text-3xl sm:text-4xl lg:text-[2.65rem] font-extrabold leading-[1.15] tracking-tight mb-4">
Construire des trajectoires, <br />
pas seuement des emplois
</h2>
<p className="text-xs sm:text-sm text-slate-300 mb-2 max-w-lg leading-relaxed font-light">
Chez gaea21, les participants développent des compétences réelles à travers des projets réels, dans un environnement structuré, collaboratif et évolutif.
</p>
<p className="text-xs sm:text-sm text-slate-300 mb-8 max-w-lg leading-relaxed font-light">
L'objectif n'est pas un simple recrutement, mais la construction de trajectoires humaines et professionnelles durables.
</p>
<a
href="#parcours"
className="inline-flex items-center gap-2 bg-[#98984B] hover:bg-[#868641] text-white text-xs sm:text-sm font-semibold px-6 py-2.5 rounded-full transition-colors shadow-sm"
>
<span>Explorer les parcours</span>
<svg className="w-4 h-4" fill="none" stroke="currentColor" strokeWidth="2.5" viewBox="0 0 24 24">
<line x1="5" y1="12" x2="19" y2="12"></line>
<polyline points="12 5 19 12 12 19"></polyline>
</svg>
</a>
</div>
</div>
</div>
{/* 2. GRILLE DES 3 CARTES DU BAS (BEIGE #F1F0E0) */}
<div className="max-w-[1440px] mx-auto px-6 sm:px-12 lg:px-16 pt-10">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 items-stretch">
{/* CARTE 1 : Parcours disponibles */}
<div className="lg:col-span-4 bg-[#F1F0E0] rounded-2xl p-6 sm:p-8 flex flex-col justify-start">
<h3 className="text-xs font-semibold text-slate-700 mb-5">
Parcours disponibles
</h3>
<ul className="space-y-3.5">
{parcours.map((item, idx) => (
<li key={idx} className="flex items-center gap-3 text-xs sm:text-[0.82rem] text-slate-800 font-medium">
<span className="shrink-0">{item.icon}</span>
<span>{item.label}</span>
</li>
))}
</ul>
</div>
{/* CARTE 2 : Ce que les participants développent */}
<div className="lg:col-span-5 bg-[#F1F0E0] rounded-2xl p-6 sm:p-8 flex flex-col justify-start">
<h3 className="text-xs font-semibold text-slate-700 mb-5">
Ce que les participants développent
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-3.5">
<ul className="space-y-3.5">
{competencesCol1.map((item, idx) => (
<li key={idx} className="flex items-center gap-3 text-xs sm:text-[0.82rem] text-slate-800 font-medium">
<span className="shrink-0">{item.icon}</span>
<span>{item.label}</span>
</li>
))}
</ul>
<ul className="space-y-3.5">
{competencesCol2.map((item, idx) => (
<li key={idx} className="flex items-center gap-3 text-xs sm:text-[0.82rem] text-slate-800 font-medium">
<span className="shrink-0">{item.icon}</span>
<span>{item.label}</span>
</li>
))}
</ul>
</div>
</div>
{/* CARTE 3 : Opportunités */}
<div className="lg:col-span-3 bg-[#F1F0E0] rounded-2xl p-6 sm:p-8 flex flex-col justify-start">
<h3 className="text-xs font-semibold text-slate-700 mb-5">
Opportunités
</h3>
<ul className="space-y-3.5">
{opportunites.map((item, idx) => (
<li key={idx} className="flex items-center gap-3 text-xs sm:text-[0.82rem] text-slate-800 font-medium">
<span className="shrink-0">{item.icon}</span>
<span>{item.label}</span>
</li>
))}
</ul>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,94 @@
import React, { useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import logo from '../../img/logo_gaea21.png';
import '../../styles/header.css';
export default function Header({ onNavigate }) {
const [isOpen, setIsOpen] = useState(false);
const location = useLocation();
// Active la couleur blanche (nav-light) pour trajectoire, projet et parcours
const isDark =
location.pathname === '/trajectoire' ||
location.pathname === '/projet' ||
location.pathname === '/parcours';
const closeMenu = () => {
setIsOpen(false);
};
return (
<header className="navbar-container">
<div className="navbar-content">
{/* Logo gaea21 */}
<Link
to="/"
className="navbar-logo"
onClick={closeMenu}
aria-label="Retour à l'accueil gaea21"
>
<img src={logo} alt="Logo gaea21" />
</Link>
{/* Bouton burger mobile */}
<button
type="button"
className={`hamburger ${isOpen ? 'active' : ''}`}
onClick={() => setIsOpen(!isOpen)}
aria-label={isOpen ? 'Fermer le menu' : 'Ouvrir le menu'}
aria-expanded={isOpen}
>
<span></span>
<span></span>
<span></span>
</button>
{/* Navigation principale */}
<nav className={`navbar-nav ${isOpen ? 'open' : ''}`}>
{/* Applique la classe nav-light si la page a un fond sombre */}
<ul className={`nav-links ${isDark ? 'nav-light' : ''}`}>
<li>
<Link to="/parcours" onClick={closeMenu}>
Parcours
</Link>
</li>
<li>
<Link
to="/trajectoire"
onClick={() => {
closeMenu();
if (typeof onNavigate === 'function') {
onNavigate('trajectoire');
}
}}
>
Projet
</Link>
</li>
<li>
<Link to="/#ecosysteme" onClick={closeMenu}>
Écosystème
</Link>
</li>
<li>
<Link to="/#contact" onClick={closeMenu}>
Contact
</Link>
</li>
</ul>
{/* Bouton Participer */}
<div className="navbar-action">
<Link
to="/#participer"
className="btn-participer"
onClick={closeMenu}
>
Participer
</Link>
</div>
</nav>
</div>
</header>
);
}

View File

@ -0,0 +1,104 @@
// 1. IMPORTATIONS DES MODULES ET DES ASSETS
import React from 'react';
// Import de l'image de bannière principale via Webpack Encore
// Webpack génère automatiquement le bon chemin d'accès avec hachage pour le cache
import heroBg from '../../img/hero-banner.png';
/**
* 2. COMPOSANT PRINCIPAL : Hero
*
* Rôle fonctionnel et visuel :
* - Première section visible sous le Header (zone "Above the Fold").
* - Transmet la proposition de valeur principale de gaea21 via un titre H1 percutant.
* - Propose un bouton d'action (Call-to-Action) guidant l'utilisateur vers la découverte de l'écosystème.
*/
export default function Hero() {
return (
/*
SECTION ENGOBANTE DU HERO :
- className="hero-section" : applique les dimensions (hauteur minimale/100vh),
le positionnement d'arrière-plan (background-size: cover, background-position: center)
et le positionnement relatif pour caler les calques enfants.
- style={{ backgroundImage: ... }} : injection dynamique de l'URL de l'image
traitée par le bundler Webpack.
*/
<section
className="hero-section"
style={{ backgroundImage: `url("${heroBg}")` }}
>
{/*
CALQUE D'OVERLAY SOMBRE :
- Élément positionné en absolu couvrant toute la surface de la section.
- Applique un gradient ou un filtre semi-transparent sombre afin d'assurer
un contraste suffisant (normes d'accessibilité WCAG) entre le texte blanc
et les zones claires de l'image d'arrière-plan.
*/}
<div className="hero-overlay"></div>
{/*
CONTENEUR DE CONTENU CENTRÉ :
- Assure le centrage horizontal du bloc de texte sur la largeur maximale de la page.
- z-index supérieur à l'overlay pour que les textes et boutons restent cliquables et visibles.
*/}
<div className="hero-content">
{/*
BLOC TEXTUEL :
- Limite la largeur maximale du texte pour éviter qu'il ne s'étale trop sur grands écrans,
ce qui garantit un confort de lecture optimal.
*/}
<div className="hero-text-block">
{/*
TITRE PRINCIPAL H1 :
- Balise unique et essentielle pour le référencement naturel (SEO).
- Les balises <br /> forcent des retours à la ligne précis pour sculpter
la silhouette du texte exactement comme sur la maquette Figma.
*/}
<h1 className="hero-title">
Construire <br />
les infrastructures <br />
humaines, économiques <br />
et territoriales de demain
</h1>
{/*
PARAGRAPHE D'INTRODUCTION :
- Résume succinctement les axes d'impact et la légitimité historique (20 ans) de gaea21.
*/}
<p className="hero-description">
Depuis plus de 20 ans, gaea21 relie insertion professionnelle, santé mentale,
économie locale, transition durable, recherche appliquée et innovation systémique.
</p>
{/*
BOUTON D'APPEL À L'ACTION (CTA) :
- Lien d'ancrage vers la section "#ecosysteme".
- Composé d'un label textuel et d'une flèche SVG vectorielle indiquant l'action/la direction.
*/}
<a href="#ecosysteme" className="btn-hero">
<span>Explorer l'écosystème</span>
{/* Flèche droite indicative (alignée horizontalement avec le texte) */}
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
// Masque l'icône purement décorative des lecteurs d'écran
aria-hidden="true"
>
<line x1="5" y1="12" x2="19" y2="12"></line>
<polyline points="12 5 19 12 12 19"></polyline>
</svg>
</a>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,23 @@
import React from 'react';
import Hero from './Hero';
import ProfileCards from './ProfileCards';
import Methodology from './Methodology';
import Impact from './Impact';
import ActualitySection from './ActualitySection';
import CareersSection from './CareersSection';
import Footer from '../Footer';
// import Hero from './Hero';
export default function Home() {
return (
<div className="relative min-h-screen bg-white overflow-x-hidden">
<Hero />
<ProfileCards />
<Methodology />
<Impact />
<ActualitySection />
<CareersSection />
<Footer />
</div>
);
}

View File

@ -0,0 +1,180 @@
// 1. IMPORTATIONS DES MODULES ET ASSETS
import React, { useState } from 'react';
// Webpack Encore gère l'empreinte de hachage (hash) et le chemin public de l'image de fond
import impactBg from '../../img/impact.png';
/**
* 2. STRUCTURE DE DONNÉES STATIQUE : DIAPOSITIVES DU CARROUSEL
* Externaliser les données hors du composant évite de recréer ce tableau
* en mémoire à chaque nouveau cycle de rendu (re-render) du composant.
*
* Le tableau est structuré sous forme de tableau de diapositives (slides).
* SLIDES[0] contient le groupe actif affiché à l'écran.
*/
const SLIDES = [
[
{
value: '3000 +',
label: 'personnes accompagnées',
size: 'w-16 h-16 sm:w-20 sm:h-20', // Taille standard des pastilles latérales
},
{
value: '94% - 97%',
label: 'de réussites en insertion',
size: 'w-24 h-24 sm:w-28 sm:h-28', // Pastille centrale plus imposante pour créer une hiérarchie visuelle
},
{
value: '20 ANS',
label: 'de recherches appliquées',
size: 'w-16 h-16 sm:w-20 sm:h-20', // Taille standard
},
],
];
/**
* 3. COMPOSANT PRINCIPAL : Impact
* Présente la section "NOTRE IMPACT" avec :
* - Un arrière-plan immersif en pleine largeur
* - 3 indicateurs chiffrés majeurs avec pastilles colorées
* - Des contrôles de carrousel (flèches gauche/droite et indicateurs à points)
*/
export default function Impact() {
/**
* ÉTAT LOCAL (State) : Indice du point actif de pagination
* Initialisé à 2 pour correspondre au point central parmi les 5 points du design Figma.
*/
const [currentSlide, setCurrentSlide] = useState(2);
return (
/*
Balise sémantique <section> :
- relative : point d'ancrage pour positionner l'overlay sombre absolu
- w-full : occupe toute la largeur de l'écran (full bleed)
- py-24 sm:py-32 : padding vertical généreux pour donner de l'espace à la section
- px-6 sm:px-12 : padding horizontal adaptatif
- bg-cover bg-center : l'image remplit tout l'arrière-plan sans déformation et reste centrée
- overflow-hidden : empêche tout débordement lié aux animations de zoom
*/
<section
className="relative w-full py-24 sm:py-32 px-6 sm:px-12 bg-cover bg-center overflow-hidden"
style={{ backgroundImage: `url("${impactBg}")` }}
>
{/*
CALQUE D'OVERLAY SOMBRE :
- absolute inset-0 : couvre 100% de la surface de la section
- bg-black/40 : voile noir à 40% d'opacité pour garantir la lisibilité des textes blancs
- pointer-events-none : empêche ce filtre de capturer les clics
*/}
<div className="absolute inset-0 bg-black/40 pointer-events-none" />
{/*
CONTENEUR DE CONTENU :
- relative z-10 : positionne le contenu au-dessus du voile sombre
- max-w-[1400px] mx-auto : largeur maximale cadrée et centrée
- text-center text-white : typographie blanche centrée par défaut
*/}
<div className="relative z-10 max-w-[1400px] mx-auto text-center text-white">
{/* ====================================================================
A. EN-TÊTE : SURTITRE & TITRE PRINCIPAL
==================================================================== */}
{/* Surtitre en majuscules avec espacement étendu (tracking-wide) */}
<span className="text-xs sm:text-sm font-bold tracking-[0.25em] uppercase text-white/90 block mb-2">
NOTRE IMPACT
</span>
{/* Titre descriptif sobre avec marge basse importante avant les chiffres */}
<h2 className="text-lg sm:text-xl font-normal text-white/95 mb-16 sm:mb-20">
Des résultats concrets et durables
</h2>
{/* ====================================================================
B. ZONE CENTRALE : FLÈCHE GAUCHE + 3 MÉTRIQUES + FLÈCHE DROITE
- flex items-center justify-between : alignement horizontal sur une seule ligne
==================================================================== */}
<div className="flex items-center justify-between gap-4 sm:gap-8">
{/* Bouton de navigation gauche (Précédent) */}
<button
type="button"
className="w-10 h-10 sm:w-12 sm:h-12 rounded-full border border-white/60 flex items-center justify-center text-white hover:bg-white/20 transition-colors shrink-0"
aria-label="Précédent"
>
{/* Icône flèche retour */}
<svg className="w-5 h-5 sm:w-6 sm:h-6" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18" />
</svg>
</button>
{/*
Grille des 3 métriques chiffrées :
- 1 colonne sur mobile (grid-cols-1)
- 3 colonnes à partir des écrans moyens (md:grid-cols-3)
- items-end : aligne les éléments par le bas pour absorber la différence de taille du cercle central
- flex-1 max-w-4xl mx-auto : occupe l'espace central disponible de façon équilibrée
*/}
<div className="grid grid-cols-1 md:grid-cols-3 gap-10 md:gap-8 flex-1 items-end max-w-4xl mx-auto">
{SLIDES[0].map((item, index) => (
<div key={index} className="flex flex-col items-center">
{/*
Pastille ronde vert olive (#9da74d) :
- Taille dynamique issue de la donnée (item.size)
- shadow-[...] : ombre portée sombre accentuant la profondeur
- hover:scale-105 : micro-interaction au survol
*/}
<div
className={`${item.size} rounded-full bg-[#9da74d] mb-6 shadow-[0_4px_16px_rgba(0,0,0,0.35)] transition-transform duration-300 hover:scale-105`}
/>
{/* Valeur numérique mise en avant (ex: 3000 +, 94% - 97%) */}
<span className="text-3xl sm:text-4xl md:text-5xl font-normal tracking-tight text-white mb-2">
{item.value}
</span>
{/* Libellé descriptif sous le chiffre */}
<span className="text-xs sm:text-sm font-light text-white/85 max-w-[200px]">
{item.label}
</span>
</div>
))}
</div>
{/* Bouton de navigation droit (Suivant) */}
<button
type="button"
className="w-10 h-10 sm:w-12 sm:h-12 rounded-full border border-white/60 flex items-center justify-center text-white hover:bg-white/20 transition-colors shrink-0"
aria-label="Suivant"
>
{/* Icône flèche suivant */}
<svg className="w-5 h-5 sm:w-6 sm:h-6" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" />
</svg>
</button>
</div>
{/* ====================================================================
C. INDICATEURS DE PAGINATION (CAROUSEL DOTS)
- 5 points horizontaux centrés en bas de section
==================================================================== */}
<div className="flex justify-center items-center gap-2 mt-16 sm:mt-20">
{[0, 1, 2, 3, 4].map((dot) => (
<span
key={dot}
/*
Style dynamique du point :
- Si c'est le point actif (dot === currentSlide) : couleur vert olive (#a3ad53) et taille augmentée (scale-125)
- Sinon : blanc translucide (bg-white/50)
*/
className={`w-2.5 h-2.5 rounded-full transition-all duration-200 ${dot === currentSlide
? 'bg-[#a3ad53] scale-125'
: 'bg-white/50'
}`}
/>
))}
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,259 @@
// 1. IMPORTATION DE REACT
import React from 'react';
/**
* 2. TABLEAU DE DONNÉES STATIQUE : LES 6 ÉTAPES DE LA MÉTHODOLOGIE
* Externaliser les étapes hors du composant évite de recréer ce tableau
* en mémoire à chaque nouveau cycle de rendu (re-render) du composant.
*/
const STEPS = [
{
number: '01',
title: 'Diagnostiquer',
description: 'Comprendre les besoins humains, professionnels et systémiques.',
// Icône SVG : Loupe d'analyse / audit
icon: (
<svg className="w-7 h-7 text-white" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7" />
<path strokeLinecap="round" strokeLinejoin="round" d="m20 20-3.5-3.5" />
</svg>
),
},
{
number: '02',
title: 'Structurer',
description: 'Créer un cadre, des outils et des trajectoires cohérentes.',
// Icône SVG : Arborescence / Organigramme hiérarchique
icon: (
<svg className="w-7 h-7 text-white" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<rect x="9" y="3" width="6" height="5" rx="1" />
<rect x="3" y="16" width="6" height="5" rx="1" />
<rect x="15" y="16" width="6" height="5" rx="1" />
<path strokeLinecap="round" strokeLinejoin="round" d="M12 8v4m0 0H6v4m6-4h6v4" />
</svg>
),
},
{
number: '03',
title: 'Appliquer',
description: 'Travailler sur des projets réels dans un environnement collaboratif.',
// Icône SVG : Outil clé / mise en œuvre pratique
icon: (
<svg className="w-7 h-7 text-white" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="m14.7 6.3 3 3-9.4 9.4H5.3v-3l9.4-9.4z" />
<path strokeLinecap="round" strokeLinejoin="round" d="m13 8 3 3" />
</svg>
),
},
{
number: '04',
title: 'Transformer',
description: 'Développer autonomie, compétences et stabilité.',
// Icône SVG : Pousse végétale / croissance durable
icon: (
<svg className="w-7 h-7 text-white" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 21V11" />
<path strokeLinecap="round" strokeLinejoin="round" d="M12 11c0-4 4-7 8-7-1 4-4 7-8 7z" />
<path strokeLinecap="round" strokeLinejoin="round" d="M12 13c0-3.5-3.5-6-7-6 .9 3.5 3.5 6 7 6z" />
</svg>
),
},
{
number: '05',
title: 'Connecter',
description: 'Relier humain, économie, territoires et opportunités.',
// Icône SVG : Maillons de chaîne / réseau
icon: (
<svg className="w-7 h-7 text-white" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
<path strokeLinecap="round" strokeLinejoin="round" d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
</svg>
),
},
{
number: '06',
title: 'Régénérer',
description: 'Créer des boucles de valeur autonomes et durables.',
// Icône SVG : Flèches d'économie circulaire / régénération
icon: (
<svg className="w-7 h-7 text-white" fill="none" stroke="currentColor" strokeWidth="2.2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M21 12a9 9 0 0 0-15.5-6.36L3 8" />
<path strokeLinecap="round" strokeLinejoin="round" d="M3 3v5h5" />
<path strokeLinecap="round" strokeLinejoin="round" d="M3 12a9 9 0 0 0 15.5 6.36L21 16" />
<path strokeLinecap="round" strokeLinejoin="round" d="M16 16h5v5" />
</svg>
),
},
];
/**
* 3. COMPOSANT PRINCIPAL : Methodology
* Présente la section "Comment ça fonctionne ?" en deux parties :
* - Haut : Titre + descriptif à gauche (4 cols) et les 6 étapes à droite (8 cols).
* - Bas : Bandeau beige avec statistiques clés et bouton d'action.
*/
export default function Methodology() {
return (
/*
Section englobante :
- py-20 : padding vertical de 5rem (80px)
- px-6 sm:px-12 : padding horizontal adaptatif
- bg-white : fond blanc assurant la continuité avec les autres blocs
*/
<section className="py-20 px-6 sm:px-12 bg-white">
{/* Conteneur centré borné à 1400px (largeur standard de la maquette Figma) */}
<div className="max-w-[1400px] mx-auto">
{/* ====================================================================
A. PARTIE SUPÉRIEURE : EN-TÊTE + GRILLE DES 6 ÉTAPES
- Grille CSS de 12 colonnes sur grand écran (lg:grid-cols-12)
- 1 colonne unique sur mobile / tablette
==================================================================== */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-10 items-start mb-16">
{/* COLONNE GAUCHE (4 colonnes sur 12) : Titres et texte explicatif */}
<div className="lg:col-span-4 pr-0 lg:pr-6">
{/* Surtitre vert olive (#798334) */}
<span className="text-[0.85rem] font-bold text-[#798334] tracking-wide block mb-2">
Notre méthodologie
</span>
{/* Titre principal */}
<h2 className="text-3xl sm:text-4xl font-extrabold text-slate-900 leading-tight mb-5">
Comment <br /> ça fonctionne ?
</h2>
{/* Sous-titre mis en avant */}
<h3 className="text-sm font-bold text-slate-900 mb-3">
Une méthodologie “Learning by Doing” validée sur plus de 20 ans.
</h3>
{/* Paragraphe descriptif avec largeur bridée pour une lecture confortable */}
<p className="text-xs sm:text-sm text-slate-500 leading-relaxed max-w-sm">
gaea21 transforme la recherche en action et les trajectoires humaines en capacités concrètes à travers une méthodologie systémique structurée.
</p>
</div>
{/* COLONNE DROITE (8 colonnes sur 12) : Les 6 étapes numérotées */}
{/*
Découpage responsive :
- Mobile : 2 colonnes (grid-cols-2)
- Tablette : 3 colonnes (sm:grid-cols-3)
- Desktop : 6 colonnes alignées (md:grid-cols-6)
*/}
<div className="lg:col-span-8 grid grid-cols-2 sm:grid-cols-3 md:grid-cols-6 gap-6 text-center">
{STEPS.map((step) => (
/*
group : permet à la bulle d'icône d'animer son zoom et sa couleur
dès que le curseur entre dans le bloc de l'étape
*/
<div key={step.number} className="flex flex-col items-center group">
{/* Numéro de l'étape (01, 02, etc.) */}
<span className="text-xs sm:text-sm font-semibold text-slate-400 mb-2">
{step.number}
</span>
{/* Bulle d'icône vert olive (#8c8f3e) avec transition fluide */}
<div className="w-16 h-16 rounded-full bg-[#8c8f3e] flex items-center justify-center mb-3 shadow-md group-hover:bg-[#737630] group-hover:scale-105 transition-all duration-200">
{step.icon}
</div>
{/* Titre de l'étape */}
<h4 className="text-sm font-bold text-slate-900 mb-1.5 leading-snug">
{step.title}
</h4>
{/* Description de l'étape */}
<p className="text-[0.68rem] sm:text-[0.72rem] text-slate-500 leading-snug">
{step.description}
</p>
</div>
))}
</div>
</div>
{/* ====================================================================
B. BANDEAU INFÉRIEUR : STATISTIQUES & BOUTON D'ACTION (CTA)
- bg-[#f7f8f0] : fond beige/vert très clair doux
- border-[#e8ebd5] : bordure fine d'encadrement
- rounded-2xl : coins arrondis
==================================================================== */}
<div className="bg-[#f7f8f0] border border-[#e8ebd5] rounded-2xl p-6 sm:p-8 flex flex-col lg:flex-row items-center justify-between gap-6 shadow-sm">
{/* Bloc Accroche textuelle à gauche */}
<div className="lg:w-1/4 text-center lg:text-left">
<h4 className="text-sm sm:text-base font-bold text-slate-900 leading-snug">
Une approche systémique et humaine
</h4>
<span className="text-xs sm:text-sm text-[#798334] font-medium block mt-0.5">
pour des résultats concrets et durables.
</span>
</div>
{/* Ligne séparatrice verticale visible uniquement sur desktop (lg) */}
<div className="hidden lg:block w-px h-12 bg-slate-300"></div>
{/* Statistique 1 : Ancienneté (20+ ans) */}
<div className="flex items-center gap-4">
{/* Icône cible / horloge */}
<div className="text-[#8c8f3e]">
<svg className="w-8 h-8" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="9" />
<path strokeLinecap="round" strokeLinejoin="round" d="M12 7v5l3 3" />
</svg>
</div>
<div>
<span className="text-xl sm:text-2xl font-black text-slate-900 block leading-tight">
20 + ans
</span>
<span className="text-xs text-slate-500 font-medium">
d'expérimentation
</span>
</div>
</div>
{/* Ligne séparatrice verticale visible uniquement sur desktop (lg) */}
<div className="hidden lg:block w-px h-12 bg-slate-300"></div>
{/* Statistique 2 : Nombre de bénéficiaires (3 000+ personnes) */}
<div className="flex items-center gap-4">
{/* Icône groupe / communauté */}
<div className="text-[#8c8f3e]">
<svg className="w-8 h-8" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path strokeLinecap="round" strokeLinejoin="round" d="M22 21v-2a4 4 0 0 0-3-3.87" />
<path strokeLinecap="round" strokeLinejoin="round" d="M16 3.13a4 4 0 0 1 0 7.75" />
</svg>
</div>
<div>
<span className="text-xl sm:text-2xl font-black text-slate-900 block leading-tight">
3 000 +
</span>
<span className="text-xs text-[#798334] font-medium">
personnes accompagnées
</span>
</div>
</div>
{/* Bouton CTA d'ancrage vers le détail de la méthodologie */}
<div className="mt-2 lg:mt-0">
<a
href="#methodologie"
className="inline-flex items-center gap-2 bg-[#798334] hover:bg-[#656d2b] text-white text-xs sm:text-sm font-semibold px-6 py-3 rounded-full transition-all duration-200 shadow-sm hover:shadow-md transform hover:-translate-y-0.5"
>
<span>Découvrir la méthodologie</span>
{/* Flèche droite indicative */}
<svg className="w-4 h-4" fill="none" stroke="currentColor" strokeWidth="2.5" viewBox="0 0 24 24">
<line x1="5" y1="12" x2="19" y2="12"></line>
<polyline points="12 5 19 12 12 19"></polyline>
</svg>
</a>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,147 @@
// 1. IMPORTATIONS DES MODULES ET DES ASSETS
import React from 'react';
// Webpack Encore gère l'empreinte de hachage (hashing) et le chemin public des images
import individusImg from '../../img/individus.png';
import institutionsImg from '../../img/institutions.png';
import coachImg from '../../img/coach.png';
import entrepriseImg from '../../img/entreprise.png';
/**
* 2. STRUCTURE DE DONNÉES STATIQUE : LISTE DES PROFILS CIBLES
* Externaliser les données hors du composant évite de recréer
* ce tableau en mémoire à chaque nouveau rendu (re-render) de React.
*/
const PROFILES = [
{
id: 1,
title: 'Individus',
image: individusImg,
href: '#individus', // Ancre ou future route vers le parcours Individus
},
{
id: 2,
title: 'Entreprises',
image: entrepriseImg,
href: '#entreprises',
},
{
id: 3,
title: 'Institutions',
image: institutionsImg,
href: '#institutions',
},
{
id: 4,
// Le caractère d'échappement '\n' force un saut de ligne contrôlé dans le titre
title: 'Université /\nCentre de recherche',
// Fallback d'image en attendant l'asset spécifique de l'université
image: institutionsImg,
href: '#universite',
},
{
id: 5,
title: 'Coach ou\nPraticien',
image: coachImg,
href: '#coach',
},
];
/**
* 3. COMPOSANT PRINCIPAL : ProfileCards
* Affiche la section de choix de profil utilisateur (« Qui êtes-vous ? »)
* sous forme d'une grille interactive de cartes verticales avec effet glass/hover.
*/
export default function ProfileCards() {
return (
/*
Balise sémantique <section> :
- py-20 : grand espacement vertical (padding-top & padding-bottom)
- px-6 sm:px-12 : padding horizontal adaptatif selon la taille d'écran
- bg-white : fond blanc assurant la continuité visuelle
*/
<section className="py-20 px-6 sm:px-12 bg-white">
{/*
Conteneur centré borné à 1380px max (conforme au Figma)
mx-auto permet de centrer horizontalement le conteneur dans la page
*/}
<div className="max-w-[1380px] mx-auto text-center">
{/* =========================================================
A. EN-TÊTE DE SECTION (Surtitre + Titre principal)
========================================================= */}
{/* Surtitre en majuscules avec espacement étendu entre les lettres (tracking) */}
<span className="text-[0.72rem] tracking-[0.22em] font-bold text-slate-400 uppercase block mb-3">
QUI ÊTES-VOUS ?
</span>
{/* Titre principal centré avec largeur maximale contrôlée (max-w-xl) */}
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold text-slate-800 leading-snug max-w-xl mx-auto mb-14">
Chaque profil est une porte d’entrée <br />
vers un écosystème de transformation
</h2>
{/* =========================================================
B. GRILLE RESPONSIVE DES 5 CARTES
- 2 colonnes sur mobile (grid-cols-2)
- 3 colonnes sur tablette (sm:grid-cols-3)
- 5 colonnes alignées sur desktop (md:grid-cols-5)
- Gouttières (gap) dynamiques
========================================================= */}
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-3.5 sm:gap-4 lg:gap-5 justify-center">
{PROFILES.map((profile) => (
/*
Chaque carte est un lien interactif cliquable <a> :
- key={profile.id} : clé unique obligatoire pour l'algorithme de réconciliation de React
- group : permet aux éléments enfants (image, overlay) de réagir au survol du parent
- relative + overflow-hidden : indispensable pour contraindre l'image zoomée à l'arrondi (rounded-xl)
- h-[...] : hauteurs fixes échelonnées par breakpoint pour garder un ratio portrait élancé
- transform hover:-translate-y-1.5 : translation douce vers le haut au survol pour donner du relief
*/
<a
key={profile.id}
href={profile.href}
className="group relative block w-full h-[360px] sm:h-[420px] md:h-[460px] rounded-xl overflow-hidden shadow-sm hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1.5"
>
{/*
CALQUE 1 (Fond) : Photographie du profil
- object-cover : l'image remplit tout le conteneur sans se déformer
- group-hover:scale-105 : léger zoom cinématographique quand la souris survole la carte
- transition-transform duration-500 : animation fluide du zoom
*/}
<img
src={profile.image}
alt={profile.title.replace('\n', ' ')} // Remplace le saut de ligne par un espace pour l'accessibilité SEO
className="w-full h-full object-cover object-center group-hover:scale-105 transition-transform duration-500 ease-out"
/>
{/*
CALQUE 2 (Intermédiaire) : Dégradé sombre pour la lisibilité
- bg-gradient-to-t : dégradé vertical partant du bas vers le haut
- from-black/85 via-black/30 to-transparent : foncé en bas pour le texte, transparent en haut
- pointer-events-none : empêche ce calque décoratif de bloquer les clics
*/}
<div className="absolute inset-0 bg-gradient-to-t from-black/85 via-black/30 to-transparent pointer-events-none" />
{/*
CALQUE 3 (Premier plan) : Titre textuel de la carte
- absolute inset-x-0 bottom-0 : positionné en bas de la carte sur toute la largeur
- flex items-end justify-center : aligne le texte en bas et au centre
*/}
<div className="absolute inset-x-0 bottom-0 p-4 pb-6 flex items-end justify-center text-center">
{/*
- whitespace-pre-line : interprète les retours à la ligne '\n' définis dans le tableau PROFILES
- drop-shadow-md : ombre portée sur le texte pour garantir un contraste optimal
*/}
<span className="text-white text-base sm:text-lg font-bold leading-snug whitespace-pre-line tracking-tight drop-shadow-md">
{profile.title}
</span>
</div>
</a>
))}
</div>
</div>
</section>
);
}