Mise en ligne de la version 0.2.0
All checks were successful
Build & Push Images / build (brain) (push) Successful in 46s
Build & Push Images / build (core) (push) Successful in 1m21s
Build & Push Images / build (web) (push) Successful in 1m25s

This commit is contained in:
2026-04-21 14:25:17 +02:00
parent ebee8e106b
commit ba8a503b3e
300 changed files with 35329 additions and 1 deletions

View File

@@ -0,0 +1,37 @@
<div class="arc-create-page">
<div class="page-header">
<h1>Créer un nouvel arc narratif</h1>
</div>
<form [formGroup]="form" (ngSubmit)="submit()" class="arc-form">
<div class="field">
<label>Nom de l'arc *</label>
<input
type="text"
formControlName="name"
placeholder="Ex: L'Ombre du Nord"
[class.invalid]="form.get('name')?.invalid && form.get('name')?.touched"
/>
</div>
<div class="field">
<label>Description</label>
<textarea
formControlName="description"
placeholder="Décrivez l'arc narratif principal..."
rows="5">
</textarea>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary" [disabled]="form.invalid">
Créer l'arc
</button>
<button type="button" class="btn-secondary" (click)="cancel()">Annuler</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,18 @@
.arc-create-page {
padding: 2.5rem 2rem;
max-width: 640px;
}
// Override local : titre en violet (pas en blanc comme le .page-header global).
.page-header h1 { color: #a5b4fc; }
.arc-form {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
// Spécificité locale : le bouton "Créer l'arc" prend toute la largeur dispo.
// Tous les autres styles (.field, .btn-primary de base, .btn-secondary, .form-actions)
// sont fournis globalement par @app/styles/_forms.scss et _buttons.scss.
.btn-primary { flex: 1; }

View File

@@ -0,0 +1,95 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { forkJoin } from 'rxjs';
import { LucideAngularModule, BookOpen } from 'lucide-angular';
import { CampaignService } from '../../services/campaign.service';
import { LayoutService, GlobalItem } from '../../services/layout.service';
import { Campaign } from '../../services/campaign.model';
import { loadCampaignTreeData, buildCampaignTree } from '../campaign-tree.helper';
/**
* Écran de création d'un nouvel Arc narratif (contexte Campagne).
* Formulaire simple : nom + description. L'ordre est auto-calculé depuis
* le nombre d'arcs existants dans la campagne courante.
*/
@Component({
selector: 'app-arc-create',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, LucideAngularModule],
templateUrl: './arc-create.component.html',
styleUrls: ['./arc-create.component.scss']
})
export class ArcCreateComponent implements OnInit, OnDestroy {
readonly BookOpen = BookOpen;
form: FormGroup;
campaignId = '';
private existingArcCount = 0;
constructor(
private fb: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private campaignService: CampaignService,
private layoutService: LayoutService
) {
this.form = this.fb.group({
name: ['', Validators.required],
description: ['']
});
}
ngOnInit(): void {
this.campaignId = this.route.snapshot.paramMap.get('campaignId')!;
this.loadLayout();
}
private loadLayout(): void {
forkJoin({
campaign: this.campaignService.getCampaignById(this.campaignId),
allCampaigns: this.campaignService.getAllCampaigns(),
treeData: loadCampaignTreeData(this.campaignService, this.campaignId)
}).subscribe(({ campaign, allCampaigns, treeData }) => {
this.existingArcCount = treeData.arcs.length;
const globalItems: GlobalItem[] = allCampaigns.map((c: Campaign) => ({
id: c.id!, name: c.name, route: `/campaigns/${c.id}`
}));
this.layoutService.show({
title: campaign.name,
items: buildCampaignTree(this.campaignId, treeData),
footerLabel: 'Toutes les campagnes',
createActions: [
{ id: 'create-arc', label: '+ Nouvel arc', variant: 'primary', route: `/campaigns/${this.campaignId}/arcs/create` }
],
globalItems,
globalBackLabel: 'Toutes les campagnes',
globalBackRoute: '/campaigns'
});
});
}
submit(): void {
if (this.form.invalid) return;
this.campaignService.createArc({
name: this.form.value.name,
description: this.form.value.description,
campaignId: this.campaignId,
order: this.existingArcCount + 1
}).subscribe({
next: (created) => this.router.navigate(['/campaigns', this.campaignId, 'arcs', created.id]),
error: () => console.error('Erreur lors de la création de l\'arc')
});
}
cancel(): void {
this.router.navigate(['/campaigns', this.campaignId]);
}
ngOnDestroy(): void {
this.layoutService.hide();
}
}