Files
ludikevent_crm/templates/revervation/home.twig
Serreau Jovann 53878e467a ```
 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.
```
2026-01-30 12:34:51 +01:00

293 lines
18 KiB
Twig

{% extends 'revervation/base.twig' %}
{% block title %}Location de Châteaux Gonflables dans l'Aisne | Ludik Event{% endblock %}
{% 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 %}
{# Génère l'URL propre automatiquement pour 99% des pages #}
<link rel="canonical" href="{{ url('reservation') }}">
{% endblock %}
{% block jsonld %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "Location de Châteaux Gonflables - Ludik Event",
"description": "Découvrez notre catalogue de structures gonflables en vidéo. Ludik Event simplifie vos événements avec des structures certifiées.",
"thumbnailUrl": "{{ absolute_url(asset('provider/video/video.jpg')) }}",
"uploadDate": "2024-01-01T08:00:00+08:00",
"contentUrl": "{{ absolute_url(asset('provider/video/video.mp4')) }}",
"embedUrl": "{{ absolute_url(asset('provider/video/video.mp4')) }}",
"potentialAction": {
"@type": "SeekToAction",
"target": "{{ absolute_url(asset('provider/video/video.mp4')) }}?t={seek_to_second_number}",
"startOffset-input": "required name=seek_to_second_number"
}
}
</script>
{% endblock %}
{% block stylesheets %}
<link rel="preload" as="image" href="{{ asset('provider/video/video.jpg') | imagine_filter('poster_hero') }}" fetchpriority="high">
{% endblock %}
{# --- 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">
{% if product.imageName and product.imageName != "" %}
<img src="{{ vich_uploader_asset(product,'imageFile') | imagine_filter('product_card') }}"
alt="{{ product.name }}"
loading="lazy"
class="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-700">
{% else %}
<div class="flex flex-col items-center justify-center p-12 text-center">
<img src="{{ asset('provider/images/favicon.png') }}"
alt="Image par défaut Ludik Event"
class="w-50 h-50 object-contain opacity-20 group-hover:opacity-100 group-hover:scale-110 transition-all duration-500 grayscale group-hover:grayscale-0">
</div>
{% endif %}
{# Badge Prix flottant #}
<div class="absolute top-5 left-5 bg-white/95 backdrop-blur-md px-4 py-2 rounded-2xl shadow-sm border border-white/50">
{% if product.category == "barnums" %}
<p class="text-[9px] font-black text-gray-600 uppercase tracking-widest mb-0.5">Week-End</p>
{% else %}
<p class="text-[9px] font-black text-gray-600 uppercase tracking-widest mb-0.5">Jour</p>
{% endif %}
<p class="text-[#0782bc] font-black text-sm uppercase leading-none">
Dès {{ product.priceDay|format_currency('EUR') }}
</p>
</div>
</div>
{# Infos Produit (Correction hiérarchie h3) #}
<div class="mt-6 px-2 pb-2 flex-grow flex flex-col justify-between">
<div>
<span class="text-[10px] font-black text-[#0782bc] uppercase tracking-widest italic mb-1 block">
Réf: {{ product.ref }}
</span>
<h3 class="text-2xl font-black text-gray-900 group-hover:text-[#f39e36] transition-colors leading-tight italic uppercase">
{{ product.name }}
</h3>
</div>
<div class="mt-8">
<a href="{{ path('reservation_product_show',{id:product.slug}) }}" class="block w-full py-2 bg-[#f39e36] text-white text-center rounded-[1.5rem] font-black uppercase text-sm tracking-widest hover:bg-blue-600 transition-all shadow-xl hover:shadow-blue-200 active:scale-95">
Réserver ce bonheur
</a>
</div>
</div>
</div>
{% endmacro %}
{% 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">
{# Utilisation du champ imageName de la formule #}
{% if formule.imageName and formule.imageName != "" %}
<img src="{{ vich_uploader_asset(formule,'imageFile') | imagine_filter('product_card') }}"
alt="{{ formule.name }}"
loading="lazy"
class="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-700">
{% else %}
<div class="flex flex-col items-center justify-center p-12 text-center">
<img src="{{ asset('provider/images/favicon.png') }}"
alt="Image par défaut"
class="w-32 h-32 object-contain opacity-20 group-hover:opacity-100 transition-all duration-500 grayscale group-hover:grayscale-0">
</div>
{% endif %}
{# Badge Type de Formule (ex: PACK) #}
<div class="absolute top-5 left-5 bg-[#0782bc] text-white px-4 py-1.5 rounded-full shadow-lg border border-white/20">
<p class="text-[9px] font-black uppercase tracking-[0.2em] italic">
{% if formule.type == "free" %}
Personnalisable
{% else %}
{{ formule.type|default('Pack') }}
{% endif %}
</p>
</div>
</div>
{# Infos Formule #}
<div class="mt-6 px-2 pb-2 flex-grow flex flex-col">
<div class="mb-4">
<h3 class="text-2xl font-black text-gray-900 group-hover:text-[#f39e36] transition-colors leading-tight italic uppercase tracking-tighter">
{{ formule.name }}
</h3>
</div>
{# Section Tarifs dégressifs #}
<div class="grid grid-cols-3 gap-2 mb-6">
<div class="bg-gray-50 rounded-2xl p-2 border border-gray-100 text-center">
<p class="text-[8px] font-black text-gray-400 uppercase">1 Jour</p>
<p class="text-xs font-black text-[#0782bc]">{{ formule.price1j|format_currency('EUR') }}</p>
</div>
<div class="bg-blue-50/50 rounded-2xl p-2 border border-blue-100 text-center">
<p class="text-[8px] font-black text-gray-400 uppercase">2 Jours</p>
<p class="text-xs font-black text-[#0782bc]">{{ formule.price2j|format_currency('EUR') }}</p>
</div>
<div class="bg-emerald-50/50 rounded-2xl p-2 border border-emerald-100 text-center">
<p class="text-[8px] font-black text-gray-400 uppercase">5 Jours</p>
<p class="text-xs font-black text-emerald-600">{{ formule.price5j|format_currency('EUR') }}</p>
</div>
</div>
<div class="mt-auto">
<a href="{{ path('reservation_formule_show',{slug: formule.slug}) }}" class="block w-full py-3 bg-[#f39e36] text-white text-center rounded-[1.5rem] font-black uppercase text-sm tracking-widest hover:bg-blue-600 transition-all shadow-xl hover:shadow-blue-200 active:scale-95">
Découvrir le pack
</a>
</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>
</div>
{% endfor %}
</div>
</section>
</div>
{% endblock %}