@windward/games 0.9.0 → 0.10.0

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,8 @@
1
1
  # Changelog
2
2
 
3
+ ### Release [0.10.0] created - 2025-01-03
4
+
5
+
3
6
  ## Release [0.7.0] - 2024-08-29
4
7
 
5
8
  * Version bump to 0.7.0
@@ -27,36 +27,39 @@
27
27
  )
28
28
  }}
29
29
  </h4>
30
- <v-container fluid :class="status">
31
- <v-row class="pa-4">
32
- <v-col></v-col>
33
- <v-col class="d-flex justify-center align-center">{{
30
+ <v-alert fluid :class="status">
31
+ <v-row class="pa-4 d-flex justify-center">
32
+ {{
34
33
  feedback
35
34
  ? feedback
36
35
  : $t(
37
36
  'windward.games.components.content.blocks.bucket_game.form.feedback.feedback_here'
38
37
  )
39
- }}</v-col>
40
- <v-col class="d-flex justify-end pl-4">
41
- <v-btn
42
- v-if="status === 'container-success-outline'"
43
- class="mr-5"
44
- color="success"
45
- elevation="0"
46
- @click="continueGame"
47
- >{{ $t('shared.forms.continue') }}
48
- </v-btn>
49
- <v-container
50
- v-if="status === 'container-error-outline'"
51
- class="d-flex justify-end"
52
- @click="continueGame"
53
- ><v-icon class="icon--error" color="error"
54
- >mdi-close-circle</v-icon
55
- >
56
- </v-container>
57
- </v-col>
38
+ }}
58
39
  </v-row>
59
- </v-container>
40
+ <v-row class="d-flex justify-center mt-0 mb-1">
41
+ <v-btn
42
+ v-if="
43
+ status === 'container-success-outline' &&
44
+ mainAnswer.length !== 0
45
+ "
46
+ color="success"
47
+ elevation="0"
48
+ @click="continueGame"
49
+ >{{ $t('shared.forms.continue') }}
50
+ </v-btn>
51
+ <v-btn
52
+ v-if="status === 'container-error-outline'"
53
+ color="error"
54
+ @click="continueGame"
55
+ >{{
56
+ $t(
57
+ 'windward.games.components.content.blocks.bucket_game.try_again'
58
+ )
59
+ }}
60
+ </v-btn>
61
+ </v-row>
62
+ </v-alert>
60
63
  <div v-if="render">
61
64
  <v-container>
62
65
  <draggable
@@ -494,16 +497,21 @@ export default {
494
497
  bucket_index
495
498
  )
