{# # ============================================================================ # MOLECULE: MONTH RANGE FILTER # ============================================================================ # # Barre de filtre de période, au MOIS : deux listes déroulantes, un bouton # « Appliquer » et une croix ronde de réinitialisation, visible seulement sous # filtre. # # Le mois, et non le jour : les écrans qu'elle sert affichent un relevé mensuel, # où un mois recouvert même partiellement est rendu entier. Deux dates au jour # près y promettaient une précision que l'écran ne tenait pas — « du 07/07 au # 17/07 » affichait juillet en entier. # # Elle émet `du` et `au` au format « YYYY-MM » — App\Service\Commercial\DateRange # les lit comme le premier et le dernier jour du mois. Aucune connaissance du # domaine : la molécule ne sait pas ce qu'elle filtre. # # Rien n'est rendu quand `months` est vide : un filtre sans choix est du bruit. # # ============================================================================ # COMPOSITION (Atomes utilisés) # ============================================================================ # # - button (« Appliquer », et la croix de réinitialisation) # # ============================================================================ # PARAMÈTRES # ============================================================================ # # | Paramètre | Type | Défaut | Description | # |-----------|--------|--------|-----------------------------------------------| # | action | string | '#' | URL du formulaire GET | # | months | array | [] | Mois proposés, clés « YYYY-MM », du plus | # | | | | récent au plus ancien | # | start | string | '' | Mois de début sélectionné, « YYYY-MM » | # | end | string | '' | Mois de fin sélectionné, « YYYY-MM » | # | idPrefix | string | '' | Préfixe des `id`/`for` des champs. À fournir | # | | | | si la molécule apparaît plusieurs fois sur une | # | | | | même page (les `id` par défaut sont fixes et | # | | | | se dupliqueraient sinon, cassant les `label`). | # | class | string | '' | Classes additionnelles | # # ============================================================================ # EXEMPLES D'UTILISATION # ============================================================================ # # {% include '_molecules/month-range-filter/month-range-filter.html.twig' with { # action: path('app_commercial_paiements'), # months: moisDisponibles, # start: range.startMonthInput(), end: range.endMonthInput() # } only %} # # ============================================================================ #} {# ============================================================================ CONFIGURATION DES VALEURS PAR DÉFAUT ============================================================================ #} {% set action = action ?? '#' %} {% set months = months ?? [] %} {% set start = start ?? '' %} {% set end = end ?? '' %} {% set idPrefix = idPrefix ?? '' %} {% set class = class ?? '' %} {% set isActive = start != '' and end != '' %} {# ============================================================================ RENDU HTML ============================================================================ #} {% if months is not empty %} {# Pas de carte : la barre se pose directement sur le fond de page et s'aligne à droite, là où on va la chercher. Les deux listes partagent UN seul cadre — c'est une période, pas deux mois indépendants. #} {# `border-0 rounded-none p-0 w-auto` : app.css stylise TOUT `select` en champ de formulaire — fond blanc, bordure, arrondi, largeur pleine. Sans ces classes, chaque liste porte son propre cadre À L'INTÉRIEUR du cadre partagé. #} {% set selectClass = 'appearance-none bg-transparent border-0 rounded-none p-0 w-auto shadow-none focus:ring-0' ~ ' pr-5 text-sm font-medium text-gray-700 cursor-pointer focus:outline-none' ~ ' bg-[url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' fill=\'none\' viewBox=\'0 0 20 20\'%3E%3Cpath stroke=\'%239ca3af\' stroke-linecap=\'round\' stroke-width=\'1.5\' d=\'m6 8 4 4 4-4\'/%3E%3C/svg%3E")]' ~ ' bg-[length:1.1rem_1.1rem] bg-[right_center] bg-no-repeat' %} {# Le formulaire ne part PAS au changement d'une liste : on règle les deux bornes, puis on applique. Partir au premier `change` rechargeait la page avant qu'on ait pu toucher au mois de fin — toute période de plusieurs mois en devenait impossible à composer. #}
{# Rendu ACTIF : sans JavaScript il reste utilisable tel quel. C'est le contrôleur qui le grise tant que la sélection n'a pas bougé. #} {% include '_atoms/button/button.html.twig' with { label: 'Appliquer', variant: 'primary', size: 'md', type: 'submit', class: 'h-10 transition-opacity', attr: { 'data-shared--month-range-target': 'apply' } } only %} {# Une croix ronde, à la hauteur d'« Appliquer » : le texte « Tout voir » mettait un troisième libellé sur la barre alors que la croix dit déjà tout. Sans libellé visible, le nom accessible passe par aria-label — une icône seule n'annonce rien à un lecteur d'écran. #} {% if isActive %} {% include '_atoms/button/button.html.twig' with { variant: 'soft-primary', size: 'md', radius: 'full', icon: 'close', iconOnly: true, href: action, class: 'h-10 w-10', attr: { 'aria-label': 'Tout voir', 'title': 'Tout voir' } } only %} {% endif %}
{% endif %}