matterviz 0.3.0 → 0.3.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.
Files changed (286) hide show
  1. package/dist/FilePicker.svelte +37 -20
  2. package/dist/Icon.svelte +2 -2
  3. package/dist/MillerIndexInput.svelte +60 -0
  4. package/dist/MillerIndexInput.svelte.d.ts +7 -0
  5. package/dist/app.css +38 -2
  6. package/dist/brillouin/BrillouinZone.svelte +20 -62
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  8. package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
  9. package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
  10. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  11. package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
  12. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  13. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  15. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  17. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
  18. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  19. package/dist/chempot-diagram/color.d.ts +10 -0
  20. package/dist/chempot-diagram/color.js +33 -0
  21. package/dist/chempot-diagram/compute.d.ts +38 -0
  22. package/dist/chempot-diagram/compute.js +650 -0
  23. package/dist/chempot-diagram/index.d.ts +5 -0
  24. package/dist/chempot-diagram/index.js +5 -0
  25. package/dist/chempot-diagram/pointer.d.ts +16 -0
  26. package/dist/chempot-diagram/pointer.js +40 -0
  27. package/dist/chempot-diagram/temperature.d.ts +15 -0
  28. package/dist/chempot-diagram/temperature.js +37 -0
  29. package/dist/chempot-diagram/types.d.ts +83 -0
  30. package/dist/chempot-diagram/types.js +27 -0
  31. package/dist/colors/index.d.ts +3 -1
  32. package/dist/colors/index.js +4 -0
  33. package/dist/composition/BarChart.svelte +13 -22
  34. package/dist/composition/BubbleChart.svelte +5 -3
  35. package/dist/composition/FormulaFilter.svelte +770 -90
  36. package/dist/composition/FormulaFilter.svelte.d.ts +37 -1
  37. package/dist/composition/PieChart.svelte +43 -18
  38. package/dist/composition/PieChart.svelte.d.ts +1 -1
  39. package/dist/constants.d.ts +1 -0
  40. package/dist/constants.js +2 -0
  41. package/dist/convex-hull/ConvexHull.svelte +14 -1
  42. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  43. package/dist/convex-hull/ConvexHull2D.svelte +14 -45
  44. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  45. package/dist/convex-hull/ConvexHull3D.svelte +396 -134
  46. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  47. package/dist/convex-hull/ConvexHull4D.svelte +93 -42
  48. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  49. package/dist/convex-hull/ConvexHullControls.svelte +94 -31
  50. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +4 -2
  51. package/dist/convex-hull/ConvexHullStats.svelte +697 -128
  52. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  53. package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
  54. package/dist/convex-hull/GasPressureControls.svelte +72 -38
  55. package/dist/convex-hull/GasPressureControls.svelte.d.ts +2 -1
  56. package/dist/convex-hull/TemperatureSlider.svelte +46 -19
  57. package/dist/convex-hull/TemperatureSlider.svelte.d.ts +2 -1
  58. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  59. package/dist/convex-hull/demo-temperature.js +36 -0
  60. package/dist/convex-hull/gas-thermodynamics.js +16 -5
  61. package/dist/convex-hull/helpers.d.ts +7 -1
  62. package/dist/convex-hull/helpers.js +45 -15
  63. package/dist/convex-hull/index.d.ts +15 -1
  64. package/dist/convex-hull/index.js +1 -0
  65. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  66. package/dist/convex-hull/thermodynamics.js +106 -17
  67. package/dist/convex-hull/types.d.ts +7 -0
  68. package/dist/convex-hull/types.js +11 -0
  69. package/dist/coordination/CoordinationBarPlot.svelte +29 -46
  70. package/dist/element/BohrAtom.svelte +1 -1
  71. package/dist/element/data.js +2 -14
  72. package/dist/element/data.json.gz +0 -0
  73. package/dist/element/index.d.ts +1 -1
  74. package/dist/element/index.js +1 -0
  75. package/dist/element/types.d.ts +1 -0
  76. package/dist/fermi-surface/FermiSurface.svelte +21 -65
  77. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
  80. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  81. package/dist/fermi-surface/compute.js +1 -21
  82. package/dist/fermi-surface/marching-cubes.d.ts +2 -13
  83. package/dist/fermi-surface/marching-cubes.js +2 -519
  84. package/dist/fermi-surface/parse.js +17 -23
  85. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
  86. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  87. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
  88. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -0
  89. package/dist/heatmap-matrix/index.d.ts +53 -0
  90. package/dist/heatmap-matrix/index.js +100 -0
  91. package/dist/heatmap-matrix/shared.d.ts +2 -0
  92. package/dist/heatmap-matrix/shared.js +4 -0
  93. package/dist/icons.d.ts +119 -0
  94. package/dist/icons.js +119 -0
  95. package/dist/index.d.ts +6 -1
  96. package/dist/index.js +6 -1
  97. package/dist/io/export.js +15 -3
  98. package/dist/io/file-drop.d.ts +7 -0
  99. package/dist/io/file-drop.js +43 -0
  100. package/dist/io/index.d.ts +2 -2
  101. package/dist/io/index.js +2 -112
  102. package/dist/io/types.d.ts +1 -0
  103. package/dist/io/url-drop.d.ts +2 -0
  104. package/dist/io/url-drop.js +118 -0
  105. package/dist/isosurface/Isosurface.svelte +231 -0
  106. package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
  107. package/dist/isosurface/IsosurfaceControls.svelte +273 -0
  108. package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
  109. package/dist/isosurface/index.d.ts +5 -0
  110. package/dist/isosurface/index.js +6 -0
  111. package/dist/isosurface/parse.d.ts +6 -0
  112. package/dist/isosurface/parse.js +548 -0
  113. package/dist/isosurface/slice.d.ts +11 -0
  114. package/dist/isosurface/slice.js +145 -0
  115. package/dist/isosurface/types.d.ts +55 -0
  116. package/dist/isosurface/types.js +178 -0
  117. package/dist/labels.d.ts +2 -1
  118. package/dist/labels.js +1 -0
  119. package/dist/layout/InfoTag.svelte +62 -62
  120. package/dist/layout/SubpageGrid.svelte +74 -0
  121. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +226 -53
  125. package/dist/layout/json-tree/JsonTree.svelte +425 -51
  126. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  127. package/dist/layout/json-tree/JsonValue.svelte +218 -97
  128. package/dist/layout/json-tree/types.d.ts +27 -2
  129. package/dist/layout/json-tree/utils.d.ts +14 -1
  130. package/dist/layout/json-tree/utils.js +254 -0
  131. package/dist/marching-cubes.d.ts +14 -0
  132. package/dist/marching-cubes.js +519 -0
  133. package/dist/math.d.ts +8 -0
  134. package/dist/math.js +374 -7
  135. package/dist/overlays/ContextMenu.svelte +3 -2
  136. package/dist/overlays/DraggablePane.svelte +163 -58
  137. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  138. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
  139. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  140. package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
  141. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  142. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
  143. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  144. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
  145. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
  146. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
  147. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  148. package/dist/phase-diagram/index.d.ts +2 -0
  149. package/dist/phase-diagram/index.js +2 -0
  150. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  151. package/dist/phase-diagram/svg-to-diagram.js +865 -0
  152. package/dist/phase-diagram/types.d.ts +10 -0
  153. package/dist/phase-diagram/utils.d.ts +7 -4
  154. package/dist/phase-diagram/utils.js +149 -59
  155. package/dist/plot/AxisLabel.svelte +26 -0
  156. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  157. package/dist/plot/BarPlot.svelte +473 -228
  158. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  159. package/dist/plot/BarPlotControls.svelte +3 -2
  160. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  161. package/dist/plot/ColorBar.svelte +54 -54
  162. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  163. package/dist/plot/ElementScatter.svelte +4 -3
  164. package/dist/plot/FillArea.svelte +4 -1
  165. package/dist/plot/Histogram.svelte +320 -230
  166. package/dist/plot/Histogram.svelte.d.ts +2 -2
  167. package/dist/plot/HistogramControls.svelte +29 -10
  168. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  169. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
  170. package/dist/plot/PlotControls.svelte +109 -27
  171. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  172. package/dist/plot/PlotLegend.svelte +1 -1
  173. package/dist/plot/PortalSelect.svelte +2 -1
  174. package/dist/plot/ReferenceLine.svelte +2 -1
  175. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  176. package/dist/plot/ReferencePlane.svelte +1 -3
  177. package/dist/plot/ScatterPlot.svelte +343 -209
  178. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  179. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  180. package/dist/plot/ScatterPlot3DControls.svelte +203 -250
  181. package/dist/plot/ScatterPlot3DScene.svelte +4 -7
  182. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  183. package/dist/plot/ScatterPlotControls.svelte +95 -55
  184. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  185. package/dist/plot/ZeroLines.svelte +44 -0
  186. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  187. package/dist/plot/ZoomRect.svelte +21 -0
  188. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  189. package/dist/plot/axis-utils.d.ts +1 -1
  190. package/dist/plot/data-cleaning.js +1 -5
  191. package/dist/plot/index.d.ts +6 -2
  192. package/dist/plot/index.js +6 -2
  193. package/dist/plot/interactions.d.ts +8 -10
  194. package/dist/plot/interactions.js +10 -19
  195. package/dist/plot/layout.d.ts +7 -1
  196. package/dist/plot/layout.js +12 -4
  197. package/dist/plot/reference-line.d.ts +4 -21
  198. package/dist/plot/reference-line.js +7 -81
  199. package/dist/plot/types.d.ts +42 -17
  200. package/dist/plot/types.js +10 -0
  201. package/dist/plot/utils/label-placement.js +14 -11
  202. package/dist/plot/utils.d.ts +1 -0
  203. package/dist/plot/utils.js +14 -0
  204. package/dist/rdf/RdfPlot.svelte +55 -66
  205. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  206. package/dist/rdf/index.d.ts +1 -1
  207. package/dist/rdf/index.js +1 -1
  208. package/dist/settings.d.ts +5 -0
  209. package/dist/settings.js +37 -3
  210. package/dist/spectral/Bands.svelte +515 -143
  211. package/dist/spectral/Bands.svelte.d.ts +22 -2
  212. package/dist/spectral/helpers.d.ts +23 -1
  213. package/dist/spectral/helpers.js +65 -9
  214. package/dist/spectral/types.d.ts +2 -0
  215. package/dist/structure/AtomLegend.svelte +31 -10
  216. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  217. package/dist/structure/CellSelect.svelte +92 -22
  218. package/dist/structure/Lattice.svelte +2 -0
  219. package/dist/structure/Structure.svelte +716 -173
  220. package/dist/structure/Structure.svelte.d.ts +7 -2
  221. package/dist/structure/StructureControls.svelte +26 -14
  222. package/dist/structure/StructureControls.svelte.d.ts +5 -1
  223. package/dist/structure/StructureInfoPane.svelte +7 -1
  224. package/dist/structure/StructureScene.svelte +386 -95
  225. package/dist/structure/StructureScene.svelte.d.ts +15 -4
  226. package/dist/structure/atom-properties.d.ts +6 -2
  227. package/dist/structure/atom-properties.js +38 -25
  228. package/dist/structure/export.js +10 -7
  229. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  230. package/dist/structure/ferrox-wasm-types.js +0 -3
  231. package/dist/structure/ferrox-wasm.d.ts +3 -2
  232. package/dist/structure/ferrox-wasm.js +1 -2
  233. package/dist/structure/index.d.ts +7 -0
  234. package/dist/structure/index.js +22 -0
  235. package/dist/structure/parse.js +19 -16
  236. package/dist/structure/partial-occupancy.d.ts +25 -0
  237. package/dist/structure/partial-occupancy.js +102 -0
  238. package/dist/structure/validation.js +6 -3
  239. package/dist/symmetry/SymmetryStats.svelte +18 -4
  240. package/dist/symmetry/WyckoffTable.svelte +18 -10
  241. package/dist/symmetry/index.d.ts +7 -4
  242. package/dist/symmetry/index.js +83 -18
  243. package/dist/table/HeatmapTable.svelte +468 -69
  244. package/dist/table/HeatmapTable.svelte.d.ts +13 -1
  245. package/dist/table/ToggleMenu.svelte +291 -44
  246. package/dist/table/ToggleMenu.svelte.d.ts +4 -1
  247. package/dist/table/index.d.ts +3 -0
  248. package/dist/tooltip/index.d.ts +1 -1
  249. package/dist/tooltip/index.js +1 -0
  250. package/dist/trajectory/Trajectory.svelte +147 -145
  251. package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
  252. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  253. package/dist/trajectory/constants.d.ts +6 -0
  254. package/dist/trajectory/constants.js +7 -0
  255. package/dist/trajectory/extract.js +3 -5
  256. package/dist/trajectory/format-detect.d.ts +9 -0
  257. package/dist/trajectory/format-detect.js +76 -0
  258. package/dist/trajectory/frame-reader.d.ts +17 -0
  259. package/dist/trajectory/frame-reader.js +339 -0
  260. package/dist/trajectory/helpers.d.ts +15 -0
  261. package/dist/trajectory/helpers.js +187 -0
  262. package/dist/trajectory/index.d.ts +1 -0
  263. package/dist/trajectory/index.js +11 -4
  264. package/dist/trajectory/parse/ase.d.ts +2 -0
  265. package/dist/trajectory/parse/ase.js +76 -0
  266. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  267. package/dist/trajectory/parse/hdf5.js +121 -0
  268. package/dist/trajectory/parse/index.d.ts +12 -0
  269. package/dist/trajectory/parse/index.js +304 -0
  270. package/dist/trajectory/parse/lammps.d.ts +5 -0
  271. package/dist/trajectory/parse/lammps.js +169 -0
  272. package/dist/trajectory/parse/vasp.d.ts +2 -0
  273. package/dist/trajectory/parse/vasp.js +65 -0
  274. package/dist/trajectory/parse/xyz.d.ts +2 -0
  275. package/dist/trajectory/parse/xyz.js +109 -0
  276. package/dist/trajectory/types.d.ts +11 -0
  277. package/dist/trajectory/types.js +1 -0
  278. package/dist/utils.d.ts +2 -0
  279. package/dist/utils.js +4 -0
  280. package/dist/xrd/XrdPlot.svelte +6 -4
  281. package/dist/xrd/calc-xrd.js +0 -1
  282. package/package.json +33 -23
  283. package/readme.md +4 -4
  284. package/dist/trajectory/parse.d.ts +0 -42
  285. package/dist/trajectory/parse.js +0 -1267
  286. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
