MaBibli 1.0.0
Gestion de bibliothèque personnelle auto-hébergée : catalogue, prêts, scan de code-barres, consultation hors-ligne. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
@*
|
||||
Les champs d'un numéro de revue, partagés par l'ajout et la modification.
|
||||
|
||||
Un seul exemplaire, et pas deux blocs jumeaux : le formulaire d'ajout et celui de
|
||||
modification doivent proposer exactement les mêmes champs, sinon une couverture ou une une
|
||||
saisies à la création ne seraient plus modifiables ensuite — ce qui est précisément le cas
|
||||
d'usage (on ajoute un numéro le jour où on l'achète, on en recopie la une plus tard).
|
||||
|
||||
⚠️ Aucun champ ne se lie DIRECTEMENT à « Saisie » : chacun passe par une propriété qui
|
||||
prévient le parent (OnChangement). Blazor ne redessine que le composant qui a traité
|
||||
l'événement — une frappe ici ne re-rendait donc pas l'écran qui porte le bouton
|
||||
« Ajouter ce numéro », et celui-ci restait grisé jusqu'à ce qu'autre chose redessine le
|
||||
parent (enregistrer la revue, par exemple). Voir CLAUDE.md.
|
||||
*@
|
||||
<div class="champs-numero">
|
||||
<label class="champ">
|
||||
<span class="champ-libelle">Numéro</span>
|
||||
<input class="champ-saisie" type="text" placeholder="43" @bind="Numero"
|
||||
@bind:event="oninput" @onkeydown="SurTouche" autocomplete="off" />
|
||||
</label>
|
||||
|
||||
<label class="champ">
|
||||
<span class="champ-libelle">Parution <span class="champ-aide">(facultatif)</span></span>
|
||||
<input class="champ-saisie" type="date" @bind="Parution" />
|
||||
</label>
|
||||
|
||||
<label class="champ">
|
||||
<span class="champ-libelle">Note <span class="champ-aide">(facultatif)</span></span>
|
||||
<input class="champ-saisie" type="text" @bind="Note" @bind:event="oninput"
|
||||
placeholder="dossier sur l'eau" autocomplete="off" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@*
|
||||
⚠️ Un titre à la fois, et surtout PAS une ligne de titres séparés par des points-virgules :
|
||||
voir SaisieListe, qui porte le pourquoi. Une virgule dans un titre (« Ukraine, deux ans
|
||||
après ») n'a plus rien à couper, puisque plus rien ne découpe.
|
||||
*@
|
||||
<SaisieListe Valeurs="Saisie.Articles" Libelle="À la une"
|
||||
Aide=" (un titre à la fois : tapez-le, puis Entrée)"
|
||||
Placeholder="Ukraine, deux ans après"
|
||||
MessageDoublon="Ce titre est déjà à la une de ce numéro."
|
||||
OnChangement="Notifier" />
|
||||
|
||||
@*
|
||||
⚠️ Une URL, pas une photo. Aucune source ne donne la couverture d'un NUMÉRO : l'ISSN désigne
|
||||
la revue, pas la parution. Et le projet ne stocke aucun fichier — « ebooks : fiches
|
||||
uniquement » vaut ici aussi.
|
||||
*@
|
||||
<label class="champ">
|
||||
<span class="champ-libelle">
|
||||
Couverture <span class="champ-aide">(adresse d'une image, facultatif)</span>
|
||||
</span>
|
||||
<input class="champ-saisie" type="url" @bind="CoverUrl" @bind:event="oninput"
|
||||
placeholder="https://…" autocomplete="off" />
|
||||
</label>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired] public AjoutNumeroRevue Saisie { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Signale au parent que la saisie a changé, pour qu'il se redessine.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ⚠️ <b>Sans cela, un bouton du parent qui dépend de la saisie reste figé.</b> Blazor ne
|
||||
/// redessine que le composant ayant traité l'événement : « Ajouter ce numéro » vit dans
|
||||
/// l'écran de la revue, le champ « Numéro » vit ici, et le bouton restait donc désactivé
|
||||
/// tant que rien d'autre ne re-rendait le parent — constaté en usage, où il fallait passer
|
||||
/// par « Modifier la revue » puis « Enregistrer » pour le débloquer.
|
||||
/// <para>
|
||||
/// Tous les champs préviennent, pas seulement le numéro : aucun autre bouton n'en dépend
|
||||
/// aujourd'hui, mais faire dépendre la correction de « lequel commande quoi » la referait
|
||||
/// oublier au premier champ ajouté.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Parameter] public EventCallback OnChangement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Les champs du numéro, servis par des propriétés plutôt que liés à <see cref="Saisie"/> :
|
||||
/// c'est le seul endroit d'où prévenir le parent à coup sûr.
|
||||
/// </summary>
|
||||
private string Numero
|
||||
{
|
||||
get => Saisie.Numero;
|
||||
set { Saisie.Numero = value; Notifier(); }
|
||||
}
|
||||
|
||||
private string? Note
|
||||
{
|
||||
get => Saisie.Note;
|
||||
set { Saisie.Note = value; Notifier(); }
|
||||
}
|
||||
|
||||
private string? CoverUrl
|
||||
{
|
||||
get => Saisie.CoverUrl;
|
||||
set { Saisie.CoverUrl = value; Notifier(); }
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Le parent est prévenu sans être attendu : <c>InvokeAsync</c> ne fait que demander un
|
||||
/// nouveau rendu, et un setter de propriété ne peut de toute façon rien attendre.
|
||||
/// </remarks>
|
||||
private void Notifier() => _ = OnChangement.InvokeAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Date affichée par le champ, en <b>local</b>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ⚠️ Le <c><input type="date"></c> produit une date sans fuseau. Elle est déclarée
|
||||
/// locale ici et convertie en UTC, comme toutes les dates du projet : sans cela la parution
|
||||
/// se décale d'un jour pour la moitié du globe. La conversion se fait dans le composant
|
||||
/// pour que les deux écrans qui s'en servent ne puissent pas l'oublier chacun de leur côté.
|
||||
/// </remarks>
|
||||
private DateTime? Parution
|
||||
{
|
||||
get => Saisie.DateParution?.ToLocalTime().Date;
|
||||
set
|
||||
{
|
||||
Saisie.DateParution = value is { } date
|
||||
? DateTime.SpecifyKind(date, DateTimeKind.Local).ToUniversalTime()
|
||||
: null;
|
||||
|
||||
Notifier();
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter] public EventCallback<KeyboardEventArgs> OnEntree { get; set; }
|
||||
|
||||
private async Task SurTouche(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Key == "Enter")
|
||||
{
|
||||
await OnEntree.InvokeAsync(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user