cognikit 0.1.0 → 0.1.2

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.
Files changed (47) hide show
  1. package/dist/client.d.ts +10 -0
  2. package/dist/client.js +4601 -0
  3. package/dist/client.js.map +7 -0
  4. package/dist/index.d.ts +9 -4
  5. package/dist/index.js +2075 -1992
  6. package/dist/index.js.map +4 -4
  7. package/dist/interactions/categorize-the-words/static.d.ts +1 -1
  8. package/dist/interactions/fill-blanks/static.d.ts +1 -1
  9. package/dist/interactions/mark-the-words/static.d.ts +1 -1
  10. package/dist/interactions/text-transformation/static.d.ts +1 -1
  11. package/dist/shared/config.d.ts +18 -0
  12. package/dist/shared/icons.d.ts +3 -0
  13. package/dist/shared/index.d.ts +1 -0
  14. package/dist/shared/managers/SoundManager.d.ts +1 -2
  15. package/dist/shared/ssr.d.ts +1 -0
  16. package/package.json +10 -5
  17. package/public/app.js +13713 -0
  18. package/public/app.js.map +7 -0
  19. package/public/assets/audio/failure.mp3 +0 -0
  20. package/public/assets/audio/flip.mp3 +0 -0
  21. package/public/assets/audio/low-time.mp3 +0 -0
  22. package/public/assets/audio/plus.mp3 +0 -0
  23. package/public/assets/audio/pop.mp3 +0 -0
  24. package/public/assets/audio/start.mp3 +0 -0
  25. package/public/assets/audio/success.mp3 +0 -0
  26. package/public/assets/eduguiders-logo.png +0 -0
  27. package/public/assets/icons/audio.svg +83 -0
  28. package/public/assets/icons/data.svg +2 -0
  29. package/public/assets/icons/down.svg +2 -0
  30. package/public/assets/icons/drag-horizontal-svgrepo-com.svg +4 -0
  31. package/public/assets/icons/drag-vertical-svgrepo-com.svg +4 -0
  32. package/public/assets/icons/error.svg +2 -0
  33. package/public/assets/icons/eye-disabled.svg +8 -0
  34. package/public/assets/icons/eye.svg +5 -0
  35. package/public/assets/icons/image-picture-svgrepo-com-dark.svg +17 -0
  36. package/public/assets/icons/image.svg +17 -0
  37. package/public/assets/icons/link.svg +5 -0
  38. package/public/assets/icons/repeat.svg +7 -0
  39. package/public/assets/icons/star.svg +4 -0
  40. package/public/assets/icons/up.svg +2 -0
  41. package/public/assets/icons/video.svg +6 -0
  42. package/public/assets/images/pointing-hand.svg +1 -0
  43. package/public/examples/chip.html +495 -0
  44. package/public/index.html +754 -0
  45. package/public/scalable-bare.html +432 -0
  46. package/public/tables-demo.html +534 -0
  47. package/public/text-interactions-demo.html +604 -0
