🐳 19/05 - 17:17 - I want you to go through every page, and I want you to add smooth transitions and interactive elements and better looking elements as well as 3D elements and designs. As well as Exp
b94499a verified | <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Generator — NSFWStudio</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/lucide@latest"></script> | |
| <script src="https://unpkg.com/react@18/umd/react.development.js"></script> | |
| <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> | |
| <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300..800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet"> | |
| <script> | |
| tailwind.config = { theme: { extend: { fontFamily: { sans: ['Inter','system-ui','sans-serif'], mono: ['JetBrains Mono','monospace'] }, colors: { bg: 'oklch(0.07 0.006 285)', surface: 'oklch(0.12 0.02 285)', 'surface-2': 'oklch(0.16 0.025 285)', 'surface-3': 'oklch(0.20 0.028 285)', fg: 'oklch(0.97 0.005 285)', muted: 'oklch(0.55 0.02 285)', primary: 'oklch(0.70 0.28 350)', 'primary-foreground': 'oklch(0.98 0.005 285)', secondary: 'oklch(0.75 0.15 215)', accent: 'oklch(0.80 0.18 85)', border: 'oklch(0.22 0.02 285)', ring: 'oklch(0.70 0.28 350)', destructive: 'oklch(0.55 0.22 25)', success: 'oklch(0.65 0.2 145)' } } } } | |
| </script> | |
| <style> | |
| body { background-color: oklch(0.07 0.006 285); color: oklch(0.97 0.005 285); font-family: 'Inter', system-ui, sans-serif; -webkit-font-smoothing: antialiased; } | |
| .glass { background: oklch(0.14 0.015 285 / 0.6); backdrop-filter: blur(24px) saturate(1.2); -webkit-backdrop-filter: blur(24px) saturate(1.2); border: 1px solid oklch(0.25 0.02 285 / 0.5); } | |
| ::selection { background: oklch(0.70 0.28 350 / 0.3); } | |
| body::after { content:''; position:fixed; inset:0; pointer-events:none; z-index:9999; opacity:0.025; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); background-repeat:repeat; background-size:256px 256px; } | |
| .no-scrollbar::-webkit-scrollbar { display: none; } .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; } | |
| .card-3d { transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.4s ease; } | |
| .card-3d:hover { transform: perspective(1000px) rotateY(-3deg) rotateX(2deg) translateZ(15px); box-shadow: 0 20px 40px rgba(0,0,0,0.35); } | |
| .hover-lift { transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.3s ease; } | |
| .hover-lift:hover { transform: translateY(-4px) scale(1.02); box-shadow: 0 12px 24px rgba(0,0,0,0.3); } | |
| @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } | |
| @keyframes pulse-glow { 0%, 100% { box-shadow: 0 0 20px oklch(0.70 0.28 350 / 0.2); } 50% { box-shadow: 0 0 40px oklch(0.70 0.28 350 / 0.4); } } | |
| .generating-glow { animation: pulse-glow 2s ease-in-out infinite; } | |
| @keyframes morph-bg { 0%, 100% { border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%; } 50% { border-radius: 30% 60% 70% 40% / 50% 60% 30% 60%; } } | |
| </style> | |
| </head> | |
| <body class="antialiased"> | |
| <div id="root"></div> | |
| <script type="text/babel"> | |
| const { useState } = React; | |
| const Icon = ({ name, size = 20, className = "", strokeWidth = 2 }) => { | |
| const ref = React.useRef(null); | |
| React.useEffect(() => { if (ref.current) { const existing = ref.current.querySelector('svg'); if (existing) existing.remove(); const svg = lucide.createElement(lucide.icons[name]); if (svg) { svg.setAttribute('width',size); svg.setAttribute('height',size); svg.setAttribute('stroke-width',strokeWidth); ref.current.appendChild(svg); } } }, [name, size, className, strokeWidth]); | |
| return <span ref={ref} className={`inline-flex items-center justify-center ${className}`} style={{ width: size, height: size }} />; | |
| }; | |
| const navItems = [ | |
| { name: 'Dashboard', icon: 'layout-dashboard', href: 'dashboard.html' }, | |
| { name: 'Generator', icon: 'sparkles', href: 'generator.html', active: true }, | |
| { name: 'Playground', icon: 'code', href: 'playground.html' }, | |
| { name: 'Models', icon: 'box', href: 'models.html' }, | |
| { name: 'Workflows', icon: 'workflow', href: 'workflows.html' }, | |
| { name: 'Marketplace', icon: 'shopping-bag', href: 'marketplace.html' }, | |
| { name: 'API Keys', icon: 'key', href: 'api-keys.html' }, | |
| { divider: true }, | |
| { name: 'Profile', icon: 'user', href: 'profile.html' }, | |
| { name: 'Settings', icon: 'settings', href: 'settings.html' }, | |
| ]; | |
| const Sidebar = ({ isOpen, setIsOpen }) => ( | |
| <> | |
| <div className={`fixed inset-0 z-40 lg:hidden transition-all ${isOpen ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}> | |
| <div className="absolute inset-0 bg-black/60 backdrop-blur-sm" onClick={() => setIsOpen(false)} /> | |
| </div> | |
| <aside className={`fixed top-0 left-0 bottom-0 z-50 w-64 bg-surface border-r border-border flex flex-col transition-transform duration-300 lg:translate-x-0 ${isOpen ? 'translate-x-0' : '-translate-x-full'}`}> | |
| <div className="p-4 flex items-center gap-2.5 border-b border-border"><div className="w-8 h-8 rounded-lg bg-primary flex items-center justify-center"><Icon name="sparkles" size={16} className="text-primary-foreground" /></div><span className="text-lg font-bold tracking-tight">NSFW<span className="text-muted">Studio</span></span></div> | |
| <nav className="flex-1 p-3 space-y-1 overflow-y-auto no-scrollbar">{navItems.map((item, i) => item.divider ? <div key={i} className="my-3 border-t border-border" /> : <a key={i} href={item.href} className={`flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium transition-colors ${item.active ? 'bg-primary/10 text-primary border border-primary/20' : 'text-muted hover:text-fg hover:bg-surface-2 border border-transparent'}`}><Icon name={item.icon} size={18} />{item.name}</a>)}</nav> | |
| <div className="p-4 border-t border-border"><a href="documentation.html" className="flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm text-muted hover:text-fg hover:bg-surface-2 transition-colors"><Icon name="book-open" size={18} />Documentation</a><a href="api-reference.html" className="flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm text-muted hover:text-fg hover:bg-surface-2 transition-colors"><Icon name="file-code" size={18} />API Reference</a></div> | |
| </aside> | |
| </> | |
| ); | |
| const App = () => { | |
| const [sidebarOpen, setSidebarOpen] = useState(false); | |
| const [model, setModel] = useState('DreamVision XL'); | |
| const [prompt, setPrompt] = useState(''); | |
| const [negativePrompt, setNegativePrompt] = useState(''); | |
| const [isGenerating, setIsGenerating] = useState(false); | |
| const [generated, setGenerated] = useState(false); | |
| const [aspectRatio, setAspectRatio] = useState('1:1'); | |
| const handleGenerate = () => { if (!prompt.trim()) return; setIsGenerating(true); setGenerated(false); setTimeout(() => { setIsGenerating(false); setGenerated(true); }, 2500); }; | |
| return ( | |
| <div className="min-h-screen bg-bg"> | |
| <Sidebar isOpen={sidebarOpen} setIsOpen={setSidebarOpen} /> | |
| <div className="lg:ml-64"> | |
| <header className="sticky top-0 z-30 glass border-b border-border"> | |
| <div className="flex items-center justify-between px-4 sm:px-6 h-16"> | |
| <div className="flex items-center gap-4"> | |
| <button onClick={() => setSidebarOpen(true)} className="lg:hidden p-2 rounded-lg hover:bg-surface-2 text-muted"><Icon name="menu" size={20} /></button> | |
| <h1 className="text-xl font-bold">Generator</h1> | |
| </div> | |
| <div className="flex items-center gap-3"> | |
| <button className="p-2 rounded-lg hover:bg-surface-2 text-muted relative"><Icon name="bell" size={20} /><span className="absolute top-1.5 right-1.5 w-2 h-2 rounded-full bg-primary" /></button> | |
| <a href="profile.html" className="w-9 h-9 rounded-lg overflow-hidden border border-border"><img src="http://static.photos/people/100x100/10" alt="" className="w-full h-full object-cover" /></a> | |
| </div> | |
| </div> | |
| </header> | |
| <div className="flex flex-col lg:flex-row h-[calc(100vh-64px)]"> | |
| {/* Settings Panel */} | |
| <div className="w-full lg:w-80 border-b lg:border-b-0 lg:border-r border-border overflow-y-auto no-scrollbar p-4 space-y-5"> | |
| <div> | |
| <label className="text-xs font-medium text-muted uppercase tracking-wider mb-2 block">Model</label> | |
| <select value={model} onChange={e => setModel(e.target.value)} className="w-full px-3 py-2.5 rounded-xl bg-surface-2 border border-border text-sm text-fg focus:outline-none focus:ring-2 focus:ring-primary/50"> | |
| {['DreamVision XL', 'SDXL 1.0', 'CyberPunk v3', 'Anime Diffusion'].map(m => <option key={m}>{m}</option>)} | |
| </select> | |
| </div> | |
| <div> | |
| <label className="text-xs font-medium text-muted uppercase tracking-wider mb-2 block">Aspect Ratio</label> | |
| <div className="grid grid-cols-4 gap-2"> | |
| {['1:1', '4:3', '16:9', '9:16'].map(r => ( | |
| <button key={r} onClick={() => setAspectRatio(r)} className={`py-2 rounded-lg text-xs font-medium transition-colors ${aspectRatio === r ? 'bg-primary text-primary-foreground' : 'bg-surface-2 border border-border text-muted hover:text-fg'}`}>{r}</button> | |
| ))} | |
| </div> | |
| </div> | |
| {[ | |
| { label: 'Steps', val: '30', desc: 'Number of denoising steps' }, | |
| ].map(p => ( | |
| <div key={p.label}> | |
| <label className="text-xs font-medium text-muted uppercase tracking-wider mb-2 block">{p.label}: {p.val}</label> | |
| <input type="range" min="1" max="50" defaultValue="30" className="w-full accent-primary" /> | |
| <p className="text-xs text-muted mt-1">{p.desc}</p> | |
| </div> | |
| ))} | |
| <div> | |
| <label className="text-xs font-medium text-muted uppercase tracking-wider mb-2 block">Guidance Scale: 7.5</label> | |
| <input type="range" min="1" max="20" defaultValue="7.5" step="0.5" className="w-full accent-primary" /> | |
| </div> | |
| <div> | |
| <label className="text-xs font-medium text-muted uppercase tracking-wider mb-2 block">Seed</label> | |
| <div className="flex gap-2"> | |
| <input type="text" defaultValue="Random" className="flex-1 px-3 py-2.5 rounded-xl bg-surface-2 border border-border text-sm text-fg focus:outline-none focus:ring-2 focus:ring-primary/50" /> | |
| <button className="px-3 rounded-xl bg-surface-2 border border-border text-muted hover:text-fg"><Icon name="shuffle" size={16} /></button> | |
| </div> | |
| </div> | |
| <div className="pt-2 border-t border-border"> | |
| <h3 className="text-xs font-medium text-muted uppercase tracking-wider mb-2">Quick Styles</h3> | |
| <div className="flex flex-wrap gap-2"> | |
| {['Photorealistic', 'Anime', 'Fantasy', 'Cinematic', 'Oil Painting', '3D Render'].map(s => ( | |
| <button key={s} className="px-3 py-1.5 rounded-lg bg-surface-2 border border-border text-xs text-muted hover:text-fg hover:border-surface-3 transition-colors">{s}</button> | |
| ))} | |
| </div> | |
| </div> | |
| </div> | |
| {/* Main Canvas */} | |
| <div className="flex-1 flex flex-col"> | |
| <div className="flex-1 flex items-center justify-center p-4 sm:p-8"> | |
| {isGenerating ? ( | |
| <div className="text-center"> | |
| <div className="w-20 h-20 mx-auto mb-6 relative"> | |
| <div className="absolute inset-0 border-4 border-primary/30 border-t-primary rounded-full animate-spin" /> | |
| <div className="absolute inset-2 border-4 border-secondary/30 border-b-secondary rounded-full animate-spin" style={{animationDirection:'reverse', animationDuration:'1.5s'}} /> | |
| <div className="absolute inset-4 border-4 border-accent/30 border-t-accent rounded-full animate-spin" style={{animationDuration:'3s'}} /> | |
| <div className="absolute inset-8 bg-primary/20 rounded-full generating-glow" style={{borderRadius:'60% 40% 30% 70%', animation:'morph-bg 3s ease-in-out infinite'}} /> | |
| </div> | |
| <p className="text-fg font-bold text-lg">Generating your fantasy...</p> | |
| <p className="text-sm text-muted mt-1">This usually takes 10-30 seconds</p> | |
| </div> | |
| ) : generated ? ( | |
| <div className="max-w-2xl w-full"> | |
| <div className="rounded-2xl overflow-hidden border border-border shadow-2xl shadow-black/40"> | |
| <img src={`http://static.photos/cyberpunk/1024x576/1`} alt="Generated" className="w-full" /> | |
| </div> | |
| <div className="flex items-center justify-between mt-4"> | |
| <div className="flex gap-2"> | |
| {['Download', 'Upscale', 'Variations', 'Add to Collection'].map(a => ( | |
| <button key={a} className="px-4 py-2 rounded-lg bg-surface border border-border text-sm text-fg hover:bg-surface-2 transition-colors flex items-center gap-1.5"><Icon name={a === 'Download' ? 'download' : a === 'Upscale' ? 'maximize' : a === 'Variations' ? 'copy' : 'bookmark'} size={14} />{a}</button> | |
| ))} | |
| </div> | |
| <span className="text-xs text-muted">DreamVision XL · 1024×1024 · 30 steps</span> | |
| </div> | |
| </div> | |
| ) : ( | |
| <div className="text-center max-w-md"> | |
| <div className="w-20 h-20 rounded-2xl bg-surface-2 flex items-center justify-center mx-auto mb-6"><Icon name="sparkles" size={32} className="text-muted" /></div> | |
| <h2 className="text-xl font-semibold mb-2">Ready to Create</h2> | |
| <p className="text-muted text-sm">Enter a prompt below and click Generate to bring your vision to life.</p> | |
| </div> | |
| )} | |
| </div> | |
| {/* Prompt Input */} | |
| <div className="p-4 border-t border-border"> | |
| <div className="max-w-4xl mx-auto space-y-3"> | |
| <textarea value={negativePrompt} onChange={e => setNegativePrompt(e.target.value)} placeholder="Negative prompt (optional)..." className="w-full px-4 py-2.5 rounded-xl bg-surface border border-border text-sm text-fg placeholder:text-muted focus:outline-none focus:ring-2 focus:ring-primary/50 resize-none h-16" /> | |
| <div className="flex gap-3"> | |
| <div className="flex-1 flex items-center gap-2 px-4 py-3 rounded-xl bg-surface border border-border focus-within:ring-2 focus-within:ring-primary/50"> | |
| <Icon name="sparkles" size={18} className="text-muted shrink-0" /> | |
| <input type="text" value={prompt} onChange={e => setPrompt(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleGenerate()} placeholder="Describe what you want to create..." className="flex-1 bg-transparent text-fg placeholder:text-muted outline-none text-sm" /> | |
| </div> | |
| <button onClick={handleGenerate} disabled={isGenerating} className="px-6 py-3 rounded-xl bg-primary text-primary-foreground font-semibold hover:brightness-110 transition-all shadow-lg shadow-primary/25 flex items-center gap-2 shrink-0"> | |
| <Icon name="zap" size={18} />Generate | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| ReactDOM.createRoot(document.getElementById('root')).render(<App />); | |
| </script> | |
| </body> | |
| </html> |