COMPOSANTS

Sidebar filtres

Structure de la sidebar filtres

La sidebar filtres accompagne toujours une liste ou une grille. Une seule structure — .filter-panel — pour toutes les apps : sidebar fixe (w-64) sur desktop, tiroir off-canvas déclenché par le bouton Filtres sur mobile. Le comportement est 100% CSS (case à cocher .filter-toggle), aucun JS à synchroniser d'une app à l'autre.

<div class="flex flex-col md:flex-row gap-6 items-start">
  <input type="checkbox" id="filters" class="filter-toggle">
  <label for="filters" class="filter-open btn btn-secondary btn-sm">Filtres</label>
  <label for="filters" class="filter-scrim"></label>

  <aside class="filter-panel">
    <label for="filters" class="filter-close" aria-label="Fermer">&times;</label>

    <!-- Section: Fournisseur -->
    <div class="mb-5">
      <h3 class="text-xs font-accent font-bold text-base-content/40 uppercase tracking-wider mb-2">
        Fournisseur
      </h3>
      <div class="space-y-1">
        <label class="flex items-center gap-2 cursor-pointer text-sm hover:text-mc-navy">
          <input type="checkbox" class="checkbox checkbox-primary checkbox-xs">
          <span class="flex-1 truncate">Stanley/Stella</span>
          <span class="badge badge-neutral">284</span>   <!-- compteur = badge-neutral, jamais badge-draft (un statut) -->
        </label>
      </div>
    </div>

    <!-- Actions -->
    <div class="flex gap-2">
      <button class="btn btn-primary btn-sm flex-1">Filtrer</button>
      <a href="#" class="btn btn-ghost btn-sm">Effacer</a>
    </div>
  </aside>

  <main class="flex-1 min-w-0"><!-- grille / liste --></main>
</div>

Filtre par plage (min / max)

Pour les valeurs numériques continues (quantité, prix). Deux champs côte à côte reliés par un séparateur visuel.

Quantité minimum

à
<div class="mb-5">
  <h3 class="text-xs font-accent font-bold text-base-content/40 uppercase tracking-wider mb-2">
    Quantité minimum
  </h3>
  <div class="flex items-center gap-2">
    <input type="number" class="input w-20" placeholder="0" min="0">
    <span class="text-xs text-base-content/40">à</span>
    <input type="number" class="input w-20" placeholder="500" min="0">
  </div>
</div>

Filtres actifs (tags visibles)

Afficher les filtres sélectionnés au-dessus des résultats pour que l'utilisateur sache ce qui est actif. Chaque tag est supprimable individuellement.

Filtres actifs : Stanley/Stella Noir Tout effacer
<div class="flex flex-wrap gap-2 mb-4">
  <span class="text-xs text-base-content/50 font-accent font-bold uppercase">Filtres actifs :</span>
  <span class="badge badge-validated gap-1">
    Stanley/Stella
    <button class="hover:opacity-70 ml-0.5">×</button>
  </span>
  <span class="badge badge-validated gap-1">
    Noir
    <button class="hover:opacity-70 ml-0.5">×</button>
  </span>
  <a href="#" class="badge badge-draft text-xs">Tout effacer</a>
</div>
Toujours afficher le nombre de résultats par filtre avec badge-neutral (un compteur est une étiquette neutre, pas un statut — jamais badge-draft).
Boutons : "Filtrer" (btn-primary) + "Effacer" (btn-ghost).
Une seule structure .filter-panel partout : sidebar sur desktop, tiroir sur mobile. Le même markup dans chaque app, pas de variante par projet.
Ne jamais filtrer en temps réel sans bouton de confirmation — trop de requêtes.
Ne pas masquer la sidebar sur desktop — elle doit toujours être visible dans les vues catalogue.