From fa1a6422400a4073ac24030ce880291983335f97 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Mon, 25 May 2026 13:18:09 +0200 Subject: [PATCH] feat(catalogue): coller une image depuis le presse-papier (Ctrl+V) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Écoute l'événement paste sur window quand le formulaire est ouvert. Si le presse-papier contient une image, déclenche le même upload que le bouton fichier. Indice visuel "ou Ctrl+V" affiché sous le bouton. Les deux méthodes (fichier + coller) coexistent. v0.4.13 Co-Authored-By: Claude Sonnet 4.6 --- frontend/package.json | 2 +- .../components/shopping/CatalogueModal.tsx | 38 ++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 5d83e9c..b652c90 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "homehub-frontend", "private": true, - "version": "0.4.12", + "version": "0.4.13", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/shopping/CatalogueModal.tsx b/frontend/src/components/shopping/CatalogueModal.tsx index e9e30da..4126373 100644 --- a/frontend/src/components/shopping/CatalogueModal.tsx +++ b/frontend/src/components/shopping/CatalogueModal.tsx @@ -147,9 +147,7 @@ export default function CatalogueModal({ stores, onClose }: CatalogueModalProps) } } - async function handlePhotoChange(e: React.ChangeEvent) { - const file = e.target.files?.[0] - if (!file) return + async function uploadFile(file: File) { setUploading(true) setError(null) try { @@ -167,6 +165,11 @@ export default function CatalogueModal({ stores, onClose }: CatalogueModalProps) } } + async function handlePhotoChange(e: React.ChangeEvent) { + const file = e.target.files?.[0] + if (file) await uploadFile(file) + } + async function handleSave() { if (!form.name.trim()) return setSaving(true) @@ -200,6 +203,18 @@ export default function CatalogueModal({ stores, onClose }: CatalogueModalProps) const isFormOpen = creating || editing !== null const previewSrc = form.thumbnail_path ?? form.image_path + useEffect(() => { + if (!isFormOpen) return + function onPaste(e: ClipboardEvent) { + const item = Array.from(e.clipboardData?.items ?? []).find(i => i.type.startsWith('image/')) + if (!item) return + const file = item.getAsFile() + if (file) void uploadFile(file) + } + window.addEventListener('paste', onPaste) + return () => window.removeEventListener('paste', onPaste) + }, [isFormOpen]) + return ( {error && ( @@ -226,12 +241,17 @@ export default function CatalogueModal({ stores, onClose }: CatalogueModalProps) }}>📷 )} - +
+ + {!uploading && ( + ou Ctrl+V pour coller + )} +
{previewSrc && (