@morscherlab/mint-sdk 1.4.0-beta.2 → 1.4.0-beta.20

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 (330) hide show
  1. package/README.md +14 -3
  2. package/dist/{ActionMenu-CScINahU.js → AlertBox-CzLg0UaL.js} +40 -209
  3. package/dist/AlertBox-CzLg0UaL.js.map +1 -0
  4. package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-6oTT-gPO.js} +1249 -239
  5. package/dist/AppSidebar-6oTT-gPO.js.map +1 -0
  6. package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-CSls2Nuv.js} +2 -2
  7. package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-CSls2Nuv.js.map} +1 -1
  8. package/dist/ExperimentPopover-9l4QZlvQ.js +337 -0
  9. package/dist/ExperimentPopover-9l4QZlvQ.js.map +1 -0
  10. package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-pR5fK3pA.js} +244 -211
  11. package/dist/ExperimentSelectorModal-pR5fK3pA.js.map +1 -0
  12. package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-CJ7EAmOq.js} +2 -2
  13. package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-CJ7EAmOq.js.map} +1 -1
  14. package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-Dyitgzfp.js} +28 -27
  15. package/dist/SettingsModal-Dyitgzfp.js.map +1 -0
  16. package/dist/__stories__/experiment-helpers.d.ts +10 -0
  17. package/dist/__tests__/components/AppTopBarOnboarding.test.d.ts +1 -0
  18. package/dist/__tests__/composables/useOnboarding.test.d.ts +1 -0
  19. package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
  20. package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
  21. package/dist/components/AppSidebar.vue.d.ts +1 -1
  22. package/dist/components/AppTopBar.vue.d.ts +20 -5
  23. package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
  24. package/dist/components/AuditTrail.vue.d.ts +1 -1
  25. package/dist/components/BaseButton.vue.d.ts +4 -2
  26. package/dist/components/BaseSelect.vue.d.ts +2 -2
  27. package/dist/components/ChartContainer.vue.d.ts +2 -0
  28. package/dist/components/DatePicker.vue.d.ts +1 -1
  29. package/dist/components/ExperimentPopover.vue.d.ts +18 -0
  30. package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -5
  31. package/dist/components/FilePicker.vue.d.ts +1 -1
  32. package/dist/components/FileUploader.vue.d.ts +2 -2
  33. package/dist/components/JobsStatusTray.vue.d.ts +15 -4
  34. package/dist/components/PluginIcon.vue.d.ts +2 -2
  35. package/dist/components/PluginWorkspaceView.props.d.ts +3 -0
  36. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -0
  37. package/dist/components/SampleSelector.vue.d.ts +6 -6
  38. package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
  39. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -1
  40. package/dist/components/StepWizard.vue.d.ts +3 -0
  41. package/dist/components/internal/AppTopBarOnboardingInternal.vue.d.ts +7 -0
  42. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
  43. package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +1 -1
  44. package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
  45. package/dist/components/internal/OnboardingLayerInternal.vue.d.ts +7 -0
  46. package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
  47. package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -0
  48. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +8 -0
  49. package/dist/composables/createClient.d.ts +2 -0
  50. package/dist/composables/index.d.ts +1 -0
  51. package/dist/composables/pluginIdentity.d.ts +24 -0
  52. package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
  53. package/dist/composables/useAppExperiment.d.ts +8 -0
  54. package/dist/composables/useCalendarGrid.d.ts +1 -1
  55. package/dist/composables/useExperimentSelector.d.ts +6 -2
  56. package/dist/composables/useJobCenter.d.ts +41 -3
  57. package/dist/composables/useOnboarding.d.ts +119 -0
  58. package/dist/composables/usePlatform.d.ts +1 -0
  59. package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-DCUOx8ll.js} +2 -2
  60. package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-DCUOx8ll.js.map} +1 -1
  61. package/dist/{data-C2PwI_dn.js → data-DBnmeBZX.js} +179 -125
  62. package/dist/data-DBnmeBZX.js.map +1 -0
  63. package/dist/data.js +8 -8
  64. package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
  65. package/dist/experiment-DyO54FQB.js.map +1 -0
  66. package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-BFrKpHAH.js} +3 -3
  67. package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-BFrKpHAH.js.map} +1 -1
  68. package/dist/index.js +20 -20
  69. package/dist/{install-DAID6c2-.js → install-qjELyNwc.js} +15 -14
  70. package/dist/{install-DAID6c2-.js.map → install-qjELyNwc.js.map} +1 -1
  71. package/dist/install.js +1 -1
  72. package/dist/{lab-DLwRl_Ql.js → lab-UyTbokQC.js} +136 -148
  73. package/dist/lab-UyTbokQC.js.map +1 -0
  74. package/dist/lab.js +4 -3
  75. package/dist/{records-BzTcxekG.js → records-CR_pYzIP.js} +533 -335
  76. package/dist/records-CR_pYzIP.js.map +1 -0
  77. package/dist/{runtime-D6gVat6r.js → runtime-CoHhBP10.js} +417 -54
  78. package/dist/runtime-CoHhBP10.js.map +1 -0
  79. package/dist/runtime.d.ts +1 -1
  80. package/dist/runtime.js +7 -7
  81. package/dist/{shell-5ju97nOS.js → shell-BDuZf2zb.js} +10 -5
  82. package/dist/{shell-5ju97nOS.js.map → shell-BDuZf2zb.js.map} +1 -1
  83. package/dist/shell.d.ts +1 -0
  84. package/dist/shell.js +6 -6
  85. package/dist/stores/index.d.ts +1 -1
  86. package/dist/stores/index.js +2 -2
  87. package/dist/stores/settings.d.ts +4 -12
  88. package/dist/styles.css +2732 -2083
  89. package/dist/types/componentWorkflowTypes.d.ts +2 -0
  90. package/dist/types/components.d.ts +2 -0
  91. package/dist/types/generated/platformContext.d.ts +1 -0
  92. package/dist/types/generated-ui.d.ts +4 -0
  93. package/dist/types/index.d.ts +1 -1
  94. package/dist/types/jobs.d.ts +9 -0
  95. package/dist/types/platform.d.ts +1 -1
  96. package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-Bb2N4m40.js} +74 -4
  97. package/dist/useDropdownState-Bb2N4m40.js.map +1 -0
  98. package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-Dno1fFMq.js} +4 -4
  99. package/dist/{useExperimentSamples-CxcnxZ8h.js.map → useExperimentSamples-Dno1fFMq.js.map} +1 -1
  100. package/dist/{useListReorder-CcbEYxX-.js → useListReorder-CQ9OCScc.js} +183 -351
  101. package/dist/useListReorder-CQ9OCScc.js.map +1 -0
  102. package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-wL3kPrRT.js} +73 -59
  103. package/dist/useRackEditor-wL3kPrRT.js.map +1 -0
  104. package/dist/useRealtime-C3whhVvb.js +508 -0
  105. package/dist/useRealtime-C3whhVvb.js.map +1 -0
  106. package/dist/useRequest-CDkrXNU7.js +244 -0
  107. package/dist/useRequest-CDkrXNU7.js.map +1 -0
  108. package/dist/utils/time.d.ts +7 -0
  109. package/package.json +1 -1
  110. package/src/__stories__/experiment-helpers.ts +3 -3
  111. package/src/__tests__/components/AppTopBar.test.ts +257 -3
  112. package/src/__tests__/components/AppTopBarOnboarding.test.ts +160 -0
  113. package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
  114. package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
  115. package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -0
  116. package/src/__tests__/components/BaseButton.test.ts +19 -0
  117. package/src/__tests__/components/BaseSelect.multiple.test.ts +87 -32
  118. package/src/__tests__/components/BaseSelect.test.ts +2 -1
  119. package/src/__tests__/components/BatchProgressList.test.ts +16 -0
  120. package/src/__tests__/components/CalendarGridPanel.test.ts +2 -2
  121. package/src/__tests__/components/ChartContainer.test.ts +11 -0
  122. package/src/__tests__/components/ChemicalFormula.test.ts +6 -3
  123. package/src/__tests__/components/DatePicker.datetime.test.ts +6 -0
  124. package/src/__tests__/components/DatePicker.test.ts +21 -0
  125. package/src/__tests__/components/DatePicker.time.test.ts +2 -2
  126. package/src/__tests__/components/EmptyState.test.ts +1 -1
  127. package/src/__tests__/components/ExperimentPopover.test.ts +125 -16
  128. package/src/__tests__/components/ExperimentSelectorModal.test.ts +153 -14
  129. package/src/__tests__/components/GeneratedPluginView.test.ts +23 -2
  130. package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
  131. package/src/__tests__/components/JobsStatusTray.test.ts +373 -71
  132. package/src/__tests__/components/PluginWorkspaceView.test.ts +63 -1
  133. package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
  134. package/src/__tests__/components/SampleSelector.test.ts +33 -8
  135. package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
  136. package/src/__tests__/components/SettingsModal.test.ts +9 -2
  137. package/src/__tests__/components/StepWizard.test.ts +11 -0
  138. package/src/__tests__/components/WellPlate.decoration.test.ts +11 -4
  139. package/src/__tests__/components/deprecationTags.test.ts +1 -1
  140. package/src/__tests__/composables/useAppExperiment.test.ts +27 -1
  141. package/src/__tests__/composables/useCalendarGrid.test.ts +4 -2
  142. package/src/__tests__/composables/useExperimentSelector.test.ts +111 -0
  143. package/src/__tests__/composables/useJobCenter.test.ts +262 -3
  144. package/src/__tests__/composables/useOnboarding.test.ts +317 -0
  145. package/src/__tests__/docs/frontendDocsCatalog.test.ts +4 -3
  146. package/src/__tests__/stores/settings.test.ts +21 -21
  147. package/src/__tests__/styles/baseControlsRules.test.ts +6 -2
  148. package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
  149. package/src/__tests__/styles/cssTokens.test.ts +6 -3
  150. package/src/__tests__/styles/menusShellRefresh.test.ts +22 -12
  151. package/src/__tests__/styles/paletteTokens.test.ts +44 -0
  152. package/src/__tests__/styles/v2AuditRules.test.ts +104 -0
  153. package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
  154. package/src/__tests__/utils/time.test.ts +18 -1
  155. package/src/components/AdductText.story.vue +7 -0
  156. package/src/components/AdductText.vue +1 -1
  157. package/src/components/AlertBox.story.vue +2 -2
  158. package/src/components/AlertBox.vue +18 -16
  159. package/src/components/AppSidebar.story.vue +0 -28
  160. package/src/components/AppTopBar.onboarding.story.vue +69 -0
  161. package/src/components/AppTopBar.story.vue +105 -15
  162. package/src/components/AppTopBar.vue +248 -122
  163. package/src/components/ArtifactSaveDialog.story.vue +23 -0
  164. package/src/components/ArtifactSaveDialog.vue +102 -12
  165. package/src/components/AuditTrail.story.vue +2 -1
  166. package/src/components/AuditTrail.vue +2 -21
  167. package/src/components/Avatar.vue +10 -14
  168. package/src/components/BaseButton.vue +16 -2
  169. package/src/components/BaseSelect.multiple.story.vue +13 -2
  170. package/src/components/BaseSelect.vue +4 -3
  171. package/src/components/BatchProgressList.vue +35 -25
  172. package/src/components/ChartContainer.story.vue +2 -1
  173. package/src/components/ChartContainer.vue +8 -6
  174. package/src/components/ConfirmDialog.story.vue +1 -1
  175. package/src/components/EmptyState.vue +1 -1
  176. package/src/components/ExperimentPopover.story.vue +165 -53
  177. package/src/components/ExperimentPopover.vue +169 -187
  178. package/src/components/ExperimentSelectorModal.story.vue +73 -31
  179. package/src/components/ExperimentSelectorModal.vue +144 -111
  180. package/src/components/FormField.story.vue +8 -48
  181. package/src/components/GeneratedPluginView.vue +11 -10
  182. package/src/components/GeneratedResultRenderer.vue +3 -4
  183. package/src/components/InstrumentStateBadge.vue +1 -1
  184. package/src/components/JobsStatusTray.story.vue +97 -43
  185. package/src/components/JobsStatusTray.vue +287 -290
  186. package/src/components/LayoutResizeHandle.story.vue +65 -4
  187. package/src/components/LoadingSpinner.vue +1 -1
  188. package/src/components/NumberInput.vue +3 -6
  189. package/src/components/PluginIcon.story.vue +2 -10
  190. package/src/components/PluginIcon.vue +2 -2
  191. package/src/components/PluginWorkspaceView.props.ts +3 -0
  192. package/src/components/PluginWorkspaceView.story.vue +1 -1
  193. package/src/components/PluginWorkspaceView.vue +17 -0
  194. package/src/components/RuntimeUpdateNotice.vue +1 -1
  195. package/src/components/SampleSelector.story.vue +22 -7
  196. package/src/components/SampleSelector.vue +34 -37
  197. package/src/components/SampleSelectorGroupNode.vue +1 -1
  198. package/src/components/SectionCard.story.vue +35 -2
  199. package/src/components/SequenceProgressBar.story.vue +9 -0
  200. package/src/components/SequenceProgressBar.vue +6 -1
  201. package/src/components/SettingsModal.schema.ts +1 -1
  202. package/src/components/SettingsModal.vue +9 -14
  203. package/src/components/SmartGroupFieldRecipe.story.vue +1 -1
  204. package/src/components/SmartGroupManual.story.vue +1 -1
  205. package/src/components/StepWizard.story.vue +33 -0
  206. package/src/components/StepWizard.vue +8 -1
  207. package/src/components/WellPlate.story.vue +3 -1
  208. package/src/components/WellPlate.vue +7 -0
  209. package/src/components/internal/AppTopBarOnboardingInternal.vue +172 -0
  210. package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
  211. package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
  212. package/src/components/internal/DatePickerDateInternal.vue +16 -40
  213. package/src/components/internal/DatePickerDateTimeInternal.vue +3 -13
  214. package/src/components/internal/DatePickerTimeInternal.vue +5 -8
  215. package/src/components/internal/OnboardingLayerInternal.vue +173 -0
  216. package/src/components/internal/ResourcePickerListInternal.vue +45 -85
  217. package/src/components/internal/SelectMultipleInternal.vue +182 -65
  218. package/src/components/internal/SelectSearchableInternal.vue +2 -3
  219. package/src/components/internal/WorkspaceShellInternal.vue +12 -0
  220. package/src/composables/createClient.ts +2 -0
  221. package/src/composables/index.ts +1 -0
  222. package/src/composables/pluginIdentity.ts +31 -0
  223. package/src/composables/pluginWorkspaceModel.ts +2 -2
  224. package/src/composables/useAppExperiment.ts +20 -0
  225. package/src/composables/useCalendarGrid.ts +4 -3
  226. package/src/composables/useExperimentSelector.ts +77 -31
  227. package/src/composables/useJobCenter.ts +188 -6
  228. package/src/composables/useOnboarding.ts +465 -0
  229. package/src/composables/usePluginWorkspace.ts +1 -1
  230. package/src/runtime.ts +2 -1
  231. package/src/shell.ts +17 -0
  232. package/src/stores/index.ts +0 -2
  233. package/src/stores/settings.ts +20 -50
  234. package/src/styles/components/adduct-text.css +13 -5
  235. package/src/styles/components/alert-box.css +39 -58
  236. package/src/styles/components/app-layout.css +7 -5
  237. package/src/styles/components/app-page-selector.css +121 -44
  238. package/src/styles/components/app-pill-nav.css +11 -12
  239. package/src/styles/components/app-sidebar.css +9 -18
  240. package/src/styles/components/app-top-bar.css +219 -55
  241. package/src/styles/components/artifact-save-dialog.css +153 -2
  242. package/src/styles/components/audit-trail.css +16 -19
  243. package/src/styles/components/avatar.css +6 -4
  244. package/src/styles/components/batch-progress-list.css +38 -36
  245. package/src/styles/components/button.css +36 -59
  246. package/src/styles/components/calendar.css +12 -12
  247. package/src/styles/components/chart-container.css +34 -23
  248. package/src/styles/components/checkbox.css +2 -12
  249. package/src/styles/components/collapsible-card.css +27 -29
  250. package/src/styles/components/confirm-dialog.css +13 -14
  251. package/src/styles/components/dataframe.css +13 -5
  252. package/src/styles/components/date-picker.css +80 -92
  253. package/src/styles/components/datetime-picker.css +31 -43
  254. package/src/styles/components/divider.css +20 -20
  255. package/src/styles/components/dose-calculator.css +3 -3
  256. package/src/styles/components/empty-state.css +20 -17
  257. package/src/styles/components/experiment-code-badge.css +2 -0
  258. package/src/styles/components/experiment-popover.css +174 -329
  259. package/src/styles/components/experiment-selector-modal.css +88 -56
  260. package/src/styles/components/file-picker.css +3 -3
  261. package/src/styles/components/file-uploader.css +38 -49
  262. package/src/styles/components/form-builder.css +3 -3
  263. package/src/styles/components/formula-input.css +1 -1
  264. package/src/styles/components/icon-button.css +18 -24
  265. package/src/styles/components/input.css +5 -4
  266. package/src/styles/components/instrument-monitor.css +13 -15
  267. package/src/styles/components/jobs-status-tray.css +140 -296
  268. package/src/styles/components/layout-resize-handle.css +59 -16
  269. package/src/styles/components/modal.css +4 -6
  270. package/src/styles/components/molecule-input.css +2 -2
  271. package/src/styles/components/multi-select.css +65 -117
  272. package/src/styles/components/number-input.css +26 -19
  273. package/src/styles/components/onboarding.css +368 -0
  274. package/src/styles/components/pill.css +3 -2
  275. package/src/styles/components/plate-editor.css +0 -1
  276. package/src/styles/components/plugin-icon.css +26 -23
  277. package/src/styles/components/popover.css +2 -2
  278. package/src/styles/components/presence-avatars.css +1 -1
  279. package/src/styles/components/progress-bar.css +3 -3
  280. package/src/styles/components/protocol-step-editor.css +1 -3
  281. package/src/styles/components/resource-card.css +2 -2
  282. package/src/styles/components/resource-picker-list.css +6 -57
  283. package/src/styles/components/sample-hierarchy-tree.css +4 -4
  284. package/src/styles/components/sample-selector.css +138 -79
  285. package/src/styles/components/schedule-calendar.css +8 -8
  286. package/src/styles/components/searchable-select.css +12 -12
  287. package/src/styles/components/section-card.css +54 -49
  288. package/src/styles/components/segmented-control.css +18 -15
  289. package/src/styles/components/select.css +3 -3
  290. package/src/styles/components/sequence-input.css +2 -2
  291. package/src/styles/components/sequence-progress-bar.css +17 -8
  292. package/src/styles/components/settings-modal.css +7 -2
  293. package/src/styles/components/smart-group.css +18 -18
  294. package/src/styles/components/step-wizard.css +52 -16
  295. package/src/styles/components/tabs.css +2 -2
  296. package/src/styles/components/textarea.css +3 -3
  297. package/src/styles/components/time-picker.css +36 -21
  298. package/src/styles/components/toast.css +12 -10
  299. package/src/styles/components/toggle.css +1 -11
  300. package/src/styles/components/tooltip.css +10 -9
  301. package/src/styles/components/unit-input.css +8 -7
  302. package/src/styles/components/well-plate.css +9 -2
  303. package/src/styles/index.css +1 -0
  304. package/src/styles/variables.css +241 -78
  305. package/src/types/componentWorkflowTypes.ts +2 -0
  306. package/src/types/components.ts +2 -0
  307. package/src/types/generated/platformContext.ts +1 -0
  308. package/src/types/generated-ui.ts +4 -0
  309. package/src/types/index.ts +1 -0
  310. package/src/types/jobs.ts +10 -0
  311. package/src/types/platform.ts +1 -1
  312. package/src/utils/time.ts +21 -0
  313. package/dist/ActionMenu-CScINahU.js.map +0 -1
  314. package/dist/AppSidebar-BmiiPfz9.js.map +0 -1
  315. package/dist/BaseModal-DfRIuVoj.js.map +0 -1
  316. package/dist/ExperimentPopover-C4sGw-is.js +0 -359
  317. package/dist/ExperimentPopover-C4sGw-is.js.map +0 -1
  318. package/dist/ExperimentSelectorModal-D-9z7cNx.js.map +0 -1
  319. package/dist/SettingsModal-CSLE31yg.js.map +0 -1
  320. package/dist/data-C2PwI_dn.js.map +0 -1
  321. package/dist/experiment-43OJtH7R.js.map +0 -1
  322. package/dist/lab-DLwRl_Ql.js.map +0 -1
  323. package/dist/records-BzTcxekG.js.map +0 -1
  324. package/dist/runtime-D6gVat6r.js.map +0 -1
  325. package/dist/useListReorder-CcbEYxX-.js.map +0 -1
  326. package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
  327. package/dist/useRealtime-PalKue84.js +0 -696
  328. package/dist/useRealtime-PalKue84.js.map +0 -1
  329. package/dist/useRequest-D5JDfsgZ.js +0 -76
  330. package/dist/useRequest-D5JDfsgZ.js.map +0 -1
