// drover-fluent-live.jsx — Fluent / Win11 live variant. // System-native: Segoe UI Variable, acrylic-blue (#0067c0), light cards on a tinted bg. const FLUENT_THEME = { l: { bg: '#f3f3f3', chrome: '#fafafa', panel: '#ffffff', panelAlt: '#f7f7f7', border: 'rgba(0,0,0,.06)', borderHard:'#d6d6d6', text: '#1a1a1a', dim: '#666666', dimmer: '#999999', accent: '#0067c0', accentHover:'#005a9e', danger: '#c42b1c', warn: '#9d5d00', pass: '#107c10', skip: '#888888', inputBg: '#fafafa', inputBorder:'#888', activeBg: '#dff6dd', activeBorder:'#9bc99b', warnBg: '#fff4ce', warnBorder:'#dba81a', }, d: { bg: '#202020', chrome: '#181818', panel: '#2b2b2b', panelAlt: '#252525', border: 'rgba(255,255,255,.06)', borderHard:'#3a3a3a', text: '#f0f0f0', dim: '#9b9b9b', dimmer: '#6a6a6a', accent: '#4cc2ff', accentHover:'#6cd0ff', danger: '#ff6b6b', warn: '#fce100', pass: '#6ccb5f', skip: '#7a7a7a', inputBg: '#2c2c2c', inputBorder:'#666', activeBg: '#1d2f1c', activeBorder:'#3d6e3a', warnBg: '#3a3017', warnBorder:'#7a6320', }, }; function FluentWindow({ mode = 'light', initial }) { const themeKey = mode === 'dark' ? 'd' : 'l'; const t = FLUENT_THEME[themeKey]; const D = window.useDrover(initial); const palette = { pending: t.dimmer, running: t.accent, passed: t.pass, failed: t.danger, skipped: t.skip }; const fontUI = "'Segoe UI Variable','Segoe UI',system-ui,-apple-system,sans-serif"; const fontMono = "'Cascadia Mono','Cascadia Code',Consolas,'JetBrains Mono',ui-monospace,monospace"; const isActive = D.phase === 'active'; return (
{/* SOCKS5 form card */} SOCKS5 Proxy
D.update({ host: e.target.value })} onKeyDown={e => e.key === 'Enter' && D.runCheck()} placeholder="95.165.72.59 или example.com" style={fluentInputStyle(t, fontMono)} /> D.update({ port: e.target.value.replace(/\D/g,'') })} onKeyDown={e => e.key === 'Enter' && D.runCheck()} placeholder="12334" inputMode="numeric" style={fluentInputStyle(t, fontMono)} />
{ D.update({ auth: v }); if (v) setTimeout(() => document.getElementById('flu-login')?.focus(), 30); }}> Authentication
D.update({ login: e.target.value })} onKeyDown={e => e.key === 'Enter' && D.runCheck()} placeholder="user" style={fluentInputStyle(t, fontMono, !D.form.auth)} /> D.update({ password: e.target.value })} onKeyDown={e => e.key === 'Enter' && D.runCheck()} placeholder="••••••" style={fluentInputStyle(t, fontMono, !D.form.auth)} />
{D.phase === 'checking' ? 'Checking…' : 'Check connection'}
{/* Status card */} Status {/* Action buttons */}
{isActive && }
); } function FluentTitleBar({ t, mode }) { return (
Drover-Go 0.4.2
); } function FluentTitleBtn({ children, t, hoverBg, hoverFg }) { const [hover, setHover] = React.useState(false); return (
setHover(true)} onMouseLeave={() => setHover(false)} style={{ width: 46, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', background: hover ? (hoverBg || 'rgba(127,127,127,.12)') : 'transparent', color: hover && hoverFg ? hoverFg : 'inherit', }}>{children}
); } function FluentCard({ t, children, style }) { return (
{children}
); } function FluentCardTitle({ t, children }) { return
{children}
; } function FluentField({ t, label, children, style }) { return ( ); } function fluentInputStyle(t, fontMono, disabled) { return { height: 30, background: t.inputBg, color: disabled ? t.dimmer : t.text, border: `1px solid ${t.border}`, borderBottom: `1.5px solid ${t.inputBorder}`, borderRadius: 4, padding: '0 10px', fontFamily: fontMono, fontSize: 12.5, outline: 'none', width: '100%', boxSizing: 'border-box', transition: 'border-color .12s', }; } function FluentCheckbox({ t, checked, onChange, children }) { return ( ); } function FluentPrimaryBtn({ t, onClick, disabled, children, style }) { const [hover, setHover] = React.useState(false); return ( ); } function FluentStatus({ t, D, palette, fontMono, themeKey }) { if (D.phase === 'idle') { return (
Ready to check
); } return ( <>
{D.phase === 'checking' ? <> Running diagnostics… {Object.keys(D.results).length}/{D.tests.length} : D.lastSummary?.failed === 0 ? All checks passed. Ready to start. : {D.lastSummary?.failed} of {D.tests.length} checks 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'); return (
{test.label} {r?.metric || (state === 'running' ? '…' : '')} {r?.result === 'failed' && ( )}
{r?.result === 'failed' && r.expanded && (
{r.error}
{r.hint}
)}
); })}
); } function FluentStartBtn({ t, D, fontMono }) { const phase = D.phase; const summary = D.lastSummary; const allFailed = summary && summary.failed === D.tests.length; const checkedOk = phase === 'checked' && !allFailed; const active = phase === 'active'; const warning = active && (summary?.failed || 0) > 0; if (active) { return (
Active{warning ? ' · UDP fallback' : ''}
); } return ( Start proxying ); } function FluentStopBtn({ t, D }) { const enabled = D.phase === 'active'; const [hover, setHover] = React.useState(false); return ( ); } function FluentLiveStats({ t, stats, fontMono }) { const cell = (label, val) => (
{label}{val}
); return (
{cell(, window.fmtBytes(stats.up))} {cell(, window.fmtBytes(stats.down))} {cell(TCP, stats.tcp)} {cell(UDP, stats.udp)} {cell(↑t, window.fmtUptime(stats.uptimeS))}
); } function FluentLogs({ t, D, fontMono }) { return (
{D.logsOpen && (
{[ ['Copy all', () => navigator.clipboard?.writeText(D.logs.map(l => `[${l.level}] ${l.msg}`).join('\n'))], ['Clear', D.clearLogs], ['Open log file', () => {}], ].map(([l, fn], i) => ( ))}
el && (el.scrollTop = el.scrollHeight)}> {D.logs.map((l, i) => (
{window.fmtTime(l.t)} {' '} [{l.level}] {' '} {l.msg}
))}
)}
); } window.FluentWindow = FluentWindow;