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

904 lines
63 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-Go · style sketches v2 — "feels like real software" set.
// Each artboard explores a DIFFERENT software UI paradigm + element vocabulary,
// not just a different palette. 480×640 fixed Win11 window unless noted.
const W = 480;
const H = 640;
const Win = ({ children, bg = '#fff', radius = 8, ring = 'rgba(0,0,0,.18)' }) => (
<div style={{
width: W, height: H, background: bg, borderRadius: radius,
boxShadow: `0 0 0 1px ${ring}, 0 24px 60px rgba(0,0,0,.18)`,
overflow: 'hidden', position: 'relative', display: 'flex', flexDirection: 'column'
}}>{children}</div>
);
const Mark = ({ size = 14, color = '#0c8c7a' }) => (
<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
<circle cx="8" cy="8" r="6.5" stroke={color} strokeWidth="1.5"/>
<path d="M5.5 5.5 8.5 8 5.5 10.5" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M9 5.5 12 8 9 10.5" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" opacity=".5"/>
</svg>
);
const TitleButtons = ({ color = '#666' }) => (
<div style={{ marginLeft: 'auto', display: 'flex', gap: 4, color }}>
<span style={{ width: 22, height: 22, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}></span>
<span style={{ width: 22, height: 22, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}></span>
<span style={{ width: 22, height: 22, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>×</span>
</div>
);
// ═════════════════════════════════════════════════════════════════════════
// 1 · Fluent / Win11 native — the safe baseline
// ═════════════════════════════════════════════════════════════════════════
const SketchFluent = () => {
const f = "'Segoe UI Variable','Segoe UI',system-ui,sans-serif";
return (
<Win bg="#f3f3f3" radius={10}>
<div style={{ height: 36, display: 'flex', alignItems: 'center', padding: '0 14px', fontFamily: f, fontSize: 12.5, color: '#1a1a1a' }}>
<Mark color="#0067c0" />
<span style={{ marginLeft: 10, fontWeight: 600 }}>Drover-Go</span>
<span style={{ marginLeft: 8, color: '#888', fontSize: 11 }}>0.4.2</span>
<TitleButtons />
</div>
<div style={{ padding: 14, fontFamily: f, fontSize: 13.5, flex: 1, display: 'flex', flexDirection: 'column', gap: 10, overflow: 'hidden' }}>
<div style={{ background: '#fff', borderRadius: 8, padding: 12, boxShadow: '0 0 0 1px rgba(0,0,0,.05), 0 1px 3px rgba(0,0,0,.04)' }}>
<div style={{ fontSize: 12, fontWeight: 600, color: '#444', marginBottom: 10 }}>SOCKS5 Proxy</div>
<div style={{ display: 'flex', gap: 8 }}>
<FluentField flex={1} label="Host" value="95.165.72.59" />
<FluentField width={88} label="Port" value="12334" />
</div>
<label style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 10, fontSize: 12.5 }}>
<span style={{ width: 16, height: 16, borderRadius: 4, border: '1px solid #ccc', background: '#fff' }} />
<span style={{ color: '#888' }}>Authentication</span>
</label>
<button style={{ marginTop: 12, width: '100%', height: 34, background: '#0067c0', color: '#fff', border: 'none', borderRadius: 4, fontFamily: f, fontWeight: 600, fontSize: 13, boxShadow: '0 1px 0 rgba(0,0,0,.1) inset, 0 1px 2px rgba(0,103,192,.3)' }}>Check connection</button>
</div>
<div style={{ background: '#fff', borderRadius: 8, padding: 12, boxShadow: '0 0 0 1px rgba(0,0,0,.05), 0 1px 3px rgba(0,0,0,.04)', flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
<div style={{ fontSize: 12, fontWeight: 600, color: '#444', marginBottom: 10 }}>Status</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, color: '#0067c0', fontSize: 12.5, marginBottom: 8 }}>
<span style={{ width: 14, height: 14, borderRadius: '50%', border: '2px solid #0067c0', borderRightColor: 'transparent', animation: 'spin 1s linear infinite' }} />
Running diagnostics
</div>
{[
['✓', 'TCP reachability', '12 ms', '#107c10'],
['✓', 'SOCKS5 greeting', 'ok', '#107c10'],
['◐', 'TCP CONNECT to Discord', '…', '#0067c0'],
['·', 'UDP ASSOCIATE', '', '#bbb'],
['·', 'UDP round-trip via STUN', '', '#bbb'],
['·', 'Discord API reachable', '', '#bbb'],
].map(([ic, name, val, c], i) => (
<div key={i} style={{ display: 'flex', alignItems: 'center', padding: '4px 0', fontSize: 12.5 }}>
<span style={{ width: 18, color: c, fontWeight: 600 }}>{ic}</span>
<span style={{ flex: 1 }}>{name}</span>
<span style={{ color: '#888', fontFamily: "'Cascadia Mono', monospace", fontSize: 11.5 }}>{val}</span>
</div>
))}
</div>
<div style={{ display: 'flex', gap: 8 }}>
<button style={{ flex: 1, height: 36, background: '#0067c0', color: '#fff', border: 'none', borderRadius: 4, fontWeight: 600, opacity: 0.4 }}>Start proxying</button>
<button style={{ flex: 1, height: 36, background: '#fff', border: '1px solid #ddd', borderRadius: 4, color: '#aaa' }}>Stop</button>
</div>
</div>
<style>{`@keyframes spin{to{transform:rotate(360deg)}}`}</style>
</Win>
);
};
const FluentField = ({ label, value, flex, width }) => (
<label style={{ flex, width, display: 'block' }}>
<div style={{ fontSize: 11, color: '#888', marginBottom: 3 }}>{label}</div>
<div style={{ height: 30, background: '#fafafa', borderRadius: 4, padding: '0 10px', display: 'flex', alignItems: 'center', fontSize: 13, color: '#1a1a1a', borderBottom: '1.5px solid #888', boxShadow: '0 0 0 1px rgba(0,0,0,.06)' }}>{value}</div>
</label>
);
// ═════════════════════════════════════════════════════════════════════════
// 2 · Sidebar nav (VS Code / Postman / Tower) — left rail with sections
// ═════════════════════════════════════════════════════════════════════════
const SketchSidebar = () => {
const f = "'Inter', system-ui, sans-serif";
const m = "'JetBrains Mono', monospace";
return (
<Win bg="#1e1f22" radius={8} ring="rgba(255,255,255,.06)">
<div style={{ height: 30, display: 'flex', alignItems: 'center', padding: '0 12px', borderBottom: '1px solid #2a2c30', fontFamily: f, fontSize: 12, color: '#cbd1d9' }}>
<Mark color="#4f8eff" />
<span style={{ marginLeft: 8, fontWeight: 500 }}>Drover-Go</span>
<span style={{ marginLeft: 8, color: '#666' }}> proxy: 95.165.72.59:12334</span>
<TitleButtons color="#888" />
</div>
<div style={{ flex: 1, display: 'flex', minHeight: 0 }}>
{/* sidebar */}
<div style={{ width: 56, background: '#191a1d', borderRight: '1px solid #2a2c30', display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '8px 0', gap: 4, fontFamily: f }}>
{[['◉', 'Proxy', true], ['◇', 'Diagnose'], ['≋', 'Traffic'], ['≣', 'Logs'], ['⚙', 'Settings']].map(([ic, l, on], i) => (
<div key={i} style={{ width: 40, height: 40, borderRadius: 6, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', color: on ? '#fff' : '#888', background: on ? '#2c3140' : 'transparent', borderLeft: on ? '2px solid #4f8eff' : '2px solid transparent', position: 'relative', fontSize: 14 }}>
<span>{ic}</span>
<span style={{ fontSize: 8, marginTop: 1 }}>{l}</span>
</div>
))}
</div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, fontFamily: f, fontSize: 13, color: '#cbd1d9' }}>
{/* breadcrumb / tabs */}
<div style={{ height: 30, display: 'flex', alignItems: 'flex-end', padding: '0 0 0 0', borderBottom: '1px solid #2a2c30', background: '#191a1d' }}>
<div style={{ padding: '6px 12px', background: '#1e1f22', borderRight: '1px solid #2a2c30', borderTop: '2px solid #4f8eff', fontSize: 11.5, color: '#fff' }}> Proxy</div>
<div style={{ padding: '6px 12px', borderRight: '1px solid #2a2c30', fontSize: 11.5, color: '#888' }}>diagnostic.run</div>
</div>
<div style={{ flex: 1, padding: 14, display: 'flex', flexDirection: 'column', gap: 12, overflow: 'hidden' }}>
<div>
<div style={{ fontSize: 10.5, letterSpacing: '.1em', color: '#888', textTransform: 'uppercase', marginBottom: 8 }}>Endpoint</div>
<div style={{ display: 'flex', gap: 6, alignItems: 'stretch' }}>
<div style={{ background: '#2c3140', border: '1px solid #3a4050', borderRight: 'none', padding: '0 10px', fontFamily: m, fontSize: 11, color: '#4f8eff', display: 'flex', alignItems: 'center', borderRadius: '4px 0 0 4px' }}>SOCKS5</div>
<div style={{ flex: 1, background: '#15171b', border: '1px solid #3a4050', padding: '0 10px', display: 'flex', alignItems: 'center', fontFamily: m, fontSize: 12, color: '#fff' }}>95.165.72.59</div>
<div style={{ width: 70, background: '#15171b', border: '1px solid #3a4050', borderLeft: 'none', padding: '0 10px', display: 'flex', alignItems: 'center', fontFamily: m, fontSize: 12, color: '#fff', borderRadius: '0 4px 4px 0' }}>:12334</div>
<button style={{ padding: '0 16px', background: '#4f8eff', color: '#fff', border: 'none', borderRadius: 4, fontWeight: 600, fontSize: 12.5 }}>Run </button>
</div>
</div>
<div style={{ flex: 1, minHeight: 0 }}>
<div style={{ fontSize: 10.5, letterSpacing: '.1em', color: '#888', textTransform: 'uppercase', marginBottom: 8 }}>Diagnostic results</div>
<div style={{ background: '#15171b', border: '1px solid #2a2c30', borderRadius: 5, fontFamily: m, fontSize: 11.5 }}>
{[
['✓', 'tcp_reachability', '12 ms', '#21d07a'],
['✓', 'socks5_greeting', 'ok', '#21d07a'],
['✓', 'socks5_authentication', 'ok', '#21d07a'],
['✓', 'tcp_connect_discord', '38 ms', '#21d07a'],
['✗', 'udp_associate', 'EPERM: blocked', '#ff5e5e'],
['—', 'udp_stun_rtt', 'skipped', '#666'],
['—', 'discord_api', 'skipped', '#666'],
].map(([ic, n, v, c], i) => (
<div key={i} style={{ display: 'flex', padding: '5px 10px', borderBottom: i < 6 ? '1px solid #1f2126' : 'none' }}>
<span style={{ width: 16, color: c }}>{ic}</span>
<span style={{ flex: 1, color: c === '#666' ? '#666' : '#cbd1d9' }}>{n}</span>
<span style={{ color: c }}>{v}</span>
</div>
))}
</div>
<div style={{ marginTop: 10, padding: 8, background: '#3a1f1f', border: '1px solid #6e2a2a', borderRadius: 5, fontSize: 11.5, color: '#ff9e9e' }}>
1 of 7 checks failed. UDP voice/screenshare won't work.
</div>
</div>
</div>
{/* status bar */}
<div style={{ height: 22, display: 'flex', alignItems: 'center', padding: '0 10px', background: '#15171b', borderTop: '1px solid #2a2c30', fontFamily: m, fontSize: 10.5, color: '#888' }}>
<span style={{ color: '#ff9e9e' }}>● 6/7</span>
<span style={{ marginLeft: 12 }}>idle</span>
<span style={{ marginLeft: 'auto' }}>UTF-8 · LF · drover.toml</span>
</div>
</div>
</div>
</Win>
);
};
// ═════════════════════════════════════════════════════════════════════════
// 3 · Step wizard / Tab progression — DigiCert / Tunnelblick connect-flow
// ═════════════════════════════════════════════════════════════════════════
const SketchWizard = () => {
const f = "'Inter', system-ui, sans-serif";
return (
<Win bg="#fafafa" radius={8} ring="rgba(0,0,0,.12)">
<div style={{ height: 32, display: 'flex', alignItems: 'center', padding: '0 12px', borderBottom: '1px solid #ececec', fontFamily: f, fontSize: 12, color: '#1a1a1a' }}>
<Mark color="#1e6fd9" />
<span style={{ marginLeft: 8, fontWeight: 600 }}>Drover-Go · Setup</span>
<TitleButtons />
</div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', fontFamily: f, color: '#1a1a1a' }}>
{/* stepper */}
<div style={{ display: 'flex', padding: '14px 18px', gap: 0, alignItems: 'center', borderBottom: '1px solid #ececec', background: '#fff' }}>
{[['1', 'Configure', true], ['2', 'Verify', true], ['3', 'Connect', false]].map(([n, l, done], i) => (
<React.Fragment key={i}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<span style={{ width: 22, height: 22, borderRadius: '50%', background: i === 1 ? '#1e6fd9' : (done ? '#1e6fd9' : '#ddd'), color: '#fff', fontSize: 11, fontWeight: 600, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
{done && i !== 1 ? '' : n}
</span>
<span style={{ fontSize: 12, fontWeight: i === 1 ? 600 : 400, color: i === 1 ? '#1a1a1a' : '#888' }}>{l}</span>
</div>
{i < 2 && <div style={{ flex: 1, height: 1, background: i === 0 ? '#1e6fd9' : '#ddd', margin: '0 10px' }} />}
</React.Fragment>
))}
</div>
<div style={{ flex: 1, padding: '20px 22px', display: 'flex', flexDirection: 'column', gap: 14, overflow: 'hidden' }}>
<div>
<h2 style={{ margin: 0, fontSize: 18, fontWeight: 600 }}>Verifying your proxy</h2>
<div style={{ fontSize: 12.5, color: '#666', marginTop: 4 }}>We're running 7 checks against <span style={{ fontFamily: "'JetBrains Mono',monospace", color: '#1a1a1a' }}>95.165.72.59:12334</span> to make sure Discord will work end-to-end.</div>
</div>
{/* progress + ring */}
<div style={{ display: 'flex', alignItems: 'center', gap: 16, padding: 14, background: '#fff', border: '1px solid #ececec', borderRadius: 8 }}>
<svg width="64" height="64" viewBox="0 0 64 64">
<circle cx="32" cy="32" r="26" fill="none" stroke="#eee" strokeWidth="6" />
<circle cx="32" cy="32" r="26" fill="none" stroke="#1e6fd9" strokeWidth="6" strokeLinecap="round" strokeDasharray="163.4" strokeDashoffset="70" transform="rotate(-90 32 32)" />
<text x="32" y="36" textAnchor="middle" fontSize="14" fontWeight="600" fill="#1a1a1a">4/7</text>
</svg>
<div style={{ flex: 1 }}>
<div style={{ fontWeight: 600, fontSize: 13.5 }}>Testing UDP relay</div>
<div style={{ fontSize: 12, color: '#666', marginTop: 2 }}>This usually takes 515 seconds.</div>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 4, fontSize: 12.5 }}>
{[
['✓', 'TCP reachability', '12 ms', '#21a655'],
['✓', 'SOCKS5 greeting', 'ok', '#21a655'],
['✓', 'SOCKS5 authentication', 'ok', '#21a655'],
['✓', 'TCP CONNECT to Discord', '38 ms', '#21a655'],
['◐', 'UDP ASSOCIATE', 'running…', '#1e6fd9'],
['·', 'UDP round-trip via STUN', '', '#bbb'],
['·', 'Discord API reachable', '', '#bbb'],
].map(([ic, n, v, c], i) => (
<div key={i} style={{ display: 'flex', alignItems: 'center', padding: '5px 10px', background: i === 4 ? '#eef4fc' : 'transparent', borderRadius: 4 }}>
<span style={{ width: 18, color: c, fontWeight: 600 }}>{ic}</span>
<span style={{ flex: 1, color: c === '#bbb' ? '#999' : '#1a1a1a' }}>{n}</span>
<span style={{ color: c, fontFamily: "'JetBrains Mono',monospace", fontSize: 11.5 }}>{v}</span>
</div>
))}
</div>
</div>
<div style={{ height: 50, display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 8, padding: '0 18px', borderTop: '1px solid #ececec', background: '#fff' }}>
<button style={{ height: 30, padding: '0 14px', background: '#fff', border: '1px solid #ddd', borderRadius: 4, fontSize: 12.5 }}>Back</button>
<button style={{ height: 30, padding: '0 14px', background: '#1e6fd9', color: '#fff', border: 'none', borderRadius: 4, fontSize: 12.5, fontWeight: 600, opacity: 0.5 }}>Continue </button>
</div>
</div>
</Win>
);
};
// ═════════════════════════════════════════════════════════════════════════
// 4 · Network monitor — gauges, sparklines, multi-pane (Wireshark / Activity)
// ═════════════════════════════════════════════════════════════════════════
const SketchMonitor = () => {
const f = "'Inter', system-ui, sans-serif";
const m = "'JetBrains Mono', monospace";
return (
<Win bg="#fcfcfc" radius={6} ring="rgba(0,0,0,.12)">
<div style={{ height: 30, display: 'flex', alignItems: 'center', padding: '0 12px', borderBottom: '1px solid #e6e6e6', fontFamily: f, fontSize: 12, background: '#f5f5f5' }}>
<Mark color="#0c8c7a" />
<span style={{ marginLeft: 8, fontWeight: 600 }}>Drover-Go</span>
<span style={{ marginLeft: 8, fontFamily: m, fontSize: 10, color: '#21a655' }}> ACTIVE 4m 12s</span>
<TitleButtons />
</div>
<div style={{ flex: 1, padding: 12, display: 'flex', flexDirection: 'column', gap: 10, fontFamily: f, fontSize: 12, color: '#222', overflow: 'hidden' }}>
{/* compact endpoint */}
<div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 10px', background: '#fff', border: '1px solid #e6e6e6', borderRadius: 5 }}>
<span style={{ width: 8, height: 8, borderRadius: '50%', background: '#21a655' }} />
<span style={{ fontFamily: m, fontSize: 11.5 }}>95.165.72.59:12334</span>
<span style={{ marginLeft: 'auto', color: '#888', fontSize: 11 }}>SOCKS5 · auth</span>
<button style={{ background: 'transparent', border: '1px solid #ddd', borderRadius: 4, padding: '2px 8px', fontSize: 11 }}>Edit</button>
</div>
{/* meters */}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 8 }}>
<Gauge label="Upload" v="142" unit="KB/s" pct={28} c="#0c8c7a" />
<Gauge label="Download" v="2.8" unit="MB/s" pct={84} c="#1e6fd9" />
</div>
{/* sparkline panel */}
<div style={{ background: '#fff', border: '1px solid #e6e6e6', borderRadius: 5, padding: 10 }}>
<div style={{ display: 'flex', alignItems: 'baseline', marginBottom: 6 }}>
<span style={{ fontSize: 10.5, letterSpacing: '.06em', color: '#888', textTransform: 'uppercase' }}>Throughput · last 60s</span>
<span style={{ marginLeft: 'auto', fontFamily: m, fontSize: 11, color: '#222' }}>peak 3.4 MB/s</span>
</div>
<svg width="100%" height="60" viewBox="0 0 400 60" preserveAspectRatio="none">
<path d="M0 50 L20 45 L40 30 L60 35 L80 18 L100 25 L120 12 L140 22 L160 8 L180 18 L200 28 L220 15 L240 30 L260 20 L280 38 L300 25 L320 32 L340 18 L360 24 L380 14 L400 20 L400 60 L0 60Z" fill="#1e6fd9" opacity=".15" />
<path d="M0 50 L20 45 L40 30 L60 35 L80 18 L100 25 L120 12 L140 22 L160 8 L180 18 L200 28 L220 15 L240 30 L260 20 L280 38 L300 25 L320 32 L340 18 L360 24 L380 14 L400 20" fill="none" stroke="#1e6fd9" strokeWidth="1.5" />
</svg>
</div>
{/* connections table */}
<div style={{ flex: 1, background: '#fff', border: '1px solid #e6e6e6', borderRadius: 5, overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
<div style={{ display: 'flex', padding: '6px 10px', background: '#f5f5f5', borderBottom: '1px solid #e6e6e6', fontSize: 10.5, color: '#888', letterSpacing: '.06em', textTransform: 'uppercase' }}>
<span style={{ width: 50 }}>Proto</span>
<span style={{ flex: 1 }}>Endpoint</span>
<span style={{ width: 80, textAlign: 'right' }}>Up</span>
<span style={{ width: 80, textAlign: 'right' }}>Down</span>
</div>
{[
['UDP', 'voice-eu-rtc-1.discord', '142 KB/s', '2.4 MB/s', '#1e6fd9'],
['TCP', 'gateway.discord:443', '8 KB/s', '12 KB/s', '#0c8c7a'],
['TCP', 'cdn.discordapp:443', '0', '380 KB/s', '#0c8c7a'],
['TCP', 'media.discordapp:443', '0', '8 KB/s', '#0c8c7a'],
].map((r, i) => (
<div key={i} style={{ display: 'flex', padding: '5px 10px', fontFamily: m, fontSize: 11, borderBottom: i < 3 ? '1px solid #f0f0f0' : 'none' }}>
<span style={{ width: 50, color: r[4], fontWeight: 600 }}>{r[0]}</span>
<span style={{ flex: 1 }}>{r[1]}</span>
<span style={{ width: 80, textAlign: 'right', color: '#666' }}>{r[2]}</span>
<span style={{ width: 80, textAlign: 'right', color: '#666' }}>{r[3]}</span>
</div>
))}
</div>
<div style={{ display: 'flex', gap: 8 }}>
<button style={{ flex: 1, height: 32, background: '#21a655', color: '#fff', border: 'none', borderRadius: 4, fontWeight: 600, fontSize: 12.5 }}> Active · 4m 12s</button>
<button style={{ flex: 1, height: 32, background: '#fff', border: '1px solid #ddd', borderRadius: 4, fontSize: 12.5 }}>Stop</button>
</div>
</div>
</Win>
);
};
const Gauge = ({ label, v, unit, pct, c }) => (
<div style={{ background: '#fff', border: '1px solid #e6e6e6', borderRadius: 5, padding: 10 }}>
<div style={{ display: 'flex', alignItems: 'baseline' }}>
<span style={{ fontSize: 10.5, letterSpacing: '.06em', color: '#888', textTransform: 'uppercase' }}>{label}</span>
</div>
<div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginTop: 4 }}>
<span style={{ fontSize: 22, fontWeight: 600, fontFamily: "'JetBrains Mono',monospace" }}>{v}</span>
<span style={{ fontSize: 11, color: '#888' }}>{unit}</span>
</div>
<div style={{ height: 4, background: '#f0f0f0', borderRadius: 2, marginTop: 6, overflow: 'hidden' }}>
<div style={{ width: pct + '%', height: '100%', background: c }} />
</div>
</div>
);
// ═════════════════════════════════════════════════════════════════════════
// 5 · Inspector / Properties — devtools-style key:value list
// ═════════════════════════════════════════════════════════════════════════
const SketchInspector = () => {
const f = "'Inter', system-ui, sans-serif";
const m = "'JetBrains Mono', monospace";
return (
<Win bg="#fff" radius={6} ring="rgba(0,0,0,.12)">
<div style={{ height: 28, display: 'flex', alignItems: 'center', padding: '0 12px', borderBottom: '1px solid #ececec', fontFamily: f, fontSize: 11.5 }}>
<Mark color="#1a1a1a" size={12} />
<span style={{ marginLeft: 8, fontWeight: 600 }}>Drover-Go</span>
<span style={{ marginLeft: 8, color: '#888', fontSize: 10.5 }}>0.4.2</span>
<TitleButtons />
</div>
{/* tabs */}
<div style={{ height: 28, display: 'flex', borderBottom: '1px solid #ececec', fontFamily: f, fontSize: 11.5, background: '#fafafa' }}>
{['Inspector', 'Network', 'Console', 'Settings'].map((t, i) => (
<div key={t} style={{ padding: '0 14px', display: 'flex', alignItems: 'center', borderBottom: i === 0 ? '2px solid #1a1a1a' : '2px solid transparent', color: i === 0 ? '#1a1a1a' : '#888', fontWeight: i === 0 ? 600 : 400 }}>{t}</div>
))}
</div>
<div style={{ flex: 1, fontFamily: m, fontSize: 11.5, color: '#1a1a1a', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
<Group title="proxy" expanded>
<KV k="protocol" v="SOCKS5" t="enum" />
<KV k="host" v={<input style={{ all: 'unset', width: '100%', fontFamily: m, fontSize: 11.5, color: '#1a1a1a' }} defaultValue="95.165.72.59" />} editable />
<KV k="port" v="12334" t="int" editable />
<KV k="auth.enabled" v="true" t="bool" />
<KV k="auth.user" v="alice" t="str" editable />
<KV k="auth.pass" v="••••••••" t="str" editable />
</Group>
<Group title="diagnostic.last_run" expanded>
<KV k="started_at" v="14:32:01" t="time" />
<KV k="duration" v="3.2 s" t="dur" />
<KV k="passed" v="7" t="int" color="#21a655" />
<KV k="failed" v="0" t="int" />
<KV k="checks[0].name" v="tcp_reachability" />
<KV k="checks[0].rtt" v="12 ms" />
<KV k="checks[1].name" v="socks5_greeting" />
<KV k="checks[2].name" v="socks5_authentication" />
</Group>
<Group title="state" expanded>
<KV k="status" v="ready" t="enum" color="#21a655" />
<KV k="active" v="false" t="bool" />
</Group>
</div>
<div style={{ height: 32, display: 'flex', gap: 6, padding: '0 8px', alignItems: 'center', borderTop: '1px solid #ececec', background: '#fafafa' }}>
<button style={{ height: 22, padding: '0 10px', background: '#fff', border: '1px solid #ccc', borderRadius: 3, fontFamily: f, fontSize: 11 }}>Run diagnostic</button>
<button style={{ height: 22, padding: '0 10px', background: '#1a1a1a', color: '#fff', border: 'none', borderRadius: 3, fontFamily: f, fontSize: 11, fontWeight: 600 }}> Start proxying</button>
<span style={{ marginLeft: 'auto', fontFamily: m, fontSize: 10.5, color: '#888' }}>14 props · saved</span>
</div>
</Win>
);
};
const Group = ({ title, expanded, children }) => (
<div>
<div style={{ padding: '4px 10px', background: '#f0f0f0', fontSize: 10.5, fontWeight: 600, color: '#444', display: 'flex', alignItems: 'center' }}>
<span style={{ marginRight: 4, fontSize: 9 }}>{expanded ? '▼' : '▶'}</span>{title}
</div>
<div>{children}</div>
</div>
);
const KV = ({ k, v, t, color, editable }) => (
<div style={{ display: 'flex', padding: '3px 10px', borderBottom: '1px solid #f5f5f5', alignItems: 'center', fontSize: 11 }}>
<span style={{ width: 150, color: '#888' }}>{k}</span>
<span style={{ flex: 1, color: color || '#1a1a1a', background: editable ? '#f9f9f9' : 'transparent', borderRadius: 2, padding: '1px 4px' }}>{v}</span>
{t && <span style={{ marginLeft: 8, fontSize: 9.5, color: '#bbb', textTransform: 'uppercase' }}>{t}</span>}
</div>
);
// ═════════════════════════════════════════════════════════════════════════
// 6 · Command palette + form — Raycast / Linear / cmd+k feel
// ═════════════════════════════════════════════════════════════════════════
const SketchPalette = () => {
const f = "'Inter', system-ui, sans-serif";
const m = "'JetBrains Mono', monospace";
return (
<Win bg="#0f1015" radius={14} ring="rgba(255,255,255,.08)">
<div style={{ height: 32, display: 'flex', alignItems: 'center', padding: '0 14px', fontFamily: f, fontSize: 12, color: '#cbd1d9' }}>
<Mark color="#a5b4ff" />
<span style={{ marginLeft: 8, fontWeight: 500 }}>Drover-Go</span>
<TitleButtons color="#666" />
</div>
<div style={{ flex: 1, padding: 14, fontFamily: f, color: '#e8e8ea', display: 'flex', flexDirection: 'column', gap: 12, overflow: 'hidden' }}>
{/* command bar */}
<div style={{ background: '#15171c', border: '1px solid #2a2d36', borderRadius: 9, padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10, boxShadow: '0 0 0 3px rgba(165,180,255,.08)' }}>
<span style={{ color: '#a5b4ff', fontSize: 14 }}></span>
<input style={{ all: 'unset', flex: 1, fontFamily: f, fontSize: 13.5, color: '#fff' }} placeholder="Search commands…" defaultValue="check con" />
<span style={{ fontFamily: m, fontSize: 10, color: '#666', padding: '2px 6px', background: '#1a1c22', border: '1px solid #2a2d36', borderRadius: 4 }}>esc</span>
</div>
{/* suggestion */}
<div style={{ background: '#15171c', borderRadius: 9, padding: 6 }}>
<div style={{ padding: '8px 10px', borderRadius: 6, background: '#23264a', display: 'flex', alignItems: 'center', gap: 10 }}>
<span style={{ width: 22, height: 22, borderRadius: 5, background: '#a5b4ff', color: '#0f1015', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontWeight: 700, fontSize: 12 }}></span>
<span style={{ flex: 1, fontSize: 13 }}>Check connection</span>
<span style={{ fontFamily: m, fontSize: 10.5, color: '#a5b4ff' }}></span>
</div>
<div style={{ padding: '8px 10px', display: 'flex', alignItems: 'center', gap: 10, color: '#888' }}>
<span style={{ width: 22, height: 22, borderRadius: 5, background: '#1a1c22', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 12 }}></span>
<span style={{ flex: 1, fontSize: 13 }}>Start proxying</span>
<span style={{ fontFamily: m, fontSize: 10.5 }}></span>
</div>
</div>
{/* Form below — proxy quick-edit */}
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 10, minHeight: 0 }}>
<div style={{ fontSize: 10.5, letterSpacing: '.1em', color: '#666', textTransform: 'uppercase' }}>Proxy</div>
<div style={{ display: 'flex', gap: 8 }}>
<PalField flex={1} label="Host" value="95.165.72.59" />
<PalField width={86} label="Port" value="12334" />
</div>
<div style={{ fontSize: 10.5, letterSpacing: '.1em', color: '#666', textTransform: 'uppercase', marginTop: 4 }}>Last run · 7/7 passed</div>
{[
['tcp_reachability', '12 ms'],
['socks5_greeting', 'ok'],
['udp_associate', 'relay 1.2.3.4'],
['udp_stun_rtt', '24 ms'],
['discord_api', '200'],
].map(([n, v], i) => (
<div key={i} style={{ display: 'flex', padding: '4px 10px', fontFamily: m, fontSize: 11.5, background: '#15171c', borderRadius: 5 }}>
<span style={{ color: '#21d07a', marginRight: 8 }}></span>
<span style={{ flex: 1, color: '#cbd1d9' }}>{n}</span>
<span style={{ color: '#888' }}>{v}</span>
</div>
))}
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 0', fontFamily: m, fontSize: 10.5, color: '#666' }}>
<span><kbd style={{ background: '#1a1c22', border: '1px solid #2a2d36', padding: '1px 5px', borderRadius: 3, color: '#cbd1d9' }}></kbd> run</span>
<span><kbd style={{ background: '#1a1c22', border: '1px solid #2a2d36', padding: '1px 5px', borderRadius: 3, color: '#cbd1d9' }}></kbd> start</span>
<span style={{ marginLeft: 'auto' }}>idle · ready</span>
</div>
</div>
</Win>
);
};
const PalField = ({ label, value, flex, width }) => (
<label style={{ flex, width }}>
<div style={{ fontSize: 10.5, color: '#888', marginBottom: 4 }}>{label}</div>
<div style={{ height: 32, background: '#15171c', border: '1px solid #2a2d36', borderRadius: 7, padding: '0 10px', display: 'flex', alignItems: 'center', fontSize: 13, color: '#fff', fontFamily: "'JetBrains Mono',monospace" }}>{value}</div>
</label>
);
// ═════════════════════════════════════════════════════════════════════════
// 7 · Big toggle / Hero — TunnelBear / NordVPN big-button connect
// ═════════════════════════════════════════════════════════════════════════
const SketchHero = () => {
const f = "'Inter', system-ui, sans-serif";
const m = "'JetBrains Mono', monospace";
return (
<Win bg="#0e1426" radius={14} ring="rgba(255,255,255,.06)">
<div style={{ height: 36, display: 'flex', alignItems: 'center', padding: '0 14px', fontFamily: f, fontSize: 12.5, color: '#cbd1d9' }}>
<Mark color="#5dd4b3" />
<span style={{ marginLeft: 10, fontWeight: 600 }}>Drover-Go</span>
<span style={{ marginLeft: 'auto', fontSize: 11, color: '#5dd4b3' }}> connected</span>
<TitleButtons color="#666" />
</div>
<div style={{ flex: 1, padding: '20px 18px', fontFamily: f, color: '#fff', display: 'flex', flexDirection: 'column', gap: 16, alignItems: 'center', overflow: 'hidden' }}>
{/* Big circular button */}
<div style={{ width: 180, height: 180, borderRadius: '50%', background: 'radial-gradient(circle at 35% 30%, #5dd4b3 0%, #2da085 60%, #1a6e5b 100%)', boxShadow: '0 0 60px rgba(93,212,179,.4), 0 0 0 6px rgba(93,212,179,.1), 0 0 0 12px rgba(93,212,179,.05)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', position: 'relative', marginTop: 12 }}>
<div style={{ position: 'absolute', inset: -20, borderRadius: '50%', border: '1px solid rgba(93,212,179,.2)', animation: 'pulse 2s infinite' }} />
<span style={{ fontSize: 36 }}></span>
<span style={{ fontSize: 11, letterSpacing: '.2em', marginTop: 4, opacity: .9 }}>ACTIVE</span>
</div>
<div style={{ textAlign: 'center' }}>
<div style={{ fontSize: 22, fontWeight: 600 }}>Discord is protected</div>
<div style={{ fontSize: 12.5, color: '#7a8499', marginTop: 4, fontFamily: m }}>via 95.165.72.59 · 4m 12s</div>
</div>
{/* Stats row */}
<div style={{ display: 'flex', gap: 0, width: '100%', background: '#15192a', borderRadius: 10, padding: 12, justifyContent: 'space-around' }}>
{[
['↑', '142', 'KB/s'],
['↓', '2.8', 'MB/s'],
['◇', '14', 'tcp'],
['◈', '3', 'udp'],
].map(([k, v, u], i) => (
<div key={i} style={{ textAlign: 'center' }}>
<div style={{ fontSize: 11, color: '#5dd4b3' }}>{k}</div>
<div style={{ fontSize: 18, fontWeight: 600, fontFamily: m, marginTop: 2 }}>{v}</div>
<div style={{ fontSize: 9.5, color: '#7a8499', letterSpacing: '.06em', textTransform: 'uppercase' }}>{u}</div>
</div>
))}
</div>
<button style={{ width: '100%', height: 38, background: 'transparent', color: '#cbd1d9', border: '1px solid #2a3042', borderRadius: 9, fontWeight: 500, fontSize: 13 }}>Disconnect</button>
<div style={{ width: '100%', fontSize: 11, color: '#5a6178', display: 'flex', alignItems: 'center', gap: 6 }}>
<span style={{ fontSize: 10 }}></span><span>Logs (3 new)</span>
</div>
</div>
<style>{`@keyframes pulse{0%,100%{transform:scale(1);opacity:.4}50%{transform:scale(1.08);opacity:0}}`}</style>
</Win>
);
};
// ═════════════════════════════════════════════════════════════════════════
// 8 · Toolbar + ribbon — old-school Office / Audacity feel
// ═════════════════════════════════════════════════════════════════════════
const SketchToolbar = () => {
const f = "'Segoe UI', system-ui, sans-serif";
const m = "'Consolas', 'JetBrains Mono', monospace";
return (
<Win bg="#ebebeb" radius={4} ring="rgba(0,0,0,.18)">
<div style={{ height: 26, display: 'flex', alignItems: 'center', padding: '0 8px', background: 'linear-gradient(180deg,#f5f5f5,#dcdcdc)', borderBottom: '1px solid #b8b8b8', fontFamily: f, fontSize: 11 }}>
<Mark color="#1a1a1a" size={12} />
<span style={{ marginLeft: 6, fontWeight: 600 }}>Drover-Go</span>
<span style={{ marginLeft: 8, color: '#666' }}> [Connected]</span>
<TitleButtons />
</div>
{/* menu bar */}
<div style={{ height: 22, display: 'flex', padding: '0 6px', background: '#ebebeb', borderBottom: '1px solid #c8c8c8', fontFamily: f, fontSize: 11, alignItems: 'center', gap: 2 }}>
{['File', 'Edit', 'Run', 'View', 'Tools', 'Help'].map(m => (
<span key={m} style={{ padding: '2px 8px', borderRadius: 2 }}>{m}</span>
))}
</div>
{/* ribbon */}
<div style={{ display: 'flex', padding: '6px 8px', background: 'linear-gradient(180deg,#f5f5f5,#e8e8e8)', borderBottom: '1px solid #c8c8c8', gap: 4 }}>
<Tool icon="▶" label="Run" primary />
<Tool icon="●" label="Start" />
<Tool icon="■" label="Stop" disabled />
<div style={{ width: 1, background: '#c8c8c8', margin: '4px 6px' }} />
<Tool icon="⚙" label="Config" />
<Tool icon="⎘" label="Copy" />
<div style={{ width: 1, background: '#c8c8c8', margin: '4px 6px' }} />
<Tool icon="≣" label="Logs" />
</div>
<div style={{ flex: 1, padding: 10, display: 'flex', flexDirection: 'column', gap: 8, fontFamily: f, fontSize: 11.5, color: '#1a1a1a', overflow: 'hidden' }}>
<Fieldset label="SOCKS5 Proxy">
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
<span style={{ width: 40 }}>Host:</span>
<div style={{ flex: 1, height: 22, background: '#fff', border: '1px solid #888', boxShadow: '1px 1px 0 #ccc inset', padding: '0 6px', display: 'flex', alignItems: 'center', fontFamily: m, fontSize: 11.5 }}>95.165.72.59</div>
<span>Port:</span>
<div style={{ width: 70, height: 22, background: '#fff', border: '1px solid #888', boxShadow: '1px 1px 0 #ccc inset', padding: '0 6px', display: 'flex', alignItems: 'center', fontFamily: m, fontSize: 11.5 }}>12334</div>
</div>
<div style={{ display: 'flex', gap: 8, alignItems: 'center', marginTop: 6 }}>
<span style={{ width: 14, height: 14, border: '1px solid #888', background: '#fff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 10 }}></span>
<span>Authentication</span>
<span style={{ marginLeft: 12 }}>User:</span>
<div style={{ flex: 1, height: 22, background: '#fff', border: '1px solid #888', boxShadow: '1px 1px 0 #ccc inset', padding: '0 6px', display: 'flex', alignItems: 'center' }}>alice</div>
</div>
</Fieldset>
<Fieldset label="Diagnostics" flex>
<div style={{ background: '#fff', border: '1px solid #888', boxShadow: '1px 1px 0 #ccc inset', flex: 1, fontFamily: m, fontSize: 11, overflow: 'auto' }}>
{[
['✓', 'TCP reachability', 'PASS · 12 ms'],
['✓', 'SOCKS5 greeting', 'PASS · ok'],
['✓', 'SOCKS5 authentication', 'PASS · ok'],
['✓', 'TCP CONNECT to Discord', 'PASS · 38 ms'],
['✓', 'UDP ASSOCIATE', 'PASS · relay 1.2.3.4'],
['✓', 'UDP round-trip via STUN', 'PASS · 24 ms'],
['✓', 'Discord API reachable', 'PASS · 200'],
].map((r, i) => (
<div key={i} style={{ display: 'flex', padding: '3px 8px', borderBottom: i < 6 ? '1px dotted #ddd' : 'none' }}>
<span style={{ width: 14, color: '#107c10' }}>{r[0]}</span>
<span style={{ flex: 1 }}>{r[1]}</span>
<span style={{ color: '#666' }}>{r[2]}</span>
</div>
))}
</div>
</Fieldset>
</div>
{/* status bar */}
<div style={{ height: 22, display: 'flex', padding: '0 8px', background: '#dcdcdc', borderTop: '1px solid #b8b8b8', alignItems: 'center', fontSize: 10.5, fontFamily: f, gap: 12 }}>
<span>Ready</span>
<span> 7/7</span>
<span> 142 KB/s 2.8 MB/s</span>
<span style={{ marginLeft: 'auto', fontFamily: m }}>uptime 4m 12s</span>
</div>
</Win>
);
};
const Tool = ({ icon, label, primary, disabled }) => (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '2px 8px', borderRadius: 2, background: primary ? 'linear-gradient(180deg,#fff,#e0e0e0)' : 'transparent', border: primary ? '1px solid #888' : '1px solid transparent', minWidth: 44, opacity: disabled ? 0.4 : 1 }}>
<span style={{ fontSize: 16, color: primary ? '#107c10' : '#1a1a1a' }}>{icon}</span>
<span style={{ fontSize: 10, marginTop: 1 }}>{label}</span>
</div>
);
const Fieldset = ({ label, children, flex }) => (
<div style={{ border: '1px solid #b8b8b8', borderRadius: 2, padding: '10px 8px 8px', position: 'relative', background: '#f5f5f5', flex: flex ? 1 : undefined, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
<span style={{ position: 'absolute', top: -8, left: 8, background: '#ebebeb', padding: '0 4px', fontSize: 10.5, fontWeight: 600 }}>{label}</span>
{children}
</div>
);
// ═════════════════════════════════════════════════════════════════════════
// 9 · Modern dev tool — Studio (Linear-ish, restrained dark)
// ═════════════════════════════════════════════════════════════════════════
const SketchStudio = () => {
const f = "'Inter', sans-serif";
return (
<Win bg="#0e0f12" radius={12} ring="rgba(255,255,255,.08)">
<div style={{ height: 36, display: 'flex', alignItems: 'center', padding: '0 14px', fontFamily: f, fontSize: 12.5, color: '#e8e8ea' }}>
<Mark color="#7c8aff" />
<span style={{ marginLeft: 10, fontWeight: 600 }}>Drover-Go</span>
<span style={{ marginLeft: 8, color: '#5a5d6a', fontSize: 11 }}>0.4.2</span>
<TitleButtons color="#777a86" />
</div>
<div style={{ padding: 14, fontFamily: f, color: '#e8e8ea', flex: 1, display: 'flex', flexDirection: 'column', gap: 12, overflow: 'hidden' }}>
<div>
<div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '.04em', color: '#a1a3ad', marginBottom: 8, textTransform: 'uppercase' }}>SOCKS5 Proxy</div>
<div style={{ display: 'flex', gap: 8 }}>
<StField flex={1} label="Host" value="95.165.72.59" />
<StField width={86} label="Port" value="12334" />
</div>
<label style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 10, fontSize: 12.5, color: '#a1a3ad' }}>
<span style={{ width: 14, height: 14, borderRadius: 4, background: '#7c8aff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontSize: 10 }}></span>
Authentication
</label>
<button style={{ marginTop: 12, width: '100%', height: 34, background: '#7c8aff', color: '#0a0a0c', border: 'none', borderRadius: 7, fontWeight: 600, fontSize: 13 }}>Check connection</button>
</div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
<div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '.04em', color: '#a1a3ad', marginBottom: 8, display: 'flex', textTransform: 'uppercase' }}>
Status <span style={{ marginLeft: 'auto', fontSize: 11, color: '#21d07a', fontWeight: 500, textTransform: 'none' }}> All systems</span>
</div>
<div style={{ background: '#15171c', border: '1px solid #1f2228', borderRadius: 9, padding: 4, flex: 1 }}>
{[
['TCP reachability', '12 ms'],
['SOCKS5 greeting', 'ok'],
['SOCKS5 authentication', 'ok'],
['TCP CONNECT to Discord', '38 ms'],
['UDP ASSOCIATE', 'relay 1.2.3.4'],
['UDP round-trip via STUN', '24 ms'],
['Discord API reachable', '200'],
].map(([n, v], i) => (
<div key={i} style={{ display: 'flex', alignItems: 'center', padding: '6px 8px', borderRadius: 6, fontSize: 12.5 }}>
<span style={{ width: 14, height: 14, borderRadius: '50%', background: '#21d07a22', border: '1px solid #21d07a', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: '#21d07a', fontSize: 9, marginRight: 10 }}></span>
<span style={{ flex: 1 }}>{n}</span>
<span style={{ color: '#777a86', fontFamily: "'Geist Mono',monospace", fontSize: 11.5 }}>{v}</span>
</div>
))}
</div>
</div>
<div style={{ display: 'flex', gap: 8 }}>
<button style={{ flex: 1, height: 36, background: '#7c8aff', color: '#0a0a0c', border: 'none', borderRadius: 7, fontWeight: 600 }}>Start proxying</button>
<button style={{ flex: 1, height: 36, background: '#1a1c22', color: '#e8e8ea', border: '1px solid #2a2d36', borderRadius: 7 }}>Stop</button>
</div>
</div>
</Win>
);
};
const StField = ({ label, value, flex, width }) => (
<label style={{ flex, width }}>
<div style={{ fontSize: 11, color: '#777a86', marginBottom: 4 }}>{label}</div>
<div style={{ height: 32, background: '#15171c', border: '1px solid #1f2228', borderRadius: 7, padding: '0 10px', display: 'flex', alignItems: 'center', fontSize: 13 }}>{value}</div>
</label>
);
// ═════════════════════════════════════════════════════════════════════════
// 10 · Pipeline / DAG — visualize the test chain as a flow
// ═════════════════════════════════════════════════════════════════════════
const SketchPipeline = () => {
const f = "'Inter', system-ui, sans-serif";
const m = "'JetBrains Mono', monospace";
const Node = ({ x, y, label, status, sub }) => {
const c = status === 'pass' ? '#21a655' : status === 'fail' ? '#e85a4f' : status === 'run' ? '#1e6fd9' : '#aaa';
const bg = status === 'pass' ? '#e8f7ee' : status === 'fail' ? '#fdebe9' : status === 'run' ? '#eaf1fb' : '#f4f4f4';
return (
<g transform={`translate(${x},${y})`}>
<rect width="120" height="40" rx="6" fill={bg} stroke={c} strokeWidth="1.5" />
<circle cx="14" cy="20" r="5" fill={c} />
<text x="26" y="17" fontSize="11" fontWeight="600" fill="#1a1a1a" fontFamily={f}>{label}</text>
<text x="26" y="30" fontSize="9.5" fill="#666" fontFamily={m}>{sub}</text>
</g>
);
};
const Arrow = ({ from, to, dashed }) => (
<line x1={from[0]} y1={from[1]} x2={to[0]} y2={to[1]} stroke="#bbb" strokeWidth="1.5" strokeDasharray={dashed ? '3 3' : ''} markerEnd="url(#ar)" />
);
return (
<Win bg="#fafafa" radius={6}>
<div style={{ height: 30, display: 'flex', alignItems: 'center', padding: '0 12px', borderBottom: '1px solid #ececec', fontFamily: f, fontSize: 12 }}>
<Mark color="#1a1a1a" size={12} />
<span style={{ marginLeft: 8, fontWeight: 600 }}>Drover-Go</span>
<span style={{ marginLeft: 8, color: '#888', fontSize: 11 }}>· pipeline view</span>
<TitleButtons />
</div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
{/* compact endpoint */}
<div style={{ padding: 10, display: 'flex', gap: 6, alignItems: 'center', borderBottom: '1px solid #ececec', background: '#fff' }}>
<span style={{ fontSize: 11, color: '#888', fontFamily: m }}>SOCKS5</span>
<input style={{ flex: 1, height: 26, padding: '0 8px', border: '1px solid #d0d0d0', borderRadius: 4, fontFamily: m, fontSize: 11.5 }} defaultValue="95.165.72.59" />
<input style={{ width: 70, height: 26, padding: '0 8px', border: '1px solid #d0d0d0', borderRadius: 4, fontFamily: m, fontSize: 11.5 }} defaultValue="12334" />
<button style={{ height: 26, padding: '0 12px', background: '#1e6fd9', color: '#fff', border: 'none', borderRadius: 4, fontWeight: 600, fontSize: 11.5 }}>Run </button>
</div>
{/* DAG */}
<div style={{ flex: 1, padding: 12, background: 'radial-gradient(circle at 1px 1px, #ddd 1px, transparent 0) 0 0/16px 16px', overflow: 'auto' }}>
<svg width="456" height="380" viewBox="0 0 456 380">
<defs>
<marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0 0 L10 5 L0 10 z" fill="#bbb"/></marker>
</defs>
<Node x={20} y={20} label="TCP reach" sub="12 ms" status="pass" />
<Arrow from={[140, 40]} to={[160, 40]} />
<Node x={160} y={20} label="SOCKS5 greet" sub="ok" status="pass" />
<Arrow from={[280, 40]} to={[300, 40]} />
<Node x={300} y={20} label="SOCKS5 auth" sub="ok" status="pass" />
<Arrow from={[360, 60]} to={[360, 90]} />
<Node x={300} y={90} label="CONNECT discord" sub="38 ms" status="pass" />
<Arrow from={[300, 110]} to={[180, 160]} />
<Arrow from={[300, 110]} to={[180, 220]} />
<Node x={60} y={140} label="UDP ASSOCIATE" sub="running…" status="run" />
<Arrow from={[180, 160]} to={[60, 240]} dashed />
<Node x={60} y={220} label="UDP STUN RTT" sub="pending" status="pending" />
<Node x={60} y={300} label="Discord API" sub="pending" status="pending" />
<Arrow from={[180, 240]} to={[60, 320]} dashed />
</svg>
</div>
<div style={{ padding: 10, borderTop: '1px solid #ececec', background: '#fff', display: 'flex', gap: 6, alignItems: 'center' }}>
<span style={{ fontSize: 11, color: '#1e6fd9', fontFamily: m }}> 4/7 running</span>
<span style={{ marginLeft: 'auto', display: 'flex', gap: 6 }}>
<button style={{ height: 28, padding: '0 14px', background: '#fff', border: '1px solid #ddd', borderRadius: 4, fontSize: 12 }}>Cancel</button>
<button style={{ height: 28, padding: '0 14px', background: '#1e6fd9', color: '#fff', border: 'none', borderRadius: 4, fontSize: 12, fontWeight: 600, opacity: 0.5 }}>Start proxying</button>
</span>
</div>
</div>
</Win>
);
};
// ═════════════════════════════════════════════════════════════════════════
// 11 · Bauhaus — geometric blocks, primary colors, asymmetric grid
// ═════════════════════════════════════════════════════════════════════════
const SketchBauhaus = () => {
const f = "'Space Grotesk', sans-serif";
return (
<Win bg="#f4ede0" radius={0} ring="#000">
<div style={{ height: 32, display: 'flex', alignItems: 'center', padding: '0 12px', borderBottom: '3px solid #000', fontFamily: f, fontSize: 13, fontWeight: 700 }}>
<span style={{ width: 14, height: 14, borderRadius: '50%', background: '#e63946' }} />
<span style={{ width: 14, height: 14, background: '#1d3557', marginLeft: 6 }} />
<span style={{ width: 0, height: 0, borderLeft: '7px solid transparent', borderRight: '7px solid transparent', borderBottom: '14px solid #f1c40f', marginLeft: 6 }} />
<span style={{ marginLeft: 12 }}>DROVER-GO</span>
<span style={{ marginLeft: 'auto', fontWeight: 400, fontSize: 11 }}>v0.4.2 · · · ×</span>
</div>
<div style={{ flex: 1, padding: 12, fontFamily: f, color: '#000', display: 'grid', gridTemplateColumns: '1fr 1fr', gridTemplateRows: 'auto 1fr auto', gap: 8 }}>
<div style={{ gridColumn: '1 / -1', background: '#1d3557', color: '#fff', padding: 14, border: '3px solid #000' }}>
<div style={{ fontSize: 10, letterSpacing: '.15em', opacity: .7 }}>FORM 01</div>
<div style={{ fontSize: 18, fontWeight: 700, marginTop: 2 }}>SOCKS5 PROXY</div>
<div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
<BaField flex={1} label="HOST" value="95.165.72.59" dark />
<BaField width={84} label="PORT" value="12334" dark />
</div>
</div>
<button style={{ background: '#e63946', color: '#fff', border: '3px solid #000', padding: '10px', fontFamily: f, fontSize: 13, fontWeight: 700, letterSpacing: '.06em' }}>CHECK </button>
<button style={{ background: '#f1c40f', color: '#000', border: '3px solid #000', padding: '10px', fontFamily: f, fontSize: 13, fontWeight: 700, letterSpacing: '.06em' }}> START</button>
<div style={{ gridColumn: '1 / -1', border: '3px solid #000', background: '#fff', padding: 14, minHeight: 0, overflow: 'hidden' }}>
<div style={{ fontSize: 10, letterSpacing: '.15em', opacity: .6 }}>STATUS · 7/7</div>
<div style={{ fontSize: 16, fontWeight: 700, marginBottom: 10 }}>ALL CHECKS PASSED</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '4px 14px' }}>
{[
['TCP reach', '12ms'],
['SOCKS5 greet', 'ok'],
['SOCKS5 auth', 'ok'],
['CONNECT', '38ms'],
['UDP assoc', 'ok'],
['UDP STUN', '24ms'],
['API', '200'],
].map(([n, v], i) => (
<div key={i} style={{ display: 'flex', alignItems: 'center', fontSize: 12, borderBottom: '1px solid #000' }}>
<span style={{ width: 8, height: 8, background: '#e63946', marginRight: 8 }} />
<span style={{ flex: 1 }}>{n}</span>
<span style={{ fontWeight: 700 }}>{v}</span>
</div>
))}
</div>
</div>
</div>
</Win>
);
};
const BaField = ({ label, value, flex, width, dark }) => (
<label style={{ flex, width }}>
<div style={{ fontSize: 9.5, marginBottom: 3, opacity: .7, letterSpacing: '.1em' }}>{label}</div>
<div style={{ height: 30, background: dark ? '#fff' : '#000', color: dark ? '#000' : '#fff', border: '2px solid #000', padding: '0 8px', display: 'flex', alignItems: 'center', fontSize: 13, fontWeight: 600 }}>{value}</div>
</label>
);
// ═════════════════════════════════════════════════════════════════════════
// 12 · Brutalist — hard borders, mono, acid lime
// ═════════════════════════════════════════════════════════════════════════
const SketchBrutalist = () => {
const m = "'Geist Mono', 'JetBrains Mono', monospace";
return (
<Win bg="#f3f1e8" radius={0} ring="#000">
<div style={{ height: 38, display: 'flex', alignItems: 'center', padding: '0 12px', borderBottom: '2px solid #000', fontFamily: m, fontSize: 12, color: '#000', background: '#e8e4d2' }}>
<span style={{ fontWeight: 700 }}> DROVER-GO</span>
<span style={{ marginLeft: 8, fontSize: 10 }}>v0.4.2</span>
<div style={{ marginLeft: 'auto', display: 'flex', gap: 6, fontSize: 14, fontWeight: 700 }}>
<span>[]</span><span>[]</span><span>[X]</span>
</div>
</div>
<div style={{ padding: 14, fontFamily: m, fontSize: 12, color: '#000', flex: 1, display: 'flex', flexDirection: 'column', gap: 12 }}>
<div style={{ border: '2px solid #000', background: '#fff', padding: 10 }}>
<div style={{ fontSize: 11, fontWeight: 700, marginBottom: 8 }}>// SOCKS5 PROXY</div>
<div style={{ display: 'flex', gap: 6 }}>
<BrField flex={1} label="HOST" value="95.165.72.59" />
<BrField width={92} label="PORT" value="12334" />
</div>
<div style={{ marginTop: 10, fontSize: 12 }}>[X] AUTHENTICATION</div>
<div style={{ display: 'flex', gap: 6, marginTop: 8 }}>
<BrField flex={1} label="LOGIN" value="alice" />
<BrField flex={1} label="PASSWORD" value="********" />
</div>
<button style={{ marginTop: 12, width: '100%', height: 36, background: '#c5f74d', border: '2px solid #000', boxShadow: '4px 4px 0 #000', fontFamily: m, fontWeight: 700, fontSize: 13, cursor: 'pointer' }}> CHECK CONNECTION</button>
</div>
<div style={{ border: '2px solid #000', background: '#fff', padding: 10, flex: 1 }}>
<div style={{ fontSize: 11, fontWeight: 700, marginBottom: 8 }}>// STATUS · 7/7 OK</div>
{[
['[OK]', 'TCP_REACHABILITY', '12ms'],
['[OK]', 'SOCKS5_GREETING', 'ok'],
['[OK]', 'SOCKS5_AUTH', 'ok'],
['[OK]', 'CONNECT_DISCORD', '38ms'],
['[OK]', 'UDP_ASSOCIATE', 'relay 1.2.3.4'],
['[OK]', 'UDP_STUN_RTT', '24ms'],
['[OK]', 'DISCORD_API', '200'],
].map(([s, n, v], i) => (
<div key={i} style={{ display: 'flex', padding: '3px 0', borderBottom: i < 6 ? '1px dashed #999' : 'none' }}>
<span style={{ width: 38, fontWeight: 700 }}>{s}</span>
<span style={{ flex: 1 }}>{n}</span>
<span>{v}</span>
</div>
))}
</div>
<div style={{ display: 'flex', gap: 6 }}>
<button style={{ flex: 1, height: 38, background: '#c5f74d', border: '2px solid #000', boxShadow: '4px 4px 0 #000', fontFamily: m, fontWeight: 700 }}> START</button>
<button style={{ flex: 1, height: 38, background: '#fff', border: '2px solid #000', boxShadow: '4px 4px 0 #000', fontFamily: m, fontWeight: 700 }}> STOP</button>
</div>
</div>
</Win>
);
};
const BrField = ({ label, value, flex, width }) => (
<label style={{ flex, width }}>
<div style={{ fontSize: 9.5, marginBottom: 3 }}>{label}</div>
<div style={{ height: 30, border: '2px solid #000', padding: '0 8px', display: 'flex', alignItems: 'center', fontSize: 12.5, background: '#fff' }}>{value}</div>
</label>
);
// ═════════════════════════════════════════════════════════════════════════
// SketchesApp
// ═════════════════════════════════════════════════════════════════════════
const SKETCHES = [
{ id: 'fluent', label: '01 · Fluent / Win11 native', el: <SketchFluent /> },
{ id: 'sidebar', label: '02 · IDE sidebar (VS Code-ish)', el: <SketchSidebar /> },
{ id: 'wizard', label: '03 · Wizard / stepper', el: <SketchWizard /> },
{ id: 'monitor', label: '04 · Network monitor (gauges)', el: <SketchMonitor /> },
{ id: 'inspector', label: '05 · Inspector / properties', el: <SketchInspector /> },
{ id: 'palette', label: '06 · Command palette (cmd+k)', el: <SketchPalette /> },
{ id: 'hero', label: '07 · Big toggle (VPN-style)', el: <SketchHero /> },
{ id: 'toolbar', label: '08 · Toolbar / ribbon (classic)', el: <SketchToolbar /> },
{ id: 'studio', label: '09 · Studio (Linear-ish)', el: <SketchStudio /> },
{ id: 'pipeline', label: '10 · Pipeline / DAG view', el: <SketchPipeline /> },
{ id: 'bauhaus', label: '11 · Bauhaus blocks', el: <SketchBauhaus /> },
{ id: 'brutalist', label: '12 · Brutalist (mono+lime)', el: <SketchBrutalist /> },
];
const SketchesApp = () => (
<DesignCanvas>
<DCSection id="about" title="Drover-Go" subtitle="12 directions — every one looks/works like real software, not a marketing site. Different UI paradigms (sidebar, wizard, palette, ribbon, DAG, gauges…), not just different palettes.">
<div data-dc-static style={{ width: 720, padding: '20px 24px', background: '#fff', borderRadius: 10, boxShadow: '0 0 0 1px rgba(0,0,0,.06)', fontSize: 13, lineHeight: 1.55, color: '#3a3530' }}>
<div style={{ fontWeight: 600, marginBottom: 8, fontSize: 14 }}>What changed</div>
<p style={{ margin: '0 0 8px' }}>Removed the "marketing" stylings (ticket, synthwave, soft pastel, editorial serif). Replaced with software-native paradigms each card explores a <em>different way to organize the same UI</em>, not just a different paint job:</p>
<ul style={{ margin: '0 0 8px', paddingLeft: 18 }}>
<li><b>Layout patterns:</b> sidebar IDE · wizard/stepper · pipeline/DAG · ribbon · palette+form · big-toggle hero</li>
<li><b>Element vocab:</b> gauges + sparklines · key/value inspector · fieldsets · tabs+breadcrumbs · status bar · toolbar buttons</li>
<li><b>Aesthetic:</b> Fluent (Win11) · classic Office · Linear/Studio · brutalist · Bauhaus blocks</li>
</ul>
<p style={{ margin: 0, color: '#7a7065' }}>Tell me which paradigm/aesthetic combo to take forward.</p>
</div>
</DCSection>
<DCSection id="sketches" title="12 directions" subtitle="Drag to reorder. Click any artboard's expand icon to focus.">
{SKETCHES.map(s => (
<DCArtboard key={s.id} id={s.id} label={s.label} width={W} height={H}>
{s.el}
</DCArtboard>
))}
</DCSection>
</DesignCanvas>
);
// Expose individual sketches so other files (e.g. shortlist) can render them.
Object.assign(window, {
SketchFluent, SketchSidebar, SketchWizard, SketchMonitor,
SketchInspector, SketchPalette, SketchHero, SketchToolbar,
SketchStudio, SketchPipeline, SketchBauhaus, SketchBrutalist,
});