feat(workflow.twig): Ajoute animations AOS pour un effet visuel amélioré.

 feat(app.js): Initialise la librairie AOS pour les animations.

 chore(package.json): Ajoute AOS comme dépendance.

 feat(reserve.js): Initialise AOS pour les animations.

 feat(formules.twig): Ajoute animations AOS pour améliorer l'UX.

 feat(catalogue.twig): Ajoute animations AOS pour une meilleure UX.

 feat(dashboard/base.twig): Améliore la mise en page du dashboard.

 feat(base.twig): Ajoute macros pour les liens de navigation.

 feat(home.twig): Ajoute animations AOS et macros pour la page d'accueil.
```
This commit is contained in:
Serreau Jovann
2026-01-30 12:34:51 +01:00
parent dfcac42e6e
commit 53878e467a
9 changed files with 223 additions and 170 deletions

View File

@@ -1,6 +1,8 @@
import './app.scss';
import * as Turbo from "@hotwired/turbo";
import * as Sentry from "@sentry/browser";
import AOS from 'aos';
import 'aos/dist/aos.css';
// --- INITIALISATION SENTRY ---
// On initialise Sentry immédiatement sans attendre le DOM pour capturer les erreurs précoces
@@ -29,6 +31,14 @@ const initApp = () => {
}, 5000);
});
// Initialize AOS
AOS.init({
duration: 800,
once: true,
// offset: 120, // Optional: offset (in px) from the original trigger point
// easing: 'ease', // Optional: default easing for AOS animations
});
// Exemple : Init d'un bouton de retour en haut de page
// initBackToTop();
};

View File

@@ -3,6 +3,8 @@ import { UtmEvent, UtmAccount } from "./tools/UtmEvent.js";
import { CookieBanner } from "./tools/CookieBanner.js";
import * as Turbo from "@hotwired/turbo";
import { onLCP, onINP, onCLS } from 'web-vitals';
import AOS from 'aos';
import 'aos/dist/aos.css';
// --- CONFIGURATION & ÉTAT ---
const CONFIG = {
@@ -272,6 +274,12 @@ document.addEventListener('turbo:load', () => {
initRegisterLogic();
initCatalogueSearch();
// Initialize AOS
AOS.init({
duration: 800,
once: true,
});
const payContainer = document.getElementById('payment-check-container');
if (payContainer?.dataset.autoRedirect) {
setTimeout(() => {

View File

@@ -28,6 +28,7 @@
"@preact/preset-vite": "^2.10.2",
"@sentry/browser": "^10.34.0",
"@tailwindcss/vite": "^4.1.18",
"aos": "^2.3.4",
"autoprefixer": "^10.4.23",
"body-scroll-lock": "^4.0.0-beta.0",
"react-email-editor": "^1.7.11",

View File

@@ -108,7 +108,7 @@
</header>
{# CONTENT #}
<div class="p-6 md:p-10 page-transition w-full">
<div class="flex-1 overflow-y-auto custom-scrollbar flex flex-col p-6 md:p-10 page-transition w-full">
<div class="flex items-end justify-between mb-10 pb-8 border-b border-slate-800/50">
<div>
<p class="text-blue-600 font-bold text-[10px] uppercase tracking-[0.4em] mb-2">Ludikevent Intranet</p>
@@ -170,7 +170,7 @@
{% endfor %}
</div>
<div class="w-full">
<div class="w-full flex-1 flex flex-col">
{% block body %}{% endblock %}
{# FOOTER #}

View File

@@ -47,6 +47,25 @@
<utm-account id="{{ app.user.id }}" email="{{ app.user.email }}" name="{{ app.user.name }} {{ app.user.surname }}"></utm-account>
{% endif %}
{# --- MACROS --- #}
{% macro nav_link(route_name, label_key, is_external = false) %}
<a href="{{ is_external ? route_name : path(route_name) }}"
{% if is_external %}target="_blank"{% endif %}
class="text-gray-700 hover:text-blue-600 font-medium transition-colors">
{{ label_key|trans }}
</a>
{% endmacro %}
{% macro mobile_nav_link(route_name, label_key, is_external = false) %}
<a href="{{ is_external ? route_name : path(route_name) }}"
{% if is_external %}target="_blank"{% endif %}
class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl">
{{ label_key|trans }}
</a>
{% endmacro %}
{% import _self as macros %}
{# --- NAVIGATION --- #}
<nav class="sticky top-0 z-50 bg-white/95 backdrop-blur-md border-b border-gray-100" role="navigation" aria-label="{{ 'nav.aria_label'|trans }}">
<div class="max-w-8xl mx-auto px-4 sm:px-6 lg:px-8">
@@ -64,12 +83,12 @@
{# Menu Desktop #}
<div class="hidden md:flex items-center space-x-8">
<a href="{{ path('reservation') }}" class="text-gray-700 hover:text-blue-600 font-medium transition-colors">{{ 'nav.home'|trans }}</a>
<a href="{{ path('reservation_catalogue') }}" class="text-gray-700 hover:text-blue-600 font-medium transition-colors">{{ 'nav.catalogue'|trans }}</a>
<a href="{{ path('reservation_formules') }}" class="text-gray-700 hover:text-blue-600 font-medium transition-colors">{{ 'nav.packages'|trans }}</a>
<a target="_blank" href="/images/Catalogue.pdf" class="text-gray-700 hover:text-blue-600 font-medium transition-colors">{{ 'nav.pdf'|trans }}</a>
<a href="{{ path('reservation_workflow') }}" class="text-gray-700 hover:text-blue-600 font-medium transition-colors">{{ 'nav.how_to_book'|trans }}</a>
<a href="{{ path('reservation_contact') }}" class="text-gray-700 hover:text-blue-600 font-medium transition-colors">{{ 'nav.contact'|trans }}</a>
{{ macros.nav_link('reservation', 'nav.home') }}
{{ macros.nav_link('reservation_catalogue', 'nav.catalogue') }}
{{ macros.nav_link('reservation_formules', 'nav.packages') }}
{{ macros.nav_link('/images/Catalogue.pdf', 'nav.pdf', true) }}
{{ macros.nav_link('reservation_workflow', 'nav.how_to_book') }}
{{ macros.nav_link('reservation_contact', 'nav.contact') }}
<a href="{{ path('reservation_search') }}" class="p-2 text-gray-600 hover:text-blue-600 transition-colors" aria-label="{{ 'nav.search_aria'|trans }}">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -113,12 +132,12 @@
{# Menu Mobile #}
<div id="mobile-menu" class="hidden md:hidden bg-white border-t border-gray-100 shadow-xl">
<div class="px-4 pt-2 pb-6 space-y-2">
<a href="{{ path('reservation') }}" class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl">{{ 'Accueil'|trans }}</a>
<a href="{{ path('reservation_catalogue') }}" class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl">{{ 'Nos structures'|trans }}</a>
<a href="{{ path('reservation_formules') }}" class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl">{{ 'Nos Formules'|trans }}</a>
<a target="_blank" href="/provider/Catalogue.pdf" class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl">{{ 'Catalogue'|trans }}</a>
<a href="{{ path('reservation_workflow') }}" class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl">{{ 'Comment reserver'|trans }}</a>
<a href="{{ path('reservation_search') }}" class="block px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 rounded-xl">{{ 'Rechercher'|trans }}</a>
{{ macros.mobile_nav_link('reservation', 'Accueil') }}
{{ macros.mobile_nav_link('reservation_catalogue', 'Nos structures') }}
{{ macros.mobile_nav_link('reservation_formules', 'Nos Formules') }}
{{ macros.mobile_nav_link('/provider/Catalogue.pdf', 'Catalogue', true) }}
{{ macros.mobile_nav_link('reservation_workflow', 'Comment reserver') }}
{{ macros.mobile_nav_link('reservation_search', 'Rechercher') }}
<div class="pt-4 border-t border-gray-50">
<a href="tel:0614172447" class="block px-3 py-3 text-center bg-blue-600 text-white rounded-xl font-bold">
{{ 'Appeler le'|trans }} 06 14 17 24 47
@@ -132,7 +151,8 @@
{% for label, messages in app.flashes %}
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 mt-4" role="alert">
{% for message in messages %}
<div class="flex items-center justify-between p-4 rounded-2xl shadow-lg border">
{% set border_class = label == 'error' ? 'border-red-200 bg-red-50 text-red-800' : (label == 'success' ? 'border-green-200 bg-green-50 text-green-800' : 'border-blue-200 bg-blue-50 text-blue-800') %}
<div class="flex items-center justify-between p-4 rounded-2xl shadow-lg border {{ border_class }}">
<div class="flex items-center gap-3">
<p class="text-sm font-bold uppercase italic">{{ message|trans }}</p>
</div>

View File

@@ -18,19 +18,19 @@
{# --- HEADER --- #}
<div class="max-w-7xl mx-auto pt-16 pb-8 px-4 text-center">
<nav class="flex justify-center space-x-4 text-[10px] mb-8 uppercase tracking-[0.3em] font-black italic">
<nav class="flex justify-center space-x-4 text-[10px] mb-8 uppercase tracking-[0.3em] font-black italic" data-aos="fade-down">
<a href="{{ url('reservation') }}" class="text-slate-600 hover:text-[#fc0e50] transition">{{ 'nav.home'|trans }}</a>
<span class="text-slate-500">/</span>
<span class="text-amber-700 underline decoration-2 underline-offset-4">{{ 'catalog.breadcrumb'|trans }}</span>
</nav>
<h1 class="text-5xl md:text-7xl font-black text-slate-900 uppercase tracking-tighter italic leading-none mb-6">
<h1 class="text-5xl md:text-7xl font-black text-slate-900 uppercase tracking-tighter italic leading-none mb-6" data-aos="fade-up" data-aos-delay="100">
{{ 'catalog.header.main'|trans }} <span class="text-[#f39e36]">{{ 'catalog.header.highlight'|trans }}</span>
</h1>
</div>
{# --- FILTRES --- #}
<div class="sticky top-0 z-40 bg-gray-50/90 backdrop-blur-md border-b border-slate-200 mb-12">
<div class="sticky top-0 z-40 bg-gray-50/90 backdrop-blur-md border-b border-slate-200 mb-12" data-aos="fade-in" data-aos-delay="200">
<div class="max-w-7xl mx-auto px-4 py-4">
<div class="flex flex-wrap justify-center gap-2 md:gap-3">
<button data-filter="all" class="filter-btn px-5 py-2.5 rounded-xl font-black italic text-[9px] tracking-widest transition-all uppercase shadow-sm bg-slate-900 text-white border border-slate-900">
@@ -61,7 +61,7 @@
<div id="product-grid" class="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-x-8 gap-y-12">
{% for product in products %}
<div class="product-item group transition-all duration-500" data-category="{{ product.category|lower }}">
<div class="product-item group transition-all duration-500" data-category="{{ product.category|lower }}" data-aos="fade-up">
<a href="{{ path('reservation_product_show', {id: product.slug}) }}" class="block">
<div class="relative overflow-hidden rounded-[1.25rem] md:rounded-[1rem] bg-slate-100 aspect-square mb-4 md:mb-6 shadow-sm group-hover:shadow-2xl transition-all duration-700">
@@ -129,7 +129,7 @@
</div>
{% endfor %}
<div id="empty-msg" class="hidden col-span-full py-24 text-center bg-white rounded-[3.5rem] border-2 border-dashed border-slate-100">
<div id="empty-msg" class="hidden col-span-full py-24 text-center bg-white rounded-[3.5rem] border-2 border-dashed border-slate-100" data-aos="fade-in">
<p class="text-slate-600 font-black italic uppercase tracking-widest text-xs">{{ 'catalog.empty'|trans }}</p>
</div>

View File

@@ -20,16 +20,16 @@
{# --- HEADER --- #}
<div class="max-w-7xl mx-auto pt-16 pb-12 px-4 text-center">
<nav class="flex justify-center space-x-4 text-[10px] mb-8 uppercase tracking-[0.3em] font-black italic">
<nav class="flex justify-center space-x-4 text-[10px] mb-8 uppercase tracking-[0.3em] font-black italic" data-aos="fade-down">
<a href="{{ url('reservation') }}" class="text-slate-600 hover:text-[#fc0e50] transition">ACCUEIL</a>
<span class="text-slate-500">/</span>
<span class="text-amber-700 underline decoration-2 underline-offset-4 tracking-[0.3em]">NOS FORMULES</span>
</nav>
<h1 class="text-6xl md:text-8xl font-black text-slate-900 uppercase tracking-tighter italic leading-none mb-6">
<h1 class="text-6xl md:text-8xl font-black text-slate-900 uppercase tracking-tighter italic leading-none mb-6" data-aos="fade-up" data-aos-delay="100">
PACKS <span class="text-[#fc0e50]">&</span> <span class="text-blue-600">FORMULES</span>
</h1>
<p class="max-w-2xl mx-auto text-slate-600 font-bold uppercase text-xs tracking-widest italic">
<p class="max-w-2xl mx-auto text-slate-600 font-bold uppercase text-xs tracking-widest italic" data-aos="fade-up" data-aos-delay="200">
Simplifiez votre événement avec nos solutions <span class="text-slate-900 underline decoration-[#f39e36] decoration-4">clés en main</span>
</p>
</div>
@@ -37,7 +37,7 @@
{# --- GRILLE DES FORMULES --- #}
<div class="max-w-7xl mx-auto px-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
{% for formule in formules %}
<div class="group bg-white rounded-[3rem] p-4 border-2 border-slate-900 shadow-[10px_10px_0px_0px_rgba(15,23,42,1)] hover:shadow-[15px_15px_0px_0px_rgba(15,23,42,1)] transition-all duration-300 flex flex-col">
<div class="group bg-white rounded-[3rem] p-4 border-2 border-slate-900 shadow-[10px_10px_0px_0px_rgba(15,23,42,1)] hover:shadow-[15px_15px_0px_0px_rgba(15,23,42,1)] transition-all duration-300 flex flex-col" data-aos="fade-up">
{# Conteneur Image #}
<div class="relative overflow-hidden rounded-[2.5rem] aspect-[4/5] bg-slate-100 flex items-center justify-center border-b-2 border-slate-900">
@@ -112,7 +112,7 @@
</div>
</div>
{% else %}
<div class="col-span-full py-32 text-center bg-white border-4 border-dashed border-slate-200 rounded-[4rem]">
<div class="col-span-full py-32 text-center bg-white border-4 border-dashed border-slate-200 rounded-[4rem]" data-aos="fade-in">
<div class="text-6xl mb-6">🎈</div>
<h2 class="text-2xl font-black text-slate-900 uppercase italic">Mise à jour imminente</h2>
<p class="text-slate-500 font-medium mt-2">Nos formules arrivent d'ici quelques minutes...</p>
@@ -121,7 +121,7 @@
</div>
{# --- CTA CATALOGUE --- #}
<div class="mt-20 text-center">
<div class="mt-20 text-center" data-aos="fade-up">
<p class="text-slate-500 font-bold uppercase text-[10px] tracking-[0.2em] mb-6">Besoin de composer votre propre bonheur ?</p>
<a href="{{ url('reservation_catalogue') }}" class="inline-flex items-center space-x-3 bg-slate-900 text-white px-10 py-5 rounded-full font-black uppercase italic tracking-wider hover:bg-[#fc0e50] transition-all group">
<span>Accéder au catalogue complet</span>

View File

@@ -4,10 +4,10 @@
{% block description %}
Ludik Event : location de structures gonflables dans le 02. Châteaux, parcours et jeux pour vos événements dans les Hauts-de-France. Devis gratuit sous 2h !
{% endblock %}
{% block canonical %}
{% block canonical %}
{# Génère l'URL propre automatiquement pour 99% des pages #}
<link rel="canonical" href="{{ url('reservation') }}">
{% endblock %}
{% endblock %}
{% block jsonld %}
<script type="application/ld+json">
{
@@ -31,107 +31,10 @@
{% block stylesheets %}
<link rel="preload" as="image" href="{{ asset('provider/video/video.jpg') | imagine_filter('poster_hero') }}" fetchpriority="high">
{% endblock %}
{% block body %}
<utm-event event="view_home"></utm-event>
<div class="space-y-20 pb-20 bg-gray-50/50">
{# --- SECTION HERO --- #}
<section class="relative overflow-hidden pt-16 pb-8 lg:pt-24" aria-label="Introduction">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="lg:grid lg:grid-cols-12 lg:gap-8 items-center">
<div class="sm:text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left">
<h1 class="text-5xl md:text-7xl font-black tracking-tight text-gray-900 leading-[1.1] uppercase italic">
Louez le <span class="text-[#f39e36]">Bonheur</span> <br>
{# Correction contraste : amber-500 -> amber-700 #}
<span class="text-[#fc0e50] underline decoration-blue-600/20">en un clic.</span>
</h1>
<p class="mt-6 text-lg text-gray-700 leading-relaxed italic">
Ludik Event simplifie vos événements. Des structures certifiées, une livraison rapide et des souvenirs inoubliables pour les petits et les grands.
</p>
<div class="mt-10 flex flex-col sm:flex-row gap-4 sm:justify-center lg:justify-start">
<a href="{{ path('reservation_catalogue') }}" class="px-8 py-4 bg-[#f39e36] text-white rounded-2xl font-bold text-lg shadow-xl shadow-blue-200 hover:bg-blue-700 transition-all hover:-translate-y-1 text-center uppercase tracking-tighter">
Voir le catalogue
</a>
<a href="tel:0614172447" class="px-8 py-4 bg-white text-gray-800 border border-gray-200 rounded-2xl font-bold text-lg hover:bg-gray-50 transition-all text-center uppercase tracking-tighter">
<span aria-hidden="true">📞</span> 06 14 17 24 47
</a>
</div>
</div>
{# Vidéo Hero #}
<div class="mt-12 lg:mt-0 lg:col-span-6 relative">
<div class="relative mx-auto w-full rounded-[3rem] overflow-hidden shadow-2xl rotate-2 hover:rotate-0 transition-transform duration-500 border-8 border-white">
<video
autoplay muted loop playsinline
{# MODIF : preload="auto" pour charger le poster immédiatement #}
preload="auto"
poster="{{ asset('provider/video/video.jpg') | imagine_filter('poster_hero') }}"
src="{{ asset('provider/video/video.mp4') }}"
{# AJOUT : Priorité de chargement haute #}
data-fetchpriority="high"
class="w-full h-full object-cover aspect-[4/3]">
<p>Location de structures gonflables Ludikevent.</p>
</video>
<div class="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent" aria-hidden="true"></div>
</div>
<div class="absolute -bottom-6 -left-6 bg-white p-6 rounded-3xl shadow-xl hidden md:block border border-gray-100">
<div class="flex items-center gap-4">
{# Correction contraste badge #}
<div class="p-3 bg-amber-100 text-amber-900 uppercase font-black text-xs tracking-widest rounded-2xl">
⭐ Top Qualité
</div>
</div>
</div>
</div>
</div>
</div>
</section>
{# --- SECTION SERVICES (Correction hiérarchie h4 -> h3) --- #}
<section class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" aria-label="Nos services">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="flex items-center gap-6 p-8 bg-white rounded-[2.5rem] border border-gray-100 shadow-sm">
<div class="w-14 h-14 bg-blue-50 rounded-2xl flex items-center justify-center text-2xl shrink-0" aria-hidden="true">💬</div>
<div>
<h2 class="font-black text-gray-900 uppercase italic text-sm">Service Client Expert</h2>
<p class="text-xs text-gray-600 mt-1 italic">Une équipe à votre écoute pour un événement sur mesure.</p>
</div>
</div>
<div class="flex items-center gap-6 p-8 bg-white rounded-[2.5rem] border border-gray-100 shadow-sm">
<div class="w-14 h-14 bg-amber-50 rounded-2xl flex items-center justify-center text-2xl shrink-0" aria-hidden="true">🚚</div>
<div>
<h2 class="font-black text-gray-900 uppercase italic text-sm">le</h2>
<p class="text-xs text-gray-600 mt-1 italic">Nous livrons vos structures directement sur le lieu de fête.</p>
</div>
</div>
<div class="flex items-center gap-6 p-8 bg-white rounded-[2.5rem] border border-gray-100 shadow-sm">
<div class="w-14 h-14 bg-indigo-50 rounded-2xl flex items-center justify-center text-2xl shrink-0" aria-hidden="true">🎡</div>
<div>
<h2 class="font-black text-gray-900 uppercase italic text-sm">Large Choix</h2>
<p class="text-xs text-gray-600 mt-1 italic">Un catalogue varié pour satisfaire toutes les envies.</p>
</div>
</div>
</div>
</section>
{# --- SECTION CATALOGUE --- #}
<section id="catalogue" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex flex-col md:flex-row justify-between items-end mb-12 gap-4">
<div>
<h2 class="text-4xl font-black text-gray-900 uppercase italic tracking-tighter">Nos <span class="text-[#f39e36]">Best-Sellers</span></h2>
<p class="text-gray-600 mt-2 italic">Sélectionnés pour le succès de vos fêtes.</p>
</div>
<a href="{{ path('reservation_catalogue') }}" class="group text-[#fc0e50] font-bold flex items-center gap-2 uppercase text-xs tracking-[0.2em] bg-orange-50 px-6 py-3 rounded-full over:text-white transition-all">
Tout le catalogue
<svg class="w-4 h-4 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
</svg>
</a>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{% for product in products %}
<div class="group bg-white rounded-[3rem] p-4 border border-gray-100 shadow-sm hover:shadow-2xl transition-all duration-500 flex flex-col">
{# --- MACROS --- #}
{% macro product_card(product) %}
<div class="group bg-white rounded-[3rem] p-4 border border-gray-100 shadow-sm hover:shadow-2xl transition-all duration-500 flex flex-col" data-aos="fade-up">
{# Conteneur Image #}
<div class="relative overflow-hidden rounded-[2.5rem] aspect-[4/5] bg-slate-50 flex items-center justify-center">
@@ -180,32 +83,10 @@
</div>
</div>
</div>
{% else %}
{# Message si aucun produit (Correction contraste) #}
<div class="col-span-full py-20 text-center bg-white rounded-[3rem] border-2 border-dashed border-gray-200">
<p class="text-gray-600 font-bold italic uppercase tracking-widest">Le catalogue est en cours de mise à jour...</p>
</div>
{% endfor %}
</div>
</section>
<section id="catalogue" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex flex-col md:flex-row justify-between items-end mb-12 gap-4">
<div>
<h2 class="text-4xl font-black text-gray-900 uppercase italic tracking-tighter">Nos <span class="text-[#f39e36]">Formules</span></h2>
<p class="text-gray-600 mt-2 italic">Sélectionnés pour le succès de vos fêtes.</p>
</div>
<a href="{{ path('reservation_formules') }}" class="group text-[#fc0e50] font-bold flex items-center gap-2 uppercase text-xs tracking-[0.2em] bg-orange-50 px-6 py-3 rounded-full over:text-white transition-all">
Tout les formules
<svg class="w-4 h-4 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
</svg>
</a>
</div>
{% endmacro %}
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{% for formule in formules %}
<div class="group bg-white rounded-[3rem] p-4 border border-gray-100 shadow-sm hover:shadow-2xl transition-all duration-500 flex flex-col">
{% macro formula_card(formule) %}
<div class="group bg-white rounded-[3rem] p-4 border border-gray-100 shadow-sm hover:shadow-2xl transition-all duration-500 flex flex-col" data-aos="fade-up">
{# Conteneur Image #}
<div class="relative overflow-hidden rounded-[2.5rem] aspect-[4/5] bg-slate-50 flex items-center justify-center">
@@ -267,6 +148,139 @@
</div>
</div>
</div>
{% endmacro %}
{% import _self as macros %}
{% block body %}
<utm-event event="view_home"></utm-event>
<div class="space-y-20 pb-20 bg-gray-50/50">
{# --- SECTION HERO --- #}
<section class="relative overflow-hidden pt-16 pb-8 lg:pt-24" aria-label="Introduction">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="lg:grid lg:grid-cols-12 lg:gap-8 items-center">
<div class="sm:text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left">
<h1 class="text-5xl md:text-7xl font-black tracking-tight text-gray-900 leading-[1.1] uppercase italic" data-aos="fade-right">
Louez le <span class="text-[#f39e36]">Bonheur</span> <br>
{# Correction contraste : amber-500 -> amber-700 #}
<span class="text-[#fc0e50] underline decoration-blue-600/20">en un clic.</span>
</h1>
<p class="mt-6 text-lg text-gray-700 leading-relaxed italic" data-aos="fade-right" data-aos-delay="100">
Ludik Event simplifie vos événements. Des structures certifiées, une livraison rapide et des souvenirs inoubliables pour les petits et les grands.
</p>
<div class="mt-10 flex flex-col sm:flex-row gap-4 sm:justify-center lg:justify-start" data-aos="fade-up" data-aos-delay="200">
<a href="{{ path('reservation_catalogue') }}" class="px-8 py-4 bg-[#f39e36] text-white rounded-2xl font-bold text-lg shadow-xl shadow-blue-200 hover:bg-blue-700 transition-all hover:-translate-y-1 text-center uppercase tracking-tighter">
Voir le catalogue
</a>
<a href="tel:0614172447" class="px-8 py-4 bg-white text-gray-800 border border-gray-200 rounded-2xl font-bold text-lg hover:bg-gray-50 transition-all text-center uppercase tracking-tighter">
<span aria-hidden="true">📞</span> 06 14 17 24 47
</a>
</div>
</div>
{# Vidéo Hero #}
<div class="mt-12 lg:mt-0 lg:col-span-6 relative" data-aos="zoom-in" data-aos-duration="1000">
<div class="relative mx-auto w-full rounded-[3rem] overflow-hidden shadow-2xl rotate-2 hover:rotate-0 transition-transform duration-500 border-8 border-white">
<video
autoplay muted loop playsinline
{# MODIF : preload="auto" pour charger le poster immédiatement #}
preload="auto"
poster="{{ asset('provider/video/video.jpg') | imagine_filter('poster_hero') }}"
src="{{ asset('provider/video/video.mp4') }}"
{# AJOUT : Priorité de chargement haute #}
data-fetchpriority="high"
class="w-full h-full object-cover aspect-[4/3]">
<p>Location de structures gonflables Ludikevent.</p>
</video>
<div class="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent" aria-hidden="true"></div>
</div>
<div class="absolute -bottom-6 -left-6 bg-white p-6 rounded-3xl shadow-xl hidden md:block border border-gray-100" data-aos="fade-up" data-aos-delay="400">
<div class="flex items-center gap-4">
{# Correction contraste badge #}
<div class="p-3 bg-amber-100 text-amber-900 uppercase font-black text-xs tracking-widest rounded-2xl">
⭐ Top Qualité
</div>
</div>
</div>
</div>
</div>
</div>
</section>
{# --- SECTION SERVICES (Correction hiérarchie h4 -> h3) --- #}
<section class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" aria-label="Nos services">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<div class="flex items-center gap-6 p-8 bg-white rounded-[2.5rem] border border-gray-100 shadow-sm" data-aos="fade-up" data-aos-delay="0">
<div class="w-14 h-14 bg-blue-50 rounded-2xl flex items-center justify-center text-2xl shrink-0" aria-hidden="true">💬</div>
<div>
<h2 class="font-black text-gray-900 uppercase italic text-sm">Service Client Expert</h2>
<p class="text-xs text-gray-600 mt-1 italic">Une équipe à votre écoute pour un événement sur mesure.</p>
</div>
</div>
<div class="flex items-center gap-6 p-8 bg-white rounded-[2.5rem] border border-gray-100 shadow-sm" data-aos="fade-up" data-aos-delay="100">
<div class="w-14 h-14 bg-amber-50 rounded-2xl flex items-center justify-center text-2xl shrink-0" aria-hidden="true">🚚</div>
<div>
<h2 class="font-black text-gray-900 uppercase italic text-sm">le</h2>
<p class="text-xs text-gray-600 mt-1 italic">Nous livrons vos structures directement sur le lieu de fête.</p>
</div>
</div>
<div class="flex items-center gap-6 p-8 bg-white rounded-[2.5rem] border border-gray-100 shadow-sm" data-aos="fade-up" data-aos-delay="200">
<div class="w-14 h-14 bg-indigo-50 rounded-2xl flex items-center justify-center text-2xl shrink-0" aria-hidden="true">🎡</div>
<div>
<h2 class="font-black text-gray-900 uppercase italic text-sm">Large Choix</h2>
<p class="text-xs text-gray-600 mt-1 italic">Un catalogue varié pour satisfaire toutes les envies.</p>
</div>
</div>
</div>
</section>
{# --- SECTION CATALOGUE --- #}
<section id="catalogue" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex flex-col md:flex-row justify-between items-end mb-12 gap-4">
<div data-aos="fade-right">
<h2 class="text-4xl font-black text-gray-900 uppercase italic tracking-tighter">Nos <span class="text-[#f39e36]">Best-Sellers</span></h2>
<p class="text-gray-600 mt-2 italic">Sélectionnés pour le succès de vos fêtes.</p>
</div>
<a href="{{ path('reservation_catalogue') }}" class="group text-[#fc0e50] font-bold flex items-center gap-2 uppercase text-xs tracking-[0.2em] bg-orange-50 px-6 py-3 rounded-full over:text-white transition-all" data-aos="fade-left">
Tout le catalogue
<svg class="w-4 h-4 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
</svg>
</a>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{% for product in products %}
{{ macros.product_card(product) }}
{% else %}
{# Message si aucun produit (Correction contraste) #}
<div class="col-span-full py-20 text-center bg-white rounded-[3rem] border-2 border-dashed border-gray-200">
<p class="text-gray-600 font-bold italic uppercase tracking-widest">Le catalogue est en cours de mise à jour...</p>
</div>
{% endfor %}
</div>
</section>
{# --- SECTION FORMULES --- #}
<section id="formules" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex flex-col md:flex-row justify-between items-end mb-12 gap-4">
<div data-aos="fade-right">
<h2 class="text-4xl font-black text-gray-900 uppercase italic tracking-tighter">Nos <span class="text-[#f39e36]">Formules</span></h2>
<p class="text-gray-600 mt-2 italic">Sélectionnés pour le succès de vos fêtes.</p>
</div>
<a href="{{ path('reservation_formules') }}" class="group text-[#fc0e50] font-bold flex items-center gap-2 uppercase text-xs tracking-[0.2em] bg-orange-50 px-6 py-3 rounded-full over:text-white transition-all" data-aos="fade-left">
Tout les formules
<svg class="w-4 h-4 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
</svg>
</a>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{% for formule in formules %}
{{ macros.formula_card(formule) }}
{% else %}
<div class="col-span-full py-20 text-center bg-white rounded-[3rem] border-2 border-dashed border-gray-200">
<p class="text-gray-600 font-bold italic uppercase tracking-widest">Les formules sont en cours de mise à jour...</p>

View File

@@ -17,13 +17,13 @@
{# --- HEADER --- #}
<div class="max-w-4xl mx-auto pt-20 pb-16 px-4 text-center">
<span class="inline-block bg-blue-100 text-blue-600 px-4 py-1.5 rounded-full text-[10px] font-black uppercase tracking-widest mb-6">
<span class="inline-block bg-blue-100 text-blue-600 px-4 py-1.5 rounded-full text-[10px] font-black uppercase tracking-widest mb-6" data-aos="fade-down">
{{ 'workflow.header.badge'|trans }}
</span>
<h1 class="text-6xl md:text-8xl font-black text-slate-900 uppercase italic tracking-tighter leading-[0.85] mb-6">
<h1 class="text-6xl md:text-8xl font-black text-slate-900 uppercase italic tracking-tighter leading-[0.85] mb-6" data-aos="fade-up" data-aos-delay="100">
{{ 'workflow.header.title_part1'|trans }} <br><span class="text-blue-600">{{ 'workflow.header.title_part2'|trans }}</span>
</h1>
<p class="text-xl text-slate-500 font-medium italic leading-relaxed">{{ 'workflow.header.subtitle'|trans }}</p>
<p class="text-xl text-slate-500 font-medium italic leading-relaxed" data-aos="fade-up" data-aos-delay="200">{{ 'workflow.header.subtitle'|trans }}</p>
</div>
{# --- TIMELINE --- #}
@@ -33,7 +33,7 @@
<div class="space-y-24 relative z-10">
{# 1. SELECTION #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-right">
<div class="flex-1 text-center md:text-right order-2 md:order-1">
<h2 class="text-3xl font-black text-slate-900 uppercase italic mb-4 group-hover:text-blue-600 transition-colors">{{ 'workflow.step1.title'|trans }}</h2>
<p class="text-slate-500 font-medium leading-relaxed">{{ 'workflow.step1.desc'|trans }}</p>
@@ -45,7 +45,7 @@
</div>
{# 2. DATES #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-left">
<div class="flex-1 hidden md:block"></div>
<div class="w-24 h-24 bg-amber-500 rounded-[2rem] flex items-center justify-center shadow-xl shadow-amber-200 shrink-0 transform group-hover:-rotate-12 transition-transform">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 00-2 2z" /></svg>
@@ -57,7 +57,7 @@
</div>
{# 3. DETAILS & LIVRAISON #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-right">
<div class="flex-1 text-center md:text-right order-2 md:order-1">
<h2 class="text-3xl font-black text-slate-900 uppercase italic mb-4 group-hover:text-blue-600 transition-colors">{{ 'workflow.step3.title'|trans }}</h2>
<p class="text-slate-500 font-medium leading-relaxed">
@@ -72,7 +72,7 @@
</div>
{# 4. SIGNATURE #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-left">
<div class="flex-1 hidden md:block"></div>
<div class="w-24 h-24 bg-indigo-600 rounded-[2rem] flex items-center justify-center shadow-xl shadow-indigo-200 shrink-0 transform group-hover:-rotate-12 transition-transform">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" /></svg>
@@ -84,7 +84,7 @@
</div>
{# 5. ARRHES #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-right">
<div class="flex-1 text-center md:text-right order-2 md:order-1">
<h2 class="text-3xl font-black text-slate-900 uppercase italic mb-4 group-hover:text-rose-500 transition-colors">{{ 'workflow.step5.title'|trans }}</h2>
<p class="text-slate-500 font-medium leading-relaxed">{{ 'workflow.step5.desc'|trans|raw }}</p>
@@ -96,7 +96,7 @@
</div>
{# 6 & 7. RAPPEL & CAUTION #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-left">
<div class="flex-1 hidden md:block"></div>
<div class="w-24 h-24 bg-violet-600 rounded-[2rem] flex items-center justify-center shadow-xl shadow-violet-200 shrink-0 transform group-hover:-rotate-12 transition-transform">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" /></svg>
@@ -108,7 +108,7 @@
</div>
{# 8 & 9. RECEPTION & SOLDE #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-right">
<div class="flex-1 text-center md:text-right order-2 md:order-1">
<h2 class="text-3xl font-black text-slate-900 uppercase italic mb-4 group-hover:text-emerald-500 transition-colors">{{ 'workflow.step8_9.title'|trans }}</h2>
<p class="text-slate-500 font-medium leading-relaxed">
@@ -123,7 +123,7 @@
</div>
{# 10. POST-LOCATION #}
<div class="flex flex-col md:flex-row items-center gap-12 group">
<div class="flex flex-col md:flex-row items-center gap-12 group" data-aos="fade-left">
<div class="flex-1 hidden md:block"></div>
<div class="w-24 h-24 bg-blue-900 rounded-[2rem] flex items-center justify-center shadow-xl shadow-slate-300 shrink-0 transform group-hover:rotate-12 transition-transform">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-7.714 2.143L11 21l-2.286-6.857L1 12l7.714-2.143L11 3z" /></svg>
@@ -139,7 +139,7 @@
{# --- CTA FINAL --- #}
<div class="max-w-4xl mx-auto mt-32 px-4">
<div class="bg-slate-900 rounded-[3rem] p-12 text-center relative overflow-hidden shadow-2xl">
<div class="bg-slate-900 rounded-[3rem] p-12 text-center relative overflow-hidden shadow-2xl" data-aos="zoom-in">
<div class="relative z-10">
<h3 class="text-3xl md:text-5xl font-black text-white uppercase italic mb-8">{{ 'workflow.cta.title'|trans|raw }}</h3>
<a href="{{ path('reservation_catalogue') }}" class="inline-flex items-center gap-4 bg-white text-slate-900 px-10 py-5 rounded-2xl font-black uppercase text-xs tracking-widest hover:bg-blue-600 hover:text-white transition-all transform hover:scale-105">