@abi-software/map-side-bar 2.10.7-demo.1 → 2.11.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/map-side-bar",
3
- "version": "2.10.7-demo.1",
3
+ "version": "2.11.2",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@abi-software/gallery": "^1.2.0",
47
- "@abi-software/map-utilities": "1.7.4",
47
+ "@abi-software/map-utilities": "1.7.6",
48
48
  "@abi-software/svg-sprite": "^1.0.2",
49
49
  "@element-plus/icons-vue": "^2.3.1",
50
50
  "algoliasearch": "^4.10.5",
@@ -0,0 +1,32 @@
1
+ export const acupointEntries = {
2
+ "LU 1": {
3
+ "Acupoint": "LU 1",
4
+ "Label": "LU 1",
5
+ "Synonym": "Test data",
6
+ "UMLS CUI": "",
7
+ "Meridian": "LTest data",
8
+ "Chinese Name": "Zhongfu",
9
+ "English Name": "Central Treasury",
10
+ "Location": " z zxczc.",
11
+ "Reference": "Test data",
12
+ "Indications": "Test data",
13
+ "Acupuncture Method": "Test data",
14
+ "Vasculature": "Test data",
15
+ "Innervation": "Test data"
16
+ },
17
+ "LU 2": {
18
+ "Acupoint": "LU 2",
19
+ "Label": "LU 2",
20
+ "Synonym": "Test data",
21
+ "UMLS CUI": "",
22
+ "Meridian": "LTest data",
23
+ "Chinese Name": "Yunmen",
24
+ "English Name": "Cloud Gate",
25
+ "Location": " z zxczc.",
26
+ "Reference": "Test data",
27
+ "Indications": "Test data",
28
+ "Acupuncture Method": "Test data",
29
+ "Vasculature": "Test data",
30
+ "Innervation": "Test data"
31
+ }
32
+ }
@@ -0,0 +1,169 @@
1
+ <template>
2
+ <div class="dataset-card-container" ref="container">
3
+ <div class="dataset-card" ref="card">
4
+ <div class="seperator-path"></div>
5
+ <div class="card"
6
+ @click="cardClicked(entry)"
7
+ @mouseover="cardHovered(entry)"
8
+ @mouseleave="cardHovered(undefined)"
9
+ >
10
+ <div class="card-right">
11
+ <div class="title">Acupoint: {{ entry.Acupoint }}</div>
12
+ <template v-for="field in displayFields" :key="field">
13
+ <div class="details" v-if="entry[field]">
14
+ <strong>{{ field }}:</strong> {{ entry[field] }}
15
+ </div>
16
+ </template>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </template>
22
+
23
+ <script>
24
+ import EventBus from './EventBus.js'
25
+ /* eslint-disable no-alert, no-console */
26
+
27
+ export default {
28
+ data() {
29
+ return {
30
+ displayFields: [
31
+ "Synonym",
32
+ "Chinese Name",
33
+ "English Name",
34
+ "Reference",
35
+ "Indications",
36
+ "Acupuncture Method",
37
+ "Vasculature",
38
+ "Innervation"
39
+ ]
40
+ }
41
+ },
42
+ name: 'AcupointsCard',
43
+ props: {
44
+ /**
45
+ * Object containing information for
46
+ * the required viewing.
47
+ */
48
+ entry: {
49
+ type: Object,
50
+ default: () => {},
51
+ },
52
+ },
53
+ methods: {
54
+ cardClicked: function (data) {
55
+ EventBus.emit('acupoints-clicked', data);
56
+ },
57
+ cardHovered: function (data) {
58
+ EventBus.emit('acupoints-hovered', data);
59
+ },
60
+ }
61
+ }
62
+ </script>
63
+
64
+ <style lang="scss" scoped>
65
+ .dataset-card {
66
+ padding-left: 5px;
67
+ padding-right: 5px;
68
+ position: relative;
69
+ min-height: 17rem;
70
+ }
71
+
72
+ .title {
73
+ padding-bottom: 0.75rem;
74
+ font-family: Asap;
75
+ font-size: 14px;
76
+ font-weight: bold;
77
+ font-stretch: normal;
78
+ font-style: normal;
79
+ line-height: 1.5;
80
+ letter-spacing: 1.05px;
81
+ color: #484848;
82
+ cursor: pointer;
83
+ }
84
+ .card {
85
+ padding-top: 18px;
86
+ position: relative;
87
+ display: flex;
88
+ }
89
+
90
+ .card-left {
91
+ flex: 1;
92
+ }
93
+
94
+ .card-right {
95
+ flex: 1.3;
96
+ padding-left: 6px;
97
+ }
98
+
99
+ .button {
100
+ z-index: 10;
101
+ font-family: Asap;
102
+ font-size: 14px;
103
+ font-weight: normal;
104
+ font-stretch: normal;
105
+ font-style: normal;
106
+ line-height: normal;
107
+ letter-spacing: normal;
108
+ background-color: $app-primary-color;
109
+ border: $app-primary-color;
110
+ color: white;
111
+ cursor: pointer;
112
+ margin-top: 8px;
113
+ }
114
+
115
+ .button:hover {
116
+ background-color: $app-primary-color;
117
+ color: white;
118
+ }
119
+
120
+ .banner-img {
121
+ width: 128px;
122
+ height: 128px;
123
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
124
+ background-color: #ffffff;
125
+ cursor: pointer;
126
+ }
127
+ .details {
128
+ font-family: Asap;
129
+ font-size: 14px;
130
+ font-weight: normal;
131
+ font-stretch: normal;
132
+ font-style: normal;
133
+ line-height: 1.5;
134
+ letter-spacing: 1.05px;
135
+ color: #484848;
136
+ }
137
+
138
+ .badges-container {
139
+ margin-top: 0.75rem;
140
+ }
141
+
142
+ .loading-icon {
143
+ z-index: 20;
144
+ width: 40px;
145
+ height: 40px;
146
+ left: 80px;
147
+ }
148
+
149
+ .loading-icon :deep(.el-loading-mask) {
150
+ background-color: rgba(117, 190, 218, 0) !important;
151
+ }
152
+
153
+ .loading-icon :deep(.el-loading-spinner .path) {
154
+ stroke: $app-primary-color;
155
+ }
156
+
157
+ .float-button-container {
158
+ position: absolute;
159
+ bottom: 8px;
160
+ right: 16px;
161
+ opacity: 0;
162
+ visibility: hidden;
163
+
164
+ .card:hover & {
165
+ opacity: 1;
166
+ visibility: visible;
167
+ }
168
+ }
169
+ </style>
@@ -0,0 +1,323 @@
1
+ <template>
2
+ <div v-if="entry" class="main">
3
+ <div class="header">
4
+ <el-input
5
+ class="search-input"
6
+ placeholder="Search"
7
+ v-model="searchInput"
8
+ @keyup="search(searchInput)"
9
+ clearable
10
+ @clear="clearSearchClicked"
11
+ ></el-input>
12
+ <el-button
13
+ v-show="false"
14
+ type="primary"
15
+ class="button"
16
+ @click="search(searchInput)"
17
+ size="large"
18
+ >
19
+ Search
20
+ </el-button>
21
+ </div>
22
+ <div class="content scrollbar" ref="content">
23
+ <div v-for="result in paginatedResults" :key="result.Acupoint" class="step-item">
24
+ <AcupointsCard
25
+ class="dataset-card"
26
+ :entry="result"
27
+ @mouseenter="hoverChanged(result)"
28
+ @mouseleave="hoverChanged(undefined)"
29
+ />
30
+ </div>
31
+ <el-pagination
32
+ class="pagination"
33
+ v-model:current-page="page"
34
+ hide-on-single-page
35
+ large
36
+ layout="prev, pager, next"
37
+ :page-size="numberPerPage"
38
+ :total="numberOfHits"
39
+ @current-change="pageChange"
40
+ ></el-pagination>
41
+ </div>
42
+ </div>
43
+ </template>
44
+
45
+ <script>
46
+ /* eslint-disable no-alert, no-console */
47
+ import {
48
+ ElButton as Button,
49
+ ElCard as Card,
50
+ ElDrawer as Drawer,
51
+ ElIcon as Icon,
52
+ ElInput as Input,
53
+ ElPagination as Pagination,
54
+ } from 'element-plus'
55
+ import AcupointsCard from './AcupointsCard.vue'
56
+
57
+ export default {
58
+ components: {
59
+ AcupointsCard,
60
+ Button,
61
+ Card,
62
+ Drawer,
63
+ Icon,
64
+ Input,
65
+ Pagination
66
+ },
67
+ name: 'AcupointsInfoSearch',
68
+ props: {
69
+ entry: {
70
+ type: Object,
71
+ default: () => initial_state,
72
+ },
73
+ },
74
+ data: function () {
75
+ return {
76
+ results: [],
77
+ paginatedResults: [],
78
+ searchInput: "",
79
+ lastSearch: "",
80
+ numberOfHits: 0,
81
+ numberPerPage: 10,
82
+ page: 1,
83
+ }
84
+ },
85
+ watch: {
86
+ entry: {
87
+ handler: function () {
88
+ this.search(
89
+ this.searchInput,
90
+ this.numberPerPage,
91
+ this.page
92
+ )
93
+ },
94
+ immediate: true,
95
+ deep: true,
96
+ },
97
+ },
98
+ methods: {
99
+ hoverChanged: function (data) {
100
+ this.$emit('hover-changed', data)
101
+ },
102
+ resetSearch: function () {
103
+ this.numberOfHits = 0
104
+ this.search(this.searchInput)
105
+ },
106
+ clearSearchClicked: function () {
107
+ this.searchInput = '';
108
+ this.search("");
109
+ },
110
+ search: function(input) {
111
+ this.results = []
112
+ if (input !== this.previousSearch) {
113
+ if (input === "") {
114
+ this.results = Object.values(this.entry)
115
+ } else {
116
+ const lowerCase = input.toLowerCase()
117
+ for (const value of Object.values(this.entry)) {
118
+ const searchFields = [
119
+ value["Acupoint"],
120
+ value["Synonym"],
121
+ value["Chinese Name"],
122
+ value["English Name"],
123
+ value["Reference"],
124
+ value["Indications"],
125
+ value["Acupuncture Method"],
126
+ value["Vasculature"],
127
+ value["Innervation"]
128
+ ];
129
+ const allstrings = searchFields.join();
130
+ const myJSON = allstrings.toLowerCase();
131
+ if (myJSON.includes(lowerCase)) {
132
+ this.results.push(value)
133
+ }
134
+ }
135
+ }
136
+ }
137
+ const start = this.numberPerPage * (this.page - 1)
138
+ this.paginatedResults = this.results.slice(start, start + this.numberPerPage)
139
+ this.numberOfHits = this.results.length
140
+ this.searchInput = input
141
+ this.lastSearch = input
142
+ console.log(this.numberOfHits)
143
+ },
144
+ numberPerPageUpdate: function (val) {
145
+ this.numberPerPage = val
146
+ this.pageChange(1)
147
+ },
148
+ pageChange: function (page) {
149
+ this.page = page
150
+ this.search( this.searchInput)
151
+ },
152
+ scrollToTop: function () {
153
+ if (this.$refs.content) {
154
+ this.$refs.content.scroll({ top: 0, behavior: 'smooth' })
155
+ }
156
+ },
157
+ resetPageNavigation: function () {
158
+ this.page = 1
159
+ },
160
+ },
161
+ }
162
+ </script>
163
+
164
+ <style lang="scss" scoped>
165
+ .dataset-card {
166
+ position: relative;
167
+
168
+ &::before {
169
+ content: "";
170
+ display: block;
171
+ width: calc(100% - 15px);
172
+ height: 100%;
173
+ position: absolute;
174
+ top: 7px;
175
+ left: 7px;
176
+ border-style: solid;
177
+ border-radius: 5px;
178
+ border-color: transparent;
179
+ }
180
+
181
+ &:hover {
182
+ &::before {
183
+ border-color: var(--el-color-primary);
184
+ }
185
+ }
186
+ }
187
+
188
+ .main {
189
+ font-size: 14px;
190
+ text-align: left;
191
+ line-height: 1.5em;
192
+ font-family: Asap, sans-serif, Helvetica;
193
+ font-weight: 400;
194
+ /* outline: thin red solid; */
195
+ overflow-y: auto;
196
+ scrollbar-width: thin;
197
+ min-width: 16rem;
198
+ background-color: #f7faff;
199
+ height: 100%;
200
+ border-left: 1px solid var(--el-border-color);
201
+ border-top: 1px solid var(--el-border-color);
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: 1.75rem;
205
+ padding: 1rem;
206
+ }
207
+
208
+ .step-item {
209
+ font-size: 14px;
210
+ margin-bottom: 18px;
211
+ text-align: left;
212
+ }
213
+
214
+ .search-input {
215
+ width: 298px !important;
216
+ height: 40px;
217
+ padding-right: 14px;
218
+
219
+ :deep(.el-input__inner) {
220
+ font-family: inherit;
221
+ }
222
+ }
223
+
224
+ .header {
225
+ .el-button {
226
+ font-family: inherit;
227
+
228
+ &:hover,
229
+ &:focus {
230
+ background: $app-primary-color;
231
+ box-shadow: -3px 2px 4px #00000040;
232
+ color: #fff;
233
+ }
234
+ }
235
+ }
236
+
237
+ .pagination {
238
+ padding-bottom: 16px;
239
+ background-color: white;
240
+ padding-left: 95px;
241
+ font-weight: bold;
242
+ }
243
+
244
+ .pagination :deep(button) {
245
+ background-color: white !important;
246
+ }
247
+ .pagination :deep(li) {
248
+ background-color: white !important;
249
+ }
250
+ .pagination :deep(li.is-active) {
251
+ color: $app-primary-color;
252
+ }
253
+
254
+ .error-feedback {
255
+ font-family: Asap;
256
+ font-size: 14px;
257
+ font-style: italic;
258
+ padding-top: 15px;
259
+ }
260
+
261
+ .content-card :deep(.el-card__header) {
262
+ background-color: #292b66;
263
+ padding: 1rem;
264
+ }
265
+
266
+ .content-card :deep(.el-card__body) {
267
+ background-color: #f7faff;
268
+ overflow-y: hidden;
269
+ padding: 1rem;
270
+ }
271
+
272
+ .content {
273
+ // width: 515px;
274
+ flex: 1 1 auto;
275
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
276
+ border: solid 1px #e4e7ed;
277
+ background-color: #ffffff;
278
+ overflow-y: scroll;
279
+ scrollbar-width: thin;
280
+ border-radius: var(--el-border-radius-base);
281
+ }
282
+
283
+ .content :deep(.el-loading-spinner .path) {
284
+ stroke: $app-primary-color;
285
+ }
286
+
287
+ .content :deep(.step-item:first-child .seperator-path) {
288
+ display: none;
289
+ }
290
+
291
+ .content :deep(.step-item:not(:first-child) .seperator-path) {
292
+ width: 455px;
293
+ height: 0px;
294
+ border: solid 1px #e4e7ed;
295
+ background-color: #e4e7ed;
296
+ }
297
+
298
+ .scrollbar::-webkit-scrollbar-track {
299
+ border-radius: 10px;
300
+ background-color: #f5f5f5;
301
+ }
302
+
303
+ .scrollbar::-webkit-scrollbar {
304
+ width: 12px;
305
+ right: -12px;
306
+ background-color: #f5f5f5;
307
+ }
308
+
309
+ .scrollbar::-webkit-scrollbar-thumb {
310
+ border-radius: 4px;
311
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.06);
312
+ background-color: #979797;
313
+ }
314
+
315
+ :deep(.el-input__suffix) {
316
+ padding-right: 0px;
317
+ }
318
+
319
+ :deep(.my-drawer) {
320
+ background: rgba(0, 0, 0, 0);
321
+ box-shadow: none;
322
+ }
323
+ </style>
@@ -289,7 +289,8 @@ export default {
289
289
  },
