@windward/games 0.11.0 → 0.12.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ### Hotfix [0.12.1] created - 2025-02-20
4
+
5
+
6
+ ### Release [0.12.0] created - 2025-02-18
7
+
8
+
3
9
  ### Release [0.11.0] created - 2025-02-05
4
10
 
5
11
 
@@ -66,10 +66,11 @@
66
66
  <v-container>
67
67
  <draggable
68
68
  v-if="mainAnswer.length !== 0"
69
- class="d-flex flex-wrap flex-row justify-center flex-fill"
69
+ class="d-flex flex-wrap flex-row justify-center flex-fill no-select"
70
70
  :list="mainAnswer"
71
71
  :disabled="!allow_drag"
72
72
  group="people"
73
+ :forceFallback="true"
73
74
  :move="onMoveCallback"
74
75
  >
75
76
  <v-row class="ma-2">
@@ -607,6 +608,9 @@ export default {
607
608
  font-size: large;
608
609
  color: black;
609
610
  }
611
+ .no-select {
612
+ user-select: none;
613
+ }
610
614
  .container-nested-answers {
611
615
  min-width: 10vw;
612
616
  padding-left: 4px;
@@ -23,10 +23,11 @@
23
23
  <v-container v-if="render" class="mt-2">
24
24
  <draggable
25
25
  v-model="input"
26
- :disabled="disabled"
26
+ :disabled="isDisabled"
27
27
  class="d-flex flex-column"
28
28
  group="cards"
29
29
  v-bind="dragOptions"
30
+ :forceFallback="true"
30
31
  @change="onDragChange"
31
32
  >
32
33
  <v-row v-for="index in input.length" :key="'sortable_' + index">
@@ -86,7 +87,7 @@
86
87
  <v-container v-if="!render" class="mt-2">
87
88
  <draggable
88
89
  v-model="block.metadata.config.answer"
89
- :disabled="disabled"
90
+ :disabled="isDisabled"
90
91
  class="d-flex flex-column"
91
92
  group="cards"
92
93
  v-bind="dragOptions"
@@ -163,7 +164,7 @@ export default {
163
164
  data() {
164
165
  return {
165
166
  ticker: '123',
166
- disabled: false,
167
+ isDisabled: false,
167
168
  reload: false,
168
169
  input: [],
169
170
  feedback: 'feedback here',
@@ -232,7 +233,7 @@ export default {
232
233
  })
233
234
  },
234
235
  onReset() {
235
- this.disabled = false
236
+ this.isDisabled = false
236
237
  this.success = []
237
238
  this.fail = []
238
239
  this.input = this.shuffle(
@@ -242,7 +243,7 @@ export default {
242
243
  this.seed = Math.floor(Math.random() * 100)
243
244
  },
244
245
  onContinueGame() {
245
- this.disabled = false
246
+ this.isDisabled = false
246
247
  this.success = []
247
248
  this.fail = []
248
249
  this.feedback = this.block.metadata.config.feedback_default
@@ -282,7 +283,7 @@ export default {
282
283
  },
283
284
  onCheckAnswers() {
284
285
  const self = this
285
- this.disabled = true
286
+ this.isDisabled = true
286
287
 
287
288
  this.input.forEach(function (item, index) {
288
289
  if (self.block.metadata.config.answer[index].id === item.id) {
@@ -313,9 +314,9 @@ export default {
313
314
  if (this.fail[index - 1]) {
314
315
  classValue += 'sortable--error '
315
316
  }
316
- if (this.disabled) {
317
+ if (this.isDisabled) {
317
318
  classValue += 'sortable-default '
318
- } else if (!this.disabled) {
319
+ } else if (!this.isDisabled) {
319
320
  classValue += 'sortable-grab '
320
321
  }
321
322
  return classValue
@@ -1,24 +1,25 @@
1
1
  <template>
2
- <v-container>
3
- <br />
4
- <div
5
- class="card-content d-flex flex-column align-center justify-center"
6
- >
7
- <v-row>
2
+ <v-container
3
+ class="fill-height d-flex flex-column align-center justify-center"
4
+ >
5
+ <div class="card-content">
6
+ <v-row class="justify-center">
8
7
  <content-viewer :class="textClass" v-model="settings.text" />
9
8
  </v-row>
10
- <br />
11
- <v-row v-if="settings.fileConfig" no-gutters>
9
+ <v-row
10
+ v-if="
11
+ settings.fileConfig.asset && settings.fileConfig.asset.file_asset_id
12
+ "
13
+ >
12
14
  <v-col>
13
15
  <ImageAssetViewer
14
16
  v-model="settings.fileConfig"
15
17
  :assets="assets"
16
18
  max-height="210"
17
- max-width="250"
19
+ :max-width="maxWidth"
18
20
  ></ImageAssetViewer>
19
21
  </v-col>
20
22
  </v-row>
21
- <br />
22
23
  </div>
23
24
  <v-row class="card-footer pt-4" align="center" justify="center">
24
25
  {{ settings.footer }}&nbsp;
@@ -66,6 +67,17 @@ export default {
66
67
 
67
68
  return 'px-6 text-left'
68
69
  },
70
+ maxWidth() {
71
+ if (window.innerWidth <= 1400 && window.innerWidth >= 1264) {
72
+ return '150'
73
+ } else if (window.innerWidth <= 613 && window.innerWidth >= 416) {
74
+ return '200'
75
+ } else if (window.innerWidth <= 415) {
76
+ return '100'
77
+ } else {
78
+ return '250'
79
+ }
80
+ },
69
81
  },
70
82
  beforeMount() {
71
83
  // so background isn't set to white by the imageassetviewer
@@ -81,6 +93,7 @@ export default {
81
93
  .card-content {
82
94
  color: var(--v-primary-base);
83
95
  font-size: 1rem;
96
+ max-height: 100%;
84
97
  }
85
98
  .card-content--bold {
86
99
  font-weight: bold;
@@ -1,12 +1,17 @@
1
1
  <template>
2
- <v-container style="height: 100%" class="div-container">
2
+ <v-container
3
+ style="height: 100%"
4
+ class="div-container"
5
+ :key="updateCardKey"
6
+ >
3
7
  <v-card
4
8
  outlined
5
9
  @click="toggleCard"
6
10
  v-show="side"
7
11
  :class="cardClass"
12
+ style="height: 90%"
8
13
  >
9
- <v-card-text>
14
+ <v-card-text class="fill-height">
10
15
  <CardFace
11
16
  side="front"
12
17
  :settings="frontFace"
@@ -14,13 +19,19 @@
14
19
  ></CardFace>
15
20
  </v-card-text>
16
21
  </v-card>
17
- <v-card outlined @click="toggleCard" v-show="!side" :class="cardClass">
22
+ <v-card
23
+ outlined
24
+ @click="toggleCard"
25
+ v-show="!side"
26
+ :class="cardClass"
27
+ style="height: 90%"
28
+ >
18
29
  <v-card-title class="card-title">
19
30
  <v-row align="center" justify="center">{{
20
31
  backFace.header
21
32
  }}</v-row>
22
33
  </v-card-title>
23
- <v-card-text>
34
+ <v-card-text style="height: 90%">
24
35
  <CardFace
25
36
  side="back"
26
37
  :settings="backFace"
@@ -33,6 +44,8 @@
33
44
  <script>
34
45
  import CardFace from './CardFace'
35
46
  import _ from 'lodash'
47
+ import Crypto from '~/helpers/Crypto'
48
+
36
49
  export default {
37
50
  components: { CardFace },
38
51
  data() {
@@ -40,6 +53,7 @@ export default {
40
53
  settings: {},
41
54
  flip: false,
42
55
  side: true,
56
+ updateCardKey: 0,
43
57
  }
44
58
  },
45
59
  props: {
@@ -102,6 +116,8 @@ export default {
102
116
  //this.cardClass = 'animated flipInY flashcard flashcard--size-md'
103
117
  this.$emit('input', !this.side)
104
118
  this.side = !this.side
119
+ // update container with correct side
120
+ this.updateCardKey = Crypto.id()
105
121
  },
106
122
  },
107
123
  }
@@ -21,14 +21,14 @@
21
21
  {{ block.metadata.config.instructions }}
22
22
  </p>
23
23
  <v-container :class="status">
24
- <v-row class="d-flex justify-center py-3">{{
24
+ <v-row class="d-flex justify-center pa-2">{{
25
25
  feedback
26
26
  ? feedback
27
27
  : $t(
28
28
  'windward.games.components.content.blocks.bucket_game.form.feedback.feedback_here'
29
29
  )
30
30
  }}</v-row>
31
- <v-row class="d-flex justify-center pb-3">
31
+ <v-row class="d-flex justify-center pa-2" v-if="!gameCompleted">
32
32
  <v-btn
33
33
  v-if="status === 'container-success-outline'"
34
34
  class="success"
@@ -46,14 +46,13 @@
46
46
  </v-row>
47
47
  </v-container>
48
48
  <v-container class="pl-0 pr-0 mt-2">
49
- <v-row
50
- v-if="render"
51
- class="d-flex flex-wrap flex-row justify-center flex-fill"
52
- >
53
- <v-row align="center" class="col-md-12">
49
+ <v-row v-if="render" class="d-flex justify-center">
50
+ <v-row
51
+ v-if="mainPrompt['textOrImage'] === 'text'"
52
+ class="col-md-12"
53
+ >
54
54
  <v-card
55
- v-if="mainPrompt['textOrImage'] === 'text'"
56
- class="flex-fill bucket"
55
+ class="flex-fill card-bucket"
57
56
  min-height="5em"
58
57
  outlined
59
58
  tile
@@ -61,7 +60,7 @@
61
60
  >
62
61
  <v-card-text class="text-center">
63
62
  <draggable
64
- class="dragArea list-group"
63
+ class="dragArea no-select"
65
64
  :key="mainPrompt['prompt']"
66
65
  v-bind="dragOptions"
67
66
  disabled
@@ -79,21 +78,23 @@
79
78
  </v-card>
80
79
  </v-row>
81
80
  <v-row
82
- align="center"
83
- class="col-md-10 d-flex justify-center"
81
+ v-if="mainPrompt['textOrImage'] === 'image'"
82
+ class="d-flex justify-center ma-2"
84
83
  >
85
84
  <v-card
86
- v-if="mainPrompt['textOrImage'] === 'image'"
87
- class="pa-2 flex-fill bucket d-flex justify-center"
85
+ class="flex-fill card-bucket"
88
86
  min-height="5em"
89
87
  max-height="400"
90
- max-width="300"
88
+ :max-width="maxWidth"
91
89
  outlined
92
90
  tile
93
91
  >
94
92
  <v-card-text>
95
93
  <draggable
96
- v-if="mainPrompt.fileConfig.asset"
94
+ v-if="
95
+ mainPrompt.fileConfig.asset &&
96
+ mainPrompt.fileConfig.asset.file_asset_id
97
+ "
97
98
  class="dragArea list-group"
98
99
  :key="mainPrompt['prompt']"
99
100
  v-bind="dragOptions"
@@ -111,7 +112,7 @@
111
112
  v-model="mainPrompt['fileConfig']"
112
113
  :assets="block.assets"
113
114
  max-height="400"
114
- max-width="300"
115
+ :max-width="maxWidth"
115
116
  ></ImageAssetViewer>
116
117
  </div>
117
118
  </draggable>
@@ -130,7 +131,7 @@
130
131
  startingIndex
131
132
  ].textOrImage === 'text'
132
133
  "
133
- class="pa-2 flex-fill bucket"
134
+ class="pa-2 flex-fill card-bucket"
134
135
  min-height="5em"
135
136
  outlined
136
137
  tile
@@ -158,18 +159,25 @@
158
159
  </v-card-text>
159
160
  </v-card>
160
161
  </v-row>
161
- <v-row align="center" class="col-md-10">
162
+ <v-row
163
+ class="d-flex justify-center ma-2"
164
+ v-if="
165
+ block.metadata.config.prompts[startingIndex][
166
+ startingIndex
167
+ ].textOrImage === 'image' &&
168
+ block.metadata.config.prompts[startingIndex][
169
+ startingIndex
170
+ ].fileConfig.asset &&
171
+ block.metadata.config.prompts[startingIndex][
172
+ startingIndex
173
+ ].fileConfig.asset.file_asset_id
174
+ "
175
+ >
162
176
  <v-card
163
- v-if="
164
- block.metadata.config.prompts[startingIndex][
165
- startingIndex
166
- ].textOrImage === 'image' &&
167
- block.metadata.config.prompts[startingIndex][
168
- startingIndex
169
- ].fileConfig.asset
170
- "
171
- class="pa-2 flex-fill bucket"
177
+ class="pa-2 flex-fill card-bucket"
172
178
  min-height="5em"
179
+ max-height="400"
180
+ :max-width="maxWidth"
173
181
  outlined
174
182
  tile
175
183
  >
@@ -201,6 +209,8 @@
201
209
  ][startingIndex].fileConfig
202
210
  "
203
211
  :assets.sync="block.assets"
212
+ max-height="400"
213
+ :max-width="maxWidth"
204
214
  ></ImageAssetViewer>
205
215
  </div>
206
216
  </draggable>
@@ -211,7 +221,7 @@
211
221
  <v-row>
212
222
  <draggable
213
223
  v-bind="dragOptions"
214
- class="d-flex justify-space-between flex-wrap col-md-12"
224
+ class="d-flex justify-space-between flex-wrap col-md-12 no-select"
215
225
  :list="block.metadata.config.answerObjects"
216
226
  :disabled="!allowDrag"
217
227
  :group="{
@@ -219,6 +229,8 @@
219
229
  pull: 'clone',
220
230
  put: false,
221
231
  }"
232
+ :forceFallback="true"
233
+ :sort="false"
222
234
  @end="onEnd"
223
235
  >
224
236
  <v-card
@@ -279,7 +291,7 @@
279
291
  outlined
280
292
  elevation="0"
281
293
  @click="onReset"
282
- >
294
+ >
283
295
  {{ $t('shared.forms.reset') }}
284
296
  </v-btn>
285
297
  </v-col>
@@ -359,6 +371,15 @@ export default {
359
371
  totalAmountQuestions() {
360
372
  return _.flatten(this.block.metadata.config.prompts).length
361
373
  },
374
+ maxWidth() {
375
+ if (window.innerWidth <= 430 && window.innerWidth >= 378) {
376
+ return '250'
377
+ } else if (window.innerWidth <= 378) {
378
+ return '200'
379
+ } else {
380
+ return '300'
381
+ }
382
+ },
362
383
  },
363
384
  data() {
364
385
  return {
@@ -387,6 +408,8 @@ export default {
387
408
  render(newVal) {
388
409
  if (newVal === true) {
389
410
  this.onReset()
411
+ } else if (newVal === false) {
412
+ this.allowDrag = false
390
413
  }
391
414
  },
392
415
  value(newValue) {
@@ -439,75 +462,58 @@ export default {
439
462
  }
440
463
  },
441
464
  onEnd(evt, originalEvent) {
442
- // if dragged to nowhere do not set target
443
- const draggedToNowhere = evt.to === evt.from
444
465
  if (!this.render) {
445
466
  this.mainPrompt =
446
467
  this.block.metadata.config.prompts[this.startingIndex]
447
468
  }
448
- let draggedElement = ''
449
- let target = ''
450
- if (!draggedToNowhere) {
451
- if (this.mainPrompt.textOrImage === 'text') {
452
- draggedElement =
453
- this.block.metadata.config.answerObjects[evt.oldIndex]
454
- this.block.metadata.config.prompts.forEach(
455
- (outerElement) => {
456
- const getMain = outerElement.find((element) => {
457
- return (
458
- element.prompt ==
459
- evt.to.firstChild.textContent.trim()
460
- )
461
- })
462
- if (getMain) {
463
- target = getMain
464
- }
465
- }
466
- )
467
- } else {
468
- draggedElement =
469
- this.block.metadata.config.answerObjects[evt.oldIndex]
470
- this.block.metadata.config.prompts.forEach(
471
- (outerElement) => {
472
- const mainElement = outerElement.find((element) => {
473
- return (
474
- element.fileConfig.asset?.file_asset_id ==
475
- evt.to.firstElementChild.id
476
- )
477
- })
478
- if (mainElement) {
479
- target = mainElement
480
- }
481
- }
482
- )
483
- }
469
+ // If dragged to the same container, do nothing
470
+ if (evt.to === evt.from) {
471
+ return
484
472
  }
473
+
474
+ const { answerObjects, prompts } = this.block.metadata.config
475
+ const draggedElement = answerObjects[evt.oldIndex]
476
+ // flatten nested prompts array and then find target by either text or image
477
+ let target = prompts
478
+ .flatMap((outerElement) => outerElement)
479
+ .find((element) =>
480
+ this.mainPrompt.textOrImage === 'text'
481
+ ? element.prompt ===
482
+ evt.to.firstChild?.textContent.trim()
483
+ : element.fileConfig.asset?.file_asset_id ===
484
+ evt.to.firstElementChild?.id
485
+ )
486
+
487
+ this.setFeedback(target, draggedElement)
488
+ },
489
+ setFeedback(target, draggedElement) {
485
490
  //set feedback information here
486
491
  if (_.isUndefined(target) || _.isEmpty(target)) {
487
492
  this.droppedElement = null
488
- } else if (draggedElement.id !== target.answer.id) {
493
+ // avoids unnecessary computing below
494
+ return
495
+ }
496
+
497
+ const isCorrect = draggedElement.id === target.answer.id
498
+
499
+ if (!isCorrect) {
489
500
  this.feedback = this.block.metadata.config.feedback_incorrect
490
501
  this.status = 'container-error-outline'
491
- this.allowDrag = false
492
- this.droppedElement = draggedElement
493
- } else if (draggedElement.id === target.answer.id) {
502
+ } else if (isCorrect) {
494
503
  this.feedback = !_.isEmpty(target.matchExplanation)
495
504
  ? target.matchExplanation
496
505
  : this.block.metadata.config.feedback_correct
497
506
  this.solvedQuestions.push(target)
498
507
  this.status = 'container-success-outline'
499
- this.allowDrag = false
500
- this.droppedElement = draggedElement
508
+ // checks if game is completed
501
509
  if (
502
510
  this.solvedQuestions.length === this.flattenedPrompts.length
503
511
  ) {
504
- this.feedback = this.$t(
505
- 'windward.games.components.content.blocks.matching_game.congratulations_feedback'
506
- )
507
512
  this.gameCompleted = true
508
- this.status = 'default'
509
513
  }
510
514
  }
515
+ this.allowDrag = false
516
+ this.droppedElement = draggedElement
511
517
  },
512
518
  onExitFeedback() {
513
519
  this.status = 'default'
@@ -519,7 +525,8 @@ export default {
519
525
  },
520
526
  onContinueGame() {
521
527
  if (!this.render) {
522
- this.startingIndex = this.startingIndex + 1
528
+ // do nothing cannot play in editing mode
529
+ return
523
530
  }
524
531
  this.status = 'default'
525
532
  this.mainPrompt = this.shufflePrompts.shift()
@@ -545,7 +552,14 @@ export default {
545
552
  }
546
553
  </script>
547
554
  <style scoped>
548
- .bucket {
555
+ .no-select {
556
+ user-select: none;
557
+ }
558
+ .dragArea {
559
+ min-height: 100%;
560
+ min-width: 100%;
561
+ }
562
+ .card-bucket {
549
563
  line-height: 1.1em;
550
564
  padding: 0.5em;
551
565
  box-shadow: 0px 2px 3px #0000004a;
@@ -118,6 +118,7 @@
118
118
  <div
119
119
  :ref="'input' + splitIndex"
120
120
  class="container-text-area ml-1 mr-1"
121
+ :class="getContainerStatus(letter)"
121
122
  maxlength="1"
122
123
  >
123
124
  <div v-if="letter.show === true">
@@ -302,6 +303,17 @@ export default {
302
303
  this.block.metadata.config.currentWord = newIndex
303
304
  this.onSlideChanged(newIndex)
304
305
  },
306
+ getContainerStatus(letter) {
307
+ if (
308
+ !_.isEmpty(letter.letter) &&
309
+ letter.letter !== ' ' &&
310
+ letter.letter !== '-'
311
+ ) {
312
+ return 'letter-underline '
313
+ } else if (letter.letter === '-') {
314
+ letter.show = true
315
+ }
316
+ },
305
317
  onChange(input) {
306
318
  this.input = input
307
319
  },
@@ -427,7 +439,11 @@ export default {
427
439
  this.block.metadata.config.words[
428
440
  this.onSlide
429
441
  ].splitWord.forEach((letter) => {
430
- if (letter.letter && letter.letter !== ' ') {
442
+ if (
443
+ letter.letter &&
444
+ letter.letter !== ' ' &&
445
+ letter.letter !== '-'
446
+ ) {
431
447
  letter.show = false
432
448
  }
433
449
  })
@@ -459,11 +475,13 @@ export default {
459
475
  .container-text-area {
460
476
  width: 20px;
461
477
  height: 20px;
462
- border-bottom: 2px solid var(--v-primary-base);
463
478
  display: flex;
464
479
  justify-content: center;
465
480
  align-items: center;
466
481
  }
482
+ .letter-underline {
483
+ border-bottom: 2px solid var(--v-primary-base);
484
+ }
467
485
  .container-strike-area {
468
486
  color: gray;
469
487
  font-size: 40px;
@@ -71,6 +71,12 @@
71
71
  </div>
72
72
  <div class="pl-15 pr-15 container-image">
73
73
  <ImageAssetViewer
74
+ v-if="
75
+ block.metadata.config.slides[index]
76
+ .fileConfig.asset &&
77
+ block.metadata.config.slides[index]
78
+ .fileConfig.asset.file_asset_id
79
+ "
74
80
  v-model="
75
81
  block.metadata.config.slides[index]
76
82
  .fileConfig
@@ -208,21 +208,12 @@ export default {
208
208
  // check against lowercase keyboard inputs
209
209
  if (element.value) {
210
210
  element.value = element.value.toLowerCase()
211
- element.splitWord = element.value.split('')
212
- element.splitWord.forEach((letter) => {
213
- const letterIndex = element.splitWord.indexOf(letter)
214
- if (letter !== ' ') {
215
- element.splitWord[letterIndex] = {
216
- letter: letter,
217
- show: false,
218
- }
219
- } else {
220
- element.splitWord[letterIndex] = {
221
- letter: letter,
222
- show: true,
223
- }
224
- }
225
- })
211
+ element.splitWord = element.value
212
+ .split('')
213
+ .map((letter, index) => ({
214
+ letter,
215
+ show: letter === ' ' || letter === '-',
216
+ }))
226
217
  }
227
218
  })
228
219
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/games",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "Windward UI Plugin Games",
5
5
  "main": "plugin.js",
6
6
  "scripts": {