matterviz 0.1.12 → 0.1.13

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 (195) hide show
  1. package/dist/ContextMenu.svelte +1 -1
  2. package/dist/ContextMenu.svelte.d.ts +3 -3
  3. package/dist/DraggablePane.svelte +10 -5
  4. package/dist/DraggablePane.svelte.d.ts +3 -3
  5. package/dist/FilePicker.svelte.d.ts +3 -3
  6. package/dist/Icon.svelte.d.ts +3 -3
  7. package/dist/Nav.svelte +76 -31
  8. package/dist/SettingsSection.svelte.d.ts +3 -3
  9. package/dist/Spinner.svelte +18 -29
  10. package/dist/Spinner.svelte.d.ts +3 -3
  11. package/dist/app.css +4 -0
  12. package/dist/bands/Bands.svelte +216 -0
  13. package/dist/bands/Bands.svelte.d.ts +16 -0
  14. package/dist/bands/BandsAndDos.svelte +26 -0
  15. package/dist/bands/BandsAndDos.svelte.d.ts +16 -0
  16. package/dist/bands/Dos.svelte +124 -0
  17. package/dist/bands/Dos.svelte.d.ts +18 -0
  18. package/dist/bands/helpers.d.ts +11 -0
  19. package/dist/bands/helpers.js +195 -0
  20. package/dist/bands/index.d.ts +5 -0
  21. package/dist/bands/index.js +6 -0
  22. package/dist/bands/types.d.ts +54 -0
  23. package/dist/bands/types.js +2 -0
  24. package/dist/brillouin/BrillouinZone.svelte +373 -0
  25. package/dist/brillouin/BrillouinZone.svelte.d.ts +57 -0
  26. package/dist/brillouin/BrillouinZoneControls.svelte +88 -0
  27. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +14 -0
  28. package/dist/brillouin/BrillouinZoneExportPane.svelte +129 -0
  29. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
  30. package/dist/brillouin/BrillouinZoneInfoPane.svelte +115 -0
  31. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
  32. package/dist/brillouin/BrillouinZoneScene.svelte +180 -0
  33. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +34 -0
  34. package/dist/brillouin/compute.d.ts +7 -0
  35. package/dist/brillouin/compute.js +215 -0
  36. package/dist/brillouin/index.d.ts +7 -0
  37. package/dist/brillouin/index.js +7 -0
  38. package/dist/brillouin/types.d.ts +23 -0
  39. package/dist/brillouin/types.js +1 -0
  40. package/dist/composition/BarChart.svelte.d.ts +3 -3
  41. package/dist/composition/BubbleChart.svelte +7 -6
  42. package/dist/composition/BubbleChart.svelte.d.ts +3 -3
  43. package/dist/composition/Composition.svelte.d.ts +3 -3
  44. package/dist/composition/PieChart.svelte +1 -1
  45. package/dist/composition/PieChart.svelte.d.ts +3 -3
  46. package/dist/composition/parse.d.ts +3 -3
  47. package/dist/coordination/CoordinationBarPlot.svelte +241 -0
  48. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +29 -0
  49. package/dist/coordination/calc-coordination.d.ts +15 -0
  50. package/dist/coordination/calc-coordination.js +66 -0
  51. package/dist/coordination/index.d.ts +8 -0
  52. package/dist/coordination/index.js +7 -0
  53. package/dist/element/BohrAtom.svelte.d.ts +3 -3
  54. package/dist/element/ElementHeading.svelte.d.ts +3 -3
  55. package/dist/element/ElementPhoto.svelte.d.ts +3 -3
  56. package/dist/element/ElementStats.svelte.d.ts +3 -3
  57. package/dist/element/ElementTile.svelte +1 -1
  58. package/dist/element/ElementTile.svelte.d.ts +4 -4
  59. package/dist/element/Nucleus.svelte.d.ts +3 -3
  60. package/dist/icons.d.ts +4 -0
  61. package/dist/icons.js +4 -0
  62. package/dist/index.d.ts +5 -1
  63. package/dist/index.js +5 -1
  64. package/dist/io/export.d.ts +1 -6
  65. package/dist/io/export.js +12 -12
  66. package/dist/labels.d.ts +19 -0
  67. package/dist/labels.js +59 -0
  68. package/dist/math.d.ts +7 -2
  69. package/dist/math.js +24 -12
  70. package/dist/periodic-table/PeriodicTable.svelte.d.ts +3 -3
  71. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +3 -3
  72. package/dist/periodic-table/PropertySelect.svelte +1 -1
  73. package/dist/periodic-table/PropertySelect.svelte.d.ts +5 -4
  74. package/dist/periodic-table/TableInset.svelte.d.ts +3 -3
  75. package/dist/phase-diagram/PhaseDiagram2D.svelte +44 -107
  76. package/dist/phase-diagram/PhaseDiagram2D.svelte.d.ts +7 -27
  77. package/dist/phase-diagram/PhaseDiagram3D.svelte +67 -170
  78. package/dist/phase-diagram/PhaseDiagram3D.svelte.d.ts +7 -31
  79. package/dist/phase-diagram/PhaseDiagram4D.svelte +87 -145
  80. package/dist/phase-diagram/PhaseDiagram4D.svelte.d.ts +5 -28
  81. package/dist/phase-diagram/PhaseDiagramControls.svelte +9 -9
  82. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +6 -6
  83. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte +4 -4
  84. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte.d.ts +5 -5
  85. package/dist/phase-diagram/PhaseDiagramStats.svelte +9 -16
  86. package/dist/phase-diagram/PhaseDiagramStats.svelte.d.ts +3 -3
  87. package/dist/phase-diagram/StructurePopup.svelte.d.ts +3 -3
  88. package/dist/phase-diagram/barycentric-coords.js +13 -24
  89. package/dist/phase-diagram/helpers.d.ts +12 -14
  90. package/dist/phase-diagram/helpers.js +70 -23
  91. package/dist/phase-diagram/index.d.ts +58 -0
  92. package/dist/phase-diagram/index.js +44 -0
  93. package/dist/phase-diagram/thermodynamics.js +2 -3
  94. package/dist/phase-diagram/types.d.ts +3 -8
  95. package/dist/plot/BarPlot.svelte +474 -240
  96. package/dist/plot/BarPlot.svelte.d.ts +16 -37
  97. package/dist/plot/BarPlotControls.svelte +33 -201
  98. package/dist/plot/BarPlotControls.svelte.d.ts +11 -22
  99. package/dist/plot/ColorBar.svelte.d.ts +3 -3
  100. package/dist/plot/ColorScaleSelect.svelte +1 -1
  101. package/dist/plot/ColorScaleSelect.svelte.d.ts +3 -3
  102. package/dist/plot/ElementScatter.svelte +5 -5
  103. package/dist/plot/ElementScatter.svelte.d.ts +8 -8
  104. package/dist/plot/Histogram.svelte +318 -170
  105. package/dist/plot/Histogram.svelte.d.ts +21 -41
  106. package/dist/plot/HistogramControls.svelte +115 -347
  107. package/dist/plot/HistogramControls.svelte.d.ts +13 -28
  108. package/dist/plot/Line.svelte +1 -1
  109. package/dist/plot/Line.svelte.d.ts +4 -4
  110. package/dist/plot/PlotControls.svelte +280 -0
  111. package/dist/plot/PlotControls.svelte.d.ts +4 -0
  112. package/dist/plot/PlotLegend.svelte +9 -24
  113. package/dist/plot/PlotLegend.svelte.d.ts +3 -3
  114. package/dist/plot/ScatterPlot.svelte +536 -571
  115. package/dist/plot/ScatterPlot.svelte.d.ts +18 -90
  116. package/dist/plot/ScatterPlotControls.svelte +108 -316
  117. package/dist/plot/ScatterPlotControls.svelte.d.ts +11 -38
  118. package/dist/plot/ScatterPoint.svelte +1 -1
  119. package/dist/plot/ScatterPoint.svelte.d.ts +5 -5
  120. package/dist/plot/SpacegroupBarPlot.svelte +235 -0
  121. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
  122. package/dist/plot/data-transform.d.ts +2 -2
  123. package/dist/plot/data-transform.js +1 -5
  124. package/dist/plot/index.d.ts +12 -200
  125. package/dist/plot/index.js +14 -6
  126. package/dist/plot/layout.d.ts +10 -16
  127. package/dist/plot/layout.js +40 -25
  128. package/dist/plot/scales.d.ts +7 -8
  129. package/dist/plot/scales.js +22 -7
  130. package/dist/plot/types.d.ts +303 -0
  131. package/dist/plot/types.js +1 -0
  132. package/dist/rdf/RdfPlot.svelte +156 -0
  133. package/dist/rdf/RdfPlot.svelte.d.ts +20 -0
  134. package/dist/rdf/calc-rdf.d.ts +4 -0
  135. package/dist/rdf/calc-rdf.js +107 -0
  136. package/dist/rdf/index.d.ts +22 -0
  137. package/dist/rdf/index.js +2 -0
  138. package/dist/settings.d.ts +86 -75
  139. package/dist/settings.js +257 -155
  140. package/dist/structure/Bond.svelte +126 -110
  141. package/dist/structure/Bond.svelte.d.ts +7 -20
  142. package/dist/structure/CanvasTooltip.svelte.d.ts +4 -4
  143. package/dist/structure/Cylinder.svelte +29 -0
  144. package/dist/structure/Cylinder.svelte.d.ts +10 -0
  145. package/dist/structure/Lattice.svelte +1 -2
  146. package/dist/structure/Lattice.svelte.d.ts +3 -3
  147. package/dist/structure/Structure.svelte +23 -8
  148. package/dist/structure/Structure.svelte.d.ts +10 -7
  149. package/dist/structure/StructureControls.svelte +25 -134
  150. package/dist/structure/StructureControls.svelte.d.ts +4 -9
  151. package/dist/structure/StructureExportPane.svelte +188 -0
  152. package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
  153. package/dist/structure/StructureInfoPane.svelte.d.ts +3 -3
  154. package/dist/structure/StructureLegend.svelte +91 -27
  155. package/dist/structure/StructureLegend.svelte.d.ts +5 -4
  156. package/dist/structure/StructureScene.svelte +93 -100
  157. package/dist/structure/StructureScene.svelte.d.ts +15 -12
  158. package/dist/structure/Vector.svelte +19 -25
  159. package/dist/structure/Vector.svelte.d.ts +3 -3
  160. package/dist/structure/bonding.d.ts +16 -14
  161. package/dist/structure/bonding.js +207 -216
  162. package/dist/structure/export.d.ts +3 -0
  163. package/dist/structure/export.js +120 -0
  164. package/dist/structure/index.d.ts +15 -1
  165. package/dist/structure/index.js +2 -0
  166. package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -3
  167. package/dist/symmetry/index.d.ts +1 -0
  168. package/dist/symmetry/index.js +1 -0
  169. package/dist/symmetry/spacegroups.d.ts +9 -0
  170. package/dist/symmetry/spacegroups.js +397 -0
  171. package/dist/theme/ThemeControl.svelte.d.ts +3 -3
  172. package/dist/theme/themes.js +2 -16
  173. package/dist/trajectory/Trajectory.svelte +52 -78
  174. package/dist/trajectory/Trajectory.svelte.d.ts +5 -5
  175. package/dist/trajectory/TrajectoryError.svelte.d.ts +3 -3
  176. package/dist/trajectory/TrajectoryExportPane.svelte +1 -1
  177. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +5 -5
  178. package/dist/trajectory/TrajectoryInfoPane.svelte +1 -1
  179. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -3
  180. package/dist/trajectory/extract.js +2 -1
  181. package/dist/trajectory/index.d.ts +1 -1
  182. package/dist/trajectory/index.js +1 -1
  183. package/dist/trajectory/parse.js +21 -14
  184. package/dist/utils.d.ts +1 -0
  185. package/dist/utils.js +17 -0
  186. package/dist/xrd/XrdPlot.svelte +14 -11
  187. package/dist/xrd/XrdPlot.svelte.d.ts +6 -5
  188. package/package.json +20 -12
  189. package/readme.md +1 -1
  190. package/dist/material/MaterialCard.svelte +0 -123
  191. package/dist/material/MaterialCard.svelte.d.ts +0 -9
  192. package/dist/material/index.d.ts +0 -1
  193. package/dist/material/index.js +0 -1
  194. package/dist/plot/formatting.d.ts +0 -7
  195. package/dist/plot/formatting.js +0 -53
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">import { Icon } from './';
2
- let { sections, selected_values = {}, on_select, position, visible, on_close, menu_element = $bindable(), ...rest } = $props();
2
+ let { sections, selected_values = {}, on_select, position, visible, on_close, menu_element, ...rest } = $props();
3
3
  // Calculate smart position that keeps menu in viewport
