File size: 19,331 Bytes
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
 
 
 
 
 
 
 
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
 
 
 
 
 
 
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<!DOCTYPE html>
<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>