Skip to content

Commit 15252c8

Browse files
jsundaiclaude
andcommitted
Restore Components layout, Key Facts, Run Demo, GitHub buttons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9ef903f commit 15252c8

5 files changed

Lines changed: 628 additions & 259 deletions

File tree

src/components/NexusDemo/ComponentsSection.tsx

Lines changed: 163 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,11 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import styles from './NexusDemo.module.css';
33

44
type Props = { onNext: () => void };
55

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-
376
export default function ComponentsSection({ onNext }: Props) {
7+
const [opTab, setOpTab] = useState<'sync' | 'async'>('sync');
8+
389
return (
3910
<div className={styles.section}>
4011
<div className={styles.progressBar}>
@@ -43,33 +14,163 @@ export default function ComponentsSection({ onNext }: Props) {
4314

4415
<h1>The Four Building Blocks</h1>
4516
<p className={styles.lead}>
46-
Nexus is composed of four concepts. Once you understand these, the rest falls into place.
17+
Nexus has four key concepts. These four concepts are the foundation of everything in Nexus.
4718
</p>
4819

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-
}}
20+
<div className={styles.componentLayout}>
21+
22+
{/* 1 — Endpoint */}
23+
<div className={styles.card} style={{ borderLeft: '4px solid var(--ifm-color-primary)' }}>
24+
<div className={styles.componentRow}>
25+
<div
26+
className={styles.componentNum}
27+
style={{ background: 'var(--nd-primary-bg)', color: 'var(--ifm-color-primary)' }}
28+
>
29+
1
30+
</div>
31+
<div className={styles.componentContent}>
32+
<h2 className={styles.componentTitle}>Nexus Endpoint</h2>
33+
<p className={styles.componentRole}>The address you publish and route through</p>
34+
<p>
35+
Think of an Endpoint like a <strong>URL for your team's services</strong>. It's a
36+
named entry point registered in the Nexus Registry that routes requests to a
37+
specific namespace and task queue.
38+
</p>
39+
<p>
40+
It's <em>not</em> a general HTTP proxy — it's specifically designed for Nexus, with
41+
built-in auth, retries, and observability.
42+
</p>
43+
<div className={styles.componentCode}>
44+
Endpoint:{' '}
45+
<span style={{ color: 'var(--ifm-color-primary)' }}>fraud-detection-prod</span>
46+
<br />
47+
Routes to:{' '}
48+
<span style={{ color: 'var(--nd-purple)' }}>fraud-ns / fraud-task-queue</span>
49+
</div>
50+
</div>
51+
</div>
52+
</div>
53+
54+
{/* 2 — Service */}
55+
<div className={styles.card} style={{ borderLeft: '4px solid var(--nd-purple)' }}>
56+
<div className={styles.componentRow}>
57+
<div
58+
className={styles.componentNum}
59+
style={{ background: 'var(--nd-purple-bg)', color: 'var(--nd-purple)' }}
6560
>
66-
{c.example}
67-
</code>
61+
2
62+
</div>
63+
<div className={styles.componentContent}>
64+
<h2 className={styles.componentTitle}>Nexus Service</h2>
65+
<p className={styles.componentRole}>The contract you publish for others to consume</p>
66+
<p>
67+
A Service is a <strong>named collection of Nexus Operations</strong> — like an API
68+
interface. Multiple services can run in the same worker. Callers import the service
69+
definition to get type safety.
70+
</p>
71+
<p>
72+
Example:{' '}
73+
<code style={{ color: 'var(--nd-purple)' }}>fraud.v1</code> service exposes{' '}
74+
<code>checkTransaction</code>, <code>flagUser</code>, and <code>getScore</code>{' '}
75+
operations.
76+
</p>
77+
</div>
6878
</div>
69-
))}
79+
</div>
80+
81+
{/* 3 — Operation */}
82+
<div className={styles.card} style={{ borderLeft: '4px solid var(--nd-green)' }}>
83+
<div className={styles.componentRow}>
84+
<div
85+
className={styles.componentNum}
86+
style={{ background: 'var(--nd-green-bg)', color: 'var(--nd-green)' }}
87+
>
88+
3
89+
</div>
90+
<div className={styles.componentContent}>
91+
<h2 className={styles.componentTitle}>Nexus Operation</h2>
92+
<p className={styles.componentRole}>The individual action — sync or async</p>
93+
94+
<div className={styles.opTabs}>
95+
<button
96+
className={`${styles.opTab} ${opTab === 'sync' ? styles.opTabActive : ''}`}
97+
onClick={() => setOpTab('sync')}
98+
>
99+
Synchronous
100+
</button>
101+
<button
102+
className={`${styles.opTab} ${opTab === 'async' ? styles.opTabActive : ''}`}
103+
onClick={() => setOpTab('async')}
104+
>
105+
Asynchronous
106+
</button>
107+
</div>
108+
109+
{opTab === 'sync' ? (
110+
<>
111+
<p>
112+
<strong>Synchronous</strong> operations complete in under 10 seconds. The
113+
result comes back in the same HTTP round-trip. Great for quick lookups, scoring,
114+
or validations.
115+
</p>
116+
<div className={styles.componentCode}>
117+
Caller → [Nexus RPC] → Handler → result → Caller
118+
<br />
119+
Duration: milliseconds to &lt;10 seconds
120+
</div>
121+
</>
122+
) : (
123+
<>
124+
<p>
125+
<strong>Asynchronous</strong> operations start a Workflow and return an
126+
operation token. The caller workflow is suspended. When the handler workflow
127+
completes, a callback delivers the result.
128+
</p>
129+
<div className={styles.componentCode}>
130+
Caller → [start] → Handler starts Workflow → [token]
131+
<br />
132+
...time passes (up to 60 days)...
133+
<br />
134+
Handler Workflow completes → [callback] → Caller resumes
135+
</div>
136+
</>
137+
)}
138+
</div>
139+
</div>
140+
</div>
141+
142+
{/* 4 — Registry */}
143+
<div className={styles.card} style={{ borderLeft: '4px solid var(--nd-amber)' }}>
144+
<div className={styles.componentRow}>
145+
<div
146+
className={styles.componentNum}
147+
style={{ background: 'var(--nd-amber-bg)', color: 'var(--nd-amber)' }}
148+
>
149+
4
150+
</div>
151+
<div className={styles.componentContent}>
152+
<h2 className={styles.componentTitle}>Nexus Registry</h2>
153+
<p className={styles.componentRole}>The directory of all Endpoints in your account</p>
154+
<p>
155+
Scoped to your Temporal Cloud account or self-hosted cluster. Teams register
156+
Endpoints here. The Registry is the source of truth for endpoint discovery, access
157+
control, and audit logging.
158+
</p>
159+
<div className={styles.componentPills}>
160+
<div className={styles.componentPill}>fraud-detection-prod</div>
161+
<div className={styles.componentPill}>kyc-verification-v2</div>
162+
<div className={styles.componentPill}>notifications-global</div>
163+
<div className={`${styles.componentPill} ${styles.componentPillNew}`}>
164+
+ register new
165+
</div>
166+
</div>
167+
</div>
168+
</div>
169+
</div>
170+
70171
</div>
71172

