UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

694 lines (691 loc) 30.4 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import { useState, useRef, useCallback } from 'react'; import { GlassCore } from '../../primitives/GlassCore.js'; import '../../primitives/glass/GlassAdvanced.js'; import '../../primitives/OptimizedGlassCore.js'; import '../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../primitives/MotionNative.js'; import '../../primitives/motion/MotionFramer.js'; import { cn } from '../../lib/utilsComprehensive.js'; import { useImageProcessing } from './GlassImageProcessingProvider.js'; const ImageEditor = ({ image, onSave, onClose }) => { const { optimizeImage, applyFilter, cropImage, resizeImage, addWatermark, detectFaces, removeBackground, enhanceImage, smartCrop, templates, applyTemplate } = useImageProcessing(); const [activeTab, setActiveTab] = useState("basic"); const [isProcessing, setIsProcessing] = useState(false); const [filters, setFilters] = useState({ brightness: 0, contrast: 0, saturation: 0, hue: 0, blur: 0, sharpen: 0 }); const handleOptimize = async () => { setIsProcessing(true); try { const optimized = await optimizeImage(image.id, { quality: 85 }); onSave(optimized); } catch (error) { console.error("Optimization failed:", error); } finally { setIsProcessing(false); } }; const handleFilterChange = async (filterType, value) => { const newFilters = { ...filters, [filterType]: value }; setFilters(newFilters); try { await applyFilter(image.id, { [filterType]: value }); } catch (error) { console.error("Filter failed:", error); } }; const handleAIEnhance = async () => { setIsProcessing(true); try { const enhanced = await enhanceImage(image.id); onSave(enhanced); } catch (error) { console.error("AI enhancement failed:", error); } finally { setIsProcessing(false); } }; const handleRemoveBackground = async () => { setIsProcessing(true); try { const processed = await removeBackground(image.id); onSave(processed); } catch (error) { console.error("Background removal failed:", error); } finally { setIsProcessing(false); } }; const handleTemplateApply = async templateId => { setIsProcessing(true); try { const templated = await applyTemplate(image.id, templateId); onSave(templated); } catch (error) { console.error("Template application failed:", error); } finally { setIsProcessing(false); } }; return jsx("div", { "data-glass-component": true, className: 'fixed inset-0 z-50 glass-flex glass-items-center glass-justify-center glass-surface-dark bg-opacity-75', children: jsx(GlassCore, { className: 'glass-w-full max-w-6xl max-h-[90vh] glass-m-4 overflow-hidden', children: jsxs("div", { className: "glass-flex glass-h-full", children: [jsx("div", { className: "glass-flex-1 glass-flex glass-items-center glass-justify-center glass-surface-subtle glass-p-4", children: jsxs("div", { className: 'relative max-w-full max-h-full', children: [jsx("img", { src: image.url, alt: image.name, className: 'max-w-full max-h-full object-contain', ref: el => { if (el) el.style.maxHeight = "70vh"; } }), isProcessing && jsx("div", { className: 'absolute inset-0 glass-surface-dark glass-opacity-50 glass-flex glass-items-center glass-justify-center', children: jsxs("div", { className: "glass-surface-subtle glass-radius-lg glass-p-4 glass-flex glass-items-center glass-gap-3", children: [jsx("div", { className: 'animate-spin w-6 h-6 glass-border-2 glass-border-blue glass-border-t-transparent glass-radius-full' }), jsx("span", { children: "Processing..." })] }) })] }) }), jsxs("div", { className: 'w-80 glass-border-l glass-border-subtle glass-flex glass-flex-col', children: [jsxs("div", { className: "glass-p-4 glass-border-b glass-border-subtle", children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsx("h3", { className: 'glass-text-lg font-semibold', children: image.name }), jsx("button", { onClick: onClose, className: 'glass-text-secondary hover:glass-text-secondary glass-p-1 glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: "\u2715" })] }), jsxs("div", { className: "glass-text-sm glass-text-secondary glass-mt-1", children: [image.width, " \u00D7 ", image.height, " \u2022", " ", (image.size / 1024).toFixed(1), " KB"] })] }), jsx("div", { className: "glass-flex glass-border-b glass-border-subtle", children: [{ key: "basic", label: "Basic", icon: "⚙️" }, { key: "filters", label: "Filters", icon: "🎨" }, { key: "ai", label: "AI", icon: "🤖" }, { key: "templates", label: "Templates", icon: "📐" }].map(tab => jsxs("button", { onClick: () => setActiveTab(tab.key), className: cn("flex-1 flex items-center justify-center gap-1 py-3 text-sm font-medium glass-transition", activeTab === tab.key ? "glass-text-primary glass-border-b-2 glass-border glass-surface-primary/10" : "glass-text-secondary hover:glass-text-primary"), children: [jsx("span", { className: "glass-text-xs", children: tab.icon }), tab.label] }, tab.key)) }), jsxs("div", { className: 'glass-flex-1 overflow-y-auto glass-p-4', children: [activeTab === "basic" && jsxs("div", { className: 'space-y-4', children: [jsxs("div", { children: [jsx("h4", { className: 'font-medium mb-3', children: "Optimization" }), jsx("button", { onClick: handleOptimize, disabled: isProcessing, className: 'glass-w-full glass-py-2 glass-surface-blue text-primary glass-radius hover:glass-surface-blue disabled:opacity-50 transition-colors glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', "aria-label": "Run smart optimization", children: isProcessing ? "Optimizing..." : "Smart Optimize" }), jsx("p", { className: "glass-text-xs glass-text-secondary glass-mt-2", children: "Reduces file size while maintaining quality" })] }), jsxs("div", { children: [jsx("h4", { className: 'font-medium mb-3', children: "Quick Actions" }), jsxs("div", { className: 'space-y-2', children: [jsx("button", { className: 'glass-w-full glass-py-2 glass-border glass-border-subtle glass-radius hover:glass-surface-subtle transition-colors glass-focus', "aria-label": "Crop and resize image", children: "Crop & Resize" }), jsx("button", { className: 'glass-w-full glass-py-2 glass-border glass-border-subtle glass-radius hover:glass-surface-subtle transition-colors glass-focus', "aria-label": "Add watermark", children: "Add Watermark" }), jsx("button", { className: 'glass-w-full glass-py-2 glass-border glass-border-subtle glass-radius hover:glass-surface-subtle transition-colors', children: "Download" })] })] }), jsxs("div", { children: [jsx("h4", { className: 'font-medium mb-3', children: "Image Info" }), jsxs("div", { className: 'space-y-2 glass-text-sm', children: [jsxs("div", { className: "glass-flex glass-justify-between", children: [jsx("span", { className: "glass-text-secondary", children: "Format:" }), jsx("span", { children: image.metadata.format.toUpperCase() })] }), jsxs("div", { className: "glass-flex glass-justify-between", children: [jsx("span", { className: "glass-text-secondary", children: "Quality:" }), jsxs("span", { children: [image.metadata.quality, "%"] })] }), jsxs("div", { className: "glass-flex glass-justify-between", children: [jsx("span", { className: "glass-text-secondary", children: "Color Space:" }), jsx("span", { children: image.metadata.colorSpace })] }), jsxs("div", { className: "glass-flex glass-justify-between", children: [jsx("span", { className: "glass-text-secondary", children: "Has Alpha:" }), jsx("span", { children: image.metadata.hasAlpha ? "Yes" : "No" })] })] })] })] }), activeTab === "filters" && jsxs("div", { className: 'space-y-4', children: [jsx("h4", { className: 'font-medium mb-3', children: "Adjust Filters" }), Object.entries(filters).map(([key, value]) => jsxs("div", { children: [jsxs("div", { className: 'glass-flex glass-justify-between mb-2', children: [jsx("label", { className: 'glass-text-sm font-medium capitalize', children: key }), jsx("span", { className: "glass-text-sm glass-text-secondary", children: value })] }), jsx("input", { type: "range", min: key === "blur" || key === "sharpen" ? 0 : -100, max: key === "blur" || key === "sharpen" ? 10 : 100, value: value, onChange: e => handleFilterChange(key, Number(e.target.value)), className: "glass-w-full" })] }, key)), jsx("button", { onClick: () => setFilters({ brightness: 0, contrast: 0, saturation: 0, hue: 0, blur: 0, sharpen: 0 }), className: 'glass-w-full glass-py-2 glass-border glass-border-subtle glass-radius hover:glass-surface-subtle transition-colors', children: "Reset Filters" })] }), activeTab === "ai" && jsxs("div", { className: 'space-y-4', children: [jsx("h4", { className: 'font-medium mb-3', children: "AI-Powered Features" }), jsxs("div", { className: 'space-y-3', children: [jsxs("button", { onClick: handleAIEnhance, disabled: isProcessing, className: 'glass-w-full glass-py-3 glass-surface-primary text-primary glass-radius hover:glass-surface-subtle disabled:opacity-50 transition-colors glass-flex glass-items-center glass-justify-center glass-gap-2 glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: [jsx("span", { children: "\uD83E\uDD16" }), "AI Auto-Enhance"] }), jsxs("button", { onClick: handleRemoveBackground, disabled: isProcessing, className: 'glass-w-full glass-py-3 glass-surface-green text-primary glass-radius hover:glass-surface-green disabled:opacity-50 transition-colors glass-flex glass-items-center glass-justify-center glass-gap-2 glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: [jsx("span", { children: "\u2702\uFE0F" }), "Remove Background"] }), jsxs("button", { onClick: () => detectFaces(image.id), disabled: isProcessing, className: 'glass-w-full glass-py-3 glass-surface-primary text-primary glass-radius hover:glass-surface-subtle disabled:opacity-50 transition-colors glass-flex glass-items-center glass-justify-center glass-gap-2', children: [jsx("span", { children: "\uD83D\uDC64" }), "Detect Faces"] }), jsxs("button", { onClick: () => smartCrop(image.id, 1.0), disabled: isProcessing, className: 'glass-w-full glass-py-3 bg-indigo-600 text-primary glass-radius hover:bg-indigo-700 disabled:opacity-50 transition-colors glass-flex glass-items-center glass-justify-center glass-gap-2', children: [jsx("span", { children: "\uD83C\uDFAF" }), "Smart Crop"] })] }), jsxs("div", { className: "glass-surface-subtle glass-p-3 glass-radius-lg", children: [jsx("h5", { className: 'font-medium text-primary mb-1', children: "AI Insights" }), jsxs("p", { className: 'glass-text-sm text-primary', children: ["Dominant colors:", " ", image.metadata.dominantColors.slice(0, 3).join(", ")] }), jsxs("p", { className: 'glass-text-sm text-primary', children: ["Brightness: ", Math.round(image.metadata.brightness), "% \u2022 Contrast: ", Math.round(image.metadata.contrast), "%"] })] })] }), activeTab === "templates" && jsxs("div", { className: 'space-y-4', children: [jsx("h4", { className: 'font-medium mb-3', children: "Templates" }), jsx("div", { className: "glass-grid glass-grid-cols-2 glass-gap-3", children: templates.map(template => jsxs("button", { onClick: () => handleTemplateApply(template.id), disabled: isProcessing, className: 'glass-p-3 glass-border glass-border-subtle glass-radius-lg hover:border-blue hover:glass-surface-subtle transition-colors text-left disabled:opacity-50', children: [jsx("div", { className: 'glass-text-sm font-medium', children: template.name }), jsxs("div", { className: "glass-text-xs glass-text-secondary glass-mt-1", children: [template.width, " \u00D7 ", template.height] }), jsx("div", { className: 'glass-text-xs text-primary glass-mt-1 capitalize', children: template.category })] }, template.id)) })] })] }), jsxs("div", { className: "glass-p-4 glass-border-t glass-border-subtle glass-flex glass-gap-2", children: [jsx("button", { onClick: onClose, className: 'glass-flex-1 glass-py-2 glass-border glass-border-subtle glass-radius hover:glass-surface-subtle transition-colors glass-focus glass-touch-target glass-contrast-guard glass-focus glass-touch-target glass-contrast-guard', children: "Cancel" }), jsx("button", { onClick: () => onSave(image), className: 'glass-flex-1 glass-py-2 glass-surface-blue text-primary glass-radius hover:glass-surface-blue transition-colors', children: "Save Changes" })] })] })] }) }) }); }; const GlassIntelligentImageUploader = ({ className, maxFiles = 10, acceptedFormats = ["image/jpeg", "image/jpg", "image/png", "image/webp", "image/gif"], maxFileSize = 10, // MB showEditor = true, showOptimization = true, showTemplates = true, showAIFeatures = true, onImagesUploaded, onImageEdited }) => { const { images, addImages, removeImage, uploadProgresses, clearProgress, getOptimizationStats, autoOptimize } = useImageProcessing(); const [dragActive, setDragActive] = useState(false); const [selectedImage, setSelectedImage] = useState(null); const [showStats, setShowStats] = useState(false); const fileInputRef = useRef(null); const handleDragEnter = useCallback(e => { e.preventDefault(); e.stopPropagation(); setDragActive(true); }, []); const handleDragLeave = useCallback(e => { e.preventDefault(); e.stopPropagation(); setDragActive(false); }, []); const handleDragOver = useCallback(e => { e.preventDefault(); e.stopPropagation(); }, []); const handleDrop = useCallback(async e => { e.preventDefault(); e.stopPropagation(); setDragActive(false); const files = e.dataTransfer.files; if (files.length > 0) { await handleFiles(files); } }, []); const handleFiles = useCallback(async files => { const validFiles = Array.from(files).filter(file => { if (!acceptedFormats.includes(file.type)) { console.warn(`File ${file.name} has unsupported format`); return false; } if (file.size > maxFileSize * 1024 * 1024) { console.warn(`File ${file.name} exceeds size limit`); return false; } return true; }); if (validFiles.length === 0) return; const filesToProcess = validFiles.slice(0, maxFiles - images.length); const fileList = new DataTransfer(); filesToProcess.forEach(file => fileList.items.add(file)); try { const uploadedImages = await addImages(fileList.files); onImagesUploaded?.(uploadedImages); } catch (error) { console.error("Upload failed:", error); } }, [acceptedFormats, maxFileSize, maxFiles, images.length, addImages, onImagesUploaded]); const handleFileSelect = useCallback(async e => { if (e.target.files && e.target.files.length > 0) { await handleFiles(e.target.files); } }, [handleFiles]); const optimizationStats = getOptimizationStats(); return jsxs(GlassCore, { className: cn("p-6", className), children: [jsxs("div", { className: 'space-y-6', children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsxs("div", { children: [jsx("h2", { className: 'glass-text-xl font-semibold glass-text-secondary', children: "\uD83E\uDD16 Intelligent Image Uploader" }), jsx("p", { className: "glass-text-secondary glass-mt-1", children: "AI-powered image optimization and editing" })] }), showOptimization && jsx("button", { onClick: () => setShowStats(!showStats), className: 'glass-px-4 glass-py-2 glass-surface-subtle text-primary glass-radius-lg hover:glass-surface-subtle transition-colors', children: "\uD83D\uDCCA Stats" })] }), showStats && showOptimization && jsxs("div", { className: "glass-surface-subtle glass-border glass-border-green-200 glass-radius-lg glass-p-4", children: [jsx("h3", { className: 'font-medium text-primary mb-3', children: "Optimization Statistics" }), jsxs("div", { className: 'glass-grid glass-grid-cols-2 md:grid-cols-4 glass-gap-4 glass-text-sm', children: [jsxs("div", { className: 'text-center', children: [jsxs("div", { className: 'glass-text-2xl font-bold text-primary', children: [optimizationStats.totalSaved, "KB"] }), jsx("div", { className: 'text-primary', children: "Total Saved" })] }), jsxs("div", { className: 'text-center', children: [jsxs("div", { className: 'glass-text-2xl font-bold text-primary', children: [optimizationStats.averageReduction, "%"] }), jsx("div", { className: 'text-primary', children: "Avg. Reduction" })] }), jsxs("div", { className: 'text-center', children: [jsx("div", { className: 'glass-text-2xl font-bold text-primary', children: optimizationStats.imagesProcessed }), jsx("div", { className: 'text-primary', children: "Images Processed" })] }), jsxs("div", { className: 'text-center', children: [jsx("div", { className: 'glass-text-2xl font-bold text-primary', children: optimizationStats.mostUsedFormat }), jsx("div", { className: 'text-primary', children: "Most Used Format" })] })] })] }), jsxs("div", { className: cn("relative border-2 border-dashed rounded-lg p-12 text-center transition-colors", dragActive ? "border-blue-500 bg-blue-50" : "border-gray-300 hover:border-gray-400"), onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [jsxs("div", { className: 'space-y-4', children: [jsx("div", { className: 'text-6xl', children: "\uD83D\uDCF8" }), jsxs("div", { children: [jsx("h3", { className: 'glass-text-lg font-medium glass-text-secondary', children: "Drop images here or click to upload" }), jsxs("p", { className: "glass-text-secondary glass-mt-1", children: ["Supports JPEG, PNG, WebP, GIF up to ", maxFileSize, "MB each"] })] }), jsx("button", { onClick: () => fileInputRef.current?.click(), className: 'glass-px-6 glass-py-3 glass-surface-blue text-primary glass-radius-lg hover:glass-surface-blue transition-colors', children: "Choose Files" }), autoOptimize && jsxs("div", { className: 'glass-flex glass-items-center glass-justify-center glass-gap-2 glass-text-sm text-primary', children: [jsx("span", { children: "\u2705" }), jsx("span", { children: "Auto-optimization enabled" })] })] }), jsx("input", { ref: fileInputRef, type: "file", multiple: true, accept: acceptedFormats.join(","), onChange: handleFileSelect, className: 'hidden glass-touch-target glass-contrast-guard' })] }), uploadProgresses.length > 0 && jsxs("div", { className: 'space-y-3', children: [jsx("h3", { className: 'font-medium glass-text-secondary', children: "Processing Images" }), uploadProgresses.map(progress => jsxs("div", { className: 'space-y-2', children: [jsxs("div", { className: "glass-flex glass-justify-between glass-text-sm", children: [jsx("span", { children: progress.message || "Processing..." }), jsxs("span", { children: [progress.progress, "%"] })] }), jsx("div", { className: 'glass-w-full glass-surface-subtle glass-radius-full h-2', children: jsx("div", { className: cn("h-2 rounded-full transition-all", progress.status === "error" ? "bg-red-500" : "bg-blue-500"), ref: el => { if (el) el.style.width = `${progress.progress}%`; } }) })] }, progress.imageId))] }), images.length > 0 && jsxs("div", { className: 'space-y-4', children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsxs("h3", { className: 'font-medium glass-text-secondary', children: ["Uploaded Images (", images.length, ")"] }), images.length > 1 && jsxs("div", { className: "glass-flex glass-gap-2", children: [jsx("button", { className: 'glass-px-3 glass-py-1 glass-text-sm glass-surface-subtle text-primary glass-radius hover:glass-surface-subtle transition-colors', children: "Batch Optimize" }), jsx("button", { className: 'glass-px-3 glass-py-1 glass-text-sm glass-surface-subtle text-primary glass-radius hover:glass-surface-subtle transition-colors', children: "Batch Download" })] })] }), jsx("div", { className: 'glass-grid glass-grid-cols-2 md:grid-cols-3 lg:grid-cols-4 glass-gap-4', children: images.map(image => jsxs("div", { className: 'group relative', children: [jsx("div", { className: 'aspect-square glass-surface-subtle glass-radius-lg overflow-hidden', children: jsx("img", { src: image.url, alt: image.name, className: 'glass-w-full glass-h-full object-cover group-hover:scale-105 transition-transform' }) }), jsx("div", { className: 'absolute inset-0 glass-surface-dark bg-opacity-0 group-hover:glass-opacity-50 transition-opacity glass-radius-lg glass-flex glass-items-center glass-justify-center', children: jsxs("div", { className: 'opacity-0 group-hover:opacity-100 transition-opacity glass-flex glass-gap-2', children: [showEditor && jsx("button", { onClick: () => setSelectedImage(image), className: 'glass-p-2 glass-surface-subtle glass-radius-full glass-text-secondary hover:text-primary transition-colors', title: "Edit Image", children: "\u270F\uFE0F" }), jsx("button", { onClick: () => removeImage(image.id), className: 'glass-p-2 glass-surface-subtle glass-radius-full glass-text-secondary hover:text-primary transition-colors', title: "Remove Image", children: "\uD83D\uDDD1\uFE0F" })] }) }), jsxs("div", { className: 'mt-2 glass-text-xs glass-text-secondary', children: [jsx("div", { className: 'truncate font-medium', children: image.name }), jsxs("div", { children: [image.width, " \u00D7 ", image.height, " \u2022", " ", (image.size / 1024).toFixed(1), "KB"] }), image.optimizedAt && jsx("div", { className: 'text-primary', children: "\u2705 Optimized" })] })] }, image.id)) })] }), showAIFeatures && jsxs("div", { className: 'glass-grid glass-grid-cols-1 md:grid-cols-3 glass-gap-4', children: [jsxs("div", { className: 'text-center glass-p-4 glass-surface-subtle glass-radius-lg', children: [jsx("div", { className: 'glass-text-2xl mb-2', children: "\uD83E\uDD16" }), jsx("h3", { className: 'font-medium text-primary', children: "AI Enhancement" }), jsx("p", { className: 'glass-text-sm text-primary glass-mt-1', children: "Automatic brightness, contrast, and sharpness optimization" })] }), jsxs("div", { className: 'text-center glass-p-4 glass-surface-subtle glass-radius-lg', children: [jsx("div", { className: 'glass-text-2xl mb-2', children: "\u2702\uFE0F" }), jsx("h3", { className: 'font-medium text-primary', children: "Smart Tools" }), jsx("p", { className: 'glass-text-sm text-primary glass-mt-1', children: "Background removal, face detection, and smart cropping" })] }), jsxs("div", { className: 'text-center glass-p-4 glass-surface-subtle glass-radius-lg', children: [jsx("div", { className: 'glass-text-2xl mb-2', children: "\u26A1" }), jsx("h3", { className: 'font-medium text-primary', children: "Optimization" }), jsx("p", { className: 'glass-text-sm text-primary glass-mt-1', children: "Reduce file sizes by up to 80% while maintaining quality" })] })] })] }), selectedImage && showEditor && jsx(ImageEditor, { image: selectedImage, onSave: editedImage => { onImageEdited?.(editedImage); setSelectedImage(null); }, onClose: () => setSelectedImage(null) })] }); }; export { GlassIntelligentImageUploader }; //# sourceMappingURL=GlassIntelligentImageUploader.js.map