'use client'; import { useCallback, useRef, useState } from 'react'; import Image from 'next/image'; import { Palette, Maximize, Shield, ImagePlus, Square, Circle, RectangleHorizontal, Trash2, Upload, ChevronDown, ChevronUp, } from 'lucide-react'; import type { QRCustomization, ErrorCorrectionLevel, ModuleStyle } from '../lib/types'; interface CustomizationPanelProps { customization: QRCustomization; onCustomizationChange: (customization: QRCustomization) => void; } const EC_LEVELS: { value: ErrorCorrectionLevel; label: string; desc: string }[] = [ { value: 'L', label: 'L', desc: '7% correction' }, { value: 'M', label: 'M', desc: '15% correction' }, { value: 'Q', label: 'Q', desc: '25% correction' }, { value: 'H', label: 'H', desc: '30% correction' }, ]; const MODULE_STYLES: { value: ModuleStyle; label: string; icon: React.ReactNode }[] = [ { value: 'square', label: 'Carré', icon: }, { value: 'rounded', label: 'Arrondi', icon: }, { value: 'dots', label: 'Points', icon: }, ]; export default function CustomizationPanel({ customization, onCustomizationChange, }: CustomizationPanelProps) { const [isOpen, setIsOpen] = useState(true); const [isDragging, setIsDragging] = useState(false); const fileInputRef = useRef(null); const update = useCallback( (partial: Partial) => { onCustomizationChange({ ...customization, ...partial }); }, [customization, onCustomizationChange] ); const handleLogoUpload = useCallback( (file: File) => { if (!file.type.startsWith('image/')) return; const reader = new FileReader(); reader.onload = (e) => { update({ logoDataUrl: e.target?.result as string }); }; reader.readAsDataURL(file); }, [update] ); const handleDrop = useCallback( (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (file) handleLogoUpload(file); }, [handleLogoUpload] ); const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); }, []); const handleDragLeave = useCallback(() => { setIsDragging(false); }, []); return (
{isOpen && (
{/* Colors */}
update({ fgColor: e.target.value })} aria-label="Couleur du QR Code" className="absolute inset-0 w-full h-full cursor-pointer opacity-0" />
update({ fgColor: e.target.value })} aria-label="Code hexadécimal couleur QR" className="flex-1 px-3 py-2 text-xs rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white font-mono" />
update({ bgColor: e.target.value })} aria-label="Couleur de fond du QR Code" className="absolute inset-0 w-full h-full cursor-pointer opacity-0" />
update({ bgColor: e.target.value })} aria-label="Code hexadécimal couleur de fond" className="flex-1 px-3 py-2 text-xs rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-white font-mono" />
{/* Size slider */}
{customization.size}px
update({ size: parseInt(e.target.value) })} aria-label="Taille du QR Code en pixels" className="w-full accent-violet-600" />
{/* Error Correction Level */}
{EC_LEVELS.map((level) => ( ))}
{/* Module Style */}
{MODULE_STYLES.map((style) => ( ))}
{/* Corner Radius */}
{customization.cornerRadius}px
update({ cornerRadius: parseInt(e.target.value) })} aria-label="Rayon des coins arrondis en pixels" className="w-full accent-violet-600" />
{/* Logo Upload */}
{customization.logoDataUrl ? (
Logo
Logo ajouté
) : (
fileInputRef.current?.click()} className={`border-2 border-dashed rounded-xl p-6 text-center cursor-pointer transition-all ${ isDragging ? 'border-violet-500 bg-violet-50 dark:bg-violet-900/20' : 'border-gray-200 dark:border-gray-700 hover:border-violet-400 hover:bg-violet-50/50 dark:hover:bg-violet-900/10' }`} >

Glissez une image ou parcourir

PNG, JPG, SVG • Conseil : utilisez un niveau H

{ const file = e.target.files?.[0]; if (file) handleLogoUpload(file); }} className="hidden" />
)}
)}
); }