Files
drover-go/docs/design/v2/drover-compact.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

294 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-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 (
<div style={{
width: 480, height: 640, background: t.bg, color: t.text, display:'flex', flexDirection:'column',
fontFamily: fontUI, fontSize: 12, overflow: 'hidden',
border: '1px solid #000',
}}>
{/* title bar */}
<div style={{
height: 28, background: t.chrome, borderBottom:`1px solid ${t.border}`,
display:'flex', alignItems:'center', userSelect:'none',
}}>
<div style={{ display:'flex', alignItems:'center', gap: 7, padding:'0 10px', flex:1 }}>
<window.BrandMark size={12} color={t.accent}/>
<span style={{ fontSize: 11.5, fontWeight: 600 }}>drover-go</span>
<span style={{ fontSize: 10, color: t.dimmer, fontFamily: fontMono }}>0.4.2</span>
<span style={{ fontSize: 10, color: t.dim, marginLeft: 8, fontFamily: fontMono }}>
· {D.form.host}:{D.form.port}{D.form.auth ? ' · auth' : ''}
</span>
</div>
<div style={{ display:'flex' }}>
<CompactCell t={t}><window.IconGear color={t.dim}/></CompactCell>
<CompactCell t={t}><window.IconMin color={t.dim}/></CompactCell>
<CompactCell t={t} hover="#c0463f"><window.IconClose color={t.dim}/></CompactCell>
</div>
</div>
<div style={{ flex: 1, overflow:'auto' }}>
{/* Row 1: form, single tight line */}
<div style={{ padding: '10px 12px', borderBottom:`1px solid ${t.borderSoft}` }}>
<div style={cptHead(t)}>SOCKS5</div>
<div style={{ display:'flex', gap: 6, alignItems:'center' }}>
<CptInput t={t} fontMono={fontMono} value={D.form.host}
onChange={v => D.update({ host: v })} placeholder="host" style={{ flex: 1 }}
onSubmit={D.runCheck}/>
<span style={{ color: t.dimmer, fontFamily: fontMono }}>:</span>
<CptInput t={t} fontMono={fontMono} value={D.form.port}
onChange={v => D.update({ port: v.replace(/\D/g,'') })}
placeholder="port" style={{ width: 64 }} onSubmit={D.runCheck}/>
<CptCheck t={t} checked={D.form.auth} onChange={(v) => {
D.update({ auth: v }); if (v) setTimeout(()=>document.getElementById('cpt-login')?.focus(),30);
}}>auth</CptCheck>
</div>
{D.form.auth && (
<div style={{ display:'flex', gap: 6, marginTop: 6 }}>
<CptInput id="cpt-login" t={t} fontMono={fontMono} value={D.form.login}
onChange={v => D.update({ login: v })} placeholder="login"
style={{ flex: 1 }} onSubmit={D.runCheck}/>
<CptInput t={t} fontMono={fontMono} value={D.form.password} type="password"
onChange={v => D.update({ password: v })} placeholder="password"
style={{ flex: 1 }} onSubmit={D.runCheck}/>
</div>
)}
<button onClick={D.runCheck} disabled={D.phase === 'checking' || isActive} style={{
marginTop: 8, width:'100%', padding:'6px 10px', borderRadius: 2, fontFamily: fontMono,
background: (D.phase==='checking'||isActive)?t.panel2:t.accent,
color: (D.phase==='checking'||isActive)?t.dimmer:t.primaryFg,
border:`1px solid ${t.border}`, fontWeight: 700, fontSize: 11.5, letterSpacing: 0.5,
cursor: D.phase==='checking'?'not-allowed':'pointer', textAlign: 'left',
}}>
{'>>'} {D.phase==='checking'?'CHECKING…':'check connection'}
</button>
</div>
{/* Row 2: status table, full width */}
<div style={{ padding: '8px 12px', borderBottom:`1px solid ${t.borderSoft}` }}>
<div style={cptHead(t)}>
<span>STATUS</span>
<span style={{ marginLeft:'auto', color: t.dim, fontFamily: fontMono }}>
{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`)}
</span>
</div>
{D.phase === 'idle'
? <div style={{ color: t.dim, fontFamily: fontMono, fontSize: 11 }}>
<span style={{ color: t.dimmer }}></span> ready to check_
</div>
: <CompactStatusTable t={t} D={D} palette={palette} fontMono={fontMono}/>}
</div>
{/* Row 3: actions */}
<div style={{ padding: '8px 12px' }}>
<div style={{ display:'flex', gap: 6 }}>
<CompactStartBtn t={t} D={D} fontMono={fontMono}/>
<CompactStopBtn t={t} D={D} fontMono={fontMono}/>
</div>
{isActive && (
<div style={{
marginTop: 8, padding: '5px 8px', background: t.panel,
border:`1px solid ${t.borderSoft}`, borderRadius: 2,
fontFamily: fontMono, fontSize: 10.5, color: t.dim,
display:'flex', justifyContent:'space-between',
}}>
<span><window.IconArrowUp color={t.pass}/> {window.fmtBytes(D.stats.up)}</span>
<span><window.IconArrowDown color={t.accent}/> {window.fmtBytes(D.stats.down)}</span>
<span>tcp:{D.stats.tcp}</span>
<span>udp:{D.stats.udp}</span>
<span>up:{window.fmtUptime(D.stats.uptimeS)}</span>
</div>
)}
</div>
</div>
{/* Logs */}
<CompactLogs t={t} D={D} fontMono={fontMono}/>
</div>
);
}
function CompactCell({ children, t, hover }) {
const [h, setH] = React.useState(false);
return <div onMouseEnter={()=>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}</div>;
}
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 <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.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 (
<label style={{
display:'inline-flex', alignItems:'center', gap: 5, cursor:'pointer', userSelect:'none',
padding:'4px 7px', border:`1px solid ${checked?t.accent:t.border}`, borderRadius: 2,
fontFamily: '"JetBrains Mono",monospace', fontSize: 11,
background: checked ? `${t.accent}22` : 'transparent', color: checked ? t.accent : t.dim,
}}>
<span>[{checked ? 'x' : ' '}]</span>
<input type="checkbox" checked={checked} onChange={e => onChange(e.target.checked)} style={{display:'none'}}/>
<span>{children}</span>
</label>
);
}
function CompactStatusTable({ t, D, palette, fontMono }) {
return (
<div style={{ fontFamily: fontMono, fontSize: 11 }}>
{D.tests.map((test) => {
const r = D.results[test.id];
const state = r?.result || (D.running === test.id ? 'running' : 'pending');
return (
<div key={test.id}>
<div style={{
display:'flex', alignItems:'center', gap: 7, padding:'2px 0', height: 20,
color: state === 'pending' ? t.dimmer : t.text,
}}>
<span style={{ width: 10, color: t.dimmer }}>{
state==='passed'?'✓':state==='failed'?'✗':state==='skipped'?'':state==='running'?'':'·'
}</span>
<window.StatusDot state={state} palette={palette} size={10}/>
<span title={test.desc}>{test.label}</span>
<span style={{
marginLeft:'auto',
color: state==='failed'?t.danger:state==='skipped'?t.skip:state==='passed'?t.pass:t.dim,
}}>{r?.metric || (state==='running'?'…':'')}</span>
{r?.result === 'failed' && (
<button onClick={() => D.toggleExpand(test.id)} style={{
background:'transparent', border:'none', cursor:'pointer', padding: 2, color: t.dim,
}}><window.IconChevron color={t.dim} dir={r.expanded?'up':'down'}/></button>
)}
</div>
{r?.result === 'failed' && r.expanded && (
<div className="drv-fadein" style={{
margin: '2px 0 6px 17px', padding:'5px 8px',
background: t.panel2, borderLeft:`2px solid ${t.danger}`,
fontSize: 10.5, color: t.dim,
}}>
<div style={{ color: t.danger, fontWeight: 600, marginBottom: 2 }}>{r.error}</div>
<div>{r.hint}</div>
</div>
)}
</div>
);
})}
</div>
);
}
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 (
<div style={{
flex:1, padding:'6px 10px', border:`1px solid ${c}`, borderRadius: 2,
background: `${c}1a`, color: c, fontFamily: fontMono, fontWeight: 700, fontSize: 11.5,
display:'flex', alignItems:'center', gap: 6,
}}>
<span className="drv-pulsedot" style={{ width: 6, height: 6, borderRadius: 3, background: c }}/>
ACTIVE{warning ? ' · UDP-FALLBACK' : ''}
</div>
);
}
return (
<button onClick={D.startProxy} disabled={!ok} style={{
flex: 1, padding:'6px 10px', borderRadius: 2,
background: ok ? t.accent : t.panel, color: ok ? t.primaryFg : t.dimmer,
border:`1px solid ${ok ? t.accent : t.border}`, fontFamily: fontMono,
fontWeight: 700, fontSize: 11.5, letterSpacing: 0.5, textAlign:'left',
cursor: ok ? 'pointer' : 'not-allowed',
}}>{'>'} start proxying</button>
);
}
function CompactStopBtn({ t, D, fontMono }) {
const enabled = D.phase === 'active';
return (
<button onClick={D.stopProxy} disabled={!enabled} style={{
flex: 1, padding:'6px 10px', borderRadius: 2,
background: t.panel, color: enabled ? t.text : t.dimmer,
border:`1px solid ${t.border}`, fontFamily: fontMono,
fontWeight: 700, fontSize: 11.5, letterSpacing: 0.5, textAlign:'left',
cursor: enabled ? 'pointer' : 'not-allowed',
}}>{'■'} stop</button>
);
}
function CompactLogs({ t, D, fontMono }) {
return (
<div style={{ borderTop:`1px solid ${t.border}`, background: t.chrome, flexShrink: 0 }}>
<button onClick={() => D.setLogsOpen(!D.logsOpen)} style={{
width:'100%', padding:'6px 12px', display:'flex', alignItems:'center', gap: 7,
background:'transparent', border:'none', color: t.dim, cursor:'pointer',
fontFamily: fontMono, fontSize: 10.5, letterSpacing: 1,
}}>
<window.IconChevron color={t.dim} dir={D.logsOpen?'down':'right'}/>
<span style={{ fontWeight: 700 }}>LOGS</span>
<span style={{ marginLeft:'auto', color: t.dimmer }}>{D.logs.length} lines</span>
</button>
{D.logsOpen && (
<>
<div style={{ display:'flex', gap: 4, padding:'0 12px 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.border}`, color: t.dim,
padding:'2px 7px', fontSize: 10, fontFamily: fontMono, cursor:'pointer', borderRadius: 2,
}}>{l}</button>
))}
</div>
<div className="drv-log" ref={el => 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) => (
<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.pass, fontWeight: 700 }}>{l.level.padEnd(5)}</span>{' '}
{l.msg}
</div>
))}
</div>
</>
)}
</div>
);
}
window.CompactWindow = CompactWindow;