@morscherlab/mint-sdk 1.0.0-beta.3 → 1.0.0-beta.5
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.
- package/README.md +9 -2
- package/dist/__tests__/composables/experiment-utils.test.d.ts +1 -0
- package/dist/__tests__/composables/useApi.test.d.ts +1 -0
- package/dist/components/AppContainer.vue.d.ts +1 -1
- package/dist/components/AppLayout.vue.d.ts +20 -1
- package/dist/components/AppSidebar.vue.d.ts +57 -5
- package/dist/components/AppTopBar.vue.d.ts +7 -25
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +3 -1
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -0
- package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +5 -0
- package/dist/components/ComponentBindingRenderer.vue.d.ts +44 -0
- package/dist/components/ControlWorkspaceView.vue.d.ts +24 -7
- package/dist/components/DoseDesignWorkspaceView.vue.d.ts +149 -0
- package/dist/components/ExperimentTimeline.vue.d.ts +1 -1
- package/dist/components/FormBuilder.vue.d.ts +9 -9
- package/dist/components/PlateMapEditor.vue.d.ts +1 -1
- package/dist/components/PluginWorkspaceView.vue.d.ts +310 -0
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/WellPlate.vue.d.ts +2 -2
- package/dist/components/index.d.ts +3 -12
- package/dist/components/index.js +3 -3
- package/dist/components/{AppPageSelector.vue.d.ts → internal/AppTopBarPageSelectorInternal.vue.d.ts} +1 -1
- package/dist/components/{AppPillNav.vue.d.ts → internal/AppTopBarPillNavInternal.vue.d.ts} +3 -1
- package/dist/components/{CalendarGridPanel.vue.d.ts → internal/CalendarGridPanelInternal.vue.d.ts} +1 -1
- package/dist/components/internal/FormSectionRenderer.vue.d.ts +4 -4
- package/dist/components/{WellEditPopup.vue.d.ts → internal/WellEditPopupInternal.vue.d.ts} +1 -1
- package/dist/{components-D_Sr0adg.js → components-DihbSJjU.js} +5932 -5408
- package/dist/components-DihbSJjU.js.map +1 -0
- package/dist/composables/experiment-utils.d.ts +8 -0
- package/dist/composables/index.d.ts +5 -7
- package/dist/composables/index.js +4 -4
- package/dist/composables/useAppExperiment.d.ts +31 -2
- package/dist/composables/useBioTemplateComponents.d.ts +5 -3
- package/dist/composables/useBioTemplatePackWorkspace.d.ts +3 -2
- package/dist/composables/useBioTemplatePresetWorkspace.d.ts +6 -5
- package/dist/composables/useBioTemplateWorkspace.d.ts +5 -4
- package/dist/composables/useControlSchema.d.ts +43 -21
- package/dist/composables/usePluginClient.d.ts +5 -2
- package/dist/{composables-C3dpXQN5.js → composables-BcgZ6diz.js} +40 -28
- package/dist/composables-BcgZ6diz.js.map +1 -0
- package/dist/index.d.ts +5 -12
- package/dist/index.js +5 -5
- package/dist/install.js +2 -2
- package/dist/styles.css +5637 -5663
- package/dist/templates/adapters.d.ts +7 -1
- package/dist/templates/catalog.d.ts +5 -5
- package/dist/templates/componentBindings.d.ts +13 -0
- package/dist/templates/index.d.ts +5 -5
- package/dist/templates/index.js +2 -2
- package/dist/templates/presets.d.ts +4 -4
- package/dist/templates/types.d.ts +4 -1
- package/dist/{templates-50NPjaxL.js → templates-Cyt0Suwf.js} +322 -73
- package/dist/templates-Cyt0Suwf.js.map +1 -0
- package/dist/types/components.d.ts +6 -25
- package/dist/types/index.d.ts +1 -1
- package/dist/{useScheduleDrag-D4oWdh41.js → useExperimentData-CM6Y0u5L.js} +400 -357
- package/dist/useExperimentData-CM6Y0u5L.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/components/ActionItem.test.ts +6 -6
- package/src/__tests__/components/AppLayout.test.ts +44 -0
- package/src/__tests__/components/AppSidebar.test.ts +130 -2
- package/src/__tests__/components/AppToastContainer.test.ts +0 -11
- package/src/__tests__/components/AppTopBar.test.ts +189 -120
- package/src/__tests__/components/{AppPageSelector.test.ts → AppTopBarPageSelector.test.ts} +8 -8
- package/src/__tests__/components/{AppPillNav.test.ts → AppTopBarPillNav.test.ts} +53 -6
- package/src/__tests__/components/BioTemplateExperimentWorkspaceView.test.ts +7 -1
- package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +32 -1
- package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +48 -1
- package/src/__tests__/components/BioTemplateRenderer.test.ts +25 -0
- package/src/__tests__/components/CalendarGridPanel.test.ts +3 -3
- package/src/__tests__/components/ComponentBindingRenderer.test.ts +278 -0
- package/src/__tests__/components/ControlWorkspaceView.test.ts +134 -63
- package/src/__tests__/components/DateTimePicker.test.ts +2 -2
- package/src/__tests__/components/DoseDesignWorkspaceView.test.ts +185 -0
- package/src/__tests__/components/PluginWorkspaceView.test.ts +548 -0
- package/src/__tests__/composables/experiment-utils.test.ts +30 -0
- package/src/__tests__/composables/useApi.test.ts +30 -0
- package/src/__tests__/composables/useAppExperiment.test.ts +100 -1
- package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +7 -4
- package/src/__tests__/composables/useBioTemplatePresetWorkspace.test.ts +7 -7
- package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +6 -1
- package/src/__tests__/composables/useControlSchema.test.ts +151 -37
- package/src/__tests__/composables/usePluginClient.test.ts +99 -2
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +120 -25
- package/src/__tests__/templates/templates.test.ts +56 -0
- package/src/components/AppAvatarMenu.vue +3 -3
- package/src/components/AppLayout.story.vue +39 -0
- package/src/components/AppLayout.vue +83 -2
- package/src/components/AppPluginSwitcher.vue +5 -5
- package/src/components/AppSidebar.story.vue +113 -5
- package/src/components/AppSidebar.vue +147 -27
- package/src/components/AppTopBar.story.vue +2 -5
- package/src/components/AppTopBar.vue +35 -425
- package/src/components/BioTemplateExperimentWorkspaceView.story.vue +2 -2
- package/src/components/BioTemplateExperimentWorkspaceView.vue +6 -0
- package/src/components/BioTemplatePackWorkspaceView.story.vue +4 -4
- package/src/components/BioTemplatePackWorkspaceView.vue +1 -0
- package/src/components/BioTemplatePresetWorkspaceView.story.vue +14 -2
- package/src/components/BioTemplatePresetWorkspaceView.vue +12 -3
- package/src/components/BioTemplateRenderer.story.vue +2 -2
- package/src/components/BioTemplateRenderer.vue +15 -227
- package/src/components/ComponentBindingRenderer.story.vue +87 -0
- package/src/components/ComponentBindingRenderer.vue +317 -0
- package/src/components/ControlWorkspaceView.story.vue +20 -9
- package/src/components/ControlWorkspaceView.vue +43 -12
- package/src/components/DatePicker.vue +2 -2
- package/src/components/DateTimePicker.vue +2 -2
- package/src/components/DoseDesignWorkspaceView.story.vue +77 -0
- package/src/components/DoseDesignWorkspaceView.vue +255 -0
- package/src/components/ExperimentPopover.story.vue +2 -2
- package/src/components/ExperimentPopover.vue +2 -6
- package/src/components/ExperimentSelectorModal.vue +6 -5
- package/src/components/FormBuilder.story.vue +190 -0
- package/src/components/PluginWorkspaceView.story.vue +334 -0
- package/src/components/PluginWorkspaceView.vue +708 -0
- package/src/components/SettingsModal.story.vue +87 -0
- package/src/components/WellPlate.vue +2 -2
- package/src/components/index.ts +3 -12
- package/src/components/{AppPageSelector.vue → internal/AppTopBarPageSelectorInternal.vue} +9 -9
- package/src/components/internal/AppTopBarPillNavInternal.vue +194 -0
- package/src/components/{CalendarGridPanel.vue → internal/CalendarGridPanelInternal.vue} +1 -1
- package/src/components/{WellEditPopup.vue → internal/WellEditPopupInternal.vue} +3 -3
- package/src/composables/experiment-utils.ts +26 -0
- package/src/composables/index.ts +21 -7
- package/src/composables/useApi.ts +9 -2
- package/src/composables/useAppExperiment.ts +85 -13
- package/src/composables/useBioTemplateComponents.ts +12 -0
- package/src/composables/useBioTemplatePackWorkspace.ts +6 -2
- package/src/composables/useBioTemplatePresetWorkspace.ts +10 -21
- package/src/composables/useBioTemplateWorkspace.ts +6 -4
- package/src/composables/useControlSchema.ts +157 -69
- package/src/composables/usePluginClient.ts +50 -9
- package/src/index.ts +6 -563
- package/src/styles/components/app-layout.css +82 -0
- package/src/styles/components/app-page-selector.css +1 -1
- package/src/styles/components/app-pill-nav.css +71 -1
- package/src/styles/components/app-sidebar.css +119 -0
- package/src/styles/components/app-top-bar.css +0 -235
- package/src/styles/components/experiment-popover.css +2 -2
- package/src/styles/index.css +0 -1
- package/src/templates/adapters.ts +193 -0
- package/src/templates/catalog.ts +5 -5
- package/src/templates/componentBindings.ts +90 -3
- package/src/templates/index.ts +10 -0
- package/src/templates/packs.ts +10 -1
- package/src/templates/presets.ts +14 -4
- package/src/templates/types.ts +4 -0
- package/src/types/components.ts +6 -31
- package/src/types/index.ts +2 -6
- package/dist/__tests__/composables/usePluginApi.test.d.ts +0 -13
- package/dist/components/FormFieldRenderer.vue.d.ts +0 -28
- package/dist/components/FormSection.vue.d.ts +0 -30
- package/dist/components/GroupingModal.vue.d.ts +0 -12
- package/dist/components/SettingsButton.vue.d.ts +0 -30
- package/dist/components/ToastNotification.vue.d.ts +0 -2
- package/dist/components-D_Sr0adg.js.map +0 -1
- package/dist/composables/usePluginApi.d.ts +0 -22
- package/dist/composables-C3dpXQN5.js.map +0 -1
- package/dist/templates-50NPjaxL.js.map +0 -1
- package/dist/useScheduleDrag-D4oWdh41.js.map +0 -1
- package/src/__tests__/components/FormCompatibility.test.ts +0 -94
- package/src/__tests__/components/GroupingModal.test.ts +0 -73
- package/src/__tests__/components/SettingsButton.test.ts +0 -44
- package/src/__tests__/composables/usePluginApi.test.ts +0 -81
- package/src/components/AppPillNav.vue +0 -71
- package/src/components/FormFieldRenderer.vue +0 -35
- package/src/components/FormSection.vue +0 -37
- package/src/components/GroupingModal.story.vue +0 -52
- package/src/components/GroupingModal.vue +0 -61
- package/src/components/SettingsButton.story.vue +0 -58
- package/src/components/SettingsButton.vue +0 -64
- package/src/components/ToastNotification.vue +0 -9
- package/src/composables/usePluginApi.ts +0 -32
- package/src/styles/components/settings-button.css +0 -31
- /package/dist/__tests__/components/{AppPageSelector.test.d.ts → AppTopBarPageSelector.test.d.ts} +0 -0
- /package/dist/__tests__/components/{AppPillNav.test.d.ts → AppTopBarPillNav.test.d.ts} +0 -0
- /package/dist/__tests__/components/{FormCompatibility.test.d.ts → ComponentBindingRenderer.test.d.ts} +0 -0
- /package/dist/__tests__/components/{GroupingModal.test.d.ts → DoseDesignWorkspaceView.test.d.ts} +0 -0
- /package/dist/__tests__/components/{SettingsButton.test.d.ts → PluginWorkspaceView.test.d.ts} +0 -0
- /package/dist/components/{ActionItem.vue.d.ts → internal/ActionItemInternal.vue.d.ts} +0 -0
- /package/src/components/{ActionItem.vue → internal/ActionItemInternal.vue} +0 -0
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* AppLayout - Page layout shell with topbar, sidebar, and main content slots
|
|
4
4
|
*
|
|
5
5
|
* Provides a responsive application layout structure with optional topbar and sidebar.
|
|
6
|
-
* The sidebar slot is a simple pass-through
|
|
6
|
+
* The sidebar slot is a simple pass-through on desktop. When responsiveSidebar is
|
|
7
|
+
* enabled, AppLayout owns the mobile toggle/backdrop shell around the sidebar.
|
|
7
8
|
*
|
|
8
9
|
* @example
|
|
9
10
|
* ```vue
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
* </AppLayout>
|
|
21
22
|
* ```
|
|
22
23
|
*/
|
|
23
|
-
import { computed } from 'vue'
|
|
24
|
+
import { computed, ref } from 'vue'
|
|
24
25
|
|
|
25
26
|
interface Props {
|
|
26
27
|
/** Position of sidebar (left or right side of screen) */
|
|
@@ -29,23 +30,61 @@ interface Props {
|
|
|
29
30
|
sidebarWidth?: string
|
|
30
31
|
/** When true, topbar/sidebar/main render as floating cards with gaps */
|
|
31
32
|
floating?: boolean
|
|
33
|
+
/** Convert the sidebar into a mobile overlay with built-in toggle and backdrop below 1024px. */
|
|
34
|
+
responsiveSidebar?: boolean
|
|
35
|
+
/** Controlled mobile sidebar open state. Desktop sidebar remains visible. */
|
|
36
|
+
sidebarOpen?: boolean
|
|
37
|
+
/** Initial mobile sidebar open state when sidebarOpen is uncontrolled. */
|
|
38
|
+
defaultSidebarOpen?: boolean
|
|
39
|
+
/** Accessible label for the mobile sidebar toggle. */
|
|
40
|
+
sidebarToggleLabel?: string
|
|
41
|
+
/** Accessible label used when the mobile sidebar is open. */
|
|
42
|
+
sidebarCloseLabel?: string
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
const props = withDefaults(defineProps<Props>(), {
|
|
35
46
|
sidebarPosition: 'left',
|
|
36
47
|
sidebarWidth: 'auto',
|
|
37
48
|
floating: false,
|
|
49
|
+
responsiveSidebar: false,
|
|
50
|
+
sidebarOpen: undefined,
|
|
51
|
+
defaultSidebarOpen: false,
|
|
52
|
+
sidebarToggleLabel: 'Open sidebar',
|
|
53
|
+
sidebarCloseLabel: 'Close sidebar',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const emit = defineEmits<{
|
|
57
|
+
'update:sidebarOpen': [value: boolean]
|
|
58
|
+
}>()
|
|
59
|
+
|
|
60
|
+
const internalSidebarOpen = ref(props.defaultSidebarOpen)
|
|
61
|
+
const sidebarOpenModel = computed({
|
|
62
|
+
get: () => props.sidebarOpen ?? internalSidebarOpen.value,
|
|
63
|
+
set: (value: boolean) => {
|
|
64
|
+
internalSidebarOpen.value = value
|
|
65
|
+
emit('update:sidebarOpen', value)
|
|
66
|
+
},
|
|
38
67
|
})
|
|
39
68
|
|
|
40
69
|
const layoutClasses = computed(() => [
|
|
41
70
|
'mint-layout',
|
|
42
71
|
props.sidebarPosition === 'right' ? 'mint-layout--sidebar-right' : '',
|
|
43
72
|
props.floating ? 'mint-layout--floating' : '',
|
|
73
|
+
props.responsiveSidebar ? 'mint-layout--responsive-sidebar' : '',
|
|
74
|
+
sidebarOpenModel.value ? 'mint-layout--sidebar-open' : '',
|
|
44
75
|
])
|
|
45
76
|
|
|
46
77
|
const sidebarStyle = computed(() => {
|
|
47
78
|
return props.sidebarWidth !== 'auto' ? { width: props.sidebarWidth } : undefined
|
|
48
79
|
})
|
|
80
|
+
|
|
81
|
+
function toggleSidebar() {
|
|
82
|
+
sidebarOpenModel.value = !sidebarOpenModel.value
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function closeSidebar() {
|
|
86
|
+
sidebarOpenModel.value = false
|
|
87
|
+
}
|
|
49
88
|
</script>
|
|
50
89
|
|
|
51
90
|
<template>
|
|
@@ -55,6 +94,48 @@ const sidebarStyle = computed(() => {
|
|
|
55
94
|
</div>
|
|
56
95
|
|
|
57
96
|
<div class="mint-layout__body">
|
|
97
|
+
<button
|
|
98
|
+
v-if="responsiveSidebar && $slots.sidebar"
|
|
99
|
+
type="button"
|
|
100
|
+
class="mint-layout__sidebar-toggle"
|
|
101
|
+
:aria-label="sidebarOpenModel ? sidebarCloseLabel : sidebarToggleLabel"
|
|
102
|
+
:aria-expanded="sidebarOpenModel"
|
|
103
|
+
@click="toggleSidebar"
|
|
104
|
+
>
|
|
105
|
+
<svg
|
|
106
|
+
v-if="!sidebarOpenModel"
|
|
107
|
+
class="mint-layout__sidebar-toggle-icon"
|
|
108
|
+
viewBox="0 0 24 24"
|
|
109
|
+
fill="none"
|
|
110
|
+
stroke="currentColor"
|
|
111
|
+
stroke-width="2"
|
|
112
|
+
stroke-linecap="round"
|
|
113
|
+
stroke-linejoin="round"
|
|
114
|
+
aria-hidden="true"
|
|
115
|
+
>
|
|
116
|
+
<path d="M4 6h16M4 12h16M4 18h16" />
|
|
117
|
+
</svg>
|
|
118
|
+
<svg
|
|
119
|
+
v-else
|
|
120
|
+
class="mint-layout__sidebar-toggle-icon"
|
|
121
|
+
viewBox="0 0 24 24"
|
|
122
|
+
fill="none"
|
|
123
|
+
stroke="currentColor"
|
|
124
|
+
stroke-width="2"
|
|
125
|
+
stroke-linecap="round"
|
|
126
|
+
stroke-linejoin="round"
|
|
127
|
+
aria-hidden="true"
|
|
128
|
+
>
|
|
129
|
+
<path d="M6 18 18 6M6 6l12 12" />
|
|
130
|
+
</svg>
|
|
131
|
+
</button>
|
|
132
|
+
|
|
133
|
+
<div
|
|
134
|
+
v-if="responsiveSidebar && $slots.sidebar && sidebarOpenModel"
|
|
135
|
+
class="mint-layout__sidebar-backdrop"
|
|
136
|
+
@click="closeSidebar"
|
|
137
|
+
/>
|
|
138
|
+
|
|
58
139
|
<div
|
|
59
140
|
v-if="$slots.sidebar"
|
|
60
141
|
class="mint-layout__sidebar"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** Dropdown menu for switching between installed plugins with color swatches, version badges, and an install link. */
|
|
3
3
|
import { useDropdownState } from '../composables/useDropdownState'
|
|
4
4
|
import type { PluginSwitcherPlugin } from '../types/components'
|
|
5
|
-
import
|
|
5
|
+
import ActionItemInternal from './internal/ActionItemInternal.vue'
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
8
8
|
current: PluginSwitcherPlugin
|
|
@@ -74,7 +74,7 @@ function handleInstall() {
|
|
|
74
74
|
|
|
75
75
|
<div v-if="isOpen" class="mint-plugin-switcher__menu" role="menu">
|
|
76
76
|
<div class="mint-plugin-switcher__menu-title">Switch plugin</div>
|
|
77
|
-
<
|
|
77
|
+
<ActionItemInternal
|
|
78
78
|
v-for="plugin in plugins"
|
|
79
79
|
:key="plugin.id"
|
|
80
80
|
:href="plugin.href"
|
|
@@ -107,13 +107,13 @@ function handleInstall() {
|
|
|
107
107
|
>
|
|
108
108
|
<path d="M5 13l4 4L19 7" />
|
|
109
109
|
</svg>
|
|
110
|
-
</
|
|
110
|
+
</ActionItemInternal>
|
|
111
111
|
|
|
112
112
|
<template v-if="plugins.length && (installHref || installTo || $slots.install)">
|
|
113
113
|
<div class="mint-plugin-switcher__divider" role="separator" />
|
|
114
114
|
</template>
|
|
115
115
|
<slot name="install">
|
|
116
|
-
<
|
|
116
|
+
<ActionItemInternal
|
|
117
117
|
v-if="installHref || installTo"
|
|
118
118
|
:href="installHref"
|
|
119
119
|
:to="installTo"
|
|
@@ -126,7 +126,7 @@ function handleInstall() {
|
|
|
126
126
|
<line x1="5" y1="12" x2="19" y2="12" />
|
|
127
127
|
</svg>
|
|
128
128
|
<span>{{ installLabel }}</span>
|
|
129
|
-
</
|
|
129
|
+
</ActionItemInternal>
|
|
130
130
|
</slot>
|
|
131
131
|
</div>
|
|
132
132
|
</div>
|
|
@@ -10,11 +10,13 @@ import NumberInput from './NumberInput.vue'
|
|
|
10
10
|
import FileUploader from './FileUploader.vue'
|
|
11
11
|
import FormField from './FormField.vue'
|
|
12
12
|
import WellPlate from './WellPlate.vue'
|
|
13
|
-
import { defineControls, getControlDefaults } from '../composables/useControlSchema'
|
|
13
|
+
import { defineControlModel, defineControls, getControlDefaults } from '../composables/useControlSchema'
|
|
14
14
|
import { useBioTemplateWorkspace } from '../composables/useBioTemplateWorkspace'
|
|
15
15
|
import { createWellPlateScreenCollection } from '../templates'
|
|
16
16
|
import type { SidebarToolSection } from '../types'
|
|
17
17
|
|
|
18
|
+
type SidebarVariant = 'analysis' | 'default'
|
|
19
|
+
|
|
18
20
|
/* --- Icon paths (Lucide-style) --- */
|
|
19
21
|
const icons = {
|
|
20
22
|
upload: ['M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4', 'M17 8l-5-5-5 5', 'M12 3v12'],
|
|
@@ -130,6 +132,13 @@ const polarity = ref('negative')
|
|
|
130
132
|
const container = ref('vial')
|
|
131
133
|
const expNumber = ref(1)
|
|
132
134
|
const initials = ref('XP')
|
|
135
|
+
const sequencePrefix = ref('exp001_260210_XP')
|
|
136
|
+
const runMode = ref('balanced')
|
|
137
|
+
const runModeOptions = [
|
|
138
|
+
{ value: 'fast', label: 'Fast' },
|
|
139
|
+
{ value: 'balanced', label: 'Balanced' },
|
|
140
|
+
{ value: 'qc', label: 'QC focused' },
|
|
141
|
+
]
|
|
133
142
|
const toggleState = reactive<Record<string, boolean>>({ naming: true, randomize: false })
|
|
134
143
|
const schemaControls = defineControls({
|
|
135
144
|
threshold: {
|
|
@@ -172,13 +181,46 @@ const schemaControls = defineControls({
|
|
|
172
181
|
},
|
|
173
182
|
},
|
|
174
183
|
})
|
|
175
|
-
const controlValues =
|
|
184
|
+
const controlValues = ref<Record<string, unknown>>({ ...getControlDefaults(schemaControls) })
|
|
185
|
+
const modelDrivenSidebarModel = defineControlModel({
|
|
186
|
+
views: {
|
|
187
|
+
analysis: {
|
|
188
|
+
label: 'Analysis',
|
|
189
|
+
sections: {
|
|
190
|
+
parameters: {
|
|
191
|
+
label: 'Parameters',
|
|
192
|
+
description: 'Thresholds and scoring',
|
|
193
|
+
icon: icons.settings,
|
|
194
|
+
controls: {
|
|
195
|
+
threshold: { type: 'number', default: 0.05, min: 0, max: 1 },
|
|
196
|
+
method: ['linear', 'logistic', 'spline'],
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
filters: {
|
|
200
|
+
label: 'Filters',
|
|
201
|
+
description: 'Result cleanup',
|
|
202
|
+
sidebar: {
|
|
203
|
+
icon: icons.zap,
|
|
204
|
+
iconColor: '#0ea5e9',
|
|
205
|
+
iconBg: '#e0f2fe',
|
|
206
|
+
defaultOpen: false,
|
|
207
|
+
},
|
|
208
|
+
controls: {
|
|
209
|
+
showOutliers: true,
|
|
210
|
+
minPeakArea: { type: 'number', default: 1000, min: 0 },
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
})
|
|
217
|
+
const modelDrivenValues = ref<Record<string, unknown>>({})
|
|
176
218
|
const templateCollection = createWellPlateScreenCollection({
|
|
177
219
|
samples: ['Control', 'Treatment'],
|
|
178
220
|
compounds: { 'Drug A': [10, 1, 0.1] },
|
|
179
221
|
})
|
|
180
222
|
const templateWorkspace = useBioTemplateWorkspace(templateCollection)
|
|
181
|
-
const templateValues =
|
|
223
|
+
const templateValues = ref<Record<string, unknown>>({ ...templateWorkspace.controls.initialValues })
|
|
182
224
|
const templateWellPlateProps = templateWorkspace.componentProps
|
|
183
225
|
.find(binding => binding.component === 'WellPlate')
|
|
184
226
|
?.propsObject ?? {}
|
|
@@ -190,8 +232,9 @@ function handleToggle(id: string, value: boolean) {
|
|
|
190
232
|
function initSimpleToolkit() {
|
|
191
233
|
return {
|
|
192
234
|
activeView: 'analysis',
|
|
235
|
+
variant: 'analysis' as SidebarVariant,
|
|
193
236
|
floating: false,
|
|
194
|
-
width: '
|
|
237
|
+
width: '20rem',
|
|
195
238
|
side: 'left' as const,
|
|
196
239
|
}
|
|
197
240
|
}
|
|
@@ -276,14 +319,70 @@ function initSimpleToolkit() {
|
|
|
276
319
|
<Variant title="Schema Driven Controls">
|
|
277
320
|
<div style="padding: 2rem; height: 520px; position: relative; background: var(--bg-primary, #f1f5f9);">
|
|
278
321
|
<AppSidebar
|
|
322
|
+
variant="analysis"
|
|
323
|
+
title="Peak Picking"
|
|
324
|
+
subtitle="Current experiment"
|
|
279
325
|
:controls="schemaControls"
|
|
280
326
|
active-view="analysis"
|
|
281
327
|
v-model="controlValues"
|
|
282
|
-
width="300px"
|
|
283
328
|
/>
|
|
284
329
|
</div>
|
|
285
330
|
</Variant>
|
|
286
331
|
|
|
332
|
+
<Variant title="Model Driven Analysis">
|
|
333
|
+
<div style="padding: 2rem; height: 560px; position: relative; background: var(--bg-primary, #f1f5f9);">
|
|
334
|
+
<AppSidebar
|
|
335
|
+
v-model="modelDrivenValues"
|
|
336
|
+
variant="analysis"
|
|
337
|
+
title="Peak Picking"
|
|
338
|
+
subtitle="Current experiment"
|
|
339
|
+
:model="modelDrivenSidebarModel"
|
|
340
|
+
/>
|
|
341
|
+
</div>
|
|
342
|
+
</Variant>
|
|
343
|
+
|
|
344
|
+
<Variant title="Route Owned Shell">
|
|
345
|
+
<div style="padding: 2rem; height: 560px; display: flex; gap: 1rem; background: var(--bg-primary, #f1f5f9);">
|
|
346
|
+
<AppSidebar
|
|
347
|
+
variant="analysis"
|
|
348
|
+
title="Sequence"
|
|
349
|
+
subtitle="Acquisition run"
|
|
350
|
+
content-id="seqgen-sidebar"
|
|
351
|
+
show-when-empty
|
|
352
|
+
>
|
|
353
|
+
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
|
354
|
+
<FormField label="File Prefix">
|
|
355
|
+
<BaseInput v-model="sequencePrefix" size="sm" />
|
|
356
|
+
</FormField>
|
|
357
|
+
<FormField label="Run Mode">
|
|
358
|
+
<BaseSelect v-model="runMode" :options="runModeOptions" size="sm" />
|
|
359
|
+
</FormField>
|
|
360
|
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem;">
|
|
361
|
+
<BaseButton size="sm" variant="secondary">NEG</BaseButton>
|
|
362
|
+
<BaseButton size="sm" variant="secondary">VIAL</BaseButton>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<template #footer>
|
|
367
|
+
<div style="display: flex; flex-direction: column; gap: 0.5rem;">
|
|
368
|
+
<BaseButton variant="cta" style="width: 100%;">Generate Sequence</BaseButton>
|
|
369
|
+
<BaseButton variant="ghost" size="sm" style="width: 100%;">Clear Draft</BaseButton>
|
|
370
|
+
</div>
|
|
371
|
+
</template>
|
|
372
|
+
</AppSidebar>
|
|
373
|
+
|
|
374
|
+
<div style="flex: 1; min-width: 0; border: 1px solid var(--border-color, #e5e7eb); border-radius: 0.5rem; background: var(--bg-card, #fff); padding: 1rem;">
|
|
375
|
+
<div style="display: flex; justify-content: space-between; gap: 1rem; align-items: center;">
|
|
376
|
+
<div>
|
|
377
|
+
<div style="font-size: 0.875rem; font-weight: 650; color: var(--text-primary, #111827);">MS queue</div>
|
|
378
|
+
<div style="font-size: 0.75rem; color: var(--text-muted, #6b7280);">{{ sequencePrefix }} · {{ runMode }}</div>
|
|
379
|
+
</div>
|
|
380
|
+
<BaseButton size="sm" variant="secondary">Preview CSV</BaseButton>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
</div>
|
|
384
|
+
</Variant>
|
|
385
|
+
|
|
287
386
|
<Variant title="Template Driven Controls">
|
|
288
387
|
<div style="padding: 2rem; min-height: 560px; display: flex; gap: 1rem; background: var(--bg-primary, #f1f5f9);">
|
|
289
388
|
<AppSidebar
|
|
@@ -335,6 +434,7 @@ function initSimpleToolkit() {
|
|
|
335
434
|
</div>
|
|
336
435
|
<AppSidebar
|
|
337
436
|
:panels="simplePanels"
|
|
437
|
+
:variant="state.variant"
|
|
338
438
|
:active-view="state.activeView"
|
|
339
439
|
:floating="state.floating"
|
|
340
440
|
:width="state.width"
|
|
@@ -365,6 +465,14 @@ function initSimpleToolkit() {
|
|
|
365
465
|
title="Active View"
|
|
366
466
|
:options="['analysis', 'results', 'settings'].map(v => ({ label: v, value: v }))"
|
|
367
467
|
/>
|
|
468
|
+
<HstSelect
|
|
469
|
+
v-model="state.variant"
|
|
470
|
+
title="Variant"
|
|
471
|
+
:options="[
|
|
472
|
+
{ label: 'Analysis', value: 'analysis' },
|
|
473
|
+
{ label: 'Default', value: 'default' },
|
|
474
|
+
]"
|
|
475
|
+
/>
|
|
368
476
|
<HstCheckbox v-model="state.floating" title="Floating" />
|
|
369
477
|
<HstText v-model="state.width" title="Width" />
|
|
370
478
|
<HstSelect
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* the `panels` config and rendered as CollapsibleCards. Controls can be
|
|
7
7
|
* provided through named slots or auto-rendered from FormBuilder schemas.
|
|
8
8
|
*
|
|
9
|
-
* When
|
|
9
|
+
* When activeView is omitted, the first non-empty panel view is selected.
|
|
10
|
+
* When no view has matching panels, the sidebar hides entirely.
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
13
|
* ```vue
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
* <AppSidebar :controls="controls" :active-view="activeTab" v-model="values" />
|
|
25
26
|
* ```
|
|
26
27
|
*/
|
|
27
|
-
import { computed } from 'vue'
|
|
28
|
+
import { computed, ref, useSlots, type Slots } from 'vue'
|
|
28
29
|
import type { PillNavItem, SidebarToolSection } from '../types'
|
|
29
30
|
import type { FormEnhancements, FormSchema } from '../types/form-builder'
|
|
30
31
|
import {
|
|
@@ -42,15 +43,23 @@ import CollapsibleCard from './CollapsibleCard.vue'
|
|
|
42
43
|
import FormBuilder from './FormBuilder.vue'
|
|
43
44
|
|
|
44
45
|
interface Props {
|
|
46
|
+
/** Optional chrome title rendered above generated sections. */
|
|
47
|
+
title?: string
|
|
48
|
+
/** Optional secondary chrome copy rendered below title. */
|
|
49
|
+
subtitle?: string
|
|
50
|
+
/** Optional compact badge/count rendered in the chrome header. */
|
|
51
|
+
badge?: string | number
|
|
52
|
+
/** Visual preset for common plugin sidebars. `analysis` preserves the LEAF-style MINT analysis sidebar design language. */
|
|
53
|
+
variant?: 'default' | 'analysis'
|
|
45
54
|
/** Map of view IDs to their tool sections */
|
|
46
55
|
panels?: Record<string, SidebarToolSection[]>
|
|
47
|
-
/** Which view's panels to display */
|
|
56
|
+
/** Which view's panels to display. Defaults to the first non-empty panel view. */
|
|
48
57
|
activeView?: string
|
|
49
|
-
/** Floating variant with absolute positioning */
|
|
58
|
+
/** Floating variant with absolute positioning. Defaults to false for analysis variant. */
|
|
50
59
|
floating?: boolean
|
|
51
60
|
/** Compact layout: smaller headers, tighter spacing, no icon backgrounds */
|
|
52
61
|
dense?: boolean
|
|
53
|
-
/** Width when visible */
|
|
62
|
+
/** Width when visible. Defaults to 20rem for analysis variant, otherwise 280px. */
|
|
54
63
|
width?: string
|
|
55
64
|
/** Position sidebar on left or right side */
|
|
56
65
|
side?: 'left' | 'right'
|
|
@@ -60,7 +69,7 @@ interface Props {
|
|
|
60
69
|
forms?: Record<string, FormSchema>
|
|
61
70
|
/** Generated view IDs from useControlSchema(). Consumed for clean v-bind ergonomics. */
|
|
62
71
|
viewIds?: string[]
|
|
63
|
-
/** Generated
|
|
72
|
+
/** Generated AppTopBar pillNav-compatible view items from useControlSchema(). Consumed for clean v-bind ergonomics. */
|
|
64
73
|
viewItems?: PillNavItem[]
|
|
65
74
|
/** Default view ID used when activeView is omitted. */
|
|
66
75
|
defaultView?: string
|
|
@@ -70,6 +79,10 @@ interface Props {
|
|
|
70
79
|
controls?: ControlSchema
|
|
71
80
|
/** Options passed to compact control schema generation, including shared initialValues. */
|
|
72
81
|
controlOptions?: ControlWorkspaceOptions
|
|
82
|
+
/** DOM id for the scrollable content area. Use with Teleport when route/tab children own sidebar controls. */
|
|
83
|
+
contentId?: string
|
|
84
|
+
/** Render the sidebar shell even when no panel matches the active view. Useful for default-slot or Teleport-driven sidebars. */
|
|
85
|
+
showWhenEmpty?: boolean
|
|
73
86
|
/** Shared values for auto-rendered section forms. Supports default v-model. */
|
|
74
87
|
modelValue?: Record<string, unknown>
|
|
75
88
|
/** Shared values for auto-rendered section forms */
|
|
@@ -86,14 +99,30 @@ interface Props {
|
|
|
86
99
|
formReadonly?: boolean
|
|
87
100
|
/** Size passed to auto-rendered section forms */
|
|
88
101
|
formSize?: 'sm' | 'md' | 'lg'
|
|
102
|
+
/** Show a built-in collapse/expand button in the sidebar chrome. Defaults to true for analysis variant. */
|
|
103
|
+
collapsible?: boolean
|
|
104
|
+
/** Controlled collapsed state. */
|
|
105
|
+
collapsed?: boolean
|
|
106
|
+
/** Initial collapsed state when collapsed is uncontrolled. */
|
|
107
|
+
defaultCollapsed?: boolean
|
|
108
|
+
/** Width when collapsed. */
|
|
109
|
+
collapsedWidth?: string
|
|
110
|
+
/** Accessible label for the collapse action. */
|
|
111
|
+
collapseButtonLabel?: string
|
|
112
|
+
/** Accessible label for the expand action. */
|
|
113
|
+
expandButtonLabel?: string
|
|
89
114
|
}
|
|
90
115
|
|
|
91
116
|
const props = withDefaults(defineProps<Props>(), {
|
|
117
|
+
title: undefined,
|
|
118
|
+
subtitle: undefined,
|
|
119
|
+
badge: undefined,
|
|
120
|
+
variant: 'default',
|
|
92
121
|
panels: () => ({}),
|
|
93
122
|
activeView: '',
|
|
94
|
-
floating:
|
|
123
|
+
floating: undefined,
|
|
95
124
|
dense: false,
|
|
96
|
-
width:
|
|
125
|
+
width: undefined,
|
|
97
126
|
side: 'left',
|
|
98
127
|
toggleState: () => ({}),
|
|
99
128
|
forms: () => ({}),
|
|
@@ -102,6 +131,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
102
131
|
defaultView: '',
|
|
103
132
|
model: undefined,
|
|
104
133
|
controlOptions: () => ({}),
|
|
134
|
+
contentId: undefined,
|
|
135
|
+
showWhenEmpty: false,
|
|
105
136
|
modelValue: undefined,
|
|
106
137
|
values: () => ({}),
|
|
107
138
|
showFormActions: false,
|
|
@@ -109,8 +140,38 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
109
140
|
formDisabled: false,
|
|
110
141
|
formReadonly: false,
|
|
111
142
|
formSize: 'sm',
|
|
143
|
+
collapsible: undefined,
|
|
144
|
+
collapsed: undefined,
|
|
145
|
+
defaultCollapsed: false,
|
|
146
|
+
collapsedWidth: '3rem',
|
|
147
|
+
collapseButtonLabel: 'Collapse sidebar',
|
|
148
|
+
expandButtonLabel: 'Expand sidebar',
|
|
112
149
|
})
|
|
113
150
|
|
|
151
|
+
const emit = defineEmits<{
|
|
152
|
+
'update:toggle': [sectionId: string, value: boolean]
|
|
153
|
+
'update:modelValue': [values: Record<string, unknown>]
|
|
154
|
+
'update:values': [values: Record<string, unknown>]
|
|
155
|
+
'update:collapsed': [value: boolean]
|
|
156
|
+
'form-submit': [sectionId: string, values: Record<string, unknown>]
|
|
157
|
+
'form-cancel': [sectionId: string]
|
|
158
|
+
}>()
|
|
159
|
+
|
|
160
|
+
const slots: Slots = useSlots()
|
|
161
|
+
const internalCollapsed = ref(props.defaultCollapsed)
|
|
162
|
+
const collapsedModel = computed({
|
|
163
|
+
get: () => props.collapsed ?? internalCollapsed.value,
|
|
164
|
+
set: (value: boolean) => {
|
|
165
|
+
internalCollapsed.value = value
|
|
166
|
+
emit('update:collapsed', value)
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const isAnalysisVariant = computed(() => props.variant === 'analysis')
|
|
171
|
+
const resolvedFloating = computed(() => props.floating ?? !isAnalysisVariant.value)
|
|
172
|
+
const resolvedWidth = computed(() => props.width ?? (isAnalysisVariant.value ? '20rem' : '280px'))
|
|
173
|
+
const resolvedCollapsible = computed(() => props.collapsible ?? isAnalysisVariant.value)
|
|
174
|
+
|
|
114
175
|
const resolvedModel = computed<ControlModelBinding | undefined>(() => {
|
|
115
176
|
if (props.model === undefined) return undefined
|
|
116
177
|
return isControlModelBinding(props.model) ? props.model : defineControlModel(props.model)
|
|
@@ -159,7 +220,6 @@ const resolvedValues = computed<Record<string, unknown>>(() => ({
|
|
|
159
220
|
const resolvedActiveView = computed(() => {
|
|
160
221
|
if (props.activeView) return props.activeView
|
|
161
222
|
if (props.defaultView) return props.defaultView
|
|
162
|
-
if (!resolvedControls.value) return ''
|
|
163
223
|
return firstVisibleViewId(resolvedPanels.value)
|
|
164
224
|
})
|
|
165
225
|
|
|
@@ -168,28 +228,25 @@ const activeSections = computed<SidebarToolSection[]>(() => {
|
|
|
168
228
|
return resolvedPanels.value[resolvedActiveView.value]
|
|
169
229
|
})
|
|
170
230
|
|
|
171
|
-
const isVisible = computed(() =>
|
|
231
|
+
const isVisible = computed<boolean>(() =>
|
|
232
|
+
activeSections.value.length > 0 || props.showWhenEmpty || Boolean(slots.default),
|
|
233
|
+
)
|
|
172
234
|
|
|
173
|
-
const sidebarClasses = computed(() => [
|
|
235
|
+
const sidebarClasses = computed<string[]>(() => [
|
|
174
236
|
'mint-sidebar',
|
|
175
237
|
`mint-sidebar--${props.side}`,
|
|
176
|
-
|
|
238
|
+
`mint-sidebar--${props.variant}`,
|
|
239
|
+
resolvedFloating.value ? 'mint-sidebar--floating' : 'mint-sidebar--static',
|
|
177
240
|
props.dense ? 'mint-sidebar--dense' : '',
|
|
241
|
+
resolvedCollapsible.value ? 'mint-sidebar--collapsible' : '',
|
|
242
|
+
collapsedModel.value ? 'mint-sidebar--collapsed' : '',
|
|
178
243
|
!isVisible.value ? 'mint-sidebar--hidden' : '',
|
|
179
244
|
])
|
|
180
245
|
|
|
181
|
-
const sidebarStyle = computed(() => ({
|
|
182
|
-
width: props.
|
|
246
|
+
const sidebarStyle = computed<Record<string, string>>(() => ({
|
|
247
|
+
width: collapsedModel.value ? props.collapsedWidth : resolvedWidth.value,
|
|
183
248
|
}))
|
|
184
249
|
|
|
185
|
-
const emit = defineEmits<{
|
|
186
|
-
'update:toggle': [sectionId: string, value: boolean]
|
|
187
|
-
'update:modelValue': [values: Record<string, unknown>]
|
|
188
|
-
'update:values': [values: Record<string, unknown>]
|
|
189
|
-
'form-submit': [sectionId: string, values: Record<string, unknown>]
|
|
190
|
-
'form-cancel': [sectionId: string]
|
|
191
|
-
}>()
|
|
192
|
-
|
|
193
250
|
function handleFormUpdate(values: Record<string, unknown>) {
|
|
194
251
|
const nextValues = { ...resolvedValues.value, ...values }
|
|
195
252
|
emit('update:modelValue', nextValues)
|
|
@@ -204,6 +261,14 @@ function handleFormCancel(sectionId: string) {
|
|
|
204
261
|
emit('form-cancel', sectionId)
|
|
205
262
|
}
|
|
206
263
|
|
|
264
|
+
function toggleCollapsed() {
|
|
265
|
+
collapsedModel.value = !collapsedModel.value
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function expandCollapsed() {
|
|
269
|
+
collapsedModel.value = false
|
|
270
|
+
}
|
|
271
|
+
|
|
207
272
|
function mergeSidebarPanels(
|
|
208
273
|
generated: Record<string, SidebarToolSection[]>,
|
|
209
274
|
explicit: Record<string, SidebarToolSection[]>,
|
|
@@ -242,13 +307,54 @@ function isControlModelBinding(model: ControlModel | ControlModelBinding): model
|
|
|
242
307
|
:class="sidebarClasses"
|
|
243
308
|
:style="sidebarStyle"
|
|
244
309
|
>
|
|
245
|
-
<!-- Header slot -->
|
|
246
|
-
<div
|
|
247
|
-
|
|
310
|
+
<!-- Header slot / built-in chrome -->
|
|
311
|
+
<div
|
|
312
|
+
v-if="$slots.header || title || subtitle || badge !== undefined || resolvedCollapsible"
|
|
313
|
+
class="mint-sidebar__header"
|
|
314
|
+
>
|
|
315
|
+
<slot
|
|
316
|
+
name="header"
|
|
317
|
+
:collapsed="collapsedModel"
|
|
318
|
+
:toggle-collapsed="toggleCollapsed"
|
|
319
|
+
>
|
|
320
|
+
<div v-if="!collapsedModel" class="mint-sidebar__heading">
|
|
321
|
+
<div class="mint-sidebar__heading-copy">
|
|
322
|
+
<h2 v-if="title" class="mint-sidebar__title">{{ title }}</h2>
|
|
323
|
+
<p v-if="subtitle" class="mint-sidebar__subtitle">{{ subtitle }}</p>
|
|
324
|
+
</div>
|
|
325
|
+
<span v-if="badge !== undefined" class="mint-sidebar__badge">{{ badge }}</span>
|
|
326
|
+
</div>
|
|
327
|
+
<button
|
|
328
|
+
v-if="resolvedCollapsible"
|
|
329
|
+
type="button"
|
|
330
|
+
class="mint-sidebar__collapse-button"
|
|
331
|
+
:aria-label="collapsedModel ? expandButtonLabel : collapseButtonLabel"
|
|
332
|
+
:aria-expanded="!collapsedModel"
|
|
333
|
+
@click="toggleCollapsed"
|
|
334
|
+
>
|
|
335
|
+
<svg
|
|
336
|
+
class="mint-sidebar__collapse-icon"
|
|
337
|
+
:class="{ 'mint-sidebar__collapse-icon--collapsed': collapsedModel }"
|
|
338
|
+
viewBox="0 0 24 24"
|
|
339
|
+
fill="none"
|
|
340
|
+
stroke="currentColor"
|
|
341
|
+
stroke-width="2"
|
|
342
|
+
stroke-linecap="round"
|
|
343
|
+
stroke-linejoin="round"
|
|
344
|
+
aria-hidden="true"
|
|
345
|
+
>
|
|
346
|
+
<path d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
|
|
347
|
+
</svg>
|
|
348
|
+
</button>
|
|
349
|
+
</slot>
|
|
248
350
|
</div>
|
|
249
351
|
|
|
250
352
|
<!-- Tool sections -->
|
|
251
|
-
<div
|
|
353
|
+
<div
|
|
354
|
+
v-if="!collapsedModel"
|
|
355
|
+
:id="contentId"
|
|
356
|
+
class="mint-sidebar__sections"
|
|
357
|
+
>
|
|
252
358
|
<CollapsibleCard
|
|
253
359
|
v-for="section in activeSections"
|
|
254
360
|
:key="section.id"
|
|
@@ -280,10 +386,24 @@ function isControlModelBinding(model: ControlModel | ControlModelBinding): model
|
|
|
280
386
|
/>
|
|
281
387
|
</slot>
|
|
282
388
|
</CollapsibleCard>
|
|
389
|
+
|
|
390
|
+
<slot
|
|
391
|
+
:sections="activeSections"
|
|
392
|
+
:active-view="resolvedActiveView"
|
|
393
|
+
:values="resolvedValues"
|
|
394
|
+
/>
|
|
395
|
+
</div>
|
|
396
|
+
|
|
397
|
+
<div v-else-if="$slots.collapsed" class="mint-sidebar__collapsed">
|
|
398
|
+
<slot
|
|
399
|
+
name="collapsed"
|
|
400
|
+
:sections="activeSections"
|
|
401
|
+
:expand="expandCollapsed"
|
|
402
|
+
/>
|
|
283
403
|
</div>
|
|
284
404
|
|
|
285
405
|
<!-- Footer slot -->
|
|
286
|
-
<div v-if="$slots.footer" class="mint-sidebar__footer">
|
|
406
|
+
<div v-if="!collapsedModel && $slots.footer" class="mint-sidebar__footer">
|
|
287
407
|
<slot name="footer" />
|
|
288
408
|
</div>
|
|
289
409
|
</aside>
|
|
@@ -231,10 +231,9 @@ const sampleAccountMenu: AccountMenuItem[] = [
|
|
|
231
231
|
</div>
|
|
232
232
|
</Variant>
|
|
233
233
|
|
|
234
|
-
<Variant title="
|
|
234
|
+
<Variant title="Navigation · Page selector">
|
|
235
235
|
<div style="padding: 2rem;">
|
|
236
236
|
<AppTopBar
|
|
237
|
-
plugin-name="IC50 Calculator"
|
|
238
237
|
title="Results"
|
|
239
238
|
:page-selector="samplePageSelector"
|
|
240
239
|
current-page-selector-id="plugins"
|
|
@@ -245,10 +244,9 @@ const sampleAccountMenu: AccountMenuItem[] = [
|
|
|
245
244
|
</div>
|
|
246
245
|
</Variant>
|
|
247
246
|
|
|
248
|
-
<Variant title="
|
|
247
|
+
<Variant title="Navigation · Pill nav">
|
|
249
248
|
<div style="padding: 2rem;">
|
|
250
249
|
<AppTopBar
|
|
251
|
-
plugin-name="Plate Analyzer"
|
|
252
250
|
title="Experiment View"
|
|
253
251
|
:pill-nav="samplePillNav.slice(0, 3)"
|
|
254
252
|
current-pill-id="workspace"
|
|
@@ -268,7 +266,6 @@ const sampleAccountMenu: AccountMenuItem[] = [
|
|
|
268
266
|
<div style="padding: 2rem;">
|
|
269
267
|
<ExperimentProvider>
|
|
270
268
|
<AppTopBar
|
|
271
|
-
plugin-name="IC50 Calculator"
|
|
272
269
|
title="Analysis"
|
|
273
270
|
variant="card"
|
|
274
271
|
:show-theme-toggle="true"
|