// drover-v2.jsx — Round 2: four new dark-only variants. // Reuses window.useDrover / StatusDot / icons / fmt helpers from drover-shared.jsx. // ============================================================================= // V5 — COMPACT PRO. High-density, table-like. Wireshark/HTOP feel. Mono numbers. // ============================================================================= const CPT = { bg: '#101216', chrome: '#0a0c0f', panel: '#15181d', panel2: '#1a1d23', border: '#262a31', borderSoft: '#1d2026', text: '#e1e3e8', dim: '#838892', dimmer: '#535862', accent: '#7aa9ff', danger: '#e5685a', warn: '#d6a64a', pass: '#5fc888', skip: '#6a6f78', inputBg: '#0c0e12', primaryFg: '#0b1426', }; function CompactWindow({ initial }) { const t = CPT; 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","SF Mono",ui-monospace,Consolas,monospace'; const fontUI = '"Inter","Segoe UI",system-ui,sans-serif'; const isActive = D.phase === 'active'; return (
{/* title bar */}
drover-go 0.4.2 · {D.form.host}:{D.form.port}{D.form.auth ? ' · auth' : ''}
{/* Row 1: form, single tight line */}
SOCKS5
D.update({ host: v })} placeholder="host" style={{ flex: 1 }} onSubmit={D.runCheck}/> : D.update({ port: v.replace(/\D/g,'') })} placeholder="port" style={{ width: 64 }} onSubmit={D.runCheck}/> { D.update({ auth: v }); if (v) setTimeout(()=>document.getElementById('cpt-login')?.focus(),30); }}>auth
{D.form.auth && (
D.update({ login: v })} placeholder="login" style={{ flex: 1 }} onSubmit={D.runCheck}/> D.update({ password: v })} placeholder="password" style={{ flex: 1 }} onSubmit={D.runCheck}/>
)}
{/* Row 2: status table, full width */}
STATUS {D.phase === 'idle' && 'idle'} {D.phase === 'checking' && `${Object.keys(D.results).length}/${D.tests.length}`} {(D.phase === 'checked' || D.phase === 'active') && (D.lastSummary?.failed === 0 ? 'all-pass' : `${D.lastSummary?.failed}/${D.tests.length} fail`)}
{D.phase === 'idle' ?
ready to check_
: }
{/* Row 3: actions */}
{isActive && (
{window.fmtBytes(D.stats.up)} {window.fmtBytes(D.stats.down)} tcp:{D.stats.tcp} udp:{D.stats.udp} up:{window.fmtUptime(D.stats.uptimeS)}
)}
{/* Logs */}
); } function CompactCell({ children, t, hover }) { const [h, setH] = React.useState(false); return
setH(true)} onMouseLeave={()=>setH(false)} style={{ width: 32, height: 28, display:'flex', alignItems:'center', justifyContent:'center', cursor:'pointer', background: h && hover ? hover : 'transparent', transition:'background .1s', }}>{children}
; } function cptHead(t) { return { fontSize: 9.5, letterSpacing: 1.5, color: t.dim, fontWeight: 700, marginBottom: 6, display:'flex', alignItems:'center', }; } function CptInput({ value, onChange, placeholder, type, style, onSubmit, t, fontMono, id }) { return onChange(e.target.value)} placeholder={placeholder} onKeyDown={e => e.key === 'Enter' && onSubmit?.()} style={{ background: t.inputBg, color: t.text, border:`1px solid ${t.border}`, borderRadius: 2, padding:'5px 7px', fontFamily: fontMono, fontSize: 11.5, outline:'none', boxSizing:'border-box', ...style, }}/>; } function CptCheck({ checked, onChange, t, children }) { return ( ); } function CompactStatusTable({ t, D, palette, fontMono }) { return (
{D.tests.map((test) => { const r = D.results[test.id]; const state = r?.result || (D.running === test.id ? 'running' : 'pending'); return (
{ state==='passed'?'✓':state==='failed'?'✗':state==='skipped'?'–':state==='running'?'›':'·' } {test.label} {r?.metric || (state==='running'?'…':'')} {r?.result === 'failed' && ( )}
{r?.result === 'failed' && r.expanded && (
{r.error}
{r.hint}
)}
); })}
); } function CompactStartBtn({ t, D, fontMono }) { const allFailed = D.lastSummary && D.lastSummary.failed === D.tests.length; const ok = D.phase === 'checked' && !allFailed; const active = D.phase === 'active'; const warning = active && (D.lastSummary?.failed || 0) > 0; if (active) { const c = warning ? t.warn : t.pass; return (
ACTIVE{warning ? ' · UDP-FALLBACK' : ''}
); } return ( ); } function CompactStopBtn({ t, D, fontMono }) { const enabled = D.phase === 'active'; return ( ); } function CompactLogs({ t, D, fontMono }) { return (
{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 12px', fontFamily: fontMono, fontSize: 10, lineHeight: 1.55, color: t.dim, background: t.panel }}> {D.logs.map((l,i) => (
{window.fmtTime(l.t)}{' '} {l.level.padEnd(5)}{' '} {l.msg}
))}
)}
); } window.CompactWindow = CompactWindow;