File size: 22,368 Bytes
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
 
 
 
 
 
 
 
 
 
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
 
07381d2
b94499a
 
 
 
 
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard — 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); }
        .gradient-text { background: linear-gradient(135deg, oklch(0.70 0.28 350), oklch(0.75 0.15 215)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
        ::selection { background: oklch(0.70 0.28 350 / 0.3); color: white; }
        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; }
        .tabular-nums { font-variant-numeric: tabular-nums; }
        .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), 0 0 0 1px oklch(0.70 0.28 350 / 0.2); }
        .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(-6px) scale(1.02); box-shadow: 0 15px 30px rgba(0,0,0,0.3); }
        .gradient-border-animated { position: relative; isolation: isolate; }
        .gradient-border-animated::before { content: ''; position: absolute; inset: 0; border-radius: inherit; padding: 1.5px; background: linear-gradient(270deg, oklch(0.70 0.28 350), oklch(0.75 0.15 215), oklch(0.80 0.18 85), oklch(0.70 0.28 350)); background-size: 300% 100%; -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; opacity: 0; transition: opacity 0.3s ease; }
        .gradient-border-animated:hover::before { opacity: 1; }
        @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
        .animate-slide-up { animation: slideUp 0.5s ease-out forwards; }
        .glow-ring:hover { box-shadow: 0 0 0 2px oklch(0.70 0.28 350 / 0.3), 0 0 20px oklch(0.70 0.28 350 / 0.1); }
    </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', active: true },
            { name: 'Generator', icon: 'sparkles', href: 'generator.html' },
            { 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 }) => (
            <>
                {/* Mobile overlay */}
                <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 stats = [
                { label: 'Generations', value: '12,847', change: '+14.2%', icon: 'image', color: 'text-primary', bg: 'bg-primary/10' },
                { label: 'Revenue', value: '$8,492', change: '+23.1%', icon: 'dollar-sign', color: 'text-success', bg: 'bg-success/10' },
                { label: 'Followers', value: '2,341', change: '+8.7%', icon: 'users', color: 'text-secondary', bg: 'bg-secondary/10' },
                { label: 'API Calls', value: '284K', change: '+31.5%', icon: 'activity', color: 'text-accent', bg: 'bg-accent/10' },
            ];

            const [hoveredStat, setHoveredStat] = useState(null);

            const recentGens = [
                { title: 'Crimson Seductress', model: 'EroticDream XL', time: '2m ago', status: 'completed', img: 'http://static.photos/cyberpunk/200x200/5' },
                { title: 'Dark Temptation', model: 'SinfulAnime XL', time: '5m ago', status: 'completed', img: 'http://static.photos/people/200x200/6' },
                { title: 'Velvet Dungeon', model: 'Fantasy Flesh XL', time: '8m ago', status: 'completed', img: 'http://static.photos/nature/200x200/7' },
                { title: 'Neon Curves', model: 'PhotoReal Erotica', time: '12m ago', status: 'completed', img: 'http://static.photos/technology/200x200/8' },
                { title: 'Shibari Art', model: 'DarkSeduction v3', time: '15m ago', status: 'processing', img: 'http://static.photos/people/200x200/9' },
            ];

            const activity = [
                { text: 'New follower: @dark_pixel', time: '1m ago', icon: 'user-plus', color: 'text-secondary' },
                { text: 'Your model earned $49.00', time: '3m ago', icon: 'dollar-sign', color: 'text-success' },
                { text: 'Workflow "Auto Tag" completed', time: '7m ago', icon: 'check-circle', color: 'text-primary' },
                { text: 'Comment on "Neon Cityscape"', time: '10m ago', icon: 'message-circle', color: 'text-accent' },
                { text: 'API key rotation reminder', time: '1h ago', icon: 'key', color: 'text-muted' },
            ];

            const topModels = [
                { name: 'DreamVision XL', runs: '45.2K', revenue: '$2,340', trend: '+12%' },
                { name: 'CyberPunk v3', runs: '28.1K', revenue: '$1,890', trend: '+8%' },
                { name: 'Anime Diffusion', runs: '19.7K', revenue: '$1,230', trend: '+21%' },
            ];

            return (
                <div className="min-h-screen bg-bg">
                    <Sidebar isOpen={sidebarOpen} setIsOpen={setSidebarOpen} />
                    <div className="lg:ml-64">
                        {/* Top bar */}
                        <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>
                                    <div className="hidden sm:flex items-center gap-2 px-4 py-2 rounded-xl bg-surface-2 border border-border text-muted text-sm w-72">
                                        <Icon name="search" size={16} />
                                        <span>Search anything...</span>
                                    </div>
                                </div>
                                <div className="flex items-center gap-3">
                                    <button className="p-2 rounded-lg hover:bg-surface-2 text-muted hover:text-fg transition-colors 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="generator.html" className="px-4 py-2 rounded-lg bg-primary text-primary-foreground text-sm font-semibold hover:brightness-110 transition-all">+ New</a>
                                    <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>

                        <main className="p-4 sm:p-6 lg:p-8">
                            <div className="mb-8">
                                <h1 className="text-2xl sm:text-3xl font-bold mb-1">Welcome back, <span className="gradient-text">Neon</span></h1>
                                <p className="text-muted">Here's what's happening with your creations today.</p>
                            </div>

                            {/* Stats */}
                            <div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
                                {stats.map((s, i) => (
                                    <div key={i} className="rounded-2xl p-5 bg-surface border border-border hover:border-primary/30 transition-all duration-500 card-3d gradient-border-animated"
                                         style={{animationDelay: `${i * 0.1}s`, animation: 'slideUp 0.5s ease-out forwards', opacity: 0}}
                                         onMouseEnter={() => setHoveredStat(i)} onMouseLeave={() => setHoveredStat(null)}>
                                        <div className="flex items-center justify-between mb-3">
                                            <div className={`w-10 h-10 rounded-xl ${s.bg} flex items-center justify-center transition-transform duration-300 ${hoveredStat === i ? 'scale-110' : ''}`}><Icon name={s.icon} size={18} className={s.color} /></div>
                                            <span className="text-xs font-bold text-success bg-success/10 px-2.5 py-1 rounded-full border border-success/20">{s.change}</span>
                                        </div>
                                        <div className="text-2xl font-bold text-fg tabular-nums">{s.value}</div>
                                        <div className="text-xs text-muted mt-1">{s.label}</div>
                                    </div>
                                ))}
                            </div>

                            <div className="grid lg:grid-cols-3 gap-6">
                                {/* Recent Generations */}
                                <div className="lg:col-span-2 rounded-2xl p-6 bg-surface border border-border">
                                    <div className="flex items-center justify-between mb-5">
                                        <h2 className="text-lg font-semibold">Recent Generations</h2>
                                        <a href="generator.html" className="text-sm text-primary hover:underline flex items-center gap-1">View all <Icon name="arrow-right" size={14} /></a>
                                    </div>
                                    <div className="space-y-3">
                                        {recentGens.map((g, i) => (
                                            <div key={i} className="flex items-center gap-4 p-3 rounded-xl hover:bg-surface-2/50 transition-colors cursor-pointer group">
                                                <img src={g.img} alt="" className="w-12 h-12 rounded-xl object-cover border border-border" />
                                                <div className="flex-1 min-w-0">
                                                    <div className="text-sm font-medium text-fg truncate">{g.title}</div>
                                                    <div className="text-xs text-muted">{g.model} · {g.time}</div>
                                                </div>
                                                <span className={`px-2.5 py-1 rounded-full text-xs font-semibold ${g.status === 'completed' ? 'bg-success/10 text-success border border-success/20' : 'bg-primary/10 text-primary border border-primary/20'}`}>
                                                    {g.status}
                                                </span>
                                            </div>
                                        ))}
                                    </div>
                                </div>

                                {/* Right column */}
                                <div className="space-y-6">
                                    {/* Activity */}
                                    <div className="rounded-2xl p-6 bg-surface border border-border">
                                        <h2 className="text-lg font-semibold mb-4">Activity</h2>
                                        <div className="space-y-4">
                                            {activity.map((a, i) => (
                                                <div key={i} className="flex items-start gap-3">
                                                    <div className={`mt-0.5 ${a.color}`}><Icon name={a.icon} size={16} /></div>
                                                    <div className="flex-1 min-w-0">
                                                        <div className="text-sm text-fg/90">{a.text}</div>
                                                        <div className="text-xs text-muted mt-0.5">{a.time}</div>
                                                    </div>
                                                </div>
                                            ))}
                                        </div>
                                    </div>

                                    {/* Top Models */}
                                    <div className="rounded-2xl p-6 bg-surface border border-border">
                                        <div className="flex items-center justify-between mb-4">
                                            <h2 className="text-lg font-semibold">Top Models</h2>
                                            <a href="models.html" className="text-xs text-primary hover:underline">See all</a>
                                        </div>
                                        <div className="space-y-3">
                                            {topModels.map((m, i) => (
                                                <div key={i} className="flex items-center justify-between p-3 rounded-xl hover:bg-surface-2/50 transition-colors cursor-pointer">
                                                    <div className="flex items-center gap-3">
                                                        <span className="w-6 h-6 rounded-full bg-surface-2 flex items-center justify-center text-xs font-bold text-muted">{i+1}</span>
                                                        <div>
                                                            <div className="text-sm font-medium text-fg">{m.name}</div>
                                                            <div className="text-xs text-muted">{m.runs} runs</div>
                                                        </div>
                                                    </div>
                                                    <div className="text-right">
                                                        <div className="text-sm font-semibold text-fg">{m.revenue}</div>
                                                        <div className="text-xs text-success">{m.trend}</div>
                                                    </div>
                                                </div>
                                            ))}
                                        </div>
                                    </div>
                                </div>
                            </div>

                            {/* Quick Actions */}
                            <div className="mt-8 grid grid-cols-2 sm:grid-cols-4 gap-3">
                                {[
                                    { label: 'Generate Image', icon: 'image', color: 'text-primary', bg: 'bg-primary/10', href: 'generator.html' },
                                    { label: 'Create Workflow', icon: 'workflow', color: 'text-secondary', bg: 'bg-secondary/10', href: 'workflows.html' },
                                    { label: 'Train Model', icon: 'box', color: 'text-success', bg: 'bg-success/10', href: 'models.html' },
                                    { label: 'Explore Marketplace', icon: 'shopping-bag', color: 'text-accent', bg: 'bg-accent/10', href: 'marketplace.html' },
                                ].map((a, i) => (
                                    <a key={i} href={a.href} className="group flex flex-col items-center gap-3 p-5 rounded-2xl bg-surface border border-border hover:border-surface-3 transition-all hover:-translate-y-0.5">
                                        <div className={`w-12 h-12 rounded-xl ${a.bg} flex items-center justify-center group-hover:scale-110 transition-transform`}><Icon name={a.icon} size={22} className={a.color} /></div>
                                        <span className="text-sm font-medium text-fg">{a.label}</span>
                                    </a>
                                ))}
                            </div>
                        </main>
                    </div>
                </div>
            );
        };
        ReactDOM.createRoot(document.getElementById('root')).render(<App />);
    </script>
</body>
</html>