// 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 (
);
}
function FluentTitleBar({ t, mode }) {
return (
);
}
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;