- ng update @angular/core@21 @angular/cli@21 (corrige GHSA-jrmj-c5cx-3cw6, XSS SVG) - Migration automatique des templates vers le control flow natif (@if/@for, 138 fichiers) - Correction des 5 `track` invalides generes par la migration (trackBy a 1 argument -> track $index) + suppression des fonctions trackBy mortes - TypeScript 5.9, zone.js 0.15 ; npm audit : 0 vulnerabilite Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
106 lines
3.3 KiB
HTML
106 lines
3.3 KiB
HTML
<div class="ce-page">
|
||
|
||
<div class="ce-header">
|
||
<button class="btn-back" (click)="back()">
|
||
<lucide-icon [img]="ArrowLeft" [size]="14"></lucide-icon>
|
||
Retour à la campagne
|
||
</button>
|
||
<div class="header-row">
|
||
<h1>
|
||
<lucide-icon [img]="User" [size]="22"></lucide-icon>
|
||
{{ characterId ? 'Éditer la fiche' : 'Nouveau personnage' }}
|
||
</h1>
|
||
@if (characterId) {
|
||
<button
|
||
type="button"
|
||
class="btn-ai"
|
||
(click)="toggleChat()"
|
||
[class.active]="chatOpen"
|
||
title="Ouvrir l'Assistant IA pour dialoguer autour de ce PJ">
|
||
<lucide-icon [img]="Sparkles" [size]="14"></lucide-icon>
|
||
Assistant IA
|
||
</button>
|
||
}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="ce-form">
|
||
|
||
<div class="field">
|
||
<label for="character-name">Nom du personnage *</label>
|
||
<input
|
||
id="character-name"
|
||
type="text"
|
||
[(ngModel)]="name"
|
||
name="name"
|
||
placeholder="Ex: Thorin le Grand-Hache, Lyra l'Errante..."
|
||
/>
|
||
</div>
|
||
|
||
<div class="field-row image-row">
|
||
<div class="field portrait-field">
|
||
<label>Portrait</label>
|
||
<app-single-image-picker
|
||
[imageId]="portraitImageId"
|
||
aspectRatio="1 / 1"
|
||
hint="Carre conseille (400×400)."
|
||
(imageIdChange)="portraitImageId = $event">
|
||
</app-single-image-picker>
|
||
</div>
|
||
<div class="field header-field">
|
||
<label>Bandeau / Header</label>
|
||
<app-single-image-picker
|
||
[imageId]="headerImageId"
|
||
aspectRatio="3 / 1"
|
||
hint="Format paysage conseille (1200×400)."
|
||
(imageIdChange)="headerImageId = $event">
|
||
</app-single-image-picker>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="template-fields">
|
||
<app-dynamic-fields-form
|
||
[fields]="templateFields"
|
||
[values]="values"
|
||
[imageValues]="imageValues"
|
||
[keyValueValues]="keyValueValues"
|
||
(valuesChange)="values = $event"
|
||
(imageValuesChange)="imageValues = $event"
|
||
(keyValueValuesChange)="keyValueValues = $event">
|
||
</app-dynamic-fields-form>
|
||
</div>
|
||
|
||
<div class="actions">
|
||
<button type="button" class="btn-primary" [disabled]="!name.trim()" (click)="submit()">
|
||
<lucide-icon [img]="Save" [size]="16"></lucide-icon>
|
||
{{ characterId ? 'Enregistrer' : 'Créer' }}
|
||
</button>
|
||
<button type="button" class="btn-secondary" (click)="back()">Annuler</button>
|
||
<span class="spacer"></span>
|
||
@if (characterId) {
|
||
<button
|
||
type="button"
|
||
class="btn-danger"
|
||
(click)="deleteCharacter()">
|
||
<lucide-icon [img]="Trash2" [size]="14"></lucide-icon>
|
||
Supprimer
|
||
</button>
|
||
}
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
@if (characterId && campaignId) {
|
||
<app-ai-chat-drawer
|
||
[campaignId]="campaignId"
|
||
entityType="character"
|
||
[entityId]="characterId"
|
||
[isOpen]="chatOpen"
|
||
welcomeMessage="Je vois cette fiche de personnage. Demande-moi de proposer stats, backstory, équipement ou objectifs personnels."
|
||
[quickSuggestions]="chatQuickSuggestions"
|
||
(close)="chatOpen = false">
|
||
</app-ai-chat-drawer>
|
||
}
|