UNPKG

aura-glass

Version:

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

620 lines (617 loc) 25.5 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import { useReducedMotion } from '../../hooks/useReducedMotion.js'; import { motion } from 'framer-motion'; import { forwardRef, useState, useRef, useCallback, useEffect } from 'react'; import { useMotionPreference } from '../../hooks/useMotionPreference.js'; import '../../primitives/GlassCore.js'; import '../../primitives/glass/GlassAdvanced.js'; import { OptimizedGlassCore } from '../../primitives/OptimizedGlassCore.js'; import '../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../primitives/MotionNative.js'; import '../../primitives/motion/MotionFramer.js'; import { useA11yId } from '../../utils/a11y.js'; import { createGlassStyle } from '../../utils/createGlassStyle.js'; import { useGlassSound } from '../../utils/soundDesign.js'; const defaultPromptSuggestions = [{ id: "cosmic-abstract", text: "Cosmic abstract painting with swirling galaxies and nebulae in vibrant colors", style: "abstract expressionism", category: "abstract", tags: ["space", "cosmic", "vibrant", "swirling"] }, { id: "cyberpunk-city", text: "Cyberpunk cityscape at night with neon lights reflecting on wet streets", style: "digital art", category: "architecture", tags: ["cyberpunk", "neon", "city", "night"] }, { id: "ethereal-portrait", text: "Ethereal portrait of a person made of flowing light and energy", style: "digital painting", category: "portrait", tags: ["ethereal", "light", "energy", "flowing"] }, { id: "surreal-landscape", text: "Surreal landscape with floating islands and impossible waterfalls", style: "surrealism", category: "landscape", tags: ["surreal", "floating", "impossible", "waterfalls"] }, { id: "biomech-fusion", text: "Biomechanical fusion of organic forms and technological components", style: "biomechanical art", category: "surreal", tags: ["biomechanical", "organic", "technology", "fusion"] }]; const stylePresets = ["photorealistic", "oil painting", "watercolor", "digital art", "abstract expressionism", "impressionism", "cyberpunk", "steampunk", "art nouveau", "minimalist", "baroque", "surrealism"]; const GlassGenerativeArt = /*#__PURE__*/forwardRef(({ prompt = "", suggestions = defaultPromptSuggestions, generationSettings = {}, showPromptLibrary = true, showAdvancedSettings = true, showGenerationHistory = true, enableIterativeGeneration = true, enablePromptEnhancement = true, enableStyleMixing = false, realTimeGeneration = false, onPromptChange, onGenerate, onImageGenerated, className = "", ...props }, ref) => { const prefersReducedMotion = useReducedMotion(); const [currentPrompt, setCurrentPrompt] = useState(prompt); const [isGenerating, setIsGenerating] = useState(false); const [generationProgress, setGenerationProgress] = useState(0); const [enablePromptEnhancementState, setEnablePromptEnhancementState] = useState(enablePromptEnhancement); const [generatedImages, setGeneratedImages] = useState([]); const [generationHistory, setGenerationHistory] = useState([]); const [settings, setSettings] = useState({ model: "stable-diffusion", style: "photorealistic", resolution: "768x768", steps: 25, guidance: 7.5, iterations: 1, ...generationSettings }); const canvasRef = useRef(null); useA11yId("glass-generative-art"); const { shouldAnimate } = useMotionPreference(); const { play } = useGlassSound(); // Enhanced prompt generation const enhancePrompt = useCallback(basePrompt => { const enhancementPhrases = ["highly detailed", "professional quality", "studio lighting", "8k resolution", "masterpiece", "trending on artstation", "photorealistic", "cinematic composition"]; const randomEnhancements = enhancementPhrases.sort(() => Math.random() - 0.5).slice(0, 3).join(", "); return `${basePrompt}, ${randomEnhancements}, ${settings.style} style`; }, [settings.style]); // Generate art simulation const generateArt = useCallback(async promptText => { if (!promptText.trim()) return; setIsGenerating(true); setGenerationProgress(0); play("processing"); const enhancedPrompt = enablePromptEnhancement ? enhancePrompt(promptText) : promptText; // Simulate generation steps const steps = [{ label: "Initializing model...", duration: 300 }, { label: "Processing prompt...", duration: 500 }, { label: "Generating base composition...", duration: 1000 }, { label: "Adding details...", duration: 1500 }, { label: "Applying style...", duration: 800 }, { label: "Refining image...", duration: 700 }, { label: "Finalizing...", duration: 400 }]; for (let i = 0; i < steps.length; i++) { await new Promise(resolve => setTimeout(resolve, steps[i].duration)); setGenerationProgress((i + 1) / steps.length * 100); } // Generate multiple iterations if requested const newImages = []; for (let i = 0; i < settings.iterations; i++) { const canvas = canvasRef.current; if (canvas) { const ctx = canvas.getContext("2d"); if (ctx) { // Create unique generative art based on prompt canvas.width = 512; canvas.height = 512; // Background based on prompt category const promptLower = promptText.toLowerCase(); let bgGradient; if (promptLower.includes("space") || promptLower.includes("cosmic")) { bgGradient = ctx.createRadialGradient(256, 256, 0, 256, 256, 400); bgGradient.addColorStop(0, "#1a1a2e"); bgGradient.addColorStop(0.5, "#16213e"); bgGradient.addColorStop(1, "#0f3460"); } else if (promptLower.includes("cyberpunk") || promptLower.includes("neon")) { bgGradient = ctx.createLinearGradient(0, 0, 512, 512); bgGradient.addColorStop(0, "#0a0a0a"); bgGradient.addColorStop(0.5, "#1a0f2e"); bgGradient.addColorStop(1, "#2d1b69"); } else if (promptLower.includes("nature") || promptLower.includes("landscape")) { bgGradient = ctx.createLinearGradient(0, 0, 0, 512); bgGradient.addColorStop(0, "#87ceeb"); bgGradient.addColorStop(0.7, "#98fb98"); bgGradient.addColorStop(1, "#228b22"); } else { bgGradient = ctx.createLinearGradient(0, 0, 512, 512); bgGradient.addColorStop(0, "#667eea"); bgGradient.addColorStop(1, "#764ba2"); } ctx.fillStyle = bgGradient; ctx.fillRect(0, 0, 512, 512); // Add generative elements based on style if (settings.style.includes("abstract")) { // Abstract shapes and forms for (let j = 0; j < 15; j++) { ctx.save(); ctx.translate(Math.random() * 512, Math.random() * 512); ctx.rotate(Math.random() * Math.PI * 2); const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 50 + Math.random() * 100); gradient.addColorStop(0, `hsla(${Math.random() * 360}, 70%, 60%, 0.8)`); gradient.addColorStop(1, `hsla(${Math.random() * 360}, 50%, 40%, 0.3)`); ctx.fillStyle = gradient; ctx.beginPath(); ctx.ellipse(0, 0, Math.random() * 80 + 20, Math.random() * 120 + 30, 0, 0, Math.PI * 2); ctx.fill(); ctx.restore(); } } else if (settings.style.includes("geometric")) { // Geometric patterns for (let j = 0; j < 20; j++) { ctx.save(); ctx.translate(Math.random() * 512, Math.random() * 512); ctx.rotate(Math.random() * Math.PI * 2); ctx.strokeStyle = `hsla(${Math.random() * 360}, 60%, 50%, 0.7)`; ctx.lineWidth = Math.random() * 3 + 1; ctx.beginPath(); const size = Math.random() * 60 + 20; ctx.rect(-size / 2, -size / 2, size, size); ctx.stroke(); ctx.restore(); } } else if (promptLower.includes("particle") || settings.style.includes("digital")) { // Particle effects for (let j = 0; j < 100; j++) { ctx.fillStyle = `hsla(${Math.random() * 60 + 180}, 80%, 60%, ${Math.random() * 0.8 + 0.2})`; ctx.beginPath(); ctx.arc(Math.random() * 512, Math.random() * 512, Math.random() * 3 + 1, 0, Math.PI * 2); ctx.fill(); } } // Add texture overlay const imageData = ctx.getImageData(0, 0, 512, 512); const data = imageData.data; for (let j = 0; j < data.length; j += 4) { const noise = (Math.random() - 0.5) * 20; data[j] = Math.max(0, Math.min(255, data[j] + noise)); data[j + 1] = Math.max(0, Math.min(255, data[j + 1] + noise)); data[j + 2] = Math.max(0, Math.min(255, data[j + 2] + noise)); } ctx.putImageData(imageData, 0, 0); const imageUrl = canvas.toDataURL("image/png"); newImages.push(imageUrl); } } } setGeneratedImages(prev => [...newImages, ...prev].slice(0, 12)); // Add to history const historyEntry = { id: Date.now().toString(), prompt: enhancedPrompt, imageUrl: newImages[0] || "", settings: { ...settings }, timestamp: Date.now() }; setGenerationHistory(prev => [historyEntry, ...prev].slice(0, 20)); setIsGenerating(false); play("success"); if (newImages[0]) { onImageGenerated?.(newImages[0], historyEntry); } }, [settings, enablePromptEnhancement, enhancePrompt, onImageGenerated, play]); // Handle prompt changes useEffect(() => { if (realTimeGeneration && currentPrompt && currentPrompt !== prompt) { const debounceTimer = setTimeout(() => { generateArt(currentPrompt); }, 2000); return () => clearTimeout(debounceTimer); } }, [currentPrompt, realTimeGeneration, generateArt, prompt]); const PromptLibrary = () => jsxs("div", { className: 'space-y-4', children: [jsx("h4", { className: 'glass-text-sm font-medium text-primary/80', children: "Prompt Library" }), jsx("div", { className: "glass-grid glass-gap-2", children: suggestions.map(suggestion => jsx(motion.div, { className: 'glass-p-3 glass-radius-lg glass-border glass-border-white/20 hover:border-white/40 glass-surface-subtle/5 cursor-pointer transition-colors', whileHover: shouldAnimate ? { scale: 1.01 } : {}, onClick: () => { setCurrentPrompt(suggestion.text); onPromptChange?.(suggestion.text); play("select"); }, children: jsx("div", { className: "glass-flex glass-items-start glass-justify-between", children: jsxs("div", { className: "glass-flex-1", children: [jsx("p", { className: 'glass-text-sm text-primary/90 mb-1', children: suggestion.text }), jsxs("div", { className: 'glass-flex glass-items-center space-x-2', children: [jsx("span", { className: ` px-2 py-0.5 rounded text-xs font-medium ${suggestion.category === "abstract" ? "bg-purple-500/20 text-purple-300" : suggestion.category === "landscape" ? "bg-green-500/20 text-green-300" : suggestion.category === "portrait" ? "bg-blue-500/20 text-blue-300" : suggestion.category === "architecture" ? "bg-gray-500/20 text-gray-300" : suggestion.category === "nature" ? "bg-emerald-500/20 text-emerald-300" : "bg-pink-500/20 text-pink-300"} `, children: suggestion.category }), suggestion.tags.slice(0, 2).map(tag => jsx("span", { className: 'glass-px-1.5 glass-py-0.5 glass-surface-subtle/10 text-primary/60 glass-radius glass-text-xs', children: tag }, tag))] })] }) }) }, suggestion.id)) })] }); const AdvancedSettings = () => jsxs("div", { className: 'space-y-4', children: [jsx("h4", { className: 'glass-text-sm font-medium text-primary/80', children: "Generation Settings" }), jsxs("div", { className: 'glass-grid glass-grid-cols-1 md:grid-cols-2 glass-gap-4', children: [jsxs("div", { children: [jsx("label", { className: 'block glass-text-xs text-primary/70 mb-2', children: "Model" }), jsxs("select", { value: settings.model, onChange: e => setSettings(prev => ({ ...prev, model: e.target.value })), className: 'glass-w-full glass-p-2 glass-surface-subtle/10 glass-border glass-border-white/20 glass-radius-lg text-primary/90 glass-text-sm', children: [jsx("option", { value: "stable-diffusion", children: "Stable Diffusion" }), jsx("option", { value: "midjourney", children: "Midjourney" }), jsx("option", { value: "dall-e", children: "DALL-E" }), jsx("option", { value: "custom", children: "Custom Model" })] })] }), jsxs("div", { children: [jsx("label", { className: 'block glass-text-xs text-primary/70 mb-2', children: "Style" }), jsx("select", { value: settings.style, onChange: e => setSettings(prev => ({ ...prev, style: e.target.value })), className: 'glass-w-full glass-p-2 glass-surface-subtle/10 glass-border glass-border-white/20 glass-radius-lg text-primary/90 glass-text-sm', children: stylePresets.map(style => jsx("option", { value: style, children: style.charAt(0).toUpperCase() + style.slice(1) }, style)) })] }), jsxs("div", { children: [jsx("label", { className: 'block glass-text-xs text-primary/70 mb-2', children: "Resolution" }), jsxs("select", { value: settings.resolution, onChange: e => setSettings(prev => ({ ...prev, resolution: e.target.value })), className: 'glass-w-full glass-p-2 glass-surface-subtle/10 glass-border glass-border-white/20 glass-radius-lg text-primary/90 glass-text-sm', children: [jsx("option", { value: "512x512", children: "512 \u00D7 512" }), jsx("option", { value: "768x768", children: "768 \u00D7 768" }), jsx("option", { value: "1024x1024", children: "1024 \u00D7 1024" }), jsx("option", { value: "1920x1080", children: "1920 \u00D7 1080" })] })] }), jsxs("div", { children: [jsxs("label", { className: 'block glass-text-xs text-primary/70 mb-2', children: ["Iterations: ", settings.iterations] }), jsx("input", { type: "range", min: "1", max: "4", value: settings.iterations, onChange: e => setSettings(prev => ({ ...prev, iterations: parseInt(e.target.value) })), className: 'glass-w-full h-2 glass-surface-subtle/20 glass-radius-lg appearance-none cursor-pointer' })] }), jsxs("div", { children: [jsxs("label", { className: 'block glass-text-xs text-primary/70 mb-2', children: ["Steps: ", settings.steps] }), jsx("input", { type: "range", min: "10", max: "50", value: settings.steps, onChange: e => setSettings(prev => ({ ...prev, steps: parseInt(e.target.value) })), className: 'glass-w-full h-2 glass-surface-subtle/20 glass-radius-lg appearance-none cursor-pointer' })] }), jsxs("div", { children: [jsxs("label", { className: 'block glass-text-xs text-primary/70 mb-2', children: ["Guidance: ", settings.guidance] }), jsx("input", { type: "range", min: "1", max: "20", step: "0.5", value: settings.guidance, onChange: e => setSettings(prev => ({ ...prev, guidance: parseFloat(e.target.value) })), className: 'glass-w-full h-2 glass-surface-subtle/20 glass-radius-lg appearance-none cursor-pointer' })] })] })] }); return jsxs(OptimizedGlassCore, { ref: ref, variant: "frosted", className: `p-6 space-y-6 ${className}`, ...props, children: [jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsxs("div", { children: [jsx("h3", { className: 'glass-text-xl font-semibold text-primary/90', children: "AI Art Generator" }), jsx("p", { className: 'glass-text-sm text-primary/60', children: "Create stunning AI-generated artwork from text prompts" })] }), jsxs("div", { className: 'glass-flex glass-items-center space-x-2', children: [realTimeGeneration && jsxs("div", { className: 'glass-flex glass-items-center space-x-1 text-primary', children: [jsx("div", { className: 'w-2 h-2 glass-surface-green glass-radius-full animate-pulse' }), jsx("span", { className: "glass-text-xs", children: "Live" })] }), isGenerating && jsxs("div", { className: 'glass-flex glass-items-center space-x-1 text-primary', children: [jsx("div", { className: 'w-4 h-4 glass-border-2 glass-border-blue glass-border-t-transparent glass-radius-full animate-spin' }), jsx("span", { className: "glass-text-xs", children: "Generating" })] })] })] }), jsxs("div", { className: 'space-y-4', children: [jsxs("div", { children: [jsx("label", { className: 'block glass-text-sm font-medium text-primary/80 mb-2', children: "Describe your artwork" }), jsx("textarea", { value: currentPrompt, onChange: e => { setCurrentPrompt(e.target.value); onPromptChange?.(e.target.value); }, placeholder: "A majestic dragon soaring through a cosmic nebula, digital art style, highly detailed...", className: 'glass-w-full h-24 glass-p-3 glass-surface-subtle/10 glass-border glass-border-white/20 glass-radius-lg text-primary/90 placeholder-white/50 resize-none focus:outline-none focus:border-blue' })] }), jsxs("div", { className: "glass-flex glass-items-center glass-justify-between", children: [jsx("div", { className: 'glass-flex glass-items-center space-x-4', children: jsxs("label", { className: 'glass-flex glass-items-center space-x-2 cursor-pointer', children: [jsx("input", { type: "checkbox", checked: enablePromptEnhancementState, onChange: e => setEnablePromptEnhancementState(e.target.checked), className: 'w-4 h-4 glass-radius glass-border-white/30' }), jsx("span", { className: 'glass-text-sm text-primary/80', children: "Enhance Prompt" })] }) }), jsx(motion.button, { className: 'glass-px-6 glass-py-2 glass-surface-blue hover:glass-surface-blue text-primary glass-radius-lg font-medium transition-colors disabled:opacity-50', whileHover: shouldAnimate ? { scale: 1.02 } : {}, whileTap: shouldAnimate ? { scale: 0.98 } : {}, onClick: () => generateArt(currentPrompt), disabled: isGenerating || !currentPrompt.trim(), children: isGenerating ? "Generating..." : "Generate Art" })] })] }), isGenerating && jsxs("div", { className: ` p-3 rounded-lg border border-blue-400/30 ${createGlassStyle({ blur: "sm", opacity: 0.8 }).background} `, children: [jsxs("div", { className: 'glass-flex glass-items-center glass-justify-between mb-2', children: [jsx("span", { className: 'glass-text-sm text-primary/80', children: "Generating artwork..." }), jsxs("span", { className: 'glass-text-sm font-medium text-primary', children: [Math.round(generationProgress), "%"] })] }), jsx("div", { className: 'glass-w-full glass-surface-subtle/20 glass-radius-full h-2', children: jsx(motion.div, { className: 'glass-surface-blue h-2 glass-radius-full', animate: { width: `${generationProgress}%` }, transition: prefersReducedMotion ? { duration: 0 } : { duration: 0.3 } }) })] }), generatedImages.length > 0 && jsxs("div", { className: 'space-y-4', children: [jsx("h4", { className: 'glass-text-sm font-medium text-primary/80', children: "Generated Artwork" }), jsx("div", { className: 'glass-grid glass-grid-cols-2 md:grid-cols-3 lg:grid-cols-4 glass-gap-4', children: generatedImages.map((imageUrl, index) => jsxs(motion.div, { className: 'relative aspect-square glass-radius-lg overflow-hidden glass-surface-subtle/10 group cursor-pointer', whileHover: shouldAnimate ? { scale: 1.02 } : {}, initial: { opacity: 0, scale: 0.9 }, animate: prefersReducedMotion ? {} : { opacity: 1, scale: 1 }, transition: prefersReducedMotion ? { duration: 0 } : { duration: 0.3 }, children: [jsx("img", { src: imageUrl, alt: `Generated art ${index + 1}`, className: 'glass-w-full glass-h-full object-cover' }), jsx("div", { className: 'absolute inset-0 glass-surface-dark/50 opacity-0 group-hover:opacity-100 transition-opacity glass-flex glass-items-center glass-justify-center', children: jsx("button", { className: 'glass-p-2 glass-surface-subtle/20 glass-radius-lg text-primary hover:glass-surface-subtle/30 transition-colors', children: jsx("svg", { className: 'w-5 h-5', fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" }) }) }) })] }, index)) })] }), jsxs("div", { className: 'glass-grid glass-grid-cols-1 lg:grid-cols-2 glass-gap-6', children: [showPromptLibrary && jsx(PromptLibrary, {}), showAdvancedSettings && jsx(AdvancedSettings, {})] }), showGenerationHistory && generationHistory.length > 0 && jsxs("div", { className: 'space-y-4', children: [jsx("h4", { className: 'glass-text-sm font-medium text-primary/80', children: "Recent Generations" }), jsx("div", { className: 'space-y-2 glass-max-h-64 overflow-y-auto', children: generationHistory.map(entry => jsxs("div", { className: 'glass-flex glass-items-center space-x-3 glass-p-2 glass-radius-lg glass-surface-subtle/5 hover:glass-surface-subtle/10 cursor-pointer transition-colors', onClick: () => { setCurrentPrompt(entry.prompt); onPromptChange?.(entry.prompt); }, children: [jsx("img", { src: entry.imageUrl, alt: "Generated", className: 'w-12 h-12 glass-radius object-cover' }), jsxs("div", { className: "glass-flex-1 glass-min-w-0", children: [jsx("p", { className: 'glass-text-sm text-primary/90 truncate', children: entry.prompt }), jsxs("div", { className: 'glass-flex glass-items-center space-x-2 mt-1', children: [jsx("span", { className: 'glass-text-xs text-primary/60', children: entry.settings.model }), jsx("span", { className: 'glass-text-xs text-primary/60', children: entry.settings.resolution }), jsx("span", { className: 'glass-text-xs text-primary/60', children: new Date(entry.timestamp).toLocaleDateString() })] })] })] }, entry.id)) })] }), jsx("canvas", { ref: canvasRef, className: 'hidden' })] }); }); GlassGenerativeArt.displayName = "GlassGenerativeArt"; export { GlassGenerativeArt }; //# sourceMappingURL=GlassGenerativeArt.js.map