All checks were successful
mode séance, battlemaps multiples et export Foundry ciblé
- Quêtes (Niveau 1) : entité Quest orthogonale à l'arbre, rattachée à un arc HUB
ou libre (migrations V9-V12, V18, V20 ; réconciliation des jumeaux V10).
Fusion quête/conteneur dans la sidebar, progression par partie (statuts
disponible/en cours/terminée), et quêtes libres avec espace de scènes créé
automatiquement (arc technique « Quêtes libres », V21 : levée de la
contrainte arcs.type héritée du baseline).
- Guidage (Pilier B) : bilan de préparation 100 % dérivé (règles arc/chapitre/
scène/quête), panneau « Prochaines étapes » avec boutons « Corriger », et
pastilles détaillées (tooltip des manques) dans l'arbre.
- Assistant IA (Pilier A) : étoffage champ par champ (scène, chapitre, arc) et
brouillons de scènes en propose→applique (brain : narrative-fields,
scene-drafts).
- Horloges & menaces (V15-V17) : clocks à segments avec déclencheurs, fronts.
- Mode séance : préparation de séance (readiness + quêtes dispo), scène
épinglée (V19), récap « précédemment » (brain : session-recap), onglet
« Partie » du panneau de référence, graphe amélioré (pan/zoom, éditeur de
liens).
- Perf : endpoint agrégé GET /api/campaigns/{id}/tree — la sidebar charge en
1 requête au lieu de ~15.
- Battlemaps multiples par scène (variantes jour/nuit, étages…) : liste JSON
étiquetée (V22, reprise automatique de la carte existante), rendu PDF avec
légendes, export/import rétro-compatible.
- Export Foundry ciblé : modale de périmètre (cartes+ennemis / journaux /
tables), bundle filtré côté serveur (zip allégé), module Foundry à jour
(respect du périmètre + une Scene Foundry par variante de carte,
rétro-compatible anciens bundles).
61 lines
2.5 KiB
HTML
61 lines
2.5 KiB
HTML
<div class="scene-draft">
|
|
<button type="button" class="draft-toggle" (click)="toggle()">
|
|
<lucide-icon [img]="open ? ChevronDown : ChevronRight" [size]="15"></lucide-icon>
|
|
<lucide-icon [img]="Sparkles" [size]="15" class="spark"></lucide-icon>
|
|
<span class="draft-title">{{ 'sceneDraft.button' | translate }}</span>
|
|
</button>
|
|
|
|
@if (open) {
|
|
<div class="draft-body">
|
|
<p class="draft-hint">{{ 'sceneDraft.hint' | translate }}</p>
|
|
|
|
<div class="draft-prompt">
|
|
<textarea [(ngModel)]="instruction" rows="2"
|
|
[placeholder]="'sceneDraft.instructionPlaceholder' | translate"></textarea>
|
|
<div class="draft-controls">
|
|
<label class="count-label">
|
|
{{ 'sceneDraft.countLabel' | translate }}
|
|
<select [(ngModel)]="count">
|
|
@for (c of countOptions; track c) { <option [ngValue]="c">{{ c }}</option> }
|
|
</select>
|
|
</label>
|
|
<button type="button" class="btn-generate" (click)="generate()" [disabled]="loading">
|
|
<lucide-icon [img]="loading ? RefreshCw : Sparkles" [size]="14" [class.spin]="loading"></lucide-icon>
|
|
{{ (loading ? 'sceneDraft.generating' : (generated ? 'sceneDraft.regenerate' : 'sceneDraft.generate')) | translate }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
@if (error) {
|
|
<p class="draft-error">{{ error }}</p>
|
|
}
|
|
|
|
@if (generated && drafts.length === 0 && !loading) {
|
|
<p class="draft-empty">{{ 'sceneDraft.empty' | translate }}</p>
|
|
}
|
|
|
|
@if (drafts.length > 0) {
|
|
<ul class="draft-list">
|
|
@for (d of drafts; track $index) {
|
|
<li class="draft-card" [class.rejected]="!d.accepted">
|
|
<label class="draft-check">
|
|
<input type="checkbox" [(ngModel)]="d.accepted" />
|
|
<span class="draft-name">{{ d.name }}</span>
|
|
</label>
|
|
@if (d.description) { <p class="draft-desc">{{ d.description }}</p> }
|
|
@if (d.playerNarration) { <p class="draft-narration">{{ d.playerNarration }}</p> }
|
|
</li>
|
|
}
|
|
</ul>
|
|
|
|
<div class="draft-actions">
|
|
<button type="button" class="btn-apply" (click)="apply()" [disabled]="acceptedCount === 0 || applying">
|
|
<lucide-icon [img]="applying ? RefreshCw : Check" [size]="14" [class.spin]="applying"></lucide-icon>
|
|
{{ (applying ? 'sceneDraft.creating' : 'sceneDraft.createSelection') | translate:{ n: acceptedCount } }}
|
|
</button>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|