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,15 @@
<div class="chips-wrapper">
<span class="chip" *ngFor="let tag of value; let i = index">
{{ tag }}
<button type="button" class="chip-remove" (click)="remove(i)" title="Retirer">
<lucide-icon [img]="X" [size]="12"></lucide-icon>
</button>
</span>
<input
type="text"
class="chip-input"
[placeholder]="placeholder"
[(ngModel)]="current"
(keydown)="onKeyDown($event)"
(blur)="add()" />
</div>

View File

@@ -0,0 +1,53 @@
.chips-wrapper {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.4rem;
padding: 0.55rem 0.65rem;
background: #1a1a2e;
border: 1px solid #2a2a3d;
border-radius: 6px;
&:focus-within {
border-color: #6c63ff;
}
}
.chip {
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.2rem 0.55rem;
background: #1e1c3a;
color: #a5b4fc;
border-radius: 999px;
font-size: 0.8rem;
line-height: 1.2;
.chip-remove {
display: inline-flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
color: inherit;
cursor: pointer;
padding: 0;
opacity: 0.7;
&:hover { opacity: 1; color: #fca5a5; }
}
}
.chip-input {
flex: 1;
min-width: 140px;
background: transparent;
border: none;
color: white;
font-size: 0.88rem;
padding: 0.15rem 0;
outline: none;
&::placeholder { color: #6b7280; }
}

View File

@@ -0,0 +1,68 @@
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { LucideAngularModule, X } from 'lucide-angular';
/**
* Composant réutilisable de saisie de chips (étiquettes textuelles).
*
* Usage :
* <app-chips-input
* [value]="tags"
* (valueChange)="tags = $event"
* placeholder="Ajouter un tag..."></app-chips-input>
*
* Règles UX :
* - Entrée valide la saisie en cours
* - Virgule valide aussi (pratique pour enchaîner plusieurs tags)
* - Doublons silencieusement ignorés
* - Espaces en début/fin trimmés
* - Clic sur X retire le chip
*/
@Component({
selector: 'app-chips-input',
standalone: true,
imports: [CommonModule, FormsModule, LucideAngularModule],
templateUrl: './chips-input.component.html',
styleUrls: ['./chips-input.component.scss']
})
export class ChipsInputComponent {
readonly X = X;
@Input() value: string[] = [];
@Input() placeholder = 'Ajouter...';
@Output() valueChange = new EventEmitter<string[]>();
/** Texte de l'input en cours de saisie. */
current = '';
/** Ajoute le texte courant s'il est non vide et non déjà présent. */
add(): void {
const raw = this.current.trim().replace(/,$/, '').trim();
if (!raw) return;
if (this.value.includes(raw)) {
this.current = '';
return;
}
this.valueChange.emit([...this.value, raw]);
this.current = '';
}
/** Retire le chip à l'index donné. */
remove(index: number): void {
const next = [...this.value];
next.splice(index, 1);
this.valueChange.emit(next);
}
/** Gère Enter et virgule comme déclencheurs d'ajout. */
onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter' || event.key === ',') {
event.preventDefault();
this.add();
} else if (event.key === 'Backspace' && this.current === '' && this.value.length > 0) {
// Backspace sur input vide retire le dernier chip (UX courante).
this.remove(this.value.length - 1);
}
}
}