4
4
  function get_smart_position() {
5
5
  if (!menu_element)
@@ -5,7 +5,7 @@ interface MenuOption {
5
5
  label?: string;
6
6
  disabled?: boolean;
7
7
  }
8
- interface Props extends HTMLAttributes<HTMLDivElement> {
8
+ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
9
9
  sections: Readonly<{
10
10
  title: string;
11
11
  options: readonly MenuOption[];
@@ -19,7 +19,7 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
19
19
  visible: boolean;
20
20
  on_close?: () => void;
21
21
  menu_element?: HTMLDivElement;
22
- }
23
- declare const ContextMenu: import("svelte").Component<Props, {}, "menu_element">;
22
+ };
23
+ declare const ContextMenu: import("svelte").Component<$$ComponentProps, {}, "">;
24
24
  type ContextMenu = ReturnType<typeof ContextMenu>;
25
25
  export default ContextMenu;
@@ -108,9 +108,10 @@ $effect(() => {
108
108
 
109
109
  <svelte:window
110
110
  onkeydown={(event: KeyboardEvent) => {
111
- if (event.key !== `Escape`) return
112
- event.preventDefault()
113
- close_pane()
111
+ if (event.key === `Escape` && show) {
112
+ event.preventDefault()
113
+ close_pane()
114
+ }
114
115
  }}
115
116
  onresize={handle_resize}
116
117
  />
@@ -238,7 +239,7 @@ $effect(() => {
238
239
  text-align: right; /* right align long line-breaking trajectory file names */
239
240
  }
240
241
  .draggable-pane :global(label) {
241
- display: flex;
242
+ display: inline-flex;
242
243
  align-items: center;
243
244
  gap: var(--pane-label-gap, 2pt);
244
245
  }
@@ -262,10 +263,14 @@ $effect(() => {
262
263
  flex: 1;
263
264
  min-width: 60px;
264
265
  }
266
+ .draggable-pane :global(input[type='color']) {
267
+ width: 2.5em;
268
+ height: 1.3em;
269
+ margin: 0 5pt;
270
+ }
265
271
  .draggable-pane :global(input[type='number']) {
266
272
  box-sizing: border-box;
267
273
  text-align: center;
268
- border-radius: 3pt;
269
274
  width: 2.2em;
270
275
  margin: 0 3pt 0 6pt;
271
276
  flex-shrink: 0;
@@ -1,7 +1,7 @@
1
1
  import type { IconName } from './icons';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- interface Props {
4
+ type $$ComponentProps = {
5
5
  show?: boolean;
6
6
  show_pane?: boolean;
7
7
  children: Snippet<[]>;
@@ -21,7 +21,7 @@ interface Props {
21
21
  pane_div?: HTMLDivElement;
22
22
  has_been_dragged?: boolean;
23
23
  currently_dragging?: boolean;
24
- }
25
- declare const DraggablePane: import("svelte").Component<Props, {}, "show" | "toggle_pane_btn" | "pane_div" | "has_been_dragged" | "currently_dragging">;
24
+ };
25
+ declare const DraggablePane: import("svelte").Component<$$ComponentProps, {}, "show" | "toggle_pane_btn" | "pane_div" | "has_been_dragged" | "currently_dragging">;
26
26
  type DraggablePane = ReturnType<typeof DraggablePane>;
27
27
  export default DraggablePane;
@@ -1,6 +1,6 @@
1
1
  import type { FileInfo } from './';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- interface Props extends HTMLAttributes<HTMLDivElement> {
3
+ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
4
4
  files: FileInfo[];
5
5
  active_files?: string[];
6
6
  show_category_filters?: boolean;
@@ -8,7 +8,7 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
8
8
  on_drag_end?: () => void;
9
9
  type_mapper?: (file: FileInfo) => string;
10
10
  file_type_colors?: Record<string, string>;
11
- }
12
- declare const FilePicker: import("svelte").Component<Props, {}, "">;
11
+ };
12
+ declare const FilePicker: import("svelte").Component<$$ComponentProps, {}, "">;
13
13
  type FilePicker = ReturnType<typeof FilePicker>;
14
14
  export default FilePicker;
@@ -1,8 +1,8 @@
1
1
  import type { SVGAttributes } from 'svelte/elements';
2
2
  import { type IconName } from './icons';
3
- interface Props extends SVGAttributes<SVGSVGElement> {
3
+ type $$ComponentProps = {
4
4
  icon: IconName;
5
- }
6
- declare const Icon: import("svelte").Component<Props, {}, "">;
5
+ } & SVGAttributes<SVGSVGElement>;
6
+ declare const Icon: import("svelte").Component<$$ComponentProps, {}, "">;
7
7
  type Icon = ReturnType<typeof Icon>;
8
8
  export default Icon;
package/dist/Nav.svelte CHANGED
@@ -1,5 +1,5 @@
1
- <script lang="ts">import { click_outside } from 'svelte-multiselect';
2
- import Icon from './Icon.svelte';
1
+ <script lang="ts">import { Icon } from './';
2
+ import { click_outside } from 'svelte-multiselect';
3
3
  let { routes = [], children, link, menu_style, page, labels, ...rest } = $props();
4
4
  let is_open = $state(false);
5
5
  let hovered_dropdown = $state(null);
@@ -132,15 +132,14 @@ function parse_route(route) {
132
132
  <!-- Dropdown menu item -->
133
133
  {@const parent = format_label(label)}
134
134
  {@const child_is_active = is_child_current(sub_routes)}
135
+ {@const parent_page_exists = sub_routes.includes(href)}
136
+ {@const filtered_sub_routes = sub_routes.filter((route) => route !== href)}
135
137
  <div
136
138
  class="dropdown-wrapper"
137
139
  class:active={child_is_active}
138
- role="button"
139
- tabindex="0"
140
140
  data-href={href}
141
+ role="group"
141
142
  aria-current={child_is_active ? `true` : undefined}
142
- aria-expanded={hovered_dropdown === href}
143
- aria-haspopup="true"
144
143
  onmouseenter={() => !is_touch_device && (hovered_dropdown = href)}
145
144
  onmouseleave={() => !is_touch_device && (hovered_dropdown = null)}
146
145
  onfocusin={() => (hovered_dropdown = href)}
@@ -150,16 +149,33 @@ function parse_route(route) {
150
149
  hovered_dropdown = null
151
150
  }
152
151
  }}
153
- onclick={() => toggle_dropdown(href, false)}
154
- onkeydown={(event) => handle_dropdown_keydown(event, href, sub_routes)}
155
152
  >
156
- <span class="dropdown-trigger" style={parent.style}>
157
- {@html parent.label}
158
- <Icon
159
- icon="ArrowDown"
160
- style="width: 0.8em; height: 0.8em; margin-left: 0.2em"
161
- />
162
- </span>
153
+ <div class="dropdown-trigger-wrapper">
154
+ <svelte:element
155
+ this={parent_page_exists ? `a` : `span`}
156
+ href={parent_page_exists ? href : undefined}
157
+ class="dropdown-trigger"
158
+ aria-current={is_current(href)}
159
+ onclick={close_menus}
160
+ role={parent_page_exists ? undefined : `button`}
161
+ style={parent.style}
162
+ >
163
+ {@html parent.label}
164
+ </svelte:element>
165
+ <button
166
+ class="dropdown-toggle"
167
+ aria-label="Toggle {parent.label} submenu"
168
+ aria-expanded={hovered_dropdown === href}
169
+ aria-haspopup="true"
170
+ onclick={() => toggle_dropdown(href, false)}
171
+ onkeydown={(event) => handle_dropdown_keydown(event, href, filtered_sub_routes)}
172
+ >
173
+ <Icon
174
+ icon="ArrowDown"
175
+ style="width: 0.8em; height: 0.8em"
176
+ />
177
+ </button>
178
+ </div>
163
179
  <div
164
180
  class="dropdown-menu"
165
181
  class:visible={hovered_dropdown === href}
@@ -175,11 +191,8 @@ function parse_route(route) {
175
191
  }
176
192
  }}
177
193
  >
178
- {#each sub_routes as child_href (child_href)}
179
- {@const child = format_label(
180
- child_href,
181
- true,
182
- )}
194
+ {#each filtered_sub_routes as child_href (child_href)}
195
+ {@const child = format_label(child_href, true)}
183
196
  {#if link}
184
197
  {@render link({ href: child_href, label: child.label })}
185
198
  {:else}
@@ -232,8 +245,7 @@ function parse_route(route) {
232
245
  flex-wrap: wrap;
233
246
  padding: 0.5em;
234
247
  }
235
- .menu-content > a,
236
- .dropdown-trigger {
248
+ .menu-content > a {
237
249
  line-height: 1.3;
238
250
  padding: 1pt 5pt;
239
251
  border-radius: var(--nav-border-radius);
@@ -241,8 +253,7 @@ function parse_route(route) {
241
253
  color: inherit;
242
254
  transition: background-color 0.2s;
243
255
  }
244
- .menu-content > a:hover,
245
- .dropdown-wrapper:hover .dropdown-trigger {
256
+ .menu-content > a:hover {
246
257
  background-color: var(--nav-link-bg-hover);
247
258
  }
248
259
  .menu-content > a[aria-current='page'] {
@@ -252,9 +263,8 @@ function parse_route(route) {
252
263
  /* Dropdown styles */
253
264
  .dropdown-wrapper {
254
265
  position: relative;
255
- cursor: pointer;
256
266
  }
257
- .dropdown-wrapper.active > .dropdown-trigger {
267
+ .dropdown-wrapper.active .dropdown-trigger {
258
268
  color: var(--nav-link-active-color);
259
269
  }
260
270
  .dropdown-wrapper::after {
@@ -265,11 +275,36 @@ function parse_route(route) {
265
275
  right: 0;
266
276
  height: var(--nav-dropdown-margin, 3pt);
267
277
  }
278
+ .dropdown-trigger-wrapper {
279
+ display: flex;
280
+ align-items: center;
281
+ gap: 0;
282
+ border-radius: var(--nav-border-radius);
283
+ transition: background-color 0.2s;
284
+ }
285
+ .dropdown-trigger-wrapper:hover {
286
+ background-color: var(--nav-link-bg-hover);
287
+ }
268
288
  .dropdown-trigger {
289
+ line-height: 1.3;
290
+ padding: 1pt 5pt;
291
+ text-decoration: none;
292
+ color: inherit;
293
+ border-radius: var(--nav-border-radius) 0 0 var(--nav-border-radius);
294
+ }
295
+ .dropdown-trigger[aria-current='page'] {
296
+ color: var(--nav-link-active-color);
297
+ }
298
+ .dropdown-toggle {
299
+ padding: 1pt 3pt;
300
+ border: none;
301
+ background: transparent;
302
+ color: inherit;
303
+ cursor: pointer;
269
304
  display: flex;
270
305
  align-items: center;
271
- gap: 0.2em;
272
- user-select: none;
306
+ justify-content: center;
307
+ border-radius: 0 var(--nav-border-radius) var(--nav-border-radius) 0;
273
308
  }
274
309
  .dropdown-menu {
275
310
  position: absolute;
@@ -372,6 +407,19 @@ function parse_route(route) {
372
407
  flex-direction: column;
373
408
  align-items: stretch;
374
409
  }
410
+ .dropdown-trigger-wrapper {
411
+ display: flex;
412
+ align-items: center;
413
+ justify-content: space-between;
414
+ }
415
+ .dropdown-trigger {
416
+ flex: 1;
417
+ border-radius: var(--nav-border-radius);
418
+ }
419
+ .dropdown-toggle {
420
+ padding: 4pt 8pt;
421
+ border-radius: var(--nav-border-radius);
422
+ }
375
423
  .dropdown-menu {
376
424
  position: static;
377
425
  border: none;
@@ -380,8 +428,5 @@ function parse_route(route) {
380
428
  padding: 0 0 0 1em;
381
429
  background-color: transparent;
382
430
  }
383
- .dropdown-trigger {
384
- cursor: pointer;
385
- }
386
431
  }
387
432
  </style>
@@ -1,11 +1,11 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- interface Props extends HTMLAttributes<HTMLElementTagNameMap[`section`]> {
3
+ type $$ComponentProps = HTMLAttributes<HTMLElementTagNameMap[`section`]> & {
4
4
  title: string;
5
5
  current_values: Record<string, unknown>;
6
6
  children: Snippet<[]>;
7
7
  on_reset?: () => void;
8
- }
9
- declare const SettingsSection: import("svelte").Component<Props, {}, "">;
8
+ };
9
+ declare const SettingsSection: import("svelte").Component<$$ComponentProps, {}, "">;
10
10
  type SettingsSection = ReturnType<typeof SettingsSection>;
11
11
  export default SettingsSection;
@@ -1,42 +1,31 @@
1
- <script lang="ts">let { text = `Loading...`, ...rest } = $props();
1
+ <script lang="ts">let { text, ...rest } = $props();
2
2
  export {};
3
3
  </script>
4
4
 
5
- <div class="spinner-overlay" role="status" aria-live="polite" aria-busy="true" {...rest}>
5
+ <div class="spinner" role="status" aria-live="polite" aria-busy="true" {...rest}>
6
6
  <div class="spinner" aria-hidden="true"></div>
7
- <p>{text}</p>
7
+ {#if text}
8
+ <span>{text}</span>
9
+ {/if}
8
10
  </div>
9
11
 
10
12
  <style>
11
- .spinner-overlay {
12
- position: absolute;
13
- top: 0;
14
- left: 0;
15
- right: 0;
16
- bottom: 0;
17
- display: flex;
18
- flex-direction: column;
19
- align-items: center;
20
- justify-content: center;
21
- background: var(--spinner-bg);
22
- color: var(--spinner-text-color, #333);
23
- backdrop-filter: blur(4px);
24
- z-index: var(--spinner-z-index, 10);
25
- }
26
13
  .spinner {
27
- width: var(--spinner-size, 40px);
28
- height: var(--spinner-size, 40px);
29
- border: var(--spinner-border-width, 4px) solid var(--spinner-track-color, #f3f3f3);
30
- border-top: var(--spinner-border-width, 4px) solid var(--spinner-color, #007acc);
31
- border-radius: 50%;
32
- animation: spin 1s linear infinite;
33
- margin-bottom: 1rem;
34
- box-sizing: border-box;
14
+ display: inline-flex;
15
+ align-items: center;
16
+ gap: 0.5rem;
17
+ margin: var(--spinner-margin, 3pt);
18
+ > div {
19
+ width: var(--spinner-size, 1em);
20
+ height: var(--spinner-size, 1em);
21
+ border: var(--spinner-border-width, 4px) solid var(--spinner-track-color, #f3f3f3);
22
+ border-top: var(--spinner-border-width, 4px) solid var(--spinner-color, #007acc);
23
+ border-radius: 50%;
24
+ animation: spin 1s linear infinite;
25
+ box-sizing: border-box;
26
+ }
35
27
  }
36
28
  @keyframes spin {
37
- 0% {
38
- transform: rotate(0deg);
39
- }
40
29
  100% {
41
30
  transform: rotate(360deg);
42
31
  }
@@ -1,7 +1,7 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
- interface Props extends HTMLAttributes<HTMLDivElement> {
2
+ type $$ComponentProps = {
3
3
  text?: string;
4
- }
5
- declare const Spinner: import("svelte").Component<Props, {}, "">;
4
+ } & HTMLAttributes<HTMLDivElement>;
5
+ declare const Spinner: import("svelte").Component<$$ComponentProps, {}, "">;
6
6
  type Spinner = ReturnType<typeof Spinner>;
7
7
  export default Spinner;
package/dist/app.css CHANGED
@@ -6,6 +6,10 @@
6
6
 
7
7
  --sms-max-width: 20em;
8
8
  --sms-text-color: var(--text-color);
9
+
10
+ /* Svelte MultiSelect */
11
+ --sms-options-bg: var(--page-bg);
12
+ --sms-active-color: light-dark(var(--accent-color), cornflowerblue);
9
13
  }
10
14
 
11
15
  /* Targeted theme transitions for performance */
@@ -0,0 +1,216 @@
1
+ <script lang="ts">import * as helpers from './helpers';
2
+ import { plot_colors } from '../colors';
3
+ import ScatterPlot from '../plot/ScatterPlot.svelte';
4
+ let { band_structs, line_kwargs = {}, path_mode = `strict`, band_type = undefined, show_legend = true, x_axis = {}, y_axis = {}, ...rest } = $props();
5
+ // Helper function to get line styling for a band
6
+ function get_line_style(color, is_acoustic, mode_type, frequencies, band_idx) {
7
+ let stroke = color;
8
+ let stroke_width = is_acoustic ? 1.5 : 1;
9
+ if (typeof line_kwargs === `function`) {
10
+ const custom = line_kwargs(frequencies, band_idx);
11
+ return {
12
+ stroke: custom.stroke ?? stroke,
13
+ stroke_width: custom.stroke_width ?? stroke_width,
14
+ };
15
+ }
16
+ if (typeof line_kwargs === `object` && line_kwargs !== null) {
17
+ const lk = line_kwargs;
18
+ // Check for mode-specific styling
19
+ if (`acoustic` in lk || `optical` in lk) {
20
+ const mode_kwargs = lk[mode_type];
21
+ if (mode_kwargs) {
22
+ stroke = mode_kwargs.stroke ?? stroke;
23
+ stroke_width = mode_kwargs.stroke_width ?? stroke_width;
24
+ }
25
+ }
26
+ else {
27
+ // Global styling for all bands
28
+ stroke = lk.stroke ?? stroke;
29
+ stroke_width = lk.stroke_width ?? stroke_width;
30
+ }
31
+ }
32
+ return { stroke, stroke_width };
33
+ }
34
+ // Normalize input to dict format
35
+ let band_structs_dict = $derived.by(() => {
36
+ if (!band_structs)
37
+ return {};
38
+ const is_single_struct = `qpoints` in band_structs && `branches` in band_structs;
39
+ if (is_single_struct) {
40
+ const normalized = helpers.normalize_band_structure(band_structs);
41
+ return normalized ? { default: normalized } : {};
42
+ }
43
+ // Normalize each structure in the dict
44
+ const result = {};
45
+ for (const [key, bs] of Object.entries(band_structs)) {
46
+ const normalized = helpers.normalize_band_structure(bs);
47
+ if (normalized)
48
+ result[key] = normalized;
49
+ }
50
+ return result;
51
+ });
52
+ let detected_band_type = $derived.by(() => band_type ?? `phonon`);
53
+ // Determine which segments to plot based on path_mode
54
+ let segments_to_plot = $derived.by(() => {
55
+ const all_segments = {};
56
+ // Collect all segments from all structures
57
+ for (const [label, bs] of Object.entries(band_structs_dict)) {
58
+ for (const branch of bs.branches) {
59
+ const start_label = bs.qpoints[branch.start_index]?.label ?? undefined;
60
+ const end_label = bs.qpoints[branch.end_index]?.label ?? undefined;
61
+ const segment_key = helpers.get_segment_key(start_label, end_label);
62
+ all_segments[segment_key] ??= [];
63
+ all_segments[segment_key].push([label, bs]);
64
+ }
65
+ }
66
+ const num_structs = Object.keys(band_structs_dict).length;
67
+ const is_intersection = path_mode === `strict` || path_mode === `intersection`;
68
+ if (is_intersection) {
69
+ // Only segments present in all structures
70
+ const common_segments = Object.keys(all_segments).filter((seg) => all_segments[seg].length === num_structs);
71
+ // Warn in strict mode if not all segments are common
72
+ if (path_mode === `strict` &&
73
+ common_segments.length !== Object.keys(all_segments).length) {
74
+ console.warn(`Band structures have different q-point paths. Use path_mode="union" or "intersection".`);
75
+ }
76
+ return new Set(common_segments);
77
+ }
78
+ // union - all segments
79
+ return new Set(Object.keys(all_segments));
80
+ });
81
+ // Map segments to x-axis positions
82
+ let x_positions = $derived.by(() => {
83
+ const positions = {};
84
+ let current_x = 0;
85
+ // Preserve physical path order using the first available structure
86
+ const canonical = Object.values(band_structs_dict)[0];
87
+ const ordered_segments = helpers.get_ordered_segments(canonical, segments_to_plot);
88
+ for (const segment_key of ordered_segments) {
89
+ if (positions[segment_key])
90
+ continue;
91
+ const [start_label, end_label] = segment_key.split(`_`);
92
+ // Find the first band structure that has this segment
93
+ for (const bs of Object.values(band_structs_dict)) {
94
+ const matching_branch = bs.branches.find((branch) => {
95
+ const branch_start = bs.qpoints[branch.start_index]?.label || `null`;
96
+ const branch_end = bs.qpoints[branch.end_index]?.label || `null`;
97
+ return branch_start === start_label && branch_end === end_label;
98
+ });
99
+ if (matching_branch) {
100
+ const segment_len = bs.distance[matching_branch.end_index] -
101
+ bs.distance[matching_branch.start_index];
102
+ positions[segment_key] = [current_x, current_x + segment_len];
103
+ current_x += segment_len;
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ return positions;
109
+ });
110
+ // Convert band structures to scatter plot series
111
+ let series_data = $derived.by(() => {
112
+ if (Object.keys(band_structs_dict).length === 0 || segments_to_plot.size === 0) {
113
+ return [];
114
+ }
115
+ const all_series = [];
116
+ for (const [bs_idx, [label, bs]] of Object.entries(band_structs_dict).entries()) {
117
+ const color = plot_colors[bs_idx % plot_colors.length];
118
+ const structure_label = label || `Structure ${bs_idx + 1}`;
119
+ for (const branch of bs.branches) {
120
+ const start_idx = branch.start_index;
121
+ const end_idx = branch.end_index + 1;
122
+ const start_label = bs.qpoints[start_idx]?.label ?? undefined;
123
+ const end_label = bs.qpoints[end_idx - 1]?.label ?? undefined;
124
+ const segment_key = helpers.get_segment_key(start_label, end_label);
125
+ if (!segments_to_plot.has(segment_key))
126
+ continue;
127
+ const [x_start, x_end] = x_positions[segment_key] || [0, 1];
128
+ // Scale distances for this segment
129
+ const segment_distances = bs.distance.slice(start_idx, end_idx);
130
+ const dist_min = segment_distances[0];
131
+ const dist_range = segment_distances[segment_distances.length - 1] - dist_min;
132
+ const scaled_distances = dist_range === 0
133
+ ? segment_distances.map(() => (x_start + x_end) / 2)
134
+ : segment_distances.map((d) => x_start + ((d - dist_min) / dist_range) * (x_end - x_start));
135
+ // Create series for each band
136
+ for (let band_idx = 0; band_idx < bs.nb_bands; band_idx++) {
137
+ const frequencies = bs.bands[band_idx].slice(start_idx, end_idx);
138
+ const is_acoustic = detected_band_type === `phonon` &&
139
+ band_idx < helpers.N_ACOUSTIC_MODES;
140
+ const mode_type = is_acoustic ? `acoustic` : `optical`;
141
+ const line_style = get_line_style(color, is_acoustic, mode_type, frequencies, band_idx);
142
+ all_series.push({
143
+ x: scaled_distances,
144
+ y: frequencies,
145
+ markers: `line`,
146
+ label: structure_label,
147
+ line_style,
148
+ });
149
+ }
150
+ }
151
+ }
152
+ return all_series;
153
+ });
154
+ // Get x-axis tick positions with custom labels for symmetry points
155
+ let x_axis_ticks = $derived.by(() => {
156
+ const tick_labels = {};
157
+ const sorted_positions = Object.entries(x_positions).sort(([, [a]], [, [b]]) => a - b);
158
+ for (const [segment_key, [x_start, x_end]] of sorted_positions) {
159
+ const [start_label, end_label] = segment_key.split(`_`);
160
+ // Add start label if not already present
161
+ if (!(x_start in tick_labels)) {
162
+ const pretty_start = start_label !== `null`
163
+ ? helpers.pretty_sym_point(start_label)
164
+ : ``;
165
+ if (pretty_start)
166
+ tick_labels[x_start] = pretty_start;
167
+ }
168
+ // Add end label
169
+ const pretty_end = end_label !== `null`
170
+ ? helpers.pretty_sym_point(end_label)
171
+ : ``;
172
+ if (pretty_end)
173
+ tick_labels[x_end] = pretty_end;
174
+ }
175
+ return tick_labels;
176
+ });
177
+ let x_range = $derived.by(() => {
178
+ const all_x = Object.values(x_positions).flat().sort();
179
+ return [all_x.at(0) ?? 0, all_x.at(-1) ?? 1];
180
+ });
181
+ </script>
182
+
183
+ <ScatterPlot
184
+ series={series_data}
185
+ x_axis={{
186
+ label: `Wave Vector`,
187
+ ticks: Object.keys(x_axis_ticks).length > 0 ? x_axis_ticks : undefined,
188
+ format: ``,
189
+ range: x_range, // Explicitly set range to disable padding
190
+ ...x_axis,
191
+ }}
192
+ y_axis={{
193
+ label: detected_band_type === `phonon` ? `Frequency (THz)` : `Energy (eV)`,
194
+ format: `.2f`,
195
+ ...y_axis,
196
+ }}
197
+ display={{ x_grid: false, y_grid: true, y_zero_line: true }}
198
+ legend={show_legend && Object.keys(band_structs_dict).length > 1 ? {} : null}
199
+ {...rest}
200
+ >
201
+ {#snippet user_content({ height, x_scale_fn, pad })}
202
+ <!-- Vertical lines at high-symmetry points -->
203
+ {@const tick_positions = Object.keys(x_axis_ticks).map(Number).sort((a, b) => a - b)}
204
+ {#each tick_positions as x_pos (x_pos)}
205
+ <line
206
+ x1={x_scale_fn(x_pos)}
207
+ x2={x_scale_fn(x_pos)}
208
+ y1={pad.t}
209
+ y2={height - pad.b}
210
+ stroke="var(--bands-symmetry-line-color, light-dark(black, white))"
211
+ stroke-width="var(--bands-symmetry-line-width, 1)"
212
+ opacity="var(--bands-symmetry-line-opacity, 0.5)"
213
+ />
214
+ {/each}
215
+ {/snippet}
216
+ </ScatterPlot>
@@ -0,0 +1,16 @@
1
+ import type { BandStructureType, BaseBandStructure, LineKwargs, PathMode } from './types';
2
+ import ScatterPlot from '../plot/ScatterPlot.svelte';
3
+ import type { AxisConfig } from '../plot/types';
4
+ import type { ComponentProps } from 'svelte';
5
+ type $$ComponentProps = ComponentProps<typeof ScatterPlot> & {
6
+ band_structs: BaseBandStructure | Record<string, BaseBandStructure>;
7
+ x_axis?: AxisConfig;
8
+ y_axis?: AxisConfig;
9
+ line_kwargs?: LineKwargs;
10
+ path_mode?: PathMode;
11
+ band_type?: BandStructureType;
12
+ show_legend?: boolean;
13
+ };
14
+ declare const Bands: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type Bands = ReturnType<typeof Bands>;
16
+ export default Bands;
@@ -0,0 +1,26 @@
1
+ <script lang="ts">import Bands from './Bands.svelte';
2
+ import Dos from './Dos.svelte';
3
+ let { band_structs, doses, bands_props = {}, dos_props = {}, shared_y_axis = true, ...rest } = $props();
4
+ // Shared y-axis configuration - use single object when shared_y_axis is true
5
+ let shared_y_axis_obj = $state({});
6
+ let bands_y_axis = $derived(shared_y_axis ? shared_y_axis_obj : {});
7
+ let dos_y_axis = $derived(shared_y_axis ? shared_y_axis_obj : {});
8
+ let grid_style = $derived(`display: grid; grid-template-columns: 1fr 200px; gap: 0; ${rest.style ?? ``}`);
9
+ </script>
10
+
11
+ <div {...rest} class="bands-and-dos {rest.class ?? ``}" style={grid_style}>
12
+ <Bands
13
+ {band_structs}
14
+ y_axis={bands_y_axis}
15
+ {...bands_props}
16
+ padding={{ r: 15 }}
17
+ />
18
+
19
+ <Dos
20
+ {doses}
21
+ orientation="horizontal"
22
+ y_axis={{ ...dos_y_axis, label: `` }}
23
+ padding={{ l: 15 }}
24
+ {...dos_props}
25
+ />
26
+ </div>
@@ -0,0 +1,16 @@
1
+ import type { ComponentProps } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import Bands from './Bands.svelte';
4
+ import Dos from './Dos.svelte';
5
+ import type { BaseBandStructure, Dos as DosData } from './types';
6
+ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
7
+ band_structs: BaseBandStructure | Record<string, BaseBandStructure>;
8
+ doses: DosData | Record<string, DosData>;
9
+ bands_props?: Partial<ComponentProps<typeof Bands>>;
10
+ dos_props?: Partial<ComponentProps<typeof Dos>>;
11
+ shared_y_axis?: boolean;
12
+ class?: string;
13
+ };
14
+ declare const BandsAndDos: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type BandsAndDos = ReturnType<typeof BandsAndDos>;
16
+ export default BandsAndDos;