290
290
  createChildrenCascaderValue: function(children, facet, facets) {
291
291
  if (children?.length) {
292
- children.forEach((facetItem, i) => {
292
+ for (let i = 0; i < children.length; i++) {
293
+ const facetItem = children[i];
293
294
  //copy the facets into
294
295
  if (children[i].facetPropPath !== 'supportingAwards.consortium.name') {
295
296
  children[i].label = convertReadableLabel(
@@ -307,7 +308,7 @@ export default {
307
308
  children[i].value = this.createCascaderItemValue(newFacets)
308
309
  this.createChildrenCascaderValue(facetItem.children, facet, newFacets)
309
310
  }
310
- })
311
+ }
311
312
  }
312
313
  },
313
314
  getNodeKey: function (nodeValue) {
@@ -328,25 +329,28 @@ export default {
328
329
  )
329
330
  },
330
331
  processOptions: function () {
332
+ // Create a deep copy to avoid triggering reactivity during processing
333
+ const processedOptions = JSON.parse(JSON.stringify(this.options));
334
+
331
335
  // create top level of options in cascader
332
- this.options.forEach((facet, i) => {
333
- this.options[i].total = this.countTotalFacet(facet)
336
+ processedOptions.forEach((facet, i) => {
337
+ processedOptions[i].total = this.countTotalFacet(facet)
334
338
 
335
- this.options[i].label = convertReadableLabel(facet.label)
336
- this.options[i].value = this.createCascaderItemValue(
339
+ processedOptions[i].label = convertReadableLabel(facet.label)
340
+ processedOptions[i].value = this.createCascaderItemValue(
337
341
  [facet.key]
338
342
  )
339
343
 
340
- if (!this.options[i].children.find((child) => child.label === 'Show all')) {
344
+ if (!processedOptions[i].children.find((child) => child.label === 'Show all')) {
341
345
  // put "Show all" as first option
342
- this.options[i].children.unshift({
346
+ processedOptions[i].children.unshift({
343
347
  value: this.createCascaderItemValue(['Show all']),
344
348
  label: 'Show all',
345
349
  })
346
350
  }
347
351
 
348
352
  if (facet.key.includes('flatmap.connectivity.source')) {
349
- this.options[i].children.unshift({
353
+ processedOptions[i].children.unshift({
350
354
  value: this.createCascaderItemValue(['ConnectivityFilters']),
351
355
  label: 'Filters',
352
356
  disabled: true,
@@ -354,8 +358,11 @@ export default {
354
358
  }
355
359
 
356
360
  // populate second level of options
357
- this.createChildrenCascaderValue(this.options[i].children, facet, [facet.label])
361
+ this.createChildrenCascaderValue(processedOptions[i].children, facet, [facet.label])
358
362
  })
363
+
364
+ // trigger reactivity only once
365
+ Object.assign(this.options, processedOptions);
359
366
  },
360
367
  populateCascader: function () {
361
368
  if (this.entry.options) {
@@ -52,8 +52,8 @@
52
52
  :envVars="envVars"
53
53
  :connectivityEntry="connectivityEntry"
54
54
  :availableAnatomyFacets="availableAnatomyFacets"
55
- :connectivityFilterOptions="filterOptions"
56
55
  @filter-visibility="$emit('filter-visibility', $event)"
56
+ :connectivityFilterOptions="filterOptions"
57
57
  :showVisibilityFilter="showVisibilityFilter"
58
58
  @search-changed="searchChanged(tab.id, $event)"
59
59
  @hover-changed="hoverChanged(tab.id, $event)"
@@ -7,6 +7,8 @@ export {}
7
7
 
8
8
  declare module 'vue' {
9
9
  export interface GlobalComponents {
10
+ AcupointsCard: typeof import('./components/AcupointsCard.vue')['default']
11
+ AcupointsInfoSearch: typeof import('./components/AcupointsInfoSearch.vue')['default']
10
12
  AnnotationTool: typeof import('./components/AnnotationTool.vue')['default']
11
13
  BadgesGroup: typeof import('./components/BadgesGroup.vue')['default']
12
14
  ConnectivityCard: typeof import('./components/ConnectivityCard.vue')['default']