From 568fe0d38ef632673cf9badcfef017524fcd9314 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Mon, 8 Jun 2026 17:45:22 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20composants=20Lightbox=20plein=20=C3=A9c?= =?UTF-8?q?ran=20+=20GlobalActions=20barre=20d'upload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/images/GlobalActions.tsx | 37 +++++++++++++ src/components/images/Lightbox.tsx | 70 +++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/components/images/GlobalActions.tsx create mode 100644 src/components/images/Lightbox.tsx diff --git a/src/components/images/GlobalActions.tsx b/src/components/images/GlobalActions.tsx new file mode 100644 index 0000000..349e535 --- /dev/null +++ b/src/components/images/GlobalActions.tsx @@ -0,0 +1,37 @@ +'use client' +import type { ImageItem } from '@/types/images' + +interface GlobalActionsProps { + items: ImageItem[] + onUploadAll: () => void +} + +export function GlobalActions({ items, onUploadAll }: GlobalActionsProps) { + if (items.length === 0) return null + + const ready = items.filter((i) => i.status === 'ready').length + const processing = items.filter((i) => ['pending', 'converting', 'processing', 'searching'].includes(i.status)).length + const notFound = items.filter((i) => i.status === 'not_found').length + const uploaded = items.filter((i) => i.status === 'uploaded').length + const errors = items.filter((i) => i.status === 'error').length + + return ( +
+
+ {processing > 0 && ⏳ {processing} en traitement} + {ready > 0 && ✓ {ready} prêtes} + {notFound > 0 && ❌ {notFound} introuvables} + {errors > 0 && ⚠️ {errors} erreurs} + {uploaded > 0 && ✅ {uploaded} uploadées} +
+ {ready > 0 && ( + + )} +
+ ) +} diff --git a/src/components/images/Lightbox.tsx b/src/components/images/Lightbox.tsx new file mode 100644 index 0000000..3edf437 --- /dev/null +++ b/src/components/images/Lightbox.tsx @@ -0,0 +1,70 @@ +'use client' +import { useEffect, useState } from 'react' +import type { ImageItem } from '@/types/images' + +interface LightboxProps { + item: ImageItem | null + onClose: () => void +} + +function BlobImg({ blob, alt }: { blob: Blob; alt: string }) { + const [url, setUrl] = useState(null) + + useEffect(() => { + const u = URL.createObjectURL(blob) + setUrl(u) + return () => URL.revokeObjectURL(u) + }, [blob]) + + if (!url) return null + return {alt} +} + +export function Lightbox({ item, onClose }: LightboxProps) { + useEffect(() => { + const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } + document.addEventListener('keydown', onKey) + return () => document.removeEventListener('keydown', onKey) + }, [onClose]) + + if (!item) return null + + return ( +
+
e.stopPropagation()} + > +
+
+ {item.ref} + {item.shopifyProductTitle && ( + {item.shopifyProductTitle} + )} +
+ +
+ +
+
+

Avant

+ +
+
+

Après

+ {item.processedBlob + ? + :

Traitement en cours…

+ } +
+
+
+
+ ) +}