@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,247 @@
1
+ <template>
2
+ <div>
3
+ <vue-tags-input
4
+ v-model="tag"
5
+ :tags="tags"
6
+ :autocomplete-items="autoCompleteSuggestions"
7
+ :separators="separators"
8
+ :add-on-key="separators"
9
+ @tags-changed="tagsChanged"
10
+ >
11
+ <template #autocomplete-item="props">
12
+ <div class="autocomplete-item" :class="{ 'is-active': props.selected }">
13
+ <span class="tag-name">{{ props.item.text }}</span>
14
+ <span v-if="props.item.data && props.item.data.snippet" class="tag-snippet">
15
+ - {{ props.item.data.snippet }}
16
+ </span>
17
+ </div>
18
+ </template>
19
+ </vue-tags-input>
20
+
21
+ <v-btn v-if="!hideSubmit" color="success" :loading="loading" @click="submit">Save Changes</v-btn>
22
+ </div>
23
+ </template>
24
+
25
+ <script lang="ts">
26
+ import { defineComponent } from 'vue';
27
+ import { getDataLayer, Tag, CourseDBInterface } from '@vue-skuilder/db';
28
+ // @ts-expect-error - suppress TS error for VueTagsInput - no types available
29
+ import { VueTagsInput } from '@vojtechlanka/vue-tags-input';
30
+
31
+ export interface TagObject {
32
+ text: string;
33
+ style?: string;
34
+ classes?: string;
35
+ data?: {
36
+ snippet: string;
37
+ };
38
+ }
39
+
40
+ export interface TagsInputInstance {
41
+ tags: Array<{
42
+ text: string;
43
+ style?: string;
44
+ classes?: string;
45
+ data?: {
46
+ snippet: string;
47
+ };
48
+ }>;
49
+ submit: () => Promise<void>;
50
+ updateAvailableCourseTags: () => Promise<void>;
51
+ }
52
+
53
+ export default defineComponent({
54
+ name: 'SkTagsInput',
55
+
56
+ components: {
57
+ VueTagsInput,
58
+ },
59
+
60
+ props: {
61
+ courseID: {
62
+ type: String,
63
+ required: true,
64
+ default: '',
65
+ },
66
+ cardID: {
67
+ type: String,
68
+ required: false,
69
+ default: '',
70
+ },
71
+ hideSubmit: {
72
+ type: Boolean,
73
+ required: false,
74
+ default: false,
75
+ },
76
+ },
77
+
78
+ data() {
79
+ return {
80
+ loading: true,
81
+ tag: '',
82
+ tags: [] as TagObject[],
83
+ initialTags: [] as string[],
84
+ availableCourseTags: [] as Tag[],
85
+ separators: [';', ',', ' '] as string[],
86
+ courseDB: null as CourseDBInterface | null,
87
+ };
88
+ },
89
+
90
+ computed: {
91
+ autoCompleteSuggestions(): TagObject[] {
92
+ return this.availableCourseTags
93
+ .filter((availableTag) => {
94
+ return availableTag.name.toLowerCase().indexOf(this.tag.toLowerCase()) !== -1;
95
+ })
96
+ .map((availableTag) => {
97
+ return {
98
+ text: availableTag.name,
99
+ data: {
100
+ snippet: availableTag.snippet,
101
+ },
102
+ };
103
+ });
104
+ },
105
+ },
106
+
107
+ watch: {
108
+ async cardID() {
109
+ await this.getAppliedTags();
110
+ },
111
+ async courseID() {
112
+ this.courseDB = getDataLayer().getCourseDB(this.courseID);
113
+ await this.updateAvailableCourseTags();
114
+ },
115
+ },
116
+
117
+ async created() {
118
+ this.courseDB = getDataLayer().getCourseDB(this.courseID);
119
+
120
+ await this.updateAvailableCourseTags();
121
+ await this.getAppliedTags();
122
+ },
123
+
124
+ methods: {
125
+ tagsChanged(newTags: TagObject[]) {
126
+ console.log(`[TagsInput] Tags changing: ${JSON.stringify(newTags)}`);
127
+ this.tags = newTags;
128
+ },
129
+
130
+ async getAppliedTags() {
131
+ this.initialTags = [];
132
+ this.tags = [];
133
+ try {
134
+ const appliedDocsFindResult = await this.courseDB!.getAppliedTags(this.cardID);
135
+ appliedDocsFindResult.rows.forEach((row) => {
136
+ console.log(`[TagsInput] The following tag is applied:
137
+ \t${JSON.stringify(row)}`);
138
+ this.tags.push({
139
+ text: row!.value.name,
140
+ style: '',
141
+ classes: '',
142
+ });
143
+ });
144
+ this.initialTags = this.tags.map((tag) => tag.text);
145
+ } catch (e) {
146
+ console.error(`Error in init-getAppliedTags: ${JSON.stringify(e)}, ${e}`);
147
+ } finally {
148
+ this.loading = false;
149
+ }
150
+ },
151
+
152
+ async updateAvailableCourseTags() {
153
+ try {
154
+ this.availableCourseTags = (await this.courseDB!.getCourseTagStubs()).rows.map((row) => {
155
+ console.log(`[TagsInput] available tag: ${JSON.stringify(row)}`);
156
+ return row.doc! as Tag;
157
+ });
158
+ } catch (e) {
159
+ console.error(`Error in init-availableCourseTags: ${JSON.stringify(e)}`);
160
+ }
161
+ },
162
+
163
+ async submit() {
164
+ console.log(`[TagsInput] tagsInput is submitting...`);
165
+ this.loading = true;
166
+
167
+ try {
168
+ await Promise.all(
169
+ this.tags.map(async (currentTag) => {
170
+ if (!this.initialTags.includes(currentTag.text)) {
171
+ try {
172
+ await this.courseDB!.addTagToCard(this.cardID, currentTag.text);
173
+ console.log(`[TagsInput] Successfully added tag: ${currentTag.text}`);
174
+ } catch (error) {
175
+ console.error(`Failed to add tag ${currentTag.text}:`, error);
176
+ }
177
+ }
178
+ })
179
+ );
180
+ } catch (e) {
181
+ console.error(`Exception adding tags: ${JSON.stringify(e)}`);
182
+ }
183
+
184
+ try {
185
+ await Promise.all(
186
+ this.initialTags.map(async (initialTag) => {
187
+ if (
188
+ this.tags.filter((tag) => {
189
+ return tag.text === initialTag;
190
+ }).length === 0
191
+ ) {
192
+ try {
193
+ await this.courseDB!.removeTagFromCard(this.cardID, initialTag);
194
+ console.log(`[TagsInput] Successfully removed tag: ${initialTag}`);
195
+ } catch (error) {
196
+ console.error(`Failed to remove tag ${initialTag}:`, error);
197
+ }
198
+ }
199
+ })
200
+ );
201
+ } catch (e) {
202
+ console.error(`Exception removing tags: ${JSON.stringify(e)}`);
203
+ }
204
+ this.loading = false;
205
+ },
206
+ },
207
+ });
208
+ </script>
209
+
210
+ <style scoped>
211
+ .vue-tags-input {
212
+ max-width: 100%;
213
+ }
214
+
215
+ .autocomplete-item {
216
+ display: flex;
217
+ align-items: center;
218
+ padding: 5px;
219
+ }
220
+
221
+ .autocomplete-item.is-active {
222
+ background-color: #e8e8e8;
223
+ }
224
+
225
+ .autocomplete-item.is-active > .tag-name {
226
+ background-color: #5c6bc0;
227
+ color: white;
228
+ }
229
+
230
+ .tag-name {
231
+ background-color: #e0e0e0;
232
+ color: #333;
233
+ padding: 2px 6px;
234
+ border-radius: 3px;
235
+ font-weight: bold;
236
+ margin-right: 5px;
237
+ }
238
+
239
+ .tag-snippet {
240
+ color: #666;
241
+ font-size: 0.9em;
242
+ }
243
+
244
+ .autocomplete-item.is-active .tag-snippet {
245
+ color: #333; /* Ensure snippet text is visible when item is active */
246
+ }
247
+ </style>