| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Sign In — 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; } |
| </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 App = () => { |
| const [isSignUp, setIsSignUp] = useState(false); |
| const [showPassword, setShowPassword] = useState(false); |
| const [email, setEmail] = useState(''); |
| const [password, setPassword] = useState(''); |
| const [name, setName] = useState(''); |
| |
| return ( |
| <div className="min-h-screen flex"> |
| {/* Left Panel - Visual */} |
| <div className="hidden lg:flex lg:w-1/2 relative overflow-hidden bg-surface items-center justify-center"> |
| <div className="absolute inset-0"> |
| <img src="http://static.photos/cyberpunk/1200x630/1" alt="" className="w-full h-full object-cover opacity-40" /> |
| <div className="absolute inset-0 bg-gradient-to-r from-bg via-bg/60 to-transparent" /> |
| <div className="absolute inset-0 bg-gradient-to-t from-bg via-transparent to-transparent" /> |
| </div> |
| <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[600px] bg-primary/20 rounded-full blur-[160px] pointer-events-none" /> |
| <div className="relative z-10 max-w-md px-12"> |
| <a href="index.html" className="flex items-center gap-2.5 mb-8"> |
| <div className="w-10 h-10 rounded-xl bg-primary flex items-center justify-center"><Icon name="sparkles" size={20} className="text-primary-foreground" /></div> |
| <span className="text-2xl font-bold tracking-tight">NSFW<span className="text-muted">Studio</span></span> |
| </a> |
| <h2 className="text-3xl font-bold mb-4 leading-tight">Create <span className="gradient-text">Without Limits</span></h2> |
| <p className="text-muted leading-relaxed mb-8">The all-in-one AI platform for creators. Generate images, videos, agents, and workflows — all in one place.</p> |
| <div className="flex items-center gap-4"> |
| {['2.8M+ Creators', '45.8K+ Models', '99.9% Uptime'].map((s, i) => ( |
| <div key={i} className="glass rounded-xl px-4 py-3"> |
| <div className="text-sm font-bold text-fg">{s.split(' ')[0]}</div> |
| <div className="text-xs text-muted">{s.split(' ').slice(1).join(' ')}</div> |
| </div> |
| ))} |
| </div> |
| </div> |
| </div> |
| |
| {/* Right Panel - Form */} |
| <div className="flex-1 flex items-center justify-center p-6 sm:p-12"> |
| <div className="w-full max-w-md"> |
| <div className="lg:hidden flex items-center gap-2.5 mb-10"> |
| <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> |
| |
| <h1 className="text-3xl font-bold mb-2">{isSignUp ? 'Create your account' : 'Welcome back'}</h1> |
| <p className="text-muted mb-8">{isSignUp ? 'Start creating for free. No credit card required.' : 'Sign in to continue to your dashboard.'}</p> |
| |
| {/* Social Buttons */} |
| <div className="grid grid-cols-3 gap-3 mb-6"> |
| {[ |
| { name: 'Google', icon: 'chrome' }, |
| { name: 'GitHub', icon: 'github' }, |
| { name: 'Discord', icon: 'message-circle' }, |
| ].map(p => ( |
| <button key={p.name} className="flex items-center justify-center gap-2 px-4 py-3 rounded-xl border border-border bg-surface hover:bg-surface-2 transition-colors text-sm font-medium"> |
| <Icon name={p.icon} size={18} /> |
| <span className="hidden sm:inline">{p.name}</span> |
| </button> |
| ))} |
| </div> |
| |
| <div className="flex items-center gap-3 mb-6"> |
| <div className="flex-1 h-px bg-border" /> |
| <span className="text-xs text-muted uppercase tracking-wider">or</span> |
| <div className="flex-1 h-px bg-border" /> |
| </div> |
| |
| <div className="space-y-4"> |
| {isSignUp && ( |
| <div> |
| <label className="block text-sm font-medium text-fg mb-2">Full Name</label> |
| <div className="relative"> |
| <div className="absolute left-3.5 top-1/2 -translate-y-1/2 text-muted"><Icon name="user" size={16} /></div> |
| <input type="text" value={name} onChange={e => setName(e.target.value)} placeholder="John Doe" className="w-full pl-10 pr-4 py-3 rounded-xl bg-surface border border-border text-fg placeholder:text-muted focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all" /> |
| </div> |
| </div> |
| )} |
| <div> |
| <label className="block text-sm font-medium text-fg mb-2">Email</label> |
| <div className="relative"> |
| <div className="absolute left-3.5 top-1/2 -translate-y-1/2 text-muted"><Icon name="mail" size={16} /></div> |
| <input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="you@example.com" className="w-full pl-10 pr-4 py-3 rounded-xl bg-surface border border-border text-fg placeholder:text-muted focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all" /> |
| </div> |
| </div> |
| <div> |
| <div className="flex items-center justify-between mb-2"> |
| <label className="block text-sm font-medium text-fg">Password</label> |
| {!isSignUp && <a href="#" className="text-xs text-primary hover:underline">Forgot password?</a>} |
| </div> |
| <div className="relative"> |
| <div className="absolute left-3.5 top-1/2 -translate-y-1/2 text-muted"><Icon name="lock" size={16} /></div> |
| <input type={showPassword ? 'text' : 'password'} value={password} onChange={e => setPassword(e.target.value)} placeholder="••••••••" className="w-full pl-10 pr-12 py-3 rounded-xl bg-surface border border-border text-fg placeholder:text-muted focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all" /> |
| <button type="button" onClick={() => setShowPassword(!showPassword)} className="absolute right-3.5 top-1/2 -translate-y-1/2 text-muted hover:text-fg transition-colors"> |
| <Icon name={showPassword ? 'eye-off' : 'eye'} size={16} /> |
| </button> |
| </div> |
| </div> |
| |
| {isSignUp && ( |
| <label className="flex items-start gap-3 cursor-pointer"> |
| <input type="checkbox" className="mt-1 w-4 h-4 rounded border-border bg-surface text-primary focus:ring-primary/50 accent-primary" /> |
| <span className="text-xs text-muted leading-relaxed">I agree to the <a href="#" className="text-fg underline">Terms of Service</a> and <a href="#" className="text-fg underline">Privacy Policy</a></span> |
| </label> |
| )} |
| |
| {!isSignUp && ( |
| <label className="flex items-center gap-3 cursor-pointer"> |
| <input type="checkbox" className="w-4 h-4 rounded border-border bg-surface text-primary focus:ring-primary/50 accent-primary" /> |
| <span className="text-sm text-muted">Remember me</span> |
| </label> |
| )} |
| |
| <button className="w-full py-3.5 rounded-xl bg-primary text-primary-foreground font-semibold hover:brightness-110 transition-all shadow-lg shadow-primary/25 text-base"> |
| {isSignUp ? 'Create Account' : 'Sign In'} |
| </button> |
| </div> |
| |
| <p className="text-center text-sm text-muted mt-8"> |
| {isSignUp ? 'Already have an account?' : "Don't have an account?"}{' '} |
| <button onClick={() => setIsSignUp(!isSignUp)} className="text-primary font-medium hover:underline">{isSignUp ? 'Sign in' : 'Sign up'}</button> |
| </p> |
| |
| <p className="text-center text-xs text-muted/60 mt-6">By continuing, you agree to our Terms of Service and Privacy Policy.</p> |
| </div> |
| </div> |
| </div> |
| ); |
| }; |
| ReactDOM.createRoot(document.getElementById('root')).render(<App />); |
| </script> |
| </body> |
| </html> |