@abi-software/map-side-bar 2.14.6 → 2.14.8-demo.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.
@@ -0,0 +1,946 @@
1
+ <template>
2
+ <div
3
+ ref="cardElementRef"
4
+ class="card"
5
+ :class="{ active: isActive }"
6
+ :style="cardStyleVars"
7
+ >
8
+ <div
9
+ class="card-header"
10
+ @click="openCard"
11
+ >
12
+ <div class="title-content">
13
+ <div class="card-title">
14
+ {{ cellType.preferredLabel }}
15
+ </div>
16
+ <div class="card-keywords">
17
+ <span>{{ cellType.species }}</span>
18
+ <div class="card-chips">
19
+ <span
20
+ v-for="somaLocation in cellType.somaLocations"
21
+ class="card-chip"
22
+ :key="somaLocation">
23
+ {{ somaLocation }}
24
+ </span>
25
+ </div>
26
+ <span class="source-publication-chip" v-if="cellType.sourceNomenclature">
27
+ {{ cellType.sourceNomenclatureLabel }}
28
+ </span>
29
+ </div>
30
+ <el-button
31
+ v-if="isActive && (cellType.alertNotes?.length || cellType.curatorNotes?.length)"
32
+ round
33
+ size="small"
34
+ class="alert-chip"
35
+ @click.stop="showAlertMessage"
36
+ >
37
+ <el-icon class="alert"><el-icon-warn-triangle-filled /></el-icon>
38
+ Notes
39
+ </el-button>
40
+ </div>
41
+ <div class="title-buttons" @click.stop>
42
+ <CopyToClipboard @copied="onCopied" :content="updatedCopyContent" />
43
+ <el-popover
44
+ width="auto"
45
+ trigger="hover"
46
+ :teleported="false"
47
+ popper-class="popover-map-pin"
48
+ >
49
+ <template #reference>
50
+ <el-button class="button-circle" circle @click="closeCard">
51
+ <el-icon color="white">
52
+ <el-icon-close />
53
+ </el-icon>
54
+ </el-button>
55
+ </template>
56
+ <span>Close</span>
57
+ </el-popover>
58
+ </div>
59
+ </div>
60
+ <div class="card-details">
61
+ <div class="card-details-inner">
62
+ <div v-if="cellType.entity" class="card-section">
63
+ <div class="card-section-title">Entity</div>
64
+ <span>{{ cellType.entity }}</span>
65
+ </div>
66
+ <div v-if="cellType.species" class="card-section">
67
+ <div class="card-section-title">Species</div>
68
+ <span>{{ cellType.species }}</span>
69
+ </div>
70
+ <div v-if="cellType.somaLocations?.length" class="card-section">
71
+ <div class="card-section-title">Soma Location</div>
72
+ <div class="card-list-items">
73
+ <div
74
+ v-for="location in somaLocations"
75
+ class="card-list-item"
76
+ :key="location.id"
77
+ @mouseenter="showSomaLocation(location.name)"
78
+ @mouseleave="showSomaLocation()"
79
+ >
80
+ <span>{{ location.name }}</span>
81
+ <div class="card-list-search">
82
+ <el-popover
83
+ width="180"
84
+ trigger="hover"
85
+ :teleported="true"
86
+ :append-to="cardElement"
87
+ popper-class="popover-origin-help popover-search-actions"
88
+ @show="onSearchPopoverShow(location.id)"
89
+ @hide="onSearchPopoverHide(location.id)"
90
+ >
91
+ <template #reference>
92
+ <el-icon
93
+ class="status-search-icon"
94
+ :class="{ 'is-visible': activeSearchPopoverLocationId === location.id }"
95
+ >
96
+ <el-icon-search />
97
+ </el-icon>
98
+ </template>
99
+ <div class="search-action-list">
100
+ <button
101
+ type="button"
102
+ class="search-action-button"
103
+ @click="openDatasetSearch(location.name)"
104
+ >
105
+ Search dataset
106
+ </button>
107
+ <button
108
+ type="button"
109
+ class="search-action-button"
110
+ @click="openConnectivitySearch(location.name)"
111
+ >
112
+ Search connectivity
113
+ </button>
114
+ </div>
115
+ </el-popover>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ <div v-if="cellType.circuitRole" class="card-section">
121
+ <div class="card-section-title">Circuit Role</div>
122
+ <span>{{ cellType.circuitRole }}</span>
123
+ </div>
124
+ <div v-if="cellType.creLine" class="card-section">
125
+ <div class="card-section-title">Cre Line</div>
126
+ <span>{{ cellType.creLine }}</span>
127
+ </div>
128
+ <div v-if="formattedMarkerGenes.length" class="card-section">
129
+ <div class="card-section-title">Marker Genes</div>
130
+ <div class="marker-genes-list">
131
+ <a
132
+ v-for="markerGene in formattedMarkerGenes"
133
+ :key="markerGene.key"
134
+ class="marker-gene-link"
135
+ :href="markerGene.uri"
136
+ target="_blank"
137
+ rel="noopener noreferrer"
138
+ >
139
+ <span>{{ markerGene.name }}</span>
140
+ <sup v-if="markerGene.expression">{{ markerGene.expression }}</sup>
141
+ <IconOpenExternal class="external-link-icon" />
142
+ </a>
143
+ </div>
144
+ </div>
145
+ <div v-if="cellType.fiberTypeString" class="card-section">
146
+ <div class="card-section-title">Axon Phenotype</div>
147
+ <div class="card-section-content">{{ cellType.fiberTypeString }}</div>
148
+ </div>
149
+ <div v-if="cellType.physiologyString" class="card-section">
150
+ <div class="card-section-title">Physiology</div>
151
+ <div class="card-section-content success">{{ cellType.physiologyString }}</div>
152
+ </div>
153
+ <div v-if="cellType.relatedCells?.length" class="card-section">
154
+ <div class="card-section-title">Related Species Variants</div>
155
+ <ul v-for="relatedCell in cellType.relatedCells" :key="relatedCell">
156
+ <li>{{ relatedCell.label }}</li>
157
+ </ul>
158
+ </div>
159
+ <div v-if="cellType.sourceNomenclature" class="card-section source-publication-section">
160
+ <div class="card-section-title">Source Publication</div>
161
+ <p>
162
+ <a
163
+ class="source-publication-link"
164
+ :href="cellType.sourceNomenclature"
165
+ target="_blank"
166
+ rel="noopener noreferrer"
167
+ >
168
+ {{ cellType.sourceNomenclatureLabel }}
169
+ <IconOpenExternal class="external-link-icon" />
170
+ </a>
171
+ </p>
172
+ </div>
173
+ <div
174
+ class="card-section"
175
+ v-if="cellType.alertNotes?.length || cellType.curatorNotes?.length"
176
+ ref="alertElement"
177
+ >
178
+ <div class="card-section-title">Notes</div>
179
+ <div class="alert-block">
180
+ <div class="alert-block-section" v-if="cellType.alertNotes?.length">
181
+ <div class="alert-block-title">Alert Notes:</div>
182
+ <div v-for="note in cellType.alertNotes"
183
+ v-html="formatAlertText(note)"
184
+ class="alert-block-note"
185
+ ></div>
186
+ </div>
187
+ <div class="alert-block-section" v-if="cellType.curatorNotes?.length">
188
+ <div class="alert-block-title">Curator Notes:</div>
189
+ <div v-for="note in cellType.curatorNotes"
190
+ v-html="formatAlertText(note)"
191
+ class="alert-block-note"
192
+ ></div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ </div>
199
+ </template>
200
+
201
+ <script>
202
+ import {
203
+ ElButton as Button,
204
+ ElIcon as Icon,
205
+ } from 'element-plus'
206
+ import { Warning as ElIconWarning } from '@element-plus/icons-vue'
207
+ import {
208
+ CopyToClipboard,
209
+ } from '@abi-software/map-utilities';
210
+ import '@abi-software/map-utilities/dist/style.css';
211
+ import EventBus from './EventBus.js'
212
+ import { capitalise, formatAlertText as formatAlertTextUtil, scrollToRef } from '../utils/common.js';
213
+ import IconOpenExternal from './icons/IconOpenExternal.vue';
214
+
215
+ const LOCATION_ID_MAP = {
216
+ 'soma_tg': 'trigeminal ganglion',
217
+ 'soma_drg': 'dorsal root ganglion',
218
+ };
219
+
220
+ export default {
221
+ name: 'CellCard',
222
+ components: {
223
+ Button,
224
+ Icon,
225
+ ElIconWarning,
226
+ CopyToClipboard,
227
+ IconOpenExternal,
228
+ },
229
+ props: {
230
+ cellType: {
231
+ type: Object,
232
+ required: true,
233
+ },
234
+ isActive: {
235
+ type: Boolean,
236
+ default: false,
237
+ },
238
+ },
239
+ emits: ['open', 'close', 'soma-location-hovered', 'dataset-search', 'connectivity-search'],
240
+ data() {
241
+ return {
242
+ cardElement: null,
243
+ activeSearchPopoverLocationId: null,
244
+ };
245
+ },
246
+ mounted: function () {
247
+ this.cardElement = this.$refs.cardElementRef;
248
+ },
249
+ computed: {
250
+ cardStyleVars: function() {
251
+ return {
252
+ '--cell-card-source-color': this.cellType?.sourceColor || this.cellType?.color || '#8300bf',
253
+ };
254
+ },
255
+ formattedMarkerGenes: function() {
256
+ return (this.cellType?.markerGenes || [])
257
+ .map((markerGene, index) => {
258
+ const name = String(markerGene?.name || '').trim();
259
+ const expression = String(markerGene?.expression || '').trim();
260
+ const uri = this.sanitizeMarkerGeneUri(markerGene?.uri, expression);
261
+
262
+ if (!name || !uri) {
263
+ return null;
264
+ }
265
+
266
+ return {
267
+ key: `${name}-${expression || 'none'}-${index}`,
268
+ name,
269
+ expression,
270
+ uri,
271
+ };
272
+ })
273
+ .filter(Boolean);
274
+ },
275
+ updatedCopyContent: function() {
276
+ const {
277
+ preferredLabel,
278
+ entity,
279
+ species,
280
+ somaLocations,
281
+ circuitRole,
282
+ creLine,
283
+ geneExpressionString,
284
+ fiberTypeString,
285
+ physiologyString,
286
+ relatedCells,
287
+ alertNotes,
288
+ curatorNotes,
289
+ sourceNomenclature,
290
+ sourceNomenclatureLabel
291
+ } = this.cellType;
292
+
293
+ const contentArray = [];
294
+ if (preferredLabel) {
295
+ contentArray.push(`<div><strong>Cell Type:</strong> ${preferredLabel}</div>`);
296
+ }
297
+ if (entity) {
298
+ contentArray.push(`<div><strong>Entity:</strong> ${entity}</div>`);
299
+ }
300
+ if (species) {
301
+ contentArray.push(`<div><strong>Species:</strong> ${species}</div>`);
302
+ }
303
+ if (somaLocations?.length) {
304
+ const items = somaLocations.map((location) => `<li>${location}</li>`).join('');
305
+ contentArray.push(`<div><strong>Soma Locations:</strong><ul>${items}</ul></div>`);
306
+ }
307
+ if (circuitRole) {
308
+ contentArray.push(`<div><strong>Circuit Role:</strong> ${circuitRole}</div>`);
309
+ }
310
+ if (creLine) {
311
+ contentArray.push(`<div><strong>Cre Line:</strong> ${creLine}</div>`);
312
+ }
313
+ if (geneExpressionString) {
314
+ contentArray.push(`<div><strong>Marker Genes:</strong> ${geneExpressionString}</div>`);
315
+ }
316
+ if (fiberTypeString) {
317
+ contentArray.push(`<div><strong>Axon Phenotype:</strong> ${fiberTypeString}</div>`);
318
+ }
319
+ if (physiologyString) {
320
+ contentArray.push(`<div><strong>Physiology:</strong> ${physiologyString}</div>`);
321
+ }
322
+ if (relatedCells?.length) {
323
+ const relatedItems = relatedCells
324
+ .map((cell) => cell?.label)
325
+ .filter(Boolean)
326
+ .map((label) => `<li>${label}</li>`)
327
+ .join('');
328
+ if (relatedItems) {
329
+ contentArray.push(`<div><strong>Related Species Variants:</strong><ul>${relatedItems}</ul></div>`);
330
+ }
331
+ }
332
+ if (sourceNomenclatureLabel) {
333
+ const sourceLabel = sourceNomenclature
334
+ ? `${sourceNomenclatureLabel} (<a href="${sourceNomenclature}">${sourceNomenclature}</a>)`
335
+ : sourceNomenclatureLabel;
336
+ contentArray.push(`<div><strong>Source Publication:</strong> ${sourceLabel}</div>`);
337
+ }
338
+
339
+ if (alertNotes?.length) {
340
+ const alertContent = alertNotes
341
+ .map((note) => formatAlertTextUtil(note))
342
+ .join('\n');
343
+ contentArray.push(`<div><strong>Alert Notes:</strong></div>\n${alertContent}`);
344
+ }
345
+
346
+ if (curatorNotes?.length) {
347
+ const curatorContent = curatorNotes
348
+ .map((note) => formatAlertTextUtil(note))
349
+ .join('\n');
350
+ contentArray.push(`<div><strong>Curator Notes:</strong></div>\n${curatorContent}`);
351
+ }
352
+
353
+ return contentArray.join('\n');
354
+ },
355
+ somaLocations: function() {
356
+ const mappedLocations = this.cellType.somaLocations.map((location) => {
357
+ const locationKey = Object.keys(LOCATION_ID_MAP).find((key) => LOCATION_ID_MAP[key] === location) || '';
358
+ const isClustered = this.cellType.clusterAttributes?.[locationKey];
359
+ if (isClustered) {
360
+ return {
361
+ name: capitalise(location),
362
+ id: locationKey,
363
+ }
364
+ }
365
+ return false;
366
+ });
367
+ return mappedLocations;
368
+ },
369
+ },
370
+ methods: {
371
+ sanitizeMarkerGeneUri: function(uri, expression = '') {
372
+ let normalizedUri = String(uri || '').trim();
373
+ const normalizedExpression = String(expression || '').trim();
374
+
375
+ if (!normalizedUri) return '';
376
+
377
+ if (normalizedExpression) {
378
+ const escapedExpression = normalizedExpression.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
379
+ normalizedUri = normalizedUri.replace(new RegExp(`\\s+${escapedExpression}$`, 'i'), '');
380
+ }
381
+
382
+ return normalizedUri.trim();
383
+ },
384
+ transformString: function(str) {
385
+ if (!str) return '';
386
+ // replace the string with ^ with <sup> and the next word with </sup>
387
+ return str.replace(/\^(\w+)/g, '<sup>$1</sup>');
388
+ },
389
+ onCopied: function() {
390
+ EventBus.emit('trackEvent', {
391
+ 'event_name': `portal_maps_cell_card_copy`,
392
+ 'category': this.cellType.preferredLabel || '',
393
+ 'location': 'map_sidebar_cell_card',
394
+ });
395
+ },
396
+ openCard: function() {
397
+ this.$emit('open', this.cellType.id);
398
+ },
399
+ closeCard: function() {
400
+ this.$emit('close');
401
+ },
402
+ showSomaLocation: function (name) {
403
+ this.$emit('soma-location-hovered', name);
404
+ },
405
+ openDatasetSearch: function (query) {
406
+ this.$emit('dataset-search', {
407
+ species: capitalise(this.cellType?.species),
408
+ location: query,
409
+ });
410
+ },
411
+ openConnectivitySearch: function (query) {
412
+ // Find the UBERON term from query value (label)
413
+ const availableDataRaw = localStorage.getItem('available-name-curie-mapping');
414
+ const availableData = availableDataRaw ? JSON.parse(availableDataRaw) : {};
415
+ const locationCurie = Object.keys(availableData).find(
416
+ (curie) => availableData[curie].toLowerCase() === query.toLowerCase()
417
+ );
418
+ const facets = locationCurie ? [
419
+ {
420
+ "facet": `[\"${locationCurie}\",[]]`,
421
+ "facetPropPath": "flatmap.connectivity.source.all",
422
+ "tagLabel": query,
423
+ "term": "All"
424
+ }
425
+ ] : [];
426
+ this.$emit('connectivity-search', {
427
+ facets: facets,
428
+ query: query,
429
+ });
430
+ },
431
+ onSearchPopoverShow: function (locationId) {
432
+ this.activeSearchPopoverLocationId = locationId;
433
+ },
434
+ onSearchPopoverHide: function (locationId) {
435
+ if (this.activeSearchPopoverLocationId === locationId) {
436
+ this.activeSearchPopoverLocationId = null;
437
+ }
438
+ },
439
+ showAlertMessage: function () {
440
+ scrollToRef(this, 'alertElement');
441
+ },
442
+ formatAlertText: function (text) {
443
+ return formatAlertTextUtil(text);
444
+ },
445
+ }
446
+ }
447
+ </script>
448
+
449
+ <style lang="scss" scoped>
450
+ .card {
451
+ position: relative;
452
+ font-family: Asap;
453
+ font-size: 14px;
454
+ box-sizing: border-box;
455
+
456
+ &::before {
457
+ content: '';
458
+ position: absolute;
459
+ top: 5px;
460
+ left: 5px;
461
+ width: calc(100% - 15px);
462
+ height: calc(100% - 10px);
463
+ border: 3px solid transparent;
464
+ border-radius: 5px;
465
+ box-sizing: border-box;
466
+ z-index: 1;
467
+ }
468
+
469
+ &.active::before,
470
+ &:hover::before {
471
+ border-color: $app-primary-color;
472
+ }
473
+
474
+ &:not(:first-child) {
475
+ margin-top: 5px;
476
+
477
+ &::after {
478
+ content: '';
479
+ position: absolute;
480
+ top: 0px;
481
+ left: 10px;
482
+ width: 455px; // Same as other cards in the sidebar
483
+ height: 2px; // Same as other cards in the sidebar
484
+ background-color: #e4e7ed;
485
+ z-index: 0;
486
+ }
487
+ }
488
+
489
+ .card-details {
490
+ display: none;
491
+ }
492
+
493
+ &.active {
494
+ background-color: #f7faff;
495
+
496
+ &::before {
497
+ top: 0;
498
+ left: 0;
499
+ width: 100%;
500
+ height: 100%;
501
+ }
502
+
503
+ .card-header {
504
+ cursor: default;
505
+
506
+ &::before {
507
+ opacity: 1;
508
+ }
509
+
510
+ .card-title {
511
+ margin: 0;
512
+ line-height: 1.3em !important;
513
+ font-size: 18px;
514
+ font-weight: bold;
515
+ color: $app-primary-color;
516
+ }
517
+
518
+ .card-keywords {
519
+ display: none;
520
+ }
521
+ }
522
+
523
+ .card-details {
524
+ display: block;
525
+ }
526
+ }
527
+ }
528
+
529
+ .card-header {
530
+ display: flex;
531
+ justify-content: space-between;
532
+ align-items: flex-start;
533
+ cursor: pointer;
534
+ position: relative;
535
+
536
+ &::before {
537
+ content: "";
538
+ position: absolute;
539
+ bottom: 7px;
540
+ left: 5px;
541
+ width: calc(100% - 10px);
542
+ height: 1px;
543
+ opacity: 0;
544
+ transition: opacity 0.25s ease;
545
+ }
546
+ }
547
+
548
+ .card-header,
549
+ .card-details {
550
+ position: relative;
551
+ z-index: 2;
552
+ }
553
+
554
+ .card-header,
555
+ .card-details-inner {
556
+ padding: 1rem;
557
+ }
558
+
559
+ .title-content {
560
+ display: flex;
561
+ flex-direction: column;
562
+ align-items: flex-start;
563
+ }
564
+
565
+ .card-title {
566
+ margin-bottom: 0.75rem;
567
+ font-weight: bold;
568
+ line-height: 1.5;
569
+ letter-spacing: 1.05px;
570
+ display: -webkit-box;
571
+ -webkit-line-clamp: 5;
572
+ line-clamp: 5;
573
+ -webkit-box-orient: vertical;
574
+ overflow: hidden;
575
+ }
576
+
577
+ .card-details-inner {
578
+ display: flex;
579
+ flex-direction: column;
580
+ gap: 1.75rem;
581
+ padding-top: 0;
582
+ }
583
+
584
+ .card-keywords,
585
+ .card-chips {
586
+ display: flex;
587
+ align-items: center;
588
+ gap: 0.5rem;
589
+
590
+ span {
591
+ color: #606266;
592
+ }
593
+ }
594
+
595
+ .card-chip {
596
+ display: inline-block;
597
+ padding: 2px 8px;
598
+ background-color: #f0f0f0;
599
+ border-radius: 12px;
600
+ transition: background-color 0.2s ease;
601
+
602
+ .card-details & {
603
+ padding: 4px 8px;
604
+ border: 1px solid #dcdcdc;
605
+
606
+ }
607
+ }
608
+
609
+ .card-list-items {
610
+ display: flex;
611
+ flex-direction: column;
612
+ gap: 0.25rem;
613
+ box-sizing: border-box;
614
+ position: relative;
615
+ }
616
+
617
+ .card-list-item {
618
+ width: 100%;
619
+ display: flex;
620
+ align-items: center;
621
+ justify-content: space-between;
622
+ gap: 0.5rem;
623
+ padding: 0.5rem;
624
+ position: relative;
625
+ box-sizing: border-box;
626
+
627
+ &::before {
628
+ content: '';
629
+ position: absolute;
630
+ inset: 0;
631
+ transition: background-color 0.2s ease, border-color 0.2s ease;
632
+ background-color: rgba($app-primary-color, 0.04);
633
+ border-left: 4px solid rgba($app-primary-color, 0.16);
634
+ }
635
+
636
+ &:hover::before {
637
+ background-color: rgba($app-primary-color, 0.07);
638
+ border-left-color: rgba($app-primary-color, 0.24);
639
+ }
640
+
641
+ > span {
642
+ line-height: 1.5em;
643
+ font-weight: 500;
644
+ }
645
+ }
646
+
647
+ .card-list-search {
648
+ display: flex;
649
+ gap: 0.25rem;
650
+ }
651
+
652
+ .status-search-icon {
653
+ font-size: 16px;
654
+ color: $app-primary-color;
655
+ cursor: pointer;
656
+ opacity: 0;
657
+ transition: opacity 0.2s ease;
658
+
659
+ &.is-visible {
660
+ opacity: 1;
661
+ }
662
+
663
+ &:hover {
664
+ color: #ac76c5;
665
+ }
666
+ }
667
+
668
+ .card-list-item:hover .status-search-icon {
669
+ opacity: 1;
670
+ }
671
+
672
+ :deep(.popover-origin-help.el-popover) {
673
+ font-family: 'Asap', sans-serif;
674
+ background: #f3ecf6 !important;
675
+ border: 1px solid $app-primary-color !important;
676
+ border-radius: 4px !important;
677
+ color: #303133 !important;
678
+ text-transform: none !important; // need to overide the tooltip text transform
679
+ font-weight: 400;
680
+
681
+ .el-popper__arrow {
682
+ &:before {
683
+ background: #f3ecf6 !important;
684
+ border-color: $app-primary-color;
685
+ background-color: #ffffff;
686
+ }
687
+ }
688
+ }
689
+
690
+ :deep(.popover-search-actions.el-popover) {
691
+ padding: 6px;
692
+ }
693
+
694
+ .search-action-list {
695
+ display: flex;
696
+ flex-direction: column;
697
+ gap: 4px;
698
+ }
699
+
700
+ .search-action-button {
701
+ border: 0;
702
+ width: 100%;
703
+ padding: 6px 8px;
704
+ text-align: left;
705
+ border-radius: 4px;
706
+ font-family: inherit;
707
+ font-size: 12px;
708
+ color: #303133;
709
+ background: transparent;
710
+ cursor: pointer;
711
+
712
+ &:hover {
713
+ background-color: rgba($app-primary-color, 0.12);
714
+ color: $app-primary-color;
715
+ }
716
+ }
717
+
718
+ .card-section {
719
+ .card-section-title {
720
+ font-weight: 600;
721
+ }
722
+
723
+ p {
724
+ margin: 0;
725
+ color: #606266;
726
+ }
727
+
728
+ ul {
729
+ margin: 0;
730
+ padding-left: 1rem;
731
+
732
+ li {
733
+ color: #606266;
734
+ }
735
+ }
736
+ }
737
+
738
+ .card-section {
739
+ .card-section-title {
740
+ display: block;
741
+ margin-bottom: 0.75rem;
742
+ font-size: 16px;
743
+ font-weight: 600;
744
+ text-transform: uppercase;
745
+ }
746
+ }
747
+
748
+ .card-section-content {
749
+ padding: 0.5rem;
750
+ background-color: #f0f0f0;
751
+ border-radius: 4px;
752
+ border: 1px solid #dcdcdc;
753
+
754
+ &.success {
755
+ border-color: #b3e5b3;
756
+ background-color: #f0f9eb;
757
+ }
758
+ }
759
+
760
+ .marker-genes-list {
761
+ display: flex;
762
+ flex-wrap: wrap;
763
+ gap: 0.5rem;
764
+ }
765
+
766
+ .marker-gene-link {
767
+ display: inline-flex;
768
+ align-items: flex-start;
769
+ gap: 0.1rem;
770
+ padding: 0.25rem 0.5rem;
771
+ font-size: 12px;
772
+ border: 1px solid $app-primary-color;
773
+ border-radius: 4px;
774
+ color: $app-primary-color;
775
+ background-color: #f9f2fc;
776
+ text-decoration: none;
777
+ line-height: 1.2;
778
+
779
+ &:hover {
780
+ background-image: linear-gradient(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.05));
781
+ }
782
+
783
+ sup {
784
+ font-size: 0.75em;
785
+ line-height: 1;
786
+ }
787
+ }
788
+
789
+ .external-link-icon {
790
+ display: inline-flex;
791
+ align-items: center;
792
+ width: 16px;
793
+ height: 16px;
794
+ margin-left: 2px;
795
+ color: currentColor;
796
+ opacity: 0.7;
797
+ vertical-align: middle;
798
+ }
799
+
800
+ .source-publication-chip,
801
+ .source-publication-link {
802
+ display: inline-block;
803
+ border: 1px solid var(--cell-card-source-color);
804
+ border-radius: 4px;
805
+ color: white !important;
806
+ text-decoration: none;
807
+ background-color: var(--cell-card-source-color);
808
+ }
809
+
810
+ .source-publication-chip {
811
+ padding: 2px 6px;
812
+ }
813
+
814
+ .alert-chip {
815
+ margin-top: 5px;
816
+ background-color: $app-primary-color;
817
+ border-color: $app-primary-color;
818
+ color: #fff;
819
+
820
+ &:hover {
821
+ color: #fff !important;
822
+ background-color: #ac76c5 !important;
823
+ border: 1px solid #ac76c5 !important;
824
+ }
825
+
826
+ :deep(> span) {
827
+ gap: 2px;
828
+ }
829
+
830
+ .alert {
831
+ width: 1rem;
832
+ height: 1rem;
833
+ color: inherit;
834
+ margin: 0;
835
+ }
836
+ }
837
+
838
+ .source-publication-link {
839
+ padding: 4px 8px;
840
+
841
+ &:hover {
842
+ background-image: linear-gradient(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.12));
843
+ }
844
+ }
845
+
846
+ :deep(.el-popper.popover-map-pin) {
847
+ padding: 4px 10px;
848
+ min-width: max-content;
849
+ font-family: Asap;
850
+ font-size: 12px;
851
+ line-height: inherit;
852
+ color: inherit;
853
+ background: #f3ecf6 !important;
854
+ border: 1px solid $app-primary-color;
855
+
856
+ & .el-popper__arrow::before {
857
+ border: 1px solid;
858
+ border-color: $app-primary-color;
859
+ background: #f3ecf6;
860
+ }
861
+ }
862
+
863
+ .title-buttons {
864
+ flex: 1 0 0%;
865
+ max-width: 20%;
866
+ flex-direction: row;
867
+ justify-content: end;
868
+ gap: 0.5rem;
869
+ display: none;
870
+
871
+ .card.active & {
872
+ display: flex;
873
+ }
874
+
875
+ :deep(.copy-clipboard-button) {
876
+ &,
877
+ &:hover,
878
+ &:focus {
879
+ border-color: $app-primary-color !important;
880
+ border-radius: 50%;
881
+ }
882
+
883
+ &.is-disabled {
884
+ border-color: #dab3ec !important;
885
+ }
886
+ }
887
+
888
+ .el-button + .el-button {
889
+ margin-left: 0 !important;
890
+ }
891
+ }
892
+
893
+ .button-circle {
894
+ margin: 0;
895
+ width: 24px !important;
896
+ height: 24px !important;
897
+ border: 1px solid $app-primary-color !important;
898
+
899
+ &,
900
+ &:hover,
901
+ &:focus,
902
+ &:active {
903
+ background-color: $app-primary-color;
904
+ border-color: $app-primary-color !important;
905
+ }
906
+
907
+ &.secondary {
908
+ background-color: white !important;
909
+ }
910
+ }
911
+
912
+ .alert-block {
913
+ background-color: var(--el-color-warning-light-9);
914
+ border: 1px dashed var(--el-color-warning);
915
+ padding: 0.75rem;
916
+ border-radius: 4px;
917
+ display: flex;
918
+ flex-direction: column;
919
+ gap: 1rem;
920
+
921
+ :deep(a) {
922
+ color: $app-primary-color;
923
+ word-break: break-all;
924
+
925
+ &:hover {
926
+ opacity: 0.8;
927
+ }
928
+ }
929
+ }
930
+
931
+ .alert-block-section {
932
+ .alert-block-title {
933
+ font-weight: 600;
934
+ margin-bottom: 0.5rem;
935
+ }
936
+
937
+ .alert-block-note {
938
+ color: #606266;
939
+ padding-left: 0.5rem;
940
+
941
+ + .alert-block-note {
942
+ margin-top: 0.5rem;
943
+ }
944
+ }
945
+ }
946
+ </style>