Rend l'attente visible, et met le champ de création sur une ligne
Une recherche BnF coûte environ une seconde par page, et jusqu'à dix pages pour les nouveautés : sans rien à l'écran, l'application se lit comme plantée. Le lot H l'avait montré — un écran qui ne dit rien pousse à recliquer, donc à relancer l'appel. Un indicateur ne remplace aucun message d'échec : une source muette garde ses `EtatSourceBibliographie` et ses motifs. Ici on dit « ça travaille », jamais « ça a marché ». L'animation se neutralise sous `prefers-reduced-motion`, la rondelle restant visible : c'est elle qui porte l'information, pas sa rotation. Le champ « nom d'une nouvelle série » et son bouton tiennent maintenant sur une ligne. `min-width: 0` est ce qui la fait tenir à 320 px : sans lui, un élément de formulaire refuse de rétrécir sous sa largeur intrinsèque et pousse le bouton hors de l'écran. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
@*
|
||||||
|
Indicateur d'attente pour les appels lents (lot L1).
|
||||||
|
|
||||||
|
⚠️ Le besoin n'est pas décoratif. Une recherche BnF coûte environ une seconde par page, et
|
||||||
|
jusqu'à dix pages pour les nouveautés : sans rien à l'écran, l'application se lit comme
|
||||||
|
plantée, et l'utilisateur reclique — donc relance l'appel. C'est exactement ce que le lot H
|
||||||
|
avait constaté sur la bibliographie.
|
||||||
|
|
||||||
|
⚠️ Un indicateur NE REMPLACE PAS un message d'échec. Une source muette garde ses états
|
||||||
|
EtatSourceBibliographie et son motif : ici on dit « ça travaille », jamais « ça a marché ».
|
||||||
|
|
||||||
|
role="status" et non role="alert" : l'attente s'annonce sans interrompre le lecteur d'écran.
|
||||||
|
L'animation est neutralisée sous prefers-reduced-motion (voir app.css).
|
||||||
|
*@
|
||||||
|
<p class="attente @Classe" role="status">
|
||||||
|
<span class="attente-rondelle" aria-hidden="true"></span>
|
||||||
|
<span>@Message</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
/// <summary>Ce qu'on attend, dit à l'utilisateur. Jamais un libellé générique si l'on sait mieux.</summary>
|
||||||
|
[Parameter, EditorRequired] public string Message { get; set; } = default!;
|
||||||
|
|
||||||
|
[Parameter] public string? Classe { get; set; }
|
||||||
|
}
|
||||||
@@ -82,9 +82,10 @@
|
|||||||
*@
|
*@
|
||||||
@if (_etape == Etape.Recherche)
|
@if (_etape == Etape.Recherche)
|
||||||
{
|
{
|
||||||
<p class="message-discret" role="status">
|
@* L1 : l'étape existait déjà pour que l'enchaînement du scan SE VOIE ; la rondelle dit en
|
||||||
Recherche de <span class="code-isbn">@FormatageIsbn.Afficher(_isbn)</span> à la BnF, puis chez OpenLibrary…
|
plus que ça travaille encore, ce qu'un texte figé ne distingue pas d'un écran bloqué. *@
|
||||||
</p>
|
<Patience Classe="attente-recherche"
|
||||||
|
Message="@($"Recherche de {FormatageIsbn.Afficher(_isbn)} à la BnF, puis chez OpenLibrary…")" />
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (_etape == Etape.Scan)
|
@if (_etape == Etape.Scan)
|
||||||
|
|||||||
@@ -19,18 +19,18 @@
|
|||||||
|
|
||||||
@* Créer une série depuis la liste : c'est le seul endroit d'où l'on part, et un écran de plus
|
@* Créer une série depuis la liste : c'est le seul endroit d'où l'on part, et un écran de plus
|
||||||
pour un unique champ ne se justifierait pas. *@
|
pour un unique champ ne se justifierait pas. *@
|
||||||
<div class="barre-recherche">
|
@* M1 : le champ et son bouton sur UNE ligne. Le champ prend la place restante, le bouton
|
||||||
|
garde la sienne et son libellé ne se tronque pas — vérifié jusqu'à 320 px. *@
|
||||||
|
<div class="ligne-creation">
|
||||||
<input class="champ-saisie" type="text" placeholder="Nom d'une nouvelle série…"
|
<input class="champ-saisie" type="text" placeholder="Nom d'une nouvelle série…"
|
||||||
@bind="_nouveau" @bind:event="oninput" @onkeydown="SurTouche"
|
@bind="_nouveau" @bind:event="oninput" @onkeydown="SurTouche"
|
||||||
aria-label="Nom de la nouvelle série" autocomplete="off" />
|
aria-label="Nom de la nouvelle série" autocomplete="off" />
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="actions-formulaire">
|
|
||||||
<button type="button" class="bouton bouton-principal"
|
<button type="button" class="bouton bouton-principal"
|
||||||
disabled="@(_enCours || !Reseau.EnLigne || string.IsNullOrWhiteSpace(_nouveau))"
|
disabled="@(_enCours || !Reseau.EnLigne || string.IsNullOrWhiteSpace(_nouveau))"
|
||||||
title="@MotifBlocage"
|
title="@MotifBlocage"
|
||||||
@onclick="CreerAsync">
|
@onclick="CreerAsync">
|
||||||
Créer la série
|
Créer
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1383,3 +1383,66 @@ body {
|
|||||||
border-bottom-color: #f5d76e;
|
border-bottom-color: #f5d76e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Attente (lot L1) -------------------------------------------------
|
||||||
|
Un appel lent doit se voir : une recherche BnF coûte ~1 s par page, et
|
||||||
|
jusqu'à dix pages pour les nouveautés. Sans indicateur, l'écran se lit
|
||||||
|
comme planté et l'on reclique, ce qui relance l'appel.
|
||||||
|
------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
.attente {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
color: var(--mb-texte-doux);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin: 0.75rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attente-rondelle {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
border: 2px solid var(--mb-bord);
|
||||||
|
border-top-color: var(--mb-accent);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: attente-tourne 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes attente-tourne {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Une animation perpétuelle est précisément ce que ce réglage demande d'éviter.
|
||||||
|
L'indicateur reste visible — c'est lui qui porte l'information, pas sa rotation. */
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.attente-rondelle {
|
||||||
|
animation: none;
|
||||||
|
border-top-color: var(--mb-accent);
|
||||||
|
border-right-color: var(--mb-accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Créer depuis une liste : champ + bouton sur une ligne (lot M1) ----
|
||||||
|
⚠️ min-width: 0 sur le champ est ce qui fait tenir la ligne à 320 px : sans
|
||||||
|
lui, un élément de formulaire refuse de rétrécir sous sa largeur intrinsèque
|
||||||
|
et pousse le bouton hors de l'écran. Le bouton, lui, ne rétrécit pas et son
|
||||||
|
libellé ne se coupe pas — un bouton tronqué ne se lit plus.
|
||||||
|
------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
.ligne-creation {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: stretch;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ligne-creation .champ-saisie {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ligne-creation .bouton {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user