@morscherlab/mld-sdk 0.9.8 → 0.10.0

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.
@@ -1,9 +1,14 @@
1
- import { defineComponent, ref, computed, onMounted, onUnmounted, resolveComponent, openBlock, createElementBlock, Fragment, createElementVNode, normalizeClass, renderSlot, createCommentVNode, createBlock, withCtx, toDisplayString, withModifiers, createTextVNode, withDirectives, renderList, vShow, createSlots } from "vue";
2
- import _sfc_main$1 from "./ThemeToggle.vue.js";
1
+ import { defineComponent, ref, computed, inject, onMounted, onUnmounted, resolveComponent, openBlock, createElementBlock, Fragment, createElementVNode, normalizeClass, renderSlot, createCommentVNode, createBlock, withCtx, toDisplayString, withModifiers, createTextVNode, withDirectives, renderList, vShow, unref, createSlots } from "vue";
2
+ import _sfc_main$2 from "./ThemeToggle.vue.js";
3
3
  /* empty css */
4
- import _sfc_main$2 from "./SettingsModal.vue.js";
4
+ import _sfc_main$3 from "./SettingsModal.vue.js";
5
5
  /* empty css */
6
+ import _sfc_main$1 from "./ExperimentPopover.vue.js";
7
+ /* empty css */
8
+ import _sfc_main$4 from "./ExperimentSelectorModal.vue.js";
9
+ /* empty css */
6
10
  import { usePlatformContext } from "../composables/usePlatformContext.js";
11
+ import { APP_EXPERIMENT_KEY } from "../composables/useAppExperiment.js";
7
12
  const _hoisted_1 = { class: "mld-topbar__container" };
8
13
  const _hoisted_2 = { class: "mld-topbar__left" };
9
14
  const _hoisted_3 = ["href"];
@@ -105,8 +110,12 @@ const _hoisted_39 = {
105
110
  key: 0,
106
111
  class: "mld-topbar__standalone-badge"
107
112
  };
