@vue-skuilder/platform-ui 0.1.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 (108) hide show
  1. package/LICENCE +661 -0
  2. package/README.md +64 -0
  3. package/dist/assets/Roboto-Black-B0ZKieaB.woff +0 -0
  4. package/dist/assets/Roboto-Black-VhoA2qKx.woff2 +0 -0
  5. package/dist/assets/Roboto-BlackItalic-D0gSnuIb.woff +0 -0
  6. package/dist/assets/Roboto-BlackItalic-D4yie1YO.woff2 +0 -0
  7. package/dist/assets/Roboto-Bold-D9plYbeK.woff +0 -0
  8. package/dist/assets/Roboto-Bold-hN3duQhD.woff2 +0 -0
  9. package/dist/assets/Roboto-BoldItalic-BWDm51uc.woff2 +0 -0
  10. package/dist/assets/Roboto-BoldItalic-CyLKvOHD.woff +0 -0
  11. package/dist/assets/Roboto-Light-Cu-PAxXt.woff +0 -0
  12. package/dist/assets/Roboto-Light-DHTugVNA.woff2 +0 -0
  13. package/dist/assets/Roboto-LightItalic-CZg5kHIB.woff +0 -0
  14. package/dist/assets/Roboto-LightItalic-JQyp2Y3P.woff2 +0 -0
  15. package/dist/assets/Roboto-Medium-ByKogCTi.woff2 +0 -0
  16. package/dist/assets/Roboto-Medium-b81vv18W.woff +0 -0
  17. package/dist/assets/Roboto-MediumItalic-DFQ-RYa0.woff +0 -0
  18. package/dist/assets/Roboto-MediumItalic-i1eR0KbF.woff2 +0 -0
  19. package/dist/assets/Roboto-Regular-BX5l9hRW.woff +0 -0
  20. package/dist/assets/Roboto-Regular-C6rbFxYz.woff2 +0 -0
  21. package/dist/assets/Roboto-RegularItalic-BjnLZsam.woff +0 -0
  22. package/dist/assets/Roboto-RegularItalic-CvPUdkvM.woff2 +0 -0
  23. package/dist/assets/Roboto-Thin-BfJvJcog.woff +0 -0
  24. package/dist/assets/Roboto-Thin-NicBC1pN.woff2 +0 -0
  25. package/dist/assets/Roboto-ThinItalic-CKlCjrO_.woff2 +0 -0
  26. package/dist/assets/Roboto-ThinItalic-DnIWFxRE.woff +0 -0
  27. package/dist/assets/index-CQ-sNKGW.css +14 -0
  28. package/dist/assets/index-EbqpUgvM.js +161 -0
  29. package/dist/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
  30. package/dist/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
  31. package/dist/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
  32. package/dist/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
  33. package/dist/assets/workbox-window.prod.es5-p40uij6f.js +1 -0
  34. package/dist/favicon.ico +0 -0
  35. package/dist/img/icons/safari-pinned-tab.svg +149 -0
  36. package/dist/index.html +19 -0
  37. package/dist/manifest.json +20 -0
  38. package/dist/manifest.webmanifest +1 -0
  39. package/dist/robots.txt +2 -0
  40. package/dist/sw.js +1 -0
  41. package/dist/workbox-1be04862.js +1 -0
  42. package/package.json +105 -0
  43. package/src/App.vue +156 -0
  44. package/src/ENVIRONMENT_VARS.ts +79 -0
  45. package/src/components/Classrooms/ClassroomCtrlPanel.vue +206 -0
  46. package/src/components/Classrooms/CreateClassroom.vue +159 -0
  47. package/src/components/Classrooms/JoinCode.vue +83 -0
  48. package/src/components/Courses/CourseCardBrowser.vue +365 -0
  49. package/src/components/Courses/CourseEditor.vue +164 -0
  50. package/src/components/Courses/CourseInformation.vue +164 -0
  51. package/src/components/Courses/CourseRouter.vue +116 -0
  52. package/src/components/Courses/CourseStubCard.vue +76 -0
  53. package/src/components/Courses/EloModeration.vue +122 -0
  54. package/src/components/Courses/TagInformation.vue +209 -0
  55. package/src/components/Edit/BulkImport/CardPreviewList.vue +345 -0
  56. package/src/components/Edit/BulkImportView.vue +633 -0
  57. package/src/components/Edit/CardBrowser.vue +79 -0
  58. package/src/components/Edit/ComponentRegistration/ComponentRegistration.vue +235 -0
  59. package/src/components/Edit/ComponentRegistration/UnregisteredComponentsTable.vue +19 -0
  60. package/src/components/Edit/CourseEditor.vue +162 -0
  61. package/src/components/Edit/NavigationStrategy/NavigationStrategyEditor.vue +170 -0
  62. package/src/components/Edit/NavigationStrategy/NavigationStrategyList.vue +92 -0
  63. package/src/components/Edit/TagsInput.vue +247 -0
  64. package/src/components/Edit/ViewableDataInputForm/DataInputForm.vue +524 -0
  65. package/src/components/Edit/ViewableDataInputForm/FieldInput.types.ts +33 -0
  66. package/src/components/Edit/ViewableDataInputForm/FieldInputs/AudioInput.vue +188 -0
  67. package/src/components/Edit/ViewableDataInputForm/FieldInputs/ChessPuzzleInput.vue +79 -0
  68. package/src/components/Edit/ViewableDataInputForm/FieldInputs/FieldInput.css +12 -0
  69. package/src/components/Edit/ViewableDataInputForm/FieldInputs/ImageInput.vue +231 -0
  70. package/src/components/Edit/ViewableDataInputForm/FieldInputs/IntegerInput.vue +49 -0
  71. package/src/components/Edit/ViewableDataInputForm/FieldInputs/MarkdownInput.vue +34 -0
  72. package/src/components/Edit/ViewableDataInputForm/FieldInputs/MediaDragDropUploader.vue +246 -0
  73. package/src/components/Edit/ViewableDataInputForm/FieldInputs/MidiInput.vue +113 -0
  74. package/src/components/Edit/ViewableDataInputForm/FieldInputs/NumberInput.vue +49 -0
  75. package/src/components/Edit/ViewableDataInputForm/FieldInputs/StringInput.vue +49 -0
  76. package/src/components/Edit/ViewableDataInputForm/FieldInputs/typeValidators.ts +49 -0
  77. package/src/components/Edit/ViewableDataInputForm/OptionsFieldInput.ts +161 -0
  78. package/src/components/Study/SessionConfiguration.vue +371 -0
  79. package/src/components/TextSwap.vue +65 -0
  80. package/src/components/User/UserStats.vue +30 -0
  81. package/src/dev/DataInputFormTester.vue +117 -0
  82. package/src/dev/readme.md +3 -0
  83. package/src/enums.ts +0 -0
  84. package/src/glyphs.txt +933 -0
  85. package/src/main.ts +45 -0
  86. package/src/plugins/vuetify.ts +41 -0
  87. package/src/registerServiceWorker.ts +18 -0
  88. package/src/router.ts +184 -0
  89. package/src/server/index.spec.ts +192 -0
  90. package/src/server/index.ts +71 -0
  91. package/src/shims-vue.d.ts +5 -0
  92. package/src/store.mock.ts +122 -0
  93. package/src/stores/useDataInputFormStore.ts +49 -0
  94. package/src/stores/useFieldInputStore.ts +191 -0
  95. package/src/types/shims-vuetify.d.ts +12 -0
  96. package/src/types/svg.d.ts +4 -0
  97. package/src/utils/bulkImport/index.ts +94 -0
  98. package/src/views/About.vue +29 -0
  99. package/src/views/Admin.vue +128 -0
  100. package/src/views/Classrooms.vue +258 -0
  101. package/src/views/Courses.vue +265 -0
  102. package/src/views/Home.vue +154 -0
  103. package/src/views/Login.vue +75 -0
  104. package/src/views/ReleaseNotes.vue +20 -0
  105. package/src/views/SignUp.vue +32 -0
  106. package/src/views/Study.vue +261 -0
  107. package/src/views/User.vue +109 -0
  108. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,345 @@
