@windward/games 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 (68) hide show
  1. package/.editorconfig +13 -0
  2. package/.eslintrc.js +11 -0
  3. package/.prettierrc +4 -0
  4. package/README.md +43 -0
  5. package/babel.config.js +1 -0
  6. package/components/content/CrudTable.vue +295 -0
  7. package/components/content/DataTableRowHandler.vue +113 -0
  8. package/components/content/DatableEditor.vue +223 -0
  9. package/components/content/blocks/BaseContentBlock.vue +8 -0
  10. package/components/content/blocks/dragDrop/BucketGame.vue +520 -0
  11. package/components/content/blocks/dragDrop/SortingGame.vue +303 -0
  12. package/components/content/blocks/flashcards/CardFace.vue +112 -0
  13. package/components/content/blocks/flashcards/Flashcard.vue +150 -0
  14. package/components/content/blocks/flashcards/FlashcardSlides.vue +121 -0
  15. package/components/content/blocks/matchingGame/MatchingGame.vue +545 -0
  16. package/components/content/blocks/quizshowGame/AnswerPanel.vue +338 -0
  17. package/components/content/blocks/quizshowGame/Gridview.vue +260 -0
  18. package/components/content/blocks/quizshowGame/QuizShow.vue +516 -0
  19. package/components/content/blocks/quizshowGame/feedbackIcons.vue +41 -0
  20. package/components/content/blocks/slideshow/SlideShow.vue +175 -0
  21. package/components/settings/BucketGameSettingsManager.vue +683 -0
  22. package/components/settings/FlashCardSlidesManager.vue +489 -0
  23. package/components/settings/MatchingGameManager.vue +775 -0
  24. package/components/settings/QuizShowSettingsManager.vue +408 -0
  25. package/components/settings/SlideShowManager.vue +248 -0
  26. package/components/settings/SortingGameSettingsManager.vue +286 -0
  27. package/i18n/en-US/components/content/blocks/bucket_game.ts +39 -0
  28. package/i18n/en-US/components/content/blocks/flashcard.ts +5 -0
  29. package/i18n/en-US/components/content/blocks/index.ts +15 -0
  30. package/i18n/en-US/components/content/blocks/matching_game.ts +26 -0
  31. package/i18n/en-US/components/content/blocks/quizshow_game.ts +35 -0
  32. package/i18n/en-US/components/content/blocks/slideshow.ts +13 -0
  33. package/i18n/en-US/components/content/blocks/sorting_game.ts +5 -0
  34. package/i18n/en-US/components/content/crud_table.ts +6 -0
  35. package/i18n/en-US/components/content/index.ts +7 -0
  36. package/i18n/en-US/components/index.ts +9 -0
  37. package/i18n/en-US/components/navigation/index.ts +5 -0
  38. package/i18n/en-US/components/settings/bucket_game.ts +35 -0
  39. package/i18n/en-US/components/settings/flashcard.ts +26 -0
  40. package/i18n/en-US/components/settings/index.ts +13 -0
  41. package/i18n/en-US/components/settings/matching_game.ts +15 -0
  42. package/i18n/en-US/components/settings/quizshow_game.ts +14 -0
  43. package/i18n/en-US/components/settings/slideshow.ts +11 -0
  44. package/i18n/en-US/index.ts +15 -0
  45. package/i18n/en-US/modules/index.ts +5 -0
  46. package/i18n/en-US/pages/index.ts +5 -0
  47. package/i18n/en-US/shared/content_blocks.ts +14 -0
  48. package/i18n/en-US/shared/index.ts +7 -0
  49. package/i18n/en-US/shared/settings.ts +10 -0
  50. package/i18n/en-US.ts +5 -0
  51. package/jest.config.js +18 -0
  52. package/package.json +51 -0
  53. package/plugin.js +150 -0
  54. package/test/blocks/dragDrop/BucketGame.spec.js +26 -0
  55. package/test/blocks/dragDrop/SortingGame.spec.js +47 -0
  56. package/test/blocks/flashcards/CardFace.spec.js +21 -0
  57. package/test/blocks/flashcards/FlashCardSlides.spec.js +24 -0
  58. package/test/blocks/flashcards/Flashcard.spec.js +24 -0
  59. package/test/blocks/matchingGame/MatchingGame.spec.js +26 -0
  60. package/test/blocks/quizShow/quizShow.spec.js +31 -0
  61. package/test/blocks/slideshow/slideshow.spec.js +24 -0
  62. package/test/mocks.js +2 -0
  63. package/test/settings/BucketGameManager.spec.js +125 -0
  64. package/test/settings/FlashCardSlidesManager.spec.js +24 -0
  65. package/test/settings/MatchingGameManager.spec.js +30 -0
  66. package/test/settings/SlideShowManager.spec.js +30 -0
  67. package/test/settings/SortingGameManager.spec.js +71 -0
  68. package/tsconfig.json +20 -0
