fcad-core-dragon 2.0.0-beta.1 → 2.0.0-beta.3

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 (118) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/{.eslintrc.js → .eslintrc.cjs} +81 -86
  4. package/CHANGELOG +364 -364
  5. package/README.md +71 -71
  6. package/bk.scss +117 -0
  7. package/package.json +61 -63
  8. package/src/$locales/en.json +143 -179
  9. package/src/$locales/fr.json +105 -181
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +1054 -614
  12. package/src/components/AppBaseButton.vue +87 -63
  13. package/src/components/AppBaseErrorDisplay.vue +438 -420
  14. package/src/components/AppBaseFlipCard.vue +84 -83
  15. package/src/components/AppBaseModule.vue +1673 -1842
  16. package/src/components/AppBasePage.vue +779 -312
  17. package/src/components/AppBasePopover.vue +41 -0
  18. package/src/components/AppCompAudio.vue +234 -0
  19. package/src/components/AppCompBranchButtons.vue +552 -582
  20. package/src/components/AppCompButtonProgress.vue +126 -147
  21. package/src/components/AppCompCarousel.vue +298 -192
  22. package/src/components/AppCompInputCheckBoxNext.vue +195 -0
  23. package/src/components/AppCompInputDropdownNext.vue +159 -0
  24. package/src/components/AppCompInputRadioNext.vue +152 -0
  25. package/src/components/{AppCompInputTextBox.vue → AppCompInputTextNext.vue} +106 -91
  26. package/src/components/AppCompInputTextTableNext.vue +141 -0
  27. package/src/components/AppCompInputTextToFillDropdownNext.vue +230 -0
  28. package/src/components/{AppCompInputTextToFillText.vue → AppCompInputTextToFillNext.vue} +171 -164
  29. package/src/components/AppCompJauge.vue +74 -55
  30. package/src/components/AppCompMenu.vue +413 -209
  31. package/src/components/AppCompMenuItem.vue +228 -174
  32. package/src/components/AppCompNavigation.vue +960 -949
  33. package/src/components/AppCompNoteCall.vue +133 -126
  34. package/src/components/AppCompNoteCredit.vue +292 -164
  35. package/src/components/AppCompPlayBar.vue +1218 -1319
  36. package/src/components/AppCompPlayBarNext.vue +2052 -0
  37. package/src/components/AppCompPlayBarProgress.vue +82 -0
  38. package/src/components/AppCompPopUpNext.vue +503 -0
  39. package/src/components/{AppCompQuiz.vue → AppCompQuizNext.vue} +2904 -2989
  40. package/src/components/AppCompQuizRecall.vue +276 -250
  41. package/src/components/AppCompSVGNext.vue +347 -0
  42. package/src/components/AppCompSettingsMenu.vue +172 -171
  43. package/src/components/AppCompTableOfContent.vue +387 -264
  44. package/src/components/AppCompTranscript.vue +24 -19
  45. package/src/components/AppCompVideoPlayer.vue +368 -336
  46. package/src/components/AppCompViewDisplay.vue +6 -6
  47. package/src/components/BaseModule.vue +72 -67
  48. package/src/composables/useQuiz.js +206 -0
  49. package/src/externalComps/ModuleView.vue +22 -0
  50. package/src/externalComps/SummaryView.vue +91 -0
  51. package/src/main.js +272 -227
  52. package/src/mixins/$mediaMixins.js +819 -0
  53. package/src/mixins/timerMixin.js +155 -156
  54. package/src/module/stores/appStore.js +893 -0
  55. package/src/module/xapi/ADL.js +376 -339
  56. package/src/module/xapi/Crypto/Hasher.js +241 -241
  57. package/src/module/xapi/Crypto/WordArray.js +278 -278
  58. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  59. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -319
  60. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  61. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  62. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  63. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  64. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  65. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  66. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  67. package/src/module/xapi/Crypto/index.js +53 -53
  68. package/src/module/xapi/Statement/activity.js +47 -47
  69. package/src/module/xapi/Statement/agent.js +55 -55
  70. package/src/module/xapi/Statement/group.js +26 -26
  71. package/src/module/xapi/Statement/index.js +259 -259
  72. package/src/module/xapi/Statement/statement.js +253 -253
  73. package/src/module/xapi/Statement/statementRef.js +23 -23
  74. package/src/module/xapi/Statement/substatement.js +22 -22
  75. package/src/module/xapi/Statement/verb.js +36 -36
  76. package/src/module/xapi/activitytypes.js +17 -17
  77. package/src/module/xapi/launch.js +157 -157
  78. package/src/module/xapi/utils.js +167 -167
  79. package/src/module/xapi/verbs.js +294 -294
  80. package/src/module/xapi/wrapper.js +1963 -1890
  81. package/src/module/xapi/xapiStatement.js +444 -444
  82. package/src/plugins/bus.js +8 -3
  83. package/src/plugins/gsap.js +14 -17
  84. package/src/plugins/helper.js +308 -295
  85. package/src/plugins/i18n.js +44 -31
  86. package/src/plugins/idb.js +219 -212
  87. package/src/plugins/save.js +37 -37
  88. package/src/plugins/scorm.js +287 -287
  89. package/src/plugins/xapi.js +11 -11
  90. package/src/public/index.html +33 -21
  91. package/src/router/index.js +43 -41
  92. package/src/router/routes.js +312 -337
  93. package/src/shared/generalfuncs.js +210 -188
  94. package/src/shared/validators.js +1069 -249
  95. package/vite.config.js +27 -0
  96. package/.prettierrc.js +0 -5
  97. package/babel.config.js +0 -3
  98. package/src/components/AppBaseDragChoice.vue +0 -91
  99. package/src/components/AppBaseDropZone.vue +0 -112
  100. package/src/components/AppCompBif.vue +0 -120
  101. package/src/components/AppCompDragAndDrop.vue +0 -339
  102. package/src/components/AppCompInputAssociation.vue +0 -332
  103. package/src/components/AppCompInputCheckBox.vue +0 -227
  104. package/src/components/AppCompInputDropdown.vue +0 -184
  105. package/src/components/AppCompInputRadio.vue +0 -169
  106. package/src/components/AppCompInputTextTable.vue +0 -155
  107. package/src/components/AppCompInputTextToFillDropdown.vue +0 -255
  108. package/src/components/AppCompMediaPlayer.vue +0 -397
  109. package/src/components/AppCompPopUp.vue +0 -522
  110. package/src/components/AppCompPopover.vue +0 -27
  111. package/src/components/AppCompSVG.vue +0 -309
  112. package/src/mixins/$pageMixins.js +0 -459
  113. package/src/mixins/$quizMixins.js +0 -456
  114. package/src/module/store.js +0 -895
  115. package/src/plugins/timeManager.js +0 -77
  116. package/src/routes_bckp.js +0 -313
  117. package/src/routes_static.js +0 -344
  118. package/vue.config.js +0 -83
