prod setup

This commit is contained in:
Johan LEROY
2026-05-04 11:00:44 +02:00
parent 7c7ff160eb
commit 5d05cd4c04
46 changed files with 2016 additions and 190 deletions

View File

@@ -0,0 +1,95 @@
import { useState, type KeyboardEvent } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { FieldError } from './FieldError';
type Props = {
name: string;
label: string;
hint?: string;
placeholder?: string;
};
export function ChipsField({ name, label, hint, placeholder = 'Ajouter puis Entrée…' }: Props) {
const { control } = useFormContext();
const [draft, setDraft] = useState('');
return (
<Controller
name={name}
control={control}
render={({ field }) => {
const items: string[] = Array.isArray(field.value) ? field.value : [];
const add = () => {
const value = draft.trim();
if (!value) return;
if (items.includes(value)) {
setDraft('');
return;
}
field.onChange([...items, value]);
setDraft('');
};
const remove = (idx: number) => {
field.onChange(items.filter((_, i) => i !== idx));
};
const onKey = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter' || e.key === ',') {
e.preventDefault();
add();
} else if (e.key === 'Backspace' && draft === '' && items.length > 0) {
field.onChange(items.slice(0, -1));
}
};
return (
<div>
<span className="block font-mono text-xs uppercase tracking-widest text-[color:var(--color-cyan)] mb-1.5">
{label}
</span>
{hint && (
<span className="block font-mono text-[10px] text-[color:var(--color-text-dim)] mb-1.5">
{hint}
</span>
)}
<div className="flex flex-wrap gap-2 mb-2">
{items.map((item, idx) => (
<span
key={`${item}-${idx}`}
className="chip group cursor-pointer"
onClick={() => remove(idx)}
title="Cliquer pour retirer"
>
{item}
<span className="ml-1 opacity-50 group-hover:opacity-100 group-hover:text-[color:var(--color-magenta)]">
×
</span>
</span>
))}
</div>
<div className="flex gap-2">
<input
type="text"
value={draft}
onChange={(e) => setDraft(e.target.value)}
onKeyDown={onKey}
placeholder={placeholder}
className="flex-1 bg-[color:var(--color-surface-2)] border border-[color:var(--color-border)] focus:border-[color:var(--color-cyan)] focus:outline-none p-2 rounded text-sm font-mono text-[color:var(--color-text)] transition-colors"
/>
<button
type="button"
onClick={add}
className="px-3 py-1.5 font-mono text-xs uppercase tracking-widest border border-[color:var(--color-cyan)] text-[color:var(--color-cyan)] rounded hover:bg-[color:var(--color-cyan)] hover:text-[color:var(--color-bg)] transition-colors"
>
+ add
</button>
</div>
<FieldError name={name} />
</div>
);
}}
/>
);
}