@@ -0,0 +1,545 @@
1
+ <template>
2
+ <div class="background">
3
+ <div>
4
+ <h1
5
+ :aria-label="
6
+ $t(
7
+ 'plugin.games.components.content.blocks.matching_game.match_game_title'
8
+ )
9
+ "
10
+ tabindex="0"
11
+ >
12
+ {{ block.metadata.config.title }}
13
+ </h1>
14
+
15
+ <p tabindex="0">
16
+ {{ block.metadata.config.instructions }}
17
+ </p>
18
+ <p tabindex="0">
19
+ {{
20
+ $t(
21
+ 'plugin.games.components.content.blocks.matching_game.description'
22
+ )
23
+ }}
24
+ </p>
25
+
26
+ <v-container fluid :class="status" class="pa-0">
27
+ <br />
28
+ <v-row>
29
+ <v-col></v-col>
30
+ <v-col class="d-flex justify-center">{{
31
+ feedback
32
+ ? feedback
33
+ : $t(
34
+ 'plugin.games.components.content.blocks.bucket_game.form.feedback.feedback_here'
35
+ )
36
+ }}</v-col>
37
+ <v-col class="d-flex justify-end pl-4">
38
+ <v-btn
39
+ v-if="status === 'successOutline'"
40
+ class="success mr-5"
41
+ @click="onContinueGame"
42
+ >{{ $t('shared.forms.continue') }}
43
+ </v-btn></v-col
44
+ >
45
+ </v-row>
46
+ <br />
47
+ </v-container>
48
+ <div>
49
+ <v-container>
50
+ <v-row>
51
+ <draggable
52
+ class="d-flex justify-space-between flex-wrap col-md-12"
53
+ v-bind="dragOptions"
54
+ :list="block.metadata.config.answerObjects"
55
+ :disabled="!allowDrag"
56
+ :group="{
57
+ name: 'people',
58
+ pull: 'clone',
59
+ put: false,
60
+ }"
61
+ @end="onEnd"
62
+ >
63
+ <v-card
64
+ v-for="(answer, aindex) in block.metadata.config
65
+ .answerObjects"
66
+ :key="aindex"
67
+ class="pa-2 ma-2 answerCard"
68
+ outlined
69
+ tile
70
+ color="primary"
71
+ >
72
+ <v-icon>mdi-gesture-tap-hold</v-icon>
73
+ <span>
74
+ {{ answer.display }}
75
+ </span>
76
+ </v-card>
77
+ </draggable>
78
+ </v-row>
79
+ <v-row
80
+ class="d-flex flex-wrap flex-row justify-center flex-fill"
81
+ v-if="render"
82
+ >
83
+ <v-row align="center" class="col-md-12">
84
+ <v-card
85
+ v-if="!mainPrompt['toggle']"
86
+ class="flex-fill bucket"
87
+ min-height="5em"
88
+ outlined
89
+ tile
90
+ color="secondary"
91
+ >
92
+ <v-card-text class="text-center">
93
+ <draggable
94
+ class="dragArea list-group"
95
+ :key="mainPrompt['prompt']"
96
+ v-bind="dragOptions"
97
+ disabled
98
+ group="people"
99
+ tabindex="0"
100
+ >
101
+ <div
102
+ class="card_text secondary"
103
+ color="secondary"
104
+ >
105
+ {{ mainPrompt['prompt'] }}
106
+ </div>
107
+ </draggable>
108
+ </v-card-text>
109
+ </v-card>
110
+ </v-row>
111
+ <v-row align="center" class="col-md-10">
112
+ <v-card
113
+ v-if="mainPrompt['toggle']"
114
+ class="pa-2 flex-fill bucket"
115
+ min-height="5em"
116
+ outlined
117
+ tile
118
+ >
119
+ <v-card-text>
120
+ <draggable
121
+ class="dragArea list-group"
122
+ :key="mainPrompt['prompt']"
123
+ v-bind="dragOptions"
124
+ disabled
125
+ group="people"
126
+ tabindex="0"
127
+ >
128
+ <div
129
+ :id="
130
+ mainPrompt['file']['asset'][
131
+ 'public_url'
132
+ ]
133
+ "
134
+ >
135
+ <v-img
136
+ v-if="mainPrompt['file']"
137
+ :aria-describedby="
138
+ mainPrompt[
139
+ 'ariaDescribedBy'
140
+ ]
141
+ "
142
+ :alt="mainPrompt['altText']"
143
+ :src="
144
+ mainPrompt['file']['asset'][
145
+ 'public_url'
146
+ ]
147
+ "
148
+ ></v-img>
149
+ </div>
150
+ </draggable>
151
+ </v-card-text>
152
+ </v-card>
153
+ </v-row>
154
+ </v-row>
155
+ <v-row
156
+ class="d-flex flex-wrap flex-row justify-center flex-fill"
157
+ v-if="
158
+ !render && block.metadata.config.prompts.length > 0
159
+ "
160
+ >
161
+ <v-row align="center" class="col-md-12">
162
+ <v-card
163
+ v-if="
164
+ !block.metadata.config.prompts[
165
+ startingIndex
166
+ ]['toggle']
167
+ "
168
+ class="pa-2 flex-fill bucket"
169
+ min-height="5em"
170
+ outlined
171
+ tile
172
+ color="secondary"
173
+ >
174
+ <v-card-text class="text-center">
175
+ <draggable
176
+ class="dragArea list-group"
177
+ :key="
178
+ block.metadata.config.prompts[
179
+ startingIndex
180
+ ]['prompt']
181
+ "
182
+ v-bind="dragOptions"
183
+ disabled
184
+ group="people"
185
+ tabindex="0"
186
+ >
187
+ <div
188
+ class="card_text secondary"
189
+ color="secondary"
190
+ >
191
+ {{
192
+ block.metadata.config.prompts[
193
+ startingIndex
194
+ ]['prompt']
195
+ }}
196
+ </div>
197
+ </draggable>
198
+ </v-card-text>
199
+ </v-card>
200
+ </v-row>
201
+ <v-row align="center" class="col-md-10">
202
+ <v-card
203
+ v-if="
204
+ block.metadata.config.prompts[
205
+ startingIndex
206
+ ]['file']
207
+ "
208
+ class="pa-2 flex-fill bucket"
209
+ min-height="5em"
210
+ outlined
211
+ tile
212
+ >
213
+ <v-card-text>
214
+ <draggable
215
+ class="dragArea list-group"
216
+ :key="
217
+ block.metadata.config.prompts[
218
+ startingIndex
219
+ ]['prompt']
220
+ "
221
+ v-bind="dragOptions"
222
+ disabled
223
+ group="people"
224
+ tabindex="0"
225
+ >
226
+ <div
227
+ :id="
228
+ block.metadata.config.prompts[
229
+ startingIndex
230
+ ]['file']['asset']['public_url']
231
+ "
232
+ >
233
+ <v-img
234
+ v-if="
235
+ block.metadata.config
236
+ .prompts[startingIndex][
237
+ 'file'
238
+ ]
239
+ "
240
+ :aria-describedby="
241
+ block.metadata.config
242
+ .prompts[startingIndex][
243
+ 'ariaDescribedBy'
244
+ ]
245
+ "
246
+ :alt="
247
+ block.metadata.config
248
+ .prompts[startingIndex][
249
+ 'altText'
250
+ ]
251
+ "
252
+ :src="
253
+ block.metadata.config
254
+ .prompts[startingIndex][
255
+ 'file'
256
+ ]['asset']['public_url']
257
+ "
258
+ ></v-img>
259
+ </div>
260
+ </draggable>
261
+ </v-card-text>
262
+ </v-card>
263
+ </v-row>
264
+ </v-row>
265
+ <v-container
266
+ class="d-flex flex-wrap flex-row justify-center flex-fill"
267
+ align="end"
268
+ >
269
+ <v-layout>
270
+ <v-flex xs8></v-flex>
271
+ <v-flex xs4>
272
+ <v-row
273
+ align="end"
274
+ tabindex="0"
275
+ :aria-label="
276
+ $t(
277
+ 'plugin.games.components.content.blocks.matching_game.of_complete',
278
+ [
279
+ completedAmount,
280
+ totalAmountQuestions,
281
+ ]
282
+ )
283
+ "
284
+ >
285
+ <v-col align="end" tabindex="0">
286
+ {{
287
+ $t(
288
+ 'plugin.games.components.content.blocks.matching_game.of_complete_text_area',
289
+ [
290
+ completedAmount,
291
+ totalAmountQuestions,
292
+ ]
293
+ )
294
+ }}
295
+ <v-progress-linear
296
+ color="primary"
297
+ outlined
298
+ v-model="completedPercent"
299
+ rounded
300
+ height="15"
301
+ ></v-progress-linear>
302
+ <br />
303
+ <v-btn
304
+ color="primary"
305
+ outlined
306
+ @click="onReset"
307
+ >{{
308
+ $t(
309
+ 'plugin.games.components.content.blocks.matching_game.reset'
310
+ )
311
+ }}
312
+ </v-btn>
313
+ </v-col>
314
+ </v-row>
315
+ </v-flex>
316
+ </v-layout>
317
+ </v-container>
318
+ </v-container>
319
+ </div>
320
+ </div>
321
+ <br />
322
+ </div>
323
+ </template>
324
+ <script>
325
+ import _ from 'lodash'
326
+ import draggable from 'vuedraggable'
327
+ import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
328
+
329
+ export default {
330
+ name: 'MatchingGame',
331
+ components: { draggable },
332
+ extends: BaseContentBlock,
333
+ beforeMount() {
334
+ if (_.isEmpty(this.block)) {
335
+ this.block = {}
336
+ }
337
+ if (_.isEmpty(this.block.metadata)) {
338
+ this.block.metadata = {}
339
+ }
340
+ if (_.isEmpty(this.block.metadata.config)) {
341
+ this.block.metadata.config = {}
342
+ }
343
+ if (_.isEmpty(this.block.metadata.config.title)) {
344
+ this.block.metadata.config.title = ''
345
+ }
346
+ if (_.isEmpty(this.block.metadata.config.instructions)) {
347
+ this.block.metadata.config.instructions = ''
348
+ }
349
+ if (_.isEmpty(this.block.metadata.config.feedback_correct)) {
350
+ this.block.metadata.config.feedback_correct = ''
351
+ }
352
+ if (_.isEmpty(this.block.metadata.config.feedback_incorrect)) {
353
+ this.block.metadata.config.feedback_incorrect = ''
354
+ }
355
+ if (_.isEmpty(this.block.metadata.config.prompts)) {
356
+ this.block.metadata.config.prompts = []
357
+ }
358
+ if (_.isEmpty(this.block.metadata.config.answerObjects)) {
359
+ this.block.metadata.config.answerObjects = []
360
+ }
361
+ },
362
+ computed: {
363
+ dragOptions() {
364
+ return {
365
+ animation: 200,
366
+ }
367
+ },
368
+ completedAmount() {
369
+ return _.flatten(this.solvedQuestions).length
370
+ },
371
+ completedPercent() {
372
+ if (this.block.metadata.config.prompts.length > 0) {
373
+ return (
374
+ (this.solvedQuestions.length /
375
+ this.block.metadata.config.prompts.length) *
376
+ 100
377
+ )
378
+ }
379
+ return 0
380
+ },
381
+ totalAmountQuestions() {
382
+ return _.flatten(this.block.metadata.config.prompts).length
383
+ },
384
+ },
385
+ data() {
386
+ return {
387
+ feedback: this.$t(
388
+ 'plugin.games.components.content.blocks.matching_game.default_feedback'
389
+ ),
390
+ toggle: false,
391
+ gameCompleted: false,
392
+ shufflePrompts: [],
393
+ solvedQuestions: [],
394
+ status: 'default',
395
+ allowDrag: true,
396
+ mainPrompt: {},
397
+ editedPrompt: {},
398
+ startingIndex: 0,
399
+ }
400
+ },
401
+ watch: {
402
+ render(newVal) {
403
+ if (newVal === true) {
404
+ this.onReset()
405
+ }
406
+ },
407
+ },
408
+ mounted() {
409
+ this.setMainPrompt()
410
+ },
411
+ methods: {
412
+ shuffle(array) {
413
+ let currentIndex = array.length,
414
+ randomIndex
415
+ // While there remain elements to shuffle.
416
+ while (currentIndex !== 0) {
417
+ // Pick a remaining element.
418
+ randomIndex = Math.floor(Math.random() * currentIndex)
419
+ currentIndex--
420
+ // And swap it with the current element.
421
+ ;[array[currentIndex], array[randomIndex]] = [
422
+ array[randomIndex],
423
+ array[currentIndex],
424
+ ]
425
+ }
426
+ return array
427
+ },
428
+ setMainPrompt() {
429
+ if (this.block.metadata.config.prompts.length !== 0) {
430
+ this.shufflePrompts = _.cloneDeep(
431
+ this.block.metadata.config.prompts
432
+ )
433
+ this.shufflePrompts = this.shuffle(this.shufflePrompts)
434
+ this.mainPrompt = this.shufflePrompts.shift()
435
+ }
436
+ },
437
+ onEnd(evt, originalEvent) {
438
+ if (!this.render) {
439
+ this.mainPrompt =
440
+ this.block.metadata.config.prompts[this.startingIndex]
441
+ }
442
+ let draggedElement = ''
443
+ let target = ''
444
+ if (this.mainPrompt.toggle === false) {
445
+ draggedElement =
446
+ this.block.metadata.config.answerObjects[evt.oldIndex]
447
+ target = this.block.metadata.config.prompts.find((element) => {
448
+ return (
449
+ element.prompt == evt.to.firstChild.textContent.trim()
450
+ )
451
+ })
452
+ } else {
453
+ draggedElement =
454
+ this.block.metadata.config.answerObjects[evt.oldIndex]
455
+ target = this.block.metadata.config.prompts.find((element) => {
456
+ return (
457
+ element.file?.asset.public_url ==
458
+ evt.to.firstElementChild.id
459
+ )
460
+ })
461
+ }
462
+ if (_.isUndefined(target)) {
463
+ } else if (draggedElement.id !== target.answer.id) {
464
+ this.feedback = this.block.metadata.config.feedback_incorrect
465
+ this.status = 'errorOutline'
466
+ } else if (draggedElement.id === target.answer.id) {
467
+ this.feedback = this.block.metadata.config.feedback_correct
468
+ this.solvedQuestions.push(target)
469
+ this.status = 'successOutline'
470
+ this.allowDrag = false
471
+ if (
472
+ this.solvedQuestions.length ===
473
+ this.block.metadata.config.prompts.length
474
+ ) {
475
+ this.feedback = this.$t(
476
+ 'plugin.games.components.content.blocks.matching_game.congratulations_feedback'
477
+ )
478
+ this.gameCompleted = true
479
+ this.status = 'default'
480
+ }
481
+ }
482
+ },
483
+ onContinueGame() {
484
+ if (!this.render) {
485
+ this.startingIndex = this.startingIndex + 1
486
+ }
487
+ this.status = 'default'
488
+ this.mainPrompt = this.shufflePrompts.shift()
489
+ this.allowDrag = true
490
+ this.feedback = this.$t(
491
+ 'plugin.games.components.content.blocks.matching_game.default_feedback'
492
+ )
493
+ },
494
+ onReset() {
495
+ this.shufflePrompts = []
496
+ this.startingIndex = 0
497
+ this.status = 'default'
498
+ this.solvedQuestions = []
499
+ this.gameCompleted = false
500
+ this.allowDrag = true
501
+ this.feedback = this.$t(
502
+ 'plugin.games.components.content.blocks.matching_game.default_feedback'
503
+ )
504
+ this.setMainPrompt()
505
+ },
506
+ },
507
+ }
508
+ </script>
509
+ <style scoped>
510
+ .bucket {
511
+ line-height: 1.1em;
512
+ padding: 0.5em;
513
+ box-shadow: 0px 2px 3px #0000004a;
514
+ transition: 0.5s box-shadow;
515
+ }
516
+ .successOutline {
517
+ border: 4px solid var(--v-success-base);
518
+ color: var(--v-success-base);
519
+ }
520
+ .errorOutline {
521
+ border: 4px solid var(--v-error-base);
522
+ color: var(--v-error-base);
523
+ }
524
+ .card_text {
525
+ font-size: large;
526
+ }
527
+ .answerCard {
528
+ min-width: 23%;
529
+ }
530
+ @media (max-width: 1270px) {
531
+ .answerCard {
532
+ min-width: 30%;
533
+ }
534
+ }
535
+ @media (max-width: 900px) {
536
+ .answerCard {
537
+ min-width: 40%;
538
+ }
539
+ }
540
+ @media (max-width: 610px) {
541
+ .answerCard {
542
+ min-width: 95%;
543
+ }
544
+ }
545
+ </style>