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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/{AlertBox-B2Bgr3ei.js → AlertBox-BdoZqANv.js} +2 -2
  2. package/dist/{AlertBox-B2Bgr3ei.js.map → AlertBox-BdoZqANv.js.map} +1 -1
  3. package/dist/{AppSidebar-mvm--GxN.js → AppSidebar-CIXJBzDv.js} +237 -70
  4. package/dist/{AppSidebar-mvm--GxN.js.map → AppSidebar-CIXJBzDv.js.map} +1 -1
  5. package/dist/{ExperimentPopover-5T1fAq2L.js → ExperimentPopover-CbD7BR_s.js} +2 -2
  6. package/dist/{ExperimentPopover-5T1fAq2L.js.map → ExperimentPopover-CbD7BR_s.js.map} +1 -1
  7. package/dist/{ExperimentSelectorModal-65peG4Up.js → ExperimentSelectorModal-BbFtr1Fr.js} +112 -96
  8. package/dist/ExperimentSelectorModal-BbFtr1Fr.js.map +1 -0
  9. package/dist/{SegmentedControl-BtnnjWzs.js → SegmentedControl-BkwYOKpG.js} +2 -2
  10. package/dist/{SegmentedControl-BtnnjWzs.js.map → SegmentedControl-BkwYOKpG.js.map} +1 -1
  11. package/dist/{SettingsModal-DO3IZ7qz.js → SettingsModal-CdhFMi8j.js} +25 -24
  12. package/dist/SettingsModal-CdhFMi8j.js.map +1 -0
  13. package/dist/__stories__/experiment-helpers.d.ts +10 -0
  14. package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
  15. package/dist/components/AppTopBar.vue.d.ts +13 -5
  16. package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -1
  17. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -1
  18. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
  19. package/dist/{controlSchemaModel-B8CTXagP.js → controlSchemaModel-BF5g4wRC.js} +2 -2
  20. package/dist/{controlSchemaModel-B8CTXagP.js.map → controlSchemaModel-BF5g4wRC.js.map} +1 -1
  21. package/dist/{data-CgILxDLW.js → data-DUt0TIp5.js} +10 -10
  22. package/dist/{data-CgILxDLW.js.map → data-DUt0TIp5.js.map} +1 -1
  23. package/dist/data.js +7 -7
  24. package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
  25. package/dist/experiment-DyO54FQB.js.map +1 -0
  26. package/dist/index.js +18 -18
  27. package/dist/{install-mB8-IyvO.js → install-Czoe1rA8.js} +13 -13
  28. package/dist/{install-mB8-IyvO.js.map → install-Czoe1rA8.js.map} +1 -1
  29. package/dist/install.js +1 -1
  30. package/dist/{lab-D5bIX426.js → lab-B-pLwc5U.js} +10 -10
  31. package/dist/{lab-D5bIX426.js.map → lab-B-pLwc5U.js.map} +1 -1
  32. package/dist/lab.js +4 -4
  33. package/dist/{records-B6gpM_3e.js → records-DnK_1Q_S.js} +2 -2
  34. package/dist/{records-B6gpM_3e.js.map → records-DnK_1Q_S.js.map} +1 -1
  35. package/dist/{runtime-D7vKpfbF.js → runtime-fPb_FEZr.js} +9 -9
  36. package/dist/{runtime-D7vKpfbF.js.map → runtime-fPb_FEZr.js.map} +1 -1
  37. package/dist/runtime.js +7 -7
  38. package/dist/{shell-CywENwBT.js → shell-lDf_EY-x.js} +4 -4
  39. package/dist/{shell-CywENwBT.js.map → shell-lDf_EY-x.js.map} +1 -1
  40. package/dist/shell.js +4 -4
  41. package/dist/stores/index.d.ts +1 -1
  42. package/dist/stores/index.js +2 -2
  43. package/dist/stores/settings.d.ts +4 -12
  44. package/dist/styles.css +409 -60
  45. package/dist/types/index.d.ts +1 -1
  46. package/dist/types/jobs.d.ts +9 -0
  47. package/dist/types/platform.d.ts +1 -1
  48. package/dist/{useExperimentSamples-DHnxKFAF.js → useExperimentSamples-BGN1dmcR.js} +4 -4
  49. package/dist/{useExperimentSamples-DHnxKFAF.js.map → useExperimentSamples-BGN1dmcR.js.map} +1 -1
  50. package/dist/{useListReorder-BitdUhxn.js → useListReorder-DPynGrCj.js} +3 -3
  51. package/dist/{useListReorder-BitdUhxn.js.map → useListReorder-DPynGrCj.js.map} +1 -1
  52. package/dist/{useRackEditor-Q8xO-cCy.js → useRackEditor-B2FrQA0p.js} +7 -7
  53. package/dist/{useRackEditor-Q8xO-cCy.js.map → useRackEditor-B2FrQA0p.js.map} +1 -1
  54. package/dist/{useRealtime-C3iy9QkU.js → useRealtime-yWjTTnc9.js} +2 -2
  55. package/dist/{useRealtime-C3iy9QkU.js.map → useRealtime-yWjTTnc9.js.map} +1 -1
  56. package/dist/{useRequest-D506eHi8.js → useRequest-Dqw12k2s.js} +3 -3
  57. package/dist/{useRequest-D506eHi8.js.map → useRequest-Dqw12k2s.js.map} +1 -1
  58. package/package.json +1 -1
  59. package/src/__stories__/experiment-helpers.ts +3 -3
  60. package/src/__tests__/components/AppTopBar.test.ts +175 -1
  61. package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
  62. package/src/__tests__/components/ExperimentSelectorModal.test.ts +34 -1
  63. package/src/__tests__/components/SettingsModal.test.ts +9 -2
  64. package/src/__tests__/stores/settings.test.ts +21 -21
  65. package/src/__tests__/styles/menusShellRefresh.test.ts +8 -2
  66. package/src/__tests__/styles/paletteTokens.test.ts +44 -0
  67. package/src/components/AppTopBar.story.vue +59 -4
  68. package/src/components/AppTopBar.vue +107 -8
  69. package/src/components/ExperimentSelectorModal.story.vue +38 -0
  70. package/src/components/ExperimentSelectorModal.vue +20 -1
  71. package/src/components/SettingsModal.vue +7 -12
  72. package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
  73. package/src/stores/index.ts +0 -2
  74. package/src/stores/settings.ts +20 -50
  75. package/src/styles/components/app-page-selector.css +120 -45
  76. package/src/styles/components/app-top-bar.css +155 -0
  77. package/src/styles/components/experiment-selector-modal.css +13 -0
  78. package/src/styles/variables.css +121 -15
  79. package/src/types/index.ts +1 -0
  80. package/src/types/jobs.ts +10 -0
  81. package/src/types/platform.ts +1 -1
  82. package/dist/ExperimentSelectorModal-65peG4Up.js.map +0 -1
  83. package/dist/SettingsModal-DO3IZ7qz.js.map +0 -1
  84. package/dist/experiment-43OJtH7R.js.map +0 -1
