feat: animation de confirmation sur le bouton save

Ajoute 3 états visuels au bouton save : repos (gris), saving (spinner),
saved (fond vert + checkmark animé pendant 2 secondes).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 08:14:35 +01:00
parent 895df3f7d9
commit c1751a1ab6
2 changed files with 27 additions and 2 deletions

View File

@@ -25,3 +25,14 @@ input:focus, select:focus, textarea:focus {
outline: none;
ring: 2px;
}
@keyframes check {
0% { stroke-dashoffset: 20; opacity: 0; }
50% { opacity: 1; }
100% { stroke-dashoffset: 0; opacity: 1; }
}
.check-icon polyline {
stroke-dasharray: 20;
animation: check 0.3s ease-out forwards;
}

View File

@@ -59,6 +59,7 @@ export function EvaluationEditor({ id, initialEvaluation, templates, users }: Ev
const router = useRouter();
const [evaluation, setEvaluation] = useState<Evaluation>(initialEvaluation);
const [saving, setSaving] = useState(false);
const [saved, setSaved] = useState(false);
const [exportOpen, setExportOpen] = useState(false);
const [shareOpen, setShareOpen] = useState(false);
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
@@ -149,6 +150,8 @@ export function EvaluationEditor({ id, initialEvaluation, templates, users }: Ev
});
if (result.success) {
if (!options?.skipRefresh) fetchEval();
setSaved(true);
setTimeout(() => setSaved(false), 2000);
} else {
alert(result.error);
}
@@ -208,9 +211,20 @@ export function EvaluationEditor({ id, initialEvaluation, templates, users }: Ev
<button
onClick={() => handleSave()}
disabled={saving}
className="rounded border border-zinc-300 dark:border-zinc-600 bg-zinc-100 dark:bg-zinc-700 px-3 py-1.5 font-mono text-xs text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700 disabled:opacity-50"
className={`rounded border px-3 py-1.5 font-mono text-xs disabled:opacity-50 transition-all duration-300 flex items-center gap-1.5 ${
saved
? "border-emerald-500/50 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
: "border-zinc-300 dark:border-zinc-600 bg-zinc-100 dark:bg-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-600"
}`}
>
{saving ? "..." : "save"}
{saving ? (
<span className="inline-block h-3 w-3 animate-spin rounded-full border border-zinc-400 border-t-transparent" />
) : saved ? (
<svg className="check-icon h-3 w-3" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="1.5,6 4.5,9 10.5,3" />
</svg>
) : null}
{saving ? "saving" : saved ? "saved" : "save"}
</button>
<button
onClick={() => {