// drover-glass.jsx — Variant 3: Glassmorphism.
// Soft animated gradient backdrop. Frosted blur on every panel. Subtle glow on active.
const GlassTheme = {
d: {
bgGrad: 'radial-gradient(120% 80% at 0% 0%, #2b1d4a 0%, #131326 50%, #0d1024 100%)',
glassBg: 'rgba(255,255,255,0.06)',
glassBg2: 'rgba(255,255,255,0.10)',
border: 'rgba(255,255,255,0.14)',
borderSoft: 'rgba(255,255,255,0.08)',
text: '#f3f1ff', dim: '#bdbcd6', dimmer: '#7e7d99',
accent: '#9b8bff', accentGlow: '#9b8bff',
danger: '#ff8a98', warn: '#ffc46b', pass: '#7ee0b3', skip: '#9aa0aa',
inputBg: 'rgba(0,0,0,0.18)', primaryFg: '#1a1538',
},
l: {
bgGrad: 'radial-gradient(110% 70% at 0% 0%, #c8d8ff 0%, #f0e8ff 55%, #ffeaf2 100%)',
glassBg: 'rgba(255,255,255,0.55)',
glassBg2: 'rgba(255,255,255,0.75)',
border: 'rgba(255,255,255,0.7)',
borderSoft: 'rgba(255,255,255,0.5)',
text: '#1a1538', dim: '#5e5b7a', dimmer: '#8e8cab',
accent: '#5e4bcf', accentGlow: '#9b8bff',
danger: '#c0463f', warn: '#a06a14', pass: '#2c8a5a', skip: '#8a8aa0',
inputBg: 'rgba(255,255,255,0.6)', primaryFg: '#ffffff',
},
};
function GlassWindow({ mode = 'dark', initial }) {
const t = GlassTheme[mode === 'dark' ? 'd' : 'l'];
const D = window.useDrover(initial);
const palette = { pending: t.dimmer, running: t.accent, passed: t.pass, failed: t.danger, skipped: t.skip };
const fontUI = '"Inter","Segoe UI",system-ui,sans-serif';
const fontMono = '"JetBrains Mono",ui-monospace,monospace';
const isActive = D.phase === 'active';
return (
{/* gradient orbs */}
{/* title */}
);
}
function GlassTitle({ t }) {
const cell = { width: 44, height: 32, display:'flex', alignItems:'center', justifyContent:'center', cursor:'pointer', color: t.dim };
return (
);
}
function GlassPanel({ t, children, style }) {
return {children}
;
}
function GlassHeader({ t, children }) {
return {children}
;
}
function GField({ t, label, children, style }) {
return ;
}
function glassInput(t, fontUI, disabled) {
return {
background: t.inputBg, color: disabled ? t.dimmer : t.text,
border: `1px solid ${t.borderSoft}`, borderRadius: 8, padding: '8px 11px',
fontSize: 13, fontFamily: fontUI, outline:'none', width:'100%', boxSizing:'border-box',
backdropFilter: 'blur(8px)',
};
}
function GlassToggle({ t, checked, onChange, children }) {
return (
);
}
function GlassPrimary({ t, onClick, disabled, children, style }) {
return (
);
}
function GlassStatus({ t, D, palette, fontMono }) {
if (D.phase === 'idle') {
return (
Ready to check
);
}
const allOk = D.lastSummary?.failed === 0;
return (
{D.phase === 'checking'
?
Running diagnostics…
:
{allOk ? '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}
{r?.result === 'failed' && (
)}
{r?.result === 'failed' && r.expanded && (
)}
);
})}
);
}
function GlassStartBtn({ t, D }) {
const allFailed = D.lastSummary && D.lastSummary.failed === D.tests.length;
const checkedOk = 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 (
Active{warning ? ' · UDP fallback' : ''}
);
}
return Start proxying;
}
function GlassStopBtn({ t, D }) {
const enabled = D.phase === 'active';
return (
);
}
function GlassLiveStats({ t, stats, fontMono }) {
const C = ({ icon, val, lbl }) => (
{icon}{val}
{lbl && {lbl}}
);
return (
} val={window.fmtBytes(stats.up)}/>
} val={window.fmtBytes(stats.down)}/>
);
}
function GlassLogs({ t, D, fontMono }) {
return (
{D.logsOpen && (
<>
{['Copy all','Clear','Open log file'].map((l,i) => (
))}
el && (el.scrollTop = el.scrollHeight)}
style={{ maxHeight: 130, overflowY: 'auto', padding: '8px 16px',
fontFamily: fontMono, fontSize: 11, lineHeight: 1.6, color: t.dim }}>
{D.logs.map((l,i) => (
{window.fmtTime(l.t)}{' '}
[{l.level}]{' '}
{l.msg}
))}
>
)}
);
}
window.GlassWindow = GlassWindow;