496
499
  ) {
497
- this.feedback = evt.added.element.feedback
498
- ? evt.added.element.feedback
499
- : this.block.metadata.config.feedback_correct
500
+ // set correct feedback
501
+ if (evt.added.element.feedback) {
502
+ this.feedback = evt.added.element.feedback
503
+ } else {
504
+ this.feedback = this.block.metadata.config.feedback_correct
505
+ ? this.block.metadata.config.feedback_correct
506
+ : this.$t(
507
+ 'windward.games.components.settings.bucket_game.form.feedback.correct_default'
508
+ )
509
+ }
500
510
  // determines if answer is correct and then sees if that was the last answer
501
511
  // needs to be nested in here because this.mainAnswer is bound to :list on draggable
502
512
  // list changes the array so when it is using the last object in the array it looks like the array is empty
503
513
  if (this.mainAnswer.length === 0) {
504
- this.feedback = this.$t(
505
- 'windward.games.components.content.blocks.matching_game.congratulations_feedback'
506
- )
514
+ this.status = 'container-success-outline'
507
515
  this.block.metadata.config.bucket_titles[
508
516
  bucket_index
509
517
  ].nested_answers.push(evt.added.element)
@@ -512,24 +520,13 @@ export default {
512
520
  this.block.metadata.config.bucket_titles[
513
521
  bucket_index
514
522
  ].nested_answers.push(evt.added.element)
515
- // set correct feedback
516
- if (evt.added.element.feedback) {
517
- this.feedback = evt.added.element.feedback
518
- } else {
519
- this.feedback = this.block.metadata.config
520
- .feedback_correct
521
- ? this.block.metadata.config.feedback_correct
522
- : this.$t(
523
- 'windward.games.components.settings.bucket_game.form.feedback.correct_default'
524
- )
525
- }
526
523
  }
527
524
  } else {
528
525
  let items = this.items[bucket_index]
529
526
  const indexOfAddedElement = items.indexOf(evt.added.element)
530
527
  this.items[bucket_index].splice(indexOfAddedElement, 1)
531
528
  // puts item back into mutable array for draggable component
532
- this.mainAnswer.push(evt.added.element)
529
+ this.mainAnswer.unshift(evt.added.element)
533
530
  // set incorrect feedback
534
531
  this.feedback = this.block.metadata.config.feedback_incorrect
535
532
  ? this.block.metadata.config.feedback_incorrect
@@ -598,6 +595,7 @@ export default {
598
595
  color: black;
599
596
  box-shadow: 0px 2px 3px #0000004a;
600
597
  border-radius: 2px;
598
+ line-height: 50px !important;
601
599
  }
602
600
  .container-buckets {
603
601
  color: black;
@@ -618,4 +616,7 @@ export default {
618
616
  overflow-x: hidden !important;
619
617
  }
620
618
  }
619
+ .container-outline {
620
+ cursor: grab;
621
+ }
621
622
  </style>
@@ -1,25 +1,22 @@
1
1
  <template>
2
2
  <v-container>
3
3
  <br />
4
- <div class="card-content">
4
+ <div
5
+ class="card-content d-flex flex-column align-center justify-center"
6
+ >
5
7
  <v-row>
6
8
  <content-viewer :class="textClass" v-model="settings.text" />
7
9
  </v-row>
8
10
  <br />
9
- <v-row
10
- v-if="imagePublicUrl"
11
- no-gutters
12
- align="center"
13
- justify="center"
14
- >
15
- <v-img
16
- contain
17
- :aspect-ratio="16 / 9"
18
- :src="imagePublicUrl"
19
- :alt="imageAlt"
20
- max-height="210"
21
- max-width="600"
22
- />
11
+ <v-row v-if="settings.fileConfig" no-gutters>
12
+ <v-col>
13
+ <ImageAssetViewer
14
+ v-model="settings.fileConfig"
15
+ :assets="assets"
16
+ max-height="210"
17
+ max-width="250"
18
+ ></ImageAssetViewer>
19
+ </v-col>
23
20
  </v-row>
24
21
  <br />
25
22
  </div>
@@ -34,10 +31,11 @@
34
31
  import _ from 'lodash'
35
32
  import { MathHelper, ContentViewer } from '@windward/core/utils'
36
33
  import Uuid from '~/helpers/Uuid'
34
+ import ImageAssetViewer from '~/components/Content/ImageAssetViewer.vue'
37
35
 
38
36
  export default {
39
37
  name: 'CardFace',
40
- components: { ContentViewer },
38
+ components: { ContentViewer, ImageAssetViewer },
41
39
  props: {
42
40
  settings: { type: Object, required: true },
43
41
  side: { type: String, required: true },
@@ -46,7 +44,7 @@ export default {
46
44
  computed: {
47
45
  textClass() {
48
46
  if (
49
- !this.settings.imageAsset &&
47
+ !this.settings.fileConfig &&
50
48
  this.settings.text &&
51
49
  this.settings.text.length < 100 &&
52
50
  this.side === 'front'
@@ -58,7 +56,7 @@ export default {
58
56
  return 'text-center card-content--bold'
59
57
  }
60
58
  if (
61
- !this.settings.imageAsset &&
59
+ !this.settings.fileConfig &&
62
60
  this.settings.text &&
63
61
  (MathHelper.containsMathML(this.settings.text.length) ||
64
62
  MathHelper.containsLatex(this.settings.text.length))
@@ -68,51 +66,18 @@ export default {
68
66
 
69
67
  return 'px-6 text-left'
70
68
  },
71
- imageAsset() {
72
- if (!this.settings.imageAsset) {
73
- return null
74
- }
75
-
76
- let image = _.cloneDeep(this.settings.imageAsset)
77
-
78
- // If the file is linked then resolve it first
79
- // Otherwise it's a hard link that we can just return
80
- if (image && image.file_asset_id !== null) {
81
- image = this.getAssetByFileAssetId(image.file_asset_id)
82
- }
83
- return image
84
- },
85
- imagePublicUrl() {
86
- return _.get(this.imageAsset, 'asset.public_url', '')
87
- },
88
- imageAlt() {
89
- // Default to user defined alt but fallback to global alt
90
- if (this.settings.imageAlt) {
91
- return this.settings.imageAlt
92
- } else {
93
- return _.get(this.imageAsset, 'asset.metadata.props.alt', '')
94
- }
95
- },
96
69
  },
97
- methods: {
98
- getAssetByFileAssetId(fileAssetId) {
99
- // Not a uuid. Instant fail
100
- if (!Uuid.test(fileAssetId)) {
101
- return null
102
- }
103
- const foundAsset = this.assets.find((asset) => {
104
- return _.get(asset, 'file_asset_id', null) === fileAssetId
105
- })
106
-
107
- return foundAsset || null
108
- },
70
+ beforeMount() {
71
+ // so background isn't set to white by the imageassetviewer
72
+ if (_.isEmpty(this.settings.fileConfig)) {
73
+ this.settings.fileConfig = {}
74
+ this.settings.fileConfig.hideBackground = true
75
+ }
109
76
  },
110
77
  }
111
78
  </script>
112
79
 
113
80
  <style lang="scss" scoped>
114
- .card-header {
115
- }
116
81
  .card-content {
117
82
  color: var(--v-primary-base);
118
83
  font-size: 1rem;
@@ -1,6 +1,11 @@
1
1
  <template>
2
2
  <v-container style="height: 100%" class="div-container">
3
- <v-card outlined @click="toggleCard" v-show="side" :class="cardClass">
3
+ <v-card
4
+ outlined
5
+ @click="toggleCard"
6
+ v-show="side"
7
+ :class="cardClass"
8
+ >
4
9
  <v-card-text>
5
10
  <CardFace
6
11
  side="front"
@@ -51,15 +56,15 @@ export default {
51
56
  }
52
57
 
53
58
  if (
54
- this.frontFace.imageAsset === '' &&
55
- this.backFace.imageAsset === ''
59
+ this.frontFace.fileConfig === '' &&
60
+ this.backFace.fileConfig === ''
56
61
  ) {
57
62
  result = result + ' flashcard--size-md'
58
63
  }
59
64
 
60
65
  if (
61
- this.frontFace.imageAsset !== '' ||
62
- this.backFace.imageAsset !== ''
66
+ this.frontFace.fileConfig !== '' ||
67
+ this.backFace.fileConfig !== ''
63
68
  ) {
64
69
  result = result + ' flashcard--size-lg'
65
70
  }
@@ -68,10 +73,7 @@ export default {
68
73
  },
69
74
  frontFace() {
70
75
  return {
71
- imageAsset: this.options.front.imageAsset,
72
- imageAlt: this.options.front.imageAlt
73
- ? this.options.front.imageAlt
74
- : '',
76
+ fileConfig: this.options.front.fileConfig,
75
77
  text: this.options.front.text,
76
78
  header: this.options.front.header,
77
79
  footer: this.$t(
@@ -81,10 +83,7 @@ export default {
81
83
  },
82
84
  backFace() {
83
85
  return {
84
- imageAsset: this.options.back.imageAsset,
85
- imageAlt: this.options.back.imageAlt
86
- ? this.options.back.imageAlt
87
- : '',
86
+ fileConfig: this.options.back.fileConfig,
88
87
  text: this.options.back.text,
89
88
  header: this.options.back.header,
90
89
  footer: this.$t(
@@ -71,6 +71,7 @@
71
71
  block.metadata.config.bucket_titles[index]
72
72
  .title
73
73
  "
74
+ :data-key="'bucket-' + index + '-title'"
74
75
  :disabled="render"
75
76
  ></TextEditor>
76
77
  </v-flex>
@@ -143,6 +144,13 @@
143
144
  answerIndex
144
145
  ].display
145
146
  "
147
+ :data-key="
148
+ 'bucket-answer-' +
149
+ index +
150
+ '-' +
151
+ answerIndex +
152
+ '-display'
153
+ "
146
154
  :disabled="render"
147
155
  ></TextEditor>
148
156
  <p class="p-label mb-0">
@@ -354,7 +362,7 @@ export default {
354
362
  title: '',
355
363
  color: colors.blueGrey.lighten5,
356
364
  expand: true,
357
- nested_answers: []
365
+ nested_answers: [],
358
366
  }
359
367
  this.block.metadata.config.bucket_titles.push(emptyString)
360
368
  },
@@ -145,6 +145,7 @@
145
145
  block.metadata.config.cards[index].front
146
146
  .text
147
147
  "
148
+ :data-key="'flashcard-' + index + '-front'"
148
149
  outlined
149
150
  auto-grow
150
151
  menubar="edit"
@@ -157,51 +158,17 @@
157
158
  required
158
159
  :disabled="render"
159
160
  ></TextEditor>
160
-
161
- <ContentBlockAsset
161
+ <ImageAssetSettings
162
162
  v-model="
163
163
  block.metadata.config.cards[index].front
164
- .imageAsset
164
+ .fileConfig
165
165
  "
166
- mimes="image/png,image/jpeg"
167
- outlined
168
166
  :assets.sync="block.assets"
167
+ hide-background
168
+ hide-decorative
169
+ hide-modal
169
170
  :disabled="render"
170
- >
171
- <template #title>
172
- {{
173
- $t(
174
- 'windward.games.shared.settings.file_picker.image'
175
- )
176
- }}
177
- </template>
178
- <template #description>
179
- {{
180
- $t(
181
- 'windward.games.components.settings.flashcard.form.image.configure_blurb'
182
- )
183
- }}
184
- </template>
185
- </ContentBlockAsset>
186
-
187
- <v-text-field
188
- v-model="
189
- block.metadata.config.cards[index].front
190
- .imageAlt
191
- "
192
- auto-grow
193
- outlined
194
- :label="$t('shared.accessibility.alt_text')"
195
- required
196
- :placeholder="
197
- getImageAlt(
198
- block.metadata.config.cards[index].front
199
- .imageAsset
200
- )
201
- "
202
- persistent-placeholder
203
- :disabled="render"
204
- ></v-text-field>
171
+ ></ImageAssetSettings>
205
172
  </v-card>
206
173
 
207
174
  <!-- The back card -->
@@ -221,6 +188,7 @@
221
188
  block.metadata.config.cards[index].back
222
189
  .text
223
190
  "
191
+ :data-key="'flashcard-' + index + '-back'"
224
192
  outlined
225
193
  auto-grow
226
194
  menubar="edit"
@@ -230,49 +198,16 @@
230
198
  :disabled="render"
231
199
  ></TextEditor>
232
200
 
233
- <ContentBlockAsset
201
+ <ImageAssetSettings
234
202
  v-model="
235
203
  block.metadata.config.cards[index].back
236
- .imageAsset
204
+ .fileConfig
237
205
  "
238
- mimes="image/png,image/jpeg"
239
- outlined
240
206
  :assets.sync="block.assets"
241
- :disabled="render"
242
- >
243
- <template #title>
244
- {{
245
- $t(
246
- 'windward.games.shared.settings.file_picker.image'
247
- )
248
- }}
249
- </template>
250
- <template #description>
251
- {{
252
- $t(
253
- 'windward.games.components.settings.flashcard.form.image.configure_blurb'
254
- )
255
- }}
256
- </template>
257
- </ContentBlockAsset>
258
- <v-text-field
259
- v-model="
260
- block.metadata.config.cards[index].back
261
- .imageAlt
262
- "
263
- auto-grow
264
- outlined
265
- :label="$t('shared.accessibility.alt_text')"
266
- required
267
- :placeholder="
268
- getImageAlt(
269
- block.metadata.config.cards[index]
270
- .back.imageAsset
271
- )
272
- "
273
- persistent-placeholder
274
- :disabled="render"
275
- ></v-text-field>
207
+ hide-background
208
+ hide-decorative
209
+ hide-modal
210
+ ></ImageAssetSettings>
276
211
  </v-card-text>
277
212
  </v-card>
278
213
  <v-row
@@ -356,6 +291,7 @@ import ContentBlockAsset from '~/components/Content/ContentBlockAsset.vue'
356
291
  import TextEditor from '~/components/Text/TextEditor.vue'
357
292
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
358
293
  import Uuid from '~/helpers/Uuid'
294
+ import ImageAssetSettings from '~/components/Content/Settings/ImageAssetSettings.vue'
359
295
 
360
296
  export default {
361
297
  name: 'FlashCardSlidesManager',
@@ -367,6 +303,7 @@ export default {
367
303
  ContentBlockAsset,
368
304
  TextEditor,
369
305
  SortableExpansionPanel,
306
+ ImageAssetSettings,
370
307
  },
371
308
  data() {
372
309
  return {
@@ -407,16 +344,18 @@ export default {
407
344
  defaultCard() {
408
345
  return {
409
346
  front: {
410
- imageAsset: null,
347
+ fileConfig: {
348
+ hideBackground: true,
349
+ },
411
350
  header: '',
412
351
  text: '',
413
- imageAlt: '',
414
352
  },
415
353
  back: {
416
- imageAsset: null,
354
+ fileConfig: {
355
+ hideBackground: true,
356
+ },
417
357
  header: '',
418
358
  text: '',
419
- imageAlt: '',
420
359
  },
421
360
  expand: false,
422
361
  title: '',
@@ -437,20 +376,20 @@ export default {
437
376
  for (const item of items) {
438
377
  if (
439
378
  Uuid.test(
440
- _.get(item, 'item.front.imageAsset.file_asset_id', null)
379
+ _.get(item, 'item.front.fileConfig.file_asset_id', null)
441
380
  )
442
381
  ) {
443
382
  assets.push(
444
- _.get(item, 'item.front.imageAsset.file_asset_id', null)
383
+ _.get(item, 'item.front.fileConfig.file_asset_id', null)
445
384
  )
446
385
  }
447
386
  if (
448
387
  Uuid.test(
449
- _.get(item, 'item.back.imageAsset.file_asset_id', null)
388
+ _.get(item, 'item.back.fileConfig.file_asset_id', null)
450
389
  )
451
390
  ) {
452
391
  assets.push(
453
- _.get(item, 'item.back.imageAsset.file_asset_id', null)
392
+ _.get(item, 'item.back.fileConfig.file_asset_id', null)
454
393
  )
455
394
  }
456
395
  }
@@ -500,10 +439,6 @@ export default {
500
439
  }
501
440
  return htmlString.replace(/(<([^>]+)>)/gi, '')
502
441
  },
503
- getImageAlt(file) {
504
- file = this.resolveAsset(file)
505
- return _.get(file, 'asset.metadata.props.alt', '')
506
- },
507
442
  },
508
443
  }
509
444
  </script>
@@ -38,4 +38,5 @@ export default {
38
38
  'The character count for this field must be less than',
39
39
  },
40
40
  },
41
+ try_again: 'Try again',
41
42
  }
@@ -38,4 +38,5 @@ export default {
38
38
  'El número de caracteres para este campo debe ser menor que',
39
39
  },
40
40
  },
41
+ try_again: 'Intentar otra vez',
41
42
  }
@@ -38,4 +38,5 @@ export default {
38
38
  'Teckenantalet för detta fält måste vara mindre än',
39
39
  },
40
40
  },
41
+ try_again: 'Försök igen',
41
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/games",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Windward UI Plugin Games",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
@@ -0,0 +1,94 @@
1
+ import mock_ from 'lodash'
2
+
3
+ jest.mock(
4
+ '~/components/Content/ActionPanel.vue',
5
+ () => {
6
+ return jest.fn().mockImplementation(() => {
7
+ return { test: () => {} }
8
+ })
9
+ },
10
+ { virtual: true }
11
+ )
12
+
13
+ jest.mock(
14
+ '~/components/Content/ContentBlockAsset.vue',
15
+ () => {
16
+ return jest.fn().mockImplementation(() => {
17
+ return { test: () => {} }
18
+ })
19
+ },
20
+ { virtual: true }
21
+ )
22
+
23
+ jest.mock(
24
+ '~/components/Content/ImageAssetViewer.vue',
25
+ () => {
26
+ return jest.fn().mockImplementation(() => {
27
+ return { test: () => {} }
28
+ })
29
+ },
30
+ { virtual: true }
31
+ )
32
+
33
+ jest.mock(
34
+ '~/components/Content/Settings/ImageAssetSettings.vue',
35
+ () => {
36
+ return jest.fn().mockImplementation(() => {
37
+ return { test: () => {} }
38
+ })
39
+ },
40
+ { virtual: true }
41
+ )
42
+
43
+ jest.mock(
44
+ '~/components/Text/TextViewer.vue',
45
+ () => {
46
+ return {
47
+ props: {},
48
+ computed: {
49
+ body() {
50
+ return ''
51
+ },
52
+ },
53
+ data() {
54
+ return {}
55
+ },
56
+ }
57
+ },
58
+ { virtual: true }
59
+ )
60
+ jest.mock(
61
+ '~/components/Text/TextEditor.vue',
62
+ () => {
63
+ return {
64
+ props: {},
65
+ computed: {
66
+ body() {
67
+ return ''
68
+ },
69
+ },
70
+ data() {
71
+ return {}
72
+ },
73
+ }
74
+ },
75
+ { virtual: true }
76
+ )
77
+
78
+ jest.mock(
79
+ '~/components/Core/FileDropZone.vue',
80
+ () => {
81
+ return {
82
+ props: {},
83
+ computed: {
84
+ body() {
85
+ return ''
86
+ },
87
+ },
88
+ data() {
89
+ return {}
90
+ },
91
+ }
92
+ },
93
+ { virtual: true }
94
+ )
package/test/mocks.js CHANGED
@@ -12,5 +12,6 @@ require('./__mocks__/fileMock')
12
12
  require('./__mocks__/styleMock')
13
13
  require('./__mocks__/modelMock')
14
14
  require('./__mocks__/componentsMock')
15
+ require('./__mocks__/contentBlockMock')
15
16
 
16
17
  export const defaultMocks = mocks