```
✨ feat(templates): Style Neubrutaliste, refonte complète des templates
Refactorise les templates principaux avec un style Neubrutaliste.
Ajoute des animations, des filigranes et améliore la responsivité.
Traduit en français.
```
This commit is contained in:
@@ -4,135 +4,178 @@
|
||||
{% block meta_description %}{{ 'events.description'|trans }}{% endblock %}
|
||||
|
||||
{% block canonical_url %}<link rel="canonical" href="{{ url('app_events') }}" />{% endblock %}
|
||||
|
||||
{% block breadcrumb_schema %}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "{{ 'breadcrumb.home'|trans }}",
|
||||
"item": "{{ app.request.schemeAndHttpHost }}"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "{{ 'breadcrumb.events'|trans }}",
|
||||
"item": "{{ app.request.schemeAndHttpHost }}{{ app.request.pathInfo }}"
|
||||
}
|
||||
]
|
||||
}
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "{{ 'breadcrumb.home'|trans }}",
|
||||
"item": "{{ app.request.schemeAndHttpHost }}"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "{{ 'breadcrumb.events'|trans }}",
|
||||
"item": "{{ app.request.schemeAndHttpHost }}{{ app.request.pathInfo }}"
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container mx-auto p-4 md:p-8 pt-12">
|
||||
<main class="bg-[#fbfbfb] min-h-screen font-sans text-gray-900 pb-24 overflow-x-hidden">
|
||||
|
||||
<h1 class="text-4xl font-extrabold text-gray-800 text-center mb-12">
|
||||
{{ 'events.list_main_title'|trans|default('Upcoming Events') }}
|
||||
</h1>
|
||||
{# --- HEADER HERO --- #}
|
||||
<header class="relative pt-16 pb-20 px-4 border-b-4 border-gray-900 bg-white">
|
||||
<div class="max-w-7xl mx-auto relative z-10">
|
||||
<h1 class="text-6xl md:text-8xl font-black italic uppercase tracking-tighter leading-none">
|
||||
{{ 'events.list_main_title'|trans|default('Upcoming Events') }}
|
||||
</h1>
|
||||
<div class="h-3 w-48 bg-yellow-500 skew-x-[-20deg] mt-6 shadow-[4px_4px_0px_rgba(0,0,0,1)]"></div>
|
||||
</div>
|
||||
{# Filigrane de fond style Esport #}
|
||||
<div class="absolute top-0 right-0 opacity-[0.03] pointer-events-none select-none hidden lg:block">
|
||||
<span class="text-[20rem] font-black italic uppercase leading-none">AGENDA</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container mx-auto px-4 py-16">
|
||||
|
||||
{% if events is defined and events is not empty %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
|
||||
{% for event in events %}
|
||||
<div class="bg-white rounded-xl shadow-lg border border-gray-100 flex flex-col justify-between transition duration-300 hover:shadow-xl hover:border-indigo-200 overflow-hidden">
|
||||
{% if events is defined and events is not empty %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10 max-w-7xl mx-auto">
|
||||
{% for event in events %}
|
||||
{# CARTE ÉVÉNEMENT NEUBRUTALISTE #}
|
||||
<div class="group relative bg-white border-4 border-gray-900 shadow-[12px_12px_0px_rgba(0,0,0,1)] hover:shadow-[16px_16px_0px_#4f46e5] hover:-translate-y-2 transition-all duration-300 flex flex-col overflow-hidden italic">
|
||||
|
||||
{# --- AJOUT DE L'AFFICHE (IMAGE) --- #}
|
||||
{% set imageUrl = event.eventsFileName ? vich_uploader_asset(event, 'affiche') : null %}
|
||||
|
||||
{% if imageUrl %}
|
||||
<div class="h-48 bg-gray-200 overflow-hidden">
|
||||
<img src="{{ asset(imageUrl) | imagine_filter('webp') }}"
|
||||
alt="Affiche de l'événement {{ event.title }}"
|
||||
class="w-full h-full object-cover">
|
||||
{# Badge de Date flottant (Style Esport) #}
|
||||
<div class="absolute top-4 left-4 z-20 bg-indigo-600 text-white px-4 py-1 font-black uppercase text-sm skew-x-[-15deg] shadow-lg border-2 border-gray-900">
|
||||
{{ event.startAt|date('d/m') }}
|
||||
</div>
|
||||
{% else %}
|
||||
{# Placeholder si aucune image n'est disponible #}
|
||||
<div class="h-48 flex items-center justify-center bg-gray-100 text-gray-400">
|
||||
<svg class="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 18m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
|
||||
|
||||
{# Image / Affiche #}
|
||||
<div class="relative h-64 bg-gray-200 overflow-hidden border-b-4 border-gray-900">
|
||||
{% set imageUrl = event.eventsFileName ? vich_uploader_asset(event, 'affiche') : null %}
|
||||
{% if imageUrl %}
|
||||
<img src="{{ asset(imageUrl) | imagine_filter('webp') }}"
|
||||
alt="{{ event.title }}"
|
||||
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700 grayscale group-hover:grayscale-0">
|
||||
{% else %}
|
||||
<div class="w-full h-full flex items-center justify-center bg-gray-900 text-gray-700">
|
||||
<span class="text-6xl font-black opacity-20 uppercase tracking-tighter">NO_IMAGE</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{# Overlay dégradé #}
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-gray-900/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{# --- FIN AJOUT DE L'AFFICHE --- #}
|
||||
|
||||
<div class="p-6 flex flex-col justify-between flex-grow">
|
||||
<div>
|
||||
{# Event Title #}
|
||||
<h2 class="text-2xl font-bold text-indigo-700 mb-4">{{ event.title }}</h2>
|
||||
{# Contenu #}
|
||||
<div class="p-6 flex flex-col flex-grow">
|
||||
<h2 class="text-3xl font-black uppercase tracking-tighter text-gray-900 mb-4 group-hover:text-indigo-600 transition-colors">
|
||||
{{ event.title }}
|
||||
</h2>
|
||||
|
||||
<div class="space-y-3 text-gray-600">
|
||||
|
||||
{# Date Block (Start Date / End Date) #}
|
||||
<p class="flex items-start text-sm">
|
||||
<svg class="w-4 h-4 mt-1 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>
|
||||
<div>
|
||||
<span class="font-medium text-gray-800">{{ 'events.list.date_label'|trans|default('Date') }}:</span>
|
||||
<div class="text-xs mt-0.5">
|
||||
<div class="space-y-4 mb-8">
|
||||
{# Date Detail #}
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-yellow-400 border-2 border-gray-900 flex items-center justify-center rotate-45">
|
||||
<i class="fas fa-calendar-alt -rotate-45 text-xs"></i>
|
||||
</div>
|
||||
<div class="text-sm font-bold uppercase tracking-tight">
|
||||
{{ event.startAt|date('d/m/Y H:i') }}
|
||||
{% if event.startAt|date('Ymd') != event.endAt|date('Ymd') %}
|
||||
- {{ event.endAt|date('d/m/Y H:i') }}
|
||||
{% else %}
|
||||
- {{ event.endAt|date('H:i') }}
|
||||
{% endif %}
|
||||
<span class="text-indigo-600">>></span>
|
||||
{{ event.endAt|date('H:i') }}
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
{# Location Block #}
|
||||
<p class="flex items-start text-sm">
|
||||
<svg class="w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
|
||||
<div>
|
||||
<span class="font-medium text-gray-800">{{ 'events.list.location_label'|trans|default('Location') }}:</span>
|
||||
<div class="text-xs mt-0.5">{{ event.location }}</div>
|
||||
{# Location Detail #}
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-white border-2 border-gray-900 flex items-center justify-center rotate-45 group-hover:bg-indigo-600 group-hover:text-white transition-colors">
|
||||
<i class="fas fa-map-marker-alt -rotate-45 text-xs"></i>
|
||||
</div>
|
||||
<div class="text-sm font-bold uppercase tracking-tight text-gray-600">
|
||||
{{ event.location }}
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
{# Organizer Block #}
|
||||
<p class="flex items-start text-sm">
|
||||
<svg class="w-4 h-4 mt-0.5 mr-2 flex-shrink-0 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path></svg>
|
||||
<div>
|
||||
<span class="font-medium text-gray-800">{{ 'events.list.organizer_label'|trans|default('Organizer') }}:</span>
|
||||
<div class="text-xs mt-0.5">{{ event.organizer }}</div>
|
||||
{# Organizer Detail #}
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-white border-2 border-gray-900 flex items-center justify-center rotate-45 group-hover:bg-indigo-600 group-hover:text-white transition-colors">
|
||||
<i class="fas fa-user-shield -rotate-45 text-xs"></i>
|
||||
</div>
|
||||
<div class="text-[10px] font-black uppercase text-gray-400 tracking-widest">
|
||||
{{ 'events.list.organizer_label'|trans }}: {{ event.organizer }}
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Details Link (assuming an 'id' or slug is available) #}
|
||||
<a href="{{ url('app_event_details', {id: event.id|default(loop.index)}) }}" class="mt-6 text-center w-full py-2 bg-indigo-50 hover:bg-indigo-100 text-indigo-600 font-semibold rounded-md text-sm transition duration-300 border border-indigo-100">
|
||||
{{ 'events.list.details_button'|trans|default('View Details') }}
|
||||
</a>
|
||||
{# Bouton Détails (Style Bouton Combat) #}
|
||||
<a href="{{ url('app_event_details', {id: event.id|default(loop.index)}) }}"
|
||||
class="mt-auto relative group/btn overflow-hidden border-4 border-gray-900 bg-white py-3 px-6 text-center transition-all hover:bg-gray-900">
|
||||
<span class="relative z-10 font-black uppercase italic tracking-widest text-sm group-hover/btn:text-white">
|
||||
{{ 'events.list.details_button'|trans|default('View Details') }} <span class="ml-2">→</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{# --- ÉTAT VIDE (NO EVENTS) --- #}
|
||||
<div class="max-w-4xl mx-auto text-center py-24 px-8 border-8 border-dashed border-gray-200 bg-white relative">
|
||||
<div class="absolute -top-10 left-1/2 -translate-x-1/2 bg-gray-900 text-white p-6 rotate-12 shadow-2xl">
|
||||
<svg class="w-16 h-16 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h2 class="text-5xl font-black uppercase italic tracking-tighter text-gray-900 mt-8 mb-4">
|
||||
{{ 'events.no_events_title'|trans|default('No Upcoming Events') }}
|
||||
</h2>
|
||||
<p class="text-xl font-bold text-gray-500 italic mb-12">
|
||||
{{ 'events.no_events_message'|trans|default('It looks like we don\'t have any events scheduled right now.') }}
|
||||
</p>
|
||||
|
||||
<a href="{{ url('app_contact') }}" class="inline-block relative group">
|
||||
<div class="absolute inset-0 bg-gray-900 translate-x-2 translate-y-2 group-hover:translate-x-0 group-hover:translate-y-0 transition-transform"></div>
|
||||
<div class="relative bg-indigo-600 text-white px-12 py-5 font-black uppercase italic tracking-tighter border-2 border-gray-900">
|
||||
{{ 'events.button_contact'|trans|default('Contact Us') }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{# --- BANDEAU TECHNIQUE BAS DE PAGE --- #}
|
||||
<div class="mt-20 bg-gray-900 py-6 overflow-hidden">
|
||||
<div class="whitespace-nowrap flex animate-marquee italic">
|
||||
{% for i in 1..10 %}
|
||||
<span class="text-white font-black uppercase mx-8 text-xl opacity-20 tracking-widest">
|
||||
Next Mission // New Event // Stay Tuned // Join the Community //
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{# Fallback if no events are found (repurposing the original styling) #}
|
||||
<div class="max-w-3xl mx-auto text-center py-16 md:py-24 bg-white rounded-xl shadow-lg border border-gray-100">
|
||||
</div>
|
||||
|
||||
<span class="text-6xl text-gray-400 mb-4 inline-block">
|
||||
{# Icon: Calendar with an X #}
|
||||
<svg class="lucide lucide-calendar-x" xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"/><line x1="16" x2="16" y1="2" y2="6"/><line x1="8" x2="8" y1="2" y2="6"/><line x1="3" x2="21" y1="10" y2="10"/><path d="m14.5 12.5-5 5"/><path d="m9.5 12.5 5 5"/></svg>
|
||||
</span>
|
||||
|
||||
<h2 class="text-4xl font-extrabold text-gray-800 mt-4 mb-3">
|
||||
{{ 'events.no_events_title'|trans|default('No Upcoming Events') }}
|
||||
</h2>
|
||||
|
||||
<p class="text-xl text-gray-600 mb-8">
|
||||
{{ 'events.no_events_message'|trans|default('It looks like we don\'t have any events scheduled right now. Check back soon!') }}
|
||||
</p>
|
||||
|
||||
{# Action to contact us #}
|
||||
<a href="{{ url('app_contact') }}" class="inline-flex items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 transition duration-300 shadow-md">
|
||||
{{ 'events.button_contact'|trans|default('Contact Us') }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
/* Animation du texte qui défile en bas */
|
||||
@keyframes marquee {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-50%); }
|
||||
}
|
||||
.animate-marquee {
|
||||
display: flex;
|
||||
width: 200%;
|
||||
animation: marquee 30s linear infinite;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user