@abi-software/flatmapvuer 1.11.4 → 1.12.0-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/flatmapvuer",
3
- "version": "1.11.4",
3
+ "version": "1.12.0-beta.0",
4
4
  "license": "Apache-2.0",
5
5
  "files": [
6
6
  "dist/*",
@@ -44,7 +44,7 @@
44
44
  "./src/*": "./src/*"
45
45
  },
46
46
  "dependencies": {
47
- "@abi-software/map-utilities": "1.7.2",
47
+ "@abi-software/map-utilities": "^1.7.6",
48
48
  "@abi-software/sparc-annotation": "0.3.2",
49
49
  "@abi-software/svg-sprite": "1.0.2",
50
50
  "@element-plus/icons-vue": "^2.3.1",
package/src/App.vue CHANGED
@@ -68,6 +68,7 @@
68
68
  @pan-zoom-callback="panZoomcallback"
69
69
  @open-map="openMap"
70
70
  @ready="FlatmapReady"
71
+ @context-restored="FlatmapReady"
71
72
  :initial="initial"
72
73
  :helpMode="helpMode"
73
74
  :helpModeDialog="useHelpModeDialog"
@@ -297,7 +298,7 @@ export default {
297
298
  position: 'absolute',
298
299
  },
299
300
  displayCloseButton: false,
300
- initial: 'Rat',
301
+ initial: 'Human Male',
301
302
  helpMode: false,
302
303
  helpModeActiveItem: 0,
303
304
  helpModeLastItem: false,
@@ -359,6 +360,8 @@ export default {
359
360
  },
360
361
  mounted: function () {
361
362
  this.multiflatmapRef = this.$refs.multi;
363
+ window.multiflatmapRef = this.multiflatmapRef;
364
+ //window.flatmapRef = this.multiflatmapRef.getCurrentFlatmap();
362
365
  },
363
366
  watch: {
364
367
  helpMode: function (newVal) {
@@ -18,6 +18,7 @@
18
18
  <div class="beta-popovers" v-show="!disableUI">
19
19
  <div>
20
20
  <el-popover
21
+ v-if="displayWarning || isLegacy"
21
22
  placement="right"
22
23
  popper-class="warning-popper flatmap-popper"
23
24
  :teleported="false"
@@ -58,7 +59,10 @@ Please use `const` to assign meaningful names to them...
58
59
  SCKAN </a
59
60
  >.
60
61
  </p>
61
- <p v-else @mouseover="showTooltip(7)" @mouseout="hideTooltip(7)">
62
+ <p v-else
63
+ @mouseover="showTooltip(7)"
64
+ @mouseout="hideTooltip(7)"
65
+ >
62
66
  This map displays the connectivity of neuron populations.
63
67
  Specifically, those from the primarily rat-based
64
68
  <a
@@ -264,35 +268,17 @@ Please use `const` to assign meaningful names to them...
264
268
  :style="{ 'max-height': pathwaysMaxHeight + 'px' }"
265
269
  v-popover:checkBoxPopover
266
270
  >
267
- <el-popover
268
- content="Location of the featured dataset"
269
- placement="bottom"
270
- :teleported="true"
271
- trigger="manual"
272
- width="max-content"
273
- :offset="-10"
274
- popper-class="flatmap-popper flatmap-teleport-popper"
275
- :visible="hoverVisibilities[9].value && showStarInLegend"
271
+ <dynamic-legends
272
+ v-if="legendEntry.length"
273
+ identifierKey="prompt"
274
+ colourKey="colour"
275
+ styleKey="style"
276
+ :legends="legendEntry"
277
+ :showStarInLegend="true"
278
+ :showDatasetMarkerTooltip="showDatasetMarkerTooltip"
276
279
  ref="featuredMarkerPopover"
277
- >
278
- <template #reference>
279
- <div
280
- v-popover:featuredMarkerPopover
281
- @mouseover="showTooltip(9)"
282
- @mouseout="hideTooltip(9)"
283
- >
284
- <dynamic-legends
285
- v-if="legendEntry.length"
286
- identifierKey="prompt"
287
- colourKey="colour"
288
- styleKey="style"
289
- :legends="legendEntry"
290
- :showStarInLegend="true"
291
- class="svg-legends-container"
292
- />
293
- </div>
294
- </template>
295
- </el-popover>
280
+ class="svg-legends-container"
281
+ />
296
282
  <!-- The line below places the yellowstar svg on the left, and the text "Featured markers on the right" with css so they are both centered in the div -->
297
283
  <el-popover
298
284
  content="Find these markers for data. The number inside the markers is the number of datasets available for each marker."
@@ -647,7 +633,7 @@ import {
647
633
  import { capitalise } from './utilities.js'
648
634
  import yellowstar from '../icons/yellowstar'
649
635
  import ResizeSensor from 'css-element-queries/src/ResizeSensor'
650
- import * as flatmap from 'https://cdn.jsdelivr.net/npm/@abi-software/flatmap-viewer@4.3.5/+esm'
636
+ import flatmap from '../services/flatmapLoader.js'
651
637
  import { AnnotationService } from '@abi-software/sparc-annotation'
652
638
  import { mapState } from 'pinia'
653
639
  import { useMainStore } from '@/store/index'
@@ -775,10 +761,19 @@ export default {
775
761
  setVisibilityFilter: function (filter) {
776
762
  // More filter options -> this.mapImp.featureFilterRanges()
777
763
  if (this.mapImp) {
778
- if (filter) {
779
- this.mapImp.setVisibilityFilter(filter);
764
+ if (this.mapImp.contextLost) {
765
+ if (filter) {
766
+ this.filterToRestore = markRaw(JSON.parse(JSON.stringify(filter)));
767
+ } else {
768
+ this.filterToRestore = undefined;
769
+ }
780
770
  } else {
781
- this.mapImp.clearVisibilityFilter();
771
+ if (filter) {
772
+ this.mapImp.setVisibilityFilter(filter);
773
+ } else {
774
+ this.mapImp.clearVisibilityFilter();
775
+ }
776
+ this.filterToRestore = undefined;
782
777
  }
783
778
  }
784
779
  },
@@ -937,6 +932,17 @@ export default {
937
932
  this.mapImp.clearAnnotationFeature()
938
933
  }
939
934
  },
935
+ forceContextLoss: function() {
936
+ if (this.mapImp && !this.mapImp.contextLost && !this.loading) {
937
+ this.mapImp.forceContextLoss()
938
+ }
939
+ },
940
+ forceContextRestore: function() {
941
+ if (this.mapImp) {
942
+ this.flatmapError = null
943
+ this.mapImp.forceContextRestore()
944
+ }
945
+ },
940
946
  /**
941
947
  * @public
942
948
  * Function to fire the ``trash`` action.
@@ -1706,6 +1712,10 @@ export default {
1706
1712
  eventType: eventType,
1707
1713
  }
1708
1714
  this.annotationEventCallback(payload, data)
1715
+ } else if (eventType === 'context-lost') {
1716
+ this.onContextLost()
1717
+ } else if (eventType === 'context-restored') {
1718
+ this.onContextRestored()
1709
1719
  } else if (eventType === 'pan-zoom') {
1710
1720
  this.$emit('pan-zoom-callback', data)
1711
1721
  } else {
@@ -1813,7 +1823,7 @@ export default {
1813
1823
  setConnectivityDataSource: function (viewingMode, data) {
1814
1824
  // Exploration mode, only path click will be used as data source
1815
1825
  if (viewingMode === 'Exploration') {
1816
- this.connectivityDataSource = data.models.startsWith('ilxtr:') ? data.models : '';
1826
+ this.connectivityDataSource = data.models?.startsWith('ilxtr:') ? data.models : '';
1817
1827
  } else {
1818
1828
  // Other modes, it can be anything
1819
1829
  // (annotation drawing doesn't have featureId or models)
@@ -2401,9 +2411,17 @@ export default {
2401
2411
  } else {
2402
2412
  // skip the unavailable tooltips
2403
2413
  this.helpModeActiveIndex += 1;
2414
+ this.setHelpMode(helpMode);
2404
2415
  }
2405
2416
  }
2406
2417
 
2418
+ // Skip checkbox tooltip if pathway filter is not shown
2419
+ const activePopoverObjAfter = this.hoverVisibilities[this.helpModeActiveIndex];
2420
+ if (activePopoverObjAfter?.ref === 'checkBoxPopover' && !this.showPathwayFilter) {
2421
+ this.helpModeActiveIndex += 1;
2422
+ this.setHelpMode(helpMode);
2423
+ }
2424
+
2407
2425
  if (!helpMode) {
2408
2426
  // reset to iniital state
2409
2427
  this.helpModeActiveIndex = this.helpModeInitialIndex;
@@ -2765,10 +2783,6 @@ export default {
2765
2783
  if (!this.mapImp && !this.loading) {
2766
2784
  this.loading = true
2767
2785
  this.flatmapError = null
2768
- let minimap = false
2769
- if (this.displayMinimap) {
2770
- minimap = { position: 'top-right' }
2771
- }
2772
2786
 
2773
2787
  //As for flatmap-viewer@2.2.7, see below for the documentation
2774
2788
  //for the identifier:
@@ -2820,7 +2834,7 @@ export default {
2820
2834
  //debug: true,
2821
2835
  minZoom: this.minZoom,
2822
2836
  tooltips: this.tooltips,
2823
- minimap: minimap,
2837
+ minimap: false,
2824
2838
  container: this.$refs.display,
2825
2839
  // tooltipDelay: 15, // new feature to delay tooltips showing
2826
2840
  }
@@ -2896,7 +2910,6 @@ export default {
2896
2910
  this.computePathControlsMaximumHeight()
2897
2911
  if (this.mapImp) {
2898
2912
  this.mapImp.resize()
2899
- this.showMinimap(this.displayMinimap)
2900
2913
  }
2901
2914
  } catch {
2902
2915
  console.error('Map resize error')
@@ -2979,12 +2992,16 @@ export default {
2979
2992
  this.processTaxon(this.mapImp.taxonIdentifiers, state ? state['taxonSelection'] : undefined)
2980
2993
  this.containsAlert = "alert" in this.mapImp.featureFilterRanges()
2981
2994
  this.flatmapLegends = this.mapImp.flatmapLegend
2982
- this.addResizeButtonToMinimap()
2983
2995
  this.loading = false
2984
2996
  this.computePathControlsMaximumHeight()
2985
2997
  this.mapResize()
2986
2998
  this.handleMapClick();
2987
2999
  this.setInitMapState();
3000
+ if (this.displayMinimap) {
3001
+ const minimapOptions = { position: 'top-right' };
3002
+ this.mapImp.createMinimap(minimapOptions);
3003
+ this.addResizeButtonToMinimap()
3004
+ }
2988
3005
  /**
2989
3006
  * This is ``onFlatmapReady`` event.
2990
3007
  * @arg ``this`` (Component Vue Instance)
@@ -3007,14 +3024,38 @@ export default {
3007
3024
  });
3008
3025
  }
3009
3026
  },
3010
- /**
3011
- * @public
3012
- * Function to show or hide the minimap
3013
- * by providing ``flag`` (boolean) value.
3014
- * @arg {Boolean} `flag`
3015
- */
3016
- showMinimap: function (flag) {
3017
- if (this.mapImp) this.mapImp.showMinimap(flag)
3027
+ onContextLost: function() {
3028
+ this.lastViewport = markRaw(this.mapImp.getState())
3029
+ this.flatmapError = {};
3030
+ this.flatmapError['title'] = 'GL context lost!'
3031
+ this.flatmapError['messages'] = [`GL context is lost due to too many concurrent GL contexts. Please try using the Restore Context button.`]
3032
+ this.flatmapError['button'] = {
3033
+ text: 'Restore Context',
3034
+ callback: () => {
3035
+ this.forceContextRestore()
3036
+ }
3037
+ };
3038
+ },
3039
+ onContextRestored: function() {
3040
+ if (this.mapImp) {
3041
+ this.handleMapClick()
3042
+ this.setInitMapState()
3043
+ const lostState = this.getState()
3044
+ if (lostState) {
3045
+ lostState.viewport = this.lastViewport
3046
+ }
3047
+ this.restoreMapState(lostState)
3048
+ if (this.displayMinimap) {
3049
+ const minimapOptions = { position: 'top-right' };
3050
+ this.mapImp.createMinimap(minimapOptions);
3051
+ this.addResizeButtonToMinimap()
3052
+ }
3053
+ if (this.filterToRestore) {
3054
+ this.mapImp.setVisibilityFilter(this.filterToRestore)
3055
+ this.filterToRestore = undefined
3056
+ }
3057
+ this.$emit('context-restored', this)
3058
+ }
3018
3059
  },
3019
3060
  /**
3020
3061
  * @public
@@ -3187,6 +3228,15 @@ export default {
3187
3228
  type: Number,
3188
3229
  default: 0,
3189
3230
  },
3231
+ /**
3232
+ * This flag dictate whether a context will be allocatged
3233
+ * for this instance
3234
+ */
3235
+ render: {
3236
+ type: Boolean,
3237
+ default: true,
3238
+ },
3239
+
3190
3240
  /**
3191
3241
  * The option to create map on component mounted.
3192
3242
  */
@@ -3352,6 +3402,7 @@ export default {
3352
3402
  },
3353
3403
  data: function () {
3354
3404
  return {
3405
+ filterToRestore: undefined,
3355
3406
  flatmapError: null,
3356
3407
  sensor: null,
3357
3408
  mapManagerRef: undefined,
@@ -3469,6 +3520,7 @@ export default {
3469
3520
  taxonLeaveDelay: undefined,
3470
3521
  connectivityFilters: [],
3471
3522
  flatmapLegends: [],
3523
+ lastViewport: undefined,
3472
3524
  }
3473
3525
  },
3474
3526
  computed: {
@@ -3505,7 +3557,10 @@ export default {
3505
3557
  },
3506
3558
  legendEntry: function () {
3507
3559
  return [...this.flatmapLegends, ...this.externalLegends]
3508
- }
3560
+ },
3561
+ showDatasetMarkerTooltip: function () {
3562
+ return this.hoverVisibilities[9].value;
3563
+ },
3509
3564
  },
3510
3565
  watch: {
3511
3566
  entry: function () {
@@ -3524,6 +3579,15 @@ export default {
3524
3579
  this.setHelpMode(this.helpMode);
3525
3580
  }
3526
3581
  },
3582
+ render: function(val) {
3583
+ if (val) {
3584
+ if (this.mapImp && this.mapImp.contextLost && !this.loading) {
3585
+ this.$nextTick(() => {
3586
+ this.forceContextRestore()
3587
+ })
3588
+ }
3589
+ }
3590
+ },
3527
3591
  state: {
3528
3592
  handler: function (state, oldVal) {
3529
3593
  if (state !== oldVal) {
@@ -58,6 +58,7 @@
58
58
  :enableOpenMapUI="enableOpenMapUI"
59
59
  :openMapOptions="openMapOptions"
60
60
  :disableUI="disableUI"
61
+ @context-restored="onContextRestored"
61
62
  @view-latest-map="viewLatestMap"
62
63
  @resource-selected="resourceSelected"
63
64
  @ready="FlatmapReady"
@@ -82,6 +83,7 @@
82
83
  @shown-tooltip="onTooltipShown"
83
84
  @shown-map-tooltip="onMapTooltipShown"
84
85
  :renderAtMounted="renderAtMounted"
86
+ :render="render && (activeSpecies == key)"
85
87
  :displayMinimap="displayMinimap"
86
88
  :showStarInLegend="showStarInLegend"
87
89
  style="height: 100%"
@@ -104,7 +106,7 @@
104
106
  import { markRaw } from 'vue'
105
107
  import EventBus from './EventBus'
106
108
  import FlatmapVuer from './FlatmapVuer.vue'
107
- import * as flatmap from 'https://cdn.jsdelivr.net/npm/@abi-software/flatmap-viewer@4.3.5/+esm'
109
+ import flatmap from '../services/flatmapLoader.js'
108
110
  import {
109
111
  ElCol as Col,
110
112
  ElOption as Option,
@@ -286,6 +288,18 @@ export default {
286
288
  */
287
289
  this.$emit('resource-selected', action)
288
290
  },
291
+ /**
292
+ * @public
293
+ * Function to emit ``context-restored`` event after the flatmap is restored.
294
+ * @arg {Object} `component`
295
+ */
296
+ onContextRestored: function (component) {
297
+ /**
298
+ * This event is emitted by ``ContextRestore`` method after the flatmap is restored.
299
+ * @arg component
300
+ */
301
+ this.$emit('context-restored', component)
302
+ },
289
303
  /**
290
304
  * @public
291
305
  * Function to emit ``ready`` event after the flatmap is loaded.
@@ -619,6 +633,13 @@ export default {
619
633
  type: Boolean,
620
634
  default: false,
621
635
  },
636
+ /**
637
+ * This option enable rendering of the map
638
+ */
639
+ render: {
640
+ type: Boolean,
641
+ default: true,
642
+ },
622
643
  /**
623
644
  * The option to show tooltips for help mode.
624
645
  */
@@ -858,6 +879,13 @@ export default {
858
879
  immediate: true,
859
880
  deep: true,
860
881
  },
882
+ activeSpecies: {
883
+ handler: function (value, oldValue) {
884
+ if (oldValue) {
885
+ this.$refs[oldValue][0].forceContextLoss()
886
+ }
887
+ }
888
+ }
861
889
  },
862
890
  }
863
891
  </script>
@@ -887,6 +915,8 @@ export default {
887
915
  left: 16px;
888
916
  top: 44px;
889
917
  position: absolute;
918
+ width: fit-content;
919
+
890
920
  :deep(.el-input__inner) {
891
921
  color: rgb(48, 49, 51);
892
922
  padding-top: 0.25em;
@@ -6,37 +6,55 @@
6
6
  :key="item[identifierKey]"
7
7
  :label="item[identifierKey]"
8
8
  >
9
- <div class="legend-item" v-if="legendStyle(item)">
10
- <template v-if="clipPathLegends.includes(legendStyle(item))">
11
- <div
12
- :class="legendStyle(item)"
13
- :style="customClipPathStyle(item, true)"
14
- >
9
+ <template v-if="item[identifierKey] === 'Featured dataset marker'">
10
+ <el-popover
11
+ content="Location of the featured dataset"
12
+ placement="right"
13
+ :teleported="true"
14
+ trigger="manual"
15
+ width="max-content"
16
+ :offset="0"
17
+ popper-class="flatmap-popper flatmap-teleport-popper"
18
+ :visible="tooltipVisible"
19
+ ref="featuredMarkerPopover"
20
+ >
21
+ <template #reference>
15
22
  <div
16
- :class="legendStyle(item)"
17
- :style="customClipPathStyle(item, false)"
23
+ v-popover:featuredMarkerPopover
24
+ @mouseover="onMouseOver"
25
+ @mouseout="onMouseOut"
18
26
  >
27
+ <LegendItem
28
+ :item="item"
29
+ :identifierKey="identifierKey"
30
+ :styleKey="styleKey"
31
+ :showStarInLegend="showStarInLegend"
32
+ />
19
33
  </div>
20
- </div>
21
- </template>
22
- <template v-else>
23
- <div
24
- :class="legendStyle(item)"
25
- :style="customStyle(item)"
26
- >
27
- </div>
28
- </template>
29
- <div class="label">{{ capitalise(item[identifierKey]) }}</div>
30
- </div>
34
+ </template>
35
+ </el-popover>
36
+ </template>
37
+ <template v-else>
38
+ <LegendItem
39
+ :item="item"
40
+ :identifierKey="identifierKey"
41
+ :styleKey="styleKey"
42
+ :showStarInLegend="showStarInLegend"
43
+ />
44
+ </template>
31
45
  </div>
32
46
  </div>
33
47
  </template>
34
48
 
35
49
  <script>
36
- const starTemplate = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="<fillColor>" stroke="<borderColor>" stroke-width="<borderWidth>" d="M11.0748 3.25583C11.4141 2.42845 12.5859 2.42845 12.9252 3.25583L14.6493 7.45955C14.793 7.80979 15.1221 8.04889 15.4995 8.07727L20.0303 8.41798C20.922 8.48504 21.2841 9.59942 20.6021 10.1778L17.1369 13.1166C16.8482 13.3614 16.7225 13.7483 16.8122 14.1161L17.8882 18.5304C18.1 19.3992 17.152 20.0879 16.3912 19.618L12.5255 17.2305C12.2034 17.0316 11.7966 17.0316 11.4745 17.2305L7.60881 19.618C6.84796 20.0879 5.90001 19.3992 6.1118 18.5304L7.18785 14.1161C7.2775 13.7483 7.1518 13.3614 6.86309 13.1166L3.3979 10.1778C2.71588 9.59942 3.07796 8.48504 3.96971 8.41798L8.50046 8.07727C8.87794 8.04889 9.20704 7.80979 9.35068 7.45955L11.0748 3.25583Z"/></svg>'
50
+ import LegendItem from './LegendItem.vue';
51
+
37
52
  /* eslint-disable no-alert, no-console */
38
53
  export default {
39
54
  name: "DynamicLegends",
55
+ components: {
56
+ LegendItem,
57
+ },
40
58
  props: {
41
59
  identifierKey: {
42
60
  type: String,
@@ -60,58 +78,35 @@ export default {
60
78
  type: Boolean,
61
79
  default: false,
62
80
  },
81
+ showDatasetMarkerTooltip: {
82
+ type: Boolean,
83
+ default: false,
84
+ },
85
+ },
86
+ data() {
87
+ return {
88
+ isHovering: false,
89
+ hoverTimeout: null,
90
+ };
63
91
  },
64
92
  computed: {
65
- clipPathLegends: function () {
66
- return ['exoid', 'hexagon'];
93
+ tooltipVisible() {
94
+ // Show tooltip when either help mode is active OR user is hovering
95
+ return (this.showDatasetMarkerTooltip && this.showStarInLegend) || this.isHovering;
67
96
  },
68
97
  },
69
98
  methods: {
70
- capitalise: function (label) {
71
- return label.charAt(0).toUpperCase() + label.slice(1).toLowerCase();
72
- },
73
- customStyle: function(item) {
74
- const specifiedColour = item["color"] ? item["color"] : item["colour"];
75
- let colour = specifiedColour ? specifiedColour : "transparent";
76
- let borderColour = item.border ? item.border : "black";
77
- if (specifiedColour && !item.border) {
78
- borderColour = colour;
79
- }
80
- if (item[this.styleKey] === 'star') {
81
- let star = starTemplate.replace('<fillColor>', colour);
82
- star = star.replace('<borderColor>', borderColour);
83
- star = star.replace('<borderWidth>', borderColour ? '2' : '0');
84
- star = 'data:image/svg+xml,' + encodeURIComponent(star);
85
- return { 'color': colour, 'background-image': `url(${star})` };
86
- } else if (item[this.styleKey] === 'line') {
87
- return {'color': colour};
88
- } else {
89
- return { 'background-color': colour, 'border-color': borderColour};
90
- }
91
- },
92
- customClipPathStyle: function(item, isBorder) {
93
- const style = this.customStyle(item);
94
- if (isBorder) {
95
- style['background-color'] = style['border-color'];
96
- } else {
97
- style.scale = 0.7;
98
- }
99
- return style;
99
+ onMouseOver() {
100
+ clearTimeout(this.hoverTimeout);
101
+ this.hoverTimeout = setTimeout(() => {
102
+ this.isHovering = true;
103
+ }, 500);
100
104
  },
101
- legendStyle: function (item) {
102
- if (item[this.styleKey] === "star") {
103
- if (item[this.identifierKey] === "Featured dataset marker") {
104
- if (!this.showStarInLegend) {
105
- return;
106
- }
107
- }
108
- return 'star';
109
- } else if (this.clipPathLegends.includes(item[this.styleKey])) {
110
- return item[this.styleKey];
111
- } else if (item[this.styleKey] === 'line') {
112
- return [item[this.styleKey], item.dashed ? 'dashed' : '', item.arrow ? 'arrow' : ''];
113
- }
114
- return [item[this.styleKey], 'shape'];
105
+ onMouseOut() {
106
+ clearTimeout(this.hoverTimeout);
107
+ this.hoverTimeout = setTimeout(() => {
108
+ this.isHovering = false;
109
+ }, 500);
115
110
  },
116
111
  },
117
112
  };
@@ -125,92 +120,4 @@ export default {
125
120
  .legend-container {
126
121
  width: max-content;
127
122
  }
128
-
129
- .legend-item {
130
- display: flex;
131
- align-items: center;
132
- margin: 8px 12.5px;
133
- }
134
-
135
- .line {
136
- position: relative;
137
- width: 20px;
138
- border-top: 2px solid currentColor;
139
- }
140
-
141
- .line.dashed {
142
- border-top: 2px dashed currentColor;
143
- }
144
-
145
- .line::after {
146
- content: "";
147
- position: absolute;
148
- right: -2px;
149
- top: -5px;
150
- width: 0;
151
- height: 0;
152
- border-left: 7px solid currentColor;
153
- border-top: 4px solid transparent;
154
- border-bottom: 4px solid transparent;
155
- display: none;
156
- }
157
-
158
- .line.arrow::after {
159
- display: block;
160
- }
161
-
162
- .shape {
163
- height: 16px;
164
- width: 16px;
165
- border-color: black;
166
- border-style: solid;
167
- border-width: 2px;
168
- background-color: transparent;
169
- display: inline-block;
170
- }
171
-
172
- .circle {
173
- border-radius: 50%;
174
- }
175
-
176
- .rounded-square {
177
- border-radius: 30%;
178
- }
179
-
180
- .hexagon {
181
- width: 20px;
182
- height: calc(20px * 0.866);
183
- background-color: transparent;
184
- clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
185
- -webkit-clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
186
- }
187
-
188
- .exoid {
189
- width: 20px;
190
- height: 25px;
191
- background-color: transparent;
192
- clip-path: path(
193
- "M9.96 0.72 c-2.01 3.53 -5.81 5.74 -9.92 5.74 l-0.15 0.23 c1.94 3.42 1.94 7.6 0 11.02 l0.15 0.23 c4.07 0 7.9 2.2 9.92 5.74 c2.01 -3.53 5.81 -5.74 9.92 -5.74 c-2.01 -3.53 -2.01 -7.94 0 -11.55 C15.81 6.5 12.04 4.29 9.96 0.72z"
194
- );
195
- -webkit-clip-path: path(
196
- "M9.96 0.72 c-2.01 3.53 -5.81 5.74 -9.92 5.74 l-0.15 0.23 c1.94 3.42 1.94 7.6 0 11.02 l0.15 0.23 c4.07 0 7.9 2.2 9.92 5.74 c2.01 -3.53 5.81 -5.74 9.92 -5.74 c-2.01 -3.53 -2.01 -7.94 0 -11.55 C15.81 6.5 12.04 4.29 9.96 0.72z"
197
- );
198
- }
199
-
200
- .star {
201
- width: 25px;
202
- height: 25px;
203
- background-color: transparent !important;
204
- background-repeat: no-repeat;
205
- background-size: contain;
206
- display: inline-block;
207
- margin: -3px;
208
- padding-right: 2px;
209
- }
210
-
211
- .label {
212
- margin-left: 14px;
213
- font-size: 12px;
214
- color: rgb(48, 49, 51);
215
- }
216
123
  </style>