package/dist/styles.css CHANGED
@@ -359,13 +359,8 @@
359
359
  where --text-secondary would drop to ~4.35:1. */
360
360
  --text-secondary-strong: #475569;
361
361
 
362
- /* Brand colors — one teal accent: teal-600 fills, teal-700 hover + ink,
363
- teal-800 pressed. White on #0D9488 is 3.74:1, a known AA exception. */
364
- --color-primary: #0D9488;
365
- --color-primary-hover: #0F766E;
366
- --color-primary-pressed: #115E59;
367
- --color-primary-soft: rgba(13, 148, 136, 0.10);
368
- --color-primary-border: #99F6E4;
362
+ /* Brand colors: the accent (--color-primary*) comes from the palette
363
+ blocks below the dark block (html[data-palette], default teal). */
369
364
  /* Fixed teal scale, the same in both themes. */
370
365
  --color-primary-50: #F0FDFA;
371
366
  --color-primary-100: #CCFBF1;
@@ -483,7 +478,7 @@
483
478
  /* Soft focus rings — 3px translucent. Used by all form primitives
484
479
  post-0.16 visual refresh. Solid variants above kept for legacy
485
480
  components that haven't migrated yet. */
486
- --focus-ring-soft: 0 0 0 3px rgba(13, 148, 136, 0.18);
481
+ --focus-ring-soft: 0 0 0 3px color-mix(in srgb, var(--color-primary) 18%, transparent);
487
482
  /* Red is perceptually brighter than teal at equal alpha; drop 2pp to keep visual weight matched. */
488
483
  --focus-ring-soft-error: 0 0 0 3px rgba(239, 68, 68, 0.18);
489
484
 
