// drover-cli.jsx — Cyber CLI: terminal aesthetic, phosphor green, ASCII feel. // All-mono. No round corners. Subtle CRT scanline overlay. const CLI = { bg: '#0a0d0a', chrome: '#070a07', panel: '#0d110d', panel2: '#111511', border: '#1f2a1f', borderSoft: '#162016', text: '#bfe7c0', // phosphor green-white dim: '#5a8a5e', dimmer: '#3a5a3d', accent: '#5cf08a', accentDim: '#2a8a44', danger: '#ff6b6b', warn: '#ffd166', pass: '#5cf08a', skip: '#6a8a6e', inputBg: '#0a0e0a', }; function CliWindow({ initial }) { const t = CLI; const D = window.useDrover(initial); const palette = { pending: t.dimmer, running: t.accent, passed: t.pass, failed: t.danger, skipped: t.skip }; const fontMono = '"JetBrains Mono","IBM Plex Mono","Cascadia Mono",ui-monospace,monospace'; const isActive = D.phase === 'active'; return (
{/* CRT scanlines */}
{/* vignette */}
{/* title bar — like a terminal tab */}
$ drover-go — ~ — 80×24
{['settings','min','close'].map(k => ( {k==='close'?'×':k==='min'?'−':'⚙'} ))}
{/* prompt-style form */}
┌── socks5 proxy ─────────────────────────────────────────
host: D.update({ host: v })} placeholder="95.165.72.59 / example.com" onSubmit={D.runCheck} style={{ flex: 1 }}/> port: D.update({ port: v.replace(/\D/g,'') })} placeholder="12334" onSubmit={D.runCheck} style={{ width: 70 }}/>
{D.form.auth && ( user: D.update({ login: v })} placeholder="login" onSubmit={D.runCheck} style={{ flex: 1 }}/> pass: D.update({ password: v })} type="password" placeholder="••••••" onSubmit={D.runCheck} style={{ flex: 1 }}/> )}
{/* status */}
┌── status ─────────────────────────────────────────────────
{D.phase === 'idle' ?
{'> '} ready to check_
:
{D.phase === 'checking' ?
{'> '} running diagnostics...
: (D.lastSummary?.failed === 0 ?
[ ✓ ] all checks passed. ready to start.
:
[ ! ] {D.lastSummary?.failed}/{D.tests.length} failed. some features won't work.
)}
{D.tests.map(test => { const r = D.results[test.id]; const state = r?.result || (D.running === test.id ? 'running' : 'pending'); const sym = state==='passed'?'✓':state==='failed'?'✗':state==='skipped'?'~':state==='running'?'›':'·'; const c = state==='passed'?t.pass:state==='failed'?t.danger:state==='skipped'?t.skip:state==='running'?t.accent:t.dimmer; return (
{sym} {test.label} {r?.metric || (state==='running'?'…':'')} {r?.result === 'failed' && ( )}
{r?.result === 'failed' && r.expanded && (
! {r.error}
{r.hint}
)}
); })}
} {/* actions */}
{(() => { const allFailed = D.lastSummary && D.lastSummary.failed === D.tests.length; const ok = D.phase === 'checked' && !allFailed; const warning = isActive && (D.lastSummary?.failed||0) > 0; if (isActive) { const c = warning ? t.warn : t.accent; return (
[ ACTIVE{warning ? ' / UDP-WARN' : ''} ]
); } return ( ); })()}
{isActive && (
↑ {window.fmtBytes(D.stats.up).padEnd(10)} ↓ {window.fmtBytes(D.stats.down).padEnd(10)} tcp={D.stats.tcp} udp={D.stats.udp} up={window.fmtUptime(D.stats.uptimeS)}
)}
{/* logs */}
{D.logsOpen && ( <>
{[['copy', () => navigator.clipboard?.writeText(D.logs.map(x=>`[${x.level}] ${x.msg}`).join('\n'))], ['clear', D.clearLogs], ['file', null]].map(([l, fn]) => ( ))}
el && (el.scrollTop = el.scrollHeight)} style={{ maxHeight: 110, overflowY:'auto', padding:'5px 14px', fontFamily: fontMono, fontSize: 10, lineHeight: 1.55, color: t.dim }}> {D.logs.map((l,i) => (
{window.fmtTime(l.t)}{' '} {l.level}{' '} {l.msg}
))}
)}
); } function cliHead(t) { return { color: t.dim, fontSize: 10.5, marginBottom: 2, letterSpacing: 0.3 }; } function CliRow({ children, style }) { return
{children}
; } function CliInput({ value, onChange, placeholder, type, onSubmit, style, t, id }) { return onChange(e.target.value)} placeholder={placeholder} onKeyDown={e => e.key === 'Enter' && onSubmit?.()} style={{ background: t.inputBg, color: t.accent, border:'none', borderBottom:`1px solid ${t.borderSoft}`, borderRadius: 0, padding:'3px 4px', fontFamily: 'inherit', fontSize: 12, outline:'none', boxSizing:'border-box', textShadow:`0 0 4px ${t.accent}60`, ...style, }}/>; } window.CliWindow = CliWindow;