selva-shared 0.8.1

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 (506) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/components/AppLayout.svelte +439 -0
  4. package/dist/components/AppLayout.svelte.d.ts +17 -0
  5. package/dist/components/CollapsedPanelStrip.svelte +67 -0
  6. package/dist/components/CollapsedPanelStrip.svelte.d.ts +11 -0
  7. package/dist/components/ComputeMessages.svelte +172 -0
  8. package/dist/components/ComputeMessages.svelte.d.ts +7 -0
  9. package/dist/components/ErrorScreen.svelte +55 -0
  10. package/dist/components/ErrorScreen.svelte.d.ts +9 -0
  11. package/dist/components/StateManager.svelte +318 -0
  12. package/dist/components/StateManager.svelte.d.ts +9 -0
  13. package/dist/components/Viewer.svelte +207 -0
  14. package/dist/components/Viewer.svelte.d.ts +12 -0
  15. package/dist/components/layout/FooterItemRenderer.svelte +20 -0
  16. package/dist/components/layout/FooterItemRenderer.svelte.d.ts +7 -0
  17. package/dist/components/layout/PageContainer.svelte +36 -0
  18. package/dist/components/layout/PageContainer.svelte.d.ts +12 -0
  19. package/dist/components/layout/PageFooter.svelte +223 -0
  20. package/dist/components/layout/PageFooter.svelte.d.ts +9 -0
  21. package/dist/components/layout/PageHeader.svelte +89 -0
  22. package/dist/components/layout/PageHeader.svelte.d.ts +12 -0
  23. package/dist/components/layout/index.d.ts +3 -0
  24. package/dist/components/layout/index.js +4 -0
  25. package/dist/components/preview/ChartOutput.svelte +257 -0
  26. package/dist/components/preview/ChartOutput.svelte.d.ts +8 -0
  27. package/dist/components/preview/Group.svelte +121 -0
  28. package/dist/components/preview/Group.svelte.d.ts +23 -0
  29. package/dist/components/preview/InputControl.svelte +119 -0
  30. package/dist/components/preview/InputControl.svelte.d.ts +11 -0
  31. package/dist/components/preview/OutputDisplay.svelte +296 -0
  32. package/dist/components/preview/OutputDisplay.svelte.d.ts +9 -0
  33. package/dist/components/preview/TabBar.svelte +36 -0
  34. package/dist/components/preview/TabBar.svelte.d.ts +8 -0
  35. package/dist/components/preview/TabContent.svelte +124 -0
  36. package/dist/components/preview/TabContent.svelte.d.ts +13 -0
  37. package/dist/components/preview/TabLayout.svelte +109 -0
  38. package/dist/components/preview/TabLayout.svelte.d.ts +13 -0
  39. package/dist/components/preview/index.d.ts +3 -0
  40. package/dist/components/preview/index.js +4 -0
  41. package/dist/components/preview/inputs/CheckboxInput.svelte +29 -0
  42. package/dist/components/preview/inputs/CheckboxInput.svelte.d.ts +10 -0
  43. package/dist/components/preview/inputs/ColorInput.svelte +21 -0
  44. package/dist/components/preview/inputs/ColorInput.svelte.d.ts +7 -0
  45. package/dist/components/preview/inputs/DropdownInput.svelte +40 -0
  46. package/dist/components/preview/inputs/DropdownInput.svelte.d.ts +10 -0
  47. package/dist/components/preview/inputs/FileInput.svelte +358 -0
  48. package/dist/components/preview/inputs/FileInput.svelte.d.ts +10 -0
  49. package/dist/components/preview/inputs/NumberInput.svelte +152 -0
  50. package/dist/components/preview/inputs/NumberInput.svelte.d.ts +11 -0
  51. package/dist/components/preview/inputs/TextInput.svelte +74 -0
  52. package/dist/components/preview/inputs/TextInput.svelte.d.ts +11 -0
  53. package/dist/components/preview/inputs/index.d.ts +6 -0
  54. package/dist/components/preview/inputs/index.js +6 -0
  55. package/dist/components/ui/CalculateButton.svelte +56 -0
  56. package/dist/components/ui/CalculateButton.svelte.d.ts +9 -0
  57. package/dist/components/ui/SolvingIndicator.svelte +55 -0
  58. package/dist/components/ui/SolvingIndicator.svelte.d.ts +6 -0
  59. package/dist/components/ui/StateDisplay.svelte +106 -0
  60. package/dist/components/ui/StateDisplay.svelte.d.ts +10 -0
  61. package/dist/components/ui/alert/alert-description.svelte +23 -0
  62. package/dist/components/ui/alert/alert-description.svelte.d.ts +5 -0
  63. package/dist/components/ui/alert/alert-title.svelte +20 -0
  64. package/dist/components/ui/alert/alert-title.svelte.d.ts +5 -0
  65. package/dist/components/ui/alert/alert.svelte +44 -0
  66. package/dist/components/ui/alert/alert.svelte.d.ts +26 -0
  67. package/dist/components/ui/alert/index.d.ts +5 -0
  68. package/dist/components/ui/alert/index.js +7 -0
  69. package/dist/components/ui/alert-dialog/alert-dialog-action.svelte +18 -0
  70. package/dist/components/ui/alert-dialog/alert-dialog-action.svelte.d.ts +4 -0
  71. package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte +18 -0
  72. package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte.d.ts +4 -0
  73. package/dist/components/ui/alert-dialog/alert-dialog-content.svelte +27 -0
  74. package/dist/components/ui/alert-dialog/alert-dialog-content.svelte.d.ts +8 -0
  75. package/dist/components/ui/alert-dialog/alert-dialog-description.svelte +17 -0
  76. package/dist/components/ui/alert-dialog/alert-dialog-description.svelte.d.ts +4 -0
  77. package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
  78. package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte.d.ts +5 -0
  79. package/dist/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
  80. package/dist/components/ui/alert-dialog/alert-dialog-header.svelte.d.ts +5 -0
  81. package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte +20 -0
  82. package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte.d.ts +4 -0
  83. package/dist/components/ui/alert-dialog/alert-dialog-title.svelte +17 -0
  84. package/dist/components/ui/alert-dialog/alert-dialog-title.svelte.d.ts +4 -0
  85. package/dist/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
  86. package/dist/components/ui/alert-dialog/alert-dialog-trigger.svelte.d.ts +4 -0
  87. package/dist/components/ui/alert-dialog/index.d.ts +12 -0
  88. package/dist/components/ui/alert-dialog/index.js +15 -0
  89. package/dist/components/ui/badge/badge.svelte +50 -0
  90. package/dist/components/ui/badge/badge.svelte.d.ts +32 -0
  91. package/dist/components/ui/badge/index.d.ts +2 -0
  92. package/dist/components/ui/badge/index.js +2 -0
  93. package/dist/components/ui/button/button.svelte +83 -0
  94. package/dist/components/ui/button/button.svelte.d.ts +67 -0
  95. package/dist/components/ui/button/index.d.ts +2 -0
  96. package/dist/components/ui/button/index.js +4 -0
  97. package/dist/components/ui/button-group/button-group-separator.svelte +20 -0
  98. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +13 -0
  99. package/dist/components/ui/button-group/button-group-text.svelte +30 -0
  100. package/dist/components/ui/button-group/button-group-text.svelte.d.ts +11 -0
  101. package/dist/components/ui/button-group/button-group.svelte +46 -0
  102. package/dist/components/ui/button-group/button-group.svelte.d.ts +26 -0
  103. package/dist/components/ui/button-group/index.d.ts +4 -0
  104. package/dist/components/ui/button-group/index.js +6 -0
  105. package/dist/components/ui/card/card-action.svelte +20 -0
  106. package/dist/components/ui/card/card-action.svelte.d.ts +5 -0
  107. package/dist/components/ui/card/card-content.svelte +15 -0
  108. package/dist/components/ui/card/card-content.svelte.d.ts +5 -0
  109. package/dist/components/ui/card/card-description.svelte +20 -0
  110. package/dist/components/ui/card/card-description.svelte.d.ts +5 -0
  111. package/dist/components/ui/card/card-footer.svelte +20 -0
  112. package/dist/components/ui/card/card-footer.svelte.d.ts +5 -0
  113. package/dist/components/ui/card/card-header.svelte +23 -0
  114. package/dist/components/ui/card/card-header.svelte.d.ts +5 -0
  115. package/dist/components/ui/card/card-title.svelte +20 -0
  116. package/dist/components/ui/card/card-title.svelte.d.ts +5 -0
  117. package/dist/components/ui/card/card.svelte +23 -0
  118. package/dist/components/ui/card/card.svelte.d.ts +5 -0
  119. package/dist/components/ui/card/index.d.ts +8 -0
  120. package/dist/components/ui/card/index.js +10 -0
  121. package/dist/components/ui/checkbox/checkbox.svelte +36 -0
  122. package/dist/components/ui/checkbox/checkbox.svelte.d.ts +4 -0
  123. package/dist/components/ui/checkbox/index.d.ts +2 -0
  124. package/dist/components/ui/checkbox/index.js +4 -0
  125. package/dist/components/ui/collapsible/collapsible-content.svelte +7 -0
  126. package/dist/components/ui/collapsible/collapsible-content.svelte.d.ts +4 -0
  127. package/dist/components/ui/collapsible/collapsible-trigger.svelte +7 -0
  128. package/dist/components/ui/collapsible/collapsible-trigger.svelte.d.ts +4 -0
  129. package/dist/components/ui/collapsible/collapsible.svelte +11 -0
  130. package/dist/components/ui/collapsible/collapsible.svelte.d.ts +4 -0
  131. package/dist/components/ui/collapsible/index.d.ts +4 -0
  132. package/dist/components/ui/collapsible/index.js +6 -0
  133. package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte +38 -0
  134. package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte.d.ts +9 -0
  135. package/dist/components/ui/context-menu/context-menu-content.svelte +25 -0
  136. package/dist/components/ui/context-menu/context-menu-content.svelte.d.ts +7 -0
  137. package/dist/components/ui/context-menu/context-menu-group-heading.svelte +21 -0
  138. package/dist/components/ui/context-menu/context-menu-group-heading.svelte.d.ts +7 -0
  139. package/dist/components/ui/context-menu/context-menu-group.svelte +7 -0
  140. package/dist/components/ui/context-menu/context-menu-group.svelte.d.ts +4 -0
  141. package/dist/components/ui/context-menu/context-menu-item.svelte +27 -0
  142. package/dist/components/ui/context-menu/context-menu-item.svelte.d.ts +8 -0
  143. package/dist/components/ui/context-menu/context-menu-label.svelte +24 -0
  144. package/dist/components/ui/context-menu/context-menu-label.svelte.d.ts +8 -0
  145. package/dist/components/ui/context-menu/context-menu-radio-group.svelte +16 -0
  146. package/dist/components/ui/context-menu/context-menu-radio-group.svelte.d.ts +4 -0
  147. package/dist/components/ui/context-menu/context-menu-radio-item.svelte +31 -0
  148. package/dist/components/ui/context-menu/context-menu-radio-item.svelte.d.ts +4 -0
  149. package/dist/components/ui/context-menu/context-menu-separator.svelte +17 -0
  150. package/dist/components/ui/context-menu/context-menu-separator.svelte.d.ts +4 -0
  151. package/dist/components/ui/context-menu/context-menu-shortcut.svelte +20 -0
  152. package/dist/components/ui/context-menu/context-menu-shortcut.svelte.d.ts +5 -0
  153. package/dist/components/ui/context-menu/context-menu-sub-content.svelte +20 -0
  154. package/dist/components/ui/context-menu/context-menu-sub-content.svelte.d.ts +4 -0
  155. package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte +29 -0
  156. package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte.d.ts +8 -0
  157. package/dist/components/ui/context-menu/context-menu-trigger.svelte +7 -0
  158. package/dist/components/ui/context-menu/context-menu-trigger.svelte.d.ts +4 -0
  159. package/dist/components/ui/context-menu/index.d.ts +16 -0
  160. package/dist/components/ui/context-menu/index.js +19 -0
  161. package/dist/components/ui/dialog/dialog-close.svelte +7 -0
  162. package/dist/components/ui/dialog/dialog-close.svelte.d.ts +4 -0
  163. package/dist/components/ui/dialog/dialog-content.svelte +43 -0
  164. package/dist/components/ui/dialog/dialog-content.svelte.d.ts +11 -0
  165. package/dist/components/ui/dialog/dialog-description.svelte +17 -0
  166. package/dist/components/ui/dialog/dialog-description.svelte.d.ts +4 -0
  167. package/dist/components/ui/dialog/dialog-footer.svelte +20 -0
  168. package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +5 -0
  169. package/dist/components/ui/dialog/dialog-header.svelte +20 -0
  170. package/dist/components/ui/dialog/dialog-header.svelte.d.ts +5 -0
  171. package/dist/components/ui/dialog/dialog-overlay.svelte +20 -0
  172. package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +4 -0
  173. package/dist/components/ui/dialog/dialog-title.svelte +17 -0
  174. package/dist/components/ui/dialog/dialog-title.svelte.d.ts +4 -0
  175. package/dist/components/ui/dialog/dialog-trigger.svelte +7 -0
  176. package/dist/components/ui/dialog/dialog-trigger.svelte.d.ts +4 -0
  177. package/dist/components/ui/dialog/index.d.ts +11 -0
  178. package/dist/components/ui/dialog/index.js +14 -0
  179. package/dist/components/ui/field/field-content.svelte +20 -0
  180. package/dist/components/ui/field/field-content.svelte.d.ts +5 -0
  181. package/dist/components/ui/field/field-description.svelte +25 -0
  182. package/dist/components/ui/field/field-description.svelte.d.ts +5 -0
  183. package/dist/components/ui/field/field-error.svelte +58 -0
  184. package/dist/components/ui/field/field-error.svelte.d.ts +12 -0
  185. package/dist/components/ui/field/field-group.svelte +23 -0
  186. package/dist/components/ui/field/field-group.svelte.d.ts +5 -0
  187. package/dist/components/ui/field/field-label.svelte +26 -0
  188. package/dist/components/ui/field/field-label.svelte.d.ts +10 -0
  189. package/dist/components/ui/field/field-legend.svelte +29 -0
  190. package/dist/components/ui/field/field-legend.svelte.d.ts +8 -0
  191. package/dist/components/ui/field/field-separator.svelte +38 -0
  192. package/dist/components/ui/field/field-separator.svelte.d.ts +9 -0
  193. package/dist/components/ui/field/field-set.svelte +24 -0
  194. package/dist/components/ui/field/field-set.svelte.d.ts +5 -0
  195. package/dist/components/ui/field/field-title.svelte +23 -0
  196. package/dist/components/ui/field/field-title.svelte.d.ts +5 -0
  197. package/dist/components/ui/field/field.svelte +53 -0
  198. package/dist/components/ui/field/field.svelte.d.ts +29 -0
  199. package/dist/components/ui/field/index.d.ts +11 -0
  200. package/dist/components/ui/field/index.js +13 -0
  201. package/dist/components/ui/index.d.ts +21 -0
  202. package/dist/components/ui/index.js +24 -0
  203. package/dist/components/ui/input/index.d.ts +2 -0
  204. package/dist/components/ui/input/index.js +4 -0
  205. package/dist/components/ui/input/input.svelte +52 -0
  206. package/dist/components/ui/input/input.svelte.d.ts +13 -0
  207. package/dist/components/ui/label/index.d.ts +2 -0
  208. package/dist/components/ui/label/index.js +4 -0
  209. package/dist/components/ui/label/label.svelte +20 -0
  210. package/dist/components/ui/label/label.svelte.d.ts +4 -0
  211. package/dist/components/ui/mode-toggle/index.d.ts +1 -0
  212. package/dist/components/ui/mode-toggle/index.js +1 -0
  213. package/dist/components/ui/mode-toggle/mode-toggle.svelte +16 -0
  214. package/dist/components/ui/mode-toggle/mode-toggle.svelte.d.ts +18 -0
  215. package/dist/components/ui/resizable/index.d.ts +4 -0
  216. package/dist/components/ui/resizable/index.js +6 -0
  217. package/dist/components/ui/resizable/resizable-handle.svelte +30 -0
  218. package/dist/components/ui/resizable/resizable-handle.svelte.d.ts +8 -0
  219. package/dist/components/ui/resizable/resizable-pane-group.svelte +20 -0
  220. package/dist/components/ui/resizable/resizable-pane-group.svelte.d.ts +7 -0
  221. package/dist/components/ui/scroll-area/index.d.ts +3 -0
  222. package/dist/components/ui/scroll-area/index.js +5 -0
  223. package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +31 -0
  224. package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte.d.ts +4 -0
  225. package/dist/components/ui/scroll-area/scroll-area.svelte +43 -0
  226. package/dist/components/ui/scroll-area/scroll-area.svelte.d.ts +11 -0
  227. package/dist/components/ui/select/index.d.ts +11 -0
  228. package/dist/components/ui/select/index.js +14 -0
  229. package/dist/components/ui/select/select-content.svelte +40 -0
  230. package/dist/components/ui/select/select-content.svelte.d.ts +8 -0
  231. package/dist/components/ui/select/select-group-heading.svelte +21 -0
  232. package/dist/components/ui/select/select-group-heading.svelte.d.ts +10 -0
  233. package/dist/components/ui/select/select-group.svelte +7 -0
  234. package/dist/components/ui/select/select-group.svelte.d.ts +4 -0
  235. package/dist/components/ui/select/select-item.svelte +38 -0
  236. package/dist/components/ui/select/select-item.svelte.d.ts +4 -0
  237. package/dist/components/ui/select/select-label.svelte +20 -0
  238. package/dist/components/ui/select/select-label.svelte.d.ts +6 -0
  239. package/dist/components/ui/select/select-scroll-down-button.svelte +20 -0
  240. package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +4 -0
  241. package/dist/components/ui/select/select-scroll-up-button.svelte +20 -0
  242. package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +4 -0
  243. package/dist/components/ui/select/select-separator.svelte +18 -0
  244. package/dist/components/ui/select/select-separator.svelte.d.ts +4 -0
  245. package/dist/components/ui/select/select-trigger.svelte +29 -0
  246. package/dist/components/ui/select/select-trigger.svelte.d.ts +8 -0
  247. package/dist/components/ui/separator/index.d.ts +2 -0
  248. package/dist/components/ui/separator/index.js +4 -0
  249. package/dist/components/ui/separator/separator.svelte +21 -0
  250. package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
  251. package/dist/components/ui/slider/index.d.ts +2 -0
  252. package/dist/components/ui/slider/index.js +4 -0
  253. package/dist/components/ui/slider/slider.svelte +52 -0
  254. package/dist/components/ui/slider/slider.svelte.d.ts +5 -0
  255. package/dist/components/ui/sonner/index.d.ts +2 -0
  256. package/dist/components/ui/sonner/index.js +2 -0
  257. package/dist/components/ui/sonner/sonner.svelte +13 -0
  258. package/dist/components/ui/sonner/sonner.svelte.d.ts +4 -0
  259. package/dist/components/ui/switch/index.d.ts +2 -0
  260. package/dist/components/ui/switch/index.js +4 -0
  261. package/dist/components/ui/switch/switch.svelte +29 -0
  262. package/dist/components/ui/switch/switch.svelte.d.ts +4 -0
  263. package/dist/components/ui/tabs/index.d.ts +5 -0
  264. package/dist/components/ui/tabs/index.js +7 -0
  265. package/dist/components/ui/tabs/tabs-content.svelte +17 -0
  266. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
  267. package/dist/components/ui/tabs/tabs-list.svelte +16 -0
  268. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
  269. package/dist/components/ui/tabs/tabs-trigger.svelte +20 -0
  270. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
  271. package/dist/components/ui/tabs/tabs.svelte +19 -0
  272. package/dist/components/ui/tabs/tabs.svelte.d.ts +4 -0
  273. package/dist/components/ui/textarea/index.d.ts +2 -0
  274. package/dist/components/ui/textarea/index.js +4 -0
  275. package/dist/components/ui/textarea/textarea.svelte +23 -0
  276. package/dist/components/ui/textarea/textarea.svelte.d.ts +5 -0
  277. package/dist/components/ui/theme-switcher/ThemeSwitcher.svelte +39 -0
  278. package/dist/components/ui/theme-switcher/ThemeSwitcher.svelte.d.ts +3 -0
  279. package/dist/components/ui/theme-switcher/index.d.ts +1 -0
  280. package/dist/components/ui/theme-switcher/index.js +1 -0
  281. package/dist/composables/useFooterItem.svelte.d.ts +15 -0
  282. package/dist/composables/useFooterItem.svelte.js +31 -0
  283. package/dist/constants.d.ts +6 -0
  284. package/dist/constants.js +6 -0
  285. package/dist/contexts/FOOTER_USAGE.md +164 -0
  286. package/dist/contexts/footerContext.svelte.d.ts +17 -0
  287. package/dist/contexts/footerContext.svelte.js +24 -0
  288. package/dist/dummy-output-values.d.ts +3 -0
  289. package/dist/dummy-output-values.js +53 -0
  290. package/dist/dummy-surface-chart.json +13 -0
  291. package/dist/example-schema-left-only.json +367 -0
  292. package/dist/example-schema-right-only.json +322 -0
  293. package/dist/example-schema.json +1582 -0
  294. package/dist/features/preview/handlers.d.ts +55 -0
  295. package/dist/features/preview/handlers.js +175 -0
  296. package/dist/features/preview/index.d.ts +2 -0
  297. package/dist/features/preview/index.js +2 -0
  298. package/dist/features/preview/notifications.d.ts +11 -0
  299. package/dist/features/preview/notifications.js +41 -0
  300. package/dist/index.d.ts +29 -0
  301. package/dist/index.js +39 -0
  302. package/dist/stores/themeStore.svelte.d.ts +12 -0
  303. package/dist/stores/themeStore.svelte.js +42 -0
  304. package/dist/styles/base.css +142 -0
  305. package/dist/styles/themes/cyberpunk.css +98 -0
  306. package/dist/styles/themes/neutral.css +72 -0
  307. package/dist/styles/themes/ocean.css +75 -0
  308. package/dist/styles/themes/selva.css +105 -0
  309. package/dist/themes.d.ts +5 -0
  310. package/dist/themes.js +13 -0
  311. package/dist/types/generated/index.d.ts +6 -0
  312. package/dist/types/generated/index.js +6 -0
  313. package/dist/types/generated/preset.d.ts +80 -0
  314. package/dist/types/generated/preset.js +7 -0
  315. package/dist/types/generated/schema.d.ts +451 -0
  316. package/dist/types/generated/schema.js +48 -0
  317. package/dist/utils/computeThrottle.svelte.d.ts +28 -0
  318. package/dist/utils/computeThrottle.svelte.js +93 -0
  319. package/dist/utils/debounce.d.ts +14 -0
  320. package/dist/utils/debounce.js +25 -0
  321. package/dist/utils/file-download.d.ts +26 -0
  322. package/dist/utils/file-download.js +76 -0
  323. package/dist/utils/loadScript.d.ts +14 -0
  324. package/dist/utils/loadScript.js +41 -0
  325. package/dist/utils/param-exporter.d.ts +30 -0
  326. package/dist/utils/param-exporter.js +186 -0
  327. package/dist/utils/solving.svelte.d.ts +12 -0
  328. package/dist/utils/solving.svelte.js +86 -0
  329. package/dist/utils/utils-shared.d.ts +9 -0
  330. package/dist/utils/utils-shared.js +53 -0
  331. package/dist/utils/visibility-rules.d.ts +12 -0
  332. package/dist/utils/visibility-rules.js +52 -0
  333. package/dist/utils.d.ts +12 -0
  334. package/dist/utils.js +5 -0
  335. package/package.json +70 -0
  336. package/src/lib/components/AppLayout.svelte +439 -0
  337. package/src/lib/components/CollapsedPanelStrip.svelte +67 -0
  338. package/src/lib/components/ComputeMessages.svelte +172 -0
  339. package/src/lib/components/ErrorScreen.svelte +55 -0
  340. package/src/lib/components/StateManager.svelte +318 -0
  341. package/src/lib/components/Viewer.svelte +207 -0
  342. package/src/lib/components/layout/FooterItemRenderer.svelte +20 -0
  343. package/src/lib/components/layout/PageContainer.svelte +36 -0
  344. package/src/lib/components/layout/PageFooter.svelte +223 -0
  345. package/src/lib/components/layout/PageHeader.svelte +89 -0
  346. package/src/lib/components/layout/index.ts +4 -0
  347. package/src/lib/components/preview/ChartOutput.svelte +257 -0
  348. package/src/lib/components/preview/Group.svelte +121 -0
  349. package/src/lib/components/preview/InputControl.svelte +119 -0
  350. package/src/lib/components/preview/OutputDisplay.svelte +296 -0
  351. package/src/lib/components/preview/TabBar.svelte +36 -0
  352. package/src/lib/components/preview/TabContent.svelte +124 -0
  353. package/src/lib/components/preview/TabLayout.svelte +109 -0
  354. package/src/lib/components/preview/index.ts +4 -0
  355. package/src/lib/components/preview/inputs/CheckboxInput.svelte +29 -0
  356. package/src/lib/components/preview/inputs/ColorInput.svelte +21 -0
  357. package/src/lib/components/preview/inputs/DropdownInput.svelte +40 -0
  358. package/src/lib/components/preview/inputs/FileInput.svelte +358 -0
  359. package/src/lib/components/preview/inputs/NumberInput.svelte +152 -0
  360. package/src/lib/components/preview/inputs/TextInput.svelte +74 -0
  361. package/src/lib/components/preview/inputs/index.ts +6 -0
  362. package/src/lib/components/ui/CalculateButton.svelte +56 -0
  363. package/src/lib/components/ui/SolvingIndicator.svelte +55 -0
  364. package/src/lib/components/ui/StateDisplay.svelte +106 -0
  365. package/src/lib/components/ui/alert/alert-description.svelte +23 -0
  366. package/src/lib/components/ui/alert/alert-title.svelte +20 -0
  367. package/src/lib/components/ui/alert/alert.svelte +44 -0
  368. package/src/lib/components/ui/alert/index.ts +14 -0
  369. package/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +18 -0
  370. package/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +18 -0
  371. package/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte +27 -0
  372. package/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte +17 -0
  373. package/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
  374. package/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
  375. package/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte +20 -0
  376. package/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte +17 -0
  377. package/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
  378. package/src/lib/components/ui/alert-dialog/index.ts +39 -0
  379. package/src/lib/components/ui/badge/badge.svelte +50 -0
  380. package/src/lib/components/ui/badge/index.ts +2 -0
  381. package/src/lib/components/ui/button/button.svelte +83 -0
  382. package/src/lib/components/ui/button/index.ts +17 -0
  383. package/src/lib/components/ui/button-group/button-group-separator.svelte +20 -0
  384. package/src/lib/components/ui/button-group/button-group-text.svelte +30 -0
  385. package/src/lib/components/ui/button-group/button-group.svelte +46 -0
  386. package/src/lib/components/ui/button-group/index.ts +13 -0
  387. package/src/lib/components/ui/card/card-action.svelte +20 -0
  388. package/src/lib/components/ui/card/card-content.svelte +15 -0
  389. package/src/lib/components/ui/card/card-description.svelte +20 -0
  390. package/src/lib/components/ui/card/card-footer.svelte +20 -0
  391. package/src/lib/components/ui/card/card-header.svelte +23 -0
  392. package/src/lib/components/ui/card/card-title.svelte +20 -0
  393. package/src/lib/components/ui/card/card.svelte +23 -0
  394. package/src/lib/components/ui/card/index.ts +25 -0
  395. package/src/lib/components/ui/checkbox/checkbox.svelte +36 -0
  396. package/src/lib/components/ui/checkbox/index.ts +6 -0
  397. package/src/lib/components/ui/collapsible/collapsible-content.svelte +7 -0
  398. package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +7 -0
  399. package/src/lib/components/ui/collapsible/collapsible.svelte +11 -0
  400. package/src/lib/components/ui/collapsible/index.ts +13 -0
  401. package/src/lib/components/ui/context-menu/context-menu-checkbox-item.svelte +38 -0
  402. package/src/lib/components/ui/context-menu/context-menu-content.svelte +25 -0
  403. package/src/lib/components/ui/context-menu/context-menu-group-heading.svelte +21 -0
  404. package/src/lib/components/ui/context-menu/context-menu-group.svelte +7 -0
  405. package/src/lib/components/ui/context-menu/context-menu-item.svelte +27 -0
  406. package/src/lib/components/ui/context-menu/context-menu-label.svelte +24 -0
  407. package/src/lib/components/ui/context-menu/context-menu-radio-group.svelte +16 -0
  408. package/src/lib/components/ui/context-menu/context-menu-radio-item.svelte +31 -0
  409. package/src/lib/components/ui/context-menu/context-menu-separator.svelte +17 -0
  410. package/src/lib/components/ui/context-menu/context-menu-shortcut.svelte +20 -0
  411. package/src/lib/components/ui/context-menu/context-menu-sub-content.svelte +20 -0
  412. package/src/lib/components/ui/context-menu/context-menu-sub-trigger.svelte +29 -0
  413. package/src/lib/components/ui/context-menu/context-menu-trigger.svelte +7 -0
  414. package/src/lib/components/ui/context-menu/index.ts +51 -0
  415. package/src/lib/components/ui/dialog/dialog-close.svelte +7 -0
  416. package/src/lib/components/ui/dialog/dialog-content.svelte +43 -0
  417. package/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  418. package/src/lib/components/ui/dialog/dialog-footer.svelte +20 -0
  419. package/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  420. package/src/lib/components/ui/dialog/dialog-overlay.svelte +20 -0
  421. package/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  422. package/src/lib/components/ui/dialog/dialog-trigger.svelte +7 -0
  423. package/src/lib/components/ui/dialog/index.ts +37 -0
  424. package/src/lib/components/ui/field/field-content.svelte +20 -0
  425. package/src/lib/components/ui/field/field-description.svelte +25 -0
  426. package/src/lib/components/ui/field/field-error.svelte +58 -0
  427. package/src/lib/components/ui/field/field-group.svelte +23 -0
  428. package/src/lib/components/ui/field/field-label.svelte +26 -0
  429. package/src/lib/components/ui/field/field-legend.svelte +29 -0
  430. package/src/lib/components/ui/field/field-separator.svelte +38 -0
  431. package/src/lib/components/ui/field/field-set.svelte +24 -0
  432. package/src/lib/components/ui/field/field-title.svelte +23 -0
  433. package/src/lib/components/ui/field/field.svelte +53 -0
  434. package/src/lib/components/ui/field/index.ts +33 -0
  435. package/src/lib/components/ui/index.ts +33 -0
  436. package/src/lib/components/ui/input/index.ts +7 -0
  437. package/src/lib/components/ui/input/input.svelte +52 -0
  438. package/src/lib/components/ui/label/index.ts +7 -0
  439. package/src/lib/components/ui/label/label.svelte +20 -0
  440. package/src/lib/components/ui/mode-toggle/index.ts +1 -0
  441. package/src/lib/components/ui/mode-toggle/mode-toggle.svelte +16 -0
  442. package/src/lib/components/ui/resizable/index.ts +13 -0
  443. package/src/lib/components/ui/resizable/resizable-handle.svelte +30 -0
  444. package/src/lib/components/ui/resizable/resizable-pane-group.svelte +20 -0
  445. package/src/lib/components/ui/scroll-area/index.ts +10 -0
  446. package/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte +31 -0
  447. package/src/lib/components/ui/scroll-area/scroll-area.svelte +43 -0
  448. package/src/lib/components/ui/select/index.ts +37 -0
  449. package/src/lib/components/ui/select/select-content.svelte +40 -0
  450. package/src/lib/components/ui/select/select-group-heading.svelte +21 -0
  451. package/src/lib/components/ui/select/select-group.svelte +7 -0
  452. package/src/lib/components/ui/select/select-item.svelte +38 -0
  453. package/src/lib/components/ui/select/select-label.svelte +20 -0
  454. package/src/lib/components/ui/select/select-scroll-down-button.svelte +20 -0
  455. package/src/lib/components/ui/select/select-scroll-up-button.svelte +20 -0
  456. package/src/lib/components/ui/select/select-separator.svelte +18 -0
  457. package/src/lib/components/ui/select/select-trigger.svelte +29 -0
  458. package/src/lib/components/ui/separator/index.ts +7 -0
  459. package/src/lib/components/ui/separator/separator.svelte +21 -0
  460. package/src/lib/components/ui/slider/index.ts +7 -0
  461. package/src/lib/components/ui/slider/slider.svelte +52 -0
  462. package/src/lib/components/ui/sonner/index.ts +2 -0
  463. package/src/lib/components/ui/sonner/sonner.svelte +13 -0
  464. package/src/lib/components/ui/switch/index.ts +7 -0
  465. package/src/lib/components/ui/switch/switch.svelte +29 -0
  466. package/src/lib/components/ui/tabs/index.ts +16 -0
  467. package/src/lib/components/ui/tabs/tabs-content.svelte +17 -0
  468. package/src/lib/components/ui/tabs/tabs-list.svelte +16 -0
  469. package/src/lib/components/ui/tabs/tabs-trigger.svelte +20 -0
  470. package/src/lib/components/ui/tabs/tabs.svelte +19 -0
  471. package/src/lib/components/ui/textarea/index.ts +7 -0
  472. package/src/lib/components/ui/textarea/textarea.svelte +23 -0
  473. package/src/lib/components/ui/theme-switcher/ThemeSwitcher.svelte +39 -0
  474. package/src/lib/components/ui/theme-switcher/index.ts +1 -0
  475. package/src/lib/composables/useFooterItem.svelte.ts +39 -0
  476. package/src/lib/constants.ts +6 -0
  477. package/src/lib/contexts/FOOTER_USAGE.md +164 -0
  478. package/src/lib/contexts/footerContext.svelte.ts +52 -0
  479. package/src/lib/dummy-output-values.ts +62 -0
  480. package/src/lib/dummy-surface-chart.json +13 -0
  481. package/src/lib/example-schema-left-only.json +367 -0
  482. package/src/lib/example-schema-right-only.json +322 -0
  483. package/src/lib/example-schema.json +1582 -0
  484. package/src/lib/features/preview/handlers.ts +243 -0
  485. package/src/lib/features/preview/index.ts +2 -0
  486. package/src/lib/features/preview/notifications.ts +52 -0
  487. package/src/lib/index.ts +52 -0
  488. package/src/lib/stores/themeStore.svelte.ts +54 -0
  489. package/src/lib/styles/base.css +142 -0
  490. package/src/lib/styles/themes/cyberpunk.css +98 -0
  491. package/src/lib/styles/themes/neutral.css +72 -0
  492. package/src/lib/styles/themes/ocean.css +75 -0
  493. package/src/lib/styles/themes/selva.css +105 -0
  494. package/src/lib/themes.ts +18 -0
  495. package/src/lib/types/generated/index.ts +6 -0
  496. package/src/lib/types/generated/preset.ts +82 -0
  497. package/src/lib/types/generated/schema.ts +527 -0
  498. package/src/lib/utils/computeThrottle.svelte.ts +117 -0
  499. package/src/lib/utils/debounce.ts +30 -0
  500. package/src/lib/utils/file-download.ts +88 -0
  501. package/src/lib/utils/loadScript.ts +52 -0
  502. package/src/lib/utils/param-exporter.ts +242 -0
  503. package/src/lib/utils/solving.svelte.ts +100 -0
  504. package/src/lib/utils/utils-shared.ts +57 -0
  505. package/src/lib/utils/visibility-rules.ts +97 -0
  506. package/src/lib/utils.ts +13 -0
