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
7
.gitignore
vendored
@ -18,3 +18,10 @@
|
||||
/public/assets/
|
||||
/assets/vendor/
|
||||
###< symfony/asset-mapper ###
|
||||
|
||||
###> symfony/webpack-encore-bundle ###
|
||||
/node_modules/
|
||||
/public/build/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
###< symfony/webpack-encore-bundle ###
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import './stimulus_bootstrap.js';
|
||||
/*
|
||||
* Welcome to your app's main JavaScript file!
|
||||
*
|
||||
* This file will be included onto the page via the importmap() Twig function,
|
||||
* which should already be in your base.html.twig.
|
||||
*/
|
||||
import './styles/app.css';
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import Home from './components/Home.jsx'; // <-- Ajoute .jsx ici !
|
||||
|
||||
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');
|
||||
const container = document.getElementById('root');
|
||||
if (container) {
|
||||
const root = createRoot(container);
|
||||
root.render(<Home />);
|
||||
}
|
||||
175
assets/components/ActualitySection.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
300
assets/components/CareersSection.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
166
assets/components/Footer.jsx
Normal file
@ -0,0 +1,166 @@
|
||||
import React, { useState } from 'react';
|
||||
// Importation du logo vectoriel ou transparent de gaea21
|
||||
import logo from '../img/logo_gaea21.png';
|
||||
// Importation de la feuille de style dédiée au Footer
|
||||
import '../styles/footer.css';
|
||||
|
||||
export default function Footer() {
|
||||
// État local pour stocker l'adresse email saisie par l'utilisateur
|
||||
const [email, setEmail] = useState('');
|
||||
|
||||
// Gestionnaire de soumission du formulaire d'abonnement à la newsletter
|
||||
const handleSubmitNewsletter = (e) => {
|
||||
e.preventDefault();
|
||||
if (email) {
|
||||
alert(`Inscription enregistrée pour : ${email}`);
|
||||
setEmail('');
|
||||
}
|
||||
};
|
||||
|
||||
// Liste ordonnée des liens pour la colonne "Écosystème"
|
||||
const ecosystemLinks = [
|
||||
'Individus',
|
||||
'Entreprises',
|
||||
'Institutions',
|
||||
'Universités',
|
||||
'Praticiens',
|
||||
];
|
||||
|
||||
return (
|
||||
<footer className="gaea-footer">
|
||||
|
||||
{/* -------------------------------------------------------------------
|
||||
1. SECTION SUPÉRIEURE (Centrée sur 1440px)
|
||||
Comprend : Le logo + Réseaux sociaux, le trait doré et les colonnes
|
||||
------------------------------------------------------------------- */}
|
||||
<div className="gaea-footer-inner">
|
||||
<div className="footer-top-row">
|
||||
|
||||
{/* Bloc Marque : Logo gaea21 et liens sociaux */}
|
||||
<div className="footer-brand-col">
|
||||
<a href="/" className="footer-logo">
|
||||
<img src={logo} alt="Logo gaea21" />
|
||||
</a>
|
||||
|
||||
<div className="footer-socials">
|
||||
{/* Icône LinkedIn */}
|
||||
<a href="#linkedin" aria-label="LinkedIn">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.28 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.75M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
{/* Icône Instagram */}
|
||||
<a href="#instagram" aria-label="Instagram">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.13-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
{/* Icône YouTube */}
|
||||
<a href="#youtube" aria-label="YouTube">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Ligne verticale dorée (#A8985A) de séparation */}
|
||||
<div className="footer-gold-divider" />
|
||||
|
||||
{/* Les 3 colonnes de liens de navigation */}
|
||||
<div className="footer-nav-columns">
|
||||
{/* Colonne 1 : Écosystème */}
|
||||
<div>
|
||||
<h4 className="footer-col-title">Écosystème</h4>
|
||||
<ul className="footer-links-list">
|
||||
{ecosystemLinks.map((item, idx) => (
|
||||
<li key={idx}>
|
||||
<a href={`#${item.toLowerCase()}`}>{item}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Colonne 2 : Ressources */}
|
||||
<div>
|
||||
<h4 className="footer-col-title">Ressources</h4>
|
||||
</div>
|
||||
|
||||
{/* Colonne 3 : À propos */}
|
||||
<div>
|
||||
<h4 className="footer-col-title">À propos</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* -------------------------------------------------------------------
|
||||
2. BANDEAU NEWSLETTER (Pleine Largeur / Full bleed)
|
||||
S'étend d'un bord à l'autre de l'écran avec la couleur #D8DCAB
|
||||
------------------------------------------------------------------- */}
|
||||
<div className="footer-newsletter-fullwidth">
|
||||
<div className="footer-newsletter-content">
|
||||
|
||||
{/* Côté gauche : Pastille ronde grise avec icône violette + Textes */}
|
||||
<div className="newsletter-brand-side">
|
||||
<div className="newsletter-icon-circle">
|
||||
<svg fill="none" stroke="currentColor" strokeWidth="1.8" 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 className="newsletter-texts">
|
||||
<h3>Ne manquez rien de nos actualités</h3>
|
||||
<p>
|
||||
Abonnez vous a notre Newsletters pour recevoir <br />
|
||||
nos dernières nouvelles et publications
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Côté droit : Formulaire (Champ ovale noir + Bouton vert olive) */}
|
||||
<form onSubmit={handleSubmitNewsletter} className="newsletter-form-side">
|
||||
<div className="newsletter-input-group">
|
||||
<input
|
||||
type="email"
|
||||
required
|
||||
placeholder="Votre adresse e-mail"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="newsletter-input"
|
||||
/>
|
||||
<button type="submit" className="newsletter-btn">
|
||||
S'abonner
|
||||
</button>
|
||||
</div>
|
||||
<span className="newsletter-privacy-text">
|
||||
Nous respectons votre vie privée. Désinscription possible à tout moment
|
||||
</span>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* -------------------------------------------------------------------
|
||||
3. BARRE DE MENTIONS LÉGALES TOUT EN BAS (Centrée sur 1440px)
|
||||
------------------------------------------------------------------- */}
|
||||
<div className="gaea-footer-inner">
|
||||
<div className="footer-bottom-bar">
|
||||
<div>gaea21 2026 - Tout droit réservés</div>
|
||||
<div className="footer-bottom-links">
|
||||
<a href="#mentions-legales">Mentions légales</a>
|
||||
<span className="divider">|</span>
|
||||
<a href="#confidentialite">Politiques de confidentialités</a>
|
||||
<span className="divider">|</span>
|
||||
<a href="#cookies">Cookies</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
119
assets/components/Header.jsx
Normal file
@ -0,0 +1,119 @@
|
||||
// 1. IMPORTATION DES MODULES ET ASSETS
|
||||
import React, { useState } from 'react';
|
||||
|
||||
// Import du logo gaea21 via Webpack Encore (gestion du hashing et du chemin public)
|
||||
import logo from '../img/logo_gaea21.png';
|
||||
|
||||
/**
|
||||
* 2. COMPOSANT PRINCIPAL : Header
|
||||
*
|
||||
* Rôle fonctionnel :
|
||||
* - Fournit la barre de navigation principale (Navbar) fixée ou relative en haut de page.
|
||||
* - Gère l'affichage responsive : menu étendu sur desktop, tiroir repliable (drawer) sur mobile.
|
||||
* - Propose un bouton d'action principal (« Participer ») pour convertir le visiteur.
|
||||
*/
|
||||
export default function Header() {
|
||||
/**
|
||||
* ÉTAT LOCAL (State) : isOpen
|
||||
* - false : le menu mobile est fermé
|
||||
* - true : le menu mobile est ouvert (déroulé/visible)
|
||||
*/
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
/*
|
||||
Balise sémantique HTML5 <header> :
|
||||
- navbar-container : gère le fond, la bordure inférieure éventuelle,
|
||||
la hauteur fixe et le z-index pour rester au-dessus du contenu de la page.
|
||||
*/
|
||||
<header className="navbar-container">
|
||||
|
||||
{/*
|
||||
Conteneur interne centré :
|
||||
- navbar-content : applique un flexbox (justify-content: space-between, align-items: center)
|
||||
et borne la largeur maximale avec un padding latéral propre.
|
||||
*/}
|
||||
<div className="navbar-content">
|
||||
|
||||
{/* =========================================================
|
||||
A. LOGO DE LA MARQUE
|
||||
========================================================= */}
|
||||
<a href="/" className="navbar-logo" aria-label="Retour à l'accueil gaea21">
|
||||
<img src={logo} alt="Logo gaea21" />
|
||||
</a>
|
||||
|
||||
{/* =========================================================
|
||||
B. BOUTON BURGER (Affiché uniquement sur écrans mobiles)
|
||||
========================================================= */}
|
||||
<button
|
||||
type="button"
|
||||
/*
|
||||
Basculement dynamique de la classe 'active' :
|
||||
Permet en CSS d'animer les 3 barres pour former une croix 'X' quand isOpen vaut true.
|
||||
*/
|
||||
className={`hamburger ${isOpen ? 'active' : ''}`}
|
||||
/* Inverse la valeur booléenne au clic (ouvre ou ferme le menu) */
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
/* Attributs d'accessibilité ARIA pour les lecteurs d'écran */
|
||||
aria-label={isOpen ? 'Fermer le menu de navigation' : 'Ouvrir le menu de navigation'}
|
||||
aria-expanded={isOpen}
|
||||
>
|
||||
{/* Les 3 barres horizontales du burger dessinées en CSS */}
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
|
||||
{/* =========================================================
|
||||
C. MENU DE NAVIGATION (DESKTOP & TIROIR MOBILE)
|
||||
========================================================= */}
|
||||
{/*
|
||||
La classe 'open' est ajoutée conditionnellement pour déclencher
|
||||
l'apparition du tiroir de navigation en version mobile.
|
||||
*/}
|
||||
<nav className={`navbar-nav ${isOpen ? 'open' : ''}`}>
|
||||
|
||||
{/* Liste ordonnée des ancres de navigation */}
|
||||
<ul className="nav-links">
|
||||
<li>
|
||||
{/* Le onClick={() => setIsOpen(false)} referme automatiquement le menu mobile après le clic */}
|
||||
<a href="#parcours" onClick={() => setIsOpen(false)}>
|
||||
Parcours
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#projet" onClick={() => setIsOpen(false)}>
|
||||
Projet
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#ecosysteme" onClick={() => setIsOpen(false)}>
|
||||
Écosystème
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#contact" onClick={() => setIsOpen(false)}>
|
||||
Contact
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{/* =========================================================
|
||||
D. BOUTON D'ACTION PRINCIPAL (CALL-TO-ACTION)
|
||||
========================================================= */}
|
||||
<div className="navbar-action">
|
||||
<a
|
||||
href="#participer"
|
||||
className="btn-participer"
|
||||
// Ferme le menu mobile si cliqué
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
Participer
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
104
assets/components/Hero.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
82
assets/components/Home.jsx
Normal file
@ -0,0 +1,82 @@
|
||||
// 1. IMPORTATION DES DÉPENDANCES ET COMPOSANTS ENFANTS
|
||||
import React from 'react';
|
||||
|
||||
// Barre de navigation supérieure (Logo, Liens, Boutons d'action)
|
||||
import Header from './Header';
|
||||
|
||||
// Section d'accroche principale (Titre fort, boutons d'appel à l'action, visuel héroïque)
|
||||
import Hero from './Hero';
|
||||
|
||||
// Cartes des profils cibles ("Qui êtes-vous ?") : Individus, Entreprises, Institutions, etc.
|
||||
import ProfileCards from './ProfileCards';
|
||||
|
||||
// Section explicative de la méthodologie ("Comment ça fonctionne ?") en 6 étapes + chiffres clés
|
||||
import Methodology from './Methodology';
|
||||
|
||||
// Section de preuve d'impact chiffrée avec fond immersif et carrousel
|
||||
import Impact from './Impact';
|
||||
|
||||
// Section actualités : événements, articles, publications et formulaire de newsletter intermédiaire
|
||||
import ActualitySection from './ActualitySection';
|
||||
|
||||
// Section opportunités et carrières ("Construire des trajectoires, pas seulement des emplois")
|
||||
import CareersSection from './CareersSection';
|
||||
|
||||
// Pied de page complet (Navigation secondaire, réseaux sociaux, newsletter pleine largeur, mentions légales)
|
||||
import Footer from './Footer';
|
||||
|
||||
/**
|
||||
* 2. COMPOSANT RACINE DE LA PAGE D'ACCUEIL : Home
|
||||
*
|
||||
* Rôle architectural :
|
||||
* - Sert de page principale (Page Component / Container) orchestrant la disposition verticale
|
||||
* de toutes les sections de la page d'accueil de gaea21.
|
||||
* - Assure une hiérarchie sémantique HTML5 claire pour le référencement (SEO) et l'accessibilité.
|
||||
*/
|
||||
export default function Home() {
|
||||
return (
|
||||
/*
|
||||
CONTENEUR GLOBAL DE PAGE :
|
||||
- relative : sert de référentiel de positionnement pour d'éventuels éléments absolus.
|
||||
- min-h-screen : garantit que la page couvre au minimum 100% de la hauteur de la fenêtre (évite les fonds blancs coupés).
|
||||
- bg-white : couleur de fond par défaut pour l'ensemble du site.
|
||||
- overflow-x-hidden : masque tout débordement horizontal causé par des animations, des bannières pleine largeur ou des marges négatives.
|
||||
*/
|
||||
<div className="relative min-h-screen bg-white overflow-x-hidden">
|
||||
|
||||
{/*
|
||||
A. EN-TÊTE DU SITE
|
||||
Balise <Header /> contenant la navigation principale fixée ou relative en haut de page.
|
||||
*/}
|
||||
<Header />
|
||||
|
||||
{/*
|
||||
B. CONTENU PRINCIPAL DE LA PAGE
|
||||
La balise sémantique HTML5 <main> délimite le cœur informationnel unique de la page d'accueil.
|
||||
*/}
|
||||
<main>
|
||||
{/* Bannière d'introduction */}
|
||||
<Hero />
|
||||
|
||||
{/* Sélection des parcours utilisateurs */}
|
||||
<ProfileCards />
|
||||
|
||||
{/* Présentation du modèle "Learning by Doing" */}
|
||||
<Methodology />
|
||||
|
||||
{/* Statistiques d'impact et résultats sur 20 ans */}
|
||||
<Impact />
|
||||
|
||||
{/* Actualités, publications et veille */}
|
||||
<ActualitySection />
|
||||
|
||||
{/* Opportunités professionnelles et développement de compétences */}
|
||||
<CareersSection />
|
||||
|
||||
{/* Pied de page et liens institutionnels */}
|
||||
<Footer />
|
||||
</main>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
180
assets/components/Impact.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
259
assets/components/Methodology.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
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>
|
||||
);
|
||||
}
|
||||
BIN
assets/img/carreer.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/img/coach.png
Normal file
|
After Width: | Height: | Size: 335 KiB |
BIN
assets/img/entreprise.png
Normal file
|
After Width: | Height: | Size: 464 KiB |
BIN
assets/img/hero-banner.png
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
BIN
assets/img/homepageactuality.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
assets/img/impact.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
assets/img/individus.png
Normal file
|
After Width: | Height: | Size: 349 KiB |
BIN
assets/img/institutions.png
Normal file
|
After Width: | Height: | Size: 425 KiB |
BIN
assets/img/logo_gaea21.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
assets/img/univeriste.png
Normal file
|
After Width: | Height: | Size: 320 KiB |
@ -1,3 +1,248 @@
|
||||
body {
|
||||
background-color: skyblue;
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
/* NAVBAR */
|
||||
.navbar-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 50;
|
||||
padding: 1.5rem 3rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.navbar-content {
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.navbar-logo img {
|
||||
height: 46px;
|
||||
width: auto;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
gap: 3rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-links li a {
|
||||
text-decoration: none;
|
||||
color: #1e293b;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
/* Contour lumineux pour détacher les liens du feuillage */
|
||||
text-shadow: 0 1px 3px rgba(255, 255, 255, 0.8), 0 0 12px rgba(255, 255, 255, 0.6);
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-links li a:hover {
|
||||
color: #8c8f3e;
|
||||
}
|
||||
|
||||
.btn-participer {
|
||||
background-color: #8c8f3e;
|
||||
color: #ffffff;
|
||||
padding: 0.65rem 1.75rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
transition: background-color 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.btn-participer:hover {
|
||||
background-color: #737630;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
width: 28px;
|
||||
height: 22px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
z-index: 60;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.hamburger span {
|
||||
width: 100%;
|
||||
height: 2.5px;
|
||||
background-color: #1e293b;
|
||||
border-radius: 2px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* HERO BANNER */
|
||||
.hero-section {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-size: cover;
|
||||
background-position: center right;
|
||||
background-repeat: no-repeat;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
.hero-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg,
|
||||
rgba(255, 255, 255, 0.45) 0%,
|
||||
rgba(255, 255, 255, 0.15) 50%,
|
||||
rgba(255, 255, 255, 0) 100%);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
max-width: 1380px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.hero-text-block {
|
||||
max-width: 580px;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 2.75rem;
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
color: #0b1320;
|
||||
margin-bottom: 1.25rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
font-size: 0.88rem;
|
||||
line-height: 1.55;
|
||||
color: #724213;
|
||||
margin-bottom: 2rem;
|
||||
max-width: 460px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.btn-hero {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
background-color: #8c8f3e;
|
||||
color: #ffffff;
|
||||
padding: 0.75rem 1.6rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: all 0.25s ease;
|
||||
box-shadow: 0 4px 12px rgba(140, 143, 62, 0.25);
|
||||
}
|
||||
|
||||
.btn-hero:hover {
|
||||
background-color: #737630;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
@media (max-width: 960px) {
|
||||
.navbar-container {
|
||||
padding: 1.25rem 1.5rem;
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.hamburger.active span:nth-child(1) {
|
||||
transform: rotate(45deg) translate(5px, 5px);
|
||||
}
|
||||
|
||||
.hamburger.active span:nth-child(2) {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hamburger.active span:nth-child(3) {
|
||||
transform: rotate(-45deg) translate(6px, -6px);
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: -100%;
|
||||
width: 280px;
|
||||
height: 100vh;
|
||||
background-color: rgba(255, 255, 255, 0.98);
|
||||
backdrop-filter: blur(12px);
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 2rem;
|
||||
box-shadow: -4px 0 20px rgba(0, 0, 0, 0.08);
|
||||
transition: right 0.35s ease-in-out;
|
||||
}
|
||||
|
||||
.navbar-nav.open {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1.75rem;
|
||||
}
|
||||
|
||||
.nav-links li a {
|
||||
text-shadow: none;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.hero-section {
|
||||
min-height: auto;
|
||||
padding: 7rem 0 4rem 0;
|
||||
background-position: 70% center;
|
||||
}
|
||||
|
||||
.hero-overlay {
|
||||
background: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 1.85rem;
|
||||
}
|
||||
}
|
||||
367
assets/styles/footer.css
Normal file
@ -0,0 +1,367 @@
|
||||
/* ==========================================================================
|
||||
FOOTER GAEA21
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
Conteneur global du footer :
|
||||
- Fond blanc pur (#ffffff).
|
||||
- Padding haut généreux pour aérer par rapport à la section précédente.
|
||||
- overflow-x caché pour éviter tout scroll horizontal indésirable.
|
||||
*/
|
||||
.gaea-footer {
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
padding-top: 50px;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/*
|
||||
Conteneur interne pour centrer le contenu :
|
||||
- Calé sur la largeur maximale de la maquette (1440px).
|
||||
- Marges automatiques gauche/droite pour un centrage parfait.
|
||||
- Padding latéral de sécurité pour les écrans plus étroits.
|
||||
*/
|
||||
.gaea-footer-inner {
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
padding: 0 48px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
1. PARTIE SUPÉRIEURE : LOGO | LIGNE SÉPARATRICE | 3 COLONNES
|
||||
========================================================================== */
|
||||
.footer-top-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
/* Aligne le haut du logo avec le haut des titres de colonnes */
|
||||
padding-bottom: 60px;
|
||||
/* Espace entre la navigation et le bandeau newsletter */
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Bloc Marque : Logo gaea21 et icônes des réseaux sociaux */
|
||||
.footer-brand-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
width: 210px;
|
||||
flex-shrink: 0;
|
||||
/* Empêche le logo de rétrécir */
|
||||
}
|
||||
|
||||
.footer-logo {
|
||||
display: block;
|
||||
margin: 0 0 24px 0;
|
||||
/* Espacement entre le logo et les icônes */
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.footer-logo img {
|
||||
height: 48px;
|
||||
width: auto;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* Rangée des icônes de réseaux sociaux */
|
||||
.footer-socials {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
/* Espace régulier entre chaque icône */
|
||||
}
|
||||
|
||||
.footer-socials a {
|
||||
color: #000000;
|
||||
display: inline-flex;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.footer-socials a:hover {
|
||||
opacity: 0.7;
|
||||
/* Effet au survol */
|
||||
}
|
||||
|
||||
.footer-socials svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
/*
|
||||
Séparateur vertical doré Figma :
|
||||
- Couleur exacte dorée / bronze (#A8985A).
|
||||
- Hauteur proportionnelle à la zone logo + liens.
|
||||
- Marges précises pour équilibrer le vide visuel.
|
||||
*/
|
||||
.footer-gold-divider {
|
||||
width: 1.5px;
|
||||
height: 130px;
|
||||
background-color: #A8985A;
|
||||
margin: 0 65px 0 45px;
|
||||
/* 45px à gauche (côté logo), 65px à droite (côté liens) */
|
||||
flex-shrink: 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
/*
|
||||
Zone des colonnes de navigation :
|
||||
- Distribution équilibrée des colonnes avec un gap généreux.
|
||||
- padding-top léger (2px) pour aligner exactement la ligne de base du titre « Écosystème » avec le haut du logo.
|
||||
*/
|
||||
.footer-nav-columns {
|
||||
display: flex;
|
||||
gap: 150px;
|
||||
/* Espacement net entre « Écosystème », « Ressources », « À propos » */
|
||||
flex: 1;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
/* Titres dorés/kaki des colonnes de navigation */
|
||||
.footer-col-title {
|
||||
color: #A8985A;
|
||||
font-size: 14.5px;
|
||||
font-weight: 700;
|
||||
margin: 0 0 18px 0;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* Liste des liens */
|
||||
.footer-links-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
/* Espace vertical entre chaque sous-lien */
|
||||
}
|
||||
|
||||
.footer-links-list li a {
|
||||
color: #1a1a1a;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
line-height: 1.35;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.footer-links-list li a:hover {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
2. BANDEAU NEWSLETTER (PLEINE LARGEUR TOTALE - FULL BLEED)
|
||||
========================================================================== */
|
||||
.footer-newsletter-fullwidth {
|
||||
width: 100%;
|
||||
background-color: #D8DCAB;
|
||||
/* Teinte officielle verte amande/kaki clair du Figma */
|
||||
padding: 28px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Conteneur intérieur du bandeau newsletter */
|
||||
.footer-newsletter-content {
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
padding: 0 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Partie gauche : Disque icône + Titre & descriptif */
|
||||
.newsletter-brand-side {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
/* Cercle gris clair (#DDE1EA) sous l'icône enveloppe */
|
||||
.newsletter-icon-circle {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
background-color: #DDE1EA;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Enveloppe violette (#6568B9) */
|
||||
.newsletter-icon-circle svg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: #6568B9;
|
||||
}
|
||||
|
||||
.newsletter-texts h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
color: #000000;
|
||||
margin: 0 0 4px 0;
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.newsletter-texts p {
|
||||
font-size: 12.5px;
|
||||
color: #000000;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* Partie droite : Formulaire d'abonnement */
|
||||
.newsletter-form-side {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.newsletter-input-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* Champ de saisie ovale bordé de noir */
|
||||
.newsletter-input {
|
||||
width: 320px;
|
||||
height: 44px;
|
||||
background-color: transparent;
|
||||
border: 1.5px solid #000000;
|
||||
border-radius: 9999px;
|
||||
padding: 0 24px;
|
||||
font-size: 13px;
|
||||
color: #000000;
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.newsletter-input::placeholder {
|
||||
color: #222222;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* Bouton vert olive (#A4AC56 / #98984B) */
|
||||
.newsletter-btn {
|
||||
height: 44px;
|
||||
padding: 0 28px;
|
||||
background-color: #A4AC56;
|
||||
color: #ffffff;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
border-radius: 9999px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: opacity 0.2s ease, transform 0.1s ease;
|
||||
}
|
||||
|
||||
.newsletter-btn:hover {
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.newsletter-btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.newsletter-privacy-text {
|
||||
font-size: 10.5px;
|
||||
color: #000000;
|
||||
margin-top: 6px;
|
||||
padding-left: 10px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
3. BARRE DE MENTIONS LÉGALES TOUT EN BAS
|
||||
========================================================================== */
|
||||
.footer-bottom-bar {
|
||||
padding-top: 18px;
|
||||
padding-bottom: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.footer-bottom-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.footer-bottom-links a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.footer-bottom-links a:hover {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.footer-bottom-links .divider {
|
||||
color: #BCA86A;
|
||||
/* Couleur dorée pour le séparateur vertical */
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
RESPONSIVE : ADAPTATION SUR ÉCRANS MOBILES ET TABLETTES
|
||||
========================================================================== */
|
||||
@media (max-width: 1024px) {
|
||||
|
||||
.gaea-footer-inner,
|
||||
.footer-newsletter-content {
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.footer-top-row {
|
||||
flex-direction: column;
|
||||
gap: 35px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.footer-gold-divider {
|
||||
display: none;
|
||||
/* Masqué sur petit écran pour aérer */
|
||||
}
|
||||
|
||||
.footer-nav-columns {
|
||||
gap: 40px;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.footer-newsletter-content {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
.newsletter-input-group {
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.newsletter-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer-bottom-bar {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
0
assets/styles/header.css
Normal file
0
assets/styles/hero.css
Normal file
@ -41,7 +41,9 @@
|
||||
"symfony/ux-turbo": "^2.36",
|
||||
"symfony/validator": "7.4.*",
|
||||
"symfony/web-link": "7.4.*",
|
||||
"symfony/webpack-encore-bundle": "^2.4",
|
||||
"symfony/yaml": "7.4.*",
|
||||
"symfonycasts/tailwind-bundle": "^1.0",
|
||||
"twig/extra-bundle": "^2.12|^3.0",
|
||||
"twig/twig": "^2.12|^3.0"
|
||||
},
|
||||
|
||||
4301
composer.lock
generated
@ -13,4 +13,6 @@ return [
|
||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
Symfonycasts\TailwindBundle\SymfonycastsTailwindBundle::class => ['all' => true],
|
||||
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
||||
];
|
||||
|
||||
2
config/packages/symfonycasts_tailwind.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
symfonycasts_tailwind:
|
||||
binary_version: v3.4.19
|
||||
45
config/packages/webpack_encore.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
webpack_encore:
|
||||
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
|
||||
output_path: '%kernel.project_dir%/public/build'
|
||||
# If multiple builds are defined (as shown below), you can disable the default build:
|
||||
# output_path: false
|
||||
|
||||
# Set attributes that will be rendered on all script and link tags
|
||||
script_attributes:
|
||||
defer: true
|
||||
# Uncomment (also under link_attributes) if using Turbo Drive
|
||||
# https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change
|
||||
# 'data-turbo-track': reload
|
||||
# link_attributes:
|
||||
# Uncomment if using Turbo Drive
|
||||
# 'data-turbo-track': reload
|
||||
|
||||
# If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
|
||||
# crossorigin: 'anonymous'
|
||||
|
||||
# Preload all rendered script and link tags automatically via the HTTP/2 Link header
|
||||
# preload: true
|
||||
|
||||
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
|
||||
# strict_mode: false
|
||||
|
||||
# If you have multiple builds:
|
||||
# builds:
|
||||
# frontend: '%kernel.project_dir%/public/frontend/build'
|
||||
|
||||
# pass the build name as the 3rd argument to the Twig functions
|
||||
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
|
||||
|
||||
framework:
|
||||
assets:
|
||||
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
|
||||
|
||||
#when@prod:
|
||||
# webpack_encore:
|
||||
# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
|
||||
# # Available in version 1.2
|
||||
# cache: true
|
||||
|
||||
#when@test:
|
||||
# webpack_encore:
|
||||
# strict_mode: false
|
||||
@ -1526,6 +1526,26 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* generate_final_classes?: bool|Param, // Default: true
|
||||
* generate_final_entities?: bool|Param, // Default: false
|
||||
* }
|
||||
* @psalm-type SymfonycastsTailwindConfig = array{
|
||||
* input_css?: list<scalar|Param|null>,
|
||||
* config_file?: scalar|Param|null, // Path to the tailwind.config.js file // Default: "%kernel.project_dir%/tailwind.config.js"
|
||||
* binary?: scalar|Param|null, // The tailwind binary to use instead of downloading a new one // Default: null
|
||||
* binary_version?: scalar|Param|null, // Tailwind CLI version to download - required unless "binary" is set (run "tailwind:init" to configure) // Default: null
|
||||
* binary_platform?: "auto"|"linux-arm64"|"linux-arm64-musl"|"linux-x64"|"linux-x64-musl"|"macos-arm64"|"macos-x64"|"windows-x64"|Param, // Tailwind CLI platform to download - "auto" will try to detect the platform automatically // Default: "auto"
|
||||
* postcss_config_file?: scalar|Param|null, // Path to PostCSS config file which is passed to the Tailwind CLI // Default: null
|
||||
* strict_mode?: bool|Param|null, // When enabled, an exception will be thrown if there are no built assets (default: false in `test` env, true otherwise) // Default: null
|
||||
* process_timeout?: int|Param, // Timeout in seconds for the Tailwind build process - use "0" to disable // Default: 60
|
||||
* }
|
||||
* @psalm-type WebpackEncoreConfig = array{
|
||||
* output_path?: scalar|Param|null, // The path where Encore is building the assets - i.e. Encore.setOutputPath()
|
||||
* crossorigin?: false|"anonymous"|"use-credentials"|Param, // crossorigin value when Encore.enableIntegrityHashes() is used, can be false (default), anonymous or use-credentials // Default: false
|
||||
* preload?: bool|Param, // preload all rendered script and link tags automatically via the http2 Link header. // Default: false
|
||||
* cache?: bool|Param, // Enable caching of the entry point file(s) // Default: false
|
||||
* strict_mode?: bool|Param, // Throw an exception if the entrypoints.json file is missing or an entry is missing from the data // Default: true
|
||||
* builds?: array<string, scalar|Param|null>,
|
||||
* script_attributes?: array<string, scalar|Param|null>,
|
||||
* link_attributes?: array<string, scalar|Param|null>,
|
||||
* }
|
||||
* @psalm-type ConfigType = array{
|
||||
* imports?: ImportsConfig,
|
||||
* parameters?: ParametersConfig,
|
||||
@ -1539,6 +1559,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* twig_extra?: TwigExtraConfig,
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||
* webpack_encore?: WebpackEncoreConfig,
|
||||
* "when@dev"?: array{
|
||||
* imports?: ImportsConfig,
|
||||
* parameters?: ParametersConfig,
|
||||
@ -1555,6 +1577,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* maker?: MakerConfig,
|
||||
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||
* webpack_encore?: WebpackEncoreConfig,
|
||||
* },
|
||||
* "when@prod"?: array{
|
||||
* imports?: ImportsConfig,
|
||||
@ -1569,6 +1593,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* twig_extra?: TwigExtraConfig,
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||
* webpack_encore?: WebpackEncoreConfig,
|
||||
* },
|
||||
* "when@test"?: array{
|
||||
* imports?: ImportsConfig,
|
||||
@ -1584,6 +1610,8 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||
* twig_extra?: TwigExtraConfig,
|
||||
* security?: SecurityConfig,
|
||||
* monolog?: MonologConfig,
|
||||
* symfonycasts_tailwind?: SymfonycastsTailwindConfig,
|
||||
* webpack_encore?: WebpackEncoreConfig,
|
||||
* },
|
||||
* ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias
|
||||
* imports?: ImportsConfig,
|
||||
|
||||
@ -25,4 +25,10 @@ return [
|
||||
'@hotwired/turbo' => [
|
||||
'version' => '8.0.23',
|
||||
],
|
||||
'react' => [
|
||||
'version' => '19.3.0',
|
||||
],
|
||||
'react-dom' => [
|
||||
'version' => '19.3.0',
|
||||
],
|
||||
];
|
||||
|
||||
6942
package-lock.json
generated
Normal file
29
package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "gaea21-v2-web",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"dev-server": "encore dev-server",
|
||||
"dev": "encore dev",
|
||||
"watch": "encore dev --watch",
|
||||
"build": "encore production --progress"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.0",
|
||||
"@babel/preset-env": "^7.24.0",
|
||||
"@babel/preset-react": "^7.24.0",
|
||||
"@symfony/webpack-encore": "^5.1.0",
|
||||
"autoprefixer": "^10.6.1",
|
||||
"babel-plugin-polyfill-corejs3": "^1.0.0",
|
||||
"core-js": "^3.40.0",
|
||||
"postcss-loader": "^8.1.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"webpack": "^5.90.0",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
}
|
||||
}
|
||||
6
postcss.config.cjs
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
16
src/Controller/HomeController.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class HomeController extends AbstractController
|
||||
{
|
||||
#[Route('/', name: 'app_home')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('home/index.html.twig');
|
||||
}
|
||||
}
|
||||
25
symfony.lock
@ -319,6 +319,31 @@
|
||||
"./config/packages/messenger.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/webpack-encore-bundle": {
|
||||
"version": "2.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "2.2",
|
||||
"ref": "b618bf5f17ed61f523da7153025bf58ec9502f65"
|
||||
},
|
||||
"files": [
|
||||
"./assets/app.js",
|
||||
"./assets/styles/app.css",
|
||||
"./config/packages/webpack_encore.yaml",
|
||||
"./package.json",
|
||||
"./webpack.config.js"
|
||||
]
|
||||
},
|
||||
"symfonycasts/tailwind-bundle": {
|
||||
"version": "1.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "0.14",
|
||||
"ref": "b8af60cec7149fd0cde0ec9d89ccb32335c4d9bd"
|
||||
}
|
||||
},
|
||||
"twig/extra-bundle": {
|
||||
"version": "v3.29.0"
|
||||
}
|
||||
|
||||
23
tailwind.config.js
Normal file
@ -0,0 +1,23 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./assets/**/*.{js,jsx,ts,tsx}",
|
||||
"./templates/**/*.html.twig",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
gaea: {
|
||||
olive: '#8c8f3e',
|
||||
'olive-hover': '#737630',
|
||||
dark: '#0b1320',
|
||||
brown: '#724213',
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'],
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
@ -2,21 +2,18 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}gaea21 - Accueil{% endblock %}</title>
|
||||
|
||||
{# Fichiers CSS compilés par Webpack Encore #}
|
||||
{% block stylesheets %}
|
||||
{{ encore_entry_link_tags('app') }}
|
||||
{% endblock %}
|
||||
|
||||
{# Fichiers JS compilés par Webpack Encore #}
|
||||
{% block javascripts %}
|
||||
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
||||
{{ encore_entry_script_tags('app') }}
|
||||
{% endblock %}
|
||||
|
||||
{% set frankenphp_hot_reload = app.request.server.get('FRANKENPHP_HOT_RELOAD') %}
|
||||
{% if frankenphp_hot_reload %}
|
||||
<meta name="frankenphp-hot-reload:url" content="{{ frankenphp_hot_reload }}">
|
||||
<script src="https://cdn.jsdelivr.net/npm/idiomorph"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/frankenphp-hot-reload/+esm" type="module"></script>
|
||||
{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
7
templates/home/index.html.twig
Normal file
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}gaea21 - Accueil{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div id="root"></div>
|
||||
{% endblock %}
|
||||
30
webpack.config.cjs
Normal file
@ -0,0 +1,30 @@
|
||||
const Encore = require('@symfony/webpack-encore');
|
||||
|
||||
// Manually configure the runtime environment if not already configured yet by the "encore" command.
|
||||
if (!Encore.isRuntimeEnvironmentConfigured()) {
|
||||
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
|
||||
}
|
||||
|
||||
Encore
|
||||
// Répertoire où les fichiers compilés seront stockés
|
||||
.setOutputPath('public/build/')
|
||||
// Chemin public utilisé par le serveur web
|
||||
.setPublicPath('/build')
|
||||
|
||||
/*
|
||||
* ENTRY CONFIG
|
||||
*/
|
||||
.addEntry('app', './assets/app.js')
|
||||
|
||||
.splitEntryChunks()
|
||||
.enableSingleRuntimeChunk()
|
||||
.cleanupOutputBeforeBuild()
|
||||
.enableSourceMaps(!Encore.isProduction())
|
||||
.enableVersioning(Encore.isProduction())
|
||||
|
||||
// Activer React
|
||||
.enableReactPreset()
|
||||
.enablePostCssLoader()
|
||||
;
|
||||
|
||||
module.exports = Encore.getWebpackConfig();
|
||||