@@ -0,0 +1,465 @@
1
+ import {
2
+ computed,
3
+ inject,
4
+ onScopeDispose,
5
+ provide,
6
+ ref,
7
+ shallowRef,
8
+ toValue,
9
+ watch,
10
+ type ComputedRef,
11
+ type InjectionKey,
12
+ type MaybeRefOrGetter,
13
+ type ShallowRef,
14
+ } from 'vue'
15
+ import type { Placement } from '@floating-ui/dom'
16
+ import { usePlatform } from './usePlatform'
17
+
18
+ /** One card of a tour. It points at the element with `data-onboarding="<anchor>"`. */
19
+ export interface OnboardingStep {
20
+ /** Stable id. A returning user sees only steps whose id is new. */
21
+ id: string
22
+ /** `data-onboarding` value of the element the step points at. */
23
+ anchor: string
24
+ title: string
25
+ body: string
26
+ /** Side of the anchor for the card. Default `bottom`. */
27
+ placement?: Placement
28
+ /** `'click'`: the highlighted element takes clicks, and a click moves the tour to the next step. */
29
+ advanceOn?: 'click'
30
+ /** Leave the step out while this returns false, e.g. without the permission its control needs. */
31
+ available?: () => boolean
32
+ }
33
+
34
+ export interface OnboardingTour {
35
+ id: string
36
+ /** Name in the Help menu. */
37
+ title: string
38
+ /** Start only while the app's route is this value. Omit it for elements on every page, such as the top bar. */
39
+ route?: string
40
+ steps: OnboardingStep[]
41
+ }
42
+
43
+ export interface OnboardingTask {
44
+ id: string
45
+ title: string
46
+ /** Leave the task out while this returns false, e.g. without the permission it needs. */
47
+ available?: () => boolean
48
+ /** The task is done when this returns true. The coordinator checks it at start, on a route change and when the Help menu opens. */
49
+ done?: () => boolean
50
+ /** The link at the end of the task row. */
51
+ action?: { label: string; run: () => void }
52
+ }
53
+
54
+ /** A new feature. A dot marks its element until the user opens it. */
55
+ export interface OnboardingNews {
56
+ id: string
57
+ anchor: string
58
+ title: string
59
+ body: string
60
+ placement?: Placement
61
+ }
62
+
63
+ export interface OnboardingDefinition {
64
+ tours?: OnboardingTour[]
65
+ /** The "Getting started" checklist. */
66
+ checklist?: OnboardingTask[]
67
+ whatsNew?: OnboardingNews[]
68
+ }
69
+
70
+ export interface ProvideOnboardingOptions {
71
+ /** Storage namespace, e.g. `platform` or the plugin name. */
72
+ appId: string
73
+ /** The signed-in user. `null` turns onboarding off (no user yet). Default: the platform user; `local` standalone or with auth off. */
74
+ userId?: MaybeRefOrGetter<string | number | null | undefined>
75
+ /** The current route, matched against `OnboardingTour.route`. */
76
+ route?: MaybeRefOrGetter<string | null | undefined>
77
+ /** Start unseen tours on their own. Default `true`. */
78
+ autoStart?: boolean
79
+ }
80
+
81
+ /** The step on screen and the element it points at. */
82
+ export interface OnboardingActiveStep {
83
+ step: OnboardingStep
84
+ element: HTMLElement
85
+ /** Position among the steps of this run, and their count. */
86
+ index: number
87
+ count: number
88
+ /** A what's-new card, not a tour step. */
89
+ news: boolean
90
+ }
91
+
92
+ export interface OnboardingState {
93
+ definition: OnboardingDefinition
94
+ /** False until a user is known. */
95
+ enabled: ComputedRef<boolean>
96
+ active: ShallowRef<OnboardingActiveStep | null>
97
+ /** Tours that can run on the current route. */
98
+ tours: ComputedRef<OnboardingTour[]>
99
+ /** The available tasks. */
100
+ tasks: ComputedRef<Array<Omit<OnboardingTask, 'done'> & { done: boolean }>>
101
+ tasksDone: ComputedRef<number>
102
+ /** The checklist chip shows while a task is open and the user did not hide it. */
103
+ checklistVisible: ComputedRef<boolean>
104
+ checklistHidden: ComputedRef<boolean>
105
+ news: ComputedRef<Array<OnboardingNews & { unseen: boolean }>>
106
+ unseenNews: ComputedRef<number>
107
+ startTour: (id: string) => void
108
+ showNews: (id: string) => void
109
+ next: () => void
110
+ back: () => void
111
+ /** End the run (× or Esc). Every step of the tour counts as seen. */
112
+ dismiss: () => void
113
+ complete: (taskId: string) => void
114
+ setChecklistHidden: (hidden: boolean) => void
115
+ /** Run the task predicates again. */
116
+ refresh: () => void
117
+ }
118
+
119
+ export const ONBOARDING_KEY: InjectionKey<OnboardingState> = Symbol('mint-onboarding')
120
+
121
+ /** Wait this long for the missing anchor of a run's first step, or of the step after a click step; then skip it. */
122
+ export const ANCHOR_WAIT_MS = 2000
123
+
124
+ const HIDE_CHECKLIST = 'hide:checklist'
125
+ const stepKey = (tour: OnboardingTour, step: OnboardingStep) => `step:${tour.id}/${step.id}`
126
+ const anchorSelector = (anchor: string) => `[data-onboarding="${CSS.escape(anchor)}"]`
127
+
128
+ /** Types a definition, so it can live in its own file. */
129
+ export function defineOnboarding(definition: OnboardingDefinition): OnboardingDefinition {
130
+ return definition
131
+ }
132
+
133
+ function readSeen(key: string): string[] | null {
134
+ try {
135
+ const raw = globalThis.localStorage?.getItem(key)
136
+ const parsed: unknown = raw ? JSON.parse(raw) : null
137
+ return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : null
138
+ } catch {
139
+ return null
140
+ }
141
+ }
142
+
143
+ function writeSeen(key: string, seen: Set<string>) {
144
+ try {
145
+ globalThis.localStorage?.setItem(key, JSON.stringify([...seen]))
146
+ } catch {
147
+ // Private windows and full storage: the state lasts until reload.
148
+ }
149
+ }
150
+
151
+ /** Resolves with the element once it is in the document, or null after `timeout` or when `signal` aborts. */
152
+ function waitForElement(selector: string, timeout: number, signal: AbortSignal): Promise<HTMLElement | null> {
153
+ const found = document.querySelector<HTMLElement>(selector)
154
+ if (found) return Promise.resolve(found)
155
+ return new Promise((resolve) => {
156
+ const observer = new MutationObserver(() => {
157
+ const element = document.querySelector<HTMLElement>(selector)
158
+ if (element) finish(element)
159
+ })
160
+ const timer = setTimeout(() => finish(null), timeout)
161
+ const onAbort = () => finish(null)
162
+ function finish(element: HTMLElement | null) {
163
+ observer.disconnect()
164
+ clearTimeout(timer)
165
+ signal.removeEventListener('abort', onAbort)
166
+ resolve(element)
167
+ }
168
+ signal.addEventListener('abort', onAbort)
169
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-onboarding'] })
170
+ })
171
+ }
172
+
173
+ // Any open modal except the tour card itself.
174
+ const MODAL_SELECTOR = '[aria-modal="true"]:not(.mint-onboarding__card)'
175
+
176
+ /** Resolves true once no modal is open, or false when `signal` aborts first. */
177
+ function waitForNoModal(signal: AbortSignal): Promise<boolean> {
178
+ if (!document.querySelector(MODAL_SELECTOR)) return Promise.resolve(true)
179
+ return new Promise((resolve) => {
180
+ const observer = new MutationObserver(() => {
181
+ if (!document.querySelector(MODAL_SELECTOR)) finish(true)
182
+ })
183
+ const onAbort = () => finish(false)
184
+ function finish(closed: boolean) {
185
+ observer.disconnect()
186
+ signal.removeEventListener('abort', onAbort)
187
+ resolve(closed)
188
+ }
189
+ signal.addEventListener('abort', onAbort)
190
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['aria-modal'] })
191
+ })
192
+ }
193
+
194
+ /**
195
+ * Creates the app's onboarding coordinator and provides it to `AppTopBar`, which then
196
+ * shows the Help button, the checklist chip and the tour layer. Call it once, in the
197
+ * root component. It shows one item at a time and waits for open modals.
198
+ *
199
+ * ```ts
200
+ * provideOnboarding(onboarding, { appId: 'leaf' })
201
+ * ```
202
+ */
203
+ export function provideOnboarding(definition: OnboardingDefinition, options: ProvideOnboardingOptions): OnboardingState {
204
+ const { user, isAdmin } = usePlatform()
205
+ const userId = computed(() => {
206
+ // With no user, isAdmin is true only standalone or with auth off.
207
+ const fallback = isAdmin.value ? 'local' : null
208
+ const value = options.userId === undefined ? (user.value?.id ?? fallback) : toValue(options.userId)
209
+ return value == null ? null : String(value)
210
+ })
211
+ const route = computed(() => toValue(options.route) ?? undefined)
212
+ const storageKey = computed(() => userId.value === null ? null : `mint.onboarding.${options.appId}.${userId.value}`)
213
+ const enabled = computed(() => storageKey.value !== null)
214
+
215
+ const seen = ref(new Set<string>())
216
+ // Bumped by refresh(): the predicates read app state that Vue may not track.
217
+ const tick = ref(0)
218
+ const active = shallowRef<OnboardingActiveStep | null>(null)
219
+ let run: { tour: OnboardingTour | null; steps: OnboardingStep[]; index: number; shown: Set<number> } | null = null
220
+ let runId = 0
221
+ let stepWait: AbortController | undefined
222
+ let detachClick: (() => void) | undefined
223
+
224
+ /** Applies `update` to the stored state merged with this tab's, so tabs do not drop each other's keys. */
225
+ function persist(update: (keys: Set<string>) => void) {
226
+ const key = storageKey.value
227
+ if (!key) return
228
+ const merged = new Set([...(readSeen(key) ?? []), ...seen.value])
229
+ update(merged)
230
+ seen.value = merged
231
+ writeSeen(key, merged)
232
+ }
233
+
234
+ function markSeen(...keys: string[]) {
235
+ if (keys.every((key) => seen.value.has(key))) return
236
+ persist((set) => keys.forEach((key) => set.add(key)))
237
+ }
238
+
239
+ // Another tab changed the state.
240
+ function onStorage(event: StorageEvent) {
241
+ if (event.key && event.key === storageKey.value) seen.value = new Set(readSeen(event.key) ?? [])
242
+ }
243
+ window.addEventListener('storage', onStorage)
244
+
245
+ watch(storageKey, (key) => {
246
+ stop()
247
+ if (!key) {
248
+ seen.value = new Set()
249
+ return
250
+ }
251
+ const stored = readSeen(key)
252
+ seen.value = new Set(stored ?? [])
253
+ // First run: the tours introduce today's features, so today's news counts as seen.
254
+ if (stored === null) {
255
+ for (const item of definition.whatsNew ?? []) seen.value.add(`news:${item.id}`)
256
+ writeSeen(key, seen.value)
257
+ }
258
+ }, { immediate: true })
259
+
260
+ const tours = computed(() => (definition.tours ?? []).filter((tour) => !tour.route || tour.route === route.value))
261
+
262
+ const tasks = computed(() => {
263
+ void tick.value
264
+ return (definition.checklist ?? []).filter((task) => task.available?.() ?? true).map((task) => ({
265
+ ...task,
266
+ done: seen.value.has(`task:${task.id}`) || !!task.done?.(),
267
+ }))
268
+ })
269
+ // Done stays done, also when a predicate later returns false.
270
+ watch(tasks, (list) => markSeen(...list.filter((task) => task.done).map((task) => `task:${task.id}`)), { immediate: true })
271
+ const tasksDone = computed(() => tasks.value.filter((task) => task.done).length)
272
+ const checklistHidden = computed(() => seen.value.has(HIDE_CHECKLIST))
273
+ const checklistVisible = computed(() =>
274
+ enabled.value && tasks.value.length > 0 && tasksDone.value < tasks.value.length && !checklistHidden.value)
275
+
276
+ const news = computed(() => (definition.whatsNew ?? []).map((item) => ({ ...item, unseen: !seen.value.has(`news:${item.id}`) })))
277
+ const unseenNews = computed(() => enabled.value ? news.value.filter((item) => item.unseen).length : 0)
278
+
279
+ function stop() {
280
+ runId += 1
281
+ stepWait?.abort()
282
+ run = null
283
+ detachClick?.()
284
+ detachClick = undefined
285
+ active.value = null
286
+ }
287
+
288
+ /**
289
+ * Shows the first step at or after `from` whose anchor is there. Only the first step of
290
+ * the run and the step after a click step wait for theirs (the page or a menu can still
291
+ * be opening); after Next a missing anchor is skipped at once. Skipped steps stay unseen.
292
+ */
293
+ /**
294
+ * The later steps the page can still show: the anchor is on the page now, or
295
+ * a click step that can show opens it. The count grows if an anchor renders later.
296
+ */
297
+ function laterSteps(steps: OnboardingStep[], from: number) {
298
+ let count = 0
299
+ let previous = true
300
+ for (let at = from + 1; at < steps.length; at += 1) {
301
+ previous = (previous && steps[at - 1].advanceOn === 'click') || !!document.querySelector(anchorSelector(steps[at].anchor))
302
+ if (previous) count += 1
303
+ }
304
+ return count
305
+ }
306
+
307
+ async function showFrom(from: number) {
308
+ if (!run) return
309
+ const id = ++runId
310
+ stepWait?.abort()
311
+ const wait = new AbortController()
312
+ stepWait = wait
313
+ detachClick?.()
314
+ detachClick = undefined
315
+ const waitFirst = from === 0 || run.steps[from - 1].advanceOn === 'click'
316
+ for (let index = from; index < run.steps.length; index += 1) {
317
+ const step = run.steps[index]
318
+ const timeout = index === from && waitFirst ? ANCHOR_WAIT_MS : 0
319
+ const element = await waitForElement(anchorSelector(step.anchor), timeout, wait.signal)
320
+ if (id !== runId) return
321
+ if (!element) {
322
+ // Debug level: a missing anchor is normal, e.g. an admin-only button for a member.
323
+ console.debug(`[mint-onboarding] No element with data-onboarding="${step.anchor}"; step "${step.id}" skipped.`)
324
+ continue
325
+ }
326
+ run.index = index
327
+ markSeen(run.tour ? stepKey(run.tour, step) : `news:${step.id}`)
328
+ if (step.advanceOn === 'click') {
329
+ const onClick = () => next()
330
+ element.addEventListener('click', onClick)
331
+ detachClick = () => element.removeEventListener('click', onClick)
332
+ }
333
+ run.shown.add(index)
334
+ // Earlier steps count as the later ones do: shown, and still on the page.
335
+ const steps = run.steps
336
+ const position = [...run.shown].filter((at) => at < index && !!document.querySelector(anchorSelector(steps[at].anchor))).length
337
+ active.value = { step, element, index: position, count: position + 1 + laterSteps(run.steps, index), news: !run.tour }
338
+ return
339
+ }
340
+ // A finished tour hands over to the next one; × does not (dismiss stops the run first).
341
+ const finished = !!run.tour
342
+ stop()
343
+ if (finished && options.autoStart !== false) void autoStart()
344
+ }
345
+
346
+ function begin(tour: OnboardingTour | null, steps: OnboardingStep[]) {
347
+ if (!enabled.value || steps.length === 0) return
348
+ stop()
349
+ run = { tour, steps, index: 0, shown: new Set() }
350
+ void showFrom(0)
351
+ }
352
+
353
+ function startTour(id: string) {
354
+ const tour = tours.value.find((item) => item.id === id)
355
+ if (!tour) return
356
+ autoStartAbort?.abort()
357
+ begin(tour, availableSteps(tour))
358
+ }
359
+
360
+ function showNews(id: string) {
361
+ const item = definition.whatsNew?.find((entry) => entry.id === id)
362
+ if (!item) return
363
+ autoStartAbort?.abort()
364
+ begin(null, [item])
365
+ }
366
+
367
+ function next() {
368
+ if (run) void showFrom(run.index + 1)
369
+ }
370
+
371
+ function back() {
372
+ if (!run) return
373
+ // Back goes only to steps whose element is still on the page; it does not wait.
374
+ for (let index = run.index - 1; index >= 0; index -= 1) {
375
+ if (document.querySelector(anchorSelector(run.steps[index].anchor))) {
376
+ void showFrom(index)
377
+ return
378
+ }
379
+ }
380
+ }
381
+
382
+ function dismiss() {
383
+ autoStartAbort?.abort()
384
+ const tour = run?.tour
385
+ if (tour) markSeen(...tour.steps.map((step) => stepKey(tour, step)))
386
+ stop()
387
+ }
388
+
389
+ function complete(taskId: string) {
390
+ markSeen(`task:${taskId}`)
391
+ }
392
+
393
+ function setChecklistHidden(hidden: boolean) {
394
+ if (!storageKey.value) return
395
+ if (hidden) markSeen(HIDE_CHECKLIST)
396
+ else persist((set) => set.delete(HIDE_CHECKLIST))
397
+ }
398
+
399
+ function refresh() {
400
+ tick.value += 1
401
+ }
402
+
403
+ const availableSteps = (tour: OnboardingTour) => tour.steps.filter((step) => step.available?.() ?? true)
404
+
405
+ // Tours started on this page; a tour with skipped steps does not start again until the page changes.
406
+ const tried = new Set<string>()
407
+ let autoStartAbort: AbortController | undefined
408
+ async function autoStart() {
409
+ autoStartAbort?.abort()
410
+ const controller = new AbortController()
411
+ autoStartAbort = controller
412
+ if (!(await waitForNoModal(controller.signal)) || run || !enabled.value) return
413
+ for (const tour of tours.value) {
414
+ if (tried.has(tour.id)) continue
415
+ const unseen = availableSteps(tour).filter((step) => !seen.value.has(stepKey(tour, step)))
416
+ if (unseen.length) {
417
+ tried.add(tour.id)
418
+ begin(tour, unseen)
419
+ return
420
+ }
421
+ }
422
+ }
423
+
424
+ // A new page ends the run: its elements are gone. Its unseen steps start again.
425
+ watch([route, storageKey], () => {
426
+ stop()
427
+ tried.clear()
428
+ refresh()
429
+ if (options.autoStart !== false) void autoStart()
430
+ }, { immediate: true })
431
+
432
+ onScopeDispose(() => {
433
+ autoStartAbort?.abort()
434
+ window.removeEventListener('storage', onStorage)
435
+ stop()
436
+ })
437
+
438
+ const state: OnboardingState = {
439
+ definition,
440
+ enabled,
441
+ active,
442
+ tours,
443
+ tasks,
444
+ tasksDone,
445
+ checklistVisible,
446
+ checklistHidden,
447
+ news,
448
+ unseenNews,
449
+ startTour,
450
+ showNews,
451
+ next,
452
+ back,
453
+ dismiss,
454
+ complete,
455
+ setChecklistHidden,
456
+ refresh,
457
+ }
458
+ provide(ONBOARDING_KEY, state)
459
+ return state
460
+ }
461
+
462
+ /** The app's onboarding coordinator, e.g. to call `complete(taskId)`. Null when the app provides none. */
463
+ export function useOnboarding(): OnboardingState | null {
464
+ return inject(ONBOARDING_KEY, null)
465
+ }
@@ -120,7 +120,7 @@ export function usePluginWorkspace(options: UsePluginWorkspaceOptions): UsePlugi
120
120
  sidebarToggleLabel: sidebar.toggleLabel ?? 'Open workspace sidebar',