108
- const _hoisted_40 = { class: "mld-topbar__profile-avatar" };
109
- const _hoisted_41 = {
113
+ const _hoisted_40 = {
114
+ key: 2,
115
+ class: "mld-topbar__standalone-badge"
116
+ };
117
+ const _hoisted_41 = { class: "mld-topbar__profile-avatar" };
118
+ const _hoisted_42 = {
110
119
  key: 0,
111
120
  class: "mld-topbar__profile-name"
112
121
  };
@@ -140,6 +149,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
140
149
  const settingsOpen = ref(false);
141
150
  const { isIntegrated } = usePlatformContext();
142
151
  const isStandalone = computed(() => !isIntegrated.value);
152
+ const appExperiment = inject(APP_EXPERIMENT_KEY, null);
143
153
  const profileInitial = computed(() => {
144
154
  if (props.userInitial) return props.userInitial;
145
155
  if (props.userName) return props.userName.charAt(0).toUpperCase();
@@ -222,7 +232,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
222
232
  }, [
223
233
  renderSlot(_ctx.$slots, "icon", {}, () => [
224
234
  renderSlot(_ctx.$slots, "logo", {}, () => [
225
- __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_4, [..._cache[8] || (_cache[8] = [
235
+ __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_4, [..._cache[14] || (_cache[14] = [
226
236
  createElementVNode("div", { class: "mld-topbar__logo-icon" }, [
227
237
  createElementVNode("span", { class: "mld-topbar__logo-text" }, "M")
228
238
  ], -1)
@@ -236,7 +246,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
236
246
  }, [
237
247
  renderSlot(_ctx.$slots, "icon", {}, () => [
238
248
  renderSlot(_ctx.$slots, "logo", {}, () => [
239
- __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_6, [..._cache[9] || (_cache[9] = [
249
+ __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_6, [..._cache[15] || (_cache[15] = [
240
250
  createElementVNode("div", { class: "mld-topbar__logo-icon" }, [
241
251
  createElementVNode("span", { class: "mld-topbar__logo-text" }, "M")
242
252
  ], -1)
@@ -251,7 +261,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
251
261
  default: withCtx(() => [
252
262
  renderSlot(_ctx.$slots, "icon", {}, () => [
253
263
  renderSlot(_ctx.$slots, "logo", {}, () => [
254
- __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_7, [..._cache[10] || (_cache[10] = [
264
+ __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_7, [..._cache[16] || (_cache[16] = [
255
265
  createElementVNode("div", { class: "mld-topbar__logo-icon" }, [
256
266
  createElementVNode("span", { class: "mld-topbar__logo-text" }, "M")
257
267
  ], -1)
@@ -262,7 +272,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
262
272
  _: 3
263
273
  }, 8, ["to"])) : renderSlot(_ctx.$slots, "icon", { key: 3 }, () => [
264
274
  renderSlot(_ctx.$slots, "logo", {}, () => [
265
- __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_8, [..._cache[11] || (_cache[11] = [
275
+ __props.showLogo ? (openBlock(), createElementBlock("div", _hoisted_8, [..._cache[17] || (_cache[17] = [
266
276
  createElementVNode("div", { class: "mld-topbar__logo-icon" }, [
267
277
  createElementVNode("span", { class: "mld-topbar__logo-text" }, "M")
268
278
  ], -1)
@@ -295,11 +305,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
295
305
  "stroke-width": "2",
296
306
  "stroke-linecap": "round",
297
307
  "stroke-linejoin": "round"
298
- }, [..._cache[12] || (_cache[12] = [
308
+ }, [..._cache[18] || (_cache[18] = [
299
309
  createElementVNode("path", { d: "m6 9 6 6 6-6" }, null, -1)
300
310
  ])], 2))
301
311
  ])) : (openBlock(), createElementBlock("span", _hoisted_12, toDisplayString(__props.pluginName), 1)),
302
- __props.title ? (openBlock(), createElementBlock("svg", _hoisted_13, [..._cache[13] || (_cache[13] = [
312
+ __props.title ? (openBlock(), createElementBlock("svg", _hoisted_13, [..._cache[19] || (_cache[19] = [
303
313
  createElementVNode("path", { d: "m9 18 6-6-6-6" }, null, -1)
304
314
  ])])) : createCommentVNode("", true),
305
315
  __props.title ? (openBlock(), createElementBlock("span", _hoisted_14, toDisplayString(__props.title), 1)) : createCommentVNode("", true),
@@ -377,7 +387,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
377
387
  "stroke-width": "2",
378
388
  "stroke-linecap": "round",
379
389
  "stroke-linejoin": "round"
380
- }, [..._cache[14] || (_cache[14] = [
390
+ }, [..._cache[20] || (_cache[20] = [
381
391
  createElementVNode("path", { d: "m6 9 6 6 6-6" }, null, -1)
382
392
  ])], 2))
383
393
  ], 10, _hoisted_26)) : tab.href ? (openBlock(), createElementBlock("a", {
@@ -465,19 +475,34 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
465
475
  }), 128))
466
476
  ])) : createCommentVNode("", true),
467
477
  createElementVNode("div", _hoisted_38, [
468
- __props.showStandaloneLabel && isStandalone.value ? (openBlock(), createElementBlock("span", _hoisted_39, toDisplayString(__props.standaloneLabel), 1)) : createCommentVNode("", true),
469
- renderSlot(_ctx.$slots, "actions"),
470
- __props.showThemeToggle ? (openBlock(), createBlock(_sfc_main$1, {
478
+ __props.showStandaloneLabel && isStandalone.value && !unref(appExperiment) ? (openBlock(), createElementBlock("span", _hoisted_39, toDisplayString(__props.standaloneLabel), 1)) : createCommentVNode("", true),
479
+ unref(appExperiment) && !isStandalone.value ? (openBlock(), createBlock(_sfc_main$1, {
471
480
  key: 1,
481
+ "experiment-name": unref(appExperiment).experimentName.value,
482
+ "experiment-status": unref(appExperiment).experimentStatus.value,
483
+ "show-save": unref(appExperiment).showSave.value,
484
+ "show-detach": unref(appExperiment).showDetach.value,
485
+ "save-disabled": unref(appExperiment).saveDisabled.value,
486
+ "save-disabled-message": unref(appExperiment).saveDisabledMessage.value,
487
+ "save-loading": unref(appExperiment).saveLoading.value,
488
+ "save-success-message": unref(appExperiment).saveSuccessMessage.value,
489
+ onSelect: _cache[4] || (_cache[4] = ($event) => unref(appExperiment).openModal()),
490
+ onSave: _cache[5] || (_cache[5] = ($event) => unref(appExperiment).handleSave()),
491
+ onDetach: _cache[6] || (_cache[6] = ($event) => unref(appExperiment).handleDetach())
492
+ }, null, 8, ["experiment-name", "experiment-status", "show-save", "show-detach", "save-disabled", "save-disabled-message", "save-loading", "save-success-message"])) : createCommentVNode("", true),
493
+ unref(appExperiment) && isStandalone.value ? (openBlock(), createElementBlock("span", _hoisted_40, toDisplayString(__props.standaloneLabel), 1)) : createCommentVNode("", true),
494
+ renderSlot(_ctx.$slots, "actions"),
495
+ __props.showThemeToggle ? (openBlock(), createBlock(_sfc_main$2, {
496
+ key: 3,
472
497
  size: "sm"
473
498
  })) : createCommentVNode("", true),
474
499
  __props.showSettings ? (openBlock(), createElementBlock("button", {
475
- key: 2,
500
+ key: 4,
476
501
  type: "button",
477
502
  class: "mld-topbar__settings-btn",
478
503
  "aria-label": "Open settings",
479
- onClick: _cache[4] || (_cache[4] = ($event) => settingsOpen.value = true)
480
- }, [..._cache[15] || (_cache[15] = [
504
+ onClick: _cache[7] || (_cache[7] = ($event) => settingsOpen.value = true)
505
+ }, [..._cache[21] || (_cache[21] = [
481
506
  createElementVNode("svg", {
482
507
  class: "mld-topbar__settings-icon",
483
508
  viewBox: "0 0 24 24",
@@ -496,13 +521,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
496
521
  ], -1)
497
522
  ])])) : createCommentVNode("", true),
498
523
  __props.showAdmin ? (openBlock(), createBlock(_component_router_link, {
499
- key: 3,
524
+ key: 5,
500
525
  to: __props.adminPath,
501
526
  class: "mld-topbar__admin-btn",
502
527
  "aria-label": "Admin Dashboard",
503
- onClick: _cache[5] || (_cache[5] = ($event) => emit("admin-click"))
528
+ onClick: _cache[8] || (_cache[8] = ($event) => emit("admin-click"))
504
529
  }, {
505
- default: withCtx(() => [..._cache[16] || (_cache[16] = [
530
+ default: withCtx(() => [..._cache[22] || (_cache[22] = [
506
531
  createElementVNode("svg", {
507
532
  class: "mld-topbar__admin-icon",
508
533
  viewBox: "0 0 24 24",
@@ -519,22 +544,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
519
544
  _: 1
520
545
  }, 8, ["to"])) : createCommentVNode("", true),
521
546
  __props.showProfile ? (openBlock(), createElementBlock("button", {
522
- key: 4,
547
+ key: 6,
523
548
  type: "button",
524
549
  class: "mld-topbar__profile-btn",
525
550
  "aria-label": "Edit profile",
526
- onClick: _cache[6] || (_cache[6] = ($event) => emit("profile-click"))
551
+ onClick: _cache[9] || (_cache[9] = ($event) => emit("profile-click"))
527
552
  }, [
528
- createElementVNode("div", _hoisted_40, toDisplayString(profileInitial.value), 1),
529
- __props.userName ? (openBlock(), createElementBlock("span", _hoisted_41, toDisplayString(__props.userName), 1)) : createCommentVNode("", true)
553
+ createElementVNode("div", _hoisted_41, toDisplayString(profileInitial.value), 1),
554
+ __props.userName ? (openBlock(), createElementBlock("span", _hoisted_42, toDisplayString(__props.userName), 1)) : createCommentVNode("", true)
530
555
  ])) : createCommentVNode("", true)
531
556
  ])
532
557
  ])
533
558
  ], 2),
534
- __props.showSettings ? (openBlock(), createBlock(_sfc_main$2, {
559
+ __props.showSettings ? (openBlock(), createBlock(_sfc_main$3, {
535
560
  key: 0,
536
561
  modelValue: settingsOpen.value,
537
- "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => settingsOpen.value = $event),
562
+ "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => settingsOpen.value = $event),
538
563
  title: (_e = __props.settingsConfig) == null ? void 0 : _e.title,
539
564
  tabs: (_f = __props.settingsConfig) == null ? void 0 : _f.tabs,
540
565
  "show-appearance": ((_g = __props.settingsConfig) == null ? void 0 : _g.showAppearance) ?? true,
@@ -553,7 +578,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
553
578
  ])
554
579
  };
555
580
  })
556
- ]), 1032, ["modelValue", "title", "tabs", "show-appearance", "size"])) : createCommentVNode("", true)
581
+ ]), 1032, ["modelValue", "title", "tabs", "show-appearance", "size"])) : createCommentVNode("", true),
582
+ unref(appExperiment) && !isStandalone.value ? (openBlock(), createBlock(_sfc_main$4, {
583
+ key: 1,
584
+ "model-value": unref(appExperiment).showModal.value,
585
+ "current-experiment-id": unref(appExperiment).experimentId.value,
586
+ "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => $event ? unref(appExperiment).openModal() : unref(appExperiment).closeModal()),
587
+ onSelect: _cache[12] || (_cache[12] = ($event) => unref(appExperiment).handleSelect($event)),
588
+ onDeselect: _cache[13] || (_cache[13] = ($event) => unref(appExperiment).handleDetach())
589
+ }, null, 8, ["model-value", "current-experiment-id"])) : createCommentVNode("", true)
557
590
  ], 64);
558
591
  };
559
592
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AppTopBar.vue.js","sources":["../../src/components/AppTopBar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted } from 'vue'\nimport type { TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, TopBarVariant } from '../types/components'\nimport ThemeToggle from './ThemeToggle.vue'\nimport SettingsModal from './SettingsModal.vue'\nimport { usePlatformContext } from '../composables/usePlatformContext'\n\ninterface Props {\n title?: string\n subtitle?: string\n showLogo?: boolean\n variant?: TopBarVariant\n pluginName?: string\n pages?: TopBarPage[]\n currentPageId?: string\n tabs?: TopBarTab[]\n currentTabId?: string\n homePath?: string\n showThemeToggle?: boolean\n showSettings?: boolean\n settingsConfig?: TopBarSettingsConfig\n showStandaloneLabel?: boolean\n standaloneLabel?: string\n showAdmin?: boolean\n adminPath?: string\n showProfile?: boolean\n userName?: string\n userInitial?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showLogo: true,\n variant: 'card',\n homePath: '/',\n showThemeToggle: false,\n showSettings: false,\n showStandaloneLabel: true,\n standaloneLabel: 'Standalone',\n showAdmin: false,\n adminPath: '/admin',\n showProfile: false,\n})\n\nconst settingsOpen = ref(false)\nconst { isIntegrated } = usePlatformContext()\nconst isStandalone = computed(() => !isIntegrated.value)\n\nconst profileInitial = computed(() => {\n if (props.userInitial) return props.userInitial\n if (props.userName) return props.userName.charAt(0).toUpperCase()\n return 'U'\n})\n\nconst emit = defineEmits<{\n 'page-select': [page: TopBarPage]\n 'tab-select': [tab: TopBarTab]\n 'tab-option-select': [option: TopBarTabOption, tab: TopBarTab]\n 'profile-click': []\n 'admin-click': []\n}>()\n\nconst showPagesDropdown = ref(false)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst openTabDropdown = ref<string | null>(null)\nconst tabDropdownRefs = ref<Map<string, HTMLElement>>(new Map())\n\nfunction togglePagesDropdown() {\n showPagesDropdown.value = !showPagesDropdown.value\n openTabDropdown.value = null\n}\n\nfunction handlePageClick(page: TopBarPage) {\n if (page.disabled) return\n emit('page-select', page)\n showPagesDropdown.value = false\n}\n\nfunction toggleTabDropdown(tabId: string) {\n showPagesDropdown.value = false\n openTabDropdown.value = openTabDropdown.value === tabId ? null : tabId\n}\n\nfunction handleTabClick(tab: TopBarTab) {\n if (tab.disabled) return\n if (tab.children?.length) {\n toggleTabDropdown(tab.id)\n } else {\n emit('tab-select', tab)\n openTabDropdown.value = null\n }\n}\n\nfunction handleTabOptionClick(option: TopBarTabOption, tab: TopBarTab) {\n if (option.disabled) return\n emit('tab-option-select', option, tab)\n openTabDropdown.value = null\n}\n\nfunction setTabDropdownRef(el: HTMLElement | null, tabId: string) {\n if (el) {\n tabDropdownRefs.value.set(tabId, el)\n } else {\n tabDropdownRefs.value.delete(tabId)\n }\n}\n\nfunction handleClickOutside(event: MouseEvent) {\n const target = event.target as Node\n\n if (showPagesDropdown.value && dropdownRef.value && !dropdownRef.value.contains(target)) {\n showPagesDropdown.value = false\n }\n\n if (openTabDropdown.value !== null) {\n const clickedInside = Array.from(tabDropdownRefs.value.values()).some((el) => el.contains(target))\n if (!clickedInside) {\n openTabDropdown.value = null\n }\n }\n}\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n})\n</script>\n\n<template>\n <header\n :class=\"[\n 'mld-topbar',\n `mld-topbar--${props.variant}`,\n ]\"\n >\n <div class=\"mld-topbar__container\">\n <!-- Left section: Icon/Logo + Title/Subtitle or Breadcrumb -->\n <div class=\"mld-topbar__left\">\n <!-- Icon/Logo with external home link (absolute URL) -->\n <a v-if=\"homePath && homePath.startsWith('http')\" :href=\"homePath\" class=\"mld-topbar-home-link\">\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </a>\n <!-- Icon/Logo with platform home link (absolute path goes to parent app) -->\n <a v-else-if=\"homePath && homePath.startsWith('/')\" :href=\"homePath\" class=\"mld-topbar-home-link\">\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </a>\n <!-- Icon/Logo with router link (relative path within app) -->\n <router-link v-else-if=\"homePath\" :to=\"homePath\" class=\"mld-topbar-home-link\">\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </router-link>\n <!-- Icon/Logo without link (homePath is empty) -->\n <template v-else>\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </template>\n\n <!-- Title with subtitle (no breadcrumb) -->\n <div v-if=\"title && subtitle && !pluginName && !pages?.length\" class=\"mld-topbar-title-group\">\n <span class=\"mld-topbar-title\">{{ title }}</span>\n <span class=\"mld-topbar-subtitle\">{{ subtitle }}</span>\n </div>\n\n <!-- Breadcrumb: Plugin Name > Current Page -->\n <div v-else-if=\"pluginName || pages?.length\" ref=\"dropdownRef\" class=\"mld-topbar-breadcrumb\">\n <!-- Plugin name with dropdown trigger -->\n <button\n v-if=\"pages?.length\"\n type=\"button\"\n class=\"mld-topbar-plugin-name\"\n @click.stop=\"togglePagesDropdown\"\n >\n {{ pluginName }}\n <svg\n class=\"mld-topbar-chevron\"\n :class=\"{ 'mld-topbar-chevron--open': showPagesDropdown }\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n <span v-else class=\"mld-topbar-plugin-name--static\">{{ pluginName }}</span>\n\n <!-- Separator -->\n <svg\n v-if=\"title\"\n class=\"mld-topbar-separator\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n\n <!-- Current page title -->\n <span v-if=\"title\" class=\"mld-topbar-current-page\">{{ title }}</span>\n\n <!-- Pages dropdown -->\n <div v-show=\"showPagesDropdown\" class=\"mld-topbar-dropdown\">\n <template v-for=\"page in pages\" :key=\"page.id\">\n <a\n v-if=\"page.href\"\n :href=\"page.href\"\n :class=\"['mld-topbar-dropdown-item', { 'mld-topbar-dropdown-item--active': page.id === currentPageId, 'mld-topbar-dropdown-item--disabled': page.disabled }]\"\n @click=\"showPagesDropdown = false\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ page.label }}</span>\n <span v-if=\"page.description\" class=\"mld-topbar-dropdown-item__description\">{{ page.description }}</span>\n </a>\n <router-link\n v-else-if=\"page.to\"\n :to=\"page.to\"\n :class=\"['mld-topbar-dropdown-item', { 'mld-topbar-dropdown-item--active': page.id === currentPageId, 'mld-topbar-dropdown-item--disabled': page.disabled }]\"\n @click=\"showPagesDropdown = false\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ page.label }}</span>\n <span v-if=\"page.description\" class=\"mld-topbar-dropdown-item__description\">{{ page.description }}</span>\n </router-link>\n <button\n v-else\n type=\"button\"\n :class=\"['mld-topbar-dropdown-item', { 'mld-topbar-dropdown-item--active': page.id === currentPageId, 'mld-topbar-dropdown-item--disabled': page.disabled }]\"\n @click=\"handlePageClick(page)\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ page.label }}</span>\n <span v-if=\"page.description\" class=\"mld-topbar-dropdown-item__description\">{{ page.description }}</span>\n </button>\n </template>\n </div>\n </div>\n\n <!-- Title only (backward compat when no pluginName and no subtitle) -->\n <span v-else-if=\"title\" class=\"mld-topbar__title-only\">{{ title }}</span>\n\n <!-- Navigation slot -->\n <slot name=\"nav\" />\n </div>\n\n <!-- Center section: Tabs -->\n <div v-if=\"tabs?.length\" class=\"mld-topbar__tabs\">\n <template v-for=\"tab in tabs\" :key=\"tab.id\">\n <div\n :ref=\"(el) => tab.children?.length ? setTabDropdownRef(el as HTMLElement, tab.id) : null\"\n class=\"mld-topbar-tab-wrapper\"\n >\n <!-- Tab with children (dropdown) -->\n <button\n v-if=\"tab.children?.length\"\n type=\"button\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId || tab.children.some(c => c.id === currentTabId) },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n @click.stop=\"handleTabClick(tab)\"\n >\n {{ tab.label }}\n <svg\n class=\"mld-topbar-tab-chevron\"\n :class=\"{ 'mld-topbar-tab-chevron--open': openTabDropdown === tab.id }\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Simple tab (no children) -->\n <a\n v-else-if=\"tab.href\"\n :href=\"tab.href\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n >\n {{ tab.label }}\n </a>\n <router-link\n v-else-if=\"tab.to\"\n :to=\"tab.to\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n >\n {{ tab.label }}\n </router-link>\n <button\n v-else\n type=\"button\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n @click=\"handleTabClick(tab)\"\n >\n {{ tab.label }}\n </button>\n\n <!-- Tab dropdown -->\n <div v-if=\"tab.children?.length\" v-show=\"openTabDropdown === tab.id\" class=\"mld-topbar-tab-dropdown\">\n <template v-for=\"option in tab.children\" :key=\"option.id\">\n <a\n v-if=\"option.href\"\n :href=\"option.href\"\n :class=\"[\n 'mld-topbar-dropdown-item',\n { 'mld-topbar-dropdown-item--active': option.id === currentTabId },\n { 'mld-topbar-dropdown-item--disabled': option.disabled }\n ]\"\n @click=\"openTabDropdown = null\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ option.label }}</span>\n <span v-if=\"option.description\" class=\"mld-topbar-dropdown-item__description\">{{ option.description }}</span>\n </a>\n <router-link\n v-else-if=\"option.to\"\n :to=\"option.to\"\n :class=\"[\n 'mld-topbar-dropdown-item',\n { 'mld-topbar-dropdown-item--active': option.id === currentTabId },\n { 'mld-topbar-dropdown-item--disabled': option.disabled }\n ]\"\n @click=\"openTabDropdown = null\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ option.label }}</span>\n <span v-if=\"option.description\" class=\"mld-topbar-dropdown-item__description\">{{ option.description }}</span>\n </router-link>\n <button\n v-else\n type=\"button\"\n :class=\"[\n 'mld-topbar-dropdown-item',\n { 'mld-topbar-dropdown-item--active': option.id === currentTabId },\n { 'mld-topbar-dropdown-item--disabled': option.disabled }\n ]\"\n @click=\"handleTabOptionClick(option, tab)\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ option.label }}</span>\n <span v-if=\"option.description\" class=\"mld-topbar-dropdown-item__description\">{{ option.description }}</span>\n </button>\n </template>\n </div>\n </div>\n </template>\n </div>\n\n <!-- Right section: Actions -->\n <div class=\"mld-topbar__right\">\n <span v-if=\"showStandaloneLabel && isStandalone\" class=\"mld-topbar__standalone-badge\">\n {{ standaloneLabel }}\n </span>\n <!-- Actions slot (right side) -->\n <slot name=\"actions\" />\n <!-- Theme toggle -->\n <ThemeToggle v-if=\"showThemeToggle\" size=\"sm\" />\n <!-- Settings gear -->\n <button\n v-if=\"showSettings\"\n type=\"button\"\n class=\"mld-topbar__settings-btn\"\n aria-label=\"Open settings\"\n @click=\"settingsOpen = true\"\n >\n <svg class=\"mld-topbar__settings-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915\" /><circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n </button>\n <!-- Admin link -->\n <router-link\n v-if=\"showAdmin\"\n :to=\"adminPath\"\n class=\"mld-topbar__admin-btn\"\n aria-label=\"Admin Dashboard\"\n @click=\"emit('admin-click')\"\n >\n <svg class=\"mld-topbar__admin-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\" /><path d=\"m9 12 2 2 4-4\" />\n </svg>\n </router-link>\n <!-- Profile button -->\n <button\n v-if=\"showProfile\"\n type=\"button\"\n class=\"mld-topbar__profile-btn\"\n aria-label=\"Edit profile\"\n @click=\"emit('profile-click')\"\n >\n <div class=\"mld-topbar__profile-avatar\">\n {{ profileInitial }}\n </div>\n <span v-if=\"userName\" class=\"mld-topbar__profile-name\">{{ userName }}</span>\n </button>\n </div>\n </div>\n </header>\n\n <SettingsModal\n v-if=\"showSettings\"\n v-model=\"settingsOpen\"\n :title=\"settingsConfig?.title\"\n :tabs=\"settingsConfig?.tabs\"\n :show-appearance=\"settingsConfig?.showAppearance ?? true\"\n :size=\"settingsConfig?.size\"\n >\n <template v-for=\"tab in (settingsConfig?.tabs ?? [])\" :key=\"tab.id\" #[`tab-${tab.id}`]>\n <slot :name=\"`settings-tab-${tab.id}`\" />\n </template>\n <template #appearance>\n <slot name=\"settings-appearance\" />\n </template>\n </SettingsModal>\n</template>\n\n<style>\n@import '../styles/components/app-top-bar.css';\n</style>\n"],"names":["_createElementVNode","_normalizeClass","_createElementBlock","_renderSlot","_openBlock","_createBlock","_toDisplayString","_createTextVNode","_withDirectives","_Fragment","_renderList","_a","_withModifiers","_b","ThemeToggle","SettingsModal"],"mappings":"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"}
1
+ {"version":3,"file":"AppTopBar.vue.js","sources":["../../src/components/AppTopBar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, inject, onMounted, onUnmounted } from 'vue'\nimport type { TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, TopBarVariant } from '../types/components'\nimport ThemeToggle from './ThemeToggle.vue'\nimport SettingsModal from './SettingsModal.vue'\nimport ExperimentPopover from './ExperimentPopover.vue'\nimport ExperimentSelectorModal from './ExperimentSelectorModal.vue'\nimport { usePlatformContext } from '../composables/usePlatformContext'\nimport { APP_EXPERIMENT_KEY } from '../composables/useAppExperiment'\n\ninterface Props {\n title?: string\n subtitle?: string\n showLogo?: boolean\n variant?: TopBarVariant\n pluginName?: string\n pages?: TopBarPage[]\n currentPageId?: string\n tabs?: TopBarTab[]\n currentTabId?: string\n homePath?: string\n showThemeToggle?: boolean\n showSettings?: boolean\n settingsConfig?: TopBarSettingsConfig\n showStandaloneLabel?: boolean\n standaloneLabel?: string\n showAdmin?: boolean\n adminPath?: string\n showProfile?: boolean\n userName?: string\n userInitial?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showLogo: true,\n variant: 'card',\n homePath: '/',\n showThemeToggle: false,\n showSettings: false,\n showStandaloneLabel: true,\n standaloneLabel: 'Standalone',\n showAdmin: false,\n adminPath: '/admin',\n showProfile: false,\n})\n\nconst settingsOpen = ref(false)\nconst { isIntegrated } = usePlatformContext()\nconst isStandalone = computed(() => !isIntegrated.value)\nconst appExperiment = inject(APP_EXPERIMENT_KEY, null)\n\nconst profileInitial = computed(() => {\n if (props.userInitial) return props.userInitial\n if (props.userName) return props.userName.charAt(0).toUpperCase()\n return 'U'\n})\n\nconst emit = defineEmits<{\n 'page-select': [page: TopBarPage]\n 'tab-select': [tab: TopBarTab]\n 'tab-option-select': [option: TopBarTabOption, tab: TopBarTab]\n 'profile-click': []\n 'admin-click': []\n}>()\n\nconst showPagesDropdown = ref(false)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst openTabDropdown = ref<string | null>(null)\nconst tabDropdownRefs = ref<Map<string, HTMLElement>>(new Map())\n\nfunction togglePagesDropdown() {\n showPagesDropdown.value = !showPagesDropdown.value\n openTabDropdown.value = null\n}\n\nfunction handlePageClick(page: TopBarPage) {\n if (page.disabled) return\n emit('page-select', page)\n showPagesDropdown.value = false\n}\n\nfunction toggleTabDropdown(tabId: string) {\n showPagesDropdown.value = false\n openTabDropdown.value = openTabDropdown.value === tabId ? null : tabId\n}\n\nfunction handleTabClick(tab: TopBarTab) {\n if (tab.disabled) return\n if (tab.children?.length) {\n toggleTabDropdown(tab.id)\n } else {\n emit('tab-select', tab)\n openTabDropdown.value = null\n }\n}\n\nfunction handleTabOptionClick(option: TopBarTabOption, tab: TopBarTab) {\n if (option.disabled) return\n emit('tab-option-select', option, tab)\n openTabDropdown.value = null\n}\n\nfunction setTabDropdownRef(el: HTMLElement | null, tabId: string) {\n if (el) {\n tabDropdownRefs.value.set(tabId, el)\n } else {\n tabDropdownRefs.value.delete(tabId)\n }\n}\n\nfunction handleClickOutside(event: MouseEvent) {\n const target = event.target as Node\n\n if (showPagesDropdown.value && dropdownRef.value && !dropdownRef.value.contains(target)) {\n showPagesDropdown.value = false\n }\n\n if (openTabDropdown.value !== null) {\n const clickedInside = Array.from(tabDropdownRefs.value.values()).some((el) => el.contains(target))\n if (!clickedInside) {\n openTabDropdown.value = null\n }\n }\n}\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n})\n</script>\n\n<template>\n <header\n :class=\"[\n 'mld-topbar',\n `mld-topbar--${props.variant}`,\n ]\"\n >\n <div class=\"mld-topbar__container\">\n <!-- Left section: Icon/Logo + Title/Subtitle or Breadcrumb -->\n <div class=\"mld-topbar__left\">\n <!-- Icon/Logo with external home link (absolute URL) -->\n <a v-if=\"homePath && homePath.startsWith('http')\" :href=\"homePath\" class=\"mld-topbar-home-link\">\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </a>\n <!-- Icon/Logo with platform home link (absolute path goes to parent app) -->\n <a v-else-if=\"homePath && homePath.startsWith('/')\" :href=\"homePath\" class=\"mld-topbar-home-link\">\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </a>\n <!-- Icon/Logo with router link (relative path within app) -->\n <router-link v-else-if=\"homePath\" :to=\"homePath\" class=\"mld-topbar-home-link\">\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </router-link>\n <!-- Icon/Logo without link (homePath is empty) -->\n <template v-else>\n <slot name=\"icon\">\n <slot name=\"logo\">\n <div v-if=\"showLogo\" class=\"mld-topbar__logo\">\n <div class=\"mld-topbar__logo-icon\">\n <span class=\"mld-topbar__logo-text\">M</span>\n </div>\n </div>\n </slot>\n </slot>\n </template>\n\n <!-- Title with subtitle (no breadcrumb) -->\n <div v-if=\"title && subtitle && !pluginName && !pages?.length\" class=\"mld-topbar-title-group\">\n <span class=\"mld-topbar-title\">{{ title }}</span>\n <span class=\"mld-topbar-subtitle\">{{ subtitle }}</span>\n </div>\n\n <!-- Breadcrumb: Plugin Name > Current Page -->\n <div v-else-if=\"pluginName || pages?.length\" ref=\"dropdownRef\" class=\"mld-topbar-breadcrumb\">\n <!-- Plugin name with dropdown trigger -->\n <button\n v-if=\"pages?.length\"\n type=\"button\"\n class=\"mld-topbar-plugin-name\"\n @click.stop=\"togglePagesDropdown\"\n >\n {{ pluginName }}\n <svg\n class=\"mld-topbar-chevron\"\n :class=\"{ 'mld-topbar-chevron--open': showPagesDropdown }\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n <span v-else class=\"mld-topbar-plugin-name--static\">{{ pluginName }}</span>\n\n <!-- Separator -->\n <svg\n v-if=\"title\"\n class=\"mld-topbar-separator\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n\n <!-- Current page title -->\n <span v-if=\"title\" class=\"mld-topbar-current-page\">{{ title }}</span>\n\n <!-- Pages dropdown -->\n <div v-show=\"showPagesDropdown\" class=\"mld-topbar-dropdown\">\n <template v-for=\"page in pages\" :key=\"page.id\">\n <a\n v-if=\"page.href\"\n :href=\"page.href\"\n :class=\"['mld-topbar-dropdown-item', { 'mld-topbar-dropdown-item--active': page.id === currentPageId, 'mld-topbar-dropdown-item--disabled': page.disabled }]\"\n @click=\"showPagesDropdown = false\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ page.label }}</span>\n <span v-if=\"page.description\" class=\"mld-topbar-dropdown-item__description\">{{ page.description }}</span>\n </a>\n <router-link\n v-else-if=\"page.to\"\n :to=\"page.to\"\n :class=\"['mld-topbar-dropdown-item', { 'mld-topbar-dropdown-item--active': page.id === currentPageId, 'mld-topbar-dropdown-item--disabled': page.disabled }]\"\n @click=\"showPagesDropdown = false\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ page.label }}</span>\n <span v-if=\"page.description\" class=\"mld-topbar-dropdown-item__description\">{{ page.description }}</span>\n </router-link>\n <button\n v-else\n type=\"button\"\n :class=\"['mld-topbar-dropdown-item', { 'mld-topbar-dropdown-item--active': page.id === currentPageId, 'mld-topbar-dropdown-item--disabled': page.disabled }]\"\n @click=\"handlePageClick(page)\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ page.label }}</span>\n <span v-if=\"page.description\" class=\"mld-topbar-dropdown-item__description\">{{ page.description }}</span>\n </button>\n </template>\n </div>\n </div>\n\n <!-- Title only (backward compat when no pluginName and no subtitle) -->\n <span v-else-if=\"title\" class=\"mld-topbar__title-only\">{{ title }}</span>\n\n <!-- Navigation slot -->\n <slot name=\"nav\" />\n </div>\n\n <!-- Center section: Tabs -->\n <div v-if=\"tabs?.length\" class=\"mld-topbar__tabs\">\n <template v-for=\"tab in tabs\" :key=\"tab.id\">\n <div\n :ref=\"(el) => tab.children?.length ? setTabDropdownRef(el as HTMLElement, tab.id) : null\"\n class=\"mld-topbar-tab-wrapper\"\n >\n <!-- Tab with children (dropdown) -->\n <button\n v-if=\"tab.children?.length\"\n type=\"button\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId || tab.children.some(c => c.id === currentTabId) },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n @click.stop=\"handleTabClick(tab)\"\n >\n {{ tab.label }}\n <svg\n class=\"mld-topbar-tab-chevron\"\n :class=\"{ 'mld-topbar-tab-chevron--open': openTabDropdown === tab.id }\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n\n <!-- Simple tab (no children) -->\n <a\n v-else-if=\"tab.href\"\n :href=\"tab.href\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n >\n {{ tab.label }}\n </a>\n <router-link\n v-else-if=\"tab.to\"\n :to=\"tab.to\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n >\n {{ tab.label }}\n </router-link>\n <button\n v-else\n type=\"button\"\n :class=\"[\n 'mld-topbar-tab',\n { 'mld-topbar-tab--active': tab.id === currentTabId },\n { 'mld-topbar-tab--disabled': tab.disabled }\n ]\"\n @click=\"handleTabClick(tab)\"\n >\n {{ tab.label }}\n </button>\n\n <!-- Tab dropdown -->\n <div v-if=\"tab.children?.length\" v-show=\"openTabDropdown === tab.id\" class=\"mld-topbar-tab-dropdown\">\n <template v-for=\"option in tab.children\" :key=\"option.id\">\n <a\n v-if=\"option.href\"\n :href=\"option.href\"\n :class=\"[\n 'mld-topbar-dropdown-item',\n { 'mld-topbar-dropdown-item--active': option.id === currentTabId },\n { 'mld-topbar-dropdown-item--disabled': option.disabled }\n ]\"\n @click=\"openTabDropdown = null\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ option.label }}</span>\n <span v-if=\"option.description\" class=\"mld-topbar-dropdown-item__description\">{{ option.description }}</span>\n </a>\n <router-link\n v-else-if=\"option.to\"\n :to=\"option.to\"\n :class=\"[\n 'mld-topbar-dropdown-item',\n { 'mld-topbar-dropdown-item--active': option.id === currentTabId },\n { 'mld-topbar-dropdown-item--disabled': option.disabled }\n ]\"\n @click=\"openTabDropdown = null\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ option.label }}</span>\n <span v-if=\"option.description\" class=\"mld-topbar-dropdown-item__description\">{{ option.description }}</span>\n </router-link>\n <button\n v-else\n type=\"button\"\n :class=\"[\n 'mld-topbar-dropdown-item',\n { 'mld-topbar-dropdown-item--active': option.id === currentTabId },\n { 'mld-topbar-dropdown-item--disabled': option.disabled }\n ]\"\n @click=\"handleTabOptionClick(option, tab)\"\n >\n <span class=\"mld-topbar-dropdown-item__label\">{{ option.label }}</span>\n <span v-if=\"option.description\" class=\"mld-topbar-dropdown-item__description\">{{ option.description }}</span>\n </button>\n </template>\n </div>\n </div>\n </template>\n </div>\n\n <!-- Right section: Actions -->\n <div class=\"mld-topbar__right\">\n <!-- Standalone badge (only when useAppExperiment is NOT active) -->\n <span v-if=\"showStandaloneLabel && isStandalone && !appExperiment\" class=\"mld-topbar__standalone-badge\">\n {{ standaloneLabel }}\n </span>\n\n <!-- Experiment popover (integrated + useAppExperiment active) -->\n <ExperimentPopover\n v-if=\"appExperiment && !isStandalone\"\n :experiment-name=\"appExperiment.experimentName.value\"\n :experiment-status=\"appExperiment.experimentStatus.value\"\n :show-save=\"appExperiment.showSave.value\"\n :show-detach=\"appExperiment.showDetach.value\"\n :save-disabled=\"appExperiment.saveDisabled.value\"\n :save-disabled-message=\"appExperiment.saveDisabledMessage.value\"\n :save-loading=\"appExperiment.saveLoading.value\"\n :save-success-message=\"appExperiment.saveSuccessMessage.value\"\n @select=\"appExperiment.openModal()\"\n @save=\"appExperiment.handleSave()\"\n @detach=\"appExperiment.handleDetach()\"\n />\n\n <!-- Standalone pill (standalone + useAppExperiment active) -->\n <span v-if=\"appExperiment && isStandalone\" class=\"mld-topbar__standalone-badge\">\n {{ standaloneLabel }}\n </span>\n\n <!-- Actions slot (right side) -->\n <slot name=\"actions\" />\n <!-- Theme toggle -->\n <ThemeToggle v-if=\"showThemeToggle\" size=\"sm\" />\n <!-- Settings gear -->\n <button\n v-if=\"showSettings\"\n type=\"button\"\n class=\"mld-topbar__settings-btn\"\n aria-label=\"Open settings\"\n @click=\"settingsOpen = true\"\n >\n <svg class=\"mld-topbar__settings-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915\" /><circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n </button>\n <!-- Admin link -->\n <router-link\n v-if=\"showAdmin\"\n :to=\"adminPath\"\n class=\"mld-topbar__admin-btn\"\n aria-label=\"Admin Dashboard\"\n @click=\"emit('admin-click')\"\n >\n <svg class=\"mld-topbar__admin-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\" /><path d=\"m9 12 2 2 4-4\" />\n </svg>\n </router-link>\n <!-- Profile button -->\n <button\n v-if=\"showProfile\"\n type=\"button\"\n class=\"mld-topbar__profile-btn\"\n aria-label=\"Edit profile\"\n @click=\"emit('profile-click')\"\n >\n <div class=\"mld-topbar__profile-avatar\">\n {{ profileInitial }}\n </div>\n <span v-if=\"userName\" class=\"mld-topbar__profile-name\">{{ userName }}</span>\n </button>\n </div>\n </div>\n </header>\n\n <SettingsModal\n v-if=\"showSettings\"\n v-model=\"settingsOpen\"\n :title=\"settingsConfig?.title\"\n :tabs=\"settingsConfig?.tabs\"\n :show-appearance=\"settingsConfig?.showAppearance ?? true\"\n :size=\"settingsConfig?.size\"\n >\n <template v-for=\"tab in (settingsConfig?.tabs ?? [])\" :key=\"tab.id\" #[`tab-${tab.id}`]>\n <slot :name=\"`settings-tab-${tab.id}`\" />\n </template>\n <template #appearance>\n <slot name=\"settings-appearance\" />\n </template>\n </SettingsModal>\n\n <ExperimentSelectorModal\n v-if=\"appExperiment && !isStandalone\"\n :model-value=\"appExperiment.showModal.value\"\n :current-experiment-id=\"appExperiment.experimentId.value\"\n @update:model-value=\"$event ? appExperiment.openModal() : appExperiment.closeModal()\"\n @select=\"appExperiment.handleSelect($event)\"\n @deselect=\"appExperiment.handleDetach()\"\n />\n</template>\n\n<style>\n@import '../styles/components/app-top-bar.css';\n</style>\n"],"names":["_createElementVNode","_normalizeClass","_createElementBlock","_renderSlot","_openBlock","_createBlock","_toDisplayString","_createTextVNode","_withDirectives","_Fragment","_renderList","_a","_withModifiers","_b","_unref","ExperimentPopover","ThemeToggle","SettingsModal","ExperimentSelectorModal"],"mappings":"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"}
@@ -25,9 +25,9 @@ declare const __VLS_component: import('vue').DefineComponent<Props, {}, {}, {},
25
25
  "onEntry-click"?: ((entry: AuditEntry) => any) | undefined;
26
26
  }>, {
27
27
  size: "sm" | "md" | "lg";
28
- emptyMessage: string;
29
28
  order: "newest" | "oldest";
30
29
  showFilters: boolean;
30
+ emptyMessage: string;
31
31
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
32
32
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
33
33
  export default _default;
@@ -19,9 +19,9 @@ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, imp
19
19
  }>, {
20
20
  size: ModalSize;
21
21
  title: string;
22
- showFilters: boolean;
23
22
  currentExperimentId: number | null;
24
23
  groupByProject: boolean;
24
+ showFilters: boolean;
25
25
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
26
26
  listRef: HTMLDivElement;
27
27
  }, any>;
@@ -7,8 +7,8 @@ interface Props {
7
7
  copyable?: boolean;
8
8
  }
9
9
  declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
10
+ copyable: boolean;
10
11
  precision: number;
11
12
  notation: NumberNotation;
12
- copyable: boolean;
13
13
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLSpanElement>;
14
14
  export default _default;
@@ -22,3 +22,4 @@ export { useExperimentSelector, type UseExperimentSelectorOptions, type UseExper
22
22
  export { formatExperimentDate, datePresetToISO, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, EXPERIMENT_STATUS_LABELS, DATE_PRESET_OPTIONS, SORT_OPTIONS, } from './experiment-utils';
23
23
  export { useExperimentData, type UseExperimentDataOptions, type UseExperimentDataReturn, } from './useExperimentData';
24
24
  export { getFieldRegistryEntry, getTypeDefault, type RegistryEntry, } from './formBuilderRegistry';
25
+ export { useAppExperiment, APP_EXPERIMENT_KEY, type UseAppExperimentOptions, type UseAppExperimentReturn, type AppExperimentState, } from './useAppExperiment';
@@ -22,7 +22,9 @@ import { useExperimentSelector } from "./useExperimentSelector.js";
22
22
  import { DATE_PRESET_OPTIONS, EXPERIMENT_STATUS_LABELS, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, SORT_OPTIONS, datePresetToISO, formatExperimentDate } from "./experiment-utils.js";
23
23
  import { useExperimentData } from "./useExperimentData.js";
24
24
  import { getFieldRegistryEntry, getTypeDefault } from "./formBuilderRegistry.js";
25
+ import { APP_EXPERIMENT_KEY, useAppExperiment } from "./useAppExperiment.js";
25
26
  export {
27
+ APP_EXPERIMENT_KEY,
26
28
  ATOMIC_WEIGHTS,
27
29
  DATE_PRESET_OPTIONS,
28
30
  DEFAULT_COLORS,
@@ -47,6 +49,7 @@ export {
47
49
  rangesOverlap,
48
50
  snapToSlot,
49
51
  useApi,
52
+ useAppExperiment,
50
53
  useAsync,
51
54
  useAsyncBatch,
52
55
  useAuth,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,34 @@
1
+ import { Ref, ComputedRef, InjectionKey } from 'vue';
2
+ import { ExperimentSummary, ExperimentStatus } from '../types';
3
+ export interface UseAppExperimentOptions {
4
+ onSelect?: (experiment: ExperimentSummary) => void | Promise<void>;
5
+ onSave?: () => string | null | Promise<string | null>;
6
+ onDetach?: () => void;
7
+ saveDisabled?: Ref<boolean> | ComputedRef<boolean>;
8
+ saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>;
9
+ }
10
+ export interface UseAppExperimentReturn {
11
+ set: (experiment: Pick<ExperimentSummary, 'id' | 'name' | 'status'>) => void;
12
+ clear: () => void;
13
+ experimentName: Readonly<Ref<string | undefined>>;
14
+ experimentId: Readonly<Ref<number | null>>;
15
+ }
16
+ export interface AppExperimentState {
17
+ experimentName: Ref<string | undefined>;
18
+ experimentStatus: Ref<ExperimentStatus | undefined>;
19
+ experimentId: Ref<number | null>;
20
+ showModal: Ref<boolean>;
21
+ saveLoading: Ref<boolean>;
22
+ saveSuccessMessage: Ref<string | undefined>;
23
+ showSave: Ref<boolean>;
24
+ showDetach: ComputedRef<boolean>;
25
+ closeModal: () => void;
26
+ saveDisabled: ComputedRef<boolean>;
27
+ saveDisabledMessage: ComputedRef<string | undefined>;
28
+ openModal: () => void;
29
+ handleSelect: (experiment: ExperimentSummary) => void;
30
+ handleSave: () => Promise<void>;
31
+ handleDetach: () => void;
32
+ }
33
+ export declare const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState>;
34
+ export declare function useAppExperiment(options?: UseAppExperimentOptions): UseAppExperimentReturn;
@@ -0,0 +1,91 @@
1
+ import { ref, computed, toValue, onScopeDispose, provide, readonly } from "vue";
2
+ const APP_EXPERIMENT_KEY = Symbol("app-experiment");
3
+ function useAppExperiment(options = {}) {
4
+ const experimentName = ref();
5
+ const experimentStatus = ref();
6
+ const experimentId = ref(null);
7
+ const showModal = ref(false);
8
+ const saveLoading = ref(false);
9
+ const saveSuccessMessage = ref();
10
+ let successTimer = null;
11
+ const showSave = ref(!!options.onSave);
12
+ const showDetach = computed(() => experimentId.value !== null);
13
+ const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false);
14
+ const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage));
15
+ function set(experiment) {
16
+ experimentId.value = experiment.id;
17
+ experimentName.value = experiment.name;
18
+ experimentStatus.value = experiment.status;
19
+ }
20
+ function clear() {
21
+ experimentId.value = null;
22
+ experimentName.value = void 0;
23
+ experimentStatus.value = void 0;
24
+ }
25
+ function openModal() {
26
+ showModal.value = true;
27
+ }
28
+ function closeModal() {
29
+ showModal.value = false;
30
+ }
31
+ function handleSelect(experiment) {
32
+ var _a;
33
+ set(experiment);
34
+ showModal.value = false;
35
+ (_a = options.onSelect) == null ? void 0 : _a.call(options, experiment);
36
+ }
37
+ async function handleSave() {
38
+ if (!options.onSave || saveLoading.value) return;
39
+ saveLoading.value = true;
40
+ try {
41
+ const message = await options.onSave();
42
+ if (message) {
43
+ saveSuccessMessage.value = message;
44
+ if (successTimer) clearTimeout(successTimer);
45
+ successTimer = setTimeout(() => {
46
+ saveSuccessMessage.value = void 0;
47
+ successTimer = null;
48
+ }, 3e3);
49
+ }
50
+ } finally {
51
+ saveLoading.value = false;
52
+ }
53
+ }
54
+ function handleDetach() {
55
+ var _a;
56
+ clear();
57
+ (_a = options.onDetach) == null ? void 0 : _a.call(options);
58
+ }
59
+ onScopeDispose(() => {
60
+ if (successTimer) clearTimeout(successTimer);
61
+ });
62
+ const state = {
63
+ experimentName,
64
+ experimentStatus,
65
+ experimentId,
66
+ showModal,
67
+ saveLoading,
68
+ saveSuccessMessage,
69
+ showSave,
70
+ showDetach,
71
+ saveDisabled,
72
+ saveDisabledMessage,
73
+ openModal,
74
+ closeModal,
75
+ handleSelect,
76
+ handleSave,
77
+ handleDetach
78
+ };
79
+ provide(APP_EXPERIMENT_KEY, state);
80
+ return {
81
+ set,
82
+ clear,
83
+ experimentName: readonly(experimentName),
84
+ experimentId: readonly(experimentId)
85
+ };
86
+ }
87
+ export {
88
+ APP_EXPERIMENT_KEY,
89
+ useAppExperiment
90
+ };
91
+ //# sourceMappingURL=useAppExperiment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAppExperiment.js","sources":["../../src/composables/useAppExperiment.ts"],"sourcesContent":["import {\n ref,\n computed,\n readonly,\n provide,\n toValue,\n onScopeDispose,\n type Ref,\n type ComputedRef,\n type InjectionKey,\n} from 'vue'\nimport type { ExperimentSummary, ExperimentStatus } from '../types'\n\nexport interface UseAppExperimentOptions {\n onSelect?: (experiment: ExperimentSummary) => void | Promise<void>\n onSave?: () => string | null | Promise<string | null>\n onDetach?: () => void\n saveDisabled?: Ref<boolean> | ComputedRef<boolean>\n saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>\n}\n\nexport interface UseAppExperimentReturn {\n set: (experiment: Pick<ExperimentSummary, 'id' | 'name' | 'status'>) => void\n clear: () => void\n experimentName: Readonly<Ref<string | undefined>>\n experimentId: Readonly<Ref<number | null>>\n}\n\nexport interface AppExperimentState {\n experimentName: Ref<string | undefined>\n experimentStatus: Ref<ExperimentStatus | undefined>\n experimentId: Ref<number | null>\n showModal: Ref<boolean>\n saveLoading: Ref<boolean>\n saveSuccessMessage: Ref<string | undefined>\n showSave: Ref<boolean>\n showDetach: ComputedRef<boolean>\n closeModal: () => void\n saveDisabled: ComputedRef<boolean>\n saveDisabledMessage: ComputedRef<string | undefined>\n openModal: () => void\n handleSelect: (experiment: ExperimentSummary) => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState> = Symbol('app-experiment')\n\nexport function useAppExperiment(options: UseAppExperimentOptions = {}): UseAppExperimentReturn {\n const experimentName = ref<string | undefined>()\n const experimentStatus = ref<ExperimentStatus | undefined>()\n const experimentId = ref<number | null>(null)\n const showModal = ref(false)\n const saveLoading = ref(false)\n const saveSuccessMessage = ref<string | undefined>()\n\n let successTimer: ReturnType<typeof setTimeout> | null = null\n\n const showSave = ref(!!options.onSave)\n const showDetach = computed(() => experimentId.value !== null)\n const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false)\n const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage))\n\n function set(experiment: Pick<ExperimentSummary, 'id' | 'name' | 'status'>) {\n experimentId.value = experiment.id\n experimentName.value = experiment.name\n experimentStatus.value = experiment.status\n }\n\n function clear() {\n experimentId.value = null\n experimentName.value = undefined\n experimentStatus.value = undefined\n }\n\n function openModal() {\n showModal.value = true\n }\n\n function closeModal() {\n showModal.value = false\n }\n\n function handleSelect(experiment: ExperimentSummary) {\n set(experiment)\n showModal.value = false\n options.onSelect?.(experiment)\n }\n\n async function handleSave() {\n if (!options.onSave || saveLoading.value) return\n saveLoading.value = true\n try {\n const message = await options.onSave()\n if (message) {\n saveSuccessMessage.value = message\n if (successTimer) clearTimeout(successTimer)\n successTimer = setTimeout(() => {\n saveSuccessMessage.value = undefined\n successTimer = null\n }, 3000)\n }\n } finally {\n saveLoading.value = false\n }\n }\n\n function handleDetach() {\n clear()\n options.onDetach?.()\n }\n\n onScopeDispose(() => {\n if (successTimer) clearTimeout(successTimer)\n })\n\n const state: AppExperimentState = {\n experimentName,\n experimentStatus,\n experimentId,\n showModal,\n saveLoading,\n saveSuccessMessage,\n showSave,\n showDetach,\n saveDisabled,\n saveDisabledMessage,\n openModal,\n closeModal,\n handleSelect,\n handleSave,\n handleDetach,\n }\n\n provide(APP_EXPERIMENT_KEY, state)\n\n return {\n set,\n clear,\n experimentName: readonly(experimentName),\n experimentId: readonly(experimentId),\n }\n}\n"],"names":[],"mappings":";AA8CO,MAAM,qBAAuD,OAAO,gBAAgB;AAEpF,SAAS,iBAAiB,UAAmC,IAA4B;AAC9F,QAAM,iBAAiB,IAAA;AACvB,QAAM,mBAAmB,IAAA;AACzB,QAAM,eAAe,IAAmB,IAAI;AAC5C,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,cAAc,IAAI,KAAK;AAC7B,QAAM,qBAAqB,IAAA;AAE3B,MAAI,eAAqD;AAEzD,QAAM,WAAW,IAAI,CAAC,CAAC,QAAQ,MAAM;AACrC,QAAM,aAAa,SAAS,MAAM,aAAa,UAAU,IAAI;AAC7D,QAAM,eAAe,SAAS,MAAM,QAAQ,QAAQ,YAAY,KAAK,KAAK;AAC1E,QAAM,sBAAsB,SAAS,MAAM,QAAQ,QAAQ,mBAAmB,CAAC;AAE/E,WAAS,IAAI,YAA+D;AAC1E,iBAAa,QAAQ,WAAW;AAChC,mBAAe,QAAQ,WAAW;AAClC,qBAAiB,QAAQ,WAAW;AAAA,EACtC;AAEA,WAAS,QAAQ;AACf,iBAAa,QAAQ;AACrB,mBAAe,QAAQ;AACvB,qBAAiB,QAAQ;AAAA,EAC3B;AAEA,WAAS,YAAY;AACnB,cAAU,QAAQ;AAAA,EACpB;AAEA,WAAS,aAAa;AACpB,cAAU,QAAQ;AAAA,EACpB;AAEA,WAAS,aAAa,YAA+B;;AACnD,QAAI,UAAU;AACd,cAAU,QAAQ;AAClB,kBAAQ,aAAR,iCAAmB;AAAA,EACrB;AAEA,iBAAe,aAAa;AAC1B,QAAI,CAAC,QAAQ,UAAU,YAAY,MAAO;AAC1C,gBAAY,QAAQ;AACpB,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,OAAA;AAC9B,UAAI,SAAS;AACX,2BAAmB,QAAQ;AAC3B,YAAI,2BAA2B,YAAY;AAC3C,uBAAe,WAAW,MAAM;AAC9B,6BAAmB,QAAQ;AAC3B,yBAAe;AAAA,QACjB,GAAG,GAAI;AAAA,MACT;AAAA,IACF,UAAA;AACE,kBAAY,QAAQ;AAAA,IACtB;AAAA,EACF;AAEA,WAAS,eAAe;;AACtB,UAAA;AACA,kBAAQ,aAAR;AAAA,EACF;AAEA,iBAAe,MAAM;AACnB,QAAI,2BAA2B,YAAY;AAAA,EAC7C,CAAC;AAED,QAAM,QAA4B;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,UAAQ,oBAAoB,KAAK;AAEjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,gBAAgB,SAAS,cAAc;AAAA,IACvC,cAAc,SAAS,YAAY;AAAA,EAAA;AAEvC;"}
@@ -54,7 +54,14 @@ function usePlatformContext(options = {}) {
54
54
  }
55
55
  platformContext.value = {
56
56
  isIntegrated: hasPluginParam,
57
- theme: localStorage.getItem("mld-theme") || "system",
57
+ theme: (() => {
58
+ try {
59
+ const s = localStorage.getItem("mld-settings");
60
+ if (s) return JSON.parse(s).theme || "system";
61
+ } catch {
62
+ }
63
+ return "system";
64
+ })(),
58
65
  platformOrigin: platformOrigin || void 0
59
66
  };
60
67
  }