tessera-learn 0.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.
Files changed (71) hide show
  1. package/AGENTS.md +1228 -0
  2. package/LICENSE +21 -0
  3. package/README.md +21 -0
  4. package/dist/plugin/index.d.ts +7 -0
  5. package/dist/plugin/index.d.ts.map +1 -0
  6. package/dist/plugin/index.js +1239 -0
  7. package/dist/plugin/index.js.map +1 -0
  8. package/package.json +77 -0
  9. package/src/archiver.d.ts +27 -0
  10. package/src/components/Accordion.svelte +32 -0
  11. package/src/components/AccordionItem.svelte +144 -0
  12. package/src/components/Audio.svelte +38 -0
  13. package/src/components/Callout.svelte +81 -0
  14. package/src/components/Carousel.svelte +194 -0
  15. package/src/components/CarouselSlide.svelte +32 -0
  16. package/src/components/DefaultLayout.svelte +108 -0
  17. package/src/components/FillInTheBlank.svelte +345 -0
  18. package/src/components/Image.svelte +47 -0
  19. package/src/components/Matching.svelte +513 -0
  20. package/src/components/MultipleChoice.svelte +363 -0
  21. package/src/components/Quiz.svelte +569 -0
  22. package/src/components/RevealModal.svelte +228 -0
  23. package/src/components/Sorting.svelte +663 -0
  24. package/src/components/Video.svelte +118 -0
  25. package/src/components/index.ts +15 -0
  26. package/src/components/quiz-payload.ts +71 -0
  27. package/src/components/util.ts +24 -0
  28. package/src/index.ts +56 -0
  29. package/src/plugin/export.ts +264 -0
  30. package/src/plugin/index.ts +464 -0
  31. package/src/plugin/layout.ts +55 -0
  32. package/src/plugin/manifest.ts +330 -0
  33. package/src/plugin/quiz.ts +65 -0
  34. package/src/plugin/validation.ts +838 -0
  35. package/src/runtime/App.svelte +435 -0
  36. package/src/runtime/ErrorPage.svelte +14 -0
  37. package/src/runtime/LoadingSkeleton.svelte +26 -0
  38. package/src/runtime/Sidebar.svelte +76 -0
  39. package/src/runtime/access.ts +55 -0
  40. package/src/runtime/adapters/cmi5.ts +341 -0
  41. package/src/runtime/adapters/discovery.ts +38 -0
  42. package/src/runtime/adapters/index.ts +99 -0
  43. package/src/runtime/adapters/retry.ts +284 -0
  44. package/src/runtime/adapters/scorm12.ts +172 -0
  45. package/src/runtime/adapters/scorm2004.ts +162 -0
  46. package/src/runtime/adapters/web.ts +62 -0
  47. package/src/runtime/contexts.ts +76 -0
  48. package/src/runtime/duration.ts +29 -0
  49. package/src/runtime/hooks.svelte.ts +543 -0
  50. package/src/runtime/interaction-format.ts +132 -0
  51. package/src/runtime/interaction.ts +96 -0
  52. package/src/runtime/navigation.svelte.ts +117 -0
  53. package/src/runtime/persistence.ts +56 -0
  54. package/src/runtime/progress.svelte.ts +168 -0
  55. package/src/runtime/quiz-policy.ts +227 -0
  56. package/src/runtime/slugify.ts +17 -0
  57. package/src/runtime/types.ts +92 -0
  58. package/src/runtime/xapi/agent-rules.ts +93 -0
  59. package/src/runtime/xapi/client.ts +133 -0
  60. package/src/runtime/xapi/derive-actor.ts +90 -0
  61. package/src/runtime/xapi/publisher.ts +604 -0
  62. package/src/runtime/xapi/registry.ts +38 -0
  63. package/src/runtime/xapi/setup.ts +250 -0
  64. package/src/runtime/xapi/types.ts +106 -0
  65. package/src/runtime/xapi/uuid.ts +21 -0
  66. package/src/runtime/xapi/validation.ts +71 -0
  67. package/src/runtime/xapi/version.ts +23 -0
  68. package/src/virtual.d.ts +16 -0
  69. package/styles/base.css +194 -0
  70. package/styles/layout.css +408 -0
  71. package/styles/theme.css +36 -0