@@ -0,0 +1,754 @@
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, maximum-scale=5.0, user-scalable=yes, viewport-fit=cover">
6
+ <meta name="mobile-web-app-capable" content="yes">
7
+ <meta name="apple-mobile-web-app-capable" content="yes">
8
+ <meta name="apple-mobile-web-app-status-bar-style" content="default">
9
+ <meta name="theme-color" content="#f7f9fc">
10
+ <title>CogniKit - Beta Interaction Playground</title>
11
+ <style>
12
+ * {
13
+ margin: 0;
14
+ padding: 0;
15
+ box-sizing: border-box;
16
+ }
17
+
18
+ html, body {
19
+ width: 100%;
20
+ height: 100%;
21
+ overflow: hidden;
22
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
23
+ -webkit-font-smoothing: antialiased;
24
+ -moz-osx-font-smoothing: grayscale;
25
+ }
26
+
27
+ :root {
28
+ --edu-bg: 247 249 252;
29
+ --edu-card: 255 255 255;
30
+ --edu-ink: 31 41 55;
31
+ --edu-second-ink: 71 85 105;
32
+ --edu-third-ink: 100 116 139;
33
+ --edu-inverted-ink: 248 250 252;
34
+ --edu-success: 22 163 74;
35
+ --edu-error: 220 38 38;
36
+ --edu-warning: 255 222 33;
37
+ --edu-neutral: 14 165 233;
38
+ --edu-first-accent: 49 120 198;
39
+ --edu-second-accent: 245 158 11;
40
+ --edu-third-accent: 236 72 153;
41
+ --edu-border: 229 231 235;
42
+ --edu-muted: 243 244 246;
43
+ --edu-radius: 0.375rem;
44
+ --edu-shadow-color: 0 0 0;
45
+ --edu-pad: 1rem;
46
+ --edu-mar: 0;
47
+ }
48
+
49
+ body {
50
+ background: rgb(var(--edu-bg));
51
+ display: flex;
52
+ flex-direction: column;
53
+ height: 100vh;
54
+ height: 100dvh;
55
+ }
56
+
57
+ /* Header */
58
+ .header {
59
+ display: flex;
60
+ align-items: center;
61
+ justify-content: space-between;
62
+ padding: 1rem 1.5rem;
63
+ background: rgb(var(--edu-card));
64
+ border-bottom: 2px solid rgb(var(--edu-border));
65
+ box-shadow: 0 2px 8px rgba(var(--edu-shadow-color), 0.05);
66
+ flex-shrink: 0;
67
+ z-index: 100;
68
+ }
69
+
70
+ .header h1 {
71
+ font-size: 1.25rem;
72
+ color: rgb(var(--edu-ink));
73
+ font-weight: 700;
74
+ }
75
+
76
+ .header-controls {
77
+ display: flex;
78
+ gap: 0.75rem;
79
+ }
80
+
81
+ .icon-button {
82
+ background: rgb(var(--edu-card));
83
+ border: 2px solid rgb(var(--edu-border));
84
+ border-radius: 8px;
85
+ width: 44px;
86
+ height: 44px;
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: center;
90
+ cursor: pointer;
91
+ transition: all 0.2s;
92
+ color: rgb(var(--edu-ink));
93
+ font-size: 1.2rem;
94
+ }
95
+
96
+ .icon-button:hover {
97
+ border-color: rgb(var(--edu-first-accent));
98
+ background: rgba(var(--edu-first-accent), 0.1);
99
+ }
100
+
101
+ .icon-button:active {
102
+ transform: scale(0.95);
103
+ }
104
+
105
+ /* Main viewport */
106
+ .main-viewport {
107
+ flex: 1;
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ padding: 1.5rem;
112
+ overflow: hidden;
113
+ }
114
+
115
+ .interaction-container {
116
+ width: 100%;
117
+ height: 100%;
118
+ max-width: 1200px;
119
+ display: flex;
120
+ flex-direction: column;
121
+ }
122
+
123
+ edu-window {
124
+ width: 100%;
125
+ height: 100%;
126
+ display: block;
127
+ }
128
+
129
+ /* Modal */
130
+ .modal-overlay {
131
+ position: fixed;
132
+ top: 0;
133
+ left: 0;
134
+ right: 0;
135
+ bottom: 0;
136
+ background: rgba(0, 0, 0, 0.5);
137
+ backdrop-filter: blur(4px);
138
+ display: none;
139
+ align-items: center;
140
+ justify-content: center;
141
+ z-index: 1000;
142
+ padding: 1rem;
143
+ }
144
+
145
+ .modal-overlay.active {
146
+ display: flex;
147
+ }
148
+
149
+ .modal {
150
+ background: rgb(var(--edu-card));
151
+ border-radius: 16px;
152
+ box-shadow: 0 20px 60px rgba(var(--edu-shadow-color), 0.3);
153
+ max-width: 600px;
154
+ width: 100%;
155
+ max-height: 90vh;
156
+ max-height: 90dvh;
157
+ overflow: hidden;
158
+ display: flex;
159
+ flex-direction: column;
160
+ }
161
+
162
+ .modal-header {
163
+ padding: 1.5rem;
164
+ border-bottom: 2px solid rgb(var(--edu-border));
165
+ display: flex;
166
+ align-items: center;
167
+ justify-content: space-between;
168
+ }
169
+
170
+ .modal-header h2 {
171
+ font-size: 1.25rem;
172
+ color: rgb(var(--edu-ink));
173
+ }
174
+
175
+ .modal-close {
176
+ background: none;
177
+ border: none;
178
+ font-size: 1.5rem;
179
+ cursor: pointer;
180
+ color: rgb(var(--edu-second-ink));
181
+ width: 32px;
182
+ height: 32px;
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ border-radius: 6px;
187
+ transition: all 0.2s;
188
+ }
189
+
190
+ .modal-close:hover {
191
+ background: rgba(var(--edu-error), 0.1);
192
+ color: rgb(var(--edu-error));
193
+ }
194
+
195
+ .modal-body {
196
+ padding: 1.5rem;
197
+ overflow-y: auto;
198
+ flex: 1;
199
+ }
200
+
201
+ .form-group {
202
+ margin-bottom: 1.5rem;
203
+ }
204
+
205
+ .form-group label {
206
+ display: block;
207
+ font-weight: 600;
208
+ color: rgb(var(--edu-ink));
209
+ margin-bottom: 0.5rem;
210
+ font-size: 0.95rem;
211
+ }
212
+
213
+ .form-group select,
214
+ .form-group input,
215
+ .form-group textarea {
216
+ width: 100%;
217
+ padding: 0.75rem;
218
+ border: 2px solid rgb(var(--edu-border));
219
+ border-radius: 8px;
220
+ background: rgb(var(--edu-bg));
221
+ color: rgb(var(--edu-ink));
222
+ font-size: 0.95rem;
223
+ font-family: inherit;
224
+ transition: all 0.2s;
225
+ }
226
+
227
+ .form-group textarea {
228
+ font-family: 'Monaco', 'Courier New', monospace;
229
+ min-height: 150px;
230
+ resize: vertical;
231
+ }
232
+
233
+ .form-group select:focus,
234
+ .form-group input:focus,
235
+ .form-group textarea:focus {
236
+ outline: none;
237
+ border-color: rgb(var(--edu-first-accent));
238
+ background: rgb(var(--edu-card));
239
+ }
240
+
241
+ .modal-footer {
242
+ padding: 1.5rem;
243
+ border-top: 2px solid rgb(var(--edu-border));
244
+ display: flex;
245
+ gap: 1rem;
246
+ justify-content: flex-end;
247
+ }
248
+
249
+ .btn {
250
+ padding: 0.75rem 1.5rem;
251
+ border-radius: 8px;
252
+ border: 2px solid rgb(var(--edu-border));
253
+ background: rgb(var(--edu-card));
254
+ color: rgb(var(--edu-ink));
255
+ font-weight: 600;
256
+ font-size: 0.95rem;
257
+ cursor: pointer;
258
+ transition: all 0.2s;
259
+ min-height: 44px;
260
+ }
261
+
262
+ .btn:hover {
263
+ border-color: rgb(var(--edu-first-accent));
264
+ background: rgba(var(--edu-first-accent), 0.1);
265
+ }
266
+
267
+ .btn:active {
268
+ transform: scale(0.98);
269
+ }
270
+
271
+ .btn-primary {
272
+ background: rgb(var(--edu-first-accent));
273
+ border-color: rgb(var(--edu-first-accent));
274
+ color: rgb(var(--edu-inverted-ink));
275
+ }
276
+
277
+ .btn-primary:hover {
278
+ opacity: 0.9;
279
+ }
280
+
281
+ .form-help {
282
+ font-size: 0.85rem;
283
+ color: rgb(var(--edu-second-ink));
284
+ margin-top: 0.5rem;
285
+ }
286
+
287
+ /* Fullscreen mode */
288
+ body.fullscreen .header {
289
+ display: none;
290
+ }
291
+
292
+ body.fullscreen .main-viewport {
293
+ padding: 0;
294
+ }
295
+
296
+ body.fullscreen .interaction-container {
297
+ max-width: none;
298
+ }
299
+
300
+ /* Mobile styles */
301
+ @media (max-width: 768px) {
302
+ .header {
303
+ padding: 0.75rem 1rem;
304
+ }
305
+
306
+ .header h1 {
307
+ font-size: 1rem;
308
+ }
309
+
310
+ .icon-button {
311
+ width: 40px;
312
+ height: 40px;
313
+ font-size: 1rem;
314
+ }
315
+
316
+ .main-viewport {
317
+ padding: 1rem;
318
+ }
319
+
320
+ .modal {
321
+ border-radius: 12px;
322
+ max-height: 95vh;
323
+ max-height: 95dvh;
324
+ }
325
+
326
+ .modal-header,
327
+ .modal-body,
328
+ .modal-footer {
329
+ padding: 1rem;
330
+ }
331
+
332
+ .form-group textarea {
333
+ min-height: 120px;
334
+ }
335
+ }
336
+
337
+ @media (max-width: 480px) {
338
+ .main-viewport {
339
+ padding: 0.5rem;
340
+ }
341
+
342
+ .modal-footer {
343
+ flex-direction: column;
344
+ }
345
+
346
+ .btn {
347
+ width: 100%;
348
+ }
349
+ }
350
+ </style>
351
+ </head>
352
+ <body>
353
+ <!-- Header -->
354
+ <div class="header">
355
+ <h1>🎯 CogniKit Beta</h1>
356
+ <div class="header-controls">
357
+ <button class="icon-button" id="settings-btn" title="Settings">⚙️</button>
358
+ <button class="icon-button" id="config-btn" title="Configure Interaction">🎨</button>
359
+ <button class="icon-button" id="fullscreen-btn" title="Toggle Fullscreen">⛶</button>
360
+ </div>
361
+ </div>
362
+
363
+ <!-- Main Viewport -->
364
+ <div class="main-viewport">
365
+ <div class="interaction-container">
366
+ <edu-window id="interaction-viewport"></edu-window>
367
+ </div>
368
+ </div>
369
+
370
+ <!-- Settings Modal -->
371
+ <div class="modal-overlay" id="settings-modal">
372
+ <div class="modal">
373
+ <div class="modal-header">
374
+ <h2>⚙️ Settings</h2>
375
+ <button class="modal-close" id="settings-close">×</button>
376
+ </div>
377
+ <div class="modal-body">
378
+ <div class="form-group">
379
+ <label for="variant-select">Variant Style</label>
380
+ <select id="variant-select">
381
+ <option value="elegant" selected>Elegant</option>
382
+ <option value="playful">Playful</option>
383
+ <option value="outline">Outline</option>
384
+ <option value="letter">Letter</option>
385
+ <option value="sign">Sign</option>
386
+ <option value="minimal">Minimal</option>
387
+ <option value="glass">Glass</option>
388
+ <option value="card">Card</option>
389
+ <option value="empty">Empty</option>
390
+ </select>
391
+ </div>
392
+
393
+ <div class="form-group">
394
+ <label for="theme-select">Theme</label>
395
+ <select id="theme-select">
396
+ <option value="light" selected>Light</option>
397
+ <option value="dark">Dark</option>
398
+ <option value="dark-blue">Dark Blue</option>
399
+ </select>
400
+ <div class="form-help">Theme switching not yet implemented</div>
401
+ </div>
402
+
403
+ <div class="form-group">
404
+ <label for="accent-color">Accent Color</label>
405
+ <input type="color" id="accent-color" value="#67CB90">
406
+ <div class="form-help">Color customization not yet implemented</div>
407
+ </div>
408
+ </div>
409
+ <div class="modal-footer">
410
+ <button class="btn" id="settings-cancel">Cancel</button>
411
+ <button class="btn btn-primary" id="settings-apply">Apply</button>
412
+ </div>
413
+ </div>
414
+ </div>
415
+
416
+ <!-- Configuration Modal -->
417
+ <div class="modal-overlay" id="config-modal">
418
+ <div class="modal">
419
+ <div class="modal-header">
420
+ <h2>🎨 Configure Interaction</h2>
421
+ <button class="modal-close" id="config-close">×</button>
422
+ </div>
423
+ <div class="modal-body">
424
+ <div class="form-group">
425
+ <label for="interaction-type">Interaction Type</label>
426
+ <select id="interaction-type">
427
+ <option value="SequentialClassification">Sequential Classification</option>
428
+ <option value="SimultaneousAssociation">Simultaneous Association</option>
429
+ <option value="OpenClassification">Open Classification</option>
430
+ <option value="RankOrder">Rank Order</option>
431
+ <option value="ListRecall">List Recall</option>
432
+ <option value="MCQ" selected>MCQ/MRQ</option>
433
+ </select>
434
+ </div>
435
+
436
+ <div class="form-group">
437
+ <label for="interaction-heading">Heading</label>
438
+ <input type="text" id="interaction-heading" value="Butterfly Life Cycle" placeholder="Enter heading...">
439
+ </div>
440
+
441
+ <div class="form-group">
442
+ <label for="interaction-timer">Timer (seconds)</label>
443
+ <input type="number" id="interaction-timer" value="120" min="0" placeholder="0 for no timer">
444
+ </div>
445
+
446
+ <div class="form-group">
447
+ <label for="data-json">Data (JSON)</label>
448
+ <textarea id="data-json" placeholder="Enter JSON data...">{
449
+ "type": "seriation",
450
+ "items": ["Egg", "Caterpillar", "Chrysalis", "Butterfly", "@:butterfly"]
451
+ }</textarea>
452
+ <div class="form-help">Must be valid JSON format</div>
453
+ </div>
454
+
455
+ <div class="form-group">
456
+ <label for="assets-yaml">Assets (YAML)</label>
457
+ <textarea id="assets-yaml" placeholder="Enter YAML assets...">butterfly:
458
+ type: image
459
+ url: https://images.unsplash.com/photo-1533048324814-79b0a31982f1?q=80&w=768</textarea>
460
+ <div class="form-help">Optional. Leave empty if no assets needed</div>
461
+ </div>
462
+ </div>
463
+ <div class="modal-footer">
464
+ <button class="btn" id="config-cancel">Cancel</button>
465
+ <button class="btn btn-primary" id="config-apply">Render Interaction</button>
466
+ </div>
467
+ </div>
468
+ </div>
469
+
470
+ <script type="module">
471
+ import {
472
+ OpenClassification,
473
+ SequentialClassification,
474
+ SimultaneousAssociation,
475
+ RankOrder,
476
+ ListRecall,
477
+ MCQ,
478
+ parseYamlAssets,
479
+ validateAndNormalizeAssets
480
+ } from './app.js';
481
+
482
+ // State
483
+ let currentVariant = 'elegant';
484
+ let currentInteraction = null;
485
+
486
+ // DOM Elements
487
+ const viewport = document.getElementById('interaction-viewport');
488
+ const settingsBtn = document.getElementById('settings-btn');
489
+ const configBtn = document.getElementById('config-btn');
490
+ const fullscreenBtn = document.getElementById('fullscreen-btn');
491
+ const settingsModal = document.getElementById('settings-modal');
492
+ const configModal = document.getElementById('config-modal');
493
+
494
+ // Modal Controls
495
+ const settingsClose = document.getElementById('settings-close');
496
+ const settingsCancel = document.getElementById('settings-cancel');
497
+ const settingsApply = document.getElementById('settings-apply');
498
+ const configClose = document.getElementById('config-close');
499
+ const configCancel = document.getElementById('config-cancel');
500
+ const configApply = document.getElementById('config-apply');
501
+
502
+ // Form Elements
503
+ const variantSelect = document.getElementById('variant-select');
504
+ const accentColor = document.getElementById('accent-color');
505
+ const interactionType = document.getElementById('interaction-type');
506
+ const interactionHeading = document.getElementById('interaction-heading');
507
+ const interactionTimer = document.getElementById('interaction-timer');
508
+ const dataJson = document.getElementById('data-json');
509
+ const assetsYaml = document.getElementById('assets-yaml');
510
+
511
+ // Modal Management
512
+ function openModal(modal) {
513
+ modal.classList.add('active');
514
+ }
515
+
516
+ function closeModal(modal) {
517
+ modal.classList.remove('active');
518
+ }
519
+
520
+ accentColor.addEventListener('change', (e) => {
521
+ const color = e.target.value;
522
+ // Convert hex to RGB
523
+ const r = parseInt(color.substr(1, 2), 16);
524
+ const g = parseInt(color.substr(3, 2), 16);
525
+ const b = parseInt(color.substr(5, 2), 16);
526
+ document.documentElement.style.setProperty('--edu-first-accent', `${r} ${g} ${b}`);
527
+ });
528
+
529
+ // Event Listeners - Modal Toggles
530
+ settingsBtn.addEventListener('click', () => openModal(settingsModal));
531
+ configBtn.addEventListener('click', () => openModal(configModal));
532
+
533
+ settingsClose.addEventListener('click', () => closeModal(settingsModal));
534
+ settingsCancel.addEventListener('click', () => closeModal(settingsModal));
535
+
536
+ configClose.addEventListener('click', () => closeModal(configModal));
537
+ configCancel.addEventListener('click', () => closeModal(configModal));
538
+
539
+ // Close modal on overlay click
540
+ settingsModal.addEventListener('click', (e) => {
541
+ if (e.target === settingsModal) closeModal(settingsModal);
542
+ });
543
+ configModal.addEventListener('click', (e) => {
544
+ if (e.target === configModal) closeModal(configModal);
545
+ });
546
+
547
+ // Settings Apply
548
+ settingsApply.addEventListener('click', () => {
549
+ currentVariant = variantSelect.value;
550
+ if (viewport) {
551
+ currentInteraction.onVariantChange(currentVariant);
552
+ viewport.setAttribute('variant', currentVariant);
553
+ }
554
+ closeModal(settingsModal);
555
+ });
556
+
557
+ // Fullscreen Toggle
558
+ fullscreenBtn.addEventListener('click', () => {
559
+ document.body.classList.toggle('fullscreen');
560
+ fullscreenBtn.textContent = document.body.classList.contains('fullscreen') ? '⛶' : '⛶';
561
+ });
562
+
563
+ // Interaction Type Data Templates
564
+ const dataTemplates = {
565
+ SequentialClassification: {
566
+ data: {
567
+ type: 'classification',
568
+ categories: [
569
+ { label: 'Ocean', items: ['Dolphin', 'Shark', 'Octopus'] },
570
+ { label: 'Land', items: ['Lion', 'Elephant', 'Tiger'] },
571
+ { label: 'Air', items: ['Eagle', 'Parrot', 'Hawk'] }
572
+ ]
573
+ },
574
+ assets: ''
575
+ },
576
+ SimultaneousAssociation: {
577
+ data: {
578
+ type: 'association',
579
+ pairs: [
580
+ { left: 'Dog', right: 'Barks' },
581
+ { left: 'Cat', right: 'Meows' },
582
+ { left: 'Bird', right: 'Chirps' },
583
+ { left: '@:cow', right: 'Moos' },
584
+ { left: 'Lion', right: 'Roars' }
585
+ ],
586
+ distractors: ['quacks', 'oinks']
587
+ },
588
+ assets: 'cow:\n type: image\n url: https://images.unsplash.com/photo-1595365691689-6b7b4e1970cf?q=80&w=765&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
589
+ },
590
+ OpenClassification: {
591
+ data: {
592
+ type: 'classification',
593
+ categories: [
594
+ { label: 'Mammals', items: ['Dog', 'Cat', 'Elephant', 'wolf'] },
595
+ { label: 'Birds', items: ['Eagle', 'Sparrow'] }
596
+ ],
597
+ distractors: ['Rock', 'Cloud']
598
+ },
599
+ assets: ''
600
+ },
601
+ RankOrder: {
602
+ data: {
603
+ type: 'seriation',
604
+ items: ['Bronze Age', 'Iron Age', 'Middle Ages', 'Renaissance', 'Industrial Revolution', 'Information Age']
605
+ },
606
+ assets: ''
607
+ },
608
+ ListRecall: {
609
+ data: {
610
+ type: 'seriation',
611
+ items: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
612
+ },
613
+ assets: ''
614
+ },
615
+ MCQ: {
616
+ data: {
617
+ type: 'recognition',
618
+ data: [
619
+ {
620
+ question: '@:paris',
621
+ correctOptions: ['Paris'],
622
+ options: ['Paris', 'London', 'Berlin', 'Madrid']
623
+ },
624
+ {
625
+ question: 'Which of these are programming languages?',
626
+ correctOptions: ['Python', 'JavaScript', 'Java'],
627
+ options: ['Python', 'JavaScript', 'Java', 'HTML', 'CSS']
628
+ },
629
+ {
630
+ question: '@:exampleHtml',
631
+ correctOptions: ['4'],
632
+ options: ['3', '4', '5', '6']
633
+ },
634
+ {
635
+ question: '@:ocean',
636
+ correctOptions: ['Ocean'],
637
+ options: ['Volcano', 'Desert', 'Forest', 'Ocean']
638
+ },
639
+ {
640
+ question: '@:laugh',
641
+ correctOptions: ["laughing"],
642
+ options: ['Crying', 'Shouting', 'Laughing']
643
+ }
644
+ ]
645
+ },
646
+ assets:
647
+ `
648
+ paris:\n type: image\n url: https://plus.unsplash.com/premium_photo-1718035557075-5111d9d906d2?q=80&w=1171&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D\n dialog: true
649
+ exampleHtml:
650
+ type: html
651
+ content: <div style="padding:1rem;"><h3>Rich HTML Question</h3><p>What is <strong>2 + 2</strong>?</p><ul><li>Addition</li><li>Basic math</li></ul></div>
652
+ dialog: true
653
+
654
+ ocean:\n type: video\n url: https://www.pexels.com/download/video/6548176\n dialog: false
655
+
656
+ laugh:\n type: audio\n url: https://www.soundjay.com/human/sounds/man-laughing-01.mp3\n dialog: true
657
+ `
658
+ }
659
+ };
660
+
661
+ dataJson.value = JSON.stringify(dataTemplates[interactionType.value].data);
662
+ assetsYaml.value = dataTemplates[interactionType.value].assets;
663
+
664
+ // Update form when interaction type changes
665
+ interactionType.addEventListener('change', (e) => {
666
+ const template = dataTemplates[e.target.value];
667
+ if (template) {
668
+ // Convert Map to object for JSON serialization
669
+ let dataToSerialize = template.data;
670
+ if (template.data.answerKey instanceof Map) {
671
+ dataToSerialize = {
672
+ ...template.data,
673
+ answerKey: Object.fromEntries(template.data.answerKey)
674
+ };
675
+ }
676
+ dataJson.value = JSON.stringify(dataToSerialize, null, 2);
677
+ assetsYaml.value = template.assets;
678
+ }
679
+ });
680
+
681
+ // Render Interaction
682
+ configApply.addEventListener('click', () => {
683
+ try {
684
+ let data = JSON.parse(dataJson.value);
685
+
686
+ if (data.answerKey && typeof data.answerKey === 'object') {
687
+ data.answerKey = new Map(Object.entries(data.answerKey));
688
+ }
689
+
690
+ let assets = null;
691
+ const yamlContent = assetsYaml.value.trim();
692
+ if (yamlContent) {
693
+ const parsedAssets = parseYamlAssets(yamlContent);
694
+ assets = validateAndNormalizeAssets(parsedAssets);
695
+ }
696
+
697
+ const config = {
698
+ variant: currentVariant,
699
+ shuffle: true,
700
+ animationsEnabled: true,
701
+ prompt: "Complete the quizz",
702
+ promptData: "https://plus.unsplash.com/premium_photo-1718035557075-5111d9d906d2?q=80&w=1171&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
703
+ promptModality: 'image',
704
+ timer: 60,
705
+ attemptLimit: 2
706
+ };
707
+
708
+ const type = interactionType.value;
709
+ let interaction;
710
+
711
+ switch (type) {
712
+ case 'SequentialClassification':
713
+ interaction = new SequentialClassification(data, config, assets);
714
+ break;
715
+ case 'SimultaneousAssociation':
716
+ interaction = new SimultaneousAssociation(data, config, assets);
717
+ break;
718
+ case 'OpenClassification':
719
+ interaction = new OpenClassification(data, config, assets);
720
+ break;
721
+ case 'RankOrder':
722
+ interaction = new RankOrder(data, config, assets);
723
+ break;
724
+ case 'ListRecall':
725
+ interaction = new ListRecall(data, config, assets);
726
+ break;
727
+ case 'MCQ':
728
+ interaction = new MCQ(data, config, assets);
729
+ break;
730
+ default:
731
+ throw new Error('Unknown interaction type');
732
+ }
733
+
734
+ // Clear any previous state and set up new interaction
735
+ // The shell now reads everything from interaction.config
736
+ viewport.setInteraction(interaction);
737
+
738
+ currentInteraction = interaction;
739
+ closeModal(configModal);
740
+
741
+ console.log('✅ Interaction rendered successfully');
742
+ } catch (error) {
743
+ console.error('❌ Error rendering interaction:', error);
744
+ alert('Error: ' + error.message);
745
+ }
746
+ });
747
+
748
+ // Initialize with default interaction
749
+ window.addEventListener('DOMContentLoaded', () => {
750
+ configApply.click();
751
+ });
752
+ </script>
753
+ </body>
754
+ </html>