Corrections visuel ; optimisation du chargement des pages (préchargement anticité, sinon temps de latence chaque fois qu'on visite un type de page une première fois)

This commit is contained in:
2026-04-22 13:17:05 +02:00
parent 8f4dd3e9d6
commit 8efa148739
13 changed files with 385 additions and 34 deletions

View File

@@ -70,7 +70,7 @@
</div>
</div>
<div class="characters-section">
<section class="detail-section characters-section">
<div class="section-header">
<h2>Personnages joueurs</h2>
<button class="btn-add" (click)="createCharacter()">
@@ -97,33 +97,33 @@
Créer votre premier PJ
</button>
</div>
</div>
</section>
<div class="arcs-section">
<section class="detail-section arcs-section">
<div class="section-header">
<h2>Arcs narratifs</h2>
<button class="btn-add">
<button class="btn-add" (click)="createArc()">
<lucide-icon [img]="Plus" [size]="14"></lucide-icon>
Nouvel arc
</button>
</div>
<div class="arcs-grid" *ngIf="arcs.length > 0">
<div class="arc-card" *ngFor="let arc of arcs">
<div class="arc-card" *ngFor="let arc of arcs" (click)="openArc(arc)">
<lucide-icon [img]="Swords" [size]="24" class="arc-icon"></lucide-icon>
<span class="arc-name">{{ arc.name }}</span>
<span class="arc-meta">{{ arc.chapterCount || 0 }} chapitres</span>
<span class="arc-meta">{{ chapterCountByArc[arc.id!] || 0 }} chapitres</span>
</div>
</div>
<div class="empty-state" *ngIf="arcs.length === 0">
<lucide-icon [img]="Swords" [size]="40" class="empty-icon"></lucide-icon>
<p>Aucun arc narratif pour le moment.</p>
<button class="btn-add-first">
<button class="btn-add-first" (click)="createArc()">
<lucide-icon [img]="Plus" [size]="14"></lucide-icon>
Créer votre premier arc
</button>
</div>
</div>
</section>
</div>

View File

@@ -1,9 +1,23 @@
.campaign-detail {
padding: 2.5rem 2rem;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
/**
* Chaque bloc (resume, PJ, arcs) est encapsule dans une carte distincte
* pour separer visuellement les zones. Le gap au niveau du parent gere
* les espacements — les sections ne portent plus de margin-bottom.
*/
.detail-section {
background: #0d1117;
border: 1px solid #1f2937;
border-radius: 12px;
padding: 1.5rem 1.75rem;
}
.detail-header {
margin-bottom: 2.5rem;
h1 {
font-size: 1.75rem;
@@ -173,9 +187,6 @@
.arc-meta { color: #6b7280; font-size: 0.75rem; }
}
.characters-section {
margin-bottom: 2.5rem;
}
.characters-grid {
display: grid;

View File

@@ -36,6 +36,8 @@ export class CampaignDetailComponent implements OnInit, OnDestroy {
campaign: Campaign | null = null;
arcs: Arc[] = [];
/** Nombre de chapitres par arc — alimente le compteur des cartes. */
chapterCountByArc: Record<string, number> = {};
/** Lore associé si `campaign.loreId` est renseigné ; sinon null. */
linkedLore: Lore | null = null;
/** Lores disponibles pour changer l'association en mode édition. */
@@ -86,11 +88,20 @@ export class CampaignDetailComponent implements OnInit, OnDestroy {
this.loadLinkedGameSystem(campaign);
this.loadCharacters(campaign.id!);
this.arcs = treeData.arcs;
this.chapterCountByArc = this.computeChapterCounts(treeData);
this.showLayout(allCampaigns, treeData);
this.pageTitleService.set(campaign.name);
});
}
private computeChapterCounts(data: CampaignTreeData): Record<string, number> {
const counts: Record<string, number> = {};
for (const arcId of Object.keys(data.chaptersByArc)) {
counts[arcId] = data.chaptersByArc[arcId].length;
}
return counts;
}
/**
* Recharge explicitement après une mise à jour locale (ex: saveEdit).
* Contrairement au flux ngOnInit, on bypass le filter sur l'ID puisqu'on
@@ -110,6 +121,7 @@ export class CampaignDetailComponent implements OnInit, OnDestroy {
this.loadLinkedGameSystem(campaign);
this.loadCharacters(campaign.id!);
this.arcs = treeData.arcs;
this.chapterCountByArc = this.computeChapterCounts(treeData);
this.showLayout(allCampaigns, treeData);
this.pageTitleService.set(campaign.name);
});
@@ -157,6 +169,16 @@ export class CampaignDetailComponent implements OnInit, OnDestroy {
this.router.navigate(['/campaigns', this.campaign.id, 'characters', character.id, 'edit']);
}
createArc(): void {
if (!this.campaign) return;
this.router.navigate(['/campaigns', this.campaign.id, 'arcs', 'create']);
}
openArc(arc: Arc): void {
if (!this.campaign || !arc.id) return;
this.router.navigate(['/campaigns', this.campaign.id, 'arcs', arc.id]);
}
/** Extrait une ligne de résumé depuis le markdown (1re ligne non-vide, non-titre). */
characterSnippet(c: Character): string {
if (!c.markdownContent) return '(Fiche vide)';