feat(ui): modularisation du css et fidélisation des composants à la maquette figma
- découpage du css par composant (navbar, hero, footer, global) - ajustement pixel-perfect du footer (newsletter full-bleed, alignements, typographies) - documentation et commentaires détaillés du code react et css
This commit is contained in:
147
assets/components/ProfileCards.jsx
Normal file
147
assets/components/ProfileCards.jsx
Normal 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 entrepriseImg from '../img/entreprise.png';
|
||||
import institutionsImg from '../img/institutions.png';
|
||||
import coachImg from '../img/coach.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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user