1
+ <template>
2
+ <div class="card-preview-list">
3
+ <!-- Delete Confirmation Dialog -->
4
+ <v-dialog v-model="showDeleteConfirm" max-width="400px">
5
+ <v-card>
6
+ <v-card-title class="text-h5">Remove Card</v-card-title>
7
+ <v-card-text>
8
+ <p>Are you sure you want to remove this card?</p>
9
+ <v-checkbox v-model="dontAskAgain" label="Don't ask me again" hide-details class="mt-2"></v-checkbox>
10
+ </v-card-text>
11
+ <v-card-actions>
12
+ <v-spacer></v-spacer>
13
+ <v-btn color="grey-darken-1" variant="text" @click="cancelDelete">Cancel</v-btn>
14
+ <v-btn color="error" @click="confirmDelete">Remove</v-btn>
15
+ </v-card-actions>
16
+ </v-card>
17
+ </v-dialog>
18
+
19
+ <v-card v-if="parsedCards.length > 0" class="mb-4">
20
+ <v-card-title class="d-flex align-center justify-space-between">
21
+ <span>Card Preview</span>
22
+ <div class="d-flex align-center">
23
+ <div class="text-subtitle-1 mr-2">{{ currentIndex + 1 }} of {{ parsedCards.length }}</div>
24
+ <sk-mouse-trap />
25
+ </div>
26
+ </v-card-title>
27
+
28
+ <v-card-text>
29
+ <div v-if="loading" class="d-flex justify-center align-center my-4">
30
+ <v-progress-circular indeterminate color="primary"></v-progress-circular>
31
+ </div>
32
+ <div v-else>
33
+ <div v-if="currentCard">
34
+ <v-sheet class="card-content pa-4 mb-4" rounded border>
35
+ <!-- Rendered card content -->
36
+ <div v-if="viewComponents && viewComponents.length > 0">
37
+ <card-browser :views="viewComponents" :data="[currentViewData]" :suppress-spinner="true" />
38
+ </div>
39
+ <!-- Fallback markdown display when no view components are available -->
40
+ <div v-else>
41
+ <div class="mb-2 font-weight-bold">Card content:</div>
42
+ <div class="markdown-content">{{ currentCard.markdown }}</div>
43
+ </div>
44
+ </v-sheet>
45
+
46
+ <div class="card-metadata mt-2">
47
+ <div class="d-flex flex-wrap gap-1">
48
+ <v-chip
49
+ v-for="tag in currentCard.tags"
50
+ :key="tag"
51
+ size="small"
52
+ color="primary"
53
+ variant="outlined"
54
+ class="mr-1 mb-1"
55
+ >
56
+ {{ tag }}
57
+ </v-chip>
58
+ </div>
59
+ <div v-if="currentCard.elo !== undefined" class="mt-2 text-caption">ELO: {{ currentCard.elo }}</div>
60
+ </div>
61
+ </div>
62
+ <div v-else class="text-center pa-4">No card selected or available to preview.</div>
63
+ </div>
64
+ </v-card-text>
65
+
66
+ <v-card-actions class="px-4 pb-4">
67
+ <v-btn variant="outlined" icon :disabled="currentIndex === 0 || loading" @click="prevCard">
68
+ <v-icon>mdi-chevron-left</v-icon>
69
+ </v-btn>
70
+
71
+ <v-spacer></v-spacer>
72
+
73
+ <v-btn
74
+ variant="tonal"
75
+ color="error"
76
+ prepend-icon="mdi-delete"
77
+ class="mx-2"
78
+ :disabled="!currentCard || loading"
79
+ @click="promptDelete"
80
+ >
81
+ Remove
82
+ </v-btn>
83
+
84
+ <v-btn
85
+ variant="tonal"
86
+ color="primary"
87
+ prepend-icon="mdi-pencil"
88
+ class="mx-2"
89
+ :disabled="!currentCard || loading"
90
+ @click="editCurrentCard"
91
+ >
92
+ Edit
93
+ </v-btn>
94
+
95
+ <v-spacer></v-spacer>
96
+
97
+ <v-btn variant="outlined" icon :disabled="currentIndex >= parsedCards.length - 1 || loading" @click="nextCard">
98
+ <v-icon>mdi-chevron-right</v-icon>
99
+ </v-btn>
100
+ </v-card-actions>
101
+ </v-card>
102
+ </div>
103
+ </template>
104
+
105
+ <script lang="ts">
106
+ import { ViewComponent, SkldrMouseTrap, HotKey, SkMouseTrap } from '@vue-skuilder/common-ui';
107
+ import { DataShape, ParsedCard, ViewData } from '@vue-skuilder/common';
108
+ import { defineComponent, PropType } from 'vue';
109
+ import CardBrowser from '../CardBrowser.vue';
110
+
111
+ export default defineComponent({
112
+ name: 'CardPreviewList',
113
+
114
+ components: {
115
+ CardBrowser,
116
+ SkMouseTrap,
117
+ },
118
+
119
+ props: {
120
+ parsedCards: {
121
+ type: Array as PropType<ParsedCard[]>,
122
+ required: true,
123
+ default: () => [],
124
+ },
125
+ dataShape: {
126
+ type: Object as PropType<DataShape>,
127
+ required: true,
128
+ },
129
+ viewComponents: {
130
+ type: Array as PropType<ViewComponent[]>,
131
+ required: false,
132
+ default: () => [],
133
+ },
134
+ },
135
+
136
+ emits: ['update:parsedCards', 'edit-card', 'delete-card'],
137
+
138
+ data() {
139
+ return {
140
+ currentIndex: 0,
141
+ loading: false,
142
+ keyBindings: [] as HotKey[],
143
+ showDeleteConfirm: false,
144
+ dontAskAgain: false,
145
+ skipDeleteConfirmation: false,
146
+ shortcutsEnabled: true,
147
+ };
148
+ },
149
+
150
+ computed: {
151
+ currentCard(): ParsedCard | null {
152
+ if (this.parsedCards.length === 0 || this.currentIndex >= this.parsedCards.length) {
153
+ return null;
154
+ }
155
+ return this.parsedCards[this.currentIndex];
156
+ },
157
+
158
+ currentViewData(): ViewData {
159
+ if (!this.currentCard) {
160
+ return { Input: '' };
161
+ }
162
+
163
+ // Convert ParsedCard to ViewData
164
+ return {
165
+ Input: this.currentCard.markdown,
166
+ // Any additional fields the view might need
167
+ };
168
+ },
169
+ },
170
+
171
+ mounted() {
172
+ this.setupKeyBindings();
173
+ },
174
+
175
+ beforeUnmount() {
176
+ // Clean up key bindings when component is unmounted
177
+ if (this.shortcutsEnabled) {
178
+ this.keyBindings.forEach(kb => {
179
+ SkldrMouseTrap.removeBinding(kb.hotkey);
180
+ });
181
+ }
182
+ },
183
+
184
+ methods: {
185
+ nextCard() {
186
+ if (this.currentIndex < this.parsedCards.length - 1) {
187
+ this.currentIndex++;
188
+ }
189
+ },
190
+
191
+ prevCard() {
192
+ if (this.currentIndex > 0) {
193
+ this.currentIndex--;
194
+ }
195
+ },
196
+
197
+ showCard(index: number) {
198
+ if (index >= 0 && index < this.parsedCards.length) {
199
+ this.currentIndex = index;
200
+ }
201
+ },
202
+
203
+ setupKeyBindings() {
204
+ // Define key bindings for navigation
205
+ this.keyBindings = [
206
+ {
207
+ command: 'Previous Card',
208
+ hotkey: 'left',
209
+ callback: () => {
210
+ this.prevCard();
211
+ return false; // Prevent default
212
+ },
213
+ },
214
+ {
215
+ command: 'Next Card',
216
+ hotkey: 'right',
217
+ callback: () => {
218
+ this.nextCard();
219
+ return false; // Prevent default
220
+ },
221
+ },
222
+ {
223
+ command: 'Delete Card',
224
+ hotkey: 'del',
225
+ callback: () => {
226
+ this.promptDelete();
227
+ return false; // Prevent default
228
+ },
229
+ },
230
+ {
231
+ command: 'Edit Card',
232
+ hotkey: 'e',
233
+ callback: () => {
234
+ this.editCurrentCard();
235
+ return false; // Prevent default
236
+ },
237
+ },
238
+ ];
239
+
240
+ if (this.shortcutsEnabled) {
241
+ // Register keyboard shortcuts
242
+ SkldrMouseTrap.addBinding(this.keyBindings);
243
+ }
244
+ },
245
+
246
+ enableShortcuts() {
247
+ if (!this.shortcutsEnabled) {
248
+ this.shortcutsEnabled = true;
249
+ SkldrMouseTrap.addBinding(this.keyBindings);
250
+ console.log('[CardPreviewList] Keyboard shortcuts enabled');
251
+ }
252
+ },
253
+
254
+ disableShortcuts() {
255
+ if (this.shortcutsEnabled) {
256
+ this.shortcutsEnabled = false;
257
+ // Remove all registered key bindings
258
+ this.keyBindings.forEach(kb => {
259
+ SkldrMouseTrap.removeBinding(kb.hotkey);
260
+ });
261
+ console.log('[CardPreviewList] Keyboard shortcuts disabled');
262
+ }
263
+ },
264
+
265
+ toggleShortcuts(enable: boolean) {
266
+ if (enable) {
267
+ this.enableShortcuts();
268
+ } else {
269
+ this.disableShortcuts();
270
+ }
271
+ },
272
+
273
+ promptDelete() {
274
+ if (!this.currentCard) return;
275
+
276
+ if (this.skipDeleteConfirmation) {
277
+ this.deleteCurrentCard();
278
+ } else {
279
+ this.showDeleteConfirm = true;
280
+ }
281
+ },
282
+
283
+ cancelDelete() {
284
+ this.showDeleteConfirm = false;
285
+ },
286
+
287
+ confirmDelete() {
288
+ if (this.dontAskAgain) {
289
+ this.skipDeleteConfirmation = true;
290
+ }
291
+
292
+ this.showDeleteConfirm = false;
293
+ this.deleteCurrentCard();
294
+ },
295
+
296
+ deleteCurrentCard() {
297
+ if (!this.currentCard) return;
298
+
299
+ // Create a new array without the current card
300
+ const updatedCards = [...this.parsedCards];
301
+ updatedCards.splice(this.currentIndex, 1);
302
+
303
+ // Emit event with updated array
304
+ this.$emit('update:parsedCards', updatedCards);
305
+
306
+ // Also emit a specific event for parent component to handle
307
+ this.$emit('delete-card', this.currentIndex);
308
+
309
+ // Adjust current index if needed
310
+ if (this.currentIndex >= updatedCards.length && updatedCards.length > 0) {
311
+ this.currentIndex = updatedCards.length - 1;
312
+ }
313
+ },
314
+
315
+ editCurrentCard() {
316
+ if (!this.currentCard) return;
317
+
318
+ // Emit event with current card and index
319
+ this.$emit('edit-card', this.currentCard, this.currentIndex);
320
+ },
321
+ },
322
+ });
323
+ </script>
324
+
325
+ <style scoped>
326
+ .card-preview-list {
327
+ width: 100%;
328
+ }
329
+
330
+ .card-content {
331
+ min-height: 150px;
332
+ background-color: #f8f9fa;
333
+ }
334
+
335
+ .markdown-content {
336
+ white-space: pre-wrap;
337
+ word-break: break-word;
338
+ line-height: 1.5;
339
+ font-family: var(--v-font-family);
340
+ }
341
+
342
+ .gap-1 {
343
+ gap: 4px;
344
+ }
345
+ </style>