@@ -0,0 +1,408 @@
1
+ /* ---- App Shell Grid ---- */
2
+ .tessera-app {
3
+ display: grid;
4
+ grid-template-columns: var(--tessera-sidebar-width) 1fr;
5
+ grid-template-rows: 1fr auto;
6
+ min-height: 100vh;
7
+ min-height: 100dvh;
8
+ }
9
+
10
+ /* ---- Sidebar ---- */
11
+ .tessera-sidebar {
12
+ grid-row: 1 / -1;
13
+ background-color: var(--tessera-bg-secondary);
14
+ border-right: 1px solid var(--tessera-border);
15
+ overflow-y: auto;
16
+ display: flex;
17
+ flex-direction: column;
18
+ height: 100vh;
19
+ height: 100dvh;
20
+ position: sticky;
21
+ top: 0;
22
+ }
23
+
24
+ .tessera-sidebar-header {
25
+ padding: var(--tessera-spacing-lg);
26
+ border-bottom: 1px solid var(--tessera-border);
27
+ flex-shrink: 0;
28
+ }
29
+
30
+ .tessera-sidebar-logo {
31
+ max-height: 48px;
32
+ width: auto;
33
+ margin-bottom: var(--tessera-spacing-sm);
34
+ }
35
+
36
+ .tessera-sidebar-title {
37
+ font-size: 1rem;
38
+ font-weight: 700;
39
+ color: var(--tessera-text);
40
+ margin: 0;
41
+ }
42
+
43
+ .tessera-sidebar-nav {
44
+ flex: 1;
45
+ overflow-y: auto;
46
+ padding: var(--tessera-spacing-md) 0;
47
+ }
48
+
49
+ /* Sidebar section */
50
+ .tessera-nav-section {
51
+ margin-bottom: var(--tessera-spacing-sm);
52
+ }
53
+
54
+ .tessera-nav-section-title {
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: space-between;
58
+ width: 100%;
59
+ padding: var(--tessera-spacing-sm) var(--tessera-spacing-lg);
60
+ font-size: 0.75rem;
61
+ font-weight: 600;
62
+ text-transform: uppercase;
63
+ letter-spacing: 0.05em;
64
+ color: var(--tessera-text-light);
65
+ background: none;
66
+ border: none;
67
+ cursor: pointer;
68
+ transition: color var(--tessera-transition-fast);
69
+ }
70
+
71
+ .tessera-nav-section-title:hover {
72
+ color: var(--tessera-text);
73
+ }
74
+
75
+ .tessera-nav-section-chevron {
76
+ width: 16px;
77
+ height: 16px;
78
+ transition: transform var(--tessera-transition-fast);
79
+ }
80
+
81
+ .tessera-nav-section-chevron.collapsed {
82
+ transform: rotate(-90deg);
83
+ }
84
+
85
+ /* Sidebar lesson */
86
+ .tessera-nav-lesson-title {
87
+ padding: var(--tessera-spacing-sm) var(--tessera-spacing-lg);
88
+ padding-left: calc(var(--tessera-spacing-lg) + var(--tessera-spacing-sm));
89
+ font-size: 0.8125rem;
90
+ font-weight: 600;
91
+ color: var(--tessera-text);
92
+ }
93
+
94
+ /* Sidebar page link */
95
+ .tessera-nav-page {
96
+ display: block;
97
+ width: 100%;
98
+ padding: 6px var(--tessera-spacing-lg);
99
+ padding-left: calc(var(--tessera-spacing-lg) + var(--tessera-spacing-xl));
100
+ font-size: 0.875rem;
101
+ color: var(--tessera-text-light);
102
+ text-decoration: none;
103
+ border: none;
104
+ background: none;
105
+ cursor: pointer;
106
+ text-align: left;
107
+ transition: background-color var(--tessera-transition-fast),
108
+ color var(--tessera-transition-fast);
109
+ border-left: 3px solid transparent;
110
+ }
111
+
112
+ .tessera-nav-page:hover {
113
+ background-color: var(--tessera-border);
114
+ color: var(--tessera-text);
115
+ }
116
+
117
+ .tessera-nav-page[aria-current="page"] {
118
+ background-color: var(--tessera-primary-light);
119
+ color: var(--tessera-primary-dark);
120
+ font-weight: 600;
121
+ border-left-color: var(--tessera-primary);
122
+ }
123
+
124
+ .tessera-nav-page[aria-disabled="true"] {
125
+ opacity: 0.45;
126
+ cursor: not-allowed;
127
+ }
128
+
129
+ .tessera-nav-page[aria-disabled="true"]:hover {
130
+ background-color: transparent;
131
+ color: var(--tessera-text-light);
132
+ }
133
+
134
+ .tessera-nav-lock-icon {
135
+ display: inline-block;
136
+ vertical-align: -1px;
137
+ margin-right: 4px;
138
+ opacity: 0.6;
139
+ }
140
+
141
+ /* ---- Content Area ---- */
142
+ .tessera-main {
143
+ display: flex;
144
+ flex-direction: column;
145
+ min-height: 0;
146
+ }
147
+
148
+ .tessera-content {
149
+ flex: 1;
150
+ width: 100%;
151
+ max-width: var(--tessera-content-max-width);
152
+ margin: 0 auto;
153
+ padding: var(--tessera-spacing-xl) var(--tessera-spacing-lg);
154
+ }
155
+
156
+ /* ---- Prev/Next Buttons ---- */
157
+ .tessera-page-nav {
158
+ display: flex;
159
+ justify-content: space-between;
160
+ align-items: center;
161
+ max-width: var(--tessera-content-max-width);
162
+ margin: 0 auto;
163
+ padding: var(--tessera-spacing-md) var(--tessera-spacing-lg);
164
+ border-top: 1px solid var(--tessera-border);
165
+ }
166
+
167
+ .tessera-page-nav-btn {
168
+ display: inline-flex;
169
+ align-items: center;
170
+ gap: var(--tessera-spacing-sm);
171
+ padding: var(--tessera-spacing-sm) var(--tessera-spacing-md);
172
+ font-size: 0.875rem;
173
+ font-weight: 600;
174
+ color: var(--tessera-primary);
175
+ background: none;
176
+ border: 1px solid var(--tessera-primary);
177
+ border-radius: 6px;
178
+ cursor: pointer;
179
+ transition: background-color var(--tessera-transition-fast),
180
+ color var(--tessera-transition-fast);
181
+ }
182
+
183
+ .tessera-page-nav-btn:hover:not(:disabled) {
184
+ background-color: var(--tessera-primary);
185
+ color: #ffffff;
186
+ }
187
+
188
+ .tessera-page-nav-btn:disabled {
189
+ opacity: 0.35;
190
+ cursor: not-allowed;
191
+ }
192
+
193
+ .tessera-page-nav-btn:focus-visible {
194
+ box-shadow: var(--tessera-focus-ring);
195
+ }
196
+
197
+ /* ---- Progress Bar ---- */
198
+ .tessera-progress {
199
+ position: sticky;
200
+ bottom: 0;
201
+ background-color: var(--tessera-bg);
202
+ border-top: 1px solid var(--tessera-border);
203
+ padding: var(--tessera-spacing-sm) var(--tessera-spacing-lg);
204
+ }
205
+
206
+ .tessera-progress-track {
207
+ width: 100%;
208
+ height: 4px;
209
+ background-color: var(--tessera-border);
210
+ border-radius: 2px;
211
+ overflow: hidden;
212
+ }
213
+
214
+ .tessera-progress-fill {
215
+ height: 100%;
216
+ background-color: var(--tessera-primary);
217
+ border-radius: 2px;
218
+ transition: width var(--tessera-transition-normal);
219
+ }
220
+
221
+ .tessera-progress-label {
222
+ font-size: 0.75rem;
223
+ color: var(--tessera-text-light);
224
+ margin-top: 4px;
225
+ text-align: right;
226
+ }
227
+
228
+ /* ---- Hamburger Button (mobile) ---- */
229
+ .tessera-hamburger {
230
+ display: none;
231
+ position: fixed;
232
+ top: var(--tessera-spacing-md);
233
+ left: var(--tessera-spacing-md);
234
+ z-index: 1001;
235
+ width: 44px;
236
+ height: 44px;
237
+ padding: 0;
238
+ background-color: var(--tessera-bg);
239
+ border: 1px solid var(--tessera-border);
240
+ border-radius: 8px;
241
+ cursor: pointer;
242
+ align-items: center;
243
+ justify-content: center;
244
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
245
+ }
246
+
247
+ .tessera-hamburger-line {
248
+ display: block;
249
+ width: 20px;
250
+ height: 2px;
251
+ background-color: var(--tessera-text);
252
+ border-radius: 1px;
253
+ transition: transform var(--tessera-transition-fast),
254
+ opacity var(--tessera-transition-fast);
255
+ }
256
+
257
+ .tessera-hamburger-lines {
258
+ display: flex;
259
+ flex-direction: column;
260
+ gap: 5px;
261
+ }
262
+
263
+ .tessera-hamburger[aria-expanded="true"] .tessera-hamburger-lines .tessera-hamburger-line:nth-child(1) {
264
+ transform: translateY(7px) rotate(45deg);
265
+ }
266
+
267
+ .tessera-hamburger[aria-expanded="true"] .tessera-hamburger-lines .tessera-hamburger-line:nth-child(2) {
268
+ opacity: 0;
269
+ }
270
+
271
+ .tessera-hamburger[aria-expanded="true"] .tessera-hamburger-lines .tessera-hamburger-line:nth-child(3) {
272
+ transform: translateY(-7px) rotate(-45deg);
273
+ }
274
+
275
+ /* ---- Sidebar Overlay (mobile) ---- */
276
+ .tessera-sidebar-overlay {
277
+ display: none;
278
+ position: fixed;
279
+ inset: 0;
280
+ background-color: rgba(0, 0, 0, 0.4);
281
+ z-index: 999;
282
+ }
283
+
284
+ /* ---- Loading Skeleton ---- */
285
+ .tessera-skeleton {
286
+ display: flex;
287
+ flex-direction: column;
288
+ gap: var(--tessera-spacing-md);
289
+ padding: var(--tessera-spacing-md) 0;
290
+ }
291
+
292
+ .tessera-skeleton-line {
293
+ height: 16px;
294
+ background-color: var(--tessera-border);
295
+ border-radius: 4px;
296
+ animation: tessera-pulse 1.5s ease-in-out infinite;
297
+ }
298
+
299
+ .tessera-skeleton-line:nth-child(1) { width: 45%; height: 28px; }
300
+ .tessera-skeleton-line:nth-child(2) { width: 100%; }
301
+ .tessera-skeleton-line:nth-child(3) { width: 92%; }
302
+ .tessera-skeleton-line:nth-child(4) { width: 78%; }
303
+ .tessera-skeleton-line:nth-child(5) { width: 85%; }
304
+ .tessera-skeleton-line:nth-child(6) { width: 60%; }
305
+
306
+ @keyframes tessera-pulse {
307
+ 0%, 100% { opacity: 1; }
308
+ 50% { opacity: 0.4; }
309
+ }
310
+
311
+ .tessera-skeleton-message {
312
+ margin-top: var(--tessera-spacing-md);
313
+ font-size: 0.875rem;
314
+ color: var(--tessera-text-light);
315
+ text-align: center;
316
+ }
317
+
318
+ /* ---- Error Page ---- */
319
+ .tessera-error {
320
+ text-align: center;
321
+ padding: var(--tessera-spacing-xl) var(--tessera-spacing-md);
322
+ }
323
+
324
+ .tessera-error h2 {
325
+ color: var(--tessera-error);
326
+ margin-bottom: var(--tessera-spacing-md);
327
+ }
328
+
329
+ .tessera-error p {
330
+ color: var(--tessera-text-light);
331
+ margin-bottom: var(--tessera-spacing-lg);
332
+ }
333
+
334
+ .tessera-error-retry {
335
+ display: inline-flex;
336
+ align-items: center;
337
+ gap: var(--tessera-spacing-sm);
338
+ padding: var(--tessera-spacing-sm) var(--tessera-spacing-lg);
339
+ font-size: 0.875rem;
340
+ font-weight: 600;
341
+ color: #ffffff;
342
+ background-color: var(--tessera-primary);
343
+ border: none;
344
+ border-radius: 6px;
345
+ cursor: pointer;
346
+ transition: background-color var(--tessera-transition-fast);
347
+ }
348
+
349
+ .tessera-error-retry:hover {
350
+ background-color: var(--tessera-primary-dark);
351
+ }
352
+
353
+ /* ---- Responsive: Tablet (max-width: 1024px) ---- */
354
+ @media (max-width: 1024px) {
355
+ .tessera-app {
356
+ grid-template-columns: 1fr;
357
+ }
358
+
359
+ .tessera-sidebar {
360
+ position: fixed;
361
+ left: 0;
362
+ top: 0;
363
+ bottom: 0;
364
+ width: var(--tessera-sidebar-width);
365
+ z-index: 1000;
366
+ transform: translateX(-100%);
367
+ transition: transform var(--tessera-transition-normal);
368
+ }
369
+
370
+ .tessera-sidebar.open {
371
+ transform: translateX(0);
372
+ }
373
+
374
+ .tessera-sidebar-overlay.visible {
375
+ display: block;
376
+ }
377
+
378
+ .tessera-hamburger {
379
+ display: flex;
380
+ }
381
+
382
+ .tessera-content {
383
+ padding-top: calc(var(--tessera-spacing-xl) + 44px + var(--tessera-spacing-md));
384
+ }
385
+ }
386
+
387
+ /* ---- Responsive: Mobile (max-width: 640px) ---- */
388
+ @media (max-width: 640px) {
389
+ .tessera-content {
390
+ padding: var(--tessera-spacing-md);
391
+ padding-top: calc(var(--tessera-spacing-md) + 44px + var(--tessera-spacing-md));
392
+ }
393
+
394
+ .tessera-page-nav {
395
+ padding: var(--tessera-spacing-md);
396
+ }
397
+
398
+ .tessera-page-nav-btn {
399
+ flex: 1;
400
+ justify-content: center;
401
+ padding: var(--tessera-spacing-md);
402
+ font-size: 1rem;
403
+ }
404
+
405
+ h1 { font-size: 1.625rem; }
406
+ h2 { font-size: 1.375rem; }
407
+ h3 { font-size: 1.125rem; }
408
+ }
@@ -0,0 +1,36 @@
1
+ :root {
2
+ /* Colors */
3
+ --tessera-primary: #2563eb;
4
+ --tessera-primary-light: #dbeafe;
5
+ --tessera-primary-dark: #1e40af;
6
+ --tessera-text: #1f2937;
7
+ --tessera-text-light: #6b7280;
8
+ --tessera-bg: #ffffff;
9
+ --tessera-bg-secondary: #f9fafb;
10
+ --tessera-border: #e5e7eb;
11
+ --tessera-success: #16a34a;
12
+ --tessera-error: #dc2626;
13
+ --tessera-warning: #d97706;
14
+
15
+ /* Typography */
16
+ --tessera-font-family: 'Inter', system-ui, sans-serif;
17
+ --tessera-font-size-base: 1rem;
18
+ --tessera-line-height: 1.6;
19
+
20
+ /* Spacing */
21
+ --tessera-spacing-sm: 0.5rem;
22
+ --tessera-spacing-md: 1rem;
23
+ --tessera-spacing-lg: 1.5rem;
24
+ --tessera-spacing-xl: 2rem;
25
+
26
+ /* Layout */
27
+ --tessera-sidebar-width: 280px;
28
+ --tessera-content-max-width: 800px;
29
+
30
+ /* Focus */
31
+ --tessera-focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.4);
32
+
33
+ /* Transitions */
34
+ --tessera-transition-fast: 150ms ease;
35
+ --tessera-transition-normal: 250ms ease;
36
+ }