```
✨ feat(form/join): Améliore le formulaire de candidature avec Tailwind et style neubrutaliste.
```
This commit is contained in:
@@ -24,3 +24,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#join_role {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class JoinController extends AbstractController
|
|||||||
'E-Cosplay',
|
'E-Cosplay',
|
||||||
'[E-Cosplay] - Nouvelle candidature',
|
'[E-Cosplay] - Nouvelle candidature',
|
||||||
'mails/candidat/new.twig',
|
'mails/candidat/new.twig',
|
||||||
['joint'=>$j],
|
['join'=>$j],
|
||||||
[new DataPart($content,'candidat.pdf','application/pdf')]
|
[new DataPart($content,'candidat.pdf','application/pdf')]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ class JoinController extends AbstractController
|
|||||||
$j->getSurname()." ".$j->getName(),
|
$j->getSurname()." ".$j->getName(),
|
||||||
"[E-Cosplay] - Confirmation de votre candidature",
|
"[E-Cosplay] - Confirmation de votre candidature",
|
||||||
'mails/candidat/confirm.twig',
|
'mails/candidat/confirm.twig',
|
||||||
['joint'=>$j],
|
['join'=>$j],
|
||||||
[new DataPart($content,'candidat.pdf','application/pdf')]
|
[new DataPart($content,'candidat.pdf','application/pdf')]
|
||||||
);
|
);
|
||||||
return $this->redirectToRoute('app_recruit_confirmed');
|
return $this->redirectToRoute('app_recruit_confirmed');
|
||||||
|
|||||||
@@ -9,22 +9,27 @@
|
|||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
|
|
||||||
{# ---------- ROW ---------- #}
|
{# ---------- ROW ---------- #}
|
||||||
|
{# ---------- ROW : Version Esport / Neubrutaliste ---------- #}
|
||||||
{% block form_row %}
|
{% block form_row %}
|
||||||
<div class="mb-5">
|
<div class="flex flex-col mb-6 last:mb-0 w-full">
|
||||||
{{ form_label(form) }}
|
{# Label avec style forcé #}
|
||||||
<div class="mt-1">
|
{{ form_label(form, null, {
|
||||||
|
'label_attr': {'class': 'font-black uppercase italic text-xs tracking-widest text-gray-900 mb-2'}
|
||||||
|
}) }}
|
||||||
|
|
||||||
|
{# Widget (Input, Select, etc.) #}
|
||||||
|
<div class="relative w-full">
|
||||||
{{ form_widget(form) }}
|
{{ form_widget(form) }}
|
||||||
</div>
|
</div>
|
||||||
{% if not compound and not form.vars.valid %}
|
|
||||||
{# Affiche l'erreur en bas du champ simple #}
|
{# Erreurs de validation #}
|
||||||
<p class="text-sm text-red-600 mt-1">{{ form_errors(form) }}</p>
|
{% if not form.vars.valid %}
|
||||||
{% else %}
|
<div class="mt-2 self-start bg-red-500 text-white font-black italic uppercase text-[10px] px-2 py-1 border-2 border-black shadow-[3px_3px_0px_#000]">
|
||||||
{# Affiche l'erreur pour les champs composés (si form_errors n'est pas déjà dans le widget) #}
|
{{ form_errors(form) }}
|
||||||
{{ form_errors(form) }}
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{# ---------- LABEL ---------- #}
|
{# ---------- LABEL ---------- #}
|
||||||
{% block form_label %}
|
{% block form_label %}
|
||||||
|
|
||||||
@@ -78,47 +83,28 @@
|
|||||||
class="form-textarea form-input mt-1 block w-full px-3 py-2 bg-white border border-gray-300 text-gray-900 placeholder-gray-400 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm transition duration-150"
|
class="form-textarea form-input mt-1 block w-full px-3 py-2 bg-white border border-gray-300 text-gray-900 placeholder-gray-400 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm transition duration-150"
|
||||||
>{{ value }}</textarea>
|
>{{ value }}</textarea>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{# ---------- CHECKBOX : Alignée en ligne ---------- #}
|
||||||
{# ---------- SELECT ---------- #}
|
|
||||||
{% block choice_widget_collapsed %}
|
|
||||||
<select
|
|
||||||
{{ block('widget_attributes') }}
|
|
||||||
class="form-select form-input mt-1 block w-full px-3 py-2 bg-white border border-gray-300 text-gray-900 placeholder-gray-400 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm transition duration-150"
|
|
||||||
>
|
|
||||||
{% if placeholder is not none %}
|
|
||||||
<option value="" {% if required and value is empty %}selected{% endif %}>
|
|
||||||
{{ placeholder != '' ? (placeholder|trans({}, translation_domain)) : '' }}
|
|
||||||
</option>
|
|
||||||
{% endif %}
|
|
||||||
{% for group_label, choice in choices %}
|
|
||||||
{% if choice is iterable %}
|
|
||||||
<optgroup label="{{ group_label|trans({}, translation_domain) }}">
|
|
||||||
{% for nested_choice in choice %}
|
|
||||||
<option value="{{ nested_choice.value }}" {% if nested_choice is selectedchoice(value) %}selected{% endif %}>
|
|
||||||
{{ nested_choice.label|trans({}, translation_domain) }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</optgroup>
|
|
||||||
{% else %}
|
|
||||||
<option value="{{ choice.value }}" {% if choice is selectedchoice(value) %}selected{% endif %}>
|
|
||||||
{{ choice.label|trans({}, translation_domain) }}
|
|
||||||
</option>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{# ---------- CHECKBOX ---------- #}
|
|
||||||
{% block checkbox_widget %}
|
{% block checkbox_widget %}
|
||||||
<div class="flex items-center">
|
<label class="flex items-center group cursor-pointer select-none w-full">
|
||||||
<input type="checkbox"
|
<input type="checkbox" value="{{ value }}" {{ block('widget_attributes') }} {% if checked %}checked="checked"{% endif %} class="peer hidden">
|
||||||
{{ block('widget_attributes') }}
|
|
||||||
{% if value not in ['', null] %} value="{{ value }}"{% endif %}
|
{# Le carré de la checkbox #}
|
||||||
{% if checked %}checked="checked"{% endif %}
|
<div class="flex-shrink-0 w-6 h-6 bg-white border-[3px] border-black shadow-[3px_3px_0px_#000] peer-checked:bg-green-400 peer-checked:shadow-none peer-checked:translate-x-[2px] peer-checked:translate-y-[2px] transition-all flex items-center justify-center">
|
||||||
class="form-checkbox h-5 w-5 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500">
|
<svg class="w-4 h-4 text-black opacity-0 peer-checked:opacity-100 transition-opacity" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
</div>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="4" d="M5 13l4 4L19 7"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Le texte à côté #}
|
||||||
|
{% if label is defined and label is not same as(false) %}
|
||||||
|
<span class="ml-3 font-black uppercase italic text-xs tracking-tight text-gray-900 leading-none">
|
||||||
|
{{ label|trans }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</label>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{# ---------- RADIO ---------- #}
|
{# ---------- RADIO ---------- #}
|
||||||
{% block radio_widget %}
|
{% block radio_widget %}
|
||||||
<input type="radio"
|
<input type="radio"
|
||||||
@@ -139,3 +125,15 @@
|
|||||||
hover:file:bg-indigo-700
|
hover:file:bg-indigo-700
|
||||||
bg-white border border-gray-300 rounded-md shadow-sm">
|
bg-white border border-gray-300 rounded-md shadow-sm">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block choice_widget_expanded %}
|
||||||
|
<div {{ block('widget_container_attributes') }} class="flex flex-col gap-3 mt-2">
|
||||||
|
{% for child in form %}
|
||||||
|
<div class="flex items-center">
|
||||||
|
{{ form_widget(child) }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@@ -221,11 +221,23 @@
|
|||||||
<div class="p-6 bg-gray-100 border-4 border-black border-dashed">
|
<div class="p-6 bg-gray-100 border-4 border-black border-dashed">
|
||||||
<h3 class="font-black uppercase italic mb-4 text-[#E63946]">{{ 'form.section.social'|trans }}</h3>
|
<h3 class="font-black uppercase italic mb-4 text-[#E63946]">{{ 'form.section.social'|trans }}</h3>
|
||||||
<div class="grid md:grid-cols-2 gap-4">
|
<div class="grid md:grid-cols-2 gap-4">
|
||||||
{{ form_row(form.discordAccount, {'label': 'form.label.discord'|trans, 'attr': {'class': 'border-2 border-black p-2 w-full font-bold'}}) }}
|
<div class="flex flex-col">
|
||||||
{{ form_row(form.instaLink, {'label': 'form.label.insta'|trans, 'attr': {'class': 'border-2 border-black p-2 w-full font-bold'}}) }}
|
{{ form_label(form.discordAccount, 'form.label.discord'|trans, {'label_attr': {'class': 'font-black uppercase text-sm mb-2'}}) }}
|
||||||
{{ form_row(form.tiktokLink, {'label': 'form.label.tiktok'|trans, 'attr': {'class': 'border-2 border-black p-2 w-full font-bold'}}) }}
|
{{ form_widget(form.discordAccount, {'attr': {'class': 'border-4 border-black p-3'}}) }}
|
||||||
{{ form_row(form.facebookLink, {'label': 'form.label.facebook'|trans, 'attr': {'class': 'border-2 border-black p-2 w-full font-bold'}}) }}
|
</div>
|
||||||
</div>
|
<div class="flex flex-col">
|
||||||
|
{{ form_label(form.instaLink, 'form.label.insta'|trans, {'label_attr': {'class': 'font-black uppercase text-sm mb-2'}}) }}
|
||||||
|
{{ form_widget(form.instaLink, {'attr': {'class': 'border-4 border-black p-3'}}) }}
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{{ form_label(form.tiktokLink, 'form.label.tiktok'|trans, {'label_attr': {'class': 'font-black uppercase text-sm mb-2'}}) }}
|
||||||
|
{{ form_widget(form.tiktokLink, {'attr': {'class': 'border-4 border-black p-3'}}) }}
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{{ form_label(form.facebookLink, 'form.label.facebook'|trans, {'label_attr': {'class': 'font-black uppercase text-sm mb-2'}}) }}
|
||||||
|
{{ form_widget(form.facebookLink, {'attr': {'class': 'border-4 border-black p-3'}}) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# RÔLE & MOTIVATION #}
|
{# RÔLE & MOTIVATION #}
|
||||||
@@ -234,11 +246,9 @@
|
|||||||
{{ form_widget(form.who, {'attr': {'class': 'border-4 border-black p-3 min-h-[120px]'}}) }}
|
{{ form_widget(form.who, {'attr': {'class': 'border-4 border-black p-3 min-h-[120px]'}}) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
{# Remplace tout ton bloc manuel par cette ligne unique #}
|
||||||
{{ form_label(form.role, 'form.label.role'|trans, {'label_attr': {'class': 'font-black uppercase text-sm mb-2'}}) }}
|
<div class="neubrutal-container">
|
||||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-2">
|
{{ form_row(form.role) }}
|
||||||
{{ form_widget(form.role) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# BOUTON ENVOI #}
|
{# BOUTON ENVOI #}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
BONJOUR {{ join.name|upper }},
|
BONJOUR {{ datas.join.name|upper }},
|
||||||
|
|
||||||
C'est confirmé ! Nous avons bien reçu ta candidature pour rejoindre l'association E-Cosplay.
|
C'est confirmé ! Nous avons bien reçu ta candidature pour rejoindre l'association E-Cosplay.
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
LA SUITE DES ÉVÉNEMENTS :
|
LA SUITE DES ÉVÉNEMENTS :
|
||||||
-------------------------
|
-------------------------
|
||||||
Nous reviendrons vers toi sous peu (généralement sous quelques jours) pour te donner une réponse ou convenir d'un petit échange, soit par email, soit directement sur Discord ({{ join.discordAccount|default('via le compte fourni') }}).
|
Nous reviendrons vers toi sous peu (généralement sous quelques jours) pour te donner une réponse ou convenir d'un petit échange, soit par email, soit directement sur Discord ({{ datas.join.discordAccount|default('via le compte fourni') }}).
|
||||||
|
|
||||||
À très bientôt,
|
À très bientôt,
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% extends 'mails/base.twig' %}
|
{% extends 'mails/base.twig' %}
|
||||||
|
|
||||||
{% block subject %}
|
{% block subject %}
|
||||||
[NOUVELLE CANDIDATURE] - {{ join.pseudo|default(join.surname|upper) }} ({{ join.civ|upper }})
|
[NOUVELLE CANDIDATURE] - {{ datas.join.pseudo|default(join.surname|upper) }} ({{ datas.join.civ|upper }})
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -15,27 +15,27 @@
|
|||||||
|
|
||||||
IDENTITÉ COSPLAY :
|
IDENTITÉ COSPLAY :
|
||||||
------------------
|
------------------
|
||||||
- Pseudo / Scène : {{ join.pseudo|default('Non renseigné') }}
|
- Pseudo / Scène : {{ datas.join.pseudo|default('Non renseigné') }}
|
||||||
- Nom Complet : ({{ join.civ|upper }}) {{ join.surname|upper }} {{ join.name }}
|
- Nom Complet : ({{ datas.join.civ|upper }}) {{ datas.join.surname|upper }} {{ datas.join.name }}
|
||||||
- Identité : {{ join.crossCosplay|upper }} (Cross) | {{ join.trans|upper }} (Trans)
|
- Identité : {{ datas.join.crossCosplay|upper }} (Cross) | {{ datas.join.trans|upper }} (Trans)
|
||||||
|
|
||||||
DÉTAILS DU CANDIDAT :
|
DÉTAILS DU CANDIDAT :
|
||||||
---------------------
|
---------------------
|
||||||
- Email : {{ join.email }}
|
- Email : {{ datas.join.email }}
|
||||||
- Téléphone : {{ join.phone }}
|
- Téléphone : {{ datas.join.phone }}
|
||||||
- Rôles souhaités : {% if join.role is iterable %}{{ join.role|join(', ') }}{% else %}{{ join.role }}{% endif %}
|
- Rôles souhaités : {% if datas.join.role is iterable %}{{ datas.join.role|join(', ') }}{% else %}{{ datas.join.role }}{% endif %}
|
||||||
- Date de dépôt : {{ join.createAt|date('d/m/Y à H:i') }}
|
- Date de dépôt : {{ datas.join.createAt|date('d/m/Y à H:i') }}
|
||||||
|
|
||||||
PRÉSENTATION :
|
PRÉSENTATION :
|
||||||
--------------
|
--------------
|
||||||
{{ join.who|default('Aucune présentation fournie.') }}
|
{{ datas.join.who|default('Aucune présentation fournie.') }}
|
||||||
|
|
||||||
COORDONNÉES NUMÉRIQUES :
|
COORDONNÉES NUMÉRIQUES :
|
||||||
------------------------
|
------------------------
|
||||||
- Discord : {{ join.discordAccount|default('Non renseigné') }}
|
- Discord : {{ datas.join.discordAccount|default('Non renseigné') }}
|
||||||
- Instagram : {{ join.instaLink|default('N/A') }}
|
- Instagram : {{ datas.join.instaLink|default('N/A') }}
|
||||||
- TikTok : {{ join.tiktokLink|default('N/A') }}
|
- TikTok : {{ datas.join.tiktokLink|default('N/A') }}
|
||||||
- Facebook : {{ join.facebookLink|default('N/A') }}
|
- Facebook : {{ datas.join.facebookLink|default('N/A') }}
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
Note : Le dossier complet avec le calcul de l'âge est
|
Note : Le dossier complet avec le calcul de l'âge est
|
||||||
|
|||||||
Reference in New Issue
Block a user