@windward/games 0.8.1 → 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.
Files changed (26) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/components/content/blocks/crosswordPuzzle/CrosswordPuzzle.vue +4 -24
  3. package/components/content/blocks/dragDrop/BucketGame.vue +139 -60
  4. package/components/content/blocks/flashcards/CardFace.vue +22 -57
  5. package/components/content/blocks/flashcards/Flashcard.vue +19 -16
  6. package/components/content/blocks/flashcards/FlashcardSlides.vue +13 -38
  7. package/components/content/blocks/matchingGame/MatchingGame.vue +3 -3
  8. package/components/content/blocks/multipleChoice/MultipleChoice.vue +18 -118
  9. package/components/content/blocks/sevenStrikes/SevenStikes.vue +158 -165
  10. package/components/content/blocks/slideshow/SlideShow.vue +49 -99
  11. package/components/content/blocks/wordJumble/WordJumble.vue +122 -129
  12. package/components/settings/BucketGameSettingsManager.vue +9 -0
  13. package/components/settings/FlashCardSlidesManager.vue +26 -91
  14. package/i18n/en-US/components/content/blocks/bucket_game.ts +1 -0
  15. package/i18n/en-US/components/content/blocks/multiple_choice.ts +0 -1
  16. package/i18n/en-US/shared/content_blocks.ts +1 -0
  17. package/i18n/es-ES/components/content/blocks/bucket_game.ts +1 -0
  18. package/i18n/es-ES/components/content/blocks/multiple_choice.ts +0 -1
  19. package/i18n/es-ES/shared/content_blocks.ts +1 -0
  20. package/i18n/sv-SE/components/content/blocks/bucket_game.ts +1 -0
  21. package/i18n/sv-SE/components/content/blocks/multiple_choice.ts +0 -1
  22. package/i18n/sv-SE/shared/content_blocks.ts +1 -0
  23. package/package.json +1 -1
  24. package/test/__mocks__/contentBlockMock.js +94 -0
  25. package/test/mocks.js +1 -0
  26. package/test/settings/BucketGameManager.spec.js +3 -3
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
@@ -501,6 +501,7 @@ export default {
501
501
  .crossword-board-container {
502
502
  position: relative;
503
503
  padding-top: 5px;
504
+ margin-top: 1rem;
504
505
  overflow: auto;
505
506
  }
506
507
 
@@ -595,8 +596,9 @@ export default {
595
596
 
596
597
  .crossword-clues {
597
598
  background: var(--v-content-background-base);
598
- position: sticky;
599
- bottom: 100px;
599
+ max-height: 30vh;
600
+ overflow-y: scroll;
601
+ bottom: 50px;
600
602
  border-radius: 5px;
601
603
  }
602
604
  .crossword-board__item--number {
@@ -613,63 +615,42 @@ export default {
613
615
  width: 500px;
614
616
  height: 500px;
615
617
  }
616
- .crossword-board-container {
617
- box-sizing: content-box !important;
618
- }
619
618
  }
620
619
  @media (max-width: 1480px) {
621
620
  .crossword-col-4 {
622
621
  width: 400px;
623
622
  height: 400px;
624
623
  }
625
- .crossword-board-container {
626
- box-sizing: content-box !important;
627
- }
628
624
  }
629
625
  @media (max-width: 1360px) {
630
626
  .crossword-col-4 {
631
627
  width: 350px;
632
628
  height: 350px;
633
629
  }
634
- .crossword-board-container {
635
- box-sizing: content-box !important;
636
- }
637
630
  }
638
631
  @media (max-width: 1300px) {
639
632
  .crossword-col-4 {
640
633
  width: 300px;
641
634
  height: 300px;
642
635
  }
643
- .crossword-board-container {
644
- box-sizing: content-box !important;
645
- }
646
636
  }
647
637
  @media (max-width: 1263px) {
648
638
  .crossword-col-4 {
649
639
  width: 550px;
650
640
  height: 550px;
651
641
  }
652
- .crossword-board-container {
653
- box-sizing: content-box !important;
654
- }
655
642
  }
656
643
  @media (max-width: 823px) {
657
644
  .crossword-col-4 {
658
645
  width: 400px;
659
646
  height: 400px;
660
647
  }
661
- .crossword-board-container {
662
- box-sizing: content-box !important;
663
- }
664
648
  }
665
649
  @media (max-width: 631px) {
666
650
  .crossword-col-4 {
667
651
  width: 300px;
668
652
  height: 300px;
669
653
  }
670
- .crossword-board-container {
671
- box-sizing: content-box !important;
672
- }
673
654
  }
674
655
  @media (max-width: 565px) {
675
656
  .crossword-col-4 {
@@ -677,7 +658,6 @@ export default {
677
658
  height: 300px;
678
659
  }
679
660
  .crossword-board-container {
680
- box-sizing: content-box !important;
681
661
  padding-top: 12px;
682
662
  padding-left: 12px;
683
663
  }
@@ -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 === 'successOutline'"
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 === 'errorOutline'"
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
@@ -83,15 +86,12 @@
83
86
  </draggable>
84
87
  <br />
85
88
 
86
- <v-row
87
- class="d-flex flex-wrap flex-row justify-center flex-fill"
88
- >
89
- <v-row align="center" class="col-md-10">
89
+ <v-row class="d-flex justify-center mb-2">
90
+ <v-row class="justify-center">
90
91
  <v-card
91
92
  v-for="(bucket, bindex) in items"
92
93
  :key="'b-v-card-' + bindex"
93
- class="pa-2 flex-fill bucket"
94
- min-height="5em"
94
+ class="card-bucket"
95
95
  outlined
96
96
  tile
97
97
  :color="
@@ -103,7 +103,7 @@
103
103
  "
104
104
  >
105
105
  <v-card-text
106
- class="d-flex justify-center text-center"
106
+ class="d-flex justify-center text-center pl-0 pr-0"
107
107
  >
108
108
  <draggable
109
109
  v-model="items[bindex]"
@@ -113,14 +113,30 @@
113
113
  @change="change($event, bindex)"
114
114
  :move="checkMove"
115
115
  tabindex="0"
116
+ class="draggable-bucket"
116
117
  >
117
118
  <TextViewer
118
119
  v-model="
119
120
  block.metadata.config
120
121
  .bucket_titles[bindex].title
121
122
  "
122
- class="d-flex align-center"
123
+ class="d-flex align-center justify-center container-buckets"
123
124
  ></TextViewer>
125
+ <v-container
126
+ v-for="(
127
+ nested_answer, nested_index
128
+ ) in block.metadata.config
129
+ .bucket_titles[bindex]
130
+ .nested_answers"
131
+ :key="nested_index"
132
+ class="d-flex justify-center align-center pa-0"
133
+ >
134
+ <TextViewer
135
+ class="container-nested-answers mb-1"
136
+ v-model="nested_answer.display"
137
+ remove-root-element
138
+ ></TextViewer>
139
+ </v-container>
124
140
  </draggable>
125
141
  </v-card-text>
126
142
  </v-card>
@@ -166,12 +182,15 @@
166
182
  <v-row
167
183
  class="d-flex flex-wrap flex-row justify-center flex-fill"
168
184
  >
169
- <v-row align="center" class="col-md-10">
185
+ <v-row
186
+ align="center"
187
+ class="col-md-10 justify-space-around"
188
+ >
170
189
  <v-card
171
190
  v-for="(bucket, bindex) in block.metadata.config
172
191
  .bucket_titles"
173
192
  :key="'b-v-card-' + bindex"
174
- class="pa-2 flex-fill bucket"
193
+ class="pa-2 card-bucket"
175
194
  min-height="5em"
176
195
  outlined
177
196
  tile
@@ -198,7 +217,7 @@
198
217
  ].title
199
218
  "
200
219
  class="d-flex align-center"
201
- ></TextViewer> </draggable
220
+ ></TextViewer></draggable
202
221
  ></v-card-text>
203
222
  </v-card>
204
223
  </v-row>
@@ -295,6 +314,17 @@ export default {
295
314
  if (_.isEmpty(this.block.metadata.config.bucket_titles)) {
296
315
  this.block.metadata.config.bucket_titles = []
297
316
  }
317
+ if (
318
+ this.block.metadata.config.bucket_titles &&
319
+ this.block.metadata.config.bucket_titles[0] &&
320
+ _.isEmpty(
321
+ this.block.metadata.config.bucket_titles[0].nested_answers
322
+ )
323
+ ) {
324
+ this.block.metadata.config.bucket_titles.forEach((bucket) => {
325
+ bucket.nested_answers = []
326
+ })
327
+ }
298
328
  if (_.isEmpty(this.block.metadata.config.bucket_answers)) {
299
329
  this.block.metadata.config.bucket_answers = []
300
330
  }
@@ -331,6 +361,7 @@ export default {
331
361
  },
332
362
  completedPercent() {
333
363
  if (
364
+ this.block.metadata.config.bucket_answers &&
334
365
  this.block.metadata.config.bucket_answers.length > 0 &&
335
366
  this.items.length > 0
336
367
  ) {
@@ -347,10 +378,16 @@ export default {
347
378
  },
348
379
  },
349
380
  mounted() {
350
- if (this.block.metadata.config.bucket_answers.length > 0) {
381
+ if (
382
+ this.block.metadata.config.bucket_answers &&
383
+ this.block.metadata.config.bucket_answers.length > 0
384
+ ) {
351
385
  this.setMainAnswer()
352
386
  }
353
- if (this.block.metadata.config.bucket_titles.length > 0) {
387
+ if (
388
+ this.block.metadata.config.bucket_titles &&
389
+ this.block.metadata.config.bucket_titles.length > 0
390
+ ) {
354
391
  this.setUpGame()
355
392
  }
356
393
  this.status = 'default'
@@ -460,43 +497,43 @@ export default {
460
497
  bucket_index
461
498
  )
462
499
  ) {
463
- this.feedback = evt.added.element.feedback
464
- ? evt.added.element.feedback
465
- : 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
+ }
466
510
  // determines if answer is correct and then sees if that was the last answer
467
511
  // needs to be nested in here because this.mainAnswer is bound to :list on draggable
468
512
  // list changes the array so when it is using the last object in the array it looks like the array is empty
469
513
  if (this.mainAnswer.length === 0) {
470
- this.feedback = this.$t(
471
- 'windward.games.components.content.blocks.matching_game.congratulations_feedback'
472
- )
514
+ this.status = 'container-success-outline'
515
+ this.block.metadata.config.bucket_titles[
516
+ bucket_index
517
+ ].nested_answers.push(evt.added.element)
473
518
  } else {
474
- this.status = 'successOutline'
475
- // set correct feedback
476
- if (evt.added.element.feedback) {
477
- this.feedback = evt.added.element.feedback
478
- } else {
479
- this.feedback = this.block.metadata.config
480
- .feedback_correct
481
- ? this.block.metadata.config.feedback_correct
482
- : this.$t(
483
- 'windward.games.components.settings.bucket_game.form.feedback.correct_default'
484
- )
485
- }
519
+ this.status = 'container-success-outline'
520
+ this.block.metadata.config.bucket_titles[
521
+ bucket_index
522
+ ].nested_answers.push(evt.added.element)
486
523
  }
487
524
  } else {
488
525
  let items = this.items[bucket_index]
489
526
  const indexOfAddedElement = items.indexOf(evt.added.element)
490
527
  this.items[bucket_index].splice(indexOfAddedElement, 1)
491
528
  // puts item back into mutable array for draggable component
492
- this.mainAnswer.push(evt.added.element)
529
+ this.mainAnswer.unshift(evt.added.element)
493
530
  // set incorrect feedback
494
531
  this.feedback = this.block.metadata.config.feedback_incorrect
495
532
  ? this.block.metadata.config.feedback_incorrect
496
533
  : this.$t(
497
534
  'windward.games.components.settings.bucket_game.form.feedback.incorrect_default'
498
535
  )
499
- this.status = 'errorOutline'
536
+ this.status = 'container-error-outline'
500
537
  }
501
538
  },
502
539
  continueGame() {
@@ -509,6 +546,9 @@ export default {
509
546
  for (const index in this.block.metadata.config.bucket_answers) {
510
547
  this.items[index] = []
511
548
  }
549
+ this.block.metadata.config.bucket_titles.forEach((element) => {
550
+ element.nested_answers = []
551
+ })
512
552
  this.status = 'default'
513
553
  this.feedback = ''
514
554
  this.allow_drag = true
@@ -518,26 +558,65 @@ export default {
518
558
  }
519
559
  </script>
520
560
  <style scoped>
521
- .successOutline {
561
+ .container-success-outline {
522
562
  border: 4px solid var(--v-success-base);
523
563
  color: var(--v-success-base);
524
564
  }
525
- .errorOutline {
565
+ .container-error-outline {
526
566
  border: 4px solid var(--v-error-base);
527
567
  color: var(--v-error-base);
528
568
  }
529
569
  .span-bold {
530
570
  font-weight: bold;
531
571
  }
532
- .bucket {
572
+ .card-bucket {
533
573
  line-height: 1.1em;
534
574
  padding: 0.5em;
535
575
  box-shadow: 0px 2px 3px #0000004a;
536
576
  transition: 0.5s box-shadow;
537
577
  margin: 1%;
578
+ max-width: 12vw;
579
+ min-width: 12vw;
580
+ color: black !important;
538
581
  }
539
582
  .card_text {
540
583
  font-size: large;
541
584
  color: black;
542
585
  }
586
+ .container-nested-answers {
587
+ max-width: 10vw;
588
+ min-width: 10vw;
589
+ padding-left: 4px;
590
+ padding-right: 4px;
591
+ overflow: hidden;
592
+ white-space: nowrap;
593
+ text-overflow: ellipsis;
594
+ background-color: white;
595
+ color: black;
596
+ box-shadow: 0px 2px 3px #0000004a;
597
+ border-radius: 2px;
598
+ line-height: 50px !important;
599
+ }
600
+ .container-buckets {
601
+ color: black;
602
+ }
603
+ .draggable-bucket {
604
+ width: 100%;
605
+ }
606
+ @media (max-width: 600px) {
607
+ .card-bucket {
608
+ width: 40vh;
609
+ max-width: 40vh;
610
+ }
611
+ .container-nested-answers {
612
+ display: block !important;
613
+ width: 100%;
614
+ max-width: 100%;
615
+ min-width: 100%;
616
+ overflow-x: hidden !important;
617
+ }
618
+ }
619
+ .container-outline {
620
+ cursor: grab;
621
+ }
543
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="value" :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"
@@ -9,7 +14,7 @@
9
14
  ></CardFace>
10
15
  </v-card-text>
11
16
  </v-card>
12
- <v-card outlined @click="toggleCard" v-show="!value" :class="cardClass">
17
+ <v-card outlined @click="toggleCard" v-show="!side" :class="cardClass">
13
18
  <v-card-title class="card-title">
14
19
  <v-row align="center" justify="center">{{
15
20
  backFace.header
@@ -34,10 +39,10 @@ export default {
34
39
  return {
35
40
  settings: {},
36
41
  flip: false,
42
+ side: true,
37
43
  }
38
44
  },
39
45
  props: {
40
- value: { type: Boolean, required: false, default: false },
41
46
  options: { type: Object, default: {} },
42
47
  slide: { type: Number, required: true, default: 0 },
43
48
  assets: { type: Array, required: true },
@@ -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(
@@ -93,12 +92,16 @@ export default {
93
92
  }
94
93
  },
95
94
  },
95
+ mounted() {
96
+ this.side = true
97
+ },
96
98
  methods: {
97
99
  toggleCard() {
98
100
  //only flip card when user click
99
101
  this.flip = true
100
102
  //this.cardClass = 'animated flipInY flashcard flashcard--size-md'
101
- this.$emit('input', !this.value)
103
+ this.$emit('input', !this.side)
104
+ this.side = !this.side
102
105
  },
103
106
  },
104
107
  }