Team Ai
Apppublic

VibeCodingStudio/deepsite-project-41uyr

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
api-keys.html189 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="en">3<head>4    <meta charset="UTF-8">5    <meta name="viewport" content="width=device-width, initial-scale=1.0">6    <title>API Keys — NSFWStudio</title>7    <script src="https://cdn.tailwindcss.com"></script>8    <script src="https://unpkg.com/lucide@latest"></script>9    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>10    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>11    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>12    <link rel="preconnect" href="https://fonts.googleapis.com">13    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>14    <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">15    <script>16        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)' } } } }17    </script>18    <style>19        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; }20        .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); }21        ::selection { background: oklch(0.70 0.28 350 / 0.3); }22        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; }23        .no-scrollbar::-webkit-scrollbar { display: none; } .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }24        .tabular-nums { font-variant-numeric: tabular-nums; }25    </style>26</head>27<body class="antialiased">28    <div id="root"></div>29    <script type="text/babel">30        const { useState } = React;31        const Icon = ({ name, size = 20, className = "", strokeWidth = 2 }) => {32            const ref = React.useRef(null);33            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]);34            return <span ref={ref} className={`inline-flex items-center justify-center ${className}`} style={{ width: size, height: size }} />;35        };36 37        const navItems = [38            { name: 'Dashboard', icon: 'layout-dashboard', href: 'dashboard.html' },39            { name: 'Generator', icon: 'sparkles', href: 'generator.html' },40            { name: 'Playground', icon: 'code', href: 'playground.html' },41            { name: 'Models', icon: 'box', href: 'models.html' },42            { name: 'Workflows', icon: 'workflow', href: 'workflows.html' },43            { name: 'Marketplace', icon: 'shopping-bag', href: 'marketplace.html' },44            { name: 'API Keys', icon: 'key', href: 'api-keys.html', active: true },45            { divider: true },46            { name: 'Profile', icon: 'user', href: 'profile.html' },47            { name: 'Settings', icon: 'settings', href: 'settings.html' },48        ];49 50        const Sidebar = ({ isOpen, setIsOpen }) => (51            <>52                <div className={`fixed inset-0 z-40 lg:hidden transition-all ${isOpen ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'}`}>53                    <div className="absolute inset-0 bg-black/60 backdrop-blur-sm" onClick={() => setIsOpen(false)} />54                </div>55                <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'}`}>56                    <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>57                    <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>58                    <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>59                </aside>60            </>61        );62 63        const App = () => {64            const [sidebarOpen, setSidebarOpen] = useState(false);65            const [keys, setKeys] = useState([66                { id: 1, name: 'Production Key', key: 'nfw_prod_sk_7f3a9b2c4d5e6f1a8b9c0d1e', created: 'Jan 15, 2025', lastUsed: '2 min ago', status: 'active' },67                { id: 2, name: 'Development Key', key: 'nfw_dev_sk_2e4b6c8d0f1a3b5c7d9e1f2a', created: 'Feb 3, 2025', lastUsed: '3 days ago', status: 'active' },68                { id: 3, name: 'Staging Environment', key: 'nfw_stg_sk_9a1b2c3d4e5f6a7b8c9d0e1f', created: 'Mar 22, 2025', lastUsed: 'Never', status: 'inactive' },69            ]);70            const [showKey, setShowKey] = useState({});71            const [showCreate, setShowCreate] = useState(false);72            const [newKeyName, setNewKeyName] = useState('');73 74            const toggleShowKey = (id) => setShowKey(prev => ({ ...prev, [id]: !prev[id] }));75 76            const maskKey = (key) => key.substring(0, 12) + '••••••••••••••••••••';77 78            return (79                <div className="min-h-screen bg-bg">80                    <Sidebar isOpen={sidebarOpen} setIsOpen={setSidebarOpen} />81                    <div className="lg:ml-64">82                        <header className="sticky top-0 z-30 glass border-b border-border">83                            <div className="flex items-center justify-between px-4 sm:px-6 h-16">84                                <div className="flex items-center gap-4">85                                    <button onClick={() => setSidebarOpen(true)} className="lg:hidden p-2 rounded-lg hover:bg-surface-2 text-muted"><Icon name="menu" size={20} /></button>86                                    <h1 className="text-xl font-bold">API Keys</h1>87                                </div>88                                <div className="flex items-center gap-3">89                                    <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>90                                </div>91                            </div>92                        </header>93 94                        <main className="p-4 sm:p-6 lg:p-8 max-w-5xl">95                            {/* Danger Zone Notice */}96                            <div className="rounded-xl p-4 bg-destructive/10 border border-destructive/20 mb-6 flex items-start gap-3">97                                <Icon name="alert-triangle" size={20} className="text-destructive shrink-0 mt-0.5" />98                                <div>99                                    <h3 className="font-semibold text-fg text-sm">Keep your API keys secure</h3>100                                    <p className="text-xs text-muted mt-0.5">Never share your secret keys in public repositories, client-side code, or public forums. If a key is compromised, revoke it immediately.</p>101                                </div>102                            </div>103 104                            <div className="flex items-center justify-between mb-6">105                                <div>106                                    <p className="text-sm text-muted">Manage your API keys for programmatic access.</p>107                                </div>108                                <button onClick={() => setShowCreate(true)} className="px-4 py-2.5 rounded-xl bg-primary text-primary-foreground font-semibold text-sm hover:brightness-110 transition-all flex items-center gap-2">109                                    <Icon name="plus" size={16} />Create Key110                                </button>111                            </div>112 113                            {/* Create dialog */}114                            {showCreate && (115                                <div className="rounded-2xl p-6 bg-surface border border-border mb-6">116                                    <h3 className="font-semibold mb-4">Create New API Key</h3>117                                    <div className="space-y-4">118                                        <div>119                                            <label className="block text-sm font-medium text-fg mb-2">Key Name</label>120                                            <input type="text" value={newKeyName} onChange={e => setNewKeyName(e.target.value)} placeholder="e.g., Production Key" className="w-full max-w-md px-4 py-2.5 rounded-xl bg-surface-2 border border-border text-sm text-fg placeholder:text-muted focus:outline-none focus:ring-2 focus:ring-primary/50" />121                                        </div>122                                        <div className="flex gap-3">123                                            <button className="px-4 py-2.5 rounded-xl bg-primary text-primary-foreground font-semibold text-sm hover:brightness-110 transition-all" onClick={() => { if(newKeyName.trim()) { setKeys([...keys, { id: Date.now(), name: newKeyName, key: 'nfw_new_sk_' + Math.random().toString(36).substring(2, 18), created: 'Just now', lastUsed: 'Never', status: 'active' }]); setNewKeyName(''); setShowCreate(false); } }}>Create</button>124                                            <button onClick={() => { setShowCreate(false); setNewKeyName(''); }} className="px-4 py-2.5 rounded-xl border border-border text-sm font-medium text-muted hover:text-fg hover:bg-surface-2 transition-colors">Cancel</button>125                                        </div>126                                    </div>127                                </div>128                            )}129 130                            {/* Keys list */}131                            <div className="space-y-4">132                                {keys.map(k => (133                                    <div key={k.id} className="rounded-2xl p-5 bg-surface border border-border hover:border-surface-3 transition-colors">134                                        <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4">135                                            <div className="flex items-center gap-3">136                                                <div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center"><Icon name="key" size={18} className="text-primary" /></div>137                                                <div>138                                                    <div className="font-semibold text-fg">{k.name}</div>139                                                    <div className="text-xs text-muted">Created {k.created}</div>140                                                </div>141                                            </div>142                                            <span className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold border ${k.status === 'active' ? 'bg-success/10 text-success border-success/20' : 'bg-muted/10 text-muted border-border'}`}>143                                                <span className="w-1.5 h-1.5 rounded-full bg-current" />144                                                {k.status === 'active' ? 'Active' : 'Inactive'}145                                            </span>146                                        </div>147                                        <div className="flex items-center gap-2 p-3 rounded-xl bg-surface-2 border border-border mb-4">148                                            <code className="flex-1 text-sm font-mono text-muted truncate">{showKey[k.id] ? k.key : maskKey(k.key)}</code>149                                            <button onClick={() => toggleShowKey(k.id)} className="p-1.5 rounded-lg hover:bg-surface-3 text-muted hover:text-fg transition-colors shrink-0"><Icon name={showKey[k.id] ? 'eye-off' : 'eye'} size={16} /></button>150                                            <button onClick={() => { navigator.clipboard?.writeText(k.key); }} className="p-1.5 rounded-lg hover:bg-surface-3 text-muted hover:text-fg transition-colors shrink-0"><Icon name="copy" size={16} /></button>151                                        </div>152                                        <div className="flex items-center justify-between text-xs text-muted">153                                            <span>Last used: {k.lastUsed}</span>154                                            <div className="flex items-center gap-2">155                                                <button className="px-3 py-1.5 rounded-lg border border-border text-muted hover:text-fg hover:bg-surface-2 transition-colors">Regenerate</button>156                                                <button className="px-3 py-1.5 rounded-lg border border-destructive/30 text-destructive hover:bg-destructive/10 transition-colors">Revoke</button>157                                            </div>158                                        </div>159                                    </div>160                                ))}161                            </div>162 163                            {/* Usage Stats */}164                            <div className="mt-8 rounded-2xl p-6 bg-surface border border-border">165                                <h2 className="font-semibold mb-4">Usage This Month</h2>166                                <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">167                                    {[168                                        { label: 'Total Requests', value: '1.2M', change: '+23%' },169                                        { label: 'Tokens Used', value: '45.8M', change: '+18%' },170                                        { label: 'Avg Latency', value: '142ms', change: '-5%' },171                                        { label: 'Error Rate', value: '0.03%', change: '-12%' },172                                    ].map((s, i) => (173                                        <div key={i} className="p-4 rounded-xl bg-surface-2 border border-border">174                                            <div className="text-xs text-muted mb-1">{s.label}</div>175                                            <div className="text-xl font-bold text-fg tabular-nums">{s.value}</div>176                                            <div className="text-xs text-success mt-1">{s.change}</div>177                                        </div>178                                    ))}179                                </div>180                            </div>181                        </main>182                    </div>183                </div>184            );185        };186        ReactDOM.createRoot(document.getElementById('root')).render(<App />);187    </script>188</body>189</html>