@abi-software/map-side-bar 2.14.0 → 2.14.1-beta.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/dist/map-side-bar.js +9658 -8776
- package/dist/map-side-bar.umd.cjs +69 -66
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/App.vue +28 -1
- package/src/acupoints.js +78 -0
- package/src/components/AcupointsCard.vue +311 -0
- package/src/components/AcupointsInfoSearch.vue +620 -0
- package/src/components/SearchFilters.vue +10 -3
- package/src/components/SideBar.vue +51 -3
- package/src/components.d.ts +4 -0
- package/src/services/flatmapKnowledge.js +94 -0
- package/src/services/flatmapQueries.js +498 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/map-side-bar",
|
|
3
|
-
"version": "2.14.0",
|
|
3
|
+
"version": "2.14.1-beta.0",
|
|
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.3.0",
|
|
47
|
-
"@abi-software/map-utilities": "1.8.
|
|
47
|
+
"@abi-software/map-utilities": "1.8.1",
|
|
48
48
|
"@abi-software/svg-sprite": "^1.0.2",
|
|
49
49
|
"@element-plus/icons-vue": "^2.3.1",
|
|
50
50
|
"algoliasearch": "^4.10.5",
|
package/src/App.vue
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
<el-button @click="keywordSearch">keyword search</el-button>
|
|
19
19
|
<el-button @click="getFacets">Get facets</el-button>
|
|
20
20
|
<el-button @click="toggleCreateData">Create Data/Annotation</el-button>
|
|
21
|
+
<el-button @click="searchAcupoints">Search Acupoints</el-button>
|
|
21
22
|
<el-button @click="openConnectivitySearch()">Connectivity Search</el-button>
|
|
22
23
|
</div>
|
|
23
24
|
<SideBar
|
|
@@ -26,14 +27,19 @@
|
|
|
26
27
|
ref="sideBar"
|
|
27
28
|
:visible="sideBarVisibility"
|
|
28
29
|
:annotationEntry="annotationEntry"
|
|
30
|
+
:acupointsInfoList="acupoints"
|
|
29
31
|
:createData="createData"
|
|
30
32
|
:connectivityEntry="connectivityEntry"
|
|
31
33
|
:connectivityKnowledge="connectivityKnowledge"
|
|
32
34
|
:showVisibilityFilter="true"
|
|
35
|
+
:tabs="tabArray"
|
|
33
36
|
@search-changed="searchChanged($event)"
|
|
34
37
|
@hover-changed="hoverChanged($event)"
|
|
35
38
|
@connectivity-hovered="onConnectivityHovered"
|
|
36
39
|
@actionClick="action"
|
|
40
|
+
@acupoints-clicked="onAcupointsClicked"
|
|
41
|
+
@acupoints-hovered="onAcupointsHovered"
|
|
42
|
+
@acupoints-result="onAcupointsResult"
|
|
37
43
|
@connectivity-collapse-change="onConnectivityCollapseChange"
|
|
38
44
|
/>
|
|
39
45
|
</div>
|
|
@@ -42,6 +48,7 @@
|
|
|
42
48
|
<script>
|
|
43
49
|
/* eslint-disable no-alert, no-console */
|
|
44
50
|
// optionally import default styles
|
|
51
|
+
import { acupointEntries } from './acupoints.js'
|
|
45
52
|
import SideBar from './components/SideBar.vue'
|
|
46
53
|
import EventBus from './components/EventBus.js'
|
|
47
54
|
import exampleConnectivityInput from './exampleConnectivityInput.js'
|
|
@@ -121,6 +128,14 @@ export default {
|
|
|
121
128
|
},
|
|
122
129
|
data: function () {
|
|
123
130
|
return {
|
|
131
|
+
acupoints: acupointEntries,
|
|
132
|
+
contextArray: [null, null],
|
|
133
|
+
tabArray: [
|
|
134
|
+
{ title: 'Dataset Explorer', id: 1, type: 'datasetExplorer', closable: false },
|
|
135
|
+
{ title: 'Connectivity Explorer', id: 2, type: 'connectivityExplorer', closable: false },
|
|
136
|
+
{ title: 'Annotation', id: 3, type: 'annotation', closable: true },
|
|
137
|
+
{title: 'Acupoints', id: 4, type: 'acupoints' },
|
|
138
|
+
],
|
|
124
139
|
annotationEntry: [{
|
|
125
140
|
featureId: "epicardium",
|
|
126
141
|
resourceId: "https://mapcore-bucket1.s3-us-west-2.amazonaws.com/others/29_Jan_2020/heartICN_metadata.json",
|
|
@@ -155,6 +170,15 @@ export default {
|
|
|
155
170
|
}
|
|
156
171
|
},
|
|
157
172
|
methods: {
|
|
173
|
+
onAcupointsClicked: function (data) {
|
|
174
|
+
console.log("acupoints-clicked", data)
|
|
175
|
+
},
|
|
176
|
+
onAcupointsHovered: function (data) {
|
|
177
|
+
console.log("acupoints-hovered", data)
|
|
178
|
+
},
|
|
179
|
+
onAcupointsResult: function (data) {
|
|
180
|
+
console.log("acupoints-result", data)
|
|
181
|
+
},
|
|
158
182
|
loadConnectivityKnowledge: async function () {
|
|
159
183
|
const sql = `select knowledge from knowledge
|
|
160
184
|
where source="${this.sckanVersion}"
|
|
@@ -231,6 +255,9 @@ export default {
|
|
|
231
255
|
'http://purl.obolibrary.org/obo/UBERON_0001103'
|
|
232
256
|
)
|
|
233
257
|
},
|
|
258
|
+
searchAcupoints: function() {
|
|
259
|
+
this.$refs.sideBar.openAcupointsSearch("LU 1")
|
|
260
|
+
},
|
|
234
261
|
singleFacets: function () {
|
|
235
262
|
this.$refs.sideBar.addFilter({
|
|
236
263
|
facet: 'Cardiovascular system',
|
|
@@ -405,4 +432,4 @@ body {
|
|
|
405
432
|
align-items: center;
|
|
406
433
|
gap: 0.5rem;
|
|
407
434
|
}
|
|
408
|
-
</style
|
|
435
|
+
</style>./acupoints.js
|
package/src/acupoints.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
"Curated": false,
|
|
17
|
+
"onMRI": true,
|
|
18
|
+
"Meridian Point": true,
|
|
19
|
+
"Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
|
|
20
|
+
},
|
|
21
|
+
"LU 2": {
|
|
22
|
+
"Acupoint": "LU 2",
|
|
23
|
+
"Label": "LU 2",
|
|
24
|
+
"Synonym": "Test data",
|
|
25
|
+
"UMLS CUI": "",
|
|
26
|
+
"Meridian": "LTest data",
|
|
27
|
+
"Chinese Name": "Yunmen",
|
|
28
|
+
"English Name": "Cloud Gate",
|
|
29
|
+
"Location": " z zxczc.",
|
|
30
|
+
"Reference": "Test data",
|
|
31
|
+
"Indications": "Test data",
|
|
32
|
+
"Acupuncture Method": "Test data",
|
|
33
|
+
"Vasculature": "Test data",
|
|
34
|
+
"Innervation": "Test data",
|
|
35
|
+
"Curated": true,
|
|
36
|
+
"onMRI": true,
|
|
37
|
+
"Meridian Point": false,
|
|
38
|
+
"Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
|
|
39
|
+
},
|
|
40
|
+
"ST 3": {
|
|
41
|
+
"Acupoint": "ST 3",
|
|
42
|
+
"Label": "ST 3",
|
|
43
|
+
"Synonym": "Test data",
|
|
44
|
+
"UMLS CUI": "",
|
|
45
|
+
"Meridian": "STest data",
|
|
46
|
+
"Chinese Name": "Cheng Qi",
|
|
47
|
+
"English Name": "Not Available",
|
|
48
|
+
"Location": " z zxcxadadadzc.",
|
|
49
|
+
"Reference": "Test data",
|
|
50
|
+
"Indications": "Test data",
|
|
51
|
+
"Acupuncture Method": "Test data",
|
|
52
|
+
"Vasculature": "Test data",
|
|
53
|
+
"Innervation": "Test data",
|
|
54
|
+
"Curated": true,
|
|
55
|
+
"onMRI": false,
|
|
56
|
+
"Meridian Point": false,
|
|
57
|
+
"Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
|
|
58
|
+
},
|
|
59
|
+
"LR 4": {
|
|
60
|
+
"Acupoint": "LR 4",
|
|
61
|
+
"Label": "LR 4",
|
|
62
|
+
"Synonym": "Test data",
|
|
63
|
+
"UMLS CUI": "",
|
|
64
|
+
"Meridian": "STest data",
|
|
65
|
+
"Chinese Name": "Zhongfeng",
|
|
66
|
+
"English Name": "Not Available",
|
|
67
|
+
"Location": " z zxcxadadadzc.",
|
|
68
|
+
"Reference": "Test data",
|
|
69
|
+
"Indications": "Test data",
|
|
70
|
+
"Acupuncture Method": "Test data",
|
|
71
|
+
"Vasculature": "Test data",
|
|
72
|
+
"Innervation": "Test data",
|
|
73
|
+
"Curated": false,
|
|
74
|
+
"onMRI": false,
|
|
75
|
+
"Meridian Point": true,
|
|
76
|
+
"Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
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
|
+
<el-collapse class="collapse-card" v-model="expanded" @change="expandedChanged">
|
|
12
|
+
<el-collapse-item :title="entry.Acupoint" name="1" class="collapse-card">
|
|
13
|
+
<template #title>
|
|
14
|
+
<div>
|
|
15
|
+
<span class="title">{{ entry.Acupoint }}</span>
|
|
16
|
+
<el-tag
|
|
17
|
+
v-for="tag in tags"
|
|
18
|
+
:key="tag.name"
|
|
19
|
+
:type="tag.type"
|
|
20
|
+
effect="plain"
|
|
21
|
+
class="acupointTags"
|
|
22
|
+
size="small"
|
|
23
|
+
>
|
|
24
|
+
{{ tag.name }}
|
|
25
|
+
</el-tag>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
<template v-for="field in displayFields" :key="field['name']">
|
|
29
|
+
<div class="details">
|
|
30
|
+
<strong>{{ field['name'] }}: </strong>
|
|
31
|
+
<template v-if="field['name'] === 'Link'">
|
|
32
|
+
<a :href="entry['Link']" target="_blank">
|
|
33
|
+
<span>
|
|
34
|
+
{{ entry['Link'] }}
|
|
35
|
+
</span>
|
|
36
|
+
</a>
|
|
37
|
+
</template>
|
|
38
|
+
<template v-else-if="field['name'] === 'Reference'">
|
|
39
|
+
<div v-html="formatReference(entry[field['name']])"></div>
|
|
40
|
+
</template>
|
|
41
|
+
<template v-else>
|
|
42
|
+
<span
|
|
43
|
+
v-if="!field['isEditing']"
|
|
44
|
+
@click="setFieldToEditing(field)"
|
|
45
|
+
>
|
|
46
|
+
{{ entry[field['name']] || 'Not Available' }}
|
|
47
|
+
</span>
|
|
48
|
+
<el-input
|
|
49
|
+
v-else
|
|
50
|
+
v-model="entry[field['name']]"
|
|
51
|
+
@blur="field['isEditing'] = false"
|
|
52
|
+
@keyup.enter="field['isEditing'] = false"
|
|
53
|
+
@vue:mounted="inputMounted"
|
|
54
|
+
type="textarea"
|
|
55
|
+
/>
|
|
56
|
+
</template>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
</el-collapse-item>
|
|
60
|
+
</el-collapse>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</template>
|
|
66
|
+
|
|
67
|
+
<script>
|
|
68
|
+
import EventBus from './EventBus.js'
|
|
69
|
+
import {
|
|
70
|
+
ElCollapse as Collapse,
|
|
71
|
+
ElCollapseItem as CollapseItem,
|
|
72
|
+
ElTag as Tag
|
|
73
|
+
} from 'element-plus'
|
|
74
|
+
/* eslint-disable no-alert, no-console */
|
|
75
|
+
|
|
76
|
+
export default {
|
|
77
|
+
components: {
|
|
78
|
+
Collapse,
|
|
79
|
+
CollapseItem,
|
|
80
|
+
Tag
|
|
81
|
+
},
|
|
82
|
+
data() {
|
|
83
|
+
return {
|
|
84
|
+
expanded: [],
|
|
85
|
+
tags: [],
|
|
86
|
+
displayFields: [
|
|
87
|
+
{name: "Link", isEditing: false},
|
|
88
|
+
{name: "Synonym", isEditing: false},
|
|
89
|
+
{name: "Pinyin Name", isEditing: false},
|
|
90
|
+
{name: "Chinese Name", isEditing: false},
|
|
91
|
+
{name: "Meridian", isEditing: false},
|
|
92
|
+
{name: "Reference", isEditing: false},
|
|
93
|
+
{name: "Indications", isEditing: false},
|
|
94
|
+
{name: "Acupuncture Method", isEditing: false},
|
|
95
|
+
{name: "Innervation", isEditing: false},
|
|
96
|
+
{name: "Nearby Nerve", isEditing: false},
|
|
97
|
+
{name: "Vasculature", isEditing: false},
|
|
98
|
+
{name: "Nearby Artery", isEditing: false},
|
|
99
|
+
{name: "Nearby Vein", isEditing: false},
|
|
100
|
+
//{name: "Notes", isEditing: false},
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
name: 'AcupointsCard',
|
|
105
|
+
props: {
|
|
106
|
+
/**
|
|
107
|
+
* Object containing information for
|
|
108
|
+
* the required viewing.
|
|
109
|
+
*/
|
|
110
|
+
entry: {
|
|
111
|
+
type: Object,
|
|
112
|
+
default: () => {},
|
|
113
|
+
},
|
|
114
|
+
allowEditing: {
|
|
115
|
+
type: Boolean,
|
|
116
|
+
default: false,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
created: function () {
|
|
120
|
+
if (this.entry["Meridian Point"]) {
|
|
121
|
+
this.tags.push({ name: 'WHO', type: 'info' })
|
|
122
|
+
}
|
|
123
|
+
if (this.entry.Meridian) {
|
|
124
|
+
this.tags.push({ name: this.entry.Meridian, type: 'info' })
|
|
125
|
+
}
|
|
126
|
+
if (this.entry.onMRI) {
|
|
127
|
+
this.tags.push({ name: 'Spotted', type: 'success' })
|
|
128
|
+
}
|
|
129
|
+
if (this.entry.userDefined) {
|
|
130
|
+
this.tags.push({ name: 'User Defined', type: 'warning' })
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
methods: {
|
|
134
|
+
expandedChanged: function() {
|
|
135
|
+
if (this.expanded.length > 0) {
|
|
136
|
+
EventBus.emit('acupoints-clicked', this.entry);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
cardClicked: function (data) {
|
|
140
|
+
EventBus.emit('acupoints-clicked', data);
|
|
141
|
+
},
|
|
142
|
+
cardHovered: function (data) {
|
|
143
|
+
EventBus.emit('acupoints-hovered', data);
|
|
144
|
+
},
|
|
145
|
+
inputMounted: function(event) {
|
|
146
|
+
event.el?.querySelector('textarea')?.focus();
|
|
147
|
+
},
|
|
148
|
+
formatReference: function(text) {
|
|
149
|
+
if (!text) {
|
|
150
|
+
return 'Not Available';
|
|
151
|
+
}
|
|
152
|
+
// Escape HTML first so only the markup added below is rendered
|
|
153
|
+
const escaped = String(text)
|
|
154
|
+
.replace(/&/g, '&')
|
|
155
|
+
.replace(/</g, '<')
|
|
156
|
+
.replace(/>/g, '>')
|
|
157
|
+
.replace(/"/g, '"')
|
|
158
|
+
.replace(/'/g, ''');
|
|
159
|
+
return escaped
|
|
160
|
+
// Bold and italicise square-bracketed labels, e.g. [Acupoint Location, Pinyin Label]
|
|
161
|
+
.replace(/\[([^\]\n]+)\]/g, '<strong><em>[$1]</em></strong>')
|
|
162
|
+
// Turn http(s) URLs into links, leaving trailing punctuation outside
|
|
163
|
+
.replace(/https?:\/\/[^\s<]+?(?=[.,;:!?)]*(?:\s|<|$))/g,
|
|
164
|
+
(url) => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`)
|
|
165
|
+
.replace(/\n/g, '<br>');
|
|
166
|
+
},
|
|
167
|
+
setFieldToEditing: function(field) {
|
|
168
|
+
if (this.allowEditing) {
|
|
169
|
+
field['isEditing'] = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
</script>
|
|
175
|
+
|
|
176
|
+
<style lang="scss" scoped>
|
|
177
|
+
|
|
178
|
+
:deep(.el-collapse-item__header) {
|
|
179
|
+
font-weight: bold;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
:deep(.el-collapse-item__content) {
|
|
183
|
+
padding-bottom: 4px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
:deep(.el-collapse-item__wrap) {
|
|
187
|
+
border: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.collapse-card {
|
|
191
|
+
border-top: none;
|
|
192
|
+
:deep(.el-collapse-item__header) {
|
|
193
|
+
border-bottom: none;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.dataset-card {
|
|
198
|
+
padding-left: 5px;
|
|
199
|
+
padding-right: 5px;
|
|
200
|
+
position: relative;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.title {
|
|
204
|
+
padding-bottom: 0.75rem;
|
|
205
|
+
font-family: Asap;
|
|
206
|
+
font-size: 14px;
|
|
207
|
+
font-weight: bold;
|
|
208
|
+
font-stretch: normal;
|
|
209
|
+
font-style: normal;
|
|
210
|
+
line-height: 1.5;
|
|
211
|
+
letter-spacing: 1.05px;
|
|
212
|
+
color: #484848;
|
|
213
|
+
cursor: pointer;
|
|
214
|
+
}
|
|
215
|
+
.card {
|
|
216
|
+
padding-top: 12px;
|
|
217
|
+
position: relative;
|
|
218
|
+
display: flex;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.card-left {
|
|
222
|
+
flex: 1;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.card-right {
|
|
226
|
+
flex: 1.3;
|
|
227
|
+
padding-left: 6px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.button {
|
|
231
|
+
z-index: 10;
|
|
232
|
+
font-family: Asap;
|
|
233
|
+
font-size: 14px;
|
|
234
|
+
font-weight: normal;
|
|
235
|
+
font-stretch: normal;
|
|
236
|
+
font-style: normal;
|
|
237
|
+
line-height: normal;
|
|
238
|
+
letter-spacing: normal;
|
|
239
|
+
background-color: $app-primary-color;
|
|
240
|
+
border: $app-primary-color;
|
|
241
|
+
color: white;
|
|
242
|
+
cursor: pointer;
|
|
243
|
+
margin-top: 8px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.button:hover {
|
|
247
|
+
background-color: $app-primary-color;
|
|
248
|
+
color: white;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.banner-img {
|
|
252
|
+
width: 128px;
|
|
253
|
+
height: 128px;
|
|
254
|
+
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
|
255
|
+
background-color: #ffffff;
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
}
|
|
258
|
+
.details {
|
|
259
|
+
font-family: Asap;
|
|
260
|
+
font-size: 14px;
|
|
261
|
+
font-weight: normal;
|
|
262
|
+
font-stretch: normal;
|
|
263
|
+
font-style: normal;
|
|
264
|
+
line-height: 1.5;
|
|
265
|
+
letter-spacing: 1.05px;
|
|
266
|
+
color: #484848;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.badges-container {
|
|
270
|
+
margin-top: 0.75rem;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.loading-icon {
|
|
274
|
+
z-index: 20;
|
|
275
|
+
width: 40px;
|
|
276
|
+
height: 40px;
|
|
277
|
+
left: 80px;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.loading-icon :deep(.el-loading-mask) {
|
|
281
|
+
background-color: rgba(117, 190, 218, 0) !important;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.loading-icon :deep(.el-loading-spinner .path) {
|
|
285
|
+
stroke: $app-primary-color;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.title {
|
|
289
|
+
font: inherit;
|
|
290
|
+
margin-top:4px;
|
|
291
|
+
padding-right:30px;
|
|
292
|
+
vertical-align:middle;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.acupointTags {
|
|
296
|
+
margin-right:4px;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.float-button-container {
|
|
300
|
+
position: absolute;
|
|
301
|
+
bottom: 8px;
|
|
302
|
+
right: 16px;
|
|
303
|
+
opacity: 0;
|
|
304
|
+
visibility: hidden;
|
|
305
|
+
|
|
306
|
+
.card:hover & {
|
|
307
|
+
opacity: 1;
|
|
308
|
+
visibility: visible;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
</style>
|