Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
examples/wasm_demo/index.html
StratoSDK / examples / wasm_demo / index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta name="description" content="OxideUI WebAssembly Demo - A Rust UI Framework for the Web">
7 <title>OxideUI WASM Demo</title>
8 <style>
9 * {
10 margin: 0;
11 padding: 0;
12 box-sizing: border-box;
13 }
14
15 body {
16 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
17 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18 min-height: 100vh;
19 display: flex;
20 flex-direction: column;
21 color: #ffffff;
22 }
23
24 header {
25 padding: 20px;
26 background: rgba(0, 0, 0, 0.2);
27 backdrop-filter: blur(10px);
28 box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
29 }
30
31 header h1 {
32 font-size: 24px;
33 font-weight: 600;
34 }
35
36 header p {
37 font-size: 14px;
38 opacity: 0.8;
39 margin-top: 5px;
40 }
41
42 main {
43 flex: 1;
44 display: flex;
45 justify-content: center;
46 align-items: center;
47 padding: 40px 20px;
48 }
49
50 #app-container {
51 background: rgba(255, 255, 255, 0.1);
52 backdrop-filter: blur(20px);
53 border-radius: 20px;
54 padding: 40px;
55 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
56 max-width: 600px;
57 width: 100%;
58 }
59
60 #loading {
61 text-align: center;
62 padding: 60px 20px;
63 }
64
65 #loading h2 {
66 font-size: 28px;
67 margin-bottom: 20px;
68 }
69
70 .spinner {
71 width: 50px;
72 height: 50px;
73 margin: 20px auto;
74 border: 4px solid rgba(255, 255, 255, 0.3);
75 border-top-color: #ffffff;
76 border-radius: 50%;
77 animation: spin 1s linear infinite;
78 }
79
80 @keyframes spin {
81 to { transform: rotate(360deg); }
82 }
83
84 #oxide-canvas {
85 width: 100%;
86 height: 400px;
87 border-radius: 10px;
88 background: #1a1a2e;
89 display: none;
90 }
91
92 #counter-display {
93 text-align: center;
94 margin: 30px 0;
95 }
96
97 #counter-value {
98 font-size: 72px;
99 font-weight: bold;
100 color: #4ecdc4;
101 text-shadow: 0 2px 10px rgba(78, 205, 196, 0.5);
102 }
103
104 #counter-label {
105 font-size: 18px;
106 opacity: 0.8;
107 margin-top: 10px;
108 }
109
110 .button-group {
111 display: flex;
112 gap: 15px;
113 justify-content: center;
114 margin: 30px 0;
115 }
116
117 button {
118 padding: 12px 30px;
119 font-size: 16px;
120 font-weight: 600;
121 border: none;
122 border-radius: 8px;
123 cursor: pointer;
124 transition: all 0.3s ease;
125 box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
126 }
127
128 button:hover {
129 transform: translateY(-2px);
130 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
131 }
132
133 button:active {
134 transform: translateY(0);
135 }
136
137 .btn-primary {
138 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
139 color: white;
140 }
141
142 .btn-secondary {
143 background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
144 color: white;
145 }
146
147 .btn-danger {
148 background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
149 color: white;
150 }
151
152 #metrics {
153 margin-top: 30px;
154 padding: 20px;
155 background: rgba(0, 0, 0, 0.2);
156 border-radius: 10px;
157 font-size: 14px;
158 font-family: 'Courier New', monospace;
159 }
160
161 #metrics h3 {
162 margin-bottom: 10px;
163 font-size: 16px;
164 }
165
166 #metrics p {
167 margin: 5px 0;
168 opacity: 0.9;
169 }
170
171 footer {
172 padding: 20px;
173 text-align: center;
174 background: rgba(0, 0, 0, 0.2);
175 backdrop-filter: blur(10px);
176 }
177
178 footer a {
179 color: #4ecdc4;
180 text-decoration: none;
181 font-weight: 600;
182 }
183
184 footer a:hover {
185 text-decoration: underline;
186 }
187
188 .hidden {
189 display: none !important;
190 }
191
192 .error {
193 background: rgba(255, 0, 0, 0.2);
194 border: 2px solid rgba(255, 0, 0, 0.5);
195 padding: 20px;
196 border-radius: 10px;
197 text-align: center;
198 }
199
200 .error h2 {
201 color: #ff6b6b;
202 margin-bottom: 10px;
203 }
204
205 @media (max-width: 600px) {
206 #app-container {
207 padding: 20px;
208 }
209
210 #counter-value {
211 font-size: 48px;
212 }
213
214 .button-group {
215 flex-direction: column;
216 }
217
218 button {
219 width: 100%;
220 }
221 }
222 </style>
223</head>
224<body>
225 <header>
226 <h1>🦀 OxideUI WebAssembly Demo</h1>
227 <p>A high-performance Rust UI framework compiled to WebAssembly</p>
228 </header>
229
230 <main>
231 <div id="app-container">
232 <div id="loading">
233 <h2>Loading OxideUI...</h2>
234 <div class="spinner"></div>
235 <p>Initializing WebAssembly module</p>
236 </div>
237
238 <div id="app-content" class="hidden">
239 <canvas id="oxide-canvas"></canvas>
240
241 <div id="counter-display">
242 <div id="counter-value">0</div>
243 <div id="counter-label">Counter Value</div>
244 </div>
245
246 <div class="button-group">
247 <button id="btn-decrement" class="btn-secondary">➖ Decrement</button>
248 <button id="btn-reset" class="btn-danger">🔄 Reset</button>
249 <button id="btn-increment" class="btn-primary">➕ Increment</button>
250 </div>
251
252 <div id="metrics">
253 <h3>📊 Metrics</h3>
254 <p>Counter: <span id="metric-counter">0</span></p>
255 <p>Uptime: <span id="metric-uptime">0</span>ms</p>
256 <p>Browser: <span id="metric-browser">Loading...</span></p>
257 </div>
258 </div>
259
260 <div id="error" class="hidden error">
261 <h2>⚠️ Error Loading Application</h2>
262 <p id="error-message"></p>
263 </div>
264 </div>
265 </main>
266
267 <footer>
268 <p>
269 Built with ❤️ using <a href="https://github.com/oxideui/oxide-ui" target="_blank">OxideUI</a> |
270 <a href="https://www.rust-lang.org/" target="_blank">Rust</a> +
271 <a href="https://webassembly.org/" target="_blank">WebAssembly</a>
272 </p>
273 </footer>
274
275 <script type="module">
276 import init, { WasmApp, get_browser_info, log_message } from './pkg/oxide_wasm_demo.js';
277
278 let app = null;
279
280 async function run() {
281 try {
282 log_message('Starting OxideUI WASM application...');
283
284 // Initialize WASM module
285 await init();
286 log_message('WASM module initialized');
287
288 // Create app instance
289 app = new WasmApp('oxide-canvas');
290 log_message('App instance created');
291
292 // Hide loading, show app
293 document.getElementById('loading').classList.add('hidden');
294 document.getElementById('app-content').classList.remove('hidden');
295
296 // Set up event listeners
297 setupEventListeners();
298
299 // Get browser info
300 const browserInfo = get_browser_info();
301 document.getElementById('metric-browser').textContent = browserInfo.userAgent.split(' ')[0];
302
303 // Start render loop
304 app.start_render_loop();
305
306 // Update metrics periodically
307 setInterval(updateMetrics, 1000);
308
309 log_message('Application started successfully');
310
311 } catch (error) {
312 console.error('Failed to start app:', error);
313 showError(error.message || 'Unknown error occurred');
314 }
315 }
316
317 function setupEventListeners() {
318 document.getElementById('btn-increment').addEventListener('click', () => {
319 app.increment();
320 updateCounter();
321 });
322
323 document.getElementById('btn-decrement').addEventListener('click', () => {
324 app.decrement();
325 updateCounter();
326 });
327
328 document.getElementById('btn-reset').addEventListener('click', () => {
329 app.reset();
330 updateCounter();
331 });
332 }
333
334 function updateCounter() {
335 const value = app.counter;
336 document.getElementById('counter-value').textContent = value;
337 document.getElementById('metric-counter').textContent = value;
338 }
339
340 function updateMetrics() {
341 if (!app) return;
342
343 try {
344 const metrics = app.get_metrics();
345 document.getElementById('metric-counter').textContent = metrics.counter;
346 document.getElementById('metric-uptime').textContent = Math.round(metrics.uptime_ms);
347 } catch (error) {
348 console.error('Failed to update metrics:', error);
349 }
350 }
351
352 function showError(message) {
353 document.getElementById('loading').classList.add('hidden');
354 document.getElementById('error').classList.remove('hidden');
355 document.getElementById('error-message').textContent = message;
356 }
357
358 // Start the application
359 run();
360 </script>
361</body>
362</html>
363