@morscherlab/mint-sdk 1.4.0-beta.1 → 1.4.0-beta.11

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 (266) hide show
  1. package/dist/{ActionMenu-CScINahU.js → AlertBox-B2Bgr3ei.js} +40 -209
  2. package/dist/AlertBox-B2Bgr3ei.js.map +1 -0
  3. package/dist/{AppSidebar-BmiiPfz9.js → AppSidebar-mvm--GxN.js} +161 -110
  4. package/dist/AppSidebar-mvm--GxN.js.map +1 -0
  5. package/dist/{ConfirmDialog-CJ7hqYUP.js → ConfirmDialog-nbJj51is.js} +2 -2
  6. package/dist/{ConfirmDialog-CJ7hqYUP.js.map → ConfirmDialog-nbJj51is.js.map} +1 -1
  7. package/dist/ExperimentPopover-5T1fAq2L.js +337 -0
  8. package/dist/ExperimentPopover-5T1fAq2L.js.map +1 -0
  9. package/dist/{ExperimentSelectorModal-D-9z7cNx.js → ExperimentSelectorModal-65peG4Up.js} +198 -181
  10. package/dist/ExperimentSelectorModal-65peG4Up.js.map +1 -0
  11. package/dist/{SegmentedControl-DERBN-Xd.js → SegmentedControl-BtnnjWzs.js} +2 -2
  12. package/dist/{SegmentedControl-DERBN-Xd.js.map → SegmentedControl-BtnnjWzs.js.map} +1 -1
  13. package/dist/{SettingsModal-CSLE31yg.js → SettingsModal-DO3IZ7qz.js} +9 -9
  14. package/dist/SettingsModal-DO3IZ7qz.js.map +1 -0
  15. package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
  16. package/dist/components/AppSidebar.vue.d.ts +1 -1
  17. package/dist/components/ArtifactSaveDialog.vue.d.ts +9 -1
  18. package/dist/components/AuditTrail.vue.d.ts +1 -1
  19. package/dist/components/BaseSelect.vue.d.ts +2 -2
  20. package/dist/components/ChartContainer.vue.d.ts +2 -0
  21. package/dist/components/DatePicker.vue.d.ts +1 -1
  22. package/dist/components/ExperimentPopover.vue.d.ts +18 -0
  23. package/dist/components/ExperimentSelectorModal.vue.d.ts +0 -4
  24. package/dist/components/FilePicker.vue.d.ts +1 -1
  25. package/dist/components/FileUploader.vue.d.ts +2 -2
  26. package/dist/components/PluginIcon.vue.d.ts +2 -2
  27. package/dist/components/SampleSelector.vue.d.ts +6 -6
  28. package/dist/components/SequenceProgressBar.vue.d.ts +3 -0
  29. package/dist/components/StepWizard.vue.d.ts +3 -0
  30. package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +1 -1
  31. package/dist/components/internal/DatePickerTimeInternal.vue.d.ts +1 -1
  32. package/dist/components/internal/ResourcePickerListInternal.vue.d.ts +2 -7
  33. package/dist/components/internal/SelectMultipleInternal.vue.d.ts +4 -0
  34. package/dist/composables/createClient.d.ts +2 -0
  35. package/dist/composables/index.d.ts +1 -0
  36. package/dist/composables/pluginIdentity.d.ts +24 -0
  37. package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
  38. package/dist/composables/useAppExperiment.d.ts +8 -0
  39. package/dist/composables/useCalendarGrid.d.ts +1 -1
  40. package/dist/composables/useExperimentSelector.d.ts +6 -2
  41. package/dist/composables/usePlatform.d.ts +1 -0
  42. package/dist/{controlSchemaModel-CP5-_nAj.js → controlSchemaModel-B8CTXagP.js} +2 -2
  43. package/dist/{controlSchemaModel-CP5-_nAj.js.map → controlSchemaModel-B8CTXagP.js.map} +1 -1
  44. package/dist/{data-C2PwI_dn.js → data-CgILxDLW.js} +178 -124
  45. package/dist/data-CgILxDLW.js.map +1 -0
  46. package/dist/data.js +8 -8
  47. package/dist/{experimentStatus-BZmU4czV.js → experimentStatus-Cqp6qNrR.js} +3 -3
  48. package/dist/{experimentStatus-BZmU4czV.js.map → experimentStatus-Cqp6qNrR.js.map} +1 -1
  49. package/dist/index.js +19 -19
  50. package/dist/{install-DAID6c2-.js → install-mB8-IyvO.js} +15 -14
  51. package/dist/{install-DAID6c2-.js.map → install-mB8-IyvO.js.map} +1 -1
  52. package/dist/install.js +1 -1
  53. package/dist/{lab-DLwRl_Ql.js → lab-D5bIX426.js} +128 -147
  54. package/dist/lab-D5bIX426.js.map +1 -0
  55. package/dist/lab.js +4 -3
  56. package/dist/{records-BzTcxekG.js → records-B6gpM_3e.js} +472 -274
  57. package/dist/records-B6gpM_3e.js.map +1 -0
  58. package/dist/{runtime-D6gVat6r.js → runtime-D7vKpfbF.js} +27 -31
  59. package/dist/runtime-D7vKpfbF.js.map +1 -0
  60. package/dist/runtime.js +6 -6
  61. package/dist/{shell-5ju97nOS.js → shell-CywENwBT.js} +5 -5
  62. package/dist/{shell-5ju97nOS.js.map → shell-CywENwBT.js.map} +1 -1
  63. package/dist/shell.js +5 -5
  64. package/dist/styles.css +1644 -1688
  65. package/dist/types/componentWorkflowTypes.d.ts +2 -0
  66. package/dist/types/generated/platformContext.d.ts +1 -0
  67. package/dist/types/generated-ui.d.ts +4 -0
  68. package/dist/{BaseModal-DfRIuVoj.js → useDropdownState-8yWMu-7_.js} +60 -2
  69. package/dist/useDropdownState-8yWMu-7_.js.map +1 -0
  70. package/dist/{useExperimentSamples-CxcnxZ8h.js → useExperimentSamples-DHnxKFAF.js} +3 -3
  71. package/dist/{useExperimentSamples-CxcnxZ8h.js.map → useExperimentSamples-DHnxKFAF.js.map} +1 -1
  72. package/dist/{useListReorder-CcbEYxX-.js → useListReorder-BitdUhxn.js} +109 -277
  73. package/dist/useListReorder-BitdUhxn.js.map +1 -0
  74. package/dist/{useRackEditor-BD5NIo5s.js → useRackEditor-Q8xO-cCy.js} +72 -58
  75. package/dist/useRackEditor-Q8xO-cCy.js.map +1 -0
  76. package/dist/{useRealtime-PalKue84.js → useRealtime-C3iy9QkU.js} +7 -4
  77. package/dist/useRealtime-C3iy9QkU.js.map +1 -0
  78. package/dist/useRequest-D506eHi8.js +244 -0
  79. package/dist/useRequest-D506eHi8.js.map +1 -0
  80. package/dist/utils/time.d.ts +7 -0
  81. package/package.json +1 -1
  82. package/src/__tests__/components/AppTopBar.test.ts +51 -2
  83. package/src/__tests__/components/AppTopBarPillNav.test.ts +35 -0
  84. package/src/__tests__/components/ArtifactSaveDialog.test.ts +78 -0
  85. package/src/__tests__/components/BaseSelect.multiple.test.ts +87 -32
  86. package/src/__tests__/components/BaseSelect.test.ts +2 -1
  87. package/src/__tests__/components/BatchProgressList.test.ts +16 -0
  88. package/src/__tests__/components/CalendarGridPanel.test.ts +2 -2
  89. package/src/__tests__/components/ChartContainer.test.ts +11 -0
  90. package/src/__tests__/components/ChemicalFormula.test.ts +6 -3
  91. package/src/__tests__/components/DatePicker.datetime.test.ts +6 -0
  92. package/src/__tests__/components/DatePicker.test.ts +21 -0
  93. package/src/__tests__/components/DatePicker.time.test.ts +2 -2
  94. package/src/__tests__/components/EmptyState.test.ts +1 -1
  95. package/src/__tests__/components/ExperimentPopover.test.ts +125 -16
  96. package/src/__tests__/components/ExperimentSelectorModal.test.ts +119 -13
  97. package/src/__tests__/components/GeneratedPluginView.test.ts +22 -1
  98. package/src/__tests__/components/InstrumentStateBadge.test.ts +4 -4
  99. package/src/__tests__/components/PluginWorkspaceView.test.ts +7 -0
  100. package/src/__tests__/components/ResourcePickerListInternal.test.ts +0 -20
  101. package/src/__tests__/components/SampleSelector.test.ts +13 -8
  102. package/src/__tests__/components/SequenceProgressBar.test.ts +12 -0
  103. package/src/__tests__/components/StepWizard.test.ts +11 -0
  104. package/src/__tests__/components/WellPlate.decoration.test.ts +11 -4
  105. package/src/__tests__/components/deprecationTags.test.ts +1 -1
  106. package/src/__tests__/composables/useAppExperiment.test.ts +27 -1
  107. package/src/__tests__/composables/useCalendarGrid.test.ts +4 -2
  108. package/src/__tests__/composables/useExperimentSelector.test.ts +111 -0
  109. package/src/__tests__/styles/baseControlsRules.test.ts +6 -2
  110. package/src/__tests__/styles/controlRefreshRules.test.ts +0 -6
  111. package/src/__tests__/styles/cssTokens.test.ts +2 -2
  112. package/src/__tests__/styles/menusShellRefresh.test.ts +14 -10
  113. package/src/__tests__/styles/v2AuditRules.test.ts +96 -0
  114. package/src/__tests__/utils/plotlyTemplate.test.ts +4 -4
  115. package/src/__tests__/utils/time.test.ts +18 -1
  116. package/src/components/AdductText.story.vue +7 -0
  117. package/src/components/AdductText.vue +1 -1
  118. package/src/components/AlertBox.story.vue +2 -2
  119. package/src/components/AlertBox.vue +18 -16
  120. package/src/components/AppSidebar.story.vue +0 -28
  121. package/src/components/AppTopBar.story.vue +47 -12
  122. package/src/components/AppTopBar.vue +118 -114
  123. package/src/components/ArtifactSaveDialog.story.vue +23 -0
  124. package/src/components/ArtifactSaveDialog.vue +102 -12
  125. package/src/components/AuditTrail.story.vue +2 -1
  126. package/src/components/AuditTrail.vue +2 -21
  127. package/src/components/Avatar.vue +10 -14
  128. package/src/components/BaseSelect.multiple.story.vue +13 -2
  129. package/src/components/BaseSelect.vue +4 -3
  130. package/src/components/BatchProgressList.vue +35 -25
  131. package/src/components/ChartContainer.story.vue +2 -1
  132. package/src/components/ChartContainer.vue +8 -6
  133. package/src/components/ConfirmDialog.story.vue +1 -1
  134. package/src/components/EmptyState.vue +1 -1
  135. package/src/components/ExperimentPopover.story.vue +165 -53
  136. package/src/components/ExperimentPopover.vue +169 -187
  137. package/src/components/ExperimentSelectorModal.story.vue +40 -36
  138. package/src/components/ExperimentSelectorModal.vue +124 -110
  139. package/src/components/FormField.story.vue +8 -48
  140. package/src/components/GeneratedPluginView.vue +7 -1
  141. package/src/components/GeneratedResultRenderer.vue +3 -4
  142. package/src/components/InstrumentStateBadge.vue +1 -1
  143. package/src/components/JobsStatusTray.vue +1 -1
  144. package/src/components/LoadingSpinner.vue +1 -1
  145. package/src/components/NumberInput.vue +3 -6
  146. package/src/components/PluginIcon.story.vue +2 -10
  147. package/src/components/PluginIcon.vue +2 -2
  148. package/src/components/PluginWorkspaceView.story.vue +1 -1
  149. package/src/components/RuntimeUpdateNotice.vue +1 -1
  150. package/src/components/SampleSelector.story.vue +1 -1
  151. package/src/components/SampleSelector.vue +27 -37
  152. package/src/components/SampleSelectorGroupNode.vue +1 -1
  153. package/src/components/SectionCard.story.vue +2 -2
  154. package/src/components/SequenceProgressBar.story.vue +9 -0
  155. package/src/components/SequenceProgressBar.vue +6 -1
  156. package/src/components/SettingsModal.schema.ts +1 -1
  157. package/src/components/SettingsModal.vue +2 -2
  158. package/src/components/SmartGroupFieldRecipe.story.vue +1 -1
  159. package/src/components/SmartGroupManual.story.vue +1 -1
  160. package/src/components/StepWizard.story.vue +33 -0
  161. package/src/components/StepWizard.vue +8 -1
  162. package/src/components/WellPlate.story.vue +3 -1
  163. package/src/components/WellPlate.vue +7 -0
  164. package/src/components/internal/AppTopBarPillNavInternal.vue +33 -2
  165. package/src/components/internal/DatePickerDateInternal.vue +16 -40
  166. package/src/components/internal/DatePickerDateTimeInternal.vue +3 -13
  167. package/src/components/internal/DatePickerTimeInternal.vue +5 -8
  168. package/src/components/internal/ResourcePickerListInternal.vue +45 -85
  169. package/src/components/internal/SelectMultipleInternal.vue +182 -65
  170. package/src/components/internal/SelectSearchableInternal.vue +2 -3
  171. package/src/composables/createClient.ts +2 -0
  172. package/src/composables/index.ts +1 -0
  173. package/src/composables/pluginIdentity.ts +31 -0
  174. package/src/composables/pluginWorkspaceModel.ts +2 -2
  175. package/src/composables/useAppExperiment.ts +20 -0
  176. package/src/composables/useCalendarGrid.ts +4 -3
  177. package/src/composables/useExperimentSelector.ts +77 -31
  178. package/src/composables/usePluginWorkspace.ts +1 -1
  179. package/src/styles/components/adduct-text.css +13 -5
  180. package/src/styles/components/alert-box.css +39 -58
  181. package/src/styles/components/app-layout.css +7 -5
  182. package/src/styles/components/app-page-selector.css +3 -1
  183. package/src/styles/components/app-pill-nav.css +11 -12
  184. package/src/styles/components/app-sidebar.css +9 -18
  185. package/src/styles/components/app-top-bar.css +57 -55
  186. package/src/styles/components/artifact-save-dialog.css +153 -2
  187. package/src/styles/components/audit-trail.css +16 -19
  188. package/src/styles/components/avatar.css +6 -4
  189. package/src/styles/components/batch-progress-list.css +38 -36
  190. package/src/styles/components/button.css +28 -59
  191. package/src/styles/components/calendar.css +12 -12
  192. package/src/styles/components/chart-container.css +34 -23
  193. package/src/styles/components/checkbox.css +2 -12
  194. package/src/styles/components/collapsible-card.css +27 -29
  195. package/src/styles/components/confirm-dialog.css +13 -14
  196. package/src/styles/components/dataframe.css +13 -5
  197. package/src/styles/components/date-picker.css +80 -92
  198. package/src/styles/components/datetime-picker.css +31 -43
  199. package/src/styles/components/divider.css +20 -20
  200. package/src/styles/components/dose-calculator.css +3 -3
  201. package/src/styles/components/empty-state.css +20 -17
  202. package/src/styles/components/experiment-code-badge.css +2 -0
  203. package/src/styles/components/experiment-popover.css +174 -329
  204. package/src/styles/components/experiment-selector-modal.css +75 -56
  205. package/src/styles/components/file-picker.css +3 -3
  206. package/src/styles/components/file-uploader.css +38 -49
  207. package/src/styles/components/form-builder.css +3 -3
  208. package/src/styles/components/formula-input.css +1 -1
  209. package/src/styles/components/icon-button.css +18 -24
  210. package/src/styles/components/input.css +5 -4
  211. package/src/styles/components/instrument-monitor.css +13 -15
  212. package/src/styles/components/jobs-status-tray.css +31 -25
  213. package/src/styles/components/modal.css +4 -6
  214. package/src/styles/components/molecule-input.css +2 -2
  215. package/src/styles/components/multi-select.css +65 -117
  216. package/src/styles/components/number-input.css +26 -19
  217. package/src/styles/components/pill.css +3 -2
  218. package/src/styles/components/plate-editor.css +0 -1
  219. package/src/styles/components/plugin-icon.css +26 -23
  220. package/src/styles/components/popover.css +2 -2
  221. package/src/styles/components/presence-avatars.css +1 -1
  222. package/src/styles/components/progress-bar.css +3 -3
  223. package/src/styles/components/protocol-step-editor.css +1 -3
  224. package/src/styles/components/resource-card.css +2 -2
  225. package/src/styles/components/resource-picker-list.css +6 -57
  226. package/src/styles/components/sample-hierarchy-tree.css +4 -4
  227. package/src/styles/components/sample-selector.css +95 -79
  228. package/src/styles/components/schedule-calendar.css +8 -8
  229. package/src/styles/components/searchable-select.css +12 -12
  230. package/src/styles/components/section-card.css +30 -47
  231. package/src/styles/components/segmented-control.css +18 -15
  232. package/src/styles/components/select.css +3 -3
  233. package/src/styles/components/sequence-input.css +2 -2
  234. package/src/styles/components/sequence-progress-bar.css +17 -8
  235. package/src/styles/components/settings-modal.css +7 -2
  236. package/src/styles/components/smart-group.css +18 -18
  237. package/src/styles/components/step-wizard.css +52 -16
  238. package/src/styles/components/tabs.css +2 -2
  239. package/src/styles/components/textarea.css +3 -3
  240. package/src/styles/components/time-picker.css +36 -21
  241. package/src/styles/components/toast.css +12 -10
  242. package/src/styles/components/toggle.css +1 -11
  243. package/src/styles/components/tooltip.css +10 -9
  244. package/src/styles/components/unit-input.css +8 -7
  245. package/src/styles/components/well-plate.css +9 -2
  246. package/src/styles/variables.css +118 -77
  247. package/src/types/componentWorkflowTypes.ts +2 -0
  248. package/src/types/generated/platformContext.ts +1 -0
  249. package/src/types/generated-ui.ts +4 -0
  250. package/src/utils/time.ts +21 -0
  251. package/dist/ActionMenu-CScINahU.js.map +0 -1
  252. package/dist/AppSidebar-BmiiPfz9.js.map +0 -1
  253. package/dist/BaseModal-DfRIuVoj.js.map +0 -1
  254. package/dist/ExperimentPopover-C4sGw-is.js +0 -359
  255. package/dist/ExperimentPopover-C4sGw-is.js.map +0 -1
  256. package/dist/ExperimentSelectorModal-D-9z7cNx.js.map +0 -1
  257. package/dist/SettingsModal-CSLE31yg.js.map +0 -1
  258. package/dist/data-C2PwI_dn.js.map +0 -1
  259. package/dist/lab-DLwRl_Ql.js.map +0 -1
  260. package/dist/records-BzTcxekG.js.map +0 -1
  261. package/dist/runtime-D6gVat6r.js.map +0 -1
  262. package/dist/useListReorder-CcbEYxX-.js.map +0 -1
  263. package/dist/useRackEditor-BD5NIo5s.js.map +0 -1
  264. package/dist/useRealtime-PalKue84.js.map +0 -1
  265. package/dist/useRequest-D5JDfsgZ.js +0 -76
  266. package/dist/useRequest-D5JDfsgZ.js.map +0 -1