@@ -1,264 +1,387 @@
1
- <!--
2
- ----------------- MUST ADD OVERAY TO CLOSE WIDGET ------------------
3
- ----------------- MUST ADD ERROR GESTION ------------------
4
- ----------------- MUST ADD label terminer ------------------
5
- ----------------- MUST ADD css ------------------
6
-
7
- @ Description: This component is used to display the sub menu to show the anchor of a activity.
8
- @ What it does: The component show the data that was enter in menu.json and create de link to the anchor from those information. This componant must be use with app-comp-menu-Item and app-comp-menu.
9
- -->
10
-
11
- <template>
12
- <div id="sidebar-submenu" :class="{ isOpen: open }">
13
- <app-base-button id="close-toc" @click="close()">X</app-base-button>
14
- <p>{{ $t('text.you_are_here') }}</p>
15
- <p v-html="title"></p>
16
-
17
- <div>
18
- <p>{{ actProgress }} {{ $t('text.activity_progress') }}</p>
19
- </div>
20
-
21
- <div class="box">
22
- <b-link
23
- v-for="anchor of anchors"
24
- :key="anchor.title"
25
- :to="{
26
- name: anchor.path
27
- }"
28
- @click="close()"
29
- >
30
- <div>
31
- <p>{{ anchor.title }}</p>
32
- <p></p>
33
- </div>
34
- </b-link>
35
- </div>
36
- </div>
37
- </template>
38
-
39
- <script>
40
- import { mapGetters } from 'vuex'
41
-
42
- export default {
43
- data() {
44
- return {
45
- title: '',
46
- anchors: [],
47
- activity: '',
48
- open: false,
49
- menuInfo: null,
50
- actProgress: null
51
- }
52
- },
53
- computed: {
54
- ...mapGetters([
55
- 'getMenuSettings',
56
- 'getAnchorsForActivity',
57
- 'getBifChoice',
58
- 'getAllCompleted',
59
- 'getAllActivitiesState'
60
- ])
61
- },
62
- mounted() {
63
- this.$bus.$on('toggle-widget', (data) => {
64
- if (data == 'toc') this.open = !this.open
65
- else this.open = false
66
- })
67
-
68
- this.$bus.$on('close-widget', (data) => {
69
- this.open = false
70
- this.reset()
71
- })
72
-
73
- this.$bus.$on('info-activity', (data) => {
74
- //should be condition to avoid event fireing multiple time on call
75
-
76
- if (data) {
77
- this.reset()
78
- this.activity = data
79
- this.getInfoSubMenu(data)
80
- this.getProgressActivity(data)
81
- }
82
- })
83
- },
84
- methods: {
85
- /* @Description:Get and set the section to output
86
- * @params: activity {Object}: the activity which sections need to be output
87
- */
88
- //
89
- getInfoSubMenu(activity) {
90
- //get the anchors for this activity from the store
91
- let menuInfo = this.getMenuSettings
92
- let nb = null
93
-
94
- //Get title are if no title construct acitivty
95
- if (menuInfo[activity] && menuInfo[activity].title)
96
- this.title = menuInfo[activity].title
97
-
98
- if (activity.charAt(1) == '0' || activity.charAt(1) == 0)
99
- nb = activity.substr(2)
100
- else nb = activity.substr(1)
101
-
102
- this.title = `${this.$t('text.activity')} ${nb} : ${
103
- menuInfo[activity].subTitle
104
- }`
105
-
106
- let count = 0
107
-
108
- //create anchors title and path
109
- if (menuInfo[activity] && menuInfo[activity].anchors) {
110
- menuInfo[activity].anchors.forEach((element) => {
111
- count++
112
-
113
- //
114
- let _path = null
115
- let b = null
116
- if (nb == 0 || nb == '0') {
117
- b = `introduction`
118
- } else {
119
- b = `activite_${nb}`
120
- }
121
-
122
- if (element.page == 'page_1') {
123
- _path = `${b}`
124
- } else {
125
- _path = `${b}.${element.page}`
126
- }
127
-
128
- let info = {
129
- title: `${this.$t('text.anchors')} ${count} : ${
130
- element.anchorName
131
- }`,
132
- path: _path
133
- }
134
- this.anchors.push(info)
135
- })
136
- }
137
- },
138
- disable(data) {
139
- let page = data.pageRef
140
- let act = this.getAct(data.path)
141
- let choosen = this.getBifChoice
142
-
143
- // disable if bif
144
- if (data.bif && choosen) {
145
- if (choosen.act == act && choosen.page == page) {
146
- return false
147
- } else {
148
- return true
149
- }
150
- } else {
151
- return false
152
- }
153
- },
154
- getAct(data) {
155
- //return the id need it
156
- if (data) {
157
- if (data.substring(data.indexOf('_') + 1).length == 1) {
158
- return `A0${data.substring(data.indexOf('_') + 1)}`
159
- } else {
160
- return `A${data.substring(data.indexOf('_') + 1)}`
161
- }
162
- }
163
- },
164
- /**
165
- * @description Gives gives length of completed page for an activity
166
- * @param {String} idActivity
167
- * @returns {Number}
168
- */
169
- getProgressActivity(idActivity) {
170
- /// give all the page that are complete to the gauge
171
- if (idActivity) {
172
- let completed = []
173
- if (this.getAllCompleted[idActivity]) {
174
- completed = this.getAllCompleted[idActivity] //get all completed page for the activity
175
- }
176
-
177
- const allActivitiesState = JSON.parse(
178
- JSON.stringify(this.getAllActivitiesState)
179
- )
180
- let size = allActivitiesState[idActivity]
181
- ? allActivitiesState[idActivity].size
182
- : 0
183
-
184
- // reduce the size if in A00
185
- if (idActivity === 'A00' && size > 0) size = size - 1
186
-
187
- // return pourcent of activity completion
188
- this.actProgress = `${Math.round((completed.length * 100) / size)} %`
189
- }
190
- },
191
- close() {
192
- this.open = !this.open
193
- this.reset()
194
- },
195
- reset() {
196
- this.anchors = []
197
- this.activity = ''
198
- this.activity = ''
199
- }
200
- }
201
- }
202
- </script>
203
- <style lang="scss">
204
- #sidebar-submenu {
205
- display: none;
206
- position: absolute;
207
- left: 200%;
208
- top: 0;
209
- background: white;
210
- width: 450px;
211
-
212
- &.isOpen {
213
- display: block;
214
- }
215
-
216
- .b-sidebar-header {
217
- display: none;
218
- pointer-events: none;
219
- }
220
-
221
- .box {
222
- .box-time {
223
- width: 100%;
224
- padding: 10px 20px;
225
- }
226
-
227
- .box-contenu {
228
- padding: 20px;
229
- @media screen and (max-width: 1100px) {
230
- padding: 0;
231
- }
232
-
233
- .box-ttl {
234
- @media screen and (max-width: 1100px) {
235
- padding: 15px 0px 10px 20px;
236
- }
237
- }
238
-
239
- .container-anchor {
240
- margin-top: 35px;
241
- margin-left: 35px;
242
- padding-left: 24px;
243
- padding-top: 14px;
244
- max-height: 75vh;
245
- overflow-y: auto;
246
-
247
- @media screen and (max-width: 1100px) {
248
- padding: 0;
249
- margin: 0;
250
- }
251
-
252
- .box-sa {
253
- margin-bottom: 16px;
254
-
255
- @media screen and (max-width: 1100px) {
256
- padding: 19px 20px 19px 47px;
257
- margin-bottom: 0;
258
- }
259
- }
260
- }
261
- }
262
- }
263
- }
264
- </style>
1
+ <!--
2
+ ----------------- MUST ADD ERROR GESTION ------------------
3
+ ----------------- MUST ADD label terminer ------------------
4
+ ----------------- MUST ADD css ------------------
5
+
6
+ @ Description: This component is used to display the sub menu to show the anchor of a activity.
7
+ @ What it does: The component show the data that was enter in menu.json and create de link to the anchor from those information. This componant must be use with app-comp-menu-Item and app-comp-menu.
8
+ -->
9
+
10
+ <template>
11
+ <div v-if="error" id="sidebar-submenu" :class="{ isOpen: open }">
12
+ <app-base-button
13
+ id="close-toc"
14
+ class="btn-ghost"
15
+ :title="$t('button.closePopUp')"
16
+ @click="close()"
17
+ >
18
+ <svg>
19
+ <use href="#close-square-icon" />
20
+ </svg>
21
+ </app-base-button>
22
+
23
+ <p class="t-act" v-html="title"></p>
24
+
25
+ <div class="box-prog-act">
26
+ <p>
27
+ {{ $t('text.activity_progress') }}
28
+ <span>{{ actProgress }}</span>
29
+ </p>
30
+ </div>
31
+
32
+ <div class="box-anchor">
33
+ <p class="t-toc">{{ $t('text.toc') }}</p>
34
+
35
+ <a
36
+ v-for="(anchor, index) of anchors"
37
+ :key="anchor.title"
38
+ class="toc-item"
39
+ :done="sectionProgress(index)"
40
+ @click="closeAndNextPage(anchor.path)"
41
+ >
42
+ <div class="box-text-anchor">
43
+ <div class="text-anchor">
44
+ <p class="anchor-t" v-html="anchor.title"></p>
45
+ <p class="state">
46
+ <svg>
47
+ <use href="#check-toc" />
48
+ </svg>
49
+ {{ $t('text.complete') }}
50
+ </p>
51
+ </div>
52
+ <svg>
53
+ <use href="#chevronD-icon" />
54
+ </svg>
55
+ </div>
56
+ </a>
57
+ </div>
58
+ </div>
59
+ <div v-else id="sidebar-submenu" :class="{ isOpen: open }">
60
+ <p>
61
+ Cette activité n'existe pas dans menu setting, svp l'ajouter à votre menu
62
+ setting
63
+ </p>
64
+ </div>
65
+ </template>
66
+
67
+ <script>
68
+ import { mapState, mapActions } from 'pinia'
69
+ import { useAppStore } from '../module/stores/appStore'
70
+ export default {
71
+ data() {
72
+ return {
73
+ title: '',
74
+ anchors: [],
75
+ activity: '',
76
+ open: false,
77
+ menuInfo: null,
78
+ actProgress: null,
79
+ error: true
80
+ }
81
+ },
82
+ computed: {
83
+ ...mapState(useAppStore, [
84
+ 'getMenuSettings',
85
+ 'getAnchorsForActivity',
86
+ 'getBifChoice',
87
+ 'getAllCompleted',
88
+ 'getAllActivitiesState'
89
+ ])
90
+ },
91
+ beforeUnmount() {
92
+ this.$bus.$off('toggle-widget', this.onToggleWidget)
93
+ this.$bus.$off('close-widget', this.onCloseWidget)
94
+ this.$bus.$off('info-activity', this.onInfoActivity)
95
+ },
96
+ mounted() {
97
+ this.$bus.$on('toggle-widget', this.onToggleWidget)
98
+ this.$bus.$on('close-widget', this.onCloseWidget)
99
+ this.$bus.$on('info-activity', this.onInfoActivity)
100
+ },
101
+ methods: {
102
+ ...mapActions(useAppStore, ['updateWidgetOpen']),
103
+ onInfoActivity(data) {
104
+ //should be condition to avoid event fireing multiple time on call
105
+
106
+ if (data) {
107
+ this.reset()
108
+ this.activity = data
109
+
110
+ if (!this.getMenuSettings[data]) {
111
+ return (this.error = false)
112
+ } else {
113
+ this.getInfoSubMenu(data)
114
+ this.getProgressActivity(data)
115
+ }
116
+ }
117
+ },
118
+ onCloseWidget(data) {
119
+ this.open = false
120
+ this.updateWidgetOpen(false)
121
+ this.reset()
122
+ },
123
+ onToggleWidget(data) {
124
+ if (data == 'toc') {
125
+ this.open = !this.open
126
+ this.updateWidgetOpen(true)
127
+ } else {
128
+ this.updateWidgetOpen(false)
129
+ this.open = false
130
+ }
131
+ },
132
+ /* @Description:Get and set the section to output
133
+ * @params: activity {Object}: the activity which sections need to be output
134
+ */
135
+ //
136
+ getInfoSubMenu(activity) {
137
+ //get the anchors for this activity from the store
138
+ let menuInfo = this.getMenuSettings
139
+
140
+ let nb = null
141
+
142
+ //Get title are if no title construct acitivty
143
+ if (menuInfo[activity] && menuInfo[activity].title)
144
+ this.title = menuInfo[activity].title
145
+
146
+ if (activity.charAt(1) == '0' || activity.charAt(1) == 0)
147
+ nb = activity.substr(2)
148
+ else nb = activity.substr(1)
149
+
150
+ this.title = `${this.$t('text.activity')} ${nb} : ${menuInfo[activity].subTitle}`
151
+
152
+ //create anchors title and path
153
+ if (menuInfo[activity] && menuInfo[activity].anchors) {
154
+ menuInfo[activity].anchors.forEach((element) => {
155
+ //
156
+ let _path = null
157
+ let b = null
158
+ if (nb == 0 || nb == '0') {
159
+ b = `introduction`
160
+ } else {
161
+ b = `activite_${nb}`
162
+ }
163
+
164
+ if (element.page == 'page_1') {
165
+ _path = `${b}`
166
+ } else {
167
+ _path = `${b}.${element.page}`
168
+ }
169
+
170
+ let info = {
171
+ title: `${element.anchorName}`,
172
+ path: _path
173
+ }
174
+ this.anchors.push(info)
175
+ })
176
+ }
177
+ },
178
+ disable(data) {
179
+ let page = data.pageRef
180
+ let act = this.getAct(data.path)
181
+ let choosen = this.getBifChoice
182
+
183
+ // disable if bif
184
+ if (data.bif && choosen) {
185
+ if (choosen.act == act && choosen.page == page) {
186
+ return false
187
+ } else {
188
+ return true
189
+ }
190
+ } else {
191
+ return false
192
+ }
193
+ },
194
+ getAct(data) {
195
+ //return the id need it
196
+ if (data) {
197
+ if (data.substring(data.indexOf('_') + 1).length == 1) {
198
+ return `A0${data.substring(data.indexOf('_') + 1)}`
199
+ } else {
200
+ return `A${data.substring(data.indexOf('_') + 1)}`
201
+ }
202
+ }
203
+ },
204
+ /**
205
+ * @description Gives gives length of completed page for an activity
206
+ * @param {String} idActivity
207
+ * @returns {Number}
208
+ */
209
+ getProgressActivity(idActivity) {
210
+ /// give all the page that are complete to the gauge
211
+ if (idActivity) {
212
+ let completed = []
213
+ if (this.getAllCompleted[idActivity]) {
214
+ completed = this.getAllCompleted[idActivity] //get all completed page for the activity
215
+ }
216
+
217
+ const allActivitiesState = JSON.parse(
218
+ JSON.stringify(this.getAllActivitiesState)
219
+ )
220
+ let size = allActivitiesState[idActivity]
221
+ ? allActivitiesState[idActivity].size
222
+ : 0
223
+
224
+ // return pourcent of activity completion
225
+ this.actProgress = `${Math.round((completed.length * 100) / size)} %`
226
+ }
227
+ },
228
+ close() {
229
+ this.open = !this.open
230
+ this.updateWidgetOpen(this.open)
231
+ },
232
+ closeAndNextPage(NextPage) {
233
+ this.open = !this.open
234
+ this.updateWidgetOpen(this.open)
235
+ this.$router.push({ name: NextPage })
236
+ },
237
+ reset() {
238
+ this.anchors = []
239
+ this.activity = ''
240
+ },
241
+ sectionProgress(index) {
242
+ let menuInfo = this.getMenuSettings
243
+ let nextIndex = index + 1
244
+ let nextSec
245
+ let curSec = menuInfo[this.activity].anchors[index].pageRef
246
+
247
+ let nb
248
+ let tabPageSec = []
249
+ let tabcomplete = []
250
+
251
+ if (nextIndex < menuInfo[this.activity].anchors.length) {
252
+ nextSec = menuInfo[this.activity].anchors[nextIndex].pageRef
253
+ }
254
+
255
+ if (nextSec != undefined) {
256
+ nb = parseInt(nextSec.substring(1))
257
+
258
+ while (nb > parseInt(curSec.substring(1))) {
259
+ nb--
260
+ if (nb < 10) tabPageSec.push(`P0${nb}`)
261
+ else tabPageSec.push(`P${nb}`)
262
+ }
263
+ } else {
264
+ if (menuInfo[this.activity].anchors.length == 1) {
265
+ let numPage = this.getAllActivitiesState[this.activity].size
266
+
267
+ for (let g = 1; g == numPage; g++) {
268
+ tabPageSec.push(`P${g}`)
269
+ }
270
+
271
+ if (
272
+ this.getAllCompleted[this.activity].length !==
273
+ this.getAllActivitiesState[this.activity].size
274
+ )
275
+ return false
276
+ }
277
+ tabPageSec.push(curSec)
278
+ }
279
+
280
+ let completeActPage = this.getAllCompleted[this.activity]
281
+
282
+ if (completeActPage) {
283
+ completeActPage.find((value) => {
284
+ let w = Object.keys(value)
285
+ tabcomplete.push(w[0])
286
+ })
287
+
288
+ const isSubset = (array1, array2) =>
289
+ array2.every((element) => array1.includes(element))
290
+
291
+ return isSubset(tabcomplete, tabPageSec)
292
+ }
293
+ }
294
+ }
295
+ }
296
+ </script>
297
+ <style lang="scss">
298
+ #sidebar-submenu {
299
+ display: none;
300
+ position: absolute;
301
+ left: 75px;
302
+ top: 0;
303
+ max-height: 592px;
304
+ width: 476px;
305
+ transition: left 0.5s ease-in-out;
306
+
307
+ &.isOpen {
308
+ display: block;
309
+ }
310
+
311
+ #close-toc {
312
+ position: absolute;
313
+ right: 24px;
314
+ margin-bottom: 0;
315
+ padding: 11px;
316
+ width: 48px;
317
+ height: 48px;
318
+ display: flex;
319
+ justify-content: center;
320
+
321
+ &:focus {
322
+ box-shadow: inherit !important;
323
+ }
324
+ }
325
+
326
+ .box-prog-act {
327
+ width: 319px;
328
+ display: flex;
329
+ flex-direction: row;
330
+ margin-bottom: 16px;
331
+
332
+ p {
333
+ position: relative;
334
+ width: 100%;
335
+
336
+ span {
337
+ position: absolute;
338
+ right: 0;
339
+ top: 0;
340
+ }
341
+ }
342
+ }
343
+
344
+ .box-anchor {
345
+ max-height: 366px;
346
+ overflow-y: auto;
347
+ padding: 0 4px;
348
+
349
+ .t-toc {
350
+ margin-bottom: 16px;
351
+ }
352
+
353
+ .toc-item {
354
+ display: block;
355
+ width: 95%;
356
+ margin-bottom: 8px;
357
+
358
+ .state {
359
+ display: none;
360
+ }
361
+ &[done='true'] {
362
+ .state {
363
+ display: block;
364
+ }
365
+ }
366
+
367
+ .box-text-anchor {
368
+ display: flex;
369
+ flex-direction: row;
370
+ align-items: center;
371
+ justify-content: space-between;
372
+ }
373
+ }
374
+ }
375
+ }
376
+
377
+ .app-nav {
378
+ &.show,
379
+ &:hover {
380
+ .ctn-w {
381
+ #sidebar-submenu {
382
+ left: 120px;
383
+ }
384
+ }
385
+ }
386
+ }
387
+ </style>