Skip to content

Commit 9ef903f

Browse files
jsundaiclaude
andcommitted
Convert Nexus demo from static HTML to React components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 631951b commit 9ef903f

12 files changed

Lines changed: 2191 additions & 19 deletions

File tree

docs/nexus-demo.mdx

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,6 @@ keywords:
1212
hide_table_of_contents: true
1313
---
1414

15-
<style>{`
16-
.main-wrapper, article, .theme-doc-markdown { padding: 0 !important; margin: 0 !important; }
17-
`}</style>
15+
import NexusDemo from '@site/src/components/NexusDemo';
1816

19-
<iframe
20-
id="nexus-demo-frame"
21-
src="/nexus-demo.html"
22-
style={{display: 'block', width: '100%', height: '100vh', border: 'none'}}
23-
title="Temporal Nexus Interactive Demo"
24-
onLoad={() => {
25-
const frame = document.getElementById('nexus-demo-frame');
26-
const resize = () => {
27-
try {
28-
frame.style.height = frame.contentDocument.body.scrollHeight + 'px';
29-
} catch(e) {}
30-
};
31-
resize();
32-
frame.contentWindow.addEventListener('click', () => setTimeout(resize, 400));
33-
}}
34-
/>
17+
<NexusDemo />
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import CodeBlock from '@theme/CodeBlock';
2+
import React, { useState } from 'react';
3+
import styles from './NexusDemo.module.css';
4+
import { buildSteps } from './buildSteps';
5+
6+
type Props = { onNext: () => void };
7+
8+
export default function BuildIt({ onNext }: Props) {
9+
const [idx, setIdx] = useState(0);
10+
const step = buildSteps[idx];
11+
12+
function go(next: number) {
13+
setIdx(Math.max(0, Math.min(buildSteps.length - 1, next)));
14+
}
15+
16+
return (
17+
<div className={styles.section}>
18+
<div className={styles.progressBar}>
19+
<div className={styles.progressFill} style={{ width: '71%' }} />
20+
</div>
21+
22+
<h1>Build It Step by Step</h1>
23+
<p className={styles.lead}>
24+
Real code from{' '}
25+
<a
26+
href="https://github.com/temporalio/samples-dotnet/tree/main/src/NexusSimple"
27+
target="_blank"
28+
rel="noopener noreferrer"
29+
>
30+
samples-dotnet/NexusSimple
31+
</a>
32+
. Walk through building a cross-namespace Nexus service from scratch.
33+
</p>
34+
35+
<div className={styles.buildLayout}>
36+
{/* Step list sidebar */}
37+
<nav className={styles.buildStepList} aria-label="Build steps">
38+
{buildSteps.map((s, i) => (
39+
<button
40+
key={i}
41+
className={`${styles.buildStepBtn} ${i === idx ? styles.buildStepBtnActive : ''}`}
42+
onClick={() => setIdx(i)}
43+
aria-current={i === idx ? 'step' : undefined}
44+
>
45+
<div className={styles.buildStepNum}>{s.num}</div>
46+
<div className={styles.buildStepTitle}>{s.title}</div>
47+
</button>
48+
))}
49+
</nav>
50+
51+
{/* Code panel */}
52+
<div className={styles.buildPanel}>
53+
<div className={styles.buildFileHeader}>{step.file}</div>
54+
<CodeBlock language={step.language}>{step.code}</CodeBlock>
55+
<div className={styles.buildNote}>{step.note}</div>
56+
<div className={styles.buildNav}>
57+
<button
58+
className={`${styles.btn} ${styles.btnSecondary}`}
59+
onClick={() => go(idx - 1)}
60+
disabled={idx === 0}
61+
>
62+
← Prev
63+
</button>
64+
<button
65+
className={styles.btn}
66+
onClick={() => go(idx + 1)}
67+
disabled={idx === buildSteps.length - 1}
68+
>
69+
Next →
70+
</button>
71+
</div>
72+
</div>
73+
</div>
74+
75+
<div className={styles.nextRow}>
76+
<button className={styles.btn} onClick={onNext}>
77+
Next: Test Yourself →
78+
</button>
79+
</div>
80+
</div>
81+
);
82+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import React from 'react';
2+
import styles from './NexusDemo.module.css';
3+
4+
type Props = { onNext: () => void };
5+
6+
const components = [
7+
{
8+
tag: 'tagBlue' as const,
9+
tagLabel: 'Endpoint',
10+
title: 'Nexus Endpoint',
11+
desc: 'A named, versioned router configured in the Temporal control plane. It maps a name (e.g. "fraud-service-endpoint") to a target namespace and task queue. This is the only thing Team A needs to know about Team B\'s infrastructure.',
12+
example: '"my-nexus-endpoint"',
13+
},
14+
{
15+
tag: 'tagPurple' as const,
16+
tagLabel: 'Service',
17+
title: 'Nexus Service',
18+
desc: 'A named collection of operations defined by an interface (Go) or decorated class (TypeScript, .NET). Think of it like a gRPC service definition or a typed REST API contract — it describes what\'s callable without exposing how.',
19+
example: '[NexusService] IHelloService',
20+
},
21+
{
22+
tag: 'tagGreen' as const,
23+
tagLabel: 'Operation',
24+
title: 'Nexus Operation',
25+
desc: 'A single callable unit within a service. Operations are either synchronous (run inline, return in < 10s) or asynchronous (start a Temporal Workflow, can run for days). The caller\'s code looks the same either way — just await the result.',
26+
example: 'Echo() | SayHello()',
27+
},
28+
{
29+
tag: 'tagBlue' as const,
30+
tagLabel: 'Registry',
31+
title: 'Nexus Registry',
32+
desc: 'The Temporal Cloud control plane (or OSS server config) that stores endpoint definitions, access policies, and routing rules. Admins configure which caller namespaces can reach which handler namespaces through which endpoints.',
33+
example: 'Temporal Cloud UI / tcld',
34+
},
35+
];
36+
37+
export default function ComponentsSection({ onNext }: Props) {
38+
return (
39+
<div className={styles.section}>
40+
<div className={styles.progressBar}>
41+
<div className={styles.progressFill} style={{ width: '28%' }} />
42+
</div>
43+
44+
<h1>The Four Building Blocks</h1>
45+
<p className={styles.lead}>
46+
Nexus is composed of four concepts. Once you understand these, the rest falls into place.
47+
</p>
48+
49+
<div className={styles.cardGrid}>
50+
{components.map((c) => (
51+
<div key={c.title} className={styles.card}>
52+
<div className={`${styles.tag} ${styles[c.tag]}`}>{c.tagLabel}</div>
53+
<h3 style={{ fontSize: 15, marginBottom: 8 }}>{c.title}</h3>
54+
<p style={{ fontSize: 13, color: 'var(--nd-muted)', margin: '0 0 10px', lineHeight: 1.6 }}>
55+
{c.desc}
56+
</p>
57+
<code
58+
style={{
59+
fontSize: 11,
60+
color: 'var(--nd-muted)',
61+
background: 'var(--nd-surface2)',
62+
padding: '2px 6px',
63+
borderRadius: 4,
64+
}}
65+
>
66+
{c.example}
67+
</code>
68+
</div>
69+
))}
70+
</div>
71+
72+
<h2 className={styles.sectionHeading}>Nexus vs. the Alternatives</h2>
73+
<table className={styles.table}>
74+
<thead>
75+
<tr>
76+
<th>Approach</th>
77+
<th>Durable</th>
78+
<th>Typed contract</th>
79+
<th>Cross-namespace</th>
80+
<th>Auto-retry</th>
81+
<th>Cancel propagation</th>
82+
</tr>
83+
</thead>
84+
<tbody>
85+
{[
86+
{
87+
name: 'Shared namespace',
88+
durable: true,
89+
typed: false,
90+
cross: false,
91+
retry: true,
92+
cancel: false,
93+
},
94+
{
95+
name: 'HTTP between teams',
96+
durable: false,
97+
typed: false,
98+
cross: true,
99+
retry: false,
100+
cancel: false,
101+
},
102+
{
103+
name: 'Child workflows',
104+
durable: true,
105+
typed: true,
106+
cross: false,
107+
retry: true,
108+
cancel: true,
109+
},
110+
{
111+
name: 'Temporal Nexus',
112+
durable: true,
113+
typed: true,
114+
cross: true,
115+
retry: true,
116+
cancel: true,
117+
highlight: true,
118+
},
119+
].map((row) => (
120+
<tr key={row.name} style={row.highlight ? { background: 'var(--nd-primary-bg)' } : {}}>
121+
<td style={{ fontWeight: row.highlight ? 700 : 400 }}>{row.name}</td>
122+
<td className={row.durable ? styles.check : styles.cross}>
123+
{row.durable ? '✓' : '—'}
124+
</td>
125+
<td className={row.typed ? styles.check : styles.cross}>
126+
{row.typed ? '✓' : '—'}
127+
</td>
128+
<td className={row.cross ? styles.check : styles.cross}>
129+
{row.cross ? '✓' : '—'}
130+
</td>
131+
<td className={row.retry ? styles.check : styles.cross}>
132+
{row.retry ? '✓' : '—'}
133+
</td>
134+
<td className={row.cancel ? styles.check : styles.cross}>
135+
{row.cancel ? '✓' : '—'}
136+
</td>
137+
</tr>
138+
))}
139+
</tbody>
140+
</table>
141+
142+
<div className={styles.nextRow}>
143+
<button className={styles.btn} onClick={onNext}>
144+
Next: How It Works →
145+
</button>
146+
</div>
147+
</div>
148+
);
149+
}

0 commit comments

Comments
 (0)