121
121
  sidebarCloseLabel: sidebar.closeLabel ?? 'Close workspace sidebar',
122
122
  hasSidebarSurface: hasSidebarSurface.value,
123
- title: props.spec?.title ?? 'Workspace',
123
+ title: props.spec?.title,
124
124
  subtitle: props.spec?.subtitle,
125
125
  topBar: topBarSpec.value === false
126
126
  ? false
package/src/runtime.ts CHANGED
@@ -77,7 +77,8 @@ export {
77
77
  combinePluginJobSources,
78
78
  useJobCenter,
79
79
  type CombinedPluginJobCenterSource,
80
- type JobsStatusTrayTab,
80
+ type JobRowOverride,
81
+ type JobRowView,
81
82
  type PluginJobCenterSource,
82
83
  type UseJobCenterOptions,
83
84
  type UseJobCenterReturn,
package/src/shell.ts CHANGED
@@ -101,3 +101,20 @@ export {
101
101
  type UsePluginWorkspaceOptions,
102
102
  type UsePluginWorkspaceReturn,
103
103
  } from './composables/usePluginWorkspace'
104
+
105
+ // Onboarding: tours, the Getting started checklist and what's-new hints
106
+ export {
107
+ ANCHOR_WAIT_MS,
108
+ defineOnboarding,
109
+ provideOnboarding,
110
+ useOnboarding,
111
+ ONBOARDING_KEY,
112
+ type OnboardingActiveStep,
113
+ type OnboardingDefinition,
114
+ type OnboardingNews,
115
+ type OnboardingState,
116
+ type OnboardingStep,
117
+ type OnboardingTask,
118
+ type OnboardingTour,
119
+ type ProvideOnboardingOptions,
120
+ } from './composables/useOnboarding'
@@ -3,9 +3,7 @@ export {
3
3
  useSettingsStore,
4
4
  tryUseSettingsStore,
5
5
  colorPalettes,
6
- paletteCssVariables,
7
6
  tableDensityToSize,
8
- PALETTE_CSS_VARIABLES,
9
7
  type SettingsState,
10
8
  } from './settings'
11
9
  export { useExperimentStore } from './experiment'
@@ -55,39 +55,24 @@ const defaultSettings: SettingsState = {
55
55
  tableDensity: 'normal',
56
56
  }
57
57
 
58
- export const colorPalettes: Record<ColorPalette, { name: string; hues: [number, number] }> = {
59
- default: { name: 'Default (Cyan-Pink)', hues: [180, 320] },
60
- colorblind: { name: 'Colorblind-friendly', hues: [45, 260] },
61
- viridis: { name: 'Viridis', hues: [280, 80] },
62
- pastel: { name: 'Pastel', hues: [200, 340] },
63
- }
64
-
65
58
  /**
66
- * Custom properties a non-default palette overrides on `<html>`.
67
- *
68
- * The saturation/lightness pairs are lifted from the original indigo/orange
69
- * tokens in `styles/variables.css` so only the hue moves; the `default`
70
- * palette writes nothing at all and the stylesheet values stand.
59
+ * Accent palettes. `styles/variables.css` holds each palette's light and dark
60
+ * tokens under `[data-palette]`; the store only writes the attribute.
71
61
  */
72
- export const PALETTE_CSS_VARIABLES = [
73
- '--color-primary',
74
- '--color-primary-hover',
75
- '--color-primary-soft',
76
- '--color-cta',
77
- '--color-cta-hover',
78
- ] as const
79
-
80
- /** Build the `<html>` custom-property overrides for a palette. */
81
- export function paletteCssVariables(palette: ColorPalette): Record<string, string> {
82
- if (palette === 'default') return {}
83
- const [primaryHue, accentHue] = colorPalettes[palette].hues
84
- return {
85
- '--color-primary': `hsl(${primaryHue} 84% 67%)`,
86
- '--color-primary-hover': `hsl(${primaryHue} 75% 59%)`,
87
- '--color-primary-soft': `hsl(${primaryHue} 84% 67% / 0.12)`,
88
- '--color-cta': `hsl(${accentHue} 95% 53%)`,
89
- '--color-cta-hover': `hsl(${accentHue} 90% 48%)`,
90
- }
62
+ export const colorPalettes: Record<ColorPalette, { name: string }> = {
63
+ default: { name: 'Teal' },
64
+ colorblind: { name: 'Colour-blind safe' },
65
+ purple: { name: 'Purple' },
66
+ ocean: { name: 'Ocean' },
67
+ forest: { name: 'Forest' },
68
+ }
69
+
70
+ /** Pre-v2 palette ids and the palette that replaces each one. */
71
+ const RETIRED_PALETTES: Record<string, ColorPalette> = { viridis: 'purple', pastel: 'default' }
72
+
73
+ function knownPalette(value: unknown): ColorPalette {
74
+ if (typeof value === 'string' && value in colorPalettes) return value as ColorPalette
75
+ return (typeof value === 'string' && RETIRED_PALETTES[value]) || 'default'
91
76
  }
92
77
 
93
78
  /** `DataFrame`-style size that each table density maps onto. */
@@ -107,13 +92,13 @@ function loadSettings(): SettingsState {
107
92
  const stored = localStorage.getItem(STORAGE_KEY)
108
93
  if (stored) {
109
94
  const parsed = JSON.parse(stored)
110
- return { ...defaultSettings, ...parsed }
95
+ return { ...defaultSettings, ...parsed, colorPalette: knownPalette(parsed.colorPalette) }
111
96
  }
112
97
 
113
98
  const legacyStored = localStorage.getItem(LEGACY_STORAGE_KEY)
114
99
  if (legacyStored) {
115
100
  const parsed = JSON.parse(legacyStored)
116
- const migrated = { ...defaultSettings, ...parsed }
101
+ const migrated = { ...defaultSettings, ...parsed, colorPalette: knownPalette(parsed.colorPalette) }
117
102
  localStorage.setItem(STORAGE_KEY, JSON.stringify(migrated))
118
103
  localStorage.removeItem(LEGACY_STORAGE_KEY)
119
104
  return migrated
@@ -202,20 +187,10 @@ export const useSettingsStore = defineStore('mint-settings', () => {
202
187
  document.documentElement.classList.toggle('dark', dark)
203
188
  }
204
189
 
205
- /**
206
- * Write the selected palette's hues onto `<html>` as custom-property
207
- * overrides. The `default` palette clears them so `styles/variables.css`
208
- * keeps ownership of the brand colors.
209
- */
190
+ /** Mirror the palette onto `<html data-palette>`; `styles/variables.css` maps it to tokens. */
210
191
  function applyPalette() {
211
192
  if (typeof document === 'undefined') return
212
- const style = document.documentElement.style
213
- const overrides = paletteCssVariables(colorPalette.value)
214
- for (const name of PALETTE_CSS_VARIABLES) {
215
- const value = overrides[name]
216
- if (value) style.setProperty(name, value)
217
- else style.removeProperty(name)
218
- }
193
+ document.documentElement.dataset.palette = colorPalette.value
219
194
  }
220
195
 
221
196
  /** Mirror the table density onto `<html data-density>` for CSS consumers. */
@@ -269,10 +244,6 @@ export const useSettingsStore = defineStore('mint-settings', () => {
269
244
  tableDensity.value = defaultSettings.tableDensity
270
245
  }
271
246
 
272
- function getPaletteHues(): [number, number] {
273
- return colorPalettes[colorPalette.value].hues
274
- }
275
-
276
247
  /** The `size` the SDK table components default to for the current density. */
277
248
  function getTableSize(): 'sm' | 'md' | 'lg' {
278
249
  return tableDensityToSize(tableDensity.value)
@@ -298,7 +269,6 @@ export const useSettingsStore = defineStore('mint-settings', () => {
298
269
  applyDensity,
299
270
  persistSettings,
300
271
  resetToDefaults,
301
- getPaletteHues,
302
272
  getTableSize,
303
273
  isDark,
304
274
  getApiBaseUrl,
@@ -6,14 +6,14 @@
6
6
  overflow: hidden;
7
7
  color: var(--text-muted);
8
8
  font-variant-numeric: tabular-nums;
9
- font-weight: 600;
9
+ font-weight: 400;
10
10
  letter-spacing: 0;
11
11
  text-overflow: ellipsis;
12
12
  white-space: nowrap;
13
13
  }
14
14
 
15
15
  .mint-adduct-text--mono { font-family: var(--font-mono); font-feature-settings: 'liga' 0, 'calt' 0; }
16
- .mint-adduct-text--sans { font-family: var(--font-sans); font-feature-settings: 'liga' 1, 'calt' 1; font-weight: 650; }
16
+ .mint-adduct-text--sans { font-family: var(--font-sans); font-feature-settings: 'liga' 1, 'calt' 1; }
17
17
 
18
18
  .mint-adduct-text--xs {
19
19
  font-size: 0.6875rem;
@@ -26,9 +26,16 @@
26
26
  }
27
27
 
28
28
  .mint-adduct-text--badge {
29
- padding: 0.125rem 0.25rem;
29
+ height: 1.25rem;
30
+ padding: 0 0.375rem;
30
31
  border-radius: var(--radius-sm);
31
32
  background: var(--bg-tertiary);
33
+ color: var(--text-secondary-strong);
34
+ }
35
+
36
+ .mint-adduct-text--badge.mint-adduct-text--xs {
37
+ font-size: 0.75rem;
38
+ line-height: 1.25rem;
32
39
  }
33
40
 
34
41
  /* On a filled surface the text inherits that surface's ink (9c: the old
@@ -44,8 +51,9 @@
44
51
  /* Charge as a superscript by relative offset, so the line box keeps its height. */
45
52
  .mint-adduct-text__charge {
46
53
  position: relative;
47
- top: -0.5em;
48
- font-size: 0.72em;
54
+ top: -0.45em;
55
+ margin-left: 1px;
56
+ font-size: 0.78em;
49
57
  line-height: 0;
50
58
  vertical-align: baseline;
51
59
  color: inherit;