File size: 20,789 Bytes
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
07381d2
 
 
 
b94499a
 
 
 
 
 
 
 
 
 
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
07381d2
 
 
 
 
 
 
 
 
b94499a
 
 
 
07381d2
 
 
b94499a
 
 
 
 
 
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
07381d2
 
 
 
 
 
 
 
b94499a
07381d2
 
 
 
 
 
b94499a
07381d2
 
b94499a
07381d2
 
 
 
 
b94499a
 
07381d2
 
b94499a
07381d2
 
 
 
 
 
 
 
 
 
 
 
b94499a
 
 
07381d2
 
 
 
 
 
 
 
 
 
 
b94499a
07381d2
b94499a
 
 
07381d2
 
 
 
b94499a
07381d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b94499a
 
07381d2
b94499a
 
 
 
 
 
 
 
 
 
 
 
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
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Models — 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); }
        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(20px); box-shadow: 0 25px 50px rgba(0,0,0,0.4), 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 20px 40px rgba(0,0,0,0.3), 0 0 0 1px oklch(0.70 0.28 350 / 0.2); }
        .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; }
        .glow-border { position: relative; isolation: isolate; }
        .glow-border::after { content: ''; position: absolute; inset: -2px; border-radius: inherit; background: linear-gradient(135deg, oklch(0.70 0.28 350), oklch(0.75 0.15 215)); z-index: -1; opacity: 0; transition: opacity 0.3s ease; filter: blur(10px); }
        .glow-border:hover::after { opacity: 0.6; }
    </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' },
            { name: 'Playground', icon: 'code', href: 'playground.html' },
            { name: 'Models', icon: 'box', href: 'models.html', active: true },
            { 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="#" 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="#" 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 [activeTab, setActiveTab] = useState('my-models');

            const myModels = [
                { name: 'EroticDream XL', type: 'NSFW Image Generation', status: 'published', runs: '45.2K', rating: 4.9, revenue: '$2,340', updated: '2 days ago', img: 'http://static.photos/cyberpunk/400x300/20', desc: 'Ultra-realistic erotic art model with advanced anatomy and lighting' },
                { name: 'DarkSeduction v3', type: 'Fantasy Erotic', status: 'published', runs: '28.1K', rating: 4.8, revenue: '$1,890', updated: '1 week ago', img: 'http://static.photos/red/400x300/21', desc: 'Dark fantasy and fetish art with stunning detail and mood' },
                { name: 'MorphX Body v2', type: 'Body Morph', status: 'draft', runs: '0', rating: '-', revenue: '$0', updated: '3 days ago', img: 'http://static.photos/abstract/400x300/22', desc: 'Advanced body transformation and morphing model' },
                { name: 'Pleasure Enhance Pro', type: 'Upscaling', status: 'review', runs: '12.8K', rating: 4.7, revenue: '$890', updated: '5 days ago', img: 'http://static.photos/nature/400x300/23', desc: '4K upscaling optimized for adult content with detail recovery' },
            ];

            const exploreModels = [
                { name: 'SinfulAnime XL', type: 'Hentai / Anime', author: '@velvet_sin', runs: '52K', rating: 4.9, price: '$7.99', img: 'http://static.photos/people/400x300/24' },
                { name: 'PhotoReal Erotica', type: 'Photorealistic', author: '@kink_architect', runs: '67K', rating: 4.9, price: '$14.99', img: 'http://static.photos/travel/400x300/25' },
                { name: 'Fantasy Flesh XL', type: 'Fantasy / Furry', author: '@fantasy_weaver', runs: '19.4K', rating: 4.8, price: '$5.99', img: 'http://static.photos/nature/400x300/26' },
                { name: 'Ink & Skink', type: 'Tattoo / Alt', author: '@dark_desires', runs: '15.3K', rating: 4.7, price: 'Free', img: 'http://static.photos/minimal/400x300/27' },
                { name: 'FutureBods', type: 'Sci-Fi Body', author: '@cosmic_ai', runs: '8.7K', rating: 4.6, price: '$3.99', img: 'http://static.photos/aerial/400x300/28' },
                { name: 'RetroPinup', type: 'Vintage Nude', author: '@retro_vibes', runs: '22.1K', rating: 4.8, price: 'Free', img: 'http://static.photos/vintage/400x300/29' },
            ];

            const statusColors = { published: 'bg-success/10 text-success border-success/20', draft: 'bg-muted/10 text-muted border-border', review: 'bg-accent/10 text-accent border-accent/20' };

            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">Models</h1>
                                </div>
                                <div className="flex items-center gap-3">
                                    <div className="hidden sm:flex items-center gap-2 px-3 py-2 rounded-xl bg-surface-2 border border-border text-muted text-sm w-56"><Icon name="search" size={16} /><span>Search models...</span></div>
                                    <a href="#" className="px-4 py-2 rounded-lg bg-primary text-primary-foreground text-sm font-semibold hover:brightness-110 transition-all hover:scale-105 shadow-lg shadow-primary/20 flex items-center gap-2"><Icon name="plus" size={16} />Train Model</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="flex items-center gap-2 mb-6 border-b border-border">
                                {[{ id: 'my-models', label: 'My Models' }, { id: 'explore', label: 'Explore' }, { id: 'training', label: 'Training' }].map(t => (
                                    <button key={t.id} onClick={() => setActiveTab(t.id)} className={`px-4 py-3 border-b-2 text-sm font-semibold transition-all duration-300 -mb-px ${activeTab === t.id ? 'border-primary text-primary' : 'border-transparent text-muted hover:text-fg'}`}>{t.label}</button>
                                ))}
                            </div>

                            {activeTab === 'my-models' && (
                                <div className="space-y-4">
                                    {myModels.map((m, i) => (
                                        <div key={i} className="group rounded-2xl bg-surface border border-border hover:border-primary/30 transition-all duration-500 overflow-hidden card-3d gradient-border-animated">
                                            <div className="flex flex-col sm:flex-row">
                                                <div className="sm:w-48 h-32 sm:h-auto shrink-0 overflow-hidden">
                                                    <img src={m.img} alt={m.name} className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700" />
                                                </div>
                                                <div className="flex-1 p-5">
                                                    <div className="flex items-start justify-between gap-3 mb-3">
                                                        <div>
                                                            <div className="flex items-center gap-2 mb-1">
                                                                <h3 className="font-bold text-fg group-hover:text-primary transition-colors duration-300">{m.name}</h3>
                                                                <span className={`px-2.5 py-0.5 rounded-full text-xs font-bold border ${statusColors[m.status]}`}>{m.status}</span>
                                                            </div>
                                                            <p className="text-sm text-muted">{m.type}</p>
                                                            <p className="text-xs text-muted/70 mt-1">{m.desc}</p>
                                                        </div>
                                                        <div className="text-right">
                                                            <div className="text-lg font-bold text-fg tabular-nums">{m.revenue}</div>
                                                            <div className="text-xs text-muted">Revenue</div>
                                                        </div>
                                                    </div>
                                                    <div className="flex items-center gap-6 text-sm text-muted">
                                                        <span className="flex items-center gap-1"><Icon name="play" size={14} />{m.runs} runs</span>
                                                        <span className="flex items-center gap-1"><Icon name="star" size={14} className="text-accent" />{m.rating}</span>
                                                        <span className="flex items-center gap-1"><Icon name="clock" size={14} />{m.updated}</span>
                                                    </div>
                                                    <div className="flex items-center gap-2 mt-4">
                                                        <button className="px-3 py-1.5 rounded-lg bg-primary text-primary-foreground text-sm font-semibold hover:brightness-110 transition-all duration-200 hover:scale-105">Manage</button>
                                                        <button className="px-3 py-1.5 rounded-lg border border-border text-sm text-muted hover:text-fg hover:bg-surface-2 transition-all duration-200">Analytics</button>
                                                        <button className="px-3 py-1.5 rounded-lg border border-border text-sm text-muted hover:text-fg hover:bg-surface-2 transition-all duration-200">Edit</button>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    ))}
                                </div>
                            )}

                            {activeTab === 'explore' && (
                                <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
                                    {exploreModels.map((m, i) => (
                                        <div key={i} className="group rounded-2xl bg-surface border border-border hover:border-primary/30 overflow-hidden transition-all duration-500 hover:-translate-y-2 hover:shadow-2xl hover:shadow-primary/10 card-3d shine gradient-border-animated">
                                            <div className="aspect-[4/3] overflow-hidden relative">
                                                <img src={m.img} alt={m.name} className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700" />
                                                <div className="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent" />
                                                <span className="absolute top-3 right-3 px-2.5 py-1 rounded-lg bg-black/50 backdrop-blur-sm text-xs font-bold border border-white/10">{m.type}</span>
                                            </div>
                                            <div className="p-4">
                                                <div className="flex items-start justify-between mb-2">
                                                    <div>
                                                        <h3 className="font-bold text-fg group-hover:text-primary transition-colors duration-300">{m.name}</h3>
                                                        <p className="text-xs text-muted">{m.author}</p>
                                                    </div>
                                                    <span className="text-sm font-bold text-primary">{m.price}</span>
                                                </div>
                                                <div className="flex items-center gap-4 text-xs text-muted">
                                                    <span className="flex items-center gap-1"><Icon name="star" size={12} className="text-accent" />{m.rating}</span>
                                                    <span className="flex items-center gap-1"><Icon name="download" size={12} />{m.runs}</span>
                                                </div>
                                            </div>
                                        </div>
                                    ))}
                                </div>
                            )}

                            {activeTab === 'training' && (
                                <div className="text-center py-16">
                                    <div className="w-20 h-20 rounded-2xl bg-primary/10 flex items-center justify-center mx-auto mb-4 hover-lift"><Icon name="cpu" size={32} className="text-primary" /></div>
                                    <h2 className="text-xl font-bold mb-2">No Active Training</h2>
                                    <p className="text-muted mb-6 max-w-md mx-auto">Start training a new model by uploading your dataset and configuring your training parameters.</p>
                                    <a href="#" className="inline-flex items-center gap-2 px-6 py-3 rounded-xl bg-primary text-primary-foreground font-bold hover:brightness-110 transition-all duration-300 hover:scale-105 shadow-lg shadow-primary/20"><Icon name="plus" size={18} />Start Training</a>
                                </div>
                            )}
                        </main>
                    </div>
                </div>
            );
        };
        ReactDOM.createRoot(document.getElementById('root')).render(<App />);
    </script>
</body>
</html>