Files
drover-go/docs/design/v2/drover-cli.jsx
T
root 113616b039
Release / release (push) Successful in 3m19s
docs/design/v2: add 12-variant React design archive
Stash the full claude.ai/design output (12 JSX variants — brutalist,
classic, cli, compact, fluent-live, glass, hero-live, minimal,
sketches, studio, wizard-live, workshop — plus shared hooks and a
standalone HTML preview) for reference when we get to the Wails
frontend in Phase 6/7.

Source archive: C:\Users\root\Downloads\app(1).zip (~1MB).

Not wired into any build target yet — current GUI is the temporary
MessageBox stub. Pulling these in is the goal of the Wails phase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 03:12:02 +03:00

264 lines
14 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 (
<div style={{
width: 480, height: 640, background: t.bg, color: t.text, display:'flex', flexDirection:'column',
fontFamily: fontMono, fontSize: 12, overflow:'hidden', position:'relative',
border:'1px solid #000', textShadow: `0 0 1px ${t.accent}30`,
}}>
{/* CRT scanlines */}
<div style={{
position:'absolute', inset:0, pointerEvents:'none', zIndex: 5, opacity: 0.18,
background: 'repeating-linear-gradient(to bottom, transparent 0, transparent 2px, rgba(0,0,0,.55) 3px, transparent 4px)',
}}/>
{/* vignette */}
<div style={{
position:'absolute', inset:0, pointerEvents:'none', zIndex: 4,
background: 'radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,.45) 100%)',
}}/>
{/* title bar — like a terminal tab */}
<div style={{
height: 28, background: t.chrome, borderBottom:`1px solid ${t.border}`,
display:'flex', alignItems:'center', position:'relative', zIndex: 6,
}}>
<div style={{ display:'flex', alignItems:'center', gap: 7, padding:'0 11px', flex:1 }}>
<span style={{ color: t.accent }}>$</span>
<span style={{ fontSize: 11.5, fontWeight: 600, letterSpacing: 0.6 }}>drover-go</span>
<span style={{ fontSize: 10.5, color: t.dim }}> ~ 80×24</span>
</div>
<div style={{ display:'flex' }}>
{['settings','min','close'].map(k => (
<span key={k} style={{
width: 32, height: 28, display:'flex', alignItems:'center', justifyContent:'center',
cursor:'pointer', color: t.dim, fontSize: 11,
}}>{k==='close'?'×':k==='min'?'':'⚙'}</span>
))}
</div>
</div>
<div style={{ flex: 1, overflow:'auto', padding: '10px 14px', position:'relative', zIndex: 6 }}>
{/* prompt-style form */}
<div style={cliHead(t)}> socks5 proxy </div>
<div style={{ marginLeft: 4, paddingLeft: 14, borderLeft:`1px solid ${t.borderSoft}`, paddingTop: 4, paddingBottom: 6 }}>
<CliRow t={t}>
<span style={{ color: t.dim }}>host:</span>
<CliInput t={t} value={D.form.host} onChange={v => D.update({ host: v })}
placeholder="95.165.72.59 / example.com" onSubmit={D.runCheck} style={{ flex: 1 }}/>
<span style={{ color: t.dim }}>port:</span>
<CliInput t={t} value={D.form.port} onChange={v => D.update({ port: v.replace(/\D/g,'') })}
placeholder="12334" onSubmit={D.runCheck} style={{ width: 70 }}/>
</CliRow>
<div style={{ marginTop: 6 }}>
<label style={{ cursor:'pointer', userSelect:'none' }}>
<span style={{ color: t.dim }}>auth:</span>{' '}
<span onClick={() => {
D.update({ auth: !D.form.auth });
if (!D.form.auth) setTimeout(()=>document.getElementById('cli-login')?.focus(),30);
}}
style={{
color: D.form.auth ? t.accent : t.dim, fontWeight: 600, cursor:'pointer',
borderBottom: `1px dotted ${t.accent}`,
}}>{D.form.auth ? '[ on ]' : '[ off ]'}</span>
</label>
</div>
{D.form.auth && (
<CliRow t={t} style={{ marginTop: 6 }}>
<span style={{ color: t.dim }}>user:</span>
<CliInput id="cli-login" t={t} value={D.form.login} onChange={v => D.update({ login: v })}
placeholder="login" onSubmit={D.runCheck} style={{ flex: 1 }}/>
<span style={{ color: t.dim }}>pass:</span>
<CliInput t={t} value={D.form.password} onChange={v => D.update({ password: v })} type="password"
placeholder="••••••" onSubmit={D.runCheck} style={{ flex: 1 }}/>
</CliRow>
)}
</div>
<button onClick={D.runCheck} disabled={D.phase==='checking'||isActive} style={{
marginTop: 8, width:'100%', padding:'7px 12px', background:'transparent',
border:`1px solid ${(D.phase==='checking'||isActive)?t.dim:t.accent}`,
color: (D.phase==='checking'||isActive)?t.dim:t.accent, fontFamily: fontMono,
fontWeight: 600, fontSize: 11.5, letterSpacing: 1, textAlign:'left',
cursor: D.phase==='checking'?'not-allowed':'pointer', borderRadius: 0,
textShadow: (D.phase==='checking'||isActive)?'none':`0 0 6px ${t.accent}80`,
}}>
{D.phase==='checking'
? <>{'>'} running<span style={{ animation:'drv-blink 1s steps(2) infinite' }}>_</span></>
: <>{'> check_connection --strict'}</>}
</button>
{/* status */}
<div style={{ height: 12 }}/>
<div style={cliHead(t)}> status </div>
{D.phase === 'idle'
? <div style={{ marginLeft: 4, paddingLeft: 14, borderLeft:`1px solid ${t.borderSoft}`, color: t.dim }}>
{'> '} ready to check<span style={{ animation: 'drv-blink 1s steps(2) infinite' }}>_</span>
</div>
: <div style={{ marginLeft: 4, paddingLeft: 14, borderLeft:`1px solid ${t.borderSoft}` }}>
{D.phase === 'checking'
? <div style={{ color: t.dim }}>{'> '} running diagnostics<span style={{ animation:'drv-blink 1s steps(2) infinite' }}>...</span></div>
: (D.lastSummary?.failed === 0
? <div style={{ color: t.accent, fontWeight: 600 }}>[ ] all checks passed. ready to start.</div>
: <div style={{ color: t.warn, fontWeight: 600 }}>[ ! ] {D.lastSummary?.failed}/{D.tests.length} failed. some features won't work.</div>
)}
<div style={{ marginTop: 6 }}>
{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 (
<div key={test.id}>
<div style={{ display:'flex', gap: 9, alignItems:'baseline', padding:'1px 0' }}>
<span style={{ color: c, width: 10 }}>{sym}</span>
<span style={{ color: state==='pending'?t.dimmer:t.text, flex: 1 }} title={test.desc}>{test.label}</span>
<span style={{ color: c, fontSize: 10.5 }}>{r?.metric || (state==='running'?'':'')}</span>
{r?.result === 'failed' && (
<button onClick={() => D.toggleExpand(test.id)} style={{
background:'transparent', border:'none', color: t.dim, cursor:'pointer', padding: 0,
}}>{r.expanded?'[]':'[+]'}</button>
)}
</div>
{r?.result === 'failed' && r.expanded && (
<div className="drv-fadein" style={{
margin:'2px 0 6px 19px', padding:'4px 8px', borderLeft:`2px solid ${t.danger}`,
background: 'rgba(255,107,107,0.06)', fontSize: 10.5,
}}>
<div style={{ color: t.danger, fontWeight: 600 }}>! {r.error}</div>
<div style={{ color: t.dim }}>{r.hint}</div>
</div>
)}
</div>
);
})}
</div>
</div>
}
{/* actions */}
<div style={{ height: 12 }}/>
<div style={{ display:'flex', gap: 6 }}>
{(() => {
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 (
<div style={{
flex: 1, padding:'7px 12px', border:`1px solid ${c}`, color: c, fontWeight: 700,
background: `${c}14`, textShadow: `0 0 6px ${c}80`,
display:'flex', alignItems:'center', gap: 7,
}}>
<span className="drv-pulsedot" style={{ width: 7, height: 7, borderRadius: 3, background: c, boxShadow:`0 0 6px ${c}` }}/>
[ ACTIVE{warning ? ' / UDP-WARN' : ''} ]
</div>
);
}
return (
<button onClick={D.startProxy} disabled={!ok} style={{
flex: 1, padding:'7px 12px', border:`1px solid ${ok?t.accent:t.dim}`,
background: ok ? `${t.accent}14` : 'transparent',
color: ok ? t.accent : t.dim, fontFamily: fontMono, fontWeight: 600, fontSize: 11.5,
letterSpacing: 1, textAlign:'left', cursor: ok?'pointer':'not-allowed',
textShadow: ok ? `0 0 6px ${t.accent}80` : 'none', borderRadius: 0,
}}>{'>'} start_proxying</button>
);
})()}
<button onClick={D.stopProxy} disabled={!isActive} style={{
flex: 1, padding:'7px 12px', border:`1px solid ${isActive?t.dim:t.borderSoft}`,
background:'transparent', color: isActive ? t.text : t.dimmer, fontFamily: fontMono,
fontWeight: 600, fontSize: 11.5, letterSpacing: 1, textAlign:'left',
cursor: isActive?'pointer':'not-allowed', borderRadius: 0,
}}>{''} stop</button>
</div>
{isActive && (
<div style={{
marginTop: 8, padding:'5px 9px', border:`1px dashed ${t.borderSoft}`,
color: t.dim, fontSize: 10.5, display:'flex', justifyContent:'space-between',
}}>
<span>↑ {window.fmtBytes(D.stats.up).padEnd(10)}</span>
<span>↓ {window.fmtBytes(D.stats.down).padEnd(10)}</span>
<span>tcp={D.stats.tcp}</span>
<span>udp={D.stats.udp}</span>
<span>up={window.fmtUptime(D.stats.uptimeS)}</span>
</div>
)}
</div>
{/* logs */}
<div style={{ borderTop:`1px solid ${t.border}`, background: t.chrome, flexShrink: 0, position:'relative', zIndex: 6 }}>
<button onClick={() => D.setLogsOpen(!D.logsOpen)} style={{
width:'100%', padding:'6px 14px', display:'flex', alignItems:'center', gap: 8,
background:'transparent', border:'none', color: t.dim, cursor:'pointer',
fontFamily: fontMono, fontSize: 11, letterSpacing: 0.6,
}}>
<span>{D.logsOpen?'':''}</span>
<span style={{ fontWeight: 600 }}>tail -f drover.log</span>
<span style={{ marginLeft:'auto', color: t.dimmer }}>{D.logs.length} lines</span>
</button>
{D.logsOpen && (
<>
<div style={{ display:'flex', gap: 6, padding:'0 14px 6px' }}>
{[['copy', () => navigator.clipboard?.writeText(D.logs.map(x=>`[${x.level}] ${x.msg}`).join('\n'))],
['clear', D.clearLogs], ['file', null]].map(([l, fn]) => (
<button key={l} onClick={fn||undefined} style={{
background:'transparent', border:`1px solid ${t.borderSoft}`, color: t.dim,
padding:'2px 7px', fontSize: 10, fontFamily: fontMono, cursor:'pointer', borderRadius: 0,
}}>{`[${l}]`}</button>
))}
</div>
<div className="drv-log" ref={el => 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) => (
<div key={i}>
<span style={{ color: t.dimmer }}>{window.fmtTime(l.t)}</span>{' '}
<span style={{ color: l.level==='ERROR'?t.danger:l.level==='WARN'?t.warn:t.accent }}>{l.level}</span>{' '}
<span style={{ color: t.text }}>{l.msg}</span>
</div>
))}
</div>
</>
)}
</div>
</div>
);
}
function cliHead(t) { return { color: t.dim, fontSize: 10.5, marginBottom: 2, letterSpacing: 0.3 }; }
function CliRow({ children, style }) {
return <div style={{ display:'flex', alignItems:'center', gap: 7, ...style }}>{children}</div>;
}
function CliInput({ value, onChange, placeholder, type, onSubmit, style, t, id }) {
return <input id={id} value={value} type={type||'text'}
onChange={e => 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;