@morscherlab/mld-sdk 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ExperimentPopover.vue.d.ts +22 -0
- package/dist/components/ExperimentPopover.vue.js +212 -0
- package/dist/components/ExperimentPopover.vue.js.map +1 -0
- package/dist/components/ExperimentPopover.vue3.js +6 -0
- package/dist/components/ExperimentPopover.vue3.js.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +5 -2
- package/dist/components/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/styles.css +445 -0
- package/package.json +1 -1
- package/src/components/ExperimentPopover.vue +177 -0
- package/src/components/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/styles/components/experiment-popover.css +252 -0
- package/src/styles/index.css +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
experimentName?: string;
|
|
3
|
+
experimentStatus?: string;
|
|
4
|
+
showSave?: boolean;
|
|
5
|
+
saveDisabled?: boolean;
|
|
6
|
+
saveLoading?: boolean;
|
|
7
|
+
saveSuccessMessage?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
10
|
+
select: () => any;
|
|
11
|
+
save: () => any;
|
|
12
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
13
|
+
onSelect?: (() => any) | undefined;
|
|
14
|
+
onSave?: (() => any) | undefined;
|
|
15
|
+
}>, {
|
|
16
|
+
showSave: boolean;
|
|
17
|
+
saveDisabled: boolean;
|
|
18
|
+
saveLoading: boolean;
|
|
19
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
20
|
+
popoverRef: HTMLDivElement;
|
|
21
|
+
}, HTMLDivElement>;
|
|
22
|
+
export default _default;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { defineComponent, ref, watch, onMounted, onUnmounted, openBlock, createElementBlock, createElementVNode, withModifiers, normalizeClass, toDisplayString, createTextVNode, createCommentVNode, Fragment } from "vue";
|
|
2
|
+
const _hoisted_1 = { class: "mld-experiment-popover__trigger-text" };
|
|
3
|
+
const _hoisted_2 = {
|
|
4
|
+
key: 0,
|
|
5
|
+
class: "mld-experiment-popover__panel"
|
|
6
|
+
};
|
|
7
|
+
const _hoisted_3 = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "mld-experiment-popover__empty"
|
|
10
|
+
};
|
|
11
|
+
const _hoisted_4 = {
|
|
12
|
+
key: 1,
|
|
13
|
+
class: "mld-experiment-popover__card"
|
|
14
|
+
};
|
|
15
|
+
const _hoisted_5 = { class: "mld-experiment-popover__card-info" };
|
|
16
|
+
const _hoisted_6 = { class: "mld-experiment-popover__card-name" };
|
|
17
|
+
const _hoisted_7 = {
|
|
18
|
+
key: 0,
|
|
19
|
+
class: "mld-experiment-popover__card-status"
|
|
20
|
+
};
|
|
21
|
+
const _hoisted_8 = { class: "mld-experiment-popover__footer" };
|
|
22
|
+
const _hoisted_9 = ["disabled"];
|
|
23
|
+
const _hoisted_10 = {
|
|
24
|
+
key: 0,
|
|
25
|
+
class: "mld-experiment-popover__spinner"
|
|
26
|
+
};
|
|
27
|
+
const _hoisted_11 = {
|
|
28
|
+
key: 1,
|
|
29
|
+
class: "mld-experiment-popover__check-icon",
|
|
30
|
+
fill: "none",
|
|
31
|
+
stroke: "currentColor",
|
|
32
|
+
viewBox: "0 0 24 24"
|
|
33
|
+
};
|
|
34
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
35
|
+
__name: "ExperimentPopover",
|
|
36
|
+
props: {
|
|
37
|
+
experimentName: {},
|
|
38
|
+
experimentStatus: {},
|
|
39
|
+
showSave: { type: Boolean, default: false },
|
|
40
|
+
saveDisabled: { type: Boolean, default: false },
|
|
41
|
+
saveLoading: { type: Boolean, default: false },
|
|
42
|
+
saveSuccessMessage: {}
|
|
43
|
+
},
|
|
44
|
+
emits: ["select", "save"],
|
|
45
|
+
setup(__props, { emit: __emit }) {
|
|
46
|
+
const props = __props;
|
|
47
|
+
const emit = __emit;
|
|
48
|
+
const isOpen = ref(false);
|
|
49
|
+
const popoverRef = ref(null);
|
|
50
|
+
const showSuccess = ref(false);
|
|
51
|
+
function toggle() {
|
|
52
|
+
isOpen.value = !isOpen.value;
|
|
53
|
+
}
|
|
54
|
+
function close() {
|
|
55
|
+
isOpen.value = false;
|
|
56
|
+
}
|
|
57
|
+
function handleSelect() {
|
|
58
|
+
emit("select");
|
|
59
|
+
close();
|
|
60
|
+
}
|
|
61
|
+
function handleSave() {
|
|
62
|
+
if (props.saveDisabled || props.saveLoading) return;
|
|
63
|
+
emit("save");
|
|
64
|
+
}
|
|
65
|
+
function handleClickOutside(event) {
|
|
66
|
+
if (popoverRef.value && !popoverRef.value.contains(event.target)) {
|
|
67
|
+
close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
watch(() => props.saveSuccessMessage, (msg) => {
|
|
71
|
+
if (msg) {
|
|
72
|
+
showSuccess.value = true;
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
showSuccess.value = false;
|
|
75
|
+
}, 3e3);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
onMounted(() => {
|
|
79
|
+
document.addEventListener("click", handleClickOutside);
|
|
80
|
+
});
|
|
81
|
+
onUnmounted(() => {
|
|
82
|
+
document.removeEventListener("click", handleClickOutside);
|
|
83
|
+
});
|
|
84
|
+
function formatStatus(status) {
|
|
85
|
+
return status.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase());
|
|
86
|
+
}
|
|
87
|
+
return (_ctx, _cache) => {
|
|
88
|
+
return openBlock(), createElementBlock("div", {
|
|
89
|
+
ref_key: "popoverRef",
|
|
90
|
+
ref: popoverRef,
|
|
91
|
+
class: "mld-experiment-popover"
|
|
92
|
+
}, [
|
|
93
|
+
createElementVNode("button", {
|
|
94
|
+
type: "button",
|
|
95
|
+
class: normalizeClass([
|
|
96
|
+
"mld-experiment-popover__trigger",
|
|
97
|
+
{ "mld-experiment-popover__trigger--active": isOpen.value },
|
|
98
|
+
{ "mld-experiment-popover__trigger--empty": !__props.experimentName }
|
|
99
|
+
]),
|
|
100
|
+
onClick: withModifiers(toggle, ["stop"])
|
|
101
|
+
}, [
|
|
102
|
+
_cache[0] || (_cache[0] = createElementVNode("svg", {
|
|
103
|
+
class: "mld-experiment-popover__trigger-icon",
|
|
104
|
+
fill: "none",
|
|
105
|
+
stroke: "currentColor",
|
|
106
|
+
viewBox: "0 0 24 24"
|
|
107
|
+
}, [
|
|
108
|
+
createElementVNode("path", {
|
|
109
|
+
"stroke-linecap": "round",
|
|
110
|
+
"stroke-linejoin": "round",
|
|
111
|
+
"stroke-width": "1.75",
|
|
112
|
+
d: "M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
|
|
113
|
+
})
|
|
114
|
+
], -1)),
|
|
115
|
+
createElementVNode("span", _hoisted_1, toDisplayString(__props.experimentName || "No experiment"), 1),
|
|
116
|
+
_cache[1] || (_cache[1] = createElementVNode("svg", {
|
|
117
|
+
class: "mld-experiment-popover__trigger-chevron",
|
|
118
|
+
viewBox: "0 0 24 24",
|
|
119
|
+
fill: "none",
|
|
120
|
+
stroke: "currentColor",
|
|
121
|
+
"stroke-width": "2",
|
|
122
|
+
"stroke-linecap": "round",
|
|
123
|
+
"stroke-linejoin": "round"
|
|
124
|
+
}, [
|
|
125
|
+
createElementVNode("path", { d: "m6 9 6 6 6-6" })
|
|
126
|
+
], -1))
|
|
127
|
+
], 2),
|
|
128
|
+
isOpen.value ? (openBlock(), createElementBlock("div", _hoisted_2, [
|
|
129
|
+
_cache[6] || (_cache[6] = createElementVNode("div", { class: "mld-experiment-popover__header" }, [
|
|
130
|
+
createElementVNode("div", { class: "mld-experiment-popover__title" }, "Experiment")
|
|
131
|
+
], -1)),
|
|
132
|
+
!__props.experimentName ? (openBlock(), createElementBlock("div", _hoisted_3, [
|
|
133
|
+
createElementVNode("button", {
|
|
134
|
+
type: "button",
|
|
135
|
+
class: "mld-experiment-popover__select-btn",
|
|
136
|
+
onClick: handleSelect
|
|
137
|
+
}, [..._cache[2] || (_cache[2] = [
|
|
138
|
+
createElementVNode("svg", {
|
|
139
|
+
width: "14",
|
|
140
|
+
height: "14",
|
|
141
|
+
fill: "none",
|
|
142
|
+
stroke: "currentColor",
|
|
143
|
+
viewBox: "0 0 24 24"
|
|
144
|
+
}, [
|
|
145
|
+
createElementVNode("path", {
|
|
146
|
+
"stroke-linecap": "round",
|
|
147
|
+
"stroke-linejoin": "round",
|
|
148
|
+
"stroke-width": "2",
|
|
149
|
+
d: "M12 4v16m8-8H4"
|
|
150
|
+
})
|
|
151
|
+
], -1),
|
|
152
|
+
createTextVNode(" Select Experiment ", -1)
|
|
153
|
+
])])
|
|
154
|
+
])) : (openBlock(), createElementBlock("div", _hoisted_4, [
|
|
155
|
+
_cache[3] || (_cache[3] = createElementVNode("div", { class: "mld-experiment-popover__card-icon" }, [
|
|
156
|
+
createElementVNode("svg", {
|
|
157
|
+
fill: "none",
|
|
158
|
+
stroke: "currentColor",
|
|
159
|
+
viewBox: "0 0 24 24"
|
|
160
|
+
}, [
|
|
161
|
+
createElementVNode("path", {
|
|
162
|
+
"stroke-linecap": "round",
|
|
163
|
+
"stroke-linejoin": "round",
|
|
164
|
+
"stroke-width": "1.75",
|
|
165
|
+
d: "M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
|
|
166
|
+
})
|
|
167
|
+
])
|
|
168
|
+
], -1)),
|
|
169
|
+
createElementVNode("div", _hoisted_5, [
|
|
170
|
+
createElementVNode("div", _hoisted_6, toDisplayString(__props.experimentName), 1),
|
|
171
|
+
__props.experimentStatus ? (openBlock(), createElementBlock("div", _hoisted_7, toDisplayString(formatStatus(__props.experimentStatus)), 1)) : createCommentVNode("", true)
|
|
172
|
+
]),
|
|
173
|
+
createElementVNode("button", {
|
|
174
|
+
type: "button",
|
|
175
|
+
class: "mld-experiment-popover__change-btn",
|
|
176
|
+
onClick: handleSelect
|
|
177
|
+
}, " Change ")
|
|
178
|
+
])),
|
|
179
|
+
__props.showSave ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
|
|
180
|
+
_cache[5] || (_cache[5] = createElementVNode("div", { class: "mld-experiment-popover__divider" }, null, -1)),
|
|
181
|
+
createElementVNode("div", _hoisted_8, [
|
|
182
|
+
createElementVNode("button", {
|
|
183
|
+
type: "button",
|
|
184
|
+
class: normalizeClass([
|
|
185
|
+
"mld-experiment-popover__save-btn",
|
|
186
|
+
{ "mld-experiment-popover__save-btn--loading": __props.saveLoading },
|
|
187
|
+
{ "mld-experiment-popover__save-btn--success": showSuccess.value }
|
|
188
|
+
]),
|
|
189
|
+
disabled: __props.saveDisabled && !showSuccess.value,
|
|
190
|
+
onClick: handleSave
|
|
191
|
+
}, [
|
|
192
|
+
__props.saveLoading ? (openBlock(), createElementBlock("span", _hoisted_10)) : showSuccess.value ? (openBlock(), createElementBlock("svg", _hoisted_11, [..._cache[4] || (_cache[4] = [
|
|
193
|
+
createElementVNode("path", {
|
|
194
|
+
"stroke-linecap": "round",
|
|
195
|
+
"stroke-linejoin": "round",
|
|
196
|
+
"stroke-width": "2",
|
|
197
|
+
d: "M5 13l4 4L19 7"
|
|
198
|
+
}, null, -1)
|
|
199
|
+
])])) : createCommentVNode("", true),
|
|
200
|
+
createElementVNode("span", null, toDisplayString(showSuccess.value && __props.saveSuccessMessage ? __props.saveSuccessMessage : "Save to Experiment"), 1)
|
|
201
|
+
], 10, _hoisted_9)
|
|
202
|
+
])
|
|
203
|
+
], 64)) : createCommentVNode("", true)
|
|
204
|
+
])) : createCommentVNode("", true)
|
|
205
|
+
], 512);
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
export {
|
|
210
|
+
_sfc_main as default
|
|
211
|
+
};
|
|
212
|
+
//# sourceMappingURL=ExperimentPopover.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExperimentPopover.vue.js","sources":["../../src/components/ExperimentPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onUnmounted } from 'vue'\n\ninterface Props {\n experimentName?: string\n experimentStatus?: string\n showSave?: boolean\n saveDisabled?: boolean\n saveLoading?: boolean\n saveSuccessMessage?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showSave: false,\n saveDisabled: false,\n saveLoading: false,\n})\n\nconst emit = defineEmits<{\n select: []\n save: []\n}>()\n\nconst isOpen = ref(false)\nconst popoverRef = ref<HTMLElement | null>(null)\nconst showSuccess = ref(false)\n\nfunction toggle() {\n isOpen.value = !isOpen.value\n}\n\nfunction close() {\n isOpen.value = false\n}\n\nfunction handleSelect() {\n emit('select')\n close()\n}\n\nfunction handleSave() {\n if (props.saveDisabled || props.saveLoading) return\n emit('save')\n}\n\nfunction handleClickOutside(event: MouseEvent) {\n if (popoverRef.value && !popoverRef.value.contains(event.target as Node)) {\n close()\n }\n}\n\n// Show success state when saveSuccessMessage changes from empty to a value\nwatch(() => props.saveSuccessMessage, (msg) => {\n if (msg) {\n showSuccess.value = true\n setTimeout(() => {\n showSuccess.value = false\n }, 3000)\n }\n})\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n})\n\n// Format status for display (e.g., \"ready_to_extract\" -> \"Ready to extract\")\nfunction formatStatus(status: string): string {\n return status.replace(/_/g, ' ').replace(/^\\w/, c => c.toUpperCase())\n}\n</script>\n\n<template>\n <div ref=\"popoverRef\" class=\"mld-experiment-popover\">\n <!-- Trigger button -->\n <button\n type=\"button\"\n :class=\"[\n 'mld-experiment-popover__trigger',\n { 'mld-experiment-popover__trigger--active': isOpen },\n { 'mld-experiment-popover__trigger--empty': !experimentName },\n ]\"\n @click.stop=\"toggle\"\n >\n <!-- Flask icon -->\n <svg class=\"mld-experiment-popover__trigger-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n <span class=\"mld-experiment-popover__trigger-text\">\n {{ experimentName || 'No experiment' }}\n </span>\n <!-- Chevron -->\n <svg class=\"mld-experiment-popover__trigger-chevron\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Popover panel -->\n <div v-if=\"isOpen\" class=\"mld-experiment-popover__panel\">\n <!-- Header -->\n <div class=\"mld-experiment-popover__header\">\n <div class=\"mld-experiment-popover__title\">Experiment</div>\n </div>\n\n <!-- No experiment selected -->\n <div v-if=\"!experimentName\" class=\"mld-experiment-popover__empty\">\n <button type=\"button\" class=\"mld-experiment-popover__select-btn\" @click=\"handleSelect\">\n <svg width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16m8-8H4\" />\n </svg>\n Select Experiment\n </button>\n </div>\n\n <!-- Experiment selected -->\n <div v-else class=\"mld-experiment-popover__card\">\n <div class=\"mld-experiment-popover__card-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.75\"\n d=\"M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z\"\n />\n </svg>\n </div>\n <div class=\"mld-experiment-popover__card-info\">\n <div class=\"mld-experiment-popover__card-name\">{{ experimentName }}</div>\n <div v-if=\"experimentStatus\" class=\"mld-experiment-popover__card-status\">\n {{ formatStatus(experimentStatus) }}\n </div>\n </div>\n <button type=\"button\" class=\"mld-experiment-popover__change-btn\" @click=\"handleSelect\">\n Change\n </button>\n </div>\n\n <!-- Save section -->\n <template v-if=\"showSave\">\n <div class=\"mld-experiment-popover__divider\" />\n <div class=\"mld-experiment-popover__footer\">\n <button\n type=\"button\"\n :class=\"[\n 'mld-experiment-popover__save-btn',\n { 'mld-experiment-popover__save-btn--loading': saveLoading },\n { 'mld-experiment-popover__save-btn--success': showSuccess },\n ]\"\n :disabled=\"saveDisabled && !showSuccess\"\n @click=\"handleSave\"\n >\n <!-- Loading spinner -->\n <span v-if=\"saveLoading\" class=\"mld-experiment-popover__spinner\" />\n <!-- Success check -->\n <svg v-else-if=\"showSuccess\" class=\"mld-experiment-popover__check-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n <!-- Label -->\n <span>{{ showSuccess && saveSuccessMessage ? saveSuccessMessage : 'Save to Experiment' }}</span>\n </button>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/experiment-popover.css';\n</style>\n"],"names":["_createElementBlock","_createElementVNode","_normalizeClass","_toDisplayString","_openBlock","_Fragment"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExperimentPopover.vue3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -77,4 +77,5 @@ export { default as TimeRangeInput } from './TimeRangeInput.vue';
|
|
|
77
77
|
export { default as ScheduleCalendar } from './ScheduleCalendar.vue';
|
|
78
78
|
export { default as ResourceCard } from './ResourceCard.vue';
|
|
79
79
|
export { default as ExperimentSelectorModal } from './ExperimentSelectorModal.vue';
|
|
80
|
+
export { default as ExperimentPopover } from './ExperimentPopover.vue';
|
|
80
81
|
export { default as FitPanel } from './FitPanel.vue';
|
package/dist/components/index.js
CHANGED
|
@@ -154,7 +154,9 @@ import { default as default79 } from "./ResourceCard.vue.js";
|
|
|
154
154
|
/* empty css */
|
|
155
155
|
import { default as default80 } from "./ExperimentSelectorModal.vue.js";
|
|
156
156
|
/* empty css */
|
|
157
|
-
import { default as default81 } from "./
|
|
157
|
+
import { default as default81 } from "./ExperimentPopover.vue.js";
|
|
158
|
+
/* empty css */
|
|
159
|
+
import { default as default82 } from "./FitPanel.vue.js";
|
|
158
160
|
/* empty css */
|
|
159
161
|
export {
|
|
160
162
|
default25 as AlertBox,
|
|
@@ -194,10 +196,11 @@ export {
|
|
|
194
196
|
default41 as EmptyState,
|
|
195
197
|
default75 as ExperimentCodeBadge,
|
|
196
198
|
default74 as ExperimentDataViewer,
|
|
199
|
+
default81 as ExperimentPopover,
|
|
197
200
|
default80 as ExperimentSelectorModal,
|
|
198
201
|
default51 as ExperimentTimeline,
|
|
199
202
|
default24 as FileUploader,
|
|
200
|
-
|
|
203
|
+
default82 as FitPanel,
|
|
201
204
|
default72 as FormActions,
|
|
202
205
|
default70 as FormBuilder,
|
|
203
206
|
default19 as FormField,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MLDSdk, default } from './install';
|
|
2
|
-
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox, ToastNotification, IconButton, ThemeToggle, SettingsButton, CollapsibleCard, AppTopBar, AppSidebar, AppLayout, AppContainer, Skeleton, WellPlate, RackEditor, SampleLegend, PlateMapEditor, ExperimentTimeline, SampleSelector, GroupingModal, AutoGroupModal, GroupAssigner, MoleculeInput, ConcentrationInput, DoseCalculator, ReagentList, SampleHierarchyTree, ProtocolStepEditor, SegmentedControl, MultiSelect, BasePill, DropdownButton, Calendar, DataFrame, LoadingSpinner, Divider, StatusIndicator, ProgressBar, Avatar, EmptyState, Breadcrumb, Tooltip, ConfirmDialog, ChartContainer, SettingsModal, ScientificNumber, ChemicalFormula, FormulaInput, SequenceInput, UnitInput, StepWizard, AuditTrail, BatchProgressList, ExperimentDataViewer, ExperimentCodeBadge, DateTimePicker, TimeRangeInput, ScheduleCalendar, ResourceCard, ExperimentSelectorModal, FitPanel, } from './components';
|
|
2
|
+
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox, ToastNotification, IconButton, ThemeToggle, SettingsButton, CollapsibleCard, AppTopBar, AppSidebar, AppLayout, AppContainer, Skeleton, WellPlate, RackEditor, SampleLegend, PlateMapEditor, ExperimentTimeline, SampleSelector, GroupingModal, AutoGroupModal, GroupAssigner, MoleculeInput, ConcentrationInput, DoseCalculator, ReagentList, SampleHierarchyTree, ProtocolStepEditor, SegmentedControl, MultiSelect, BasePill, DropdownButton, Calendar, DataFrame, LoadingSpinner, Divider, StatusIndicator, ProgressBar, Avatar, EmptyState, Breadcrumb, Tooltip, ConfirmDialog, ChartContainer, SettingsModal, ScientificNumber, ChemicalFormula, FormulaInput, SequenceInput, UnitInput, StepWizard, AuditTrail, BatchProgressList, ExperimentDataViewer, ExperimentCodeBadge, DateTimePicker, TimeRangeInput, ScheduleCalendar, ResourceCard, ExperimentSelectorModal, ExperimentPopover, FitPanel, } from './components';
|
|
3
3
|
export { useApi, useAuth, usePasskey, useTheme, useToast, usePlatformContext, useWellPlateEditor, useConcentrationUnits, useDoseCalculator, useProtocolTemplates, useRackEditor, useChemicalFormula, ATOMIC_WEIGHTS, useSequenceUtils, type ApiClientOptions, type UseWellPlateEditorOptions, type UseWellPlateEditorReturn, type UseRackEditorOptions, type UseRackEditorReturn, type ConcentrationValue, type ConcentrationUnit, type VolumeValue, type VolumeUnit, type StepTemplate, type FormulaParseResult, type FormulaPart, type SequenceType, type SequenceStats, parseTime, formatTime, generateTimeSlots, rangesOverlap, durationMinutes, formatDuration, isTimeInRange, findAvailableSlots, snapToSlot, addMinutes, compareTime, useScheduleDrag, usePluginConfig, type UsePluginConfigReturn, useAutoGroup, DEFAULT_COLORS, useExperimentSelector, type UseExperimentSelectorOptions, type UseExperimentSelectorReturn, formatExperimentDate, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, EXPERIMENT_STATUS_LABELS, useExperimentData, type UseExperimentDataOptions, type UseExperimentDataReturn, } from './composables';
|
|
4
4
|
export { useAuthStore, useSettingsStore, colorPalettes, type SettingsState, } from './stores';
|
|
5
5
|
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, OutlierAction, InputMode, OutlierInfo, ColumnInfo, MetadataRow, AutoGroupResult, ParsedCsvData, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, ExperimentStatus, ExperimentSummary, ExperimentListResponse, ExperimentFilters, FitState, FitResultSummary, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, SummaryData, SummarySection, SummarySectionItem, TreeNode, TreeNodeType, PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -149,7 +149,9 @@ import { default as default75 } from "./components/ResourceCard.vue.js";
|
|
|
149
149
|
/* empty css */
|
|
150
150
|
import { default as default76 } from "./components/ExperimentSelectorModal.vue.js";
|
|
151
151
|
/* empty css */
|
|
152
|
-
import { default as default77 } from "./components/
|
|
152
|
+
import { default as default77 } from "./components/ExperimentPopover.vue.js";
|
|
153
|
+
/* empty css */
|
|
154
|
+
import { default as default78 } from "./components/FitPanel.vue.js";
|
|
153
155
|
/* empty css */
|
|
154
156
|
import { useApi } from "./composables/useApi.js";
|
|
155
157
|
import { useAuth } from "./composables/useAuth.js";
|
|
@@ -216,10 +218,11 @@ export {
|
|
|
216
218
|
default41 as EmptyState,
|
|
217
219
|
default71 as ExperimentCodeBadge,
|
|
218
220
|
default70 as ExperimentDataViewer,
|
|
221
|
+
default77 as ExperimentPopover,
|
|
219
222
|
default76 as ExperimentSelectorModal,
|
|
220
223
|
default51 as ExperimentTimeline,
|
|
221
224
|
default24 as FileUploader,
|
|
222
|
-
|
|
225
|
+
default78 as FitPanel,
|
|
223
226
|
default19 as FormField,
|
|
224
227
|
default64 as FormulaInput,
|
|
225
228
|
default55 as GroupAssigner,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/styles.css
CHANGED
|
@@ -12765,6 +12765,223 @@ html.dark .mld-settings-modal__option-btn--active {
|
|
|
12765
12765
|
color: var(--text-muted);
|
|
12766
12766
|
margin-top: 0.125rem;
|
|
12767
12767
|
}
|
|
12768
|
+
/* ExperimentPopover - BEM-style naming */
|
|
12769
|
+
/* Trigger button */
|
|
12770
|
+
.mld-experiment-popover {
|
|
12771
|
+
position: relative;
|
|
12772
|
+
}
|
|
12773
|
+
.mld-experiment-popover__trigger {
|
|
12774
|
+
display: inline-flex;
|
|
12775
|
+
align-items: center;
|
|
12776
|
+
gap: 0.375rem;
|
|
12777
|
+
padding: 0.3125rem 0.625rem;
|
|
12778
|
+
border: 1px solid var(--border-color, var(--mld-border, #e5e7eb));
|
|
12779
|
+
background: var(--bg-secondary, var(--mld-bg-card, #ffffff));
|
|
12780
|
+
border-radius: var(--mld-radius, 0.5rem);
|
|
12781
|
+
color: var(--text-primary, var(--mld-text-primary, #111827));
|
|
12782
|
+
font-size: 0.8125rem;
|
|
12783
|
+
font-weight: 500;
|
|
12784
|
+
cursor: pointer;
|
|
12785
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
12786
|
+
white-space: nowrap;
|
|
12787
|
+
max-width: 220px;
|
|
12788
|
+
}
|
|
12789
|
+
.mld-experiment-popover__trigger:hover {
|
|
12790
|
+
border-color: var(--color-primary, #6366F1);
|
|
12791
|
+
}
|
|
12792
|
+
.mld-experiment-popover__trigger--active {
|
|
12793
|
+
border-color: var(--color-primary, #6366F1);
|
|
12794
|
+
box-shadow: 0 0 0 1px var(--color-primary, #6366F1);
|
|
12795
|
+
}
|
|
12796
|
+
.mld-experiment-popover__trigger--empty {
|
|
12797
|
+
border-style: dashed;
|
|
12798
|
+
color: var(--text-secondary, var(--mld-text-secondary, #6b7280));
|
|
12799
|
+
}
|
|
12800
|
+
.mld-experiment-popover__trigger-icon {
|
|
12801
|
+
width: 1rem;
|
|
12802
|
+
height: 1rem;
|
|
12803
|
+
flex-shrink: 0;
|
|
12804
|
+
color: var(--color-primary, #6366F1);
|
|
12805
|
+
}
|
|
12806
|
+
.mld-experiment-popover__trigger--empty .mld-experiment-popover__trigger-icon {
|
|
12807
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
12808
|
+
}
|
|
12809
|
+
.mld-experiment-popover__trigger-text {
|
|
12810
|
+
overflow: hidden;
|
|
12811
|
+
text-overflow: ellipsis;
|
|
12812
|
+
white-space: nowrap;
|
|
12813
|
+
}
|
|
12814
|
+
.mld-experiment-popover__trigger-chevron {
|
|
12815
|
+
width: 0.875rem;
|
|
12816
|
+
height: 0.875rem;
|
|
12817
|
+
flex-shrink: 0;
|
|
12818
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
12819
|
+
transition: transform 0.15s ease;
|
|
12820
|
+
}
|
|
12821
|
+
.mld-experiment-popover__trigger--active .mld-experiment-popover__trigger-chevron {
|
|
12822
|
+
transform: rotate(180deg);
|
|
12823
|
+
}
|
|
12824
|
+
/* Popover panel */
|
|
12825
|
+
.mld-experiment-popover__panel {
|
|
12826
|
+
position: absolute;
|
|
12827
|
+
top: calc(100% + 0.5rem);
|
|
12828
|
+
right: 0;
|
|
12829
|
+
width: 280px;
|
|
12830
|
+
background: var(--bg-secondary, var(--mld-bg-card, #ffffff));
|
|
12831
|
+
border: 1px solid var(--border-color, var(--mld-border, #e5e7eb));
|
|
12832
|
+
border-radius: var(--mld-radius, 0.5rem);
|
|
12833
|
+
box-shadow: var(--mld-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05));
|
|
12834
|
+
z-index: 50;
|
|
12835
|
+
overflow: hidden;
|
|
12836
|
+
}
|
|
12837
|
+
/* Header */
|
|
12838
|
+
.mld-experiment-popover__header {
|
|
12839
|
+
padding: 0.75rem 1rem 0.5rem;
|
|
12840
|
+
}
|
|
12841
|
+
.mld-experiment-popover__title {
|
|
12842
|
+
font-size: 0.75rem;
|
|
12843
|
+
font-weight: 600;
|
|
12844
|
+
text-transform: uppercase;
|
|
12845
|
+
letter-spacing: 0.05em;
|
|
12846
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
12847
|
+
}
|
|
12848
|
+
/* Empty state */
|
|
12849
|
+
.mld-experiment-popover__empty {
|
|
12850
|
+
padding: 0 1rem 0.75rem;
|
|
12851
|
+
}
|
|
12852
|
+
.mld-experiment-popover__select-btn {
|
|
12853
|
+
display: flex;
|
|
12854
|
+
align-items: center;
|
|
12855
|
+
justify-content: center;
|
|
12856
|
+
gap: 0.375rem;
|
|
12857
|
+
width: 100%;
|
|
12858
|
+
padding: 0.5rem;
|
|
12859
|
+
border: 1.5px dashed var(--color-primary, #6366F1);
|
|
12860
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.06));
|
|
12861
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
12862
|
+
color: var(--color-primary, #6366F1);
|
|
12863
|
+
font-size: 0.8125rem;
|
|
12864
|
+
font-weight: 500;
|
|
12865
|
+
cursor: pointer;
|
|
12866
|
+
transition: background-color 0.15s ease;
|
|
12867
|
+
}
|
|
12868
|
+
.mld-experiment-popover__select-btn:hover {
|
|
12869
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.12));
|
|
12870
|
+
}
|
|
12871
|
+
/* Experiment card */
|
|
12872
|
+
.mld-experiment-popover__card {
|
|
12873
|
+
display: flex;
|
|
12874
|
+
align-items: center;
|
|
12875
|
+
gap: 0.625rem;
|
|
12876
|
+
padding: 0 1rem 0.75rem;
|
|
12877
|
+
}
|
|
12878
|
+
.mld-experiment-popover__card-icon {
|
|
12879
|
+
width: 2rem;
|
|
12880
|
+
height: 2rem;
|
|
12881
|
+
flex-shrink: 0;
|
|
12882
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
12883
|
+
background: rgba(139, 92, 246, 0.12);
|
|
12884
|
+
display: flex;
|
|
12885
|
+
align-items: center;
|
|
12886
|
+
justify-content: center;
|
|
12887
|
+
}
|
|
12888
|
+
.mld-experiment-popover__card-icon svg {
|
|
12889
|
+
width: 1.125rem;
|
|
12890
|
+
height: 1.125rem;
|
|
12891
|
+
color: #8B5CF6;
|
|
12892
|
+
}
|
|
12893
|
+
.mld-experiment-popover__card-info {
|
|
12894
|
+
flex: 1;
|
|
12895
|
+
min-width: 0;
|
|
12896
|
+
}
|
|
12897
|
+
.mld-experiment-popover__card-name {
|
|
12898
|
+
font-size: 0.8125rem;
|
|
12899
|
+
font-weight: 500;
|
|
12900
|
+
color: var(--text-primary, var(--mld-text-primary, #111827));
|
|
12901
|
+
overflow: hidden;
|
|
12902
|
+
text-overflow: ellipsis;
|
|
12903
|
+
white-space: nowrap;
|
|
12904
|
+
}
|
|
12905
|
+
.mld-experiment-popover__card-status {
|
|
12906
|
+
font-size: 0.6875rem;
|
|
12907
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
12908
|
+
}
|
|
12909
|
+
.mld-experiment-popover__change-btn {
|
|
12910
|
+
flex-shrink: 0;
|
|
12911
|
+
padding: 0.25rem 0.5rem;
|
|
12912
|
+
border: none;
|
|
12913
|
+
background: transparent;
|
|
12914
|
+
border-radius: var(--mld-radius-sm, 0.25rem);
|
|
12915
|
+
color: var(--color-primary, #6366F1);
|
|
12916
|
+
font-size: 0.75rem;
|
|
12917
|
+
font-weight: 500;
|
|
12918
|
+
cursor: pointer;
|
|
12919
|
+
transition: background-color 0.15s ease;
|
|
12920
|
+
}
|
|
12921
|
+
.mld-experiment-popover__change-btn:hover {
|
|
12922
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.08));
|
|
12923
|
+
}
|
|
12924
|
+
/* Divider */
|
|
12925
|
+
.mld-experiment-popover__divider {
|
|
12926
|
+
height: 1px;
|
|
12927
|
+
background: var(--border-color, var(--mld-border, #e5e7eb));
|
|
12928
|
+
margin: 0;
|
|
12929
|
+
}
|
|
12930
|
+
/* Footer (save section) */
|
|
12931
|
+
.mld-experiment-popover__footer {
|
|
12932
|
+
padding: 0.75rem 1rem;
|
|
12933
|
+
}
|
|
12934
|
+
.mld-experiment-popover__save-btn {
|
|
12935
|
+
display: flex;
|
|
12936
|
+
align-items: center;
|
|
12937
|
+
justify-content: center;
|
|
12938
|
+
gap: 0.375rem;
|
|
12939
|
+
width: 100%;
|
|
12940
|
+
padding: 0.4375rem 0.75rem;
|
|
12941
|
+
border: none;
|
|
12942
|
+
background: var(--color-primary, #6366F1);
|
|
12943
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
12944
|
+
color: white;
|
|
12945
|
+
font-size: 0.8125rem;
|
|
12946
|
+
font-weight: 500;
|
|
12947
|
+
cursor: pointer;
|
|
12948
|
+
transition: background-color 0.15s ease, opacity 0.15s ease;
|
|
12949
|
+
}
|
|
12950
|
+
.mld-experiment-popover__save-btn:hover:not(:disabled) {
|
|
12951
|
+
background: var(--color-primary-hover, #4F46E5);
|
|
12952
|
+
}
|
|
12953
|
+
.mld-experiment-popover__save-btn:disabled {
|
|
12954
|
+
opacity: 0.5;
|
|
12955
|
+
cursor: not-allowed;
|
|
12956
|
+
}
|
|
12957
|
+
.mld-experiment-popover__save-btn--loading {
|
|
12958
|
+
opacity: 0.8;
|
|
12959
|
+
pointer-events: none;
|
|
12960
|
+
}
|
|
12961
|
+
/* Save success state */
|
|
12962
|
+
.mld-experiment-popover__save-btn--success {
|
|
12963
|
+
background: var(--mld-success-bg, #059669);
|
|
12964
|
+
}
|
|
12965
|
+
.mld-experiment-popover__save-btn--success:hover {
|
|
12966
|
+
background: var(--mld-success-bg, #059669);
|
|
12967
|
+
}
|
|
12968
|
+
/* Spinner */
|
|
12969
|
+
.mld-experiment-popover__spinner {
|
|
12970
|
+
width: 0.875rem;
|
|
12971
|
+
height: 0.875rem;
|
|
12972
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
12973
|
+
border-top-color: white;
|
|
12974
|
+
border-radius: 50%;
|
|
12975
|
+
animation: mld-experiment-popover-spin 0.6s linear infinite;
|
|
12976
|
+
}
|
|
12977
|
+
@keyframes mld-experiment-popover-spin {
|
|
12978
|
+
to { transform: rotate(360deg); }
|
|
12979
|
+
}
|
|
12980
|
+
/* Check icon for success */
|
|
12981
|
+
.mld-experiment-popover__check-icon {
|
|
12982
|
+
width: 0.875rem;
|
|
12983
|
+
height: 0.875rem;
|
|
12984
|
+
}
|
|
12768
12985
|
/* FitPanel Component Styles */
|
|
12769
12986
|
.mld-fit-panel {
|
|
12770
12987
|
display: flex;
|
|
@@ -25176,6 +25393,234 @@ to { transform: rotate(360deg);
|
|
|
25176
25393
|
color: var(--text-muted);
|
|
25177
25394
|
margin-top: 0.125rem;
|
|
25178
25395
|
}
|
|
25396
|
+
/* ExperimentPopover - BEM-style naming */
|
|
25397
|
+
|
|
25398
|
+
/* Trigger button */
|
|
25399
|
+
.mld-experiment-popover {
|
|
25400
|
+
position: relative;
|
|
25401
|
+
}
|
|
25402
|
+
.mld-experiment-popover__trigger {
|
|
25403
|
+
display: inline-flex;
|
|
25404
|
+
align-items: center;
|
|
25405
|
+
gap: 0.375rem;
|
|
25406
|
+
padding: 0.3125rem 0.625rem;
|
|
25407
|
+
border: 1px solid var(--border-color, var(--mld-border, #e5e7eb));
|
|
25408
|
+
background: var(--bg-secondary, var(--mld-bg-card, #ffffff));
|
|
25409
|
+
border-radius: var(--mld-radius, 0.5rem);
|
|
25410
|
+
color: var(--text-primary, var(--mld-text-primary, #111827));
|
|
25411
|
+
font-size: 0.8125rem;
|
|
25412
|
+
font-weight: 500;
|
|
25413
|
+
cursor: pointer;
|
|
25414
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
25415
|
+
white-space: nowrap;
|
|
25416
|
+
max-width: 220px;
|
|
25417
|
+
}
|
|
25418
|
+
.mld-experiment-popover__trigger:hover {
|
|
25419
|
+
border-color: var(--color-primary, #6366F1);
|
|
25420
|
+
}
|
|
25421
|
+
.mld-experiment-popover__trigger--active {
|
|
25422
|
+
border-color: var(--color-primary, #6366F1);
|
|
25423
|
+
box-shadow: 0 0 0 1px var(--color-primary, #6366F1);
|
|
25424
|
+
}
|
|
25425
|
+
.mld-experiment-popover__trigger--empty {
|
|
25426
|
+
border-style: dashed;
|
|
25427
|
+
color: var(--text-secondary, var(--mld-text-secondary, #6b7280));
|
|
25428
|
+
}
|
|
25429
|
+
.mld-experiment-popover__trigger-icon {
|
|
25430
|
+
width: 1rem;
|
|
25431
|
+
height: 1rem;
|
|
25432
|
+
flex-shrink: 0;
|
|
25433
|
+
color: var(--color-primary, #6366F1);
|
|
25434
|
+
}
|
|
25435
|
+
.mld-experiment-popover__trigger--empty .mld-experiment-popover__trigger-icon {
|
|
25436
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
25437
|
+
}
|
|
25438
|
+
.mld-experiment-popover__trigger-text {
|
|
25439
|
+
overflow: hidden;
|
|
25440
|
+
text-overflow: ellipsis;
|
|
25441
|
+
white-space: nowrap;
|
|
25442
|
+
}
|
|
25443
|
+
.mld-experiment-popover__trigger-chevron {
|
|
25444
|
+
width: 0.875rem;
|
|
25445
|
+
height: 0.875rem;
|
|
25446
|
+
flex-shrink: 0;
|
|
25447
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
25448
|
+
transition: transform 0.15s ease;
|
|
25449
|
+
}
|
|
25450
|
+
.mld-experiment-popover__trigger--active .mld-experiment-popover__trigger-chevron {
|
|
25451
|
+
transform: rotate(180deg);
|
|
25452
|
+
}
|
|
25453
|
+
|
|
25454
|
+
/* Popover panel */
|
|
25455
|
+
.mld-experiment-popover__panel {
|
|
25456
|
+
position: absolute;
|
|
25457
|
+
top: calc(100% + 0.5rem);
|
|
25458
|
+
right: 0;
|
|
25459
|
+
width: 280px;
|
|
25460
|
+
background: var(--bg-secondary, var(--mld-bg-card, #ffffff));
|
|
25461
|
+
border: 1px solid var(--border-color, var(--mld-border, #e5e7eb));
|
|
25462
|
+
border-radius: var(--mld-radius, 0.5rem);
|
|
25463
|
+
box-shadow: var(--mld-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05));
|
|
25464
|
+
z-index: 50;
|
|
25465
|
+
overflow: hidden;
|
|
25466
|
+
}
|
|
25467
|
+
|
|
25468
|
+
/* Header */
|
|
25469
|
+
.mld-experiment-popover__header {
|
|
25470
|
+
padding: 0.75rem 1rem 0.5rem;
|
|
25471
|
+
}
|
|
25472
|
+
.mld-experiment-popover__title {
|
|
25473
|
+
font-size: 0.75rem;
|
|
25474
|
+
font-weight: 600;
|
|
25475
|
+
text-transform: uppercase;
|
|
25476
|
+
letter-spacing: 0.05em;
|
|
25477
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
25478
|
+
}
|
|
25479
|
+
|
|
25480
|
+
/* Empty state */
|
|
25481
|
+
.mld-experiment-popover__empty {
|
|
25482
|
+
padding: 0 1rem 0.75rem;
|
|
25483
|
+
}
|
|
25484
|
+
.mld-experiment-popover__select-btn {
|
|
25485
|
+
display: flex;
|
|
25486
|
+
align-items: center;
|
|
25487
|
+
justify-content: center;
|
|
25488
|
+
gap: 0.375rem;
|
|
25489
|
+
width: 100%;
|
|
25490
|
+
padding: 0.5rem;
|
|
25491
|
+
border: 1.5px dashed var(--color-primary, #6366F1);
|
|
25492
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.06));
|
|
25493
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
25494
|
+
color: var(--color-primary, #6366F1);
|
|
25495
|
+
font-size: 0.8125rem;
|
|
25496
|
+
font-weight: 500;
|
|
25497
|
+
cursor: pointer;
|
|
25498
|
+
transition: background-color 0.15s ease;
|
|
25499
|
+
}
|
|
25500
|
+
.mld-experiment-popover__select-btn:hover {
|
|
25501
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.12));
|
|
25502
|
+
}
|
|
25503
|
+
|
|
25504
|
+
/* Experiment card */
|
|
25505
|
+
.mld-experiment-popover__card {
|
|
25506
|
+
display: flex;
|
|
25507
|
+
align-items: center;
|
|
25508
|
+
gap: 0.625rem;
|
|
25509
|
+
padding: 0 1rem 0.75rem;
|
|
25510
|
+
}
|
|
25511
|
+
.mld-experiment-popover__card-icon {
|
|
25512
|
+
width: 2rem;
|
|
25513
|
+
height: 2rem;
|
|
25514
|
+
flex-shrink: 0;
|
|
25515
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
25516
|
+
background: rgba(139, 92, 246, 0.12);
|
|
25517
|
+
display: flex;
|
|
25518
|
+
align-items: center;
|
|
25519
|
+
justify-content: center;
|
|
25520
|
+
}
|
|
25521
|
+
.mld-experiment-popover__card-icon svg {
|
|
25522
|
+
width: 1.125rem;
|
|
25523
|
+
height: 1.125rem;
|
|
25524
|
+
color: #8B5CF6;
|
|
25525
|
+
}
|
|
25526
|
+
.mld-experiment-popover__card-info {
|
|
25527
|
+
flex: 1;
|
|
25528
|
+
min-width: 0;
|
|
25529
|
+
}
|
|
25530
|
+
.mld-experiment-popover__card-name {
|
|
25531
|
+
font-size: 0.8125rem;
|
|
25532
|
+
font-weight: 500;
|
|
25533
|
+
color: var(--text-primary, var(--mld-text-primary, #111827));
|
|
25534
|
+
overflow: hidden;
|
|
25535
|
+
text-overflow: ellipsis;
|
|
25536
|
+
white-space: nowrap;
|
|
25537
|
+
}
|
|
25538
|
+
.mld-experiment-popover__card-status {
|
|
25539
|
+
font-size: 0.6875rem;
|
|
25540
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
25541
|
+
}
|
|
25542
|
+
.mld-experiment-popover__change-btn {
|
|
25543
|
+
flex-shrink: 0;
|
|
25544
|
+
padding: 0.25rem 0.5rem;
|
|
25545
|
+
border: none;
|
|
25546
|
+
background: transparent;
|
|
25547
|
+
border-radius: var(--mld-radius-sm, 0.25rem);
|
|
25548
|
+
color: var(--color-primary, #6366F1);
|
|
25549
|
+
font-size: 0.75rem;
|
|
25550
|
+
font-weight: 500;
|
|
25551
|
+
cursor: pointer;
|
|
25552
|
+
transition: background-color 0.15s ease;
|
|
25553
|
+
}
|
|
25554
|
+
.mld-experiment-popover__change-btn:hover {
|
|
25555
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.08));
|
|
25556
|
+
}
|
|
25557
|
+
|
|
25558
|
+
/* Divider */
|
|
25559
|
+
.mld-experiment-popover__divider {
|
|
25560
|
+
height: 1px;
|
|
25561
|
+
background: var(--border-color, var(--mld-border, #e5e7eb));
|
|
25562
|
+
margin: 0;
|
|
25563
|
+
}
|
|
25564
|
+
|
|
25565
|
+
/* Footer (save section) */
|
|
25566
|
+
.mld-experiment-popover__footer {
|
|
25567
|
+
padding: 0.75rem 1rem;
|
|
25568
|
+
}
|
|
25569
|
+
.mld-experiment-popover__save-btn {
|
|
25570
|
+
display: flex;
|
|
25571
|
+
align-items: center;
|
|
25572
|
+
justify-content: center;
|
|
25573
|
+
gap: 0.375rem;
|
|
25574
|
+
width: 100%;
|
|
25575
|
+
padding: 0.4375rem 0.75rem;
|
|
25576
|
+
border: none;
|
|
25577
|
+
background: var(--color-primary, #6366F1);
|
|
25578
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
25579
|
+
color: white;
|
|
25580
|
+
font-size: 0.8125rem;
|
|
25581
|
+
font-weight: 500;
|
|
25582
|
+
cursor: pointer;
|
|
25583
|
+
transition: background-color 0.15s ease, opacity 0.15s ease;
|
|
25584
|
+
}
|
|
25585
|
+
.mld-experiment-popover__save-btn:hover:not(:disabled) {
|
|
25586
|
+
background: var(--color-primary-hover, #4F46E5);
|
|
25587
|
+
}
|
|
25588
|
+
.mld-experiment-popover__save-btn:disabled {
|
|
25589
|
+
opacity: 0.5;
|
|
25590
|
+
cursor: not-allowed;
|
|
25591
|
+
}
|
|
25592
|
+
.mld-experiment-popover__save-btn--loading {
|
|
25593
|
+
opacity: 0.8;
|
|
25594
|
+
pointer-events: none;
|
|
25595
|
+
}
|
|
25596
|
+
|
|
25597
|
+
/* Save success state */
|
|
25598
|
+
.mld-experiment-popover__save-btn--success {
|
|
25599
|
+
background: var(--mld-success-bg, #059669);
|
|
25600
|
+
}
|
|
25601
|
+
.mld-experiment-popover__save-btn--success:hover {
|
|
25602
|
+
background: var(--mld-success-bg, #059669);
|
|
25603
|
+
}
|
|
25604
|
+
|
|
25605
|
+
/* Spinner */
|
|
25606
|
+
.mld-experiment-popover__spinner {
|
|
25607
|
+
width: 0.875rem;
|
|
25608
|
+
height: 0.875rem;
|
|
25609
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
25610
|
+
border-top-color: white;
|
|
25611
|
+
border-radius: 50%;
|
|
25612
|
+
animation: mld-experiment-popover-spin 0.6s linear infinite;
|
|
25613
|
+
}
|
|
25614
|
+
@keyframes mld-experiment-popover-spin {
|
|
25615
|
+
to { transform: rotate(360deg);
|
|
25616
|
+
}
|
|
25617
|
+
}
|
|
25618
|
+
|
|
25619
|
+
/* Check icon for success */
|
|
25620
|
+
.mld-experiment-popover__check-icon {
|
|
25621
|
+
width: 0.875rem;
|
|
25622
|
+
height: 0.875rem;
|
|
25623
|
+
}
|
|
25179
25624
|
/* FitPanel Component Styles */
|
|
25180
25625
|
.mld-fit-panel {
|
|
25181
25626
|
display: flex;
|
package/package.json
CHANGED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch, onMounted, onUnmounted } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
experimentName?: string
|
|
6
|
+
experimentStatus?: string
|
|
7
|
+
showSave?: boolean
|
|
8
|
+
saveDisabled?: boolean
|
|
9
|
+
saveLoading?: boolean
|
|
10
|
+
saveSuccessMessage?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
14
|
+
showSave: false,
|
|
15
|
+
saveDisabled: false,
|
|
16
|
+
saveLoading: false,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const emit = defineEmits<{
|
|
20
|
+
select: []
|
|
21
|
+
save: []
|
|
22
|
+
}>()
|
|
23
|
+
|
|
24
|
+
const isOpen = ref(false)
|
|
25
|
+
const popoverRef = ref<HTMLElement | null>(null)
|
|
26
|
+
const showSuccess = ref(false)
|
|
27
|
+
|
|
28
|
+
function toggle() {
|
|
29
|
+
isOpen.value = !isOpen.value
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function close() {
|
|
33
|
+
isOpen.value = false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function handleSelect() {
|
|
37
|
+
emit('select')
|
|
38
|
+
close()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function handleSave() {
|
|
42
|
+
if (props.saveDisabled || props.saveLoading) return
|
|
43
|
+
emit('save')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function handleClickOutside(event: MouseEvent) {
|
|
47
|
+
if (popoverRef.value && !popoverRef.value.contains(event.target as Node)) {
|
|
48
|
+
close()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Show success state when saveSuccessMessage changes from empty to a value
|
|
53
|
+
watch(() => props.saveSuccessMessage, (msg) => {
|
|
54
|
+
if (msg) {
|
|
55
|
+
showSuccess.value = true
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
showSuccess.value = false
|
|
58
|
+
}, 3000)
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
onMounted(() => {
|
|
63
|
+
document.addEventListener('click', handleClickOutside)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
onUnmounted(() => {
|
|
67
|
+
document.removeEventListener('click', handleClickOutside)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// Format status for display (e.g., "ready_to_extract" -> "Ready to extract")
|
|
71
|
+
function formatStatus(status: string): string {
|
|
72
|
+
return status.replace(/_/g, ' ').replace(/^\w/, c => c.toUpperCase())
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<div ref="popoverRef" class="mld-experiment-popover">
|
|
78
|
+
<!-- Trigger button -->
|
|
79
|
+
<button
|
|
80
|
+
type="button"
|
|
81
|
+
:class="[
|
|
82
|
+
'mld-experiment-popover__trigger',
|
|
83
|
+
{ 'mld-experiment-popover__trigger--active': isOpen },
|
|
84
|
+
{ 'mld-experiment-popover__trigger--empty': !experimentName },
|
|
85
|
+
]"
|
|
86
|
+
@click.stop="toggle"
|
|
87
|
+
>
|
|
88
|
+
<!-- Flask icon -->
|
|
89
|
+
<svg class="mld-experiment-popover__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
90
|
+
<path
|
|
91
|
+
stroke-linecap="round"
|
|
92
|
+
stroke-linejoin="round"
|
|
93
|
+
stroke-width="1.75"
|
|
94
|
+
d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
|
|
95
|
+
/>
|
|
96
|
+
</svg>
|
|
97
|
+
<span class="mld-experiment-popover__trigger-text">
|
|
98
|
+
{{ experimentName || 'No experiment' }}
|
|
99
|
+
</span>
|
|
100
|
+
<!-- Chevron -->
|
|
101
|
+
<svg class="mld-experiment-popover__trigger-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
102
|
+
<path d="m6 9 6 6 6-6" />
|
|
103
|
+
</svg>
|
|
104
|
+
</button>
|
|
105
|
+
|
|
106
|
+
<!-- Popover panel -->
|
|
107
|
+
<div v-if="isOpen" class="mld-experiment-popover__panel">
|
|
108
|
+
<!-- Header -->
|
|
109
|
+
<div class="mld-experiment-popover__header">
|
|
110
|
+
<div class="mld-experiment-popover__title">Experiment</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<!-- No experiment selected -->
|
|
114
|
+
<div v-if="!experimentName" class="mld-experiment-popover__empty">
|
|
115
|
+
<button type="button" class="mld-experiment-popover__select-btn" @click="handleSelect">
|
|
116
|
+
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
117
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
118
|
+
</svg>
|
|
119
|
+
Select Experiment
|
|
120
|
+
</button>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- Experiment selected -->
|
|
124
|
+
<div v-else class="mld-experiment-popover__card">
|
|
125
|
+
<div class="mld-experiment-popover__card-icon">
|
|
126
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
127
|
+
<path
|
|
128
|
+
stroke-linecap="round"
|
|
129
|
+
stroke-linejoin="round"
|
|
130
|
+
stroke-width="1.75"
|
|
131
|
+
d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"
|
|
132
|
+
/>
|
|
133
|
+
</svg>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="mld-experiment-popover__card-info">
|
|
136
|
+
<div class="mld-experiment-popover__card-name">{{ experimentName }}</div>
|
|
137
|
+
<div v-if="experimentStatus" class="mld-experiment-popover__card-status">
|
|
138
|
+
{{ formatStatus(experimentStatus) }}
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
<button type="button" class="mld-experiment-popover__change-btn" @click="handleSelect">
|
|
142
|
+
Change
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<!-- Save section -->
|
|
147
|
+
<template v-if="showSave">
|
|
148
|
+
<div class="mld-experiment-popover__divider" />
|
|
149
|
+
<div class="mld-experiment-popover__footer">
|
|
150
|
+
<button
|
|
151
|
+
type="button"
|
|
152
|
+
:class="[
|
|
153
|
+
'mld-experiment-popover__save-btn',
|
|
154
|
+
{ 'mld-experiment-popover__save-btn--loading': saveLoading },
|
|
155
|
+
{ 'mld-experiment-popover__save-btn--success': showSuccess },
|
|
156
|
+
]"
|
|
157
|
+
:disabled="saveDisabled && !showSuccess"
|
|
158
|
+
@click="handleSave"
|
|
159
|
+
>
|
|
160
|
+
<!-- Loading spinner -->
|
|
161
|
+
<span v-if="saveLoading" class="mld-experiment-popover__spinner" />
|
|
162
|
+
<!-- Success check -->
|
|
163
|
+
<svg v-else-if="showSuccess" class="mld-experiment-popover__check-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
164
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
165
|
+
</svg>
|
|
166
|
+
<!-- Label -->
|
|
167
|
+
<span>{{ showSuccess && saveSuccessMessage ? saveSuccessMessage : 'Save to Experiment' }}</span>
|
|
168
|
+
</button>
|
|
169
|
+
</div>
|
|
170
|
+
</template>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<style>
|
|
176
|
+
@import '../styles/components/experiment-popover.css';
|
|
177
|
+
</style>
|
package/src/components/index.ts
CHANGED
|
@@ -108,4 +108,5 @@ export { default as ResourceCard } from './ResourceCard.vue'
|
|
|
108
108
|
|
|
109
109
|
// Experiment / analysis components
|
|
110
110
|
export { default as ExperimentSelectorModal } from './ExperimentSelectorModal.vue'
|
|
111
|
+
export { default as ExperimentPopover } from './ExperimentPopover.vue'
|
|
111
112
|
export { default as FitPanel } from './FitPanel.vue'
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/* ExperimentPopover - BEM-style naming */
|
|
2
|
+
|
|
3
|
+
/* Trigger button */
|
|
4
|
+
.mld-experiment-popover {
|
|
5
|
+
position: relative;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.mld-experiment-popover__trigger {
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
gap: 0.375rem;
|
|
12
|
+
padding: 0.3125rem 0.625rem;
|
|
13
|
+
border: 1px solid var(--border-color, var(--mld-border, #e5e7eb));
|
|
14
|
+
background: var(--bg-secondary, var(--mld-bg-card, #ffffff));
|
|
15
|
+
border-radius: var(--mld-radius, 0.5rem);
|
|
16
|
+
color: var(--text-primary, var(--mld-text-primary, #111827));
|
|
17
|
+
font-size: 0.8125rem;
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
max-width: 220px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.mld-experiment-popover__trigger:hover {
|
|
26
|
+
border-color: var(--color-primary, #6366F1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.mld-experiment-popover__trigger--active {
|
|
30
|
+
border-color: var(--color-primary, #6366F1);
|
|
31
|
+
box-shadow: 0 0 0 1px var(--color-primary, #6366F1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.mld-experiment-popover__trigger--empty {
|
|
35
|
+
border-style: dashed;
|
|
36
|
+
color: var(--text-secondary, var(--mld-text-secondary, #6b7280));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.mld-experiment-popover__trigger-icon {
|
|
40
|
+
width: 1rem;
|
|
41
|
+
height: 1rem;
|
|
42
|
+
flex-shrink: 0;
|
|
43
|
+
color: var(--color-primary, #6366F1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.mld-experiment-popover__trigger--empty .mld-experiment-popover__trigger-icon {
|
|
47
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.mld-experiment-popover__trigger-text {
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
text-overflow: ellipsis;
|
|
53
|
+
white-space: nowrap;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.mld-experiment-popover__trigger-chevron {
|
|
57
|
+
width: 0.875rem;
|
|
58
|
+
height: 0.875rem;
|
|
59
|
+
flex-shrink: 0;
|
|
60
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
61
|
+
transition: transform 0.15s ease;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.mld-experiment-popover__trigger--active .mld-experiment-popover__trigger-chevron {
|
|
65
|
+
transform: rotate(180deg);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Popover panel */
|
|
69
|
+
.mld-experiment-popover__panel {
|
|
70
|
+
position: absolute;
|
|
71
|
+
top: calc(100% + 0.5rem);
|
|
72
|
+
right: 0;
|
|
73
|
+
width: 280px;
|
|
74
|
+
background: var(--bg-secondary, var(--mld-bg-card, #ffffff));
|
|
75
|
+
border: 1px solid var(--border-color, var(--mld-border, #e5e7eb));
|
|
76
|
+
border-radius: var(--mld-radius, 0.5rem);
|
|
77
|
+
box-shadow: var(--mld-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05));
|
|
78
|
+
z-index: 50;
|
|
79
|
+
overflow: hidden;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Header */
|
|
83
|
+
.mld-experiment-popover__header {
|
|
84
|
+
padding: 0.75rem 1rem 0.5rem;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.mld-experiment-popover__title {
|
|
88
|
+
font-size: 0.75rem;
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
text-transform: uppercase;
|
|
91
|
+
letter-spacing: 0.05em;
|
|
92
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Empty state */
|
|
96
|
+
.mld-experiment-popover__empty {
|
|
97
|
+
padding: 0 1rem 0.75rem;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.mld-experiment-popover__select-btn {
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
justify-content: center;
|
|
104
|
+
gap: 0.375rem;
|
|
105
|
+
width: 100%;
|
|
106
|
+
padding: 0.5rem;
|
|
107
|
+
border: 1.5px dashed var(--color-primary, #6366F1);
|
|
108
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.06));
|
|
109
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
110
|
+
color: var(--color-primary, #6366F1);
|
|
111
|
+
font-size: 0.8125rem;
|
|
112
|
+
font-weight: 500;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
transition: background-color 0.15s ease;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.mld-experiment-popover__select-btn:hover {
|
|
118
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.12));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Experiment card */
|
|
122
|
+
.mld-experiment-popover__card {
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
gap: 0.625rem;
|
|
126
|
+
padding: 0 1rem 0.75rem;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.mld-experiment-popover__card-icon {
|
|
130
|
+
width: 2rem;
|
|
131
|
+
height: 2rem;
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
134
|
+
background: rgba(139, 92, 246, 0.12);
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.mld-experiment-popover__card-icon svg {
|
|
141
|
+
width: 1.125rem;
|
|
142
|
+
height: 1.125rem;
|
|
143
|
+
color: #8B5CF6;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.mld-experiment-popover__card-info {
|
|
147
|
+
flex: 1;
|
|
148
|
+
min-width: 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.mld-experiment-popover__card-name {
|
|
152
|
+
font-size: 0.8125rem;
|
|
153
|
+
font-weight: 500;
|
|
154
|
+
color: var(--text-primary, var(--mld-text-primary, #111827));
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
text-overflow: ellipsis;
|
|
157
|
+
white-space: nowrap;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.mld-experiment-popover__card-status {
|
|
161
|
+
font-size: 0.6875rem;
|
|
162
|
+
color: var(--text-muted, var(--mld-text-muted, #9ca3af));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.mld-experiment-popover__change-btn {
|
|
166
|
+
flex-shrink: 0;
|
|
167
|
+
padding: 0.25rem 0.5rem;
|
|
168
|
+
border: none;
|
|
169
|
+
background: transparent;
|
|
170
|
+
border-radius: var(--mld-radius-sm, 0.25rem);
|
|
171
|
+
color: var(--color-primary, #6366F1);
|
|
172
|
+
font-size: 0.75rem;
|
|
173
|
+
font-weight: 500;
|
|
174
|
+
cursor: pointer;
|
|
175
|
+
transition: background-color 0.15s ease;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.mld-experiment-popover__change-btn:hover {
|
|
179
|
+
background: var(--color-primary-soft, rgba(99, 102, 241, 0.08));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Divider */
|
|
183
|
+
.mld-experiment-popover__divider {
|
|
184
|
+
height: 1px;
|
|
185
|
+
background: var(--border-color, var(--mld-border, #e5e7eb));
|
|
186
|
+
margin: 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Footer (save section) */
|
|
190
|
+
.mld-experiment-popover__footer {
|
|
191
|
+
padding: 0.75rem 1rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.mld-experiment-popover__save-btn {
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
justify-content: center;
|
|
198
|
+
gap: 0.375rem;
|
|
199
|
+
width: 100%;
|
|
200
|
+
padding: 0.4375rem 0.75rem;
|
|
201
|
+
border: none;
|
|
202
|
+
background: var(--color-primary, #6366F1);
|
|
203
|
+
border-radius: var(--mld-radius-sm, 0.375rem);
|
|
204
|
+
color: white;
|
|
205
|
+
font-size: 0.8125rem;
|
|
206
|
+
font-weight: 500;
|
|
207
|
+
cursor: pointer;
|
|
208
|
+
transition: background-color 0.15s ease, opacity 0.15s ease;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.mld-experiment-popover__save-btn:hover:not(:disabled) {
|
|
212
|
+
background: var(--color-primary-hover, #4F46E5);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.mld-experiment-popover__save-btn:disabled {
|
|
216
|
+
opacity: 0.5;
|
|
217
|
+
cursor: not-allowed;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.mld-experiment-popover__save-btn--loading {
|
|
221
|
+
opacity: 0.8;
|
|
222
|
+
pointer-events: none;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* Save success state */
|
|
226
|
+
.mld-experiment-popover__save-btn--success {
|
|
227
|
+
background: var(--mld-success-bg, #059669);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.mld-experiment-popover__save-btn--success:hover {
|
|
231
|
+
background: var(--mld-success-bg, #059669);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Spinner */
|
|
235
|
+
.mld-experiment-popover__spinner {
|
|
236
|
+
width: 0.875rem;
|
|
237
|
+
height: 0.875rem;
|
|
238
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
239
|
+
border-top-color: white;
|
|
240
|
+
border-radius: 50%;
|
|
241
|
+
animation: mld-experiment-popover-spin 0.6s linear infinite;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@keyframes mld-experiment-popover-spin {
|
|
245
|
+
to { transform: rotate(360deg); }
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Check icon for success */
|
|
249
|
+
.mld-experiment-popover__check-icon {
|
|
250
|
+
width: 0.875rem;
|
|
251
|
+
height: 0.875rem;
|
|
252
|
+
}
|
package/src/styles/index.css
CHANGED