@@ -521,12 +516,7 @@ html.dark {
521
516
  --border-light: #172033;
522
517
  --border-strong: #334155;
523
518
 
524
- /* Brand colors - Dark mode (CTA, purple and entity aliases follow) */
525
- --color-primary: #2DD4BF;
526
- --color-primary-hover: #5EEAD4;
527
- --color-primary-pressed: #99F6E4;
528
- --color-primary-soft: rgba(45, 212, 191, 0.12);
529
- --color-primary-border: rgba(45, 212, 191, 0.35);
519
+ /* Brand colors - Dark mode: the accent comes from the palette blocks below. */
530
520
  /* Dark ink on the light accent fill (10.1:1 on #2DD4BF). */
531
521
  --text-on-accent: #0B1120;
532
522
  --color-experiment-hover: #E2E8F0;
@@ -562,7 +552,7 @@ html.dark {
562
552
 
563
553
  /* Focus ring - dark mode offset uses bg-primary instead of white */
564
554
  --focus-ring-offset: 0 0 0 2px var(--bg-primary), 0 0 0 4px var(--color-primary);
565
- --focus-ring-soft: 0 0 0 3px rgba(45, 212, 191, 0.22);
555
+ --focus-ring-soft: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent);
566
556
  --focus-ring-soft-error: 0 0 0 3px rgba(248, 113, 113, 0.26);
567
557
 
568
558
  /* Legacy aliases */
@@ -572,6 +562,122 @@ html.dark {
572
562
  color-scheme: dark;
573
563
  }
574
564
 
565
+ /* Accent palettes (Settings → Color palette). The settings store writes
566
+ html[data-palette]; the palette swatches set the same attribute on their
567
+ strip to preview a palette. Each palette is one accent in both themes: white
568
+ text on the light-mode fill, dark text (--text-on-accent) on the dark-mode
569
+ fill. Hues come from the biology plot-style palettes. */
570
+
571
+ /* Teal (default): teal-600 fill, teal-700 hover + ink, teal-800 pressed.
572
+ White on #0D9488 is 3.74:1, a known AA exception. */
573
+ :root,
574
+ [data-palette="default"] {
575
+ --color-primary: #0D9488;
576
+ --color-primary-hover: #0F766E;
577
+ --color-primary-pressed: #115E59;
578
+ --color-primary-soft: rgba(13, 148, 136, 0.10);
579
+ --color-primary-border: #99F6E4;
580
+ }
581
+ html.dark,
582
+ html.dark [data-palette="default"] {
583
+ --color-primary: #2DD4BF;
584
+ --color-primary-hover: #5EEAD4;
585
+ --color-primary-pressed: #99F6E4;
586
+ --color-primary-soft: rgba(45, 212, 191, 0.12);
587
+ --color-primary-border: rgba(45, 212, 191, 0.35);
588
+ }
589
+
590
+ /* Colour-blind safe: Okabe-Ito blue accent, and Okabe-Ito bluish green,
591
+ vermilion and orange for status, so success and error differ for every
592
+ colour-vision type. White on #0072B2 is 5.19:1. */
593
+ :root[data-palette="colorblind"],
594
+ [data-palette="colorblind"] {
595
+ --color-primary: #0072B2;
596
+ --color-primary-hover: #005F94;
597
+ --color-primary-pressed: #004C77;
598
+ --color-primary-soft: rgba(0, 114, 178, 0.10);
599
+ --color-primary-border: #B3D5EA;
600
+ --mint-success: #009E73;
601
+ --mint-success-hover: #00805D;
602
+ --mint-success-bg: rgba(0, 158, 115, 0.1);
603
+ --mint-success-border: rgba(0, 158, 115, 0.3);
604
+ --mint-error: #D55E00;
605
+ --mint-error-hover: #B34E00;
606
+ --mint-error-bg: rgba(213, 94, 0, 0.1);
607
+ --mint-error-border: rgba(213, 94, 0, 0.3);
608
+ --mint-warning: #E69F00;
609
+ --mint-warning-hover: #C78800;
610
+ --mint-warning-bg: rgba(230, 159, 0, 0.1);
611
+ --mint-warning-border: rgba(230, 159, 0, 0.3);
612
+ --mint-warning-text: #8F5F00;
613
+ }
614
+ html.dark[data-palette="colorblind"],
615
+ html.dark [data-palette="colorblind"] {
616
+ --color-primary: #56B4E9;
617
+ --color-primary-hover: #7CC5EE;
618
+ --color-primary-pressed: #A3D6F3;
619
+ --color-primary-soft: rgba(86, 180, 233, 0.14);
620
+ --color-primary-border: rgba(86, 180, 233, 0.38);
621
+ --mint-success-bg: rgba(0, 158, 115, 0.15);
622
+ --mint-error-bg: rgba(213, 94, 0, 0.15);
623
+ --mint-warning-bg: rgba(230, 159, 0, 0.15);
624
+ --mint-warning-text: #FCD34D;
625
+ }
626
+
627
+ /* Purple: plot-style purple #8781bd, deepened so white text is 5.15:1. */
628
+ :root[data-palette="purple"],
629
+ [data-palette="purple"] {
630
+ --color-primary: #6B64B0;
631
+ --color-primary-hover: #5A539E;
632
+ --color-primary-pressed: #4A448A;
633
+ --color-primary-soft: rgba(107, 100, 176, 0.10);
634
+ --color-primary-border: #D3D0EC;
635
+ }
636
+ html.dark[data-palette="purple"],
637
+ html.dark [data-palette="purple"] {
638
+ --color-primary: #A9A3DB;
639
+ --color-primary-hover: #C2BDE7;
640
+ --color-primary-pressed: #D8D4F1;
641
+ --color-primary-soft: rgba(169, 163, 219, 0.14);
642
+ --color-primary-border: rgba(169, 163, 219, 0.38);
643
+ }
644
+
645
+ /* Ocean: plot-style ocean ramp, #2171B5 fill (white 5.13:1), #6BAED6 dark. */
646
+ :root[data-palette="ocean"],
647
+ [data-palette="ocean"] {
648
+ --color-primary: #2171B5;
649
+ --color-primary-hover: #1B5F99;
650
+ --color-primary-pressed: #164E7E;
651
+ --color-primary-soft: rgba(33, 113, 181, 0.10);
652
+ --color-primary-border: #BBD7EE;
653
+ }
654
+ html.dark[data-palette="ocean"],
655
+ html.dark [data-palette="ocean"] {
656
+ --color-primary: #6BAED6;
657
+ --color-primary-hover: #8EC2E2;
658
+ --color-primary-pressed: #B0D5EC;
659
+ --color-primary-soft: rgba(107, 174, 214, 0.14);
660
+ --color-primary-border: rgba(107, 174, 214, 0.38);
661
+ }
662
+
663
+ /* Forest: plot-style forest_clay, #2F6B4F fill (white 6.29:1), #7AA874 dark. */
664
+ :root[data-palette="forest"],
665
+ [data-palette="forest"] {
666
+ --color-primary: #2F6B4F;
667
+ --color-primary-hover: #275A42;
668
+ --color-primary-pressed: #1F4935;
669
+ --color-primary-soft: rgba(47, 107, 79, 0.10);
670
+ --color-primary-border: #BFD8C6;
671
+ }
672
+ html.dark[data-palette="forest"],
673
+ html.dark [data-palette="forest"] {
674
+ --color-primary: #7AA874;
675
+ --color-primary-hover: #95BC90;
676
+ --color-primary-pressed: #B1CFAD;
677
+ --color-primary-soft: rgba(122, 168, 116, 0.14);
678
+ --color-primary-border: rgba(122, 168, 116, 0.38);
679
+ }
680
+
575
681
  /* Comfortable density (html[data-density], written by the settings store):
576
682
  the pre-v2 control heights and a wider gutter. */
577
683
  [data-density="comfortable"] {
@@ -2397,6 +2503,161 @@ button, input, select, textarea {
2397
2503
  white-space: nowrap;
2398
2504
  user-select: none;
2399
2505
  }
2506
+
2507
+ /* ─── Run slot: [ experiment | job ] ───
2508
+ While a job shows, one border wraps the experiment chip and the job
2509
+ segment, as the experiment popover does for Save. The wrapper does not
2510
+ clip: the popover panel and the focus rings reach outside it, so each
2511
+ segment rounds its own outer corners. The idle Jobs button stands apart
2512
+ with its own border. */
2513
+ .mint-topbar__run-slot {
2514
+ display: inline-flex;
2515
+ align-items: center;
2516
+ gap: 0.5rem;
2517
+ min-width: 0;
2518
+ }
2519
+
2520
+ .mint-topbar__run-slot--joined {
2521
+ gap: 0;
2522
+ border: 1px solid var(--border-color);
2523
+ border-radius: var(--radius-md);
2524
+ background: var(--bg-card);
2525
+ }
2526
+
2527
+ .mint-topbar__run-slot--joined .mint-experiment-popover,
2528
+ .mint-topbar__run-slot--joined .mint-experiment-popover__trigger {
2529
+ border: 0;
2530
+ border-radius: calc(var(--radius-md) - 1px) 0 0 calc(var(--radius-md) - 1px);
2531
+ }
2532
+
2533
+ /* The job takes the name's place: the name folds away while the job grows in,
2534
+ and the code badge stays. The name stays in the accessible name. A trigger
2535
+ with no code, the empty placeholder and the error text keep their text. */
2536
+ .mint-topbar__run-slot .mint-experiment-popover__trigger-text {
2537
+ transition:
2538
+ max-width 200ms ease,
2539
+ opacity 150ms ease,
2540
+ margin 200ms ease;
2541
+ }
2542
+
2543
+ .mint-topbar__run-slot--joined
2544
+ .mint-experiment-popover__trigger:has(.mint-exp-code)
2545
+ .mint-experiment-popover__trigger-text {
2546
+ max-width: 0 !important; /* beats the inline maxNameWidth */
2547
+ margin-inline-start: -0.5rem; /* takes back the trigger gap */
2548
+ opacity: 0;
2549
+ }
2550
+
2551
+ .mint-topbar__job {
2552
+ display: inline-flex;
2553
+ max-width: 6rem; /* close to the content (icon + bar, or "Jobs"), so the fold is even */
2554
+ overflow: hidden;
2555
+ align-items: center;
2556
+ gap: 0.375rem;
2557
+ flex-shrink: 0;
2558
+ height: 30px;
2559
+ padding: 0 0.625rem;
2560
+ border: 0;
2561
+ background: transparent;
2562
+ color: var(--text-secondary);
2563
+ font: inherit;
2564
+ font-size: 0.75rem;
2565
+ font-weight: 500;
2566
+ white-space: nowrap;
2567
+ cursor: pointer;
2568
+ transition: background-color var(--mint-transition);
2569
+ }
2570
+
2571
+ .mint-topbar__run-slot--joined .mint-topbar__job {
2572
+ border-radius: calc(var(--radius-md) - 1px);
2573
+ }
2574
+
2575
+ .mint-topbar__run-slot--joined .mint-experiment-popover + .mint-topbar__job {
2576
+ border-left: 1px solid var(--border-color);
2577
+ border-radius: 0 calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px) 0;
2578
+ }
2579
+
2580
+ .mint-topbar__job--idle {
2581
+ height: 32px;
2582
+ border: 1px solid var(--border-color);
2583
+ border-radius: var(--radius-md);
2584
+ background: var(--bg-card);
2585
+ }
2586
+
2587
+ .mint-topbar__job--idle:hover,
2588
+ .mint-topbar__job--neutral:hover {
2589
+ background: var(--bg-hover);
2590
+ }
2591
+
2592
+ .mint-topbar__job:focus-visible {
2593
+ outline: none;
2594
+ box-shadow: inset var(--focus-ring);
2595
+ }
2596
+
2597
+ .mint-topbar__job--primary { background: var(--color-primary-soft); color: var(--_ink-primary); }
2598
+ .mint-topbar__job--warning { background: var(--mint-warning-bg); color: var(--mint-warning-text); }
2599
+ .mint-topbar__job--success { background: var(--mint-success-bg); color: color-mix(in srgb, var(--mint-success) 50%, var(--text-primary)); }
2600
+ .mint-topbar__job--error { background: var(--mint-error-bg); color: var(--_ink-error); }
2601
+
2602
+ .mint-topbar__job--primary:hover,
2603
+ .mint-topbar__job--warning:hover,
2604
+ .mint-topbar__job--success:hover,
2605
+ .mint-topbar__job--error:hover {
2606
+ filter: brightness(0.97);
2607
+ }
2608
+
2609
+ .mint-topbar__job-icon {
2610
+ flex-shrink: 0;
2611
+ }
2612
+
2613
+ .mint-topbar__job-icon--spin {
2614
+ animation: mint-topbar-job-spin 1s linear infinite;
2615
+ }
2616
+
2617
+ @keyframes mint-topbar-job-spin {
2618
+ to { transform: rotate(360deg); }
2619
+ }
2620
+
2621
+ .mint-topbar__job-bar {
2622
+ width: 2rem;
2623
+ height: 4px;
2624
+ border-radius: 2px;
2625
+ background: var(--border-color);
2626
+ overflow: hidden;
2627
+ }
2628
+
2629
+ .mint-topbar__job-bar > span {
2630
+ display: block;
2631
+ height: 100%;
2632
+ background: var(--color-primary);
2633
+ transition: width var(--mint-transition);
2634
+ }
2635
+
2636
+ /* Enter and leave: the job grows in from zero width and folds back out. */
2637
+ .mint-topbar-job-enter-active,
2638
+ .mint-topbar-job-leave-active {
2639
+ transition:
2640
+ max-width 200ms ease,
2641
+ padding 200ms ease,
2642
+ opacity 150ms ease;
2643
+ }
2644
+
2645
+ .mint-topbar-job-enter-from,
2646
+ .mint-topbar-job-leave-to {
2647
+ max-width: 0;
2648
+ padding-inline: 0;
2649
+ opacity: 0;
2650
+ }
2651
+
2652
+ /* Screen-reader only: announces status changes of the shown job. */
2653
+ .mint-topbar__job-status {
2654
+ position: absolute;
2655
+ width: 1px;
2656
+ height: 1px;
2657
+ overflow: hidden;
2658
+ clip-path: inset(50%);
2659
+ white-space: nowrap;
2660
+ }
2400
2661
  /* BaseButton Component Styles */
2401
2662
 
2402
2663
  .mint-button {
@@ -16679,13 +16940,26 @@ button.mint-unit-input__unit:focus-visible {
16679
16940
  }
16680
16941
 
16681
16942
  /* Footer with clear selection */
16943
+ .mint-experiment-selector__description {
16944
+ padding: 0 1.25rem 0.75rem;
16945
+ font-size: 0.8125rem;
16946
+ color: var(--text-secondary);
16947
+ }
16948
+
16682
16949
  .mint-experiment-selector__footer {
16683
16950
  display: flex;
16951
+ align-items: center;
16952
+ gap: 0.75rem;
16684
16953
  justify-content: flex-start;
16685
16954
  padding: 0.5rem 1.25rem 0.75rem;
16686
16955
  border-top: 1px solid var(--border-light);
16687
16956
  }
16688
16957
 
16958
+ .mint-experiment-selector__footer-slot {
16959
+ flex: 1;
16960
+ min-width: 0;
16961
+ }
16962
+
16689
16963
  .mint-experiment-selector__clear-btn {
16690
16964
  padding: 0.25rem 0;
16691
16965
  border: none;
@@ -17226,54 +17500,79 @@ button.mint-unit-input__unit:focus-visible {
17226
17500
  animation: none;
17227
17501
  }
17228
17502
  }
17229
- /* AppTopBar page selector — left-side route/page dropdown.
17230
- Trigger speaks the field language (5a): 36px (the identity tile height), hover changes the background
17231
- only, open = field focus, inline 12px chevron. The menu keeps the 1.2 panel
17232
- (own card, tinted active row) rather than .mint-popover + .mint-menu-item. */
17503
+ /* AppTopBar page selector — design v2 option C: "<plugin> / <page>" as one switcher.
17504
+ The crumb holds the plugin name, a slash and the tinted 32px trigger. The menu keeps its own
17505
+ card (not .mint-popover): a "<plugin> pages" title, then one row per page with its hint and number key. */
17506
+
17507
+ /* Shrinks with the bar: the plugin name and the page label truncate instead of overlapping the nav. */
17508
+ .mint-page-selector__crumb {
17509
+ display: inline-flex;
17510
+ align-items: center;
17511
+ gap: 0.375rem;
17512
+ min-width: 0;
17513
+ flex-shrink: 1;
17514
+ }
17515
+
17516
+ .mint-page-selector__plugin {
17517
+ min-width: 0;
17518
+ font-size: 0.875rem;
17519
+ font-weight: 600;
17520
+ color: var(--text-primary);
17521
+ white-space: nowrap;
17522
+ overflow: hidden;
17523
+ text-overflow: ellipsis;
17524
+ }
17525
+
17526
+ .mint-page-selector__slash {
17527
+ flex-shrink: 0;
17528
+ font-size: 1.125rem;
17529
+ font-weight: 300;
17530
+ line-height: 1;
17531
+ color: var(--text-muted);
17532
+ }
17233
17533
 
17234
- /* Shrinks down to its inline min-width (11.25rem) so a crowded bar truncates the label instead of overlapping the nav. */
17534
+ /* Anchors the menu under the trigger, not under the plugin name. */
17235
17535
  .mint-page-selector {
17236
17536
  position: relative;
17237
- flex-shrink: 1;
17537
+ display: flex;
17538
+ min-width: 0;
17238
17539
  }
17239
17540
 
17240
17541
  .mint-page-selector__trigger {
17241
17542
  display: inline-flex;
17242
17543
  align-items: center;
17243
- gap: 0.5rem;
17244
- width: 100%;
17245
- height: 2.25rem;
17246
- padding: 0 0.5rem 0 0.4375rem;
17247
- border: 1px solid var(--border-color);
17248
- background: var(--bg-card);
17544
+ gap: 0.375rem;
17545
+ min-width: 0;
17546
+ max-width: 100%;
17547
+ height: 2rem;
17548
+ padding: 0 0.5rem 0 0.375rem;
17549
+ border: 0;
17550
+ background: var(--color-primary-soft);
17249
17551
  color: var(--text-primary);
17250
17552
  border-radius: var(--radius-md);
17251
17553
  font-size: 0.8125rem;
17252
- font-weight: 500;
17554
+ font-weight: 600;
17253
17555
  font-family: inherit;
17254
17556
  cursor: pointer;
17255
17557
  transition:
17256
17558
  background-color var(--mint-transition),
17257
- border-color var(--mint-transition),
17258
17559
  box-shadow var(--mint-transition);
17259
17560
  }
17260
17561
 
17261
- .mint-page-selector__trigger:hover:not(.mint-page-selector__trigger--open) {
17262
- background: var(--bg-hover);
17562
+ .mint-page-selector__trigger:hover {
17563
+ background: color-mix(in srgb, var(--color-primary) 16%, transparent);
17263
17564
  }
17264
17565
 
17265
- .mint-page-selector__trigger:focus-visible,
17266
- .mint-page-selector__trigger--open {
17566
+ .mint-page-selector__trigger:focus-visible {
17267
17567
  outline: none;
17268
- border-color: var(--color-primary);
17269
- box-shadow: var(--focus-ring-soft);
17568
+ box-shadow: var(--focus-ring-offset);
17270
17569
  }
17271
17570
 
17272
17571
  /* Page icon tile is neutral; the plugin carries the color. */
17273
17572
  .mint-page-selector__icon {
17274
17573
  width: 1.25rem;
17275
17574
  height: 1.25rem;
17276
- border-radius: var(--radius-sm);
17575
+ border-radius: var(--radius);
17277
17576
  background: var(--bg-tertiary);
17278
17577
  color: var(--text-secondary-strong);
17279
17578
  display: grid;
@@ -17294,7 +17593,7 @@ button.mint-unit-input__unit:focus-visible {
17294
17593
  .mint-page-selector__trigger-metadata-icon.mint-plugin-icon--sm {
17295
17594
  width: 1.25rem;
17296
17595
  height: 1.25rem;
17297
- border-radius: var(--radius-sm);
17596
+ border-radius: var(--radius);
17298
17597
  }
17299
17598
 
17300
17599
  .mint-page-selector__icon-fallback {
@@ -17304,7 +17603,6 @@ button.mint-unit-input__unit:focus-visible {
17304
17603
  }
17305
17604
 
17306
17605
  .mint-page-selector__label {
17307
- flex: 1;
17308
17606
  min-width: 0;
17309
17607
  text-align: left;
17310
17608
  white-space: nowrap;
@@ -17312,7 +17610,6 @@ button.mint-unit-input__unit:focus-visible {
17312
17610
  text-overflow: ellipsis;
17313
17611
  }
17314
17612
 
17315
- /* The chevron sits inline; the wrap no longer draws a tile. */
17316
17613
  .mint-page-selector__chevron-wrap {
17317
17614
  display: inline-flex;
17318
17615
  color: var(--text-secondary);
@@ -17329,38 +17626,46 @@ button.mint-unit-input__unit:focus-visible {
17329
17626
  transform: rotate(180deg);
17330
17627
  }
17331
17628
 
17629
+ /* max-height: 8 two-line hint rows (8 x 68px) + title (~25px) + padding (8px) = ~577px; a 9th row scrolls. A short window caps it. */
17332
17630
  .mint-page-selector__menu {
17333
17631
  position: absolute;
17632
+ box-sizing: border-box;
17334
17633
  top: calc(100% + 0.375rem);
17335
17634
  left: 0;
17336
- width: 16.25rem;
17635
+ width: 18.75rem;
17636
+ max-height: min(36.25rem, calc(100vh - 6rem));
17637
+ overflow-y: auto;
17337
17638
  background: var(--bg-card);
17338
17639
  border: 1px solid var(--border-color);
17339
17640
  border-radius: var(--radius-lg);
17340
17641
  box-shadow: var(--shadow-md);
17341
- padding: 0.375rem;
17642
+ padding: 0.25rem;
17342
17643
  z-index: 50;
17343
17644
  }
17344
17645
 
17646
+ /* The mockup's 10px uppercase eyebrow breaks rules 2a (no uppercase) and 8d (UI text >= 11px): 11px, sentence case. */
17345
17647
  .mint-page-selector__menu-title {
17346
- padding: 0.375rem 0.625rem 0.5rem;
17347
- font-size: 0.75rem;
17648
+ padding: 0.375rem 0.5rem 0.25rem;
17649
+ font-family: var(--font-mono);
17650
+ font-size: 0.6875rem;
17348
17651
  font-weight: 500;
17349
- color: var(--text-secondary);
17652
+ letter-spacing: 0.06em;
17653
+ color: var(--text-muted);
17350
17654
  }
17351
17655
 
17352
17656
  .mint-page-selector__item {
17353
17657
  display: flex;
17354
- align-items: center;
17658
+ box-sizing: border-box;
17659
+ align-items: flex-start;
17355
17660
  gap: 0.625rem;
17356
17661
  width: 100%;
17357
- padding: 0.5rem 0.625rem;
17662
+ padding: 0.5rem;
17358
17663
  border: 0;
17359
17664
  background: transparent;
17360
- border-radius: 0.4375rem;
17665
+ border-radius: var(--radius);
17361
17666
  color: var(--text-primary);
17362
17667
  font-size: 0.8125rem;
17363
- font-weight: 500;
17668
+ line-height: 1.4;
17364
17669
  font-family: inherit;
17365
17670
  text-align: left;
17366
17671
  text-decoration: none;
@@ -17368,13 +17673,22 @@ button.mint-unit-input__unit:focus-visible {
17368
17673
  transition: background-color var(--mint-transition);
17369
17674
  }
17370
17675
 
17371
- .mint-page-selector__item:hover:not(.mint-page-selector__item--disabled) {
17676
+ /* A row without a hint has one line: centre it on the icon tile. */
17677
+ .mint-page-selector__item:not(:has(.mint-page-selector__item-hint)) {
17678
+ align-items: center;
17679
+ }
17680
+
17681
+ .mint-page-selector__item:hover:not(.mint-page-selector__item--disabled):not(.mint-page-selector__item--active) {
17372
17682
  background: var(--bg-hover);
17373
17683
  }
17374
17684
 
17685
+ .mint-page-selector__item:focus-visible {
17686
+ outline: 2px solid var(--color-primary);
17687
+ outline-offset: -2px;
17688
+ }
17689
+
17375
17690
  .mint-page-selector__item--active {
17376
- background: var(--bg-tertiary);
17377
- font-weight: 600;
17691
+ background: var(--color-primary-soft);
17378
17692
  }
17379
17693
 
17380
17694
  .mint-page-selector__item--disabled {
@@ -17383,9 +17697,9 @@ button.mint-unit-input__unit:focus-visible {
17383
17697
  }
17384
17698
 
17385
17699
  .mint-page-selector__item-icon {
17386
- width: 1.375rem;
17387
- height: 1.375rem;
17388
- border-radius: 0.3125rem;
17700
+ width: 1.75rem;
17701
+ height: 1.75rem;
17702
+ border-radius: var(--radius-md);
17389
17703
  background: var(--bg-tertiary);
17390
17704
  color: var(--text-secondary);
17391
17705
  display: grid;
@@ -17393,6 +17707,10 @@ button.mint-unit-input__unit:focus-visible {
17393
17707
  flex-shrink: 0;
17394
17708
  }
17395
17709
 
17710
+ .mint-page-selector__item-icon .mint-page-selector__icon-fallback {
17711
+ font-size: 0.8125rem;
17712
+ }
17713
+
17396
17714
  .mint-page-selector__item--active .mint-page-selector__item-icon {
17397
17715
  background: var(--color-primary-soft);
17398
17716
  color: var(--color-primary);
@@ -17405,24 +17723,55 @@ button.mint-unit-input__unit:focus-visible {
17405
17723
  }
17406
17724
 
17407
17725
  .mint-page-selector__item-icon svg {
17408
- width: 0.8125rem;
17409
- height: 0.8125rem;
17726
+ width: 0.9375rem;
17727
+ height: 0.9375rem;
17410
17728
  }
17411
17729
 
17412
17730
  .mint-page-selector__metadata-icon.mint-plugin-icon--sm {
17413
- width: 1.375rem;
17414
- height: 1.375rem;
17415
- border-radius: 0.3125rem;
17731
+ width: 1.75rem;
17732
+ height: 1.75rem;
17733
+ border-radius: var(--radius-md);
17416
17734
  }
17417
17735
 
17418
- .mint-page-selector__item-label {
17736
+ .mint-page-selector__item-text {
17419
17737
  flex: 1;
17420
17738
  min-width: 0;
17739
+ display: grid;
17740
+ gap: 1px;
17741
+ }
17742
+
17743
+ .mint-page-selector__item-label {
17744
+ font-weight: 600;
17421
17745
  overflow: hidden;
17422
17746
  text-overflow: ellipsis;
17423
17747
  white-space: nowrap;
17424
17748
  }
17425
17749
 
17750
+ /* --_ink-primary is --color-primary-hover in light mode and stays legible in dark mode. */
17751
+ .mint-page-selector__item--active .mint-page-selector__item-label {
17752
+ color: var(--_ink-primary);
17753
+ }
17754
+
17755
+ .mint-page-selector__item-hint {
17756
+ font-size: 0.75rem;
17757
+ line-height: 1.35;
17758
+ color: var(--text-secondary);
17759
+ }
17760
+
17761
+ /* 11px, the rule 8d floor (the mockup has 10.5px). */
17762
+ .mint-page-selector__item-key {
17763
+ flex-shrink: 0;
17764
+ margin-top: 0.125rem;
17765
+ padding: 0 0.25rem;
17766
+ border: 1px solid var(--border-color);
17767
+ border-radius: var(--radius);
17768
+ font-family: var(--font-mono);
17769
+ font-size: 0.6875rem;
17770
+ font-weight: 500;
17771
+ line-height: 1rem;
17772
+ color: var(--text-muted);
17773
+ }
17774
+
17426
17775
  @media (prefers-reduced-motion: reduce) {
17427
17776
  .mint-page-selector__trigger,
17428
17777
  .mint-page-selector__chevron {
@@ -3,7 +3,7 @@ export type * from './generated-ui';
3
3
  export type { AnalysisArtifactStatus, AnalysisArtifactStatusFilter, AnalysisArtifactSummary, AnalysisArtifactDetail, AnalysisArtifactListResponse, AnalysisArtifactTarget, AnalysisArtifactMetadataUpdate, ArtifactSaveMode, ArtifactFileSource, JsonArtifactSavePayload, FileArtifactCreatePayload, FileArtifactUpdatePayload, HandlerFileArtifactCreatePayload, HandlerFileArtifactUpdatePayload, ArtifactSavePayload, HandlerArtifactSavePayload, ArtifactSaveDialogPayload, ArtifactSaveResult, ArtifactSaveHandler, HandlerArtifactSaveHandler, ArtifactSaveDialogHandler, } from './analysisArtifactTypes';
4
4
  export { ANALYSIS_FILE_ARTIFACT_SCHEMA } from './analysisArtifactTypes';
5
5
  export type { FileBrowserLocation, FileBrowserSortKey, FileDirectoryListing, FileDirectoryTree, FileEntry, FileEntryKind, FilePathCrumb, FileSearchResult, FileSelection, ServerMount, } from './fileBrowserTypes';
6
- export type { JobListPayload, JobProgress, JobSnapshotPayload, JobState, JobStateInput, JobStatus, JobStreamData, } from './jobs';
6
+ export type { JobListPayload, JobProgress, JobSnapshotPayload, JobState, JobStateInput, JobStatus, JobStreamData, TopBarJob, } from './jobs';
7
7
  export type { InjectionMetricSeries, InstrumentAlert, InstrumentAlertLevel, InstrumentAlertList, InstrumentBadgeState, InstrumentLiveProgress, InstrumentLiveStatus, InstrumentState, InstrumentStatus, InstrumentStatusReporter, SampleInfo, SampleInfo as InstrumentSampleInfo, SequenceProgress, StatusPanel, } from './instrument';
8
8
  export type { AccessAudience, AccessAudienceInput, AccessPolicy, AccessControlled, PermissionUser, RoleInfo, } from '../permissions';
9
9
  export type { FormFieldType, FieldCondition, FieldValidation, FormFieldSchema, FormOptionInput, FormSectionSchema, FormStepSchema, FormSchema, FieldEnhancement, FormEnhancements, UseFormBuilderReturn, } from './form-builder';
@@ -53,3 +53,12 @@ export interface JobSnapshotPayload {
53
53
  jobs: JobStateInput[];
54
54
  }
55
55
  export type JobStreamData = JobStateInput | JobSnapshotPayload;
56
+ /** What the top-bar run slot shows for the viewer's own job. The plugin picks the job. */
57
+ export interface TopBarJob {
58
+ /** Lifecycle of the shown job; sets the icon and the tone. */
59
+ status: JobStatus;
60
+ /** Tooltip and accessible name, e.g. "Extracting", "Saved to EXP-0142". Not shown as text. */
61
+ label: string;
62
+ /** 0-100; drawn as a small bar after the icon. */
63
+ percent?: number | null;
64
+ }
@@ -50,5 +50,5 @@ export type PlatformContext = Partial<Omit<PlatformFrontendContext, 'plugin'>> &
50
50
  theme: ThemeMode;
51
51
  };
52
52
  export type ThemeMode = 'light' | 'dark' | 'system';
53
- export type ColorPalette = 'default' | 'colorblind' | 'viridis' | 'pastel';
53
+ export type ColorPalette = 'default' | 'colorblind' | 'purple' | 'ocean' | 'forest';
54
54
  export type TableDensity = 'compact' | 'normal' | 'comfortable';