cyclecad 0.9.7 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,800 @@
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
+ <title>Basic Tutorial Runner - cycleCAD</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ * {
12
+ margin: 0;
13
+ padding: 0;
14
+ box-sizing: border-box;
15
+ }
16
+
17
+ body {
18
+ font-family: 'Inter', sans-serif;
19
+ background-color: #f0f2f5;
20
+ color: #1a1a2e;
21
+ height: 100vh;
22
+ display: flex;
23
+ flex-direction: column;
24
+ overflow: hidden;
25
+ }
26
+
27
+ /* Header */
28
+ header {
29
+ background-color: #ffffff;
30
+ border-bottom: 1px solid #d0d7de;
31
+ padding: 16px 20px;
32
+ flex-shrink: 0;
33
+ position: sticky;
34
+ top: 0;
35
+ z-index: 100;
36
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
37
+ }
38
+
39
+ .header-content {
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: space-between;
43
+ gap: 20px;
44
+ max-width: 2000px;
45
+ margin: 0 auto;
46
+ }
47
+
48
+ .header-left {
49
+ display: flex;
50
+ align-items: center;
51
+ gap: 12px;
52
+ flex: 1;
53
+ }
54
+
55
+ .header-title {
56
+ font-size: 18px;
57
+ font-weight: 700;
58
+ color: #0969da;
59
+ }
60
+
61
+ .progress-section {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 12px;
65
+ flex: 1;
66
+ min-width: 300px;
67
+ }
68
+
69
+ .progress-bar-container {
70
+ flex: 1;
71
+ height: 8px;
72
+ background-color: #d0d7de;
73
+ border-radius: 4px;
74
+ overflow: hidden;
75
+ }
76
+
77
+ .progress-bar {
78
+ height: 100%;
79
+ background: linear-gradient(90deg, #0969da, #54aeff);
80
+ width: 0%;
81
+ transition: width 0.3s ease;
82
+ }
83
+
84
+ .step-counter {
85
+ font-size: 12px;
86
+ color: #57606a;
87
+ white-space: nowrap;
88
+ }
89
+
90
+ .header-controls {
91
+ display: flex;
92
+ gap: 8px;
93
+ }
94
+
95
+ button {
96
+ padding: 8px 16px;
97
+ border-radius: 6px;
98
+ border: 1px solid #d0d7de;
99
+ background-color: #ffffff;
100
+ color: #1a1a2e;
101
+ cursor: pointer;
102
+ font-size: 13px;
103
+ font-weight: 500;
104
+ transition: all 0.2s ease;
105
+ font-family: 'Inter', sans-serif;
106
+ }
107
+
108
+ button:hover:not(:disabled) {
109
+ background-color: #f0f2f5;
110
+ border-color: #0969da;
111
+ }
112
+
113
+ .btn-primary {
114
+ background-color: #0969da;
115
+ border-color: #0969da;
116
+ color: #fff;
117
+ }
118
+
119
+ .btn-primary:hover:not(:disabled) {
120
+ background-color: #0860ca;
121
+ border-color: #0860ca;
122
+ }
123
+
124
+ .btn-danger {
125
+ background-color: #cf222e;
126
+ border-color: #cf222e;
127
+ color: #fff;
128
+ }
129
+
130
+ .btn-danger:hover:not(:disabled) {
131
+ background-color: #a40e26;
132
+ border-color: #a40e26;
133
+ }
134
+
135
+ button:disabled {
136
+ opacity: 0.5;
137
+ cursor: not-allowed;
138
+ }
139
+
140
+ /* Main Container */
141
+ .container {
142
+ display: flex;
143
+ flex: 1;
144
+ overflow: hidden;
145
+ gap: 0;
146
+ }
147
+
148
+ /* Left Panel - Tutorial Steps */
149
+ .tutorial-panel {
150
+ width: 35%;
151
+ background-color: #ffffff;
152
+ border-right: 1px solid #d0d7de;
153
+ display: flex;
154
+ flex-direction: column;
155
+ overflow: hidden;
156
+ }
157
+
158
+ .steps-container {
159
+ flex: 1;
160
+ overflow-y: auto;
161
+ padding: 16px;
162
+ }
163
+
164
+ .steps-container::-webkit-scrollbar {
165
+ width: 8px;
166
+ }
167
+
168
+ .steps-container::-webkit-scrollbar-track {
169
+ background: transparent;
170
+ }
171
+
172
+ .steps-container::-webkit-scrollbar-thumb {
173
+ background-color: #c1c8cf;
174
+ border-radius: 4px;
175
+ }
176
+
177
+ .steps-container::-webkit-scrollbar-thumb:hover {
178
+ background-color: #57606a;
179
+ }
180
+
181
+ /* Step Card */
182
+ .step-card {
183
+ background-color: #f6f8fa;
184
+ border: 1px solid #d0d7de;
185
+ border-radius: 8px;
186
+ padding: 12px;
187
+ margin-bottom: 12px;
188
+ transition: all 0.2s ease;
189
+ cursor: pointer;
190
+ }
191
+
192
+ .step-card:hover {
193
+ border-color: #0969da;
194
+ background-color: #eaf5ff;
195
+ }
196
+
197
+ .step-card.active {
198
+ background-color: #ddf4ff;
199
+ border-color: #0969da;
200
+ animation: pulse 1s infinite;
201
+ }
202
+
203
+ .step-card.active .step-badge {
204
+ background-color: #0969da;
205
+ color: #fff;
206
+ }
207
+
208
+ .step-card.completed {
209
+ border-color: #1a7f37;
210
+ background-color: #dafbe1;
211
+ }
212
+
213
+ .step-card.completed .step-badge {
214
+ background-color: #1a7f37;
215
+ color: #fff;
216
+ }
217
+
218
+ .step-card.completed::after {
219
+ content: " ✓";
220
+ color: #1a7f37;
221
+ font-weight: 700;
222
+ margin-left: 4px;
223
+ }
224
+
225
+ @keyframes pulse {
226
+ 0%, 100% {
227
+ box-shadow: 0 0 0 0 rgba(9, 105, 218, 0.4);
228
+ }
229
+ 50% {
230
+ box-shadow: 0 0 0 10px rgba(9, 105, 218, 0);
231
+ }
232
+ }
233
+
234
+ .step-header {
235
+ display: flex;
236
+ align-items: center;
237
+ gap: 12px;
238
+ margin-bottom: 8px;
239
+ }
240
+
241
+ .step-badge {
242
+ background-color: #0969da;
243
+ color: #ffffff;
244
+ width: 28px;
245
+ height: 28px;
246
+ border-radius: 50%;
247
+ display: flex;
248
+ align-items: center;
249
+ justify-content: center;
250
+ font-size: 12px;
251
+ font-weight: 700;
252
+ flex-shrink: 0;
253
+ }
254
+
255
+ .step-title {
256
+ font-size: 14px;
257
+ font-weight: 600;
258
+ color: #1a1a2e;
259
+ flex: 1;
260
+ }
261
+
262
+ .step-status {
263
+ font-size: 11px;
264
+ color: #57606a;
265
+ }
266
+
267
+ .step-description {
268
+ font-size: 13px;
269
+ color: #57606a;
270
+ margin-bottom: 8px;
271
+ line-height: 1.4;
272
+ }
273
+
274
+ .step-details {
275
+ display: none;
276
+ background-color: #eaf5ff;
277
+ border-left: 2px solid #0969da;
278
+ padding: 8px 12px;
279
+ border-radius: 4px;
280
+ margin-bottom: 8px;
281
+ font-size: 12px;
282
+ color: #1a1a2e;
283
+ line-height: 1.5;
284
+ }
285
+
286
+ .step-details.expanded {
287
+ display: block;
288
+ }
289
+
290
+ .step-code {
291
+ background-color: #f6f8fa;
292
+ border: 1px solid #d0d7de;
293
+ border-radius: 4px;
294
+ padding: 8px;
295
+ margin-top: 4px;
296
+ font-family: 'Monaco', monospace;
297
+ font-size: 11px;
298
+ color: #0969da;
299
+ overflow-x: auto;
300
+ }
301
+
302
+ .step-actions {
303
+ display: flex;
304
+ gap: 8px;
305
+ }
306
+
307
+ .step-run-btn {
308
+ flex: 1;
309
+ padding: 8px 12px;
310
+ font-size: 12px;
311
+ background-color: #0969da;
312
+ border-color: #0969da;
313
+ color: #ffffff;
314
+ font-weight: 600;
315
+ border-radius: 4px;
316
+ }
317
+
318
+ .step-run-btn:hover:not(:disabled) {
319
+ background-color: #79c0ff;
320
+ border-color: #79c0ff;
321
+ }
322
+
323
+ .step-run-btn:disabled {
324
+ background-color: #d0d7de;
325
+ border-color: #d0d7de;
326
+ color: #57606a;
327
+ }
328
+
329
+ .step-details-toggle {
330
+ padding: 6px 10px;
331
+ font-size: 11px;
332
+ background-color: transparent;
333
+ border: 1px solid #d0d7de;
334
+ }
335
+
336
+ /* Right Panel - App Preview */
337
+ .app-panel {
338
+ flex: 1;
339
+ display: flex;
340
+ flex-direction: column;
341
+ background-color: #ffffff;
342
+ overflow: hidden;
343
+ }
344
+
345
+ .app-header {
346
+ background-color: #f6f8fa;
347
+ border-bottom: 1px solid #d0d7de;
348
+ padding: 12px 16px;
349
+ display: flex;
350
+ align-items: center;
351
+ justify-content: space-between;
352
+ gap: 12px;
353
+ flex-shrink: 0;
354
+ }
355
+
356
+ .app-header-left {
357
+ display: flex;
358
+ align-items: center;
359
+ gap: 12px;
360
+ }
361
+
362
+ .app-indicator {
363
+ width: 10px;
364
+ height: 10px;
365
+ border-radius: 50%;
366
+ background-color: #1a7f37;
367
+ animation: blink 1s infinite;
368
+ }
369
+
370
+ @keyframes blink {
371
+ 0%, 50%, 100% { opacity: 1; }
372
+ 25%, 75% { opacity: 0.5; }
373
+ }
374
+
375
+ .app-url {
376
+ font-size: 12px;
377
+ color: #57606a;
378
+ font-family: 'Monaco', monospace;
379
+ }
380
+
381
+ .app-actions {
382
+ display: flex;
383
+ gap: 8px;
384
+ }
385
+
386
+ iframe {
387
+ flex: 1;
388
+ border: none;
389
+ background-color: #ffffff;
390
+ }
391
+
392
+ .message-box {
393
+ padding: 12px 16px;
394
+ border-radius: 6px;
395
+ border-left: 3px solid;
396
+ font-size: 12px;
397
+ line-height: 1.5;
398
+ }
399
+
400
+ .message-box.warning {
401
+ background-color: #fff8c5;
402
+ border-left-color: #d29922;
403
+ color: #1a1a2e;
404
+ }
405
+
406
+ footer {
407
+ background-color: #f6f8fa;
408
+ border-top: 1px solid #d0d7de;
409
+ padding: 8px 16px;
410
+ font-size: 11px;
411
+ color: #57606a;
412
+ flex-shrink: 0;
413
+ }
414
+
415
+ /* Floating Shortcuts Panel */
416
+ .shortcuts-panel {
417
+ position: fixed;
418
+ bottom: 80px;
419
+ right: 20px;
420
+ width: 320px;
421
+ max-height: 500px;
422
+ background-color: #f6f8fa;
423
+ border: 1px solid #d0d7de;
424
+ border-radius: 8px;
425
+ display: none;
426
+ flex-direction: column;
427
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
428
+ z-index: 200;
429
+ }
430
+
431
+ .shortcuts-panel.visible {
432
+ display: flex;
433
+ }
434
+
435
+ .shortcuts-header {
436
+ padding: 12px 16px;
437
+ border-bottom: 1px solid #d0d7de;
438
+ display: flex;
439
+ justify-content: space-between;
440
+ align-items: center;
441
+ flex-shrink: 0;
442
+ }
443
+
444
+ .shortcuts-header h3 {
445
+ font-size: 14px;
446
+ font-weight: 600;
447
+ }
448
+
449
+ .shortcuts-close {
450
+ background: none;
451
+ border: none;
452
+ color: #57606a;
453
+ cursor: pointer;
454
+ padding: 0;
455
+ font-size: 16px;
456
+ }
457
+
458
+ .shortcuts-content {
459
+ flex: 1;
460
+ overflow-y: auto;
461
+ padding: 12px 16px;
462
+ }
463
+
464
+ .shortcuts-content::-webkit-scrollbar {
465
+ width: 6px;
466
+ }
467
+
468
+ .shortcuts-content::-webkit-scrollbar-thumb {
469
+ background-color: #d0d7de;
470
+ border-radius: 3px;
471
+ }
472
+
473
+ .shortcut-item {
474
+ display: flex;
475
+ justify-content: space-between;
476
+ gap: 12px;
477
+ margin-bottom: 8px;
478
+ font-size: 12px;
479
+ padding-bottom: 8px;
480
+ border-bottom: 1px solid #d0d7de;
481
+ }
482
+
483
+ .shortcut-item:last-child {
484
+ border-bottom: none;
485
+ margin-bottom: 0;
486
+ padding-bottom: 0;
487
+ }
488
+
489
+ .shortcut-key {
490
+ background-color: #ffffff;
491
+ border: 1px solid #d0d7de;
492
+ border-radius: 4px;
493
+ padding: 2px 6px;
494
+ font-family: 'Monaco', monospace;
495
+ font-weight: 600;
496
+ color: #0969da;
497
+ white-space: nowrap;
498
+ flex-shrink: 0;
499
+ }
500
+
501
+ .shortcut-desc {
502
+ color: #57606a;
503
+ }
504
+
505
+ .shortcuts-toggle {
506
+ position: fixed;
507
+ bottom: 20px;
508
+ right: 20px;
509
+ width: 48px;
510
+ height: 48px;
511
+ border-radius: 50%;
512
+ background-color: #0969da;
513
+ border: none;
514
+ color: #ffffff;
515
+ font-size: 20px;
516
+ font-weight: 700;
517
+ cursor: pointer;
518
+ display: flex;
519
+ align-items: center;
520
+ justify-content: center;
521
+ z-index: 150;
522
+ transition: all 0.2s ease;
523
+ }
524
+
525
+ .shortcuts-toggle:hover {
526
+ background-color: #0860ca;
527
+ transform: scale(1.1);
528
+ }
529
+ </style>
530
+ </head>
531
+ <body>
532
+ <!-- Header -->
533
+ <header>
534
+ <div class="header-content">
535
+ <div class="header-left">
536
+ <div class="header-title">Basic Tutorial Runner</div>
537
+ </div>
538
+ <div class="progress-section">
539
+ <div class="progress-bar-container">
540
+ <div class="progress-bar" id="progressBar"></div>
541
+ </div>
542
+ <div class="step-counter" id="stepCounter">Step 0 of 4</div>
543
+ </div>
544
+ <div class="header-controls">
545
+ <button class="btn-primary" id="runAllBtn">▶ Run All</button>
546
+ <button class="btn-danger" id="stopBtn" disabled>⏹ Stop</button>
547
+ </div>
548
+ </div>
549
+ </header>
550
+
551
+ <!-- Main Container -->
552
+ <div class="container">
553
+ <!-- Left Panel - Tutorial Steps -->
554
+ <div class="tutorial-panel">
555
+ <div class="steps-container" id="stepsContainer"></div>
556
+ <footer>
557
+ <div id="footerText">Select a step to begin</div>
558
+ </footer>
559
+ </div>
560
+
561
+ <!-- Right Panel - App Preview -->
562
+ <div class="app-panel">
563
+ <div class="app-header">
564
+ <div class="app-header-left">
565
+ <div class="app-indicator" id="appIndicator"></div>
566
+ <div class="app-url">cyclecad.com/app/</div>
567
+ </div>
568
+ <div class="app-actions">
569
+ <button id="openTabBtn">↗ Open in Tab</button>
570
+ <button id="reloadAppBtn">⟳ Reload</button>
571
+ </div>
572
+ </div>
573
+ <iframe id="app-frame" src="../index.html"></iframe>
574
+ <div class="message-box warning" style="margin: 12px; display: none;" id="crossOriginMsg">
575
+ <strong>Note:</strong> If steps don't auto-execute, the app may need to be on the same origin. Open cycleCAD in a separate tab and follow along manually.
576
+ </div>
577
+ </div>
578
+ </div>
579
+
580
+ <!-- Floating Shortcuts Panel -->
581
+ <button class="shortcuts-toggle" id="shortcutsToggle" title="Keyboard Shortcuts (?)">?</button>
582
+ <div class="shortcuts-panel" id="shortcutsPanel">
583
+ <div class="shortcuts-header">
584
+ <h3>Basic Tutorial Steps</h3>
585
+ <button class="shortcuts-close" id="shortcutsClose">✕</button>
586
+ </div>
587
+ <div class="shortcuts-content" id="shortcutsContent"></div>
588
+ </div>
589
+
590
+ <script>
591
+ // Basic Tutorial Steps Data
592
+ const TUTORIAL_STEPS = [
593
+ {
594
+ number: 1,
595
+ title: "Create Your First Sketch",
596
+ description: "Start by creating a 2D sketch on the XY plane",
597
+ detail: "Draw a simple rectangle on the sketch plane. Click the Sketch tool, draw a rectangle with dimensions 80x40mm, then finish the sketch.",
598
+ action: "Click the Sketch button in the Create tab",
599
+ type: "button-click",
600
+ category: "Getting Started"
601
+ },
602
+ {
603
+ number: 2,
604
+ title: "Draw a Rectangle",
605
+ description: "In the sketch, draw a rectangle shape",
606
+ detail: "Use the rectangle tool to create a 80x40mm shape. Click two opposite corners to define the rectangle.",
607
+ action: "Press R for rectangle tool, click and drag",
608
+ type: "keyboard",
609
+ category: "Getting Started"
610
+ },
611
+ {
612
+ number: 3,
613
+ title: "Extrude the Sketch",
614
+ description: "Convert the 2D sketch into 3D geometry by extruding",
615
+ detail: "Exit the sketch and click the Extrude button. Set the height to 25mm. This creates a solid box from your rectangle.",
616
+ action: "Press E or click Extrude in Create tab, set height to 25mm",
617
+ type: "keyboard",
618
+ category: "Creating 3D"
619
+ },
620
+ {
621
+ number: 4,
622
+ title: "Export Your Model",
623
+ description: "Save your model in your preferred format",
624
+ detail: "Go to the Export tab and choose STL, OBJ, or glTF format. Click Export and save the file to your computer.",
625
+ action: "Click Export tab, select format, click Export button",
626
+ type: "button-click",
627
+ category: "Finishing"
628
+ }
629
+ ];
630
+
631
+ let currentStep = 0;
632
+ let isRunning = false;
633
+
634
+ // Initialize UI
635
+ function initializeUI() {
636
+ const stepsContainer = document.getElementById('stepsContainer');
637
+ stepsContainer.innerHTML = '';
638
+
639
+ TUTORIAL_STEPS.forEach((step, index) => {
640
+ const card = document.createElement('div');
641
+ card.className = 'step-card';
642
+ card.innerHTML = `
643
+ <div class="step-header">
644
+ <div class="step-badge">${step.number}</div>
645
+ <div class="step-title">${step.title}</div>
646
+ </div>
647
+ <div class="step-description">${step.description}</div>
648
+ <div class="step-details" id="details-${index}">
649
+ <strong>Details:</strong> ${step.detail}<br><br>
650
+ <strong>Action:</strong> ${step.action}
651
+ </div>
652
+ <div class="step-actions">
653
+ <button class="step-run-btn" data-step="${index}">▶ Run</button>
654
+ <button class="step-details-toggle" data-step="${index}">Details</button>
655
+ </div>
656
+ `;
657
+
658
+ card.addEventListener('click', () => selectStep(index));
659
+ card.querySelector('.step-run-btn').addEventListener('click', (e) => {
660
+ e.stopPropagation();
661
+ runStep(index);
662
+ });
663
+ card.querySelector('.step-details-toggle').addEventListener('click', (e) => {
664
+ e.stopPropagation();
665
+ toggleDetails(index);
666
+ });
667
+
668
+ stepsContainer.appendChild(card);
669
+ });
670
+
671
+ setupShortcutsPanel();
672
+ }
673
+
674
+ function selectStep(index) {
675
+ document.querySelectorAll('.step-card').forEach((card, i) => {
676
+ card.classList.toggle('active', i === index);
677
+ });
678
+ currentStep = index;
679
+ updateProgressBar();
680
+ }
681
+
682
+ function toggleDetails(index) {
683
+ const detailsEl = document.getElementById(`details-${index}`);
684
+ detailsEl.classList.toggle('expanded');
685
+ }
686
+
687
+ function runStep(index) {
688
+ const step = TUTORIAL_STEPS[index];
689
+ selectStep(index);
690
+
691
+ // Show feedback
692
+ const card = document.querySelectorAll('.step-card')[index];
693
+ card.classList.add('completed');
694
+
695
+ // Try to send message to iframe
696
+ const iframe = document.getElementById('app-frame');
697
+ try {
698
+ iframe.contentWindow.postMessage({
699
+ type: 'tutorial-step',
700
+ step: step.number,
701
+ action: step.action,
702
+ actionType: step.type
703
+ }, '*');
704
+ } catch (e) {
705
+ console.log('Cross-origin restriction: manual execution needed');
706
+ showCrossOriginMessage();
707
+ }
708
+
709
+ updateFooter(`Step ${step.number}: ${step.title} executed`);
710
+ }
711
+
712
+ async function runAllSteps() {
713
+ isRunning = true;
714
+ document.getElementById('runAllBtn').disabled = true;
715
+ document.getElementById('stopBtn').disabled = false;
716
+
717
+ for (let i = 0; i < TUTORIAL_STEPS.length && isRunning; i++) {
718
+ runStep(i);
719
+ await new Promise(resolve => setTimeout(resolve, 1500));
720
+ }
721
+
722
+ isRunning = false;
723
+ document.getElementById('runAllBtn').disabled = false;
724
+ document.getElementById('stopBtn').disabled = true;
725
+ updateFooter('All steps completed!');
726
+ }
727
+
728
+ function stopRunning() {
729
+ isRunning = false;
730
+ document.getElementById('runAllBtn').disabled = false;
731
+ document.getElementById('stopBtn').disabled = true;
732
+ updateFooter('Execution stopped');
733
+ }
734
+
735
+ function updateProgressBar() {
736
+ const completedCount = document.querySelectorAll('.step-card.completed').length;
737
+ const percentage = (completedCount / TUTORIAL_STEPS.length) * 100;
738
+ document.getElementById('progressBar').style.width = percentage + '%';
739
+ document.getElementById('stepCounter').textContent = `Step ${completedCount} of ${TUTORIAL_STEPS.length}`;
740
+ }
741
+
742
+ function updateFooter(text) {
743
+ document.getElementById('footerText').textContent = text;
744
+ }
745
+
746
+ function showCrossOriginMessage() {
747
+ const msg = document.getElementById('crossOriginMsg');
748
+ msg.style.display = 'block';
749
+ setTimeout(() => { msg.style.display = 'none'; }, 5000);
750
+ }
751
+
752
+ function setupShortcutsPanel() {
753
+ const shortcuts = [
754
+ { key: 'R', desc: 'Rectangle tool (in sketch)' },
755
+ { key: 'E', desc: 'Extrude operation' },
756
+ { key: 'Esc', desc: 'Exit current tool' },
757
+ { key: '?', desc: 'Toggle this panel' }
758
+ ];
759
+
760
+ const content = document.getElementById('shortcutsContent');
761
+ content.innerHTML = shortcuts.map(s => `
762
+ <div class="shortcut-item">
763
+ <span class="shortcut-desc">${s.desc}</span>
764
+ <span class="shortcut-key">${s.key}</span>
765
+ </div>
766
+ `).join('');
767
+ }
768
+
769
+ // Event Listeners
770
+ document.getElementById('runAllBtn').addEventListener('click', runAllSteps);
771
+ document.getElementById('stopBtn').addEventListener('click', stopRunning);
772
+ document.getElementById('openTabBtn').addEventListener('click', () => {
773
+ window.open('../index.html', 'cyclecad-app');
774
+ });
775
+ document.getElementById('reloadAppBtn').addEventListener('click', () => {
776
+ document.getElementById('app-frame').src = document.getElementById('app-frame').src;
777
+ });
778
+ document.getElementById('shortcutsToggle').addEventListener('click', () => {
779
+ document.getElementById('shortcutsPanel').classList.toggle('visible');
780
+ });
781
+ document.getElementById('shortcutsClose').addEventListener('click', () => {
782
+ document.getElementById('shortcutsPanel').classList.remove('visible');
783
+ });
784
+
785
+ // Initialize on load
786
+ window.addEventListener('load', () => {
787
+ initializeUI();
788
+ selectStep(0);
789
+ updateFooter('Select a step to begin');
790
+ });
791
+
792
+ // Receive messages from iframe
793
+ window.addEventListener('message', (event) => {
794
+ if (event.data.type === 'app-ready') {
795
+ updateFooter('App loaded and ready');
796
+ }
797
+ });
798
+ </script>
799
+ </body>
800
+ </html>