@@ -0,0 +1,223 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import * as Dialog from '$lib/components/ui/dialog';
4
+ import * as Collapsible from '$lib/components/ui/collapsible';
5
+ import { CircleAlert, TriangleAlert, ChevronDown, ChevronRight } from '@lucide/svelte';
6
+ import { SvelteMap } from 'svelte/reactivity';
7
+ import { useFooter, type FooterItem } from '$lib/contexts/footerContext.svelte';
8
+ import FooterItemRenderer from './FooterItemRenderer.svelte';
9
+
10
+ interface Props {
11
+ errors?: string[];
12
+ warnings?: string[];
13
+ children?: Snippet;
14
+ }
15
+
16
+ let { errors = [], warnings = [], children }: Props = $props();
17
+
18
+ let footerStore = (() => {
19
+ try {
20
+ return useFooter();
21
+ } catch {
22
+ return null;
23
+ }
24
+ })();
25
+
26
+ // Access items directly so SvelteMap reactivity is tracked
27
+ const leftItems = $derived(
28
+ footerStore
29
+ ? Array.from(footerStore.items.values())
30
+ .filter((item) => item.position === 'left')
31
+ .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0))
32
+ : []
33
+ );
34
+ const rightItems = $derived(
35
+ footerStore
36
+ ? Array.from(footerStore.items.values())
37
+ .filter((item) => item.position === 'right')
38
+ .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0))
39
+ : []
40
+ );
41
+
42
+ let _currentYear = new Date().getFullYear();
43
+ let dialogOpen = $state(false);
44
+ let showErrors = $state(true);
45
+ let showWarnings = $state(false);
46
+
47
+ const hasMessages = $derived(errors.length > 0 || warnings.length > 0);
48
+ const totalCount = $derived(errors.length + warnings.length);
49
+
50
+ function groupMessages(messages: string[]): Array<{ message: string; count: number }> {
51
+ const grouped = new SvelteMap<string, number>();
52
+
53
+ for (const msg of messages) {
54
+ // Extract the base message without the component GUID
55
+ const baseMsg = msg.replace(/\([a-f0-9-]{36}\)$/i, '(...)').trim();
56
+ const currentCount = grouped.get(baseMsg) || 0;
57
+ grouped.set(baseMsg, currentCount + 1);
58
+ }
59
+
60
+ return Array.from(grouped.entries())
61
+ .map(([message, count]) => ({ message, count }))
62
+ .sort((a, b) => b.count - a.count);
63
+ }
64
+
65
+ const groupedErrors = $derived(groupMessages(errors));
66
+ const groupedWarnings = $derived(groupMessages(warnings));
67
+ </script>
68
+
69
+ <footer
70
+ class="px-4 gap-4 text-xs h-7 mt-2 flex shrink-0 items-center justify-between border-t border-border bg-background text-muted-foreground select-none"
71
+ >
72
+ <!-- Left section: Status items + custom context items -->
73
+ <div class="gap-4 flex items-center">
74
+ <!-- Custom left items from context -->
75
+ {#each leftItems as item (item.id)}
76
+ <FooterItemRenderer {item} />
77
+ {/each}
78
+
79
+ {#if hasMessages}
80
+ <Dialog.Root bind:open={dialogOpen}>
81
+ <Dialog.Trigger
82
+ class="gap-1.5 px-2 py-1 rounded flex cursor-pointer items-center transition-colors hover:bg-muted {errors.length >
83
+ 0
84
+ ? 'text-destructive hover:bg-destructive/10'
85
+ : 'text-warning hover:bg-warning/10'}"
86
+ title={`${totalCount} ${totalCount === 1 ? 'issue' : 'issues'}`}
87
+ >
88
+ {#if errors.length > 0}
89
+ <CircleAlert class="h-3.5 w-3.5" />
90
+ <span class="font-medium">{errors.length} Error{errors.length !== 1 ? 's' : ''}</span>
91
+ {/if}
92
+
93
+ {#if warnings.length > 0}
94
+ {#if errors.length > 0}
95
+ <span class="text-border">•</span>
96
+ {/if}
97
+ <TriangleAlert class="h-3.5 w-3.5" />
98
+ <span class="font-medium"
99
+ >{warnings.length} Warning{warnings.length !== 1 ? 's' : ''}</span
100
+ >
101
+ {/if}
102
+ </Dialog.Trigger>
103
+
104
+ <Dialog.Content class="max-w-2xl max-h-[80vh]">
105
+ <Dialog.Header>
106
+ <Dialog.Title class="gap-2 flex items-center">
107
+ <CircleAlert class="h-5 w-5" />
108
+ Compute Messages
109
+ </Dialog.Title>
110
+ <Dialog.Description>
111
+ {totalCount}
112
+ {totalCount === 1 ? 'issue' : 'issues'} detected during solve
113
+ </Dialog.Description>
114
+ </Dialog.Header>
115
+
116
+ <div class="space-y-3 pr-2 overflow-y-auto" style="max-height: calc(80vh - 180px);">
117
+ <!-- Errors Section -->
118
+ {#if errors.length > 0}
119
+ <Collapsible.Root bind:open={showErrors}>
120
+ <div class="overflow-hidden rounded-lg border border-destructive bg-card">
121
+ <div class="px-4 py-3 flex items-center">
122
+ <Collapsible.Trigger
123
+ class="-mx-4 -my-3 gap-3 px-4 py-3 flex flex-1 items-center text-left transition-colors hover:bg-destructive/5"
124
+ >
125
+ {#if showErrors}
126
+ <ChevronDown class="h-4 w-4 shrink-0 text-destructive" />
127
+ {:else}
128
+ <ChevronRight class="h-4 w-4 shrink-0 text-destructive" />
129
+ {/if}
130
+ <CircleAlert class="h-4 w-4 shrink-0 text-destructive" />
131
+ <span class="text-sm font-medium text-destructive">
132
+ {errors.length === 1 ? '1 Error' : `${errors.length} Errors`}
133
+ </span>
134
+ </Collapsible.Trigger>
135
+ </div>
136
+
137
+ <Collapsible.Content class="space-y-0">
138
+ <div
139
+ class="max-h-60 px-4 py-3 overflow-y-auto border-t border-destructive bg-card"
140
+ >
141
+ <ul class="space-y-2">
142
+ {#each groupedErrors as { message, count } (message)}
143
+ <li class="gap-2 text-sm flex text-destructive/90">
144
+ <span class="shrink-0">•</span>
145
+ <span class="flex-1">
146
+ {message}
147
+ {#if count > 1}
148
+ <span class="ml-1 font-medium text-destructive/70">×{count} </span>
149
+ {/if}
150
+ </span>
151
+ </li>
152
+ {/each}
153
+ </ul>
154
+ </div>
155
+ </Collapsible.Content>
156
+ </div>
157
+ </Collapsible.Root>
158
+ {/if}
159
+
160
+ <!-- Warnings Section -->
161
+ {#if warnings.length > 0}
162
+ <Collapsible.Root bind:open={showWarnings}>
163
+ <div class="overflow-hidden rounded-lg border border-warning/50 bg-card">
164
+ <div class="px-4 py-3 flex items-center">
165
+ <Collapsible.Trigger
166
+ class="-mx-4 -my-3 gap-3 px-4 py-3 flex flex-1 items-center text-left transition-colors hover:bg-warning/5"
167
+ >
168
+ {#if showWarnings}
169
+ <ChevronDown class="h-4 w-4 shrink-0 text-warning" />
170
+ {:else}
171
+ <ChevronRight class="h-4 w-4 shrink-0 text-warning" />
172
+ {/if}
173
+ <TriangleAlert class="h-4 w-4 shrink-0 text-warning" />
174
+ <span class="text-sm font-medium text-warning">
175
+ {warnings.length === 1 ? '1 Warning' : `${warnings.length} Warnings`}
176
+ </span>
177
+ </Collapsible.Trigger>
178
+ </div>
179
+
180
+ <Collapsible.Content class="space-y-0">
181
+ <div
182
+ class="max-h-60 px-4 py-3 overflow-y-auto border-t border-warning/50 bg-card"
183
+ >
184
+ <ul class="space-y-2">
185
+ {#each groupedWarnings as { message, count } (message)}
186
+ <li class="gap-2 text-sm flex text-muted-foreground">
187
+ <span class="shrink-0">•</span>
188
+ <span class="flex-1">
189
+ {message}
190
+ {#if count > 1}
191
+ <span class="ml-1 font-medium text-warning/70">×{count}</span>
192
+ {/if}
193
+ </span>
194
+ </li>
195
+ {/each}
196
+ </ul>
197
+ </div>
198
+ </Collapsible.Content>
199
+ </div>
200
+ </Collapsible.Root>
201
+ {/if}
202
+ </div>
203
+ </Dialog.Content>
204
+ </Dialog.Root>
205
+ {/if}
206
+
207
+ {#if children}
208
+ <div class="gap-4 flex items-center">
209
+ {@render children()}
210
+ </div>
211
+ {/if}
212
+ </div>
213
+
214
+ <!-- Right section: Custom items + Copyright -->
215
+ <div class="gap-4 ml-auto flex items-center">
216
+ <!-- Custom right items from context -->
217
+ {#each rightItems as item (item.id)}
218
+ <FooterItemRenderer {item} />
219
+ {/each}
220
+
221
+ <p>by Selva &copy; {_currentYear}</p>
222
+ </div>
223
+ </footer>
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { ModeToggle } from '$lib/components/ui/mode-toggle';
4
+ import { page } from '$app/state';
5
+ import { SvelteURLSearchParams } from 'svelte/reactivity';
6
+
7
+ interface PageHeaderProps {
8
+ title: string;
9
+ showModeToggle?: boolean;
10
+ logo?: string;
11
+ children?: Snippet;
12
+ rightContent?: Snippet;
13
+ class?: string;
14
+ }
15
+
16
+ let {
17
+ title,
18
+ logo = '/favicon/favicon.svg',
19
+ children,
20
+ rightContent,
21
+ class: className = '',
22
+ showModeToggle = false
23
+ }: PageHeaderProps = $props();
24
+
25
+ // Build home URL preserving current session/wsPort query params
26
+ const homeUrl = $derived.by(() => {
27
+ const session = page.url.searchParams.get('session');
28
+ const wsPort = page.url.searchParams.get('wsPort');
29
+ if (!session && !wsPort) return '/';
30
+ const params = new SvelteURLSearchParams();
31
+ if (session) params.set('session', session);
32
+ if (wsPort) params.set('wsPort', wsPort);
33
+ return `/?${params.toString()}`;
34
+ });
35
+ </script>
36
+
37
+ <header
38
+ class={`px-4 py-3 backdrop-blur-sm sm:px-6 mb-0 sm:mb-4 border-b border-border bg-linear-to-b from-background to-card transition-all duration-200 ${className}`}
39
+ >
40
+ <div class="gap-2 sm:flex-row sm:items-center sm:justify-between sm:gap-4 flex flex-col">
41
+ <!-- Left section -->
42
+ <div class="gap-2 min-w-0 sm:gap-3 flex flex-1 items-center">
43
+ {#if logo}
44
+ <a
45
+ href={homeUrl}
46
+ class="shrink-0 cursor-pointer transition-opacity hover:opacity-75"
47
+ title="Go to home"
48
+ >
49
+ <img src={logo} alt="Logo" class="h-8 w-8" />
50
+ </a>
51
+ {/if}
52
+ <h1 class="text-lg font-bold sm:text-2xl truncate text-foreground">
53
+ {title}
54
+ </h1>
55
+
56
+ {#if showModeToggle && !rightContent}
57
+ <div class="sm:hidden ml-auto">
58
+ <ModeToggle />
59
+ </div>
60
+ {/if}
61
+
62
+ {#if children}
63
+ <div class="gap-2 text-xs sm:flex hidden flex-wrap items-center text-muted-foreground">
64
+ {@render children()}
65
+ </div>
66
+ {/if}
67
+ </div>
68
+
69
+ <!-- Right section (rightContent + ModeToggle) -->
70
+ {#if rightContent || showModeToggle}
71
+ <div class="sm:flex gap-2 hidden items-center">
72
+ {#if rightContent}
73
+ {@render rightContent()}
74
+ {/if}
75
+ {#if showModeToggle}
76
+ <ModeToggle />
77
+ {/if}
78
+ </div>
79
+ {/if}
80
+ </div>
81
+ </header>
82
+
83
+ <style>
84
+ :global(header) {
85
+ box-shadow:
86
+ 0 1px 3px rgba(0, 0, 0, 0.08),
87
+ 0 0 0 1px rgba(0, 0, 0, 0.02);
88
+ }
89
+ </style>
@@ -0,0 +1,4 @@
1
+ // Layout Components - Page structure and organization
2
+ export { default as PageContainer } from './PageContainer.svelte';
3
+ export { default as PageHeader } from './PageHeader.svelte';
4
+ export { default as PageFooter } from './PageFooter.svelte';
@@ -0,0 +1,257 @@
1
+ <script lang="ts">
2
+ import type { OutputChartLayoutItem } from '$lib/types/generated';
3
+ import { onMount } from 'svelte';
4
+ import { Loader, Maximize, Minimize } from '@lucide/svelte';
5
+ import { Label } from '$lib/components/ui/label';
6
+ import { loadScript } from '$lib/utils/loadScript';
7
+
8
+ interface Props {
9
+ item: OutputChartLayoutItem;
10
+ value: string;
11
+ }
12
+
13
+ let { item, value }: Props = $props();
14
+
15
+ const MAP_TYPE_SET = new Set(['scattermap', 'scattermapbox', 'choropleth', 'scattergeo']);
16
+
17
+ // ── Figure parsing ──────────────────────────────────────────────────
18
+
19
+ type PlotlyTrace = Record<string, unknown>;
20
+ type PlotlyFigure = {
21
+ data: PlotlyTrace[];
22
+ layout: Record<string, unknown>;
23
+ config?: Record<string, unknown>;
24
+ };
25
+
26
+ const figData = $derived.by(() => {
27
+ if (!value) return null;
28
+ try {
29
+ return JSON.parse(value) as PlotlyFigure;
30
+ } catch {
31
+ return null;
32
+ }
33
+ });
34
+
35
+ const figTitle = $derived.by(() => {
36
+ if (!figData) return null;
37
+ const t = figData.layout?.title;
38
+ if (!t) return null;
39
+ if (typeof t === 'string') return t;
40
+ if (typeof t === 'object' && 'text' in t) return (t as Record<string, unknown>).text as string;
41
+ return null;
42
+ });
43
+
44
+ // ── DOM refs & state ────────────────────────────────────────────────
45
+
46
+ let containerEl = $state<HTMLDivElement | null>(null);
47
+ let wrapperEl = $state<HTMLDivElement | null>(null);
48
+ let loading = $state(false);
49
+ let error = $state<string | null>(null);
50
+ let isFullscreen = $state(false);
51
+ let mounted = false;
52
+
53
+ // ── Plotly loader ──────────────────────────────────────────────────
54
+
55
+ async function loadPlotly(): Promise<any> {
56
+ // @ts-expect-error — Plotly is loaded dynamically onto window
57
+ if (window.Plotly) return window.Plotly;
58
+
59
+ await loadScript('https://cdn.plot.ly/plotly-3.4.0.min.js', { crossOrigin: 'anonymous' });
60
+ // @ts-expect-error — Plotly is loaded dynamically onto window
61
+ return window.Plotly;
62
+ }
63
+
64
+ // ── Fullscreen ──────────────────────────────────────────────────────
65
+
66
+ function toggleFullscreen() {
67
+ if (!wrapperEl) return;
68
+ if (!document.fullscreenElement) {
69
+ wrapperEl.requestFullscreen().catch((err) => {
70
+ error = `Fullscreen unavailable: ${err.message}`;
71
+ });
72
+ } else {
73
+ document.exitFullscreen().catch((err) => {
74
+ error = `Exit fullscreen failed: ${err.message}`;
75
+ });
76
+ }
77
+ }
78
+
79
+ $effect(() => {
80
+ function onFullscreenChange() {
81
+ isFullscreen = !!document.fullscreenElement;
82
+ // Resize immediately after state updates, then once more to catch layout
83
+ Promise.resolve().then(() => {
84
+ // @ts-expect-error — Plotly is loaded dynamically onto window
85
+ if (containerEl && window.Plotly) {
86
+ // @ts-expect-error — Plotly is loaded dynamically onto window
87
+ window.Plotly.Plots.resize(containerEl);
88
+ }
89
+ });
90
+ }
91
+ document.addEventListener('fullscreenchange', onFullscreenChange);
92
+ return () => document.removeEventListener('fullscreenchange', onFullscreenChange);
93
+ });
94
+
95
+ // ── Theme-aware colors ──────────────────────────────────────────────
96
+
97
+ function getThemeColors(): { textColor: string; gridColor: string } {
98
+ if (!containerEl) return { textColor: '#333', gridColor: '#eee' };
99
+ const style = getComputedStyle(containerEl);
100
+ const textColor = style.getPropertyValue('color').trim() || '#333';
101
+ const gridColor =
102
+ style.getPropertyValue('--border')?.trim() ||
103
+ style.getPropertyValue('--color-border')?.trim() ||
104
+ 'rgba(128,128,128,0.2)';
105
+ return { textColor, gridColor };
106
+ }
107
+
108
+ // ── Render ──────────────────────────────────────────────────────────
109
+
110
+ async function renderChart() {
111
+ if (!containerEl || !figData) return;
112
+ error = null;
113
+ loading = true;
114
+ try {
115
+ const Plotly = await loadPlotly();
116
+ const { textColor, gridColor } = getThemeColors();
117
+ const isMapFigure = figData.data?.some((t) => MAP_TYPE_SET.has(t.type as string));
118
+
119
+ // Strip title, template, and explicit sizing
120
+ const {
121
+ title: _title,
122
+ template: _template,
123
+ height: _height,
124
+ width: _width,
125
+ ...layoutRest
126
+ } = figData.layout as Record<string, unknown> & {
127
+ title?: unknown;
128
+ template?: unknown;
129
+ height?: unknown;
130
+ width?: unknown;
131
+ };
132
+
133
+ const layout: Record<string, unknown> = {
134
+ ...layoutRest,
135
+ autosize: true,
136
+ margin: { t: 24, r: 8, b: 40, l: 60, pad: 0 },
137
+ font: { color: textColor },
138
+ paper_bgcolor: layoutRest.paper_bgcolor ?? 'transparent',
139
+ plot_bgcolor: layoutRest.plot_bgcolor ?? 'transparent',
140
+ ...(!isMapFigure && layoutRest.xaxis
141
+ ? { xaxis: { ...(layoutRest.xaxis as object), gridcolor: gridColor, color: textColor } }
142
+ : {}),
143
+ ...(!isMapFigure && layoutRest.yaxis
144
+ ? { yaxis: { ...(layoutRest.yaxis as object), gridcolor: gridColor, color: textColor } }
145
+ : {})
146
+ };
147
+
148
+ Plotly.react(containerEl, figData.data, layout, {
149
+ responsive: true,
150
+ displayModeBar: 'hover',
151
+ displaylogo: false,
152
+ modeBarButtonsToRemove: ['sendDataToCloud', 'lasso2d', 'select2d'],
153
+ ...figData.config
154
+ });
155
+ } catch (e) {
156
+ error = e instanceof Error ? e.message : 'Failed to render chart';
157
+ } finally {
158
+ loading = false;
159
+ }
160
+ }
161
+
162
+ // ── Lifecycle ───────────────────────────────────────────────────────
163
+
164
+ onMount(() => {
165
+ mounted = true;
166
+
167
+ let resizeTimer: ReturnType<typeof setTimeout> | null = null;
168
+ const ro = new ResizeObserver(() => {
169
+ if (resizeTimer) clearTimeout(resizeTimer);
170
+ resizeTimer = setTimeout(() => {
171
+ // @ts-expect-error — Plotly is loaded dynamically onto window
172
+ if (containerEl && window.Plotly) {
173
+ // @ts-expect-error — Plotly is loaded dynamically onto window
174
+ window.Plotly.Plots.resize(containerEl);
175
+ }
176
+ resizeTimer = null;
177
+ }, 150);
178
+ });
179
+ // Observe the wrapper (parent) so we catch sidebar resizes affecting the container's available space
180
+ if (wrapperEl) ro.observe(wrapperEl);
181
+
182
+ return () => {
183
+ ro.disconnect();
184
+ if (resizeTimer) clearTimeout(resizeTimer);
185
+ // @ts-expect-error — Plotly is loaded dynamically onto window
186
+ if (containerEl && window.Plotly) window.Plotly.purge(containerEl);
187
+ };
188
+ });
189
+
190
+ // ── Debounced re-render on value change ─────────────────────────────
191
+
192
+ let renderTimeout: ReturnType<typeof setTimeout> | null = null;
193
+
194
+ $effect(() => {
195
+ if (!value || !mounted || !containerEl) return;
196
+ if (renderTimeout) clearTimeout(renderTimeout);
197
+ renderTimeout = setTimeout(() => {
198
+ renderChart();
199
+ renderTimeout = null;
200
+ }, 150);
201
+ return () => {
202
+ if (renderTimeout) clearTimeout(renderTimeout);
203
+ };
204
+ });
205
+ </script>
206
+
207
+ <div
208
+ bind:this={wrapperEl}
209
+ class="gap-0 flex flex-col overflow-hidden rounded-lg border border-border {isFullscreen
210
+ ? 'bg-background'
211
+ : ''}"
212
+ >
213
+ <!-- Header: title + controls -->
214
+ <div class="gap-2 px-3 py-1.5 relative z-10 flex items-center border-b border-border bg-muted/40">
215
+ <Label
216
+ class="text-xs font-medium truncate text-foreground"
217
+ title={figTitle ?? item.displayName ?? item.paramId}
218
+ >
219
+ {figTitle ?? item.displayName ?? item.paramId}
220
+ </Label>
221
+
222
+ <div class="gap-1 ml-auto flex items-center">
223
+ {#if loading}
224
+ <div class="text-muted-foreground">
225
+ <Loader size={12} class="animate-spin" />
226
+ </div>
227
+ {/if}
228
+
229
+ <button
230
+ onclick={toggleFullscreen}
231
+ disabled={loading}
232
+ title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}
233
+ class="rounded p-1 flex items-center text-muted-foreground transition-colors hover:bg-background/60 hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
234
+ >
235
+ {#if isFullscreen}
236
+ <Minimize size={14} />
237
+ {:else}
238
+ <Maximize size={14} />
239
+ {/if}
240
+ </button>
241
+ </div>
242
+ </div>
243
+
244
+ {#if error}
245
+ <div class="px-4 py-3 text-sm text-destructive">{error}</div>
246
+ {:else if !figData && value}
247
+ <div class="px-4 py-8 text-sm text-center text-muted-foreground">Receiving chart data...</div>
248
+ {:else if !figData}
249
+ <div class="px-4 py-8 text-sm text-center text-muted-foreground">Waiting for chart data...</div>
250
+ {:else}
251
+ <div
252
+ bind:this={containerEl}
253
+ class="w-full"
254
+ style="height: {isFullscreen ? 'calc(100vh - 36px)' : '380px'};"
255
+ ></div>
256
+ {/if}
257
+ </div>
@@ -0,0 +1,121 @@
1
+ <script lang="ts">
2
+ import type { LayoutItem, InputLayoutItem, OutputLayoutItem } from '$lib/types/generated';
3
+ import type { Snippet } from 'svelte';
4
+ import * as Card from '$lib/components/ui/card';
5
+ import { ChevronDown } from '@lucide/svelte';
6
+ import { evaluateVisibility } from '$lib/utils/visibility-rules';
7
+
8
+ interface Props {
9
+ label: string;
10
+ description?: string;
11
+ items: LayoutItem[];
12
+ columns: number;
13
+ collapsed: boolean;
14
+ values: Record<string, unknown>;
15
+ onToggle: () => void;
16
+ inputSnippet: Snippet<
17
+ [
18
+ layoutItem: InputLayoutItem,
19
+ visibility: { visible: boolean; disabled: boolean; defaultValue?: unknown }
20
+ ]
21
+ >;
22
+ outputSnippet: Snippet<[layoutItem: OutputLayoutItem]>;
23
+ }
24
+
25
+ let {
26
+ label,
27
+ description,
28
+ items,
29
+ columns,
30
+ collapsed,
31
+ values,
32
+ onToggle,
33
+ inputSnippet,
34
+ outputSnippet
35
+ }: Props = $props();
36
+
37
+ function handleKeydown(e: KeyboardEvent) {
38
+ if (e.key === 'Enter' || e.key === ' ') {
39
+ e.preventDefault();
40
+ onToggle();
41
+ }
42
+ }
43
+ </script>
44
+
45
+ <Card.Root class="gap-0 py-0 pt-0 overflow-hidden">
46
+ <Card.Header
47
+ class="pt-4 pb-4! cursor-pointer border-b border-border bg-muted transition-colors select-none hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
48
+ role="button"
49
+ tabindex={0}
50
+ aria-expanded={!collapsed}
51
+ onclick={onToggle}
52
+ onkeydown={handleKeydown}
53
+ >
54
+ <Card.Title>{label}</Card.Title>
55
+ {#if description}
56
+ <Card.Description>{description}</Card.Description>
57
+ {/if}
58
+ <Card.Action>
59
+ <ChevronDown
60
+ class="h-4 w-4 text-muted-foreground transition-transform duration-200 {collapsed
61
+ ? ''
62
+ : 'rotate-180'}"
63
+ />
64
+ </Card.Action>
65
+ </Card.Header>
66
+ <div class="content-wrapper" class:collapsed>
67
+ <div class="content-inner">
68
+ <Card.Content class="p-6">
69
+ <div class="schema-grid gap-6 grid" style="--schema-cols: {columns};">
70
+ {#each items as layoutItem (layoutItem.type === 'linebreak' ? layoutItem.id : layoutItem.paramId)}
71
+ {@render gridItem(layoutItem, columns)}
72
+ {/each}
73
+ </div>
74
+ </Card.Content>
75
+ </div>
76
+ </div>
77
+ </Card.Root>
78
+
79
+ {#snippet gridItem(layoutItem: LayoutItem, cols: number)}
80
+ {#if layoutItem.type === 'linebreak'}
81
+ <div style="grid-column: 1 / -1" class="h-px bg-border" aria-hidden="true"></div>
82
+ {:else}
83
+ {@const visibility = evaluateVisibility(layoutItem, values)}
84
+ {@const span = Math.min(Math.max(1, layoutItem.span ?? 1), cols)}
85
+ {#if visibility.visible}
86
+ {#if layoutItem.type === 'input'}
87
+ <div
88
+ class="min-w-0 flex items-center"
89
+ class:opacity-50={visibility.disabled}
90
+ style="grid-column: span {span} / span {span}"
91
+ >
92
+ {@render inputSnippet(layoutItem, visibility)}
93
+ </div>
94
+ {:else if layoutItem.type === 'output'}
95
+ <div style="grid-column: span {span} / span {span}">
96
+ {@render outputSnippet(layoutItem)}
97
+ </div>
98
+ {/if}
99
+ {/if}
100
+ {/if}
101
+ {/snippet}
102
+
103
+ <style>
104
+ .content-wrapper {
105
+ display: grid;
106
+ grid-template-rows: 1fr;
107
+ transition: grid-template-rows 0.3s cubic-bezier(0.4, 0, 0.2, 1);
108
+ }
109
+
110
+ .content-wrapper.collapsed {
111
+ grid-template-rows: 0fr;
112
+ }
113
+
114
+ .content-inner {
115
+ min-height: 0;
116
+ }
117
+
118
+ .schema-grid {
119
+ grid-template-columns: repeat(var(--schema-cols), minmax(0, 1fr));
120
+ }
121
+ </style>