IT-Stock/app/templates/materiels.html
maxsoch f734259f73 Refonte du système visuel : tokens sémantiques, mode sombre, cohérence
Évolution du thème existant "étiquette d'inventaire" plutôt que
remplacement : couche de tokens sémantiques + échelles espacement/
typographie, mode sombre via prefers-color-scheme, hiérarchie de boutons
(primaire/secondaire/danger), icônes SVG et état actif dans la nav, fil
d'Ariane et compteur de résultats sur /materiels, badges de stock bas
réutilisés depuis /scan, formulaire de planification regroupé en carte
sur /destinataires, et correctif de contraste en mode sombre (inputs
natifs + boutons qui restaient rendus en clair).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EEC2W1xtjmpHkEYgua7gWC
2026-07-19 08:47:50 +02:00

150 lines
6.2 KiB
HTML

{% extends "base.html" %}
{% block titre %}Matériels - Gestion de stock IT{% endblock %}
{#
Macro pour une ligne de matériel : utilisée à la fois en affichage plat
et en affichage groupé par catégorie (tri=categorie), pour ne pas
dupliquer le HTML entre les deux.
Chaque ligne est repliée par défaut (juste le résumé, pas les champs
d'édition) : avec beaucoup de matériels, afficher 5 <input> par ligne en
permanence rend la liste illisible et pousse le contenu hors de l'écran.
On ne dépense la largeur d'un vrai formulaire que sur la ligne qu'on
déplie. Voir aussi CLAUDE.md pour le contexte de ce choix.
#}
{% macro ligne_materiel(materiel, categories_aplaties) %}
{% set sous_seuil = materiel.seuil_alerte is not none and materiel.quantite < materiel.seuil_alerte %}
<li>
<details class="ligne-materiel">
<summary>
<span class="noeud-chevron" aria-hidden="true"></span>
<span class="materiel-nom">{{ materiel.nom }}</span>
<span class="materiel-categorie">{{ materiel.categorie.chemin() }}</span>
<span class="materiel-code">{{ materiel.code_barre or "—" }}</span>
<span class="materiel-quantite {{ 'quantite-basse' if sous_seuil else '' }}">
{{ materiel.quantite }}
{% if sous_seuil %}<span class="badge badge-bas"><span class="statut-puce" aria-hidden="true"></span>bas</span>{% endif %}
</span>
</summary>
<form method="post" action="/materiels/{{ materiel.id }}/modifier" class="formulaire-edition">
<label>Nom
<input type="text" name="nom" value="{{ materiel.nom }}" required>
</label>
<label>Catégorie
<select name="categorie_id" required>
{% for profondeur, categorie in categories_aplaties %}
<option value="{{ categorie.id }}" {{ "selected" if categorie.id == materiel.categorie_id else "" }}>
{{ "— " * profondeur }}{{ categorie.nom }}
</option>
{% endfor %}
</select>
</label>
<label>Code-barre
<input type="text" name="code_barre" value="{{ materiel.code_barre or '' }}">
</label>
<label>Quantité
<input type="number" name="quantite" value="{{ materiel.quantite }}" min="0" required>
</label>
<label>Seuil d'alerte
<input type="number" name="seuil_alerte" value="{{ materiel.seuil_alerte if materiel.seuil_alerte is not none else '' }}" min="0">
</label>
<div class="formulaire-actions">
<button type="submit">Enregistrer</button>
<button type="submit" formaction="/materiels/{{ materiel.id }}/supprimer" class="bouton-danger">Supprimer</button>
</div>
</form>
</details>
</li>
{% endmacro %}
{% block contenu %}
<h1>Matériels</h1>
<form method="get" action="/materiels" class="barre-filtres">
<input type="search" name="q" value="{{ q }}" placeholder="Rechercher par nom ou code-barre…">
<select name="categorie_id">
<option value="">Toutes les catégories</option>
{% for profondeur, categorie in categories_aplaties %}
<option value="{{ categorie.id }}" {{ "selected" if categorie_id == categorie.id|string else "" }}>
{{ "— " * profondeur }}{{ categorie.nom }}
</option>
{% endfor %}
</select>
<select name="tri">
<option value="nom_asc" {{ "selected" if tri == "nom_asc" else "" }}>Nom (A → Z)</option>
<option value="nom_desc" {{ "selected" if tri == "nom_desc" else "" }}>Nom (Z → A)</option>
<option value="quantite_asc" {{ "selected" if tri == "quantite_asc" else "" }}>Quantité (croissant)</option>
<option value="quantite_desc" {{ "selected" if tri == "quantite_desc" else "" }}>Quantité (décroissant)</option>
<option value="categorie" {{ "selected" if tri == "categorie" else "" }}>Regrouper par catégorie</option>
</select>
<label class="case-stock-bas">
<input type="checkbox" name="stock_bas" value="1" {{ "checked" if stock_bas else "" }}>
Stock bas uniquement
</label>
<button type="submit">Filtrer</button>
{% if q or categorie_id or stock_bas or tri != "nom_asc" %}
<a href="/materiels" class="lien-effacer">Réinitialiser</a>
{% endif %}
<span class="compteur-resultats">{{ materiels|length }} matériel(s)</span>
</form>
{#
Le select de catégorie ci-dessus ne montre plus, une fois soumis, quel
sous-arbre est réellement affiché (juste son nom dans la liste
déroulante). Ce fil d'Ariane le rappelle explicitement, avec un lien
pour revenir à "toutes les catégories".
#}
{% if categorie_selectionnee %}
<p class="fil-ariane-categorie">
Filtré sur <span class="chemin-categorie">{{ categorie_selectionnee.chemin() }}</span>
<a href="/materiels{{ '?q=' + q if q else '' }}" class="lien-effacer">(retirer)</a>
</p>
{% endif %}
<ul class="liste-materiels">
{% if groupes %}
{% for chemin, groupe in groupes %}
<li class="groupe-categorie-entete">{{ chemin }}</li>
{% for materiel in groupe %}
{{ ligne_materiel(materiel, categories_aplaties) }}
{% endfor %}
{% endfor %}
{% else %}
{% for materiel in materiels %}
{{ ligne_materiel(materiel, categories_aplaties) }}
{% endfor %}
{% endif %}
{% if not materiels %}
<li class="liste-vide">
{% if q or categorie_id or stock_bas %}Aucun matériel ne correspond à ces filtres.{% else %}Aucun matériel pour l'instant.{% endif %}
</li>
{% endif %}
</ul>
<h2>Ajouter un matériel</h2>
{% if categories_aplaties %}
<form method="post" action="/materiels" class="formulaire-grille">
<label>Nom <input type="text" name="nom" required></label>
<label>Catégorie
<select name="categorie_id" required>
{% for profondeur, categorie in categories_aplaties %}
<option value="{{ categorie.id }}">{{ "— " * profondeur }}{{ categorie.nom }}</option>
{% endfor %}
</select>
</label>
<label>Code-barre <input type="text" name="code_barre"></label>
<label>Quantité initiale <input type="number" name="quantite" value="0" min="0"></label>
<label>Seuil d'alerte <input type="number" name="seuil_alerte" min="0"></label>
<button type="submit" class="bouton-primaire">Créer</button>
</form>
{% else %}
<p>Créez d'abord une <a href="/categories">catégorie</a> avant d'ajouter un matériel.</p>
{% endif %}
{% endblock %}