Files
ludikevent_crm/templates/revervation/produit.twig
Serreau Jovann 492fd1b7e8 feat(Product): Ajoute la génération de slug pour les produits.
🐛 fix(ReserverController): Corrige la route de la sitemap.
♻️ refactor(SiteMapListener): Génère les URLs des produits dans la sitemap.
🔧 chore(ansible): Ajoute le dossier seo aux dossiers à sauvegarder.
2026-01-20 14:31:12 +01:00

172 lines
10 KiB
Twig

{% extends 'revervation/base.twig' %}
{% block title %}{{ product.name }} - Location Ludikevent{% endblock %}
{% block breadcrumb_json %}
,{
"@type": "ListItem",
"position": 1,
"name": "Catalogue",
"item": "{{ path('reservation_catalogue') }}"
},{
"@type": "ListItem",
"position": 2
"name": "Catalogue",
"item": "{{ path('reservation_product_show',{id:product.id}) }}"
}
{% endblock %}
{% block body %}
<div class="min-h-screen bg-white font-sans antialiased">
{# --- 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">
<a href="{{ url('reservation') }}" class="text-slate-400 hover:text-blue-600 transition">ACCUEIL</a>
<span class="text-slate-300">/</span>
<a href="{{ url('reservation_catalogue') }}" class="text-slate-400 hover:text-blue-600 transition">Catalogue</a>
<span class="text-slate-300">/</span>
<span class="text-amber-500 underline decoration-2 underline-offset-4">{{ product.name }}</span>
</nav>
</div>
{# --- FIL D'ARIANE / RETOUR --- #}
<div class="max-w-7xl mx-auto px-4 pt-8">
<a href="{{ path('reservation_catalogue') }}" class="group inline-flex items-center gap-3 text-[10px] font-black uppercase tracking-[0.2em] text-slate-400 hover:text-blue-600 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 transform group-hover:-translate-x-2 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Retour au catalogue
</a>
</div>
<main class="max-w-7xl mx-auto px-4 py-12 md:py-20">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-16 md:gap-24 items-start">
{# --- COLONNE GAUCHE : IMAGE --- #}
<div class="sticky top-24">
<div class="relative overflow-hidden rounded-[4rem] bg-slate-50 aspect-[4/5] shadow-2xl">
{% if product.imageName %}
<img src="{{ vich_uploader_asset(product,'imageFile') | imagine_filter('webp') }}"
alt="{{ product.name }}"
class="w-full h-full object-cover">
{% else %}
{# FALLBACK : Image par défaut si vide #}
<div class="h-full flex flex-col items-center justify-center p-12 text-center">
<img src="{{ asset('provider/images/favicon.png') }}"
alt="Ludik Event"
class="w-75 h-75 object-contain opacity-50 group-hover:opacity-100 group-hover:scale-110 transition-all duration-500 grayscale group-hover:grayscale-0">
</div>
{% endif %}
{# Badge catégorie flottant #}
<div class="absolute top-8 left-8">
<span class="bg-blue-600 text-white px-6 py-2 rounded-2xl text-[10px] font-black uppercase tracking-widest shadow-xl">
{{ product.category }}
</span>
</div>
</div>
</div>
{# --- COLONNE DROITE : INFOS --- #}
<div class="flex flex-col h-full py-4">
<div class="mb-10">
<span class="text-[12px] font-black text-slate-300 uppercase tracking-[0.4em] mb-4 block italic">
Référence : {{ product.ref }}
</span>
<h1 class="text-6xl md:text-8xl font-black text-slate-900 uppercase italic tracking-tighter leading-[0.85] mb-8">
{{ product.name }}
</h1>
<div class="flex items-baseline gap-4">
<span class="text-5xl font-black text-blue-600 italic">{{ product.priceDay }}€</span>
<span class="text-sm font-bold text-slate-400 uppercase tracking-widest italic">TTC / Journée</span>
</div>
</div>
{# --- DESCRIPTION / CARACTERISTIQUES --- #}
<div class="border-t border-slate-100 pt-10 mb-12">
<p class="text-xl text-slate-600 leading-relaxed italic font-medium">
Louez ce produit pour vos événements. Qualité professionnelle, sécurité certifiée et plaisir garanti.
</p>
<div class="grid grid-cols-2 gap-6 mt-10">
<div class="bg-slate-50 p-6 rounded-[2rem] border border-slate-100">
<span class="block text-[9px] font-black text-slate-400 uppercase tracking-widest mb-1">Âge conseillé</span>
<span class="text-lg font-black text-slate-900 uppercase italic">{{ product.category }}</span>
</div>
<div class="bg-slate-50 p-6 rounded-[2rem] border border-slate-100">
<span class="block text-[9px] font-black text-slate-400 uppercase tracking-widest mb-1">Disponibilité</span>
<span class="text-lg font-black text-emerald-500 uppercase italic">En stock ⚡</span>
</div>
</div>
</div>
{# --- ACTION --- #}
<div class="mt-auto">
<a href="{{ path('reservation_contact', {id: product.id}) }}"
class="flex items-center justify-center w-full py-8 bg-slate-900 text-white rounded-[2.5rem] font-black uppercase text-[12px] tracking-[0.3em] hover:bg-blue-600 transition-all shadow-2xl hover:scale-[1.02] active:scale-95">
Réserver maintenant
</a>
<p class="text-center mt-6 text-[9px] font-black text-slate-300 uppercase tracking-widest italic">
Réponse rapide sous 24h • Ludikevent
</p>
</div>
</div>
</div>
</main>
{# --- SECTION SUGGESTIONS DISCRETE --- #}
{# --- SECTION SUGGESTIONS --- #}
<section class="max-w-7xl mx-auto px-4 py-20 border-t border-slate-100">
<div class="flex items-end justify-between mb-12">
<div>
<span class="text-[10px] font-black text-blue-600 uppercase tracking-[0.3em] mb-2 block italic">Vous pourriez aussi aimer</span>
<h2 class="text-4xl md:text-5xl font-black text-slate-900 uppercase italic tracking-tighter leading-none">D'autres <span class="text-blue-600">idées ?</span></h2>
</div>
<a href="{{ path('reservation_catalogue') }}" class="hidden md:block text-[10px] font-black uppercase tracking-widest border-b-2 border-blue-600 pb-1 hover:text-blue-600 transition-colors">
Voir tout le catalogue
</a>
</div>
{# Grille de suggestions (on réutilise le style épuré) #}
<div class="grid grid-cols-2 md:grid-cols-4 gap-8">
{% for other in otherProducts %}
<div class="group transition-all duration-500">
<a href="{{ path('reservation_product_show', {id: other.id}) }}" class="block">
{# Image miniature #}
<div class="relative overflow-hidden rounded-[2.5rem] bg-slate-50 aspect-square mb-4 shadow-sm group-hover:shadow-xl transition-all duration-700">
{% if other.imageName %}
<img src="{{ vich_uploader_asset(other,'imageFile') | imagine_filter('webp') }}"
alt="{{ other.name }}"
class="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-1000">
{% else %}
<img src="{{ asset('provider/images/favicon.png') | imagine_filter('webp') }}"
alt="{{ product.name }}"
class="w-full h-full object-cover opacity-50 transform group-hover:scale-110 transition-transform duration-1000">
{% endif %}
<div class="absolute top-3 right-3 bg-white/90 backdrop-blur-md px-3 py-1 rounded-xl shadow-sm">
<p class="text-slate-900 font-black text-[11px] italic leading-none">{{ other.priceDay }}€</p>
</div>
</div>
{# Infos miniatures #}
<div class="px-2">
<span class="text-[8px] font-black text-slate-300 uppercase tracking-widest mb-1 block italic">{{ other.category }}</span>
<h3 class="text-sm font-black text-slate-900 uppercase italic tracking-tighter leading-tight group-hover:text-blue-600 transition-colors line-clamp-1">
{{ other.name }}
</h3>
</div>
</a>
</div>
{% else %}
{# Cas où il n'y a pas d'autres produits à suggérer #}
<p class="col-span-full text-slate-400 italic text-sm">Plus de surprises arrivent bientôt...</p>
{% endfor %}
</div>
</section>
</div>
{% endblock %}