/* global React, Icon, Btn */
/* ──────────────────────────────────────────────────────────────
tech-demos.jsx — interactive "See demo" modal, one per solution
────────────────────────────────────────────────────────────── */
const { useState: useStateD, useEffect: useEffectD, useRef: useRefD } = React;
const DEMO_META = {
modernize: { title: 'Legacy code translation', sub: 'Watch AI convert COBOL to production Java.' },
qa: { title: 'Self-healing test suite', sub: 'Run the suite and watch broken selectors repair themselves.' },
mobile: { title: 'Cross-platform code gen', sub: 'One definition compiles to Swift and Kotlin at once.' },
ux: { title: 'Wireframe to frontend', sub: 'Turn a sketch into accessible, shipped UI.' },
};
// ── Shared bits ──────────────────────────────────────────────────
const CodeLine = ({ children, color, delay = 0, animate }) => (
{children}
);
const Pane = ({ dark, label, dotColor, children, style }) => (
);
// ── 1 · Modernize demo ───────────────────────────────────────────
const ModernizeDemo = () => {
const cobol = ['IDENTIFICATION DIVISION.', 'PROGRAM-ID. LEDGER.', 'PROCEDURE DIVISION.', ' PERFORM CALC-INTEREST', ' UNTIL WS-DONE = "Y".', ' COMPUTE WS-BAL =', ' WS-BAL * WS-RATE.', ' MOVE WS-BAL TO OUT-REC.'];
const java = ['@Service', 'class LedgerService {', ' BigDecimal accrue(Account a) {', ' var bal = a.balance();', ' while (!a.settled())', ' bal = bal.multiply(rate);', ' return bal;', ' }', '}'];
const [phase, setPhase] = useStateD('idle'); // idle|running|done
const [shown, setShown] = useStateD(0);
const [pct, setPct] = useStateD(0);
const timers = useRefD([]);
const clearAll = () => { timers.current.forEach(clearTimeout); timers.current = []; };
useEffectD(() => clearAll, []);
const run = () => {
clearAll(); setPhase('running'); setShown(0); setPct(0);
let p = 0;
const iv = setInterval(() => { p += 4; setPct(Math.min(100, p)); if (p >= 100) clearInterval(iv); }, 60);
timers.current.push(iv);
java.forEach((_, i) => timers.current.push(setTimeout(() => setShown(i + 1), 500 + i * 200)));
timers.current.push(setTimeout(() => setPhase('done'), 600 + java.length * 200));
};
return (
{cobol.map((l, i) => {l})}
{phase === 'running' && }
{phase === 'idle' && Output appears here.
}
{java.slice(0, shown).map((l, i) => {l})}
{phase === 'running' ? 'Translating…' : phase === 'done' ? 'Translate again' : 'Translate with AI'}
{phase === 'done'
?
98.6% accuracy
:
{pct}%}
);
};
// ── 2 · QA demo ──────────────────────────────────────────────────
const QADemo = () => {
const base = [
{ n: 'checkout.spec.ts', heal: false }, { n: 'auth-flow.spec.ts', heal: true },
{ n: 'cart-merge.spec.ts', heal: false }, { n: 'search-rank.spec.ts', heal: false }, { n: 'profile.spec.ts', heal: false },
];
const [st, setSt] = useStateD(base.map(() => 'idle')); // idle|running|fail|healing|pass
const [running, setRunning] = useStateD(false);
const timers = useRefD([]);
const clearAll = () => { timers.current.forEach(clearTimeout); timers.current = []; };
useEffectD(() => clearAll, []);
const run = () => {
clearAll(); setRunning(true);
let next = base.map(() => 'idle'); setSt([...next]);
let t = 0;
base.forEach((test, i) => {
t += 480;
timers.current.push(setTimeout(() => setSt((s) => s.map((v, j) => j === i ? 'running' : v)), t));
if (test.heal) {
t += 520; timers.current.push(setTimeout(() => setSt((s) => s.map((v, j) => j === i ? 'fail' : v)), t));
t += 520; timers.current.push(setTimeout(() => setSt((s) => s.map((v, j) => j === i ? 'healing' : v)), t));
t += 720; timers.current.push(setTimeout(() => setSt((s) => s.map((v, j) => j === i ? 'pass' : v)), t));
} else {
t += 460; timers.current.push(setTimeout(() => setSt((s) => s.map((v, j) => j === i ? 'pass' : v)), t));
}
});
timers.current.push(setTimeout(() => setRunning(false), t + 200));
};
const cfg = {
idle: { bg: 'var(--neutral-50)', fg: 'var(--fg-4)', ic: 'clock', label: 'queued' },
running: { bg: 'var(--info-bg)', fg: 'var(--primary-700)', ic: 'refresh', label: 'running', spin: true },
fail: { bg: 'var(--error-bg)', fg: '#991B1B', ic: 'x', label: 'selector broken' },
healing: { bg: 'var(--warning-bg)', fg: '#fbbf24', ic: 'refresh', label: 'AI healing selector', spin: true },
pass: { bg: 'var(--success-bg)', fg: '#4ade80', ic: 'check', label: 'passed' },
};
const passed = st.filter((s) => s === 'pass').length;
return (
{base.map((test, i) => {
const c = cfg[st[i]];
return (
{test.n}
{c.label}
);
})}
{running ? 'Running suite…' : 'Run test suite'}
{passed} / {base.length} passed
1 auto-healed
0 flaky
);
};
// ── 3 · Mobile demo ──────────────────────────────────────────────
const MobileDemo = () => {
const code = {
Swift: ['struct ProfileView: View {', ' @State var user: User', ' var body: some View {', ' VStack(spacing: 12) {', ' Avatar(user.photo)', ' Text(user.name)', ' .font(.headline)', ' Button("Follow") {', ' store.follow(user)', ' }', ' }', ' }', '}'],
Kotlin: ['@Composable', 'fun ProfileView(user: User) {', ' Column(', ' verticalArrangement =', ' Arrangement.spacedBy(12.dp)', ' ) {', ' Avatar(user.photo)', ' Text(user.name,', ' style = h6)', ' Button(onClick = {', ' store.follow(user)', ' }) { Text("Follow") }', ' }', '}'],
};
const [lang, setLang] = useStateD('Swift');
const [gen, setGen] = useStateD(false);
const [shown, setShown] = useStateD(0);
const timers = useRefD([]);
const clearAll = () => { timers.current.forEach(clearTimeout); timers.current = []; };
useEffectD(() => clearAll, []);
const reveal = (l) => {
clearAll(); setShown(0);
code[l].forEach((_, i) => timers.current.push(setTimeout(() => setShown(i + 1), 80 + i * 70)));
};
const generate = () => { setGen(true); reveal(lang); };
const switchLang = (l) => { setLang(l); if (gen) reveal(l); };
return (
Spec
“A profile screen with an avatar, the user's name, and a follow button.”
{['Swift', 'Kotlin'].map((l) => (
))}
{!gen && Generate to see code.
}
{gen && code[lang].slice(0, shown).map((l, i) => {l})}
{/* phone preview */}
{gen ? (
) :
preview
}
{lang === 'Swift' ? 'iOS' : 'Android'}
{gen ? 'Regenerate' : 'Generate apps'}
);
};
// ── 4 · UX demo ──────────────────────────────────────────────────
const UXDemo = () => {
const [gen, setGen] = useStateD(false);
const checks = ['Color contrast 4.8:1 — AA', 'All controls keyboard-reachable', 'Labels bound to inputs', 'Focus order is logical'];
const [ticked, setTicked] = useStateD(0);
const timers = useRefD([]);
const clearAll = () => { timers.current.forEach(clearTimeout); timers.current = []; };
useEffectD(() => clearAll, []);
const generate = () => {
clearAll(); setGen(true); setTicked(0);
checks.forEach((_, i) => timers.current.push(setTimeout(() => setTicked(i + 1), 600 + i * 350)));
};
return (
{/* wireframe */}
{/* rendered */}
{gen ? (
) : Generate to render UI.
}
{/* a11y checklist */}
{checks.map((c, i) => (
{i < ticked && }
{c}
))}
{gen ? 'Regenerate UI' : 'Generate UI'}
);
};
const DEMOS = { modernize: ModernizeDemo, qa: QADemo, mobile: MobileDemo, ux: UXDemo };
// ── Modal shell ──────────────────────────────────────────────────
const DemoModal = ({ solId, onClose }) => {
useEffectD(() => {
if (!solId) return undefined;
const onKey = (e) => { if (e.key === 'Escape') onClose(); };
document.addEventListener('keydown', onKey);
document.body.style.overflow = 'hidden';
return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
}, [solId]);
if (!solId) return null;
const meta = DEMO_META[solId];
const Demo = DEMOS[solId];
return (
e.stopPropagation()} style={{ width: 'min(880px, 100%)', maxHeight: '88vh', background: 'var(--bg-raised)',
borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-xl)', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
Live demo
{meta.title}
{meta.sub}
);
};
Object.assign(window, { DemoModal });