{% extends 'base.html.twig' %} {% block title %}{{ is_edit ? 'Modifier' : 'Nouvelle' }} annonce - Admin{% endblock %} {% set inputClass = 'w-full px-4 py-3 border-2 border-gray-200 rounded-xl focus:ring-2 focus:ring-primary/20 focus:border-primary transition-all bg-gray-50 focus:bg-white' %} {% set labelClass = 'block text-sm font-medium text-gray-700 mb-2' %} {% set helpClass = 'mt-1.5 text-xs text-gray-400' %} {% set scope = 'admin--announcement-preview' %} {% block body %}
{# Header #}
{% include '_molecules/page-header/page-header.html.twig' with { title: is_edit ? 'Modifier « ' ~ announcement.title ~ ' »' : 'Nouvelle annonce', icon: is_edit ? 'edit' : 'plus', backHref: path('admin_announcement_list'), backLabel: 'Retour aux annonces' } only %}
{{ form_start(form, {'attr': {'class': 'space-y-6', 'data-turbo': 'false'}}) }} {# ── Contenu ── #}
{% include '_atoms/icon/icon.html.twig' with { name: 'document', size: 'md', color: 'primary' } only %}

Contenu

Ce que la personne lit dans la modale

{{ form_label(form.badge, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.badge, {'attr': { 'class': inputClass ~ ' uppercase', ('data-' ~ scope ~ '-target'): 'badgeInput', 'data-action': scope ~ '#refresh' }}) }}

{{ form.badge.vars.help }}

{{ form_errors(form.badge) }}
{{ form_label(form.title, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.title, {'attr': { 'class': inputClass, ('data-' ~ scope ~ '-target'): 'titleInput', 'data-action': scope ~ '#refresh' }}) }} {{ form_errors(form.title) }}
{{ form_label(form.body, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.body, {'attr': { 'class': inputClass ~ ' resize-none', ('data-' ~ scope ~ '-target'): 'bodyInput', 'data-action': scope ~ '#refresh' }}) }}

{{ form.body.vars.help }}

{{ form_errors(form.body) }}
{{ form_label(form.bullets, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.bullets, {'attr': { 'class': inputClass ~ ' resize-none', ('data-' ~ scope ~ '-target'): 'bulletsInput', 'data-action': scope ~ '#refresh' }}) }}

{{ form.bullets.vars.help }}

{{ form_errors(form.bullets) }}
{# ── Illustration ── #}
{% include '_atoms/icon/icon.html.twig' with { name: 'palette-2', size: 'md', color: 'primary' } only %}

Illustration

Affichée à droite du texte, au-dessus sur mobile

{{ form_label(form.imageFile, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.imageFile, {'attr': { 'class': 'w-full text-sm text-gray-600 file:mr-4 file:py-2.5 file:px-4 file:rounded-xl file:border-0 file:text-sm file:font-semibold file:bg-primary/10 file:text-primary hover:file:bg-primary/20 file:cursor-pointer cursor-pointer', ('data-' ~ scope ~ '-target'): 'imageInput', 'data-action': scope ~ '#refresh', 'accept': 'image/jpeg,image/png,image/gif,image/webp' }}) }}

{{ form.imageFile.vars.help }}

{{ form_errors(form.imageFile) }}
{{ form_label(form.imageAlt, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.imageAlt, {'attr': { 'class': inputClass, ('data-' ~ scope ~ '-target'): 'imageAltInput', 'data-action': scope ~ '#refresh' }}) }}

{{ form.imageAlt.vars.help }}

{# Direction artistique commune aux illustrations. Elle est ici, à l'endroit et au moment où l'on cherche une image, plutôt que dans une documentation qu'il faudrait penser à rouvrir. #}

Prompt de génération

{{ image_style_prompt }}

Collez-le chez OpenAI, puis ajoutez votre sujet à la suite.

Image actuelle

{% if announcement.imagePath %} {{ announcement.imageAlt }} {% else %}

Aucune image — le texte occupera toute la modale

{% endif %}
{# ── Bouton ── #}
{% include '_atoms/icon/icon.html.twig' with { name: 'arrow-right', size: 'md', color: 'primary' } only %}

Bouton

Optionnel — sans lui, seul « Fermer » est proposé

{{ form_label(form.ctaLabel, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.ctaLabel, {'attr': { 'class': inputClass, ('data-' ~ scope ~ '-target'): 'ctaLabelInput', 'data-action': scope ~ '#refresh' }}) }}

{{ form.ctaLabel.vars.help }}

{{ form_label(form.ctaUrl, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.ctaUrl, {'attr': { 'class': inputClass ~ ' font-mono text-sm', ('data-' ~ scope ~ '-target'): 'ctaUrlInput', 'data-action': scope ~ '#refresh' }}) }}

{{ form.ctaUrl.vars.help }}

{# ── Fenêtre d'affichage ── #}
{% include '_atoms/icon/icon.html.twig' with { name: 'calendar', size: 'md', color: 'primary' } only %}

Fenêtre d'affichage

La publication se fait depuis la liste, une annonce à la fois

{{ form_label(form.startsAt, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.startsAt, {'attr': {'class': inputClass}}) }} {{ form_errors(form.startsAt) }}
{{ form_label(form.endsAt, null, {'label_attr': {'class': labelClass}}) }} {{ form_widget(form.endsAt, {'attr': {'class': inputClass}}) }}

{{ form.endsAt.vars.help }}

{{ form_errors(form.endsAt) }}
{# Actions #}
{% include '_atoms/button/button.html.twig' with { label: 'Annuler', variant: 'ghost', size: 'lg', icon: 'arrow-left', href: path('admin_announcement_list') } only %}
{% include '_atoms/button/button.html.twig' with { label: 'Prévisualiser', variant: 'secondary', size: 'lg', icon: 'eye', type: 'button', attr: { 'data-action': scope ~ '#open' } } only %} {% include '_atoms/button/button.html.twig' with { label: is_edit ? 'Enregistrer' : 'Créer l\'annonce', variant: 'primary', size: 'lg', icon: 'check', type: 'submit' } only %}
{{ form_end(form) }} {# Comportement des boutons [data-copy] — mutualisé avec l'espace commercial. #} {% include 'admin/commercial/_copy-script.html.twig' %} {# Prévisualisation — le vrai gabarit de la modale, rempli à la volée par le contrôleur depuis les champs ci-dessus. Aucune mise en forme n'est réécrite en JavaScript : ce qui s'affiche ici est ce que verront les utilisateurs. #} {% include '_organisms/announcement-modal/announcement-modal.html.twig' with { badge: announcement.badge, title: announcement.title, body: announcement.body, bullets: announcement.bullets, imagePath: announcement.imagePath, imageAlt: announcement.imageAlt, ctaLabel: announcement.ctaLabel, ctaUrl: announcement.safeCtaUrl, targetScope: scope, previewBulletSlots: max_bullets, modalAttr: { ('data-' ~ scope ~ '-target'): 'modal' }, closeAttr: { 'data-action': scope ~ '#close' }, ctaAttr: { 'data-action': scope ~ '#preventNavigation' } } only %}
{% endblock %}