-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
403 lines (382 loc) · 22.2 KB
/
Copy pathindex.html
File metadata and controls
403 lines (382 loc) · 22.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blazor Server Basics</title>
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.5/babel.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@keyframes slideDown {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.8; transform: scale(1.05); }
}
@keyframes flowPath {
0% { stroke-dashoffset: 500; }
100% { stroke-dashoffset: 0; }
}
.slide-down { animation: slideDown 0.5s ease-out; }
.pulse-animate { animation: pulse 1s ease-in-out; }
.flow-line {
stroke-dasharray: 500;
stroke-dashoffset: 500;
}
.flow-line.active {
animation: flowPath 0.8s ease-out forwards;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const RotateCcw = () => (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
);
const BlazorServerBasics = () => {
const [step, setStep] = useState(0);
const [activeFlow, setActiveFlow] = useState([]);
const [counterValue, setCounterValue] = useState(0);
const [showMessage, setShowMessage] = useState(false);
const steps = [
{
title: 'Browser Request',
description: 'O χρήστης ανοίγει την εφαρμογή',
highlight: 'browser',
flow: ['browser'],
code: 'https://myapp.com/',
detail: 'Ο browser στέλνει HTTP request'
},
{
title: 'Server Receives',
description: 'Ο Server δέχεται το request',
highlight: 'server',
flow: ['browser', 'server'],
code: 'app.MapBlazorHub()',
detail: 'ASP.NET Core server ξεκινάει'
},
{
title: 'Render Razor Component',
description: 'Server κάνει render το component',
highlight: 'component',
flow: ['server', 'component'],
code: '@page "/counter"\n<h1>Counter</h1>',
detail: 'Blazor component εκτελείται στον server'
},
{
title: 'Initial HTML Sent',
description: 'Στέλνει HTML στον browser',
highlight: 'browser',
flow: ['component', 'browser'],
code: '<html><body>...</body></html>',
detail: 'Static HTML για το initial load'
},
{
title: 'SignalR Connection',
description: 'Ανοίγει WebSocket connection',
highlight: 'signalr',
flow: ['browser', 'signalr'],
code: 'blazor.server.js connects',
detail: 'Persistent connection για interactivity'
},
{
title: 'User Clicks Button',
description: 'Πατάει το "Increment" κουμπί',
highlight: 'browser',
flow: ['browser'],
code: '<button @onclick="IncrementCount">',
detail: 'DOM event στον browser',
showClick: true
},
{
title: 'Event via SignalR',
description: 'Στέλνει event στον server',
highlight: 'signalr',
flow: ['browser', 'signalr', 'server'],
code: 'SignalR: "onclick" event',
detail: 'WebSocket message με το event'
},
{
title: 'Execute C# Method',
description: 'Server εκτελεί τη μέθοδο',
highlight: 'component',
flow: ['server', 'component'],
code: 'void IncrementCount() { count++; }',
detail: 'C# code τρέχει στον server',
counter: 1
},
{
title: 'StateHasChanged',
description: 'Component ζητάει re-render',
highlight: 'component',
flow: ['component'],
code: 'StateHasChanged();',
detail: 'Blazor ξέρει ότι πρέπει να ανανεώσει το UI'
},
{
title: 'Diff Calculation',
description: 'Server υπολογίζει τις αλλαγές',
highlight: 'server',
flow: ['component', 'server'],
code: 'RenderTree diff',
detail: 'Βρίσκει τι άλλαξε στο DOM'
},
{
title: 'Send UI Update',
description: 'Στέλνει μόνο τις αλλαγές',
highlight: 'signalr',
flow: ['server', 'signalr', 'browser'],
code: 'SignalR: DOM update patch',
detail: 'Μικρό message με τις διαφορές'
},
{
title: 'Update DOM',
description: 'Browser ενημερώνει το UI! 🎉',
highlight: 'browser',
flow: ['browser'],
code: 'DOM: <p>Counter: 1</p>',
detail: 'Το UI ανανεώνεται χωρίς page reload',
showUpdate: true
}
];
const handleNext = () => {
if (step < steps.length - 1) {
const nextStep = step + 1;
setStep(nextStep);
setActiveFlow(steps[nextStep].flow || []);
if (steps[nextStep].counter !== undefined) {
setCounterValue(steps[nextStep].counter);
}
if (steps[nextStep].showClick) {
setShowMessage(true);
setTimeout(() => setShowMessage(false), 1000);
}
if (steps[nextStep].showUpdate) {
setShowMessage(true);
setTimeout(() => setShowMessage(false), 1000);
}
}
};
const handlePrevious = () => {
if (step > 0) {
const prevStep = step - 1;
setStep(prevStep);
setActiveFlow(steps[prevStep].flow || []);
if (prevStep < 7) {
setCounterValue(0);
}
setShowMessage(false);
}
};
const reset = () => {
setStep(0);
setActiveFlow([]);
setCounterValue(0);
setShowMessage(false);
};
const isHighlighted = (component) => steps[step]?.highlight === component;
const isFlowActive = (from, to) => {
return activeFlow.includes(from) && activeFlow.includes(to);
};
return (
<div className="min-h-screen bg-gradient-to-br from-blue-900 via-indigo-900 to-purple-900 text-white p-4">
<div className="max-w-6xl mx-auto">
{/* Header */}
<div className="text-center mb-6">
<h1 className="text-4xl font-bold mb-2">Blazor Server Basics</h1>
<p className="text-blue-200 text-sm">Server-Side Interactive Web Apps</p>
</div>
{/* Controls */}
<div className="flex justify-center gap-3 mb-6">
<button
onClick={handlePrevious}
disabled={step === 0}
className="bg-gray-600 hover:bg-gray-700 disabled:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed px-5 py-2 rounded-lg text-sm font-semibold flex items-center gap-2 transition-all"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Previous
</button>
<button
onClick={handleNext}
disabled={step === steps.length - 1}
className="bg-blue-600 hover:bg-blue-700 disabled:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed px-5 py-2 rounded-lg text-sm font-semibold flex items-center gap-2 transition-all"
>
Next
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
<button
onClick={reset}
className="bg-gray-700 hover:bg-gray-600 px-5 py-2 rounded-lg text-sm font-semibold flex items-center gap-2 transition-all"
>
<RotateCcw />
Reset
</button>
</div>
{/* Step Info */}
<div className="bg-black/40 backdrop-blur rounded-lg p-5 mb-6 border border-blue-500/30">
<div className="flex items-center gap-3 mb-3">
<div className="bg-blue-600 rounded-full w-10 h-10 flex items-center justify-center font-bold text-lg">
{step + 1}
</div>
<div>
<h3 className="text-2xl font-bold">{steps[step].title}</h3>
<p className="text-blue-200 text-sm">{steps[step].detail}</p>
</div>
</div>
<p className="text-blue-100 mb-3">{steps[step].description}</p>
<div className="bg-gray-900/70 rounded p-3 font-mono text-sm text-green-300 whitespace-pre-wrap">
{steps[step].code}
</div>
</div>
{/* Main Architecture Diagram */}
<div className="relative bg-black/30 backdrop-blur rounded-xl p-8 border border-blue-500/30 mb-6">
<svg className="absolute inset-0 w-full h-full pointer-events-none" style={{zIndex: 0}}>
{/* Browser to SignalR */}
<line x1="25%" y1="50%" x2="50%" y2="50%"
className={`flow-line ${isFlowActive('browser', 'signalr') ? 'active' : ''}`}
stroke="#60a5fa" strokeWidth="4" />
{/* SignalR to Server */}
<line x1="50%" y1="50%" x2="75%" y2="30%"
className={`flow-line ${isFlowActive('signalr', 'server') ? 'active' : ''}`}
stroke="#60a5fa" strokeWidth="4" />
{/* Server to Component */}
<line x1="75%" y1="40%" x2="75%" y2="60%"
className={`flow-line ${isFlowActive('server', 'component') ? 'active' : ''}`}
stroke="#60a5fa" strokeWidth="4" />
{/* Component back to Server */}
<line x1="75%" y1="70%" x2="75%" y2="50%"
className={`flow-line ${isFlowActive('component', 'server') ? 'active' : ''}`}
stroke="#a78bfa" strokeWidth="4" />
</svg>
<div className="relative grid grid-cols-3 gap-6 items-center" style={{zIndex: 1}}>
{/* Browser */}
<div className={`bg-gradient-to-br from-cyan-600 to-blue-700 rounded-xl p-6 border-4 transition-all duration-300 ${
isHighlighted('browser') ? 'border-yellow-400 scale-105 shadow-2xl shadow-yellow-400/50' : 'border-cyan-500/30'
}`}>
<div className="text-center">
<div className="text-lg font-bold mb-3">🌐 Browser</div>
<div className="bg-white/10 rounded-lg p-4 mb-3">
<div className="text-xs text-cyan-200 mb-2">Counter Component</div>
<div className="bg-blue-900 rounded p-3">
<div className={`text-2xl font-bold mb-2 ${step >= 7 ? 'slide-down' : ''}`}>
Counter: {counterValue}
</div>
<button className={`bg-blue-500 hover:bg-blue-600 text-sm py-2 px-4 rounded w-full font-semibold ${
showMessage && step === 5 ? 'pulse-animate bg-yellow-500' : ''
}`}>
Increment
</button>
</div>
</div>
<div className="text-xs text-cyan-200">
HTML + JavaScript<br/>blazor.server.js
</div>
</div>
</div>
{/* SignalR Hub */}
<div className={`bg-gradient-to-br from-amber-600 to-orange-700 rounded-xl p-6 border-4 transition-all duration-300 ${
isHighlighted('signalr') ? 'border-yellow-400 scale-105 shadow-2xl shadow-yellow-400/50' : 'border-amber-500/30'
}`}>
<div className="text-center">
<div className="text-lg font-bold mb-3">⚡ SignalR Hub</div>
<div className="bg-orange-900/50 rounded-lg p-4 mb-3">
<div className="text-xs mb-2">WebSocket Connection</div>
<div className="flex items-center justify-center gap-2 mb-2">
<div className="w-3 h-3 bg-green-400 rounded-full animate-pulse"></div>
<span className="text-xs">Connected</span>
</div>
<div className="text-xs font-mono bg-orange-950 p-2 rounded">
ws://server/blazor
</div>
</div>
<div className="text-xs text-amber-200">
Persistent Connection<br/>Bi-directional
</div>
</div>
</div>
{/* Server Side */}
<div className="space-y-4">
{/* ASP.NET Server */}
<div className={`bg-gradient-to-br from-green-600 to-emerald-700 rounded-xl p-5 border-4 transition-all duration-300 ${
isHighlighted('server') ? 'border-yellow-400 scale-105 shadow-2xl shadow-yellow-400/50' : 'border-green-500/30'
}`}>
<div className="text-center">
<div className="text-base font-bold mb-2">🖥️ ASP.NET Server</div>
<div className="bg-green-900/50 rounded p-3 text-xs">
<div className="mb-1">• Render Components</div>
<div className="mb-1">• Execute C# Code</div>
<div>• Calculate Diffs</div>
</div>
</div>
</div>
{/* Blazor Component */}
<div className={`bg-gradient-to-br from-purple-600 to-pink-700 rounded-xl p-5 border-4 transition-all duration-300 ${
isHighlighted('component') ? 'border-yellow-400 scale-105 shadow-2xl shadow-yellow-400/50 pulse-animate' : 'border-purple-500/30'
}`}>
<div className="text-center">
<div className="text-base font-bold mb-2">⚙️ Component</div>
<div className="bg-purple-900/50 rounded p-3 font-mono text-xs text-left">
<div className="text-pink-300">@code {'{'}</div>
<div className="ml-2">int count = {counterValue};</div>
<div className="ml-2 text-green-300">void Increment()</div>
<div className="ml-4">count++;</div>
<div className="text-pink-300">{'}'}</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Progress Bar */}
<div className="bg-black/40 backdrop-blur rounded-lg p-4 mb-4">
<div className="flex justify-between mb-2 text-sm text-blue-200">
<span>Progress</span>
<span>{step + 1} / {steps.length}</span>
</div>
<div className="w-full bg-gray-800 rounded-full h-2">
<div
className="bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 h-2 rounded-full transition-all duration-500"
style={{ width: `${((step + 1) / steps.length) * 100}%` }}
/>
</div>
</div>
{/* Key Concepts */}
<div className="grid grid-cols-4 gap-3 text-xs">
<div className="bg-cyan-900/40 border border-cyan-500 rounded-lg p-3">
<div className="font-bold mb-1">🎯 Server-Side</div>
<div className="text-cyan-200">C# code τρέχει στον server</div>
</div>
<div className="bg-amber-900/40 border border-amber-500 rounded-lg p-3">
<div className="font-bold mb-1">⚡ Real-time</div>
<div className="text-amber-200">SignalR WebSocket connection</div>
</div>
<div className="bg-purple-900/40 border border-purple-500 rounded-lg p-3">
<div className="font-bold mb-1">🔄 Stateful</div>
<div className="text-purple-200">Server κρατάει το state</div>
</div>
<div className="bg-green-900/40 border border-green-500 rounded-lg p-3">
<div className="font-bold mb-1">📦 Small Updates</div>
<div className="text-green-200">Μόνο DOM diffs στέλνονται</div>
</div>
</div>
</div>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<BlazorServerBasics />);
</script>
</body>
</html>