@@ -14,6 +14,10 @@ let { files = [], active_files = [], show_category_filters = false, layout = `wr
14
14
  yaml: `rgba(255, 0, 255, 0.8)`,
15
15
  xdatcar: `rgba(255, 215, 0, 0.8)`,
16
16
  tdb: `rgba(0, 188, 212, 0.8)`,
17
+ chgcar: `rgba(59, 130, 246, 0.8)`,
18
+ locpot: `rgba(245, 158, 11, 0.8)`,
19
+ elfcar: `rgba(16, 185, 129, 0.8)`,
20
+ cube: `rgba(168, 85, 247, 0.8)`,
17
21
  }, ...rest } = $props();
18
22
  let active_category_filter = $state(null);
19
23
  let active_type_filter = $state(null);
@@ -28,11 +32,11 @@ const clear_click_timer = () => {
28
32
  };
29
33
  // Helper function to get the base file type (removing .gz extension)
30
34
  const get_base_file_type = (file) => {
31
- // Use custom type mapper if provided
32
35
  if (type_mapper)
33
36
  return type_mapper(file);
37
+ if (file.type)
38
+ return file.type.toLowerCase();
34
39
  let base_name = file.name.toLowerCase();
35
- // Remove .gz extension if present
36
40
  if (base_name.endsWith(`.gz`))
37
41
  base_name = base_name.slice(0, -3);
38
42
  return base_name.split(`.`).pop() || `file`;
@@ -103,7 +107,10 @@ let uniq_categories = $derived([...new Set(files.map(get_category_id))].filter(B
103
107
  {category}
104
108
  </span>
105
109
  {/each}
106
- {#if uniq_categories.length > 0 && uniq_formats.length > 0}&emsp;{/if}
110
+ {#if show_category_filters && uniq_categories.length > 0 &&
111
+ uniq_formats.length > 0}
112
+ <span class="divider"></span>
113
+ {/if}
107
114
 
108
115
  {#each uniq_formats as format (format)}
109
116
  {@const is_active = active_type_filter === format}
@@ -137,11 +144,9 @@ let uniq_categories = $derived([...new Set(files.map(get_category_id))].filter(B
137
144
 
138
145
  {#each filtered_files as file (file.name)}
139
146
  {@const base_type = get_base_file_type(file)}
140
- {@const is_compressed = file.name.toLowerCase().endsWith(`.gz`)}
141
147
  <div
142
148
  class="file-item"
143
149
  class:active={active_files.includes(file.name)}
144
- class:compressed={is_compressed}
145
150
  style:background-color={file_type_colors[base_type]?.replace(`0.8`, `0.08`)}
146
151
  draggable="true"
147
152
  ondragstart={handle_drag_start(file)}
@@ -179,9 +184,14 @@ let uniq_categories = $derived([...new Set(files.map(get_category_id))].filter(B
179
184
  ? `Click to load or drag this ${base_type.toUpperCase()} file`
180
185
  : `Drag this ${base_type.toUpperCase()} file`}
181
186
  >
187
+ {#if file.label}
188
+ <span
189
+ class="file-type-badge"
190
+ style:background-color={file_type_colors[base_type] ?? `rgba(128,128,128,0.8)`}
191
+ >{base_type.toUpperCase()}</span>
192
+ {/if}
182
193
  <div class="file-name">
183
- {file.category ? `${file.category_icon} ` : ``}{file.name}
184
- {#if is_compressed}<span class="compression-indicator">📦</span>{/if}
194
+ {file.category ? `${file.category_icon} ` : ``}{file.label ?? file.name}
185
195
  </div>
186
196
  </div>
187
197
  {/each}
@@ -220,6 +230,12 @@ let uniq_categories = $derived([...new Set(files.map(get_category_id))].filter(B
220
230
  opacity: 0.8;
221
231
  margin: 0 0 0.5em;
222
232
  }
233
+ .divider {
234
+ width: 1px;
235
+ align-self: stretch;
236
+ background: light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2));
237
+ margin-inline: 0.3em;
238
+ }
223
239
  .legend-item {
224
240
  cursor: pointer;
225
241
  padding: 0.2em 0.4em;
@@ -267,7 +283,10 @@ let uniq_categories = $derived([...new Set(files.map(get_category_id))].filter(B
267
283
  cursor: grab;
268
284
  background: light-dark(rgba(0, 0, 0, 0.02), rgba(255, 255, 255, 0.1));
269
285
  transition: all 0.2s ease;
270
- gap: 0.5em;
286
+ gap: 4pt;
287
+ &:has(.file-type-badge) {
288
+ padding-left: 3pt;
289
+ }
271
290
  }
272
291
  .file-item.active {
273
292
  border-color: var(--success-color, #00ff00);
@@ -282,21 +301,19 @@ let uniq_categories = $derived([...new Set(files.map(get_category_id))].filter(B
282
301
  background: light-dark(rgba(0, 122, 204, 0.15), rgba(0, 122, 204, 0.25));
283
302
  filter: brightness(1.1);
284
303
  }
304
+ .file-type-badge {
305
+ font-size: 0.5em;
306
+ font-weight: 700;
307
+ letter-spacing: 0.03em;
308
+ padding: 1px 5px;
309
+ border-radius: 10px;
310
+ color: white;
311
+ white-space: nowrap;
312
+ line-height: 1.4;
313
+ }
285
314
  .file-name {
286
315
  font-size: 0.7em;
287
316
  line-height: 1.1;
288
317
  white-space: pre-line;
289
318
  }
290
- .compression-indicator {
291
- opacity: 0.7;
292
- font-size: 0.8em;
293
- margin-left: 0.2em;
294
- }
295
- .file-item.compressed {
296
- border-style: dashed;
297
- opacity: 0.9;
298
- }
299
- .file-item.compressed:hover {
300
- opacity: 1;
301
- }
302
319
  </style>
package/dist/Icon.svelte CHANGED
@@ -27,8 +27,8 @@ const data = $derived.by(() => {
27
27
 
28
28
  <style>
29
29
  svg {
30
- width: 1em;
31
- height: auto;
30
+ width: var(--icon-size, 1em);
31
+ height: var(--icon-size, auto);
32
32
  display: inline-block;
33
33
  vertical-align: middle;
34
34
  }
@@ -0,0 +1,60 @@
1
+ <script lang="ts">let { value = $bindable([0, 0, 1]) } = $props();
2
+ // Format: compact "001" for single-digit, spaced "10 0 1" for multi-digit
3
+ let hkl_text = $derived(value.every((v) => Math.abs(v) < 10) ? value.join(``) : value.join(` `));
4
+ // Parse hkl string: supports compact "001"/"-101" and spaced/comma "10, 0, 1"
5
+ function parse_hkl(input) {
6
+ // Try spaced/comma format first (handles multi-digit)
7
+ const spaced = input.trim().split(/[,\s]+/);
8
+ if (spaced.length === 3) {
9
+ const nums = spaced.map(Number);
10
+ if (nums.every((n) => !isNaN(n)))
11
+ return nums;
12
+ }
13
+ // Fall back to compact single-digit format: "001", "-101"
14
+ const compact = input.replace(/\s+/g, ``);
15
+ const match = compact.match(/^(-?\d)(-?\d)(-?\d)$/);
16
+ if (match)
17
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
18
+ return null;
19
+ }
20
+ function handle_input(event) {
21
+ const parsed = parse_hkl(event.target.value);
22
+ if (parsed)
23
+ value = parsed;
24
+ }
25
+ export {};
26
+ </script>
27
+
28
+ <label class="miller-input">
29
+ <span>hkl</span>
30
+ <input
31
+ type="text"
32
+ value={hkl_text}
33
+ oninput={handle_input}
34
+ placeholder="001"
35
+ maxlength="12"
36
+ title="Miller indices (e.g. 001, -101, or 10 0 1)"
37
+ />
38
+ </label>
39
+
40
+ <style>
41
+ .miller-input {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 0.3em;
45
+ span {
46
+ font-weight: 600;
47
+ font-size: 0.85em;
48
+ }
49
+ input {
50
+ width: 4em;
51
+ padding: 0.15em 0.3em;
52
+ border: 1px solid var(--border-color, #ccc);
53
+ border-radius: 4px;
54
+ font-family: monospace;
55
+ font-size: 0.9em;
56
+ text-align: center;
57
+ box-sizing: border-box;
58
+ }
59
+ }
60
+ </style>
@@ -0,0 +1,7 @@
1
+ import type { Vec3 } from './math';
2
+ type $$ComponentProps = {
3
+ value?: Vec3;
4
+ };
5
+ declare const MillerIndexInput: import("svelte").Component<$$ComponentProps, {}, "value">;
6
+ type MillerIndexInput = ReturnType<typeof MillerIndexInput>;
7
+ export default MillerIndexInput;
package/dist/app.css CHANGED
@@ -8,12 +8,14 @@
8
8
  --max-text-width: 50em;
9
9
 
10
10
  --sms-max-width: 20em;
11
+ --sms-min-height: 19pt;
11
12
  --sms-text-color: var(--text-color);
12
13
 
13
14
  /* Svelte MultiSelect */
14
15
  --sms-options-bg: var(--page-bg);
15
16
  --sms-active-color: light-dark(var(--accent-color), cornflowerblue);
16
17
  --sms-li-active-bg: light-dark(rgba(100, 149, 237, 0.25), cornflowerblue);
18
+ --sms-selected-bg: light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.15));
17
19
  --border-radius: 3pt;
18
20
  }
19
21
 
@@ -33,18 +35,23 @@
33
35
  }
34
36
  body {
35
37
  background: var(--page-bg);
36
- padding: 6vh 3vw;
38
+ padding: 5vh 3vw 3vh;
37
39
  font-family: -apple-system, BlinkMacSystemFont, Roboto, sans-serif;
38
40
  margin: auto;
39
41
  color: var(--text-color);
40
42
  line-height: 1.5;
43
+ /* Sticky footer: footer stays at bottom when content is short */
44
+ display: flex;
45
+ flex-direction: column;
46
+ min-height: 100vh;
47
+ box-sizing: border-box;
41
48
  }
42
49
  main {
43
50
  margin: auto;
44
- margin-bottom: 3em;
45
51
  width: 100%;
46
52
  max-width: var(--max-text-width);
47
53
  container-type: inline-size;
54
+ flex: 1; /* Grow to fill available space (sticky footer) */
48
55
  }
49
56
  a {
50
57
  color: var(--accent-color, cornflowerblue);
@@ -128,6 +135,35 @@ textarea {
128
135
  margin: 1em auto;
129
136
  }
130
137
 
138
+ /* Theme-aware form controls (works consistently in notebooks and VSCode/Cursor webviews) */
139
+ :is(
140
+ input:not([type='checkbox'], [type='radio'], [type='range'], [type='color']),
141
+ textarea,
142
+ select
143
+ ) {
144
+ background-color: var(--surface-bg);
145
+ color: var(--text-color);
146
+ border: 1px solid var(--border-color);
147
+ border-radius: var(--border-radius);
148
+ padding: 2px 6px;
149
+ }
150
+ :is(
151
+ input:not([type='checkbox'], [type='radio'], [type='range'], [type='color']),
152
+ textarea,
153
+ select
154
+ ):focus {
155
+ outline: none;
156
+ border-color: var(--accent-color);
157
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-color) 25%, transparent);
158
+ }
159
+ :is(input, textarea)::placeholder {
160
+ color: var(--text-color-muted);
161
+ }
162
+ select option {
163
+ background-color: var(--surface-bg);
164
+ color: var(--text-color);
165
+ }
166
+
131
167
  /* Modern flat input styling */
132
168
  input {
133
169
  border: none;
@@ -1,17 +1,17 @@
1
- <script lang="ts">import { toggle_fullscreen } from '../layout';
2
- import { normalize_show_controls } from '../controls';
1
+ <script lang="ts">import { normalize_show_controls } from '../controls';
3
2
  import EmptyState from '../EmptyState.svelte';
3
+ import { StatusMessage } from '../feedback';
4
4
  import Spinner from '../feedback/Spinner.svelte';
5
5
  import Icon from '../Icon.svelte';
6
- import { decompress_file, handle_url_drop, load_from_url } from '../io';
7
- import { set_fullscreen_bg } from '../layout';
6
+ import { create_file_drop_handler, load_from_url } from '../io';
7
+ import { set_fullscreen_bg, toggle_fullscreen } from '../layout';
8
+ import { PlotTooltip } from '../plot';
8
9
  import { DEFAULTS } from '../settings';
9
10
  import { parse_any_structure } from '../structure/parse';
10
11
  import { analyze_structure_symmetry } from '../symmetry';
11
12
  import { Canvas } from '@threlte/core';
12
13
  import { untrack } from 'svelte';
13
14
  import { tooltip } from 'svelte-multiselect/attachments';
14
- import { PlotTooltip } from '../plot';
15
15
  import BrillouinZoneControls from './BrillouinZoneControls.svelte';
16
16
  import BrillouinZoneExportPane from './BrillouinZoneExportPane.svelte';
17
17
  import BrillouinZoneInfoPane from './BrillouinZoneInfoPane.svelte';
@@ -131,33 +131,19 @@ $effect(() => {
131
131
  }
132
132
  }
133
133
  });
134
- async function handle_file_drop(event) {
135
- event.preventDefault();
136
- dragover = false;
137
- if (!allow_file_drop)
138
- return;
139
- loading = true;
140
- error_msg = undefined;
141
- try {
142
- const handler = on_file_drop || safe_parse;
143
- const handled = await handle_url_drop(event, handler).catch(() => false);
144
- if (handled)
145
- return;
146
- const file = event.dataTransfer?.files[0];
147
- if (file) {
148
- const { content, filename } = await decompress_file(file);
149
- if (content)
150
- handler(content, filename);
151
- }
152
- }
153
- catch (err) {
154
- error_msg = `File drop failed: ${err}`;
155
- on_error?.({ error_msg });
156
- }
157
- finally {
158
- loading = false;
159
- }
160
- }
134
+ const handle_file_drop = create_file_drop_handler({
135
+ allow: () => allow_file_drop,
136
+ on_drop: (content, filename) => (on_file_drop || safe_parse)(content, filename),
137
+ on_error: (msg) => {
138
+ error_msg = msg;
139
+ on_error?.({ error_msg: msg });
140
+ },
141
+ set_loading: (val) => {
142
+ loading = val;
143
+ if (val)
144
+ [error_msg, dragover] = [undefined, false];
145
+ },
146
+ });
161
147
  function onkeydown(event) {
162
148
  const target = event.target;
163
149
  if (target.tagName === `INPUT` || target.tagName === `TEXTAREA`)
@@ -221,10 +207,7 @@ $effect(() => {
221
207
  {#if loading}
222
208
  <Spinner text="Loading structure..." {...spinner_props} />
223
209
  {:else if error_msg}
224
- <div class="error-state">
225
- <p class="error">{error_msg}</p>
226
- <button onclick={() => (error_msg = undefined)}>Dismiss</button>
227
- </div>
210
+ <StatusMessage bind:message={error_msg} type="error" dismissible />
228
211
  {:else if structure && `lattice` in structure}
229
212
  <section
230
213
  class="control-buttons {controls_config.class}"
@@ -394,7 +377,7 @@ $effect(() => {
394
377
  display: flex;
395
378
  padding: 4px;
396
379
  border-radius: var(--border-radius, 3pt);
397
- font-size: clamp(0.85em, 2cqmin, 2.5em);
380
+ font-size: clamp(0.85em, 2cqmin, 1.3em);
398
381
  }
399
382
  section.control-buttons :global(button:hover) {
400
383
  background-color: color-mix(in srgb, currentColor 8%, transparent);
@@ -414,29 +397,4 @@ $effect(() => {
414
397
  text-align: center;
415
398
  padding: 2rem;
416
399
  }
417
- .error-state {
418
- display: flex;
419
- flex-direction: column;
420
- align-items: center;
421
- justify-content: center;
422
- height: 100%;
423
- padding: 2rem;
424
- text-align: center;
425
- box-sizing: border-box;
426
- }
427
- .error-state p {
428
- color: var(--error-color, #ff6b6b);
429
- margin: 0 0 1rem;
430
- }
431
- .error-state button {
432
- padding: 0.5rem 1rem;
433
- background: var(--error-color, #ff6b6b);
434
- color: white;
435
- border: none;
436
- border-radius: 4px;
437
- cursor: pointer;
438
- }
439
- .error-state button:hover {
440
- background: var(--error-color-hover, #ff5252);
441
- }
442
400
  </style>
@@ -78,6 +78,6 @@ type $$ComponentProps = {
78
78
  on_fullscreen_change?: (data: BZHandlerData) => void;
79
79
  on_hover?: (data: BZHoverData | null) => void;
80
80
  } & HTMLAttributes<HTMLDivElement>;
81
- declare const BrillouinZone: import("svelte").Component<$$ComponentProps, {}, "height" | "width" | "dragover" | "fullscreen" | "structure" | "hovered" | "controls_open" | "camera_projection" | "info_pane_open" | "loading" | "error_msg" | "wrapper" | "png_dpi" | "bz_order" | "surface_color" | "surface_opacity" | "edge_color" | "edge_width" | "show_vectors" | "show_ibz" | "ibz_color" | "ibz_opacity" | "bz_data" | "vector_scale" | "ibz_data">;
81
+ declare const BrillouinZone: import("svelte").Component<$$ComponentProps, {}, "structure" | "height" | "width" | "dragover" | "controls_open" | "loading" | "fullscreen" | "hovered" | "camera_projection" | "info_pane_open" | "wrapper" | "error_msg" | "png_dpi" | "bz_order" | "surface_color" | "surface_opacity" | "edge_color" | "edge_width" | "show_vectors" | "show_ibz" | "ibz_color" | "ibz_opacity" | "bz_data" | "vector_scale" | "ibz_data">;
82
82
  type BrillouinZone = ReturnType<typeof BrillouinZone>;
83
83
  export default BrillouinZone;
@@ -1,9 +1,9 @@
1
- <script lang="ts">import DraggablePane from '../overlays/DraggablePane.svelte';
2
- import { export_canvas_as_png } from '../io/export';
1
+ <script lang="ts">import { export_canvas_as_png } from '../io/export';
2
+ import DraggablePane from '../overlays/DraggablePane.svelte';
3
+ import { CopyButton } from 'svelte-multiselect';
3
4
  import { tooltip } from 'svelte-multiselect/attachments';
4
5
  let { export_pane_open = $bindable(false), bz_data, wrapper, scene, camera, filename = `brillouin-zone`, png_dpi = $bindable(150), ...rest } = $props();
5
- let copy_status = $state(false);
6
- const copy_confirm = `✅`;
6
+ let json_copy_state = $state(`ready`);
7
7
  function export_as_png() {
8
8
  const canvas = wrapper?.querySelector(`canvas`);
9
9
  if (!canvas || !scene || !camera)
@@ -38,16 +38,10 @@ function get_json_data() {
38
38
  reciprocal_lattice: bz_data.k_lattice,
39
39
  };
40
40
  }
41
- async function copy_json() {
41
+ let json_string = $derived.by(() => {
42
42
  const json_data = get_json_data();
43
- if (!json_data)
44
- return;
45
- await navigator.clipboard.writeText(JSON.stringify(json_data, null, 2));
46
- copy_status = true;
47
- setTimeout(() => {
48
- copy_status = false;
49
- }, 1000);
50
- }
43
+ return json_data ? JSON.stringify(json_data, null, 2) : null;
44
+ });
51
45
  </script>
52
46
 
53
47
  <DraggablePane
@@ -97,14 +91,12 @@ async function copy_json() {
97
91
  >
98
92
 
99
93
  </button>
100
- <button
101
- type="button"
102
- onclick={copy_json}
103
- disabled={!bz_data}
94
+ <CopyButton
95
+ content={json_string ?? ``}
96
+ bind:state={json_copy_state}
97
+ disabled={!json_string}
104
98
  title="Copy JSON to clipboard"
105
- >
106
- {copy_status ? copy_confirm : `📋`}
107
- </button>
99
+ />
108
100
  </label>
109
101
  </DraggablePane>
110
102
 
@@ -243,7 +243,7 @@ function handle_leave(is_ibz) {
243
243
  {/if}
244
244
 
245
245
  <!-- BZ edges -->
246
- {#each bz_data.edges as edge_segment (JSON.stringify(edge_segment))}
246
+ {#each bz_data.edges as edge_segment, edge_idx (`bz-edge-${edge_idx}`)}
247
247
  {@const [from, to] = edge_segment}
248
248
  <Cylinder {from} {to} thickness={edge_width} color={edge_color} />
249
249
  {/each}
@@ -267,7 +267,7 @@ function handle_leave(is_ibz) {
267
267
 
268
268
  <!-- IBZ edges -->
269
269
  {#if show_ibz && ibz_data}
270
- {#each ibz_data.edges as edge_segment (JSON.stringify(edge_segment))}
270
+ {#each ibz_data.edges as edge_segment, edge_idx (`ibz-edge-${edge_idx}`)}
271
271
  {@const [from, to] = edge_segment}
272
272
  <Cylinder {from} {to} thickness={edge_width * 1.5} color={ibz_color} />
273
273
  {/each}
@@ -43,6 +43,6 @@ type $$ComponentProps = {
43
43
  hovered_qpoint_index?: number | null;
44
44
  hover_data?: BZHoverData | null;
45
45
  };
46
- declare const BrillouinZoneScene: import("svelte").Component<$$ComponentProps, {}, "camera_position" | "camera_projection" | "camera_is_moving" | "scene" | "camera" | "surface_color" | "surface_opacity" | "edge_color" | "edge_width" | "show_vectors" | "bz_data" | "vector_scale" | "hover_data">;
46
+ declare const BrillouinZoneScene: import("svelte").Component<$$ComponentProps, {}, "camera_position" | "camera_projection" | "scene" | "camera" | "camera_is_moving" | "surface_color" | "surface_opacity" | "edge_color" | "edge_width" | "show_vectors" | "bz_data" | "vector_scale" | "hover_data">;
47
47
  type BrillouinZoneScene = ReturnType<typeof BrillouinZoneScene>;
48
48
  export default BrillouinZoneScene;
@@ -0,0 +1,192 @@
1
+ <script lang="ts">import { get_hill_formula } from '../composition/format';
2
+ import { format_num } from '../labels';
3
+ import ChemPotDiagram2D from './ChemPotDiagram2D.svelte';
4
+ import ChemPotDiagram3D from './ChemPotDiagram3D.svelte';
5
+ import { CHEMPOT_DEFAULTS } from './types';
6
+ let { entries = [], config = {}, width = $bindable(600), height = $bindable(600),
7
+ // Bound temperature may be auto-corrected by 2D/3D child components.
8
+ temperature = $bindable(), hover_info = $bindable(null), } = $props();
9
+ // Extract unique elements from all entries (composition keys are element symbols)
10
+ const all_elements = $derived([
11
+ ...new Set(entries.flatMap((entry) => Object.entries(entry.composition)
12
+ .filter(([, amount]) => amount > 0)
13
+ .map(([element]) => element))),
14
+ ].sort());
15
+ // How many display axes (2 = binary/2D, 3+ = ternary/3D)
16
+ const display_elements = $derived(config.elements ?? all_elements);
17
+ const n_display = $derived(display_elements.length);
18
+ const show_tooltip = $derived(config.show_tooltip ?? CHEMPOT_DEFAULTS.show_tooltip);
19
+ const tooltip_detail_level = $derived(config.tooltip_detail_level ?? CHEMPOT_DEFAULTS.tooltip_detail_level);
20
+ function is_hover_info_3d(value) {
21
+ return value?.view === `3d`;
22
+ }
23
+ </script>
24
+
25
+ <div class="chempot-diagram-wrapper">
26
+ {#if n_display < 2}
27
+ <div
28
+ class="chempot-error"
29
+ role="alert"
30
+ aria-live="polite"
31
+ style:width="{width}px"
32
+ style:height="{height}px"
33
+ >
34
+ <div>
35
+ <h3 id="unsupported-chemical-system">Unsupported Chemical System</h3>
36
+ <p>
37
+ Chemical potential diagrams require at least 2 elements. Found {n_display}
38
+ element{n_display === 1 ? `` : `s`}:
39
+ {display_elements.join(`, `) || `none`}
40
+ </p>
41
+ </div>
42
+ </div>
43
+ {:else if n_display === 2}
44
+ <ChemPotDiagram2D
45
+ {entries}
46
+ {config}
47
+ bind:width
48
+ bind:height
49
+ bind:temperature
50
+ bind:hover_info
51
+ render_local_tooltip={false}
52
+ />
53
+ {:else}
54
+ <ChemPotDiagram3D
55
+ {entries}
56
+ {config}
57
+ bind:width
58
+ bind:height
59
+ bind:temperature
60
+ bind:hover_info
61
+ render_local_tooltip={false}
62
+ />
63
+ {/if}
64
+ {#if show_tooltip && hover_info}
65
+ <aside
66
+ class="chempot-tooltip"
67
+ style:left="{hover_info.pointer?.x ?? 4}px"
68
+ style:top="{hover_info.pointer?.y ?? 4}px"
69
+ >
70
+ <h4>{@html get_hill_formula(hover_info.formula, false, ``)}</h4>
71
+ {#if hover_info.view === `2d`}
72
+ <p>2D domain · Points: {hover_info.n_points}</p>
73
+ {#if tooltip_detail_level === `detailed`}
74
+ <h5 id="axis-ranges">Axis ranges</h5>
75
+ {#each hover_info.axis_ranges as axis_range (axis_range.element)}
76
+ <p>
77
+ {axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
78
+ {format_num(axis_range.max_val, `.4~g`)} eV
79
+ </p>
80
+ {/each}
81
+ {/if}
82
+ {:else if is_hover_info_3d(hover_info)}
83
+ <p>
84
+ {hover_info.is_elemental ? `Elemental phase` : `Compound phase`}
85
+ {#if hover_info.is_draw_formula}
86
+ <span> · Overlay target</span>
87
+ {/if}
88
+ </p>
89
+ <p>
90
+ Vertices: {hover_info.n_vertices} · Edges: {hover_info.n_edges} · Points:
91
+ {hover_info.n_points}
92
+ </p>
93
+ <p>
94
+ Entries: {hover_info.matching_entry_count}
95
+ {#if hover_info.min_energy_per_atom !== null &&
96
+ hover_info.max_energy_per_atom !== null}
97
+ · E/atom: {format_num(hover_info.min_energy_per_atom, `.4~g`)}
98
+ to {format_num(hover_info.max_energy_per_atom, `.4~g`)} eV
99
+ {/if}
100
+ </p>
101
+ {#if tooltip_detail_level === `detailed`}
102
+ <h5 id="axis-ranges-1">Axis ranges</h5>
103
+ {#each hover_info.axis_ranges as axis_range (axis_range.element)}
104
+ <p>
105
+ {axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
106
+ {format_num(axis_range.max_val, `.4~g`)} eV
107
+ </p>
108
+ {/each}
109
+ <p>
110
+ Centroid: ({
111
+ hover_info.ann_loc.map((value) => format_num(value, `.3~g`)).join(
112
+ `, `,
113
+ )
114
+ })
115
+ </p>
116
+ {#if hover_info.neighbors.length > 0}
117
+ <h5 id="neighbors">Neighbors ({hover_info.neighbors.length})</h5>
118
+ <p>
119
+ {
120
+ hover_info.neighbors.map((f) => get_hill_formula(f, true, ``)).join(
121
+ `, `,
122
+ )
123
+ }
124
+ </p>
125
+ {/if}
126
+ {#if hover_info.touches_limits.length > 0}
127
+ <h5 id="touches-bounds">Touches bounds</h5>
128
+ <p>{hover_info.touches_limits.join(`, `)}</p>
129
+ {/if}
130
+ {/if}
131
+ {/if}
132
+ </aside>
133
+ {/if}
134
+ </div>
135
+
136
+ <style>
137
+ .chempot-diagram-wrapper {
138
+ position: relative;
139
+ }
140
+ .chempot-error {
141
+ display: flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ border: 1px solid var(--border-color, #ccc);
145
+ border-radius: var(--border-radius, 3pt);
146
+ background: var(--bg-color, transparent);
147
+ }
148
+ .chempot-error > div {
149
+ text-align: center;
150
+ padding: 2em;
151
+ color: var(--text-color, #666);
152
+ }
153
+ .chempot-error h3 {
154
+ margin: 0 0 1em;
155
+ }
156
+ .chempot-error p {
157
+ margin: 0;
158
+ }
159
+ .chempot-tooltip {
160
+ position: absolute;
161
+ max-width: min(32rem, 92vw);
162
+ background: var(
163
+ --tooltip-bg,
164
+ light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.9))
165
+ );
166
+ color: var(--tooltip-text, var(--text-color, #222));
167
+ border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
168
+ border-radius: 6px;
169
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
170
+ padding: 8px 10px;
171
+ font-size: 12px;
172
+ line-height: 1.35;
173
+ pointer-events: none;
174
+ z-index: 40;
175
+ }
176
+ .chempot-tooltip h4 {
177
+ margin: 0 0 4px;
178
+ font-size: 13px;
179
+ }
180
+ .chempot-tooltip p {
181
+ margin: 1px 0;
182
+ white-space: nowrap;
183
+ overflow: hidden;
184
+ text-overflow: ellipsis;
185
+ }
186
+ .chempot-tooltip h5 {
187
+ margin-top: 6px;
188
+ margin-bottom: 0;
189
+ font-size: 12px;
190
+ font-weight: 600;
191
+ }
192
+ </style>