72-
<h2 className={styles.sectionHeading}>Nexus vs. the Alternatives</h2>
173+
<h2 className={styles.sectionHeading} style={{ marginTop: 32 }}>Nexus vs. the Alternatives</h2>
73174
<table className={styles.table}>
74175
<thead>
75176
<tr>
@@ -83,57 +184,18 @@ export default function ComponentsSection({ onNext }: Props) {
83184
</thead>
84185
<tbody>
85186
{[
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-
},
187+
{ name: 'Shared namespace', durable: true, typed: false, cross: false, retry: true, cancel: false },
188+
{ name: 'HTTP between teams', durable: false, typed: false, cross: true, retry: false, cancel: false },
189+
{ name: 'Child workflows', durable: true, typed: true, cross: false, retry: true, cancel: true },
190+
{ name: 'Temporal Nexus', durable: true, typed: true, cross: true, retry: true, cancel: true, highlight: true },
119191
].map((row) => (
120192
<tr key={row.name} style={row.highlight ? { background: 'var(--nd-primary-bg)' } : {}}>
121193
<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>
194+
<td className={row.durable ? styles.check : styles.cross}>{row.durable ? '✓' : '—'}</td>
195+
<td className={row.typed ? styles.check : styles.cross}>{row.typed ? '✓' : '—'}</td>
196+
<td className={row.cross ? styles.check : styles.cross}>{row.cross ? '✓' : '—'}</td>
197+
<td className={row.retry ? styles.check : styles.cross}>{row.retry ? '✓' : '—'}</td>
198+
<td className={row.cancel ? styles.check : styles.cross}>{row.cancel ? '✓' : '—'}</td>
137199
</tr>
138200
))}
139201
</tbody>

src/components/NexusDemo/HowItWorks.tsx

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,16 +188,22 @@ export default function HowItWorks({ onNext }: Props) {
188188

189189
{/* Controls */}
190190
<div className={styles.flowControls}>
191+
<button className={styles.btn} onClick={handlePlay}>
192+
{playing
193+
? '⏸ Pause'
194+
: log.length === 0
195+
? 'Run Demo'
196+
: stepIdx >= steps.length - 1
197+
? '↺ Replay'
198+
: '▶ Resume'}
199+
</button>
191200
<button
192201
className={`${styles.btn} ${styles.btnSecondary}`}
193202
onClick={() => handleStep(-1)}
194203
disabled={stepIdx === 0}
195204
>
196205
← Prev
197206
</button>
198-
<button className={styles.btn} onClick={handlePlay}>
199-
{playing ? '⏸ Pause' : stepIdx >= steps.length - 1 ? '↺ Replay' : '▶ Play'}
200-
</button>
201207
<button
202208
className={`${styles.btn} ${styles.btnSecondary}`}
203209
onClick={() => handleStep(1)}
@@ -235,6 +241,28 @@ export default function HowItWorks({ onNext }: Props) {
235241
))}
236242
</div>
237243
)}
244+
245+
{/* Timeline */}
246+
<div className={styles.timeline}>
247+
{steps.map((step, i) => (
248+
<div
249+
key={i}
250+
className={`${styles.tlStep} ${
251+
i < stepIdx
252+
? styles.tlStepDone
253+
: i === stepIdx && log.length > 0
254+
? styles.tlStepActive
255+
: ''
256+
}`}
257+
>
258+
<div className={styles.tlNum}>{i + 1}</div>
259+
<div className={styles.tlContent}>
260+
<div className={styles.tlTitle}>{step.label}</div>
261+
<div className={styles.tlDesc}>{step.log.msg}</div>
262+
</div>
263+
</div>
264+
))}
265+
</div>
238266
</div>
239267

240268
<div className={styles.nextRow}>

0 commit comments

Comments
 (0)