@@ -29,11 +29,11 @@ describe('SDK control refresh base-control rules', () => {
29
29
  })
30
30
 
31
31
  it('should find no soft or plain focus ring when scanning pressable controls (1a)', () => {
32
- const pressables = ['checkbox.css', 'radio-group.css', 'toggle.css', 'icon-button.css', 'multi-select.css']
32
+ const pressables = ['checkbox.css', 'radio-group.css', 'toggle.css', 'icon-button.css']
33
33
  expect(offenders(pressables, (l) => /var\(--focus-ring(-soft)?\)/.test(l))).toEqual([])
34
34
  })
35
35
 
36
- it.each(['input.css', 'select.css', 'textarea.css'])(
36
+ it.each(['input.css', 'select.css', 'textarea.css', 'multi-select.css'])(
37
37
  'should use the shared field hover border when scanning %s (1e)',
38
38
  (file) => {
39
39
  expect(css(file)).toContain('border-color: var(--_field-border-hover)')
@@ -77,6 +77,10 @@ describe('SDK control refresh base-control rules', () => {
77
77
  expect(offenders(['alert-box.css'], (l) => /\.mint-alert--\w+ \.mint-alert__title/.test(l))).toEqual([])
78
78
  })
79
79
 
80
+ it('should find no tone fill on the alert surface when scanning alert-box.css (v2 callout)', () => {
81
+ expect(offenders(['alert-box.css'], (l) => /^\.mint-alert--\w+\s*\{/.test(l))).toEqual([])
82
+ })
83
+
80
84
  it('should find no pill radius on the chip when scanning multi-select.css (1i)', () => {
81
85
  expect(offenders(['multi-select.css'], (l) => /9999px|999px/.test(l))).toEqual([])
82
86
  })
@@ -197,12 +197,6 @@ describe('SDK control refresh style rules', () => {
197
197
  expect(rule).toMatch(/padding:\s*0/)
198
198
  })
199
199
 
200
- it('should pad resource picker group bars to the modal gutter when scanning resource-picker-list.css', () => {
201
- const css = stripComments(readFileSync(component('resource-picker-list.css'), 'utf-8'))
202
- const rule = /\.mint-resource-picker__group\s*\{([^}]*)\}/.exec(css)?.[1] ?? ''
203
- expect(rule).toMatch(/padding:\s*0 1\.25rem/)
204
- })
205
-
206
200
  // The list sat in a bordered card inside the modal card.
207
201
  it('should draw no frame around the resource picker list when scanning resource-picker-list.css', () => {
208
202
  const css = stripComments(readFileSync(component('resource-picker-list.css'), 'utf-8'))
@@ -93,8 +93,8 @@ describe('CSS custom properties', () => {
93
93
 
94
94
  // 9a: PlotlyChart reads it through getComputedStyle('--font-sans'), which the
95
95
  // scan above counts as a declaration, so it slipped through as undefined.
96
- it('should declare --font-sans as Fira Sans when charts read the sans font token (9a)', () => {
97
- expect(variablesCss).toMatch(/--font-sans:\s*'Fira Sans'/)
96
+ it('should declare --font-sans as Geist when charts read the sans font token (9a)', () => {
97
+ expect(variablesCss).toMatch(/--font-sans:\s*'Geist'/)
98
98
  })
99
99
 
100
100
  it('does not use the platform-only --color-bg-*/--color-text-*/--color-border aliases', () => {
@@ -25,9 +25,9 @@ describe('menus and app shell styles', () => {
25
25
  expect(css('app-top-bar.css')).toMatch(/\.mint-topbar\s*\{[^}]*padding:\s*0\.75rem 1rem;/)
26
26
  })
27
27
 
28
- // 28px items + 3px track padding + 1px border on each side = the 36px top-bar control height.
29
- it('should size pill nav items so the track matches the 36px top-bar controls', () => {
30
- expect(css('app-pill-nav.css')).toMatch(/\.mint-pill-nav__item\s*\{[^}]*height:\s*1\.75rem;/)
28
+ // 26px items + 2px track padding + 1px border on each side = the 32px top-bar control height.
29
+ it('should size pill nav items so the track matches the 32px top-bar controls', () => {
30
+ expect(css('app-pill-nav.css')).toMatch(/\.mint-pill-nav__item\s*\{[^}]*height:\s*1\.625rem;/)
31
31
  })
32
32
 
33
33
  it('should size the page selector trigger to the 36px identity tile', () => {
@@ -44,17 +44,21 @@ describe('menus and app shell styles', () => {
44
44
  expect(css('app-top-bar.css')).toMatch(/\.mint-topbar__identity > \*\s*\{[^}]*max-width:\s*100%;[^}]*max-height:\s*100%;/)
45
45
  })
46
46
 
47
- // 15px x 1.15 + 12px x 1.2 = 31.7px, so the title group fits the 32px control row.
48
- it('should fit the top-bar title and subtitle inside the control row (5a)', () => {
49
- expect(css('app-top-bar.css')).toMatch(/\.mint-topbar-title\s*\{[^}]*line-height:\s*1\.15;/)
47
+ // 18px name + 15px subtitle lines, spread over the 36px identity tile height (top and bottom aligned).
48
+ it('should fit the top-bar title and subtitle to the 36px identity tile (5a)', () => {
49
+ const topBar = css('app-top-bar.css')
50
+ expect(topBar).toMatch(/\.mint-topbar-title-group\s*\{[^}]*justify-content:\s*space-between;[^}]*height:\s*2\.25rem;/)
51
+ expect(topBar).toMatch(/\.mint-topbar-title\s*\{[^}]*font-size:\s*0\.9375rem;[^}]*line-height:\s*1\.125rem;/)
52
+ expect(topBar).toMatch(/\.mint-topbar-subtitle\s*\{[^}]*font-size:\s*0\.75rem;[^}]*line-height:\s*0\.9375rem;/)
50
53
  })
51
54
 
52
- it('should size the top-bar experiment trigger to the 32px control height (5a)', () => {
53
- expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__trigger\s*\{[^}]*height:\s*var\(--form-height-sm\);/)
55
+ // Design v2: the joined [trigger | Save] group is 30px inside its 1px border.
56
+ it('should size the top-bar experiment trigger to the 30px v2 control height (5a)', () => {
57
+ expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__trigger\s*\{[^}]*height:\s*30px;/)
54
58
  })
55
59
 
56
- it('should size the top-bar experiment save trigger to the 32px control height (5a)', () => {
57
- expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__save-trigger\s*\{[^}]*height:\s*var\(--form-height-sm\);/)
60
+ it('should size the top-bar experiment save button to the 30px v2 control height (5a)', () => {
61
+ expect(css('experiment-popover.css')).toMatch(/\.mint-experiment-popover__save\s*\{[^}]*height:\s*30px;/)
58
62
  })
59
63
 
60
64
  it('should give settings number rows a 120px control (5d)', () => {
@@ -0,0 +1,96 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { dirname, join, resolve } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { describe, expect, it } from 'vitest'
5
+
6
+ // v2 design audit (2026-10-28) fixes in the SDK stylesheets.
7
+
8
+ const srcRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..')
9
+ const stylesDir = join(srcRoot, 'styles')
10
+
11
+ function css(path: string): string {
12
+ return readFileSync(join(stylesDir, path), 'utf-8').replace(/\/\*[\s\S]*?\*\//g, '')
13
+ }
14
+
15
+ function rule(text: string, selector: string): string {
16
+ const escaped = selector.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
17
+ return new RegExp(`(?:^|\\})\\s*${escaped}\\s*\\{([^}]*)\\}`).exec(text)?.[1] ?? ''
18
+ }
19
+
20
+ const rem = (value: string): number => Number(value.replace('rem', '')) * 16
21
+
22
+ describe('v2 audit style rules', () => {
23
+ it('should keep the outermost cards at least 16px from the window edge', () => {
24
+ const inset = /--mint-page-inset:\s*([\d.]+rem)/.exec(css('variables.css'))?.[1] ?? '0rem'
25
+ expect(rem(inset)).toBeGreaterThanOrEqual(16)
26
+ expect(rule(css('components/app-layout.css'), '.mint-layout--floating')).toMatch(/padding:\s*var\(--mint-page-inset\)/)
27
+ const topBarCard = rule(css('components/app-top-bar.css'), '.mint-topbar--card')
28
+ expect(topBarCard).toMatch(/width:\s*calc\(100% - 2 \* var\(--mint-page-inset\)\)/)
29
+ expect(topBarCard).toMatch(/margin:\s*var\(--mint-page-inset\) var\(--mint-page-inset\) 0/)
30
+ })
31
+
32
+ it('should put the SDK utility classes in the utilities layer so host variants beat them', () => {
33
+ const vars = css('variables.css')
34
+ const order = vars.indexOf('@layer theme, base, components, utilities;')
35
+ const layer = vars.indexOf('@layer utilities {')
36
+ expect(order).toBeGreaterThan(-1)
37
+ expect(order).toBeLessThan(vars.indexOf('@layer base {'))
38
+ const utilities = vars.slice(layer, vars.indexOf('@media (prefers-reduced-motion'))
39
+ expect(layer).toBeGreaterThan(-1)
40
+ for (const selector of ['.flex-col {', '.text-text-muted {', '.truncate {', '.max-w-sm {']) {
41
+ expect(utilities).toContain(selector)
42
+ }
43
+ })
44
+
45
+ it('should drop the last DataFrame row rule over the !important cell border', () => {
46
+ const body = rule(css('components/dataframe.css'), '.mint-dataframe__row:last-child .mint-dataframe__td')
47
+ expect(body).toMatch(/border-bottom:\s*none\s*!important/)
48
+ })
49
+
50
+ it('should round the modal close button with --radius-md', () => {
51
+ expect(rule(css('components/modal.css'), '.mint-modal__close')).toMatch(/border-radius:\s*var\(--radius-md\)/)
52
+ })
53
+
54
+ it('should draw no capsule on the progress rail or the sheet grab hint', () => {
55
+ expect(css('components/progress-bar.css')).not.toMatch(/9999px/)
56
+ expect(rule(css('components/modal.css'), '.mint-modal__grab-hint')).not.toMatch(/9999px/)
57
+ })
58
+
59
+ it('should keep a 28px header control inside the section card header strip', () => {
60
+ const text = css('components/section-card.css')
61
+ const cases: Array<[string, number]> = [
62
+ ['.mint-section-card__header', 28],
63
+ ['[data-density="comfortable"] .mint-section-card__header', 32],
64
+ ]
65
+ for (const [selector, control] of cases) {
66
+ const body = rule(text, selector)
67
+ const minHeight = rem(/min-height:\s*([\d.]+rem)/.exec(body)?.[1] ?? '0rem')
68
+ const padTop = rem(/padding:\s*([\d.]+rem)/.exec(body)?.[1] ?? '0rem')
69
+ expect(control + 2 * padTop + 1, selector).toBeLessThanOrEqual(minHeight)
70
+ }
71
+ })
72
+
73
+ it('should end the settings pane without a closing row hairline and draw no box around the density preview', () => {
74
+ const text = css('components/settings-modal.css')
75
+ const last = rule(
76
+ text,
77
+ '.mint-settings-modal__group:last-of-type > .mint-settings-modal__group-grid > .mint-settings-modal__row:last-child',
78
+ )
79
+ expect(last).toMatch(/border-bottom:\s*none/)
80
+ expect(rule(text, '.mint-settings-modal__density-preview')).not.toMatch(/(^|;)\s*border(-radius)?:/)
81
+ })
82
+
83
+ it('should set the md number input text no smaller than the sm one', () => {
84
+ const text = css('components/number-input.css')
85
+ const size = (variant: string) =>
86
+ rem(/font-size:\s*([\d.]+rem)/.exec(rule(text, `.mint-number-input__input--${variant}`))?.[1] ?? '0rem')
87
+ expect(size('md')).toBeGreaterThan(size('sm'))
88
+ })
89
+
90
+ it('should give the generated JSON block a token radius and no frame', () => {
91
+ const sfc = readFileSync(join(srcRoot, 'components/GeneratedResultRenderer.vue'), 'utf-8')
92
+ const body = /\.mint-generated-result__json\s*\{([^}]*overflow:[^}]*)\}/.exec(sfc)?.[1] ?? ''
93
+ expect(body).toMatch(/border-radius:\s*var\(--radius-md\)/)
94
+ expect(body).not.toMatch(/(^|;)\s*border:/)
95
+ })
96
+ })
@@ -10,8 +10,8 @@ const tokens: Record<string, string> = {
10
10
  '--mint-sample-6': '#666666',
11
11
  '--mint-sample-7': '#777777',
12
12
  '--mint-sample-8': '#888888',
13
- '--font-sans': 'Fira Sans',
14
- '--font-mono': 'Fira Code',
13
+ '--font-sans': 'Geist',
14
+ '--font-mono': 'Geist Mono',
15
15
  '--text-primary': '#1E293B',
16
16
  '--text-secondary': '#64748B',
17
17
  '--border-light': '#F3F4F6',
@@ -35,11 +35,11 @@ describe('mintPlotlyTemplate', () => {
35
35
  })
36
36
 
37
37
  it('should set 12px sans body text in the primary text color when tokens are defined', () => {
38
- expect(mintPlotlyTemplate().layout?.font).toEqual({ family: 'Fira Sans', size: 12, color: '#1E293B' })
38
+ expect(mintPlotlyTemplate().layout?.font).toEqual({ family: 'Geist', size: 12, color: '#1E293B' })
39
39
  })
40
40
 
41
41
  it('should set 11px mono ticks in the secondary text color when tokens are defined', () => {
42
- expect(mintPlotlyTemplate().layout?.yaxis?.tickfont).toEqual({ family: 'Fira Code', size: 11, color: '#64748B' })
42
+ expect(mintPlotlyTemplate().layout?.yaxis?.tickfont).toEqual({ family: 'Geist Mono', size: 11, color: '#64748B' })
43
43
  })
44
44
 
45
45
  it('should draw the grid with --border-light when tokens are defined', () => {
@@ -1,6 +1,7 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
2
  import {
3
3
  findNearestTimeSlotIndex,
4
+ formatRelativeTime,
4
5
  formatTimeSlot,
5
6
  fromMinutes,
6
7
  generateTimeSlots,
@@ -25,4 +26,20 @@ describe('time', () => {
25
26
  expect(findNearestTimeSlotIndex('08:00', [])).toBe(-1)
26
27
  })
27
28
 
29
+ describe('formatRelativeTime', () => {
30
+ afterEach(() => {
31
+ vi.useRealTimers()
32
+ })
33
+
34
+ it.each([
35
+ [{ weeks: true }, '2 weeks ago'],
36
+ [{}, new Date('2026-10-14T12:00:00Z').toLocaleDateString()],
37
+ ])('should format a 14-day-old time as a week count only when weeks is on (%o)', (options, expected) => {
38
+ vi.useFakeTimers({ toFake: ['Date'] })
39
+ vi.setSystemTime(new Date('2026-10-28T12:00:00Z'))
40
+
41
+ expect(formatRelativeTime('2026-10-14T12:00:00Z', options)).toBe(expected)
42
+ })
43
+ })
44
+
28
45
  })
@@ -12,6 +12,13 @@ import AdductText from './AdductText.vue'
12
12
  </div>
13
13
  </Variant>
14
14
 
15
+ <Variant title="Badges">
16
+ <div style="display: flex; align-items: center; gap: 0.5rem; padding: 2rem;">
17
+ <AdductText v-for="v in ['[M+H]+', '[M-H]-', '[M+Na]+', '[M-H2O+H]+', '[M+2H]2+']" :key="v" :value="v" variant="badge" />
18
+ <AdductText value="[M+H]+" variant="badge" font="mono" />
19
+ </div>
20
+ </Variant>
21
+
15
22
  <Variant title="Tones and inherited size">
16
23
  <div style="display: flex; flex-direction: column; gap: 0.75rem; padding: 2rem; max-width: 600px; color: var(--text-primary); font-size: 0.875rem;">
17
24
  <div style="display: flex; align-items: center; gap: 1rem;">
@@ -17,7 +17,7 @@ const props = withDefaults(defineProps<Props>(), {
17
17
  variant: 'inline',
18
18
  tone: 'default',
19
19
  size: 'xs',
20
- font: 'mono',
20
+ font: 'sans',
21
21
  })
22
22
 
23
23
  const value = computed(() => props.value?.trim() ?? '')
@@ -35,7 +35,7 @@ function handleAction(label: string) {
35
35
  </AlertBox>
36
36
  <p
37
37
  v-if="actionFired"
38
- style="margin-top: 0.75rem; font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: 'Fira Code', monospace;"
38
+ style="margin-top: 0.75rem; font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: var(--font-mono);"
39
39
  >
40
40
  Action fired: "{{ actionFired }}"
41
41
  </p>
@@ -111,7 +111,7 @@ function handleAction(label: string) {
111
111
 
112
112
  <p
113
113
  v-if="actionFired"
114
- style="font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: 'Fira Code', monospace;"
114
+ style="font-size: 0.8rem; color: var(--mint-success, #10B981); font-family: var(--font-mono);"
115
115
  >
116
116
  Action fired: "{{ actionFired }}"
117
117
  </p>
@@ -31,22 +31,24 @@ const hasActions = () => !!props.actionLabel || !!slots.actions
31
31
  :class="`mint-alert--${props.tone}`"
32
32
  role="alert"
33
33
  >
34
- <!-- Lucide circle-check -->
35
- <svg v-if="props.tone === 'success'" class="mint-alert__icon mint-alert__icon--success" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
36
- <circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" />
37
- </svg>
38
- <!-- Lucide circle-x -->
39
- <svg v-else-if="props.tone === 'error'" class="mint-alert__icon mint-alert__icon--error" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
40
- <circle cx="12" cy="12" r="10" /><path d="m15 9-6 6" /><path d="m9 9 6 6" />
41
- </svg>
42
- <!-- Lucide triangle-alert -->
43
- <svg v-else-if="props.tone === 'warning'" class="mint-alert__icon mint-alert__icon--warning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
44
- <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /><path d="M12 9v4" /><path d="M12 17h.01" />
45
- </svg>
46
- <!-- Lucide info -->
47
- <svg v-else :class="['mint-alert__icon', `mint-alert__icon--${props.tone}`]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
48
- <circle cx="12" cy="12" r="10" /><path d="M12 16v-4" /><path d="M12 8h.01" />
49
- </svg>
34
+ <span :class="['mint-alert__icon', `mint-alert__icon--${props.tone}`]">
35
+ <!-- Lucide circle-check -->
36
+ <svg v-if="props.tone === 'success'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
37
+ <circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" />
38
+ </svg>
39
+ <!-- Lucide circle-x -->
40
+ <svg v-else-if="props.tone === 'error'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
41
+ <circle cx="12" cy="12" r="10" /><path d="m15 9-6 6" /><path d="m9 9 6 6" />
42
+ </svg>
43
+ <!-- Lucide triangle-alert -->
44
+ <svg v-else-if="props.tone === 'warning'" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
45
+ <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /><path d="M12 9v4" /><path d="M12 17h.01" />
46
+ </svg>
47
+ <!-- Lucide info -->
48
+ <svg v-else viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">
49
+ <circle cx="12" cy="12" r="10" /><path d="M12 16v-4" /><path d="M12 8h.01" />
50
+ </svg>
51
+ </span>
50
52
 
51
53
  <div class="mint-alert__content">
52
54
  <h4 v-if="props.title" class="mint-alert__title">
@@ -36,16 +36,12 @@ const sequencePanels: Record<string, SidebarToolSection[]> = {
36
36
  label: 'Import Layout',
37
37
  subtitle: 'Upload from Excel',
38
38
  icon: icons.upload,
39
- iconColor: '#3b82f6',
40
- iconBg: '#dbeafe',
41
39
  },
42
40
  {
43
41
  id: 'naming',
44
42
  label: 'Experiment & Naming',
45
43
  subtitle: 'exp001_260210_XP_M...',
46
44
  icon: icons.fileText,
47
- iconColor: '#6366f1',
48
- iconBg: '#e0e7ff',
49
45
  showToggle: true,
50
46
  badge: 'on',
51
47
  badgeTone: 'success',
@@ -55,8 +51,6 @@ const sequencePanels: Record<string, SidebarToolSection[]> = {
55
51
  label: 'Randomize Samples',
56
52
  subtitle: 'Sequential order',
57
53
  icon: icons.shuffle,
58
- iconColor: '#6366f1',
59
- iconBg: '#e0e7ff',
60
54
  showToggle: true,
61
55
  badge: 3,
62
56
  badgeTone: 'cta',
@@ -70,16 +64,12 @@ const sequencePanels: Record<string, SidebarToolSection[]> = {
70
64
  label: 'Acquisition',
71
65
  subtitle: 'NEG, VIAL',
72
66
  icon: icons.zap,
73
- iconColor: '#ef4444',
74
- iconBg: '#fee2e2',
75
67
  },
76
68
  {
77
69
  id: 'method',
78
70
  label: 'Method & Path',
79
71
  subtitle: 'Select method',
80
72
  icon: icons.route,
81
- iconColor: '#8b5cf6',
82
- iconBg: '#ede9fe',
83
73
  defaultOpen: false,
84
74
  },
85
75
  ],
@@ -93,16 +83,12 @@ const simplePanels: Record<string, SidebarToolSection[]> = {
93
83
  label: 'Parameters',
94
84
  subtitle: 'Analysis settings',
95
85
  icon: ['M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z', 'M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8z'],
96
- iconColor: '#6366f1',
97
- iconBg: '#e0e7ff',
98
86
  },
99
87
  {
100
88
  id: 'filters',
101
89
  label: 'Filters',
102
90
  subtitle: 'Refine results',
103
91
  icon: ['M22 3H2l8 9.46V19l4 2v-8.54L22 3'],
104
- iconColor: '#0ea5e9',
105
- iconBg: '#e0f2fe',
106
92
  defaultOpen: false,
107
93
  },
108
94
  ],
@@ -112,16 +98,12 @@ const simplePanels: Record<string, SidebarToolSection[]> = {
112
98
  label: 'Display Options',
113
99
  subtitle: 'Chart and table settings',
114
100
  icon: ['M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z', 'M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z'],
115
- iconColor: '#8b5cf6',
116
- iconBg: '#ede9fe',
117
101
  },
118
102
  {
119
103
  id: 'export',
120
104
  label: 'Export',
121
105
  subtitle: 'Download data',
122
106
  icon: ['M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4', 'M7 10l5 5 5-5', 'M12 15V3'],
123
- iconColor: '#10b981',
124
- iconBg: '#d1fae5',
125
107
  defaultOpen: false,
126
108
  },
127
109
  ],
@@ -163,8 +145,6 @@ const schemaControls = defineControls({
163
145
  view: 'analysis',
164
146
  sidebar: {
165
147
  icon: icons.settings,
166
- iconColor: '#6366f1',
167
- iconBg: '#e0e7ff',
168
148
  },
169
149
  },
170
150
  method: {
@@ -180,16 +160,12 @@ const schemaControls = defineControls({
180
160
  default: true,
181
161
  hint: 'Keep flagged points visible',
182
162
  icon: icons.eye,
183
- iconColor: '#0ea5e9',
184
- iconBg: '#e0f2fe',
185
163
  section: 'display',
186
164
  sectionLabel: 'Display',
187
165
  sectionSubtitle: 'Result filters',
188
166
  view: 'analysis',
189
167
  sidebar: {
190
168
  icon: icons.zap,
191
- iconColor: '#0ea5e9',
192
- iconBg: '#e0f2fe',
193
169
  defaultOpen: false,
194
170
  },
195
171
  },
@@ -215,8 +191,6 @@ const modelDrivenSidebarModel = defineControlModel({
215
191
  description: 'Result cleanup',
216
192
  sidebar: {
217
193
  icon: icons.zap,
218
- iconColor: '#0ea5e9',
219
- iconBg: '#e0f2fe',
220
194
  defaultOpen: false,
221
195
  },
222
196
  controls: {
@@ -225,8 +199,6 @@ const modelDrivenSidebarModel = defineControlModel({
225
199
  default: true,
226
200
  hint: 'Keep flagged points visible',
227
201
  icon: icons.eye,
228
- iconColor: '#0ea5e9',
229
- iconBg: '#e0f2fe',
230
202
  },
231
203
  minPeakArea: { type: 'number', default: 1000, min: 0 },
232
204
  },
@@ -1,7 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import AppTopBar from './AppTopBar.vue'
3
3
  import Avatar from './Avatar.vue'
4
+ import PluginIcon from './PluginIcon.vue'
4
5
  import { ExperimentProvider } from '../__stories__/experiment-helpers'
6
+ import { providePluginIdentity } from '../composables/pluginIdentity'
7
+ import type { App } from 'vue'
5
8
  import type {
6
9
  TopBarVariant,
7
10
  PillNavItem,
@@ -59,6 +62,25 @@ const samplePlugin: PluginInfo = {
59
62
  settings_api: 'platform',
60
63
  }
61
64
 
65
+ const samplePluginWithSubtitle: PluginInfo = {
66
+ ...samplePlugin,
67
+ id: 'ms-planner',
68
+ name: 'ms-planner',
69
+ display_name: 'MS Planner',
70
+ subtitle: 'Experiment Scheduler',
71
+ icon: 'calendar',
72
+ route_prefix: '/ms-planner',
73
+ api_prefix: '/api/ms-planner',
74
+ }
75
+
76
+ // The seed is module state: clear it when the variant unmounts.
77
+ function seedIdentity({ app }: { app: App }) {
78
+ providePluginIdentity({
79
+ plugin: { name: 'ms-planner', displayName: 'MS Planner', subtitle: 'Experiment Scheduler', icon: 'calendar' },
80
+ })
81
+ app.onUnmount(() => providePluginIdentity({ plugin: { name: '' } }))
82
+ }
83
+
62
84
  </script>
63
85
 
64
86
  <template>
@@ -82,18 +104,7 @@ const samplePlugin: PluginInfo = {
82
104
  pill="experiments"
83
105
  >
84
106
  <template #icon>
85
- <div
86
- style="width: 2.25rem; height: 2.25rem; border-radius: 0.5rem; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #F97316 0%, #FB923C 100%);"
87
- >
88
- <svg
89
- style="width: 1.25rem; height: 1.25rem; color: white;"
90
- fill="none"
91
- stroke="currentColor"
92
- viewBox="0 0 24 24"
93
- >
94
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
95
- </svg>
96
- </div>
107
+ <PluginIcon size="topbar" />
97
108
  </template>
98
109
  </AppTopBar>
99
110
  </div>
@@ -223,6 +234,20 @@ const samplePlugin: PluginInfo = {
223
234
  </div>
224
235
  </Variant>
225
236
 
237
+ <Variant title="Identity · Integrated with subtitle">
238
+ <div style="padding: 2rem; background: var(--bg-primary); min-height: 12rem;">
239
+ <ExperimentProvider :plugin="samplePluginWithSubtitle">
240
+ <AppTopBar :spec="{ pills: samplePillNav, homePath: '' }" pill="workspace" />
241
+ </ExperimentProvider>
242
+ </div>
243
+ </Variant>
244
+
245
+ <Variant title="Identity · Standalone seeded" :setup-app="seedIdentity">
246
+ <div style="padding: 2rem;">
247
+ <AppTopBar :spec="{ pills: samplePillNav, homePath: '' }" pill="workspace" />
248
+ </div>
249
+ </Variant>
250
+
226
251
  <Variant title="Navigation · Page selector">
227
252
  <div style="padding: 2rem;">
228
253
  <AppTopBar
@@ -244,6 +269,16 @@ const samplePlugin: PluginInfo = {
244
269
  </div>
245
270
  </Variant>
246
271
 
272
+ <Variant title="Navigation · Pill nav overflow (More)">
273
+ <div style="padding: 2rem; min-height: 14rem;">
274
+ <AppTopBar
275
+ :spec="{ pills: ['Queue', 'Calendar', 'Utilization', 'Instruments', 'Reports', 'Settings', 'Logs'], homePath: '' }"
276
+ title="MS Planner"
277
+ pill="Reports"
278
+ />
279
+ </div>
280
+ </Variant>
281
+
247
282
  <Variant title="Navigation · Pill nav with dropdown and dot">
248
283
  <div style="padding: 2rem;">
249
284
  <AppTopBar