deepsite-project-41uyr / playground.html
VibeCodingStudio's picture
Initial DeepSite commit
07381d2 verified
Raw
History Blame Contribute Delete
17.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Playground — 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; }
</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', active: true },
{ 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 [selectedModel, setSelectedModel] = useState('DreamVision XL');
const [prompt, setPrompt] = useState('');
const [isRunning, setIsRunning] = useState(false);
const models = ['DreamVision XL', 'SDXL 1.0', 'CyberPunk v3', 'Anime Diffusion', 'Photo Real v2', 'Fantasy Art XL'];
const history = [
{ prompt: 'A neon cityscape at night with rain', model: 'DreamVision XL', time: '2 min ago', status: 'success' },
{ prompt: 'Cyberpunk anime girl with glowing eyes', model: 'Anime Diffusion', time: '8 min ago', status: 'success' },
{ prompt: 'Dark forest with mystical creatures', model: 'Fantasy Art XL', time: '15 min ago', status: 'error' },
{ prompt: 'Futuristic soldier in power armor', model: 'SDXL 1.0', time: '22 min ago', status: 'success' },
];
const handleRun = () => { setIsRunning(true); setTimeout(() => setIsRunning(false), 3000); };
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">API Playground</h1>
</div>
<div className="flex items-center gap-3">
<select className="px-3 py-2 rounded-lg bg-surface-2 border border-border text-sm text-fg" value={selectedModel} onChange={e => setSelectedModel(e.target.value)}>
{models.map(m => <option key={m} value={m}>{m}</option>)}
</select>
<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 h-[calc(100vh-64px)]">
{/* Left Panel - Config */}
<div className="w-80 border-r border-border flex flex-col overflow-y-auto no-scrollbar hidden md:flex">
<div className="p-4 border-b border-border">
<h3 className="font-semibold text-sm mb-3">Parameters</h3>
<div className="space-y-4">
<div>
<label className="text-xs text-muted mb-1.5 block">Model</label>
<select className="w-full px-3 py-2.5 rounded-xl bg-surface-2 border border-border text-sm text-fg" value={selectedModel} onChange={e => setSelectedModel(e.target.value)}>
{models.map(m => <option key={m} value={m}>{m}</option>)}
</select>
</div>
{[
{ label: 'Width', value: '1024', id: 'w' },
{ label: 'Height', value: '1024', id: 'h' },
{ label: 'Steps', value: '30', id: 's' },
].map(p => (
<div key={p.id}>
<label className="text-xs text-muted mb-1.5 block">{p.label}</label>
<input type="text" defaultValue={p.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" />
</div>
))}
<div>
<label className="text-xs text-muted mb-1.5 block">Guidance Scale</label>
<input type="range" min="1" max="20" defaultValue="7.5" className="w-full accent-primary" />
<div className="flex justify-between text-xs text-muted mt-1"><span>1</span><span>7.5</span><span>20</span></div>
</div>
<div>
<label className="text-xs text-muted mb-1.5 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 py-2.5 rounded-xl bg-surface-2 border border-border text-muted hover:text-fg transition-colors"><Icon name="shuffle" size={16} /></button>
</div>
</div>
<div>
<label className="text-xs text-muted mb-1.5 block">Negative Prompt</label>
<textarea 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 h-20 resize-none" placeholder="blurry, low quality, watermark..." />
</div>
</div>
</div>
<div className="p-4">
<h3 className="font-semibold text-sm mb-3">History</h3>
<div className="space-y-2">
{history.map((h, i) => (
<div key={i} className="p-3 rounded-xl hover:bg-surface-2/50 cursor-pointer transition-colors">
<div className="flex items-center justify-between mb-1">
<span className={`w-2 h-2 rounded-full ${h.status === 'success' ? 'bg-success' : 'bg-destructive'}`} />
<span className="text-xs text-muted">{h.time}</span>
</div>
<p className="text-xs text-fg/80 truncate">{h.prompt}</p>
<p className="text-xs text-muted mt-0.5">{h.model}</p>
</div>
))}
</div>
</div>
</div>
{/* Main Content */}
<div className="flex-1 flex flex-col">
{/* Code & Result tabs */}
<div className="flex-1 flex flex-col overflow-hidden">
<div className="flex items-center gap-1 px-4 pt-4 pb-2">
<button className="px-4 py-2 rounded-lg text-sm font-medium bg-primary text-primary-foreground">Request</button>
<button className="px-4 py-2 rounded-lg text-sm font-medium text-muted hover:text-fg hover:bg-surface-2 transition-colors">Response</button>
<button className="px-4 py-2 rounded-lg text-sm font-medium text-muted hover:text-fg hover:bg-surface-2 transition-colors">cURL</button>
<button className="px-4 py-2 rounded-lg text-sm font-medium text-muted hover:text-fg hover:bg-surface-2 transition-colors">Python</button>
</div>
<div className="flex-1 px-4">
<textarea className="w-full h-full min-h-[200px] px-4 py-3 rounded-xl bg-surface border border-border text-sm text-fg font-mono focus:outline-none focus:ring-2 focus:ring-primary/50 resize-none" value={`{\n "model": "${selectedModel}",\n "prompt": "A stunning neon cityscape...",\n "width": 1024,\n "height": 1024,\n "steps": 30,\n "guidance_scale": 7.5,\n "seed": null\n}`} readOnly />
</div>
</div>
{/* Prompt bar */}
<div className="p-4 border-t border-border">
<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="terminal" size={18} className="text-muted" />
<input type="text" value={prompt} onChange={e => setPrompt(e.target.value)} placeholder="Enter your prompt..." className="flex-1 bg-transparent text-fg placeholder:text-muted outline-none text-sm" />
</div>
<button onClick={handleRun} disabled={isRunning} className={`px-6 py-3 rounded-xl font-semibold transition-all flex items-center gap-2 ${isRunning ? 'bg-surface-2 border border-border text-muted' : 'bg-primary text-primary-foreground hover:brightness-110 shadow-lg shadow-primary/25'}`}>
{isRunning ? <><span className="w-4 h-4 border-2 border-muted border-t-transparent rounded-full animate-spin" />Running...</> : <><Icon name="play" size={18} />Run</>}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>