Mise à jour avec la possibilité de mettre des images
This commit is contained in:
@@ -44,7 +44,16 @@
|
||||
|
||||
<ul class="fields-list">
|
||||
<li class="field-row" *ngFor="let f of fields; let i = index">
|
||||
<span class="field-chip">{{ f }}</span>
|
||||
<span class="field-chip" [class.field-chip-image]="f.type === 'IMAGE'">
|
||||
<lucide-icon [img]="f.type === 'IMAGE' ? ImageIcon : Type" [size]="12"></lucide-icon>
|
||||
{{ f.name }}
|
||||
</span>
|
||||
<button type="button"
|
||||
class="btn-icon-ghost btn-type-toggle"
|
||||
(click)="toggleFieldType(i)"
|
||||
[title]="f.type === 'TEXT' ? 'Transformer en champ Image' : 'Transformer en champ Texte'">
|
||||
{{ f.type === 'TEXT' ? 'Texte' : 'Image' }}
|
||||
</button>
|
||||
<button type="button" class="btn-icon-ghost" (click)="removeField(i)" aria-label="Supprimer">
|
||||
<lucide-icon [img]="X" [size]="14"></lucide-icon>
|
||||
</button>
|
||||
@@ -58,12 +67,20 @@
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
placeholder="+ Ajouter un champ"
|
||||
(keydown.enter)="$event.preventDefault(); addField()" />
|
||||
<select
|
||||
class="type-select"
|
||||
[(ngModel)]="newFieldType"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
aria-label="Type du champ">
|
||||
<option value="TEXT">Texte</option>
|
||||
<option value="IMAGE">Image</option>
|
||||
</select>
|
||||
<button type="button" class="btn-add" (click)="addField()">
|
||||
<lucide-icon [img]="Plus" [size]="14"></lucide-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="hint">Définissez les champs qui apparaîtront dans les pages créées avec ce template</p>
|
||||
<p class="hint">Texte = zone editable + generable par l'IA. Image = galerie d'illustrations.</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -103,9 +103,39 @@
|
||||
padding: 0.6rem 0.9rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.88rem;
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.45rem;
|
||||
|
||||
// Discriminant visuel pour les champs IMAGE (palette indigo).
|
||||
&.field-chip-image {
|
||||
background: #1f1b3a;
|
||||
border-color: #3d3566;
|
||||
color: #c7b8ff;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-type-toggle {
|
||||
width: auto;
|
||||
padding: 0 0.7rem;
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.02em;
|
||||
color: #9ca3af;
|
||||
|
||||
&:hover { color: #a5b4fc; background: #1f1b3a; }
|
||||
}
|
||||
|
||||
.type-select {
|
||||
background: #1a1a2e;
|
||||
border: 1px solid #2a2a3d;
|
||||
color: white;
|
||||
padding: 0 0.6rem;
|
||||
height: 36px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.82rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus { outline: none; border-color: #6c63ff; }
|
||||
}
|
||||
|
||||
input {
|
||||
|
||||
@@ -3,14 +3,14 @@ import { CommonModule } from '@angular/common';
|
||||
import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { LucideAngularModule, Plus, X, Trash2 } from 'lucide-angular';
|
||||
import { LucideAngularModule, Plus, X, Trash2, Type, Image as ImageIcon } from 'lucide-angular';
|
||||
import { LoreService } from '../../services/lore.service';
|
||||
import { TemplateService } from '../../services/template.service';
|
||||
import { PageService } from '../../services/page.service';
|
||||
import { LayoutService } from '../../services/layout.service';
|
||||
import { PageTitleService } from '../../services/page-title.service';
|
||||
import { LoreNode } from '../../services/lore.model';
|
||||
import { Template } from '../../services/template.model';
|
||||
import { FieldType, Template, TemplateField } from '../../services/template.model';
|
||||
import { loadLoreSidebarData, buildLoreSidebarConfig } from '../lore-sidebar.helper';
|
||||
|
||||
/**
|
||||
@@ -28,14 +28,17 @@ export class TemplateEditComponent implements OnInit, OnDestroy {
|
||||
readonly Plus = Plus;
|
||||
readonly X = X;
|
||||
readonly Trash2 = Trash2;
|
||||
readonly Type = Type;
|
||||
readonly ImageIcon = ImageIcon;
|
||||
|
||||
form: FormGroup;
|
||||
loreId = '';
|
||||
templateId = '';
|
||||
template: Template | null = null;
|
||||
nodes: LoreNode[] = [];
|
||||
fields: string[] = [];
|
||||
fields: TemplateField[] = [];
|
||||
newFieldName = '';
|
||||
newFieldType: FieldType = 'TEXT';
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
@@ -70,7 +73,12 @@ export class TemplateEditComponent implements OnInit, OnDestroy {
|
||||
|
||||
private hydrate(template: Template): void {
|
||||
this.template = template;
|
||||
this.fields = [...template.fields];
|
||||
// Copie defensive + normalisation du type (defaut TEXT si inconnu/manquant,
|
||||
// utile pour les templates legacy cote frontend meme si le backend le fait aussi).
|
||||
this.fields = (template.fields ?? []).map(f => ({
|
||||
name: f.name,
|
||||
type: f.type === 'IMAGE' ? 'IMAGE' : 'TEXT'
|
||||
}));
|
||||
this.form.patchValue({
|
||||
name: template.name,
|
||||
description: template.description,
|
||||
@@ -81,8 +89,9 @@ export class TemplateEditComponent implements OnInit, OnDestroy {
|
||||
|
||||
addField(): void {
|
||||
const name = this.newFieldName.trim();
|
||||
if (!name || this.fields.includes(name)) return;
|
||||
this.fields = [...this.fields, name];
|
||||
if (!name) return;
|
||||
if (this.fields.some(f => f.name === name)) return;
|
||||
this.fields = [...this.fields, { name, type: this.newFieldType }];
|
||||
this.newFieldName = '';
|
||||
}
|
||||
|
||||
@@ -90,6 +99,14 @@ export class TemplateEditComponent implements OnInit, OnDestroy {
|
||||
this.fields = this.fields.filter((_, i) => i !== index);
|
||||
}
|
||||
|
||||
/** Bascule le type d'un champ (TEXT <-> IMAGE). */
|
||||
toggleFieldType(index: number): void {
|
||||
const field = this.fields[index];
|
||||
if (!field) return;
|
||||
const nextType: FieldType = field.type === 'TEXT' ? 'IMAGE' : 'TEXT';
|
||||
this.fields = this.fields.map((f, i) => i === index ? { ...f, type: nextType } : f);
|
||||
}
|
||||
|
||||
save(): void {
|
||||
if (this.form.invalid || !this.template) return;
|
||||
const raw = this.form.value;
|
||||
|
||||
Reference in New Issue
Block a user