Distinguer scénario, dessin et couleurs sur chaque livre

Le rôle vit sur le LIEN livre-auteur, jamais sur l'auteur : le même auteur
scénarise un album et dessine le suivant, et il ne doit pas exister en deux
fiches pour autant — ce que l'index unique sur la clé de regroupement
interdit de toute façon.

Les rôles se retrouvent par clé d'auteur résolue et non par position :
ResoudreAsync écarte les noms vides et fusionne les variantes, donc sa
liste peut être plus courte que la saisie.

Piège traité : le champ des noms reconstruit la liste à chaque frappe.
Decouper reprend les rôles connus en rapprochant sur la forme normalisée,
sans quoi corriger une faute de frappe les effacerait tous.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-19 22:37:20 +02:00
co-authored by Claude Opus 5
parent 9ab6f23b8c
commit 07cb48b2be
16 changed files with 895 additions and 22 deletions
@@ -31,6 +31,38 @@
placeholder="Prénom Nom ; Prénom Nom" autocomplete="off" />
</label>
@*
Les rôles n'apparaissent qu'à partir de DEUX auteurs, et c'est délibéré : un roman n'a
qu'un signataire dont le rôle ne se pose pas, et une ligne de boutons sous chaque saisie
n'apprendrait rien. La question « qui écrit, qui dessine ? » ne se pose qu'à plusieurs.
Le défaut reste « non précisé » : on ne remplit pas une case à la place de l'utilisateur.
*@
@if (Saisie.Auteurs.Count > 1)
{
<fieldset class="champ">
<legend class="champ-libelle">
Rôles<span class="champ-aide"> (facultatif — utile pour une BD)</span>
</legend>
@foreach (var (auteur, index) in Saisie.Auteurs.Select((a, i) => (a, i)))
{
<div class="ligne-role" @key="index">
<span class="nom-role">@auteur.Nom</span>
<div class="segments">
@foreach (var role in Roles)
{
<button type="button"
class="segment @(auteur.Role == role ? "segment-actif" : null)"
@onclick="() => PoserRole(index, role)">
@Libelles.RoleAuteur(role)
</button>
}
</div>
</div>
}
</fieldset>
}
<label class="champ">
<span class="champ-libelle">Éditeur</span>
<input class="champ-saisie" type="text" @bind="Saisie.Editeur" @bind:event="oninput"
@@ -135,6 +167,19 @@
private static readonly TypeDocument[] Types = Enum.GetValues<TypeDocument>();
private static readonly RoleAuteur[] Roles = Enum.GetValues<RoleAuteur>();
/// <summary>
/// Pose le rôle d'un auteur.
/// </summary>
/// <remarks>
/// <see cref="AuteurSaisi"/> est un record : on remplace l'entrée plutôt que de la muter,
/// et la liste reste celle que la propriété <c>Auteur</c> saura relire pour préserver les
/// rôles à la frappe suivante.
/// </remarks>
private void PoserRole(int index, RoleAuteur role) =>
Saisie.Auteurs[index] = Saisie.Auteurs[index] with { Role = role };
[Parameter, EditorRequired] public EnregistrementLivre Saisie { get; set; } = new();
[Parameter] public string LibelleValidation { get; set; } = "Enregistrer";
+13
View File
@@ -25,6 +25,19 @@ public static class Libelles
_ => type.ToString(),
};
/// <summary>
/// Libellé d'un rôle d'auteur. « Non précisé » ne s'affiche jamais sur une fiche : c'est
/// l'absence de choix, pas une information.
/// </summary>
public static string RoleAuteur(RoleAuteur role) => role switch
{
MaBibli.Shared.Entites.RoleAuteur.NonPrecise => "Non précisé",
MaBibli.Shared.Entites.RoleAuteur.Scenario => "Scénario",
MaBibli.Shared.Entites.RoleAuteur.Dessin => "Dessin",
MaBibli.Shared.Entites.RoleAuteur.Couleurs => "Couleurs",
_ => role.ToString(),
};
public static string Statut(Statut statut) => statut switch
{
MaBibli.Shared.Entites.Statut.ALire => "À lire",