@vite-plugin-opencode-assistant/components 1.0.12 → 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/es/index.d.ts +1 -1
  2. package/es/index.js +1 -1
  3. package/es/open-code-widget/composables/use-inspector.js +35 -8
  4. package/es/open-code-widget/composables/use-selection.js +1 -6
  5. package/es/open-code-widget/src/components/Frame-sfc.css +1 -1
  6. package/es/open-code-widget/src/components/Frame.vue.d.ts +4 -2
  7. package/es/open-code-widget/src/components/Frame.vue.js +17 -3
  8. package/es/open-code-widget/src/components/SelectHint-sfc.css +1 -1
  9. package/es/open-code-widget/src/components/SessionList.vue.js +3 -1
  10. package/es/open-code-widget/src/context.d.ts +4 -1
  11. package/es/open-code-widget/src/index.vue.d.ts +34 -28
  12. package/es/open-code-widget/src/index.vue.js +24 -9
  13. package/es/open-code-widget/src/types.d.ts +3 -79
  14. package/lib/@vite-plugin-opencode-assistant/components.cjs.js +84 -34
  15. package/lib/@vite-plugin-opencode-assistant/components.es.js +83 -33
  16. package/lib/components.css +2 -2
  17. package/lib/index.d.ts +1 -1
  18. package/lib/index.js +1 -1
  19. package/lib/open-code-widget/composables/use-inspector.js +36 -9
  20. package/lib/open-code-widget/composables/use-selection.js +2 -7
  21. package/lib/open-code-widget/src/components/Frame-sfc.css +1 -1
  22. package/lib/open-code-widget/src/components/Frame.vue.d.ts +4 -2
  23. package/lib/open-code-widget/src/components/Frame.vue.js +17 -3
  24. package/lib/open-code-widget/src/components/SelectHint-sfc.css +1 -1
  25. package/lib/open-code-widget/src/components/SessionList.vue.js +3 -1
  26. package/lib/open-code-widget/src/context.d.ts +4 -1
  27. package/lib/open-code-widget/src/index.vue.d.ts +34 -28
  28. package/lib/open-code-widget/src/index.vue.js +24 -9
  29. package/lib/open-code-widget/src/types.d.ts +3 -79
  30. package/lib/web-types.json +1 -1
  31. package/package.json +4 -1
@@ -3,6 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  let vue = require("vue");
6
+ let _vite_plugin_opencode_assistant_shared = require("@vite-plugin-opencode-assistant/shared");
6
7
  //#region es/open-code-widget/src/context.js
7
8
  var CONTEXT_KEY = /* @__PURE__ */ Symbol("OpenCodeWidgetContext");
8
9
  function provideOpenCodeWidgetContext(context) {
@@ -37,7 +38,7 @@ var __vue_sfc__$7 = /* @__PURE__ */ (0, vue.defineComponent)({
37
38
  setup(__props, { expose: __expose }) {
38
39
  __expose();
39
40
  const iframeRef = (0, vue.ref)(null);
40
- const { loading, showEmptyState, iframeSource: iframeSrc, emptyStateText, emptyStateActionText, handleEmptyAction, theme, resolvedTheme } = useOpenCodeWidgetContext();
41
+ const { frameLoading, showEmptyState, showError, iframeSource: iframeSrc, emptyStateText, emptyStateActionText, handleEmptyAction, handleFrameLoaded, theme, resolvedTheme } = useOpenCodeWidgetContext();
41
42
  const iframeReady = (0, vue.ref)(false);
42
43
  function sendMessageToIframe(type, data) {
43
44
  var _a;
@@ -57,6 +58,7 @@ var __vue_sfc__$7 = /* @__PURE__ */ (0, vue.defineComponent)({
57
58
  (0, vue.onMounted)(() => {
58
59
  if (iframeRef.value) iframeRef.value.addEventListener("load", () => {
59
60
  iframeReady.value = true;
61
+ handleFrameLoaded();
60
62
  });
61
63
  window.addEventListener("message", handleIframeMessage);
62
64
  });
@@ -65,12 +67,14 @@ var __vue_sfc__$7 = /* @__PURE__ */ (0, vue.defineComponent)({
65
67
  });
66
68
  const __returned__ = {
67
69
  iframeRef,
68
- loading,
70
+ frameLoading,
69
71
  showEmptyState,
72
+ showError,
70
73
  iframeSrc,
71
74
  emptyStateText,
72
75
  emptyStateActionText,
73
76
  handleEmptyAction,
77
+ handleFrameLoaded,
74
78
  theme,
75
79
  resolvedTheme,
76
80
  iframeReady,
@@ -111,7 +115,8 @@ function __vue_render__$7(_ctx, _cache, $props, $setup, $data, $options) {
111
115
  onClick: _cache[0] || (_cache[0] = (...args) => $setup.handleEmptyAction && $setup.handleEmptyAction(...args))
112
116
  }, (0, vue.toDisplayString)($setup.emptyStateActionText), 1)
113
117
  ])], 2),
114
- (0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["opencode-loading-overlay", { visible: $setup.loading }]) }, [(0, vue.renderSlot)(_ctx.$slots, "loading", {}, () => [_cache[2] || (_cache[2] = (0, vue.createElementVNode)("div", { class: "opencode-loading-spinner" }, null, -1)), _cache[3] || (_cache[3] = (0, vue.createElementVNode)("div", { class: "opencode-loading-text" }, "加载中...", -1))])], 2),
118
+ (0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["opencode-loading-overlay", { visible: $setup.frameLoading }]) }, [(0, vue.renderSlot)(_ctx.$slots, "loading", {}, () => [_cache[2] || (_cache[2] = (0, vue.createElementVNode)("div", { class: "opencode-loading-spinner" }, null, -1)), _cache[3] || (_cache[3] = (0, vue.createElementVNode)("div", { class: "opencode-loading-text" }, "加载中...", -1))])], 2),
119
+ (0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["opencode-error-overlay", { visible: $setup.showError }]) }, [(0, vue.renderSlot)(_ctx.$slots, "error")], 2),
115
120
  (0, vue.renderSlot)(_ctx.$slots, "content", {}, () => [(0, vue.createElementVNode)("iframe", {
116
121
  ref: "iframeRef",
117
122
  class: "opencode-iframe",
@@ -427,7 +432,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)({
427
432
  __name: "SessionList",
428
433
  setup(__props, { expose: __expose }) {
429
434
  __expose();
430
- const { sessionListCollapsed: collapsed, sessionItems: sessions, loadingSessionList, handleCreateSession, handleSelectSession, handleDeleteSession, sessionKey } = useOpenCodeWidgetContext();
435
+ const { sessionListCollapsed: collapsed, sessionItems: sessions, loadingSessionList, showSessionListSkeleton, handleCreateSession, handleSelectSession, handleDeleteSession, sessionKey } = useOpenCodeWidgetContext();
431
436
  const isAnimating = (0, vue.ref)(false);
432
437
  let animTimer = null;
433
438
  (0, vue.watch)(collapsed, () => {
@@ -441,6 +446,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)({
441
446
  collapsed,
442
447
  sessions,
443
448
  loadingSessionList,
449
+ showSessionListSkeleton,
444
450
  handleCreateSession,
445
451
  handleSelectSession,
446
452
  handleDeleteSession,
@@ -454,6 +460,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)({
454
460
  },
455
461
  showSkeleton: (0, vue.computed)(() => {
456
462
  if (isAnimating.value) return true;
463
+ if (showSessionListSkeleton.value) return true;
457
464
  return false;
458
465
  })
459
466
  };
@@ -601,10 +608,6 @@ var __async$1 = (__this, __arguments, generator) => {
601
608
  step((generator = generator.apply(__this, __arguments)).next());
602
609
  });
603
610
  };
604
- function truncate$1(value, maxLength) {
605
- if (value.length <= maxLength) return value;
606
- return `${value.slice(0, maxLength)}...`;
607
- }
608
611
  function getElementKey(element, index) {
609
612
  var _a;
610
613
  if (element.filePath && element.line) return `${element.filePath}:${element.line}:${(_a = element.column) != null ? _a : 0}`;
@@ -618,7 +621,7 @@ function getPanelFileText(element) {
618
621
  var _a, _b;
619
622
  const fileName = ((_a = element.filePath) == null ? void 0 : _a.split("/").pop()) || "未知文件";
620
623
  const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
621
- return `${((_b = element.innerText) == null ? void 0 : _b.trim()) ? `${truncate$1(element.innerText.trim(), 30)} \xB7 ` : ""}${fileName}${lineInfo}`;
624
+ return `${((_b = element.innerText) == null ? void 0 : _b.trim()) ? `${(0, _vite_plugin_opencode_assistant_shared.truncate)(element.innerText.trim(), 30)} \xB7 ` : ""}${fileName}${lineInfo}`;
622
625
  }
623
626
  function useSelection(options) {
624
627
  const bubbleVisible = (0, vue.computed)(() => options.selectMode.value);
@@ -838,10 +841,6 @@ function useWidget(options) {
838
841
  }
839
842
  //#endregion
840
843
  //#region es/open-code-widget/composables/use-inspector.js
841
- function truncate(str, maxLength) {
842
- if (!str) return "";
843
- return str.length > maxLength ? str.substring(0, maxLength) + "..." : str;
844
- }
845
844
  function getDirectText(element) {
846
845
  let text = "";
847
846
  for (let i = 0; i < element.childNodes.length; i++) {
@@ -867,6 +866,32 @@ function getElementDescription(element) {
867
866
  if (href && href !== "#") parts.push(`[href]`);
868
867
  return parts.join("");
869
868
  }
869
+ function getPreciseElementAtPoint(x, y, boundary) {
870
+ var _a, _b;
871
+ const highlight = document.querySelector(".opencode-element-highlight");
872
+ const tooltip = document.querySelector(".opencode-element-tooltip");
873
+ const highlightDisplay = ((_a = highlight == null ? void 0 : highlight.getAttribute("style")) == null ? void 0 : _a.includes("display: block")) ? "block" : "none";
874
+ const tooltipDisplay = ((_b = tooltip == null ? void 0 : tooltip.getAttribute("style")) == null ? void 0 : _b.includes("display: block")) ? "block" : "none";
875
+ if (highlight) highlight.style.display = "none";
876
+ if (tooltip) tooltip.style.display = "none";
877
+ let element = null;
878
+ try {
879
+ const elements = document.elementsFromPoint(x, y);
880
+ for (const el of elements) {
881
+ if (el.closest("#vue-inspector-container")) continue;
882
+ if (el.closest(".opencode-widget")) continue;
883
+ if (el.hasAttribute("data-v-inspector-ignore")) continue;
884
+ if (boundary.contains(el) || el === boundary) {
885
+ element = el;
886
+ break;
887
+ }
888
+ }
889
+ } finally {
890
+ if (highlight) highlight.style.display = highlightDisplay;
891
+ if (tooltip) tooltip.style.display = tooltipDisplay;
892
+ }
893
+ return element;
894
+ }
870
895
  function useInspector(options) {
871
896
  const highlightVisible = (0, vue.ref)(false);
872
897
  const highlightStyle = (0, vue.ref)({
@@ -892,7 +917,8 @@ function useInspector(options) {
892
917
  if (!inspector) return;
893
918
  const { targetNode, params } = inspector.getTargetNode(e);
894
919
  if (targetNode && params) {
895
- const rect = targetNode.getBoundingClientRect();
920
+ const elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
921
+ const rect = elementToHighlight.getBoundingClientRect();
896
922
  const widget = document.querySelector(".opencode-widget");
897
923
  let primary = "#3b82f6";
898
924
  let primaryBg = "rgba(59, 130, 246, 0.1)";
@@ -910,7 +936,7 @@ function useInspector(options) {
910
936
  border: `2px solid ${primary}`,
911
937
  background: primaryBg
912
938
  };
913
- const description = getElementDescription(targetNode);
939
+ const description = getElementDescription(elementToHighlight);
914
940
  const fileName = params.file ? params.file.split("/").pop() : "";
915
941
  let lineInfo = "";
916
942
  if (params.line) {
@@ -946,13 +972,14 @@ function useInspector(options) {
946
972
  if (options.selectMode.value) {
947
973
  const { targetNode, params } = inspector.getTargetNode(e);
948
974
  if (targetNode && params) {
949
- const innerText = getDirectText(targetNode);
950
- const description = getElementDescription(targetNode);
975
+ const elementToSelect = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
976
+ const innerText = getDirectText(elementToSelect);
977
+ const description = getElementDescription(elementToSelect);
951
978
  const elementInfo = {
952
979
  filePath: (_a = params.file) != null ? _a : null,
953
980
  line: (_b = params.line) != null ? _b : null,
954
981
  column: (_c = params.column) != null ? _c : null,
955
- innerText: truncate(innerText, 200),
982
+ innerText: (0, _vite_plugin_opencode_assistant_shared.truncate)(innerText, 200),
956
983
  description
957
984
  };
958
985
  options.onAddSelectedNode(elementInfo);
@@ -1079,7 +1106,7 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1079
1106
  required: false,
1080
1107
  default: "id"
1081
1108
  },
1082
- loading: {
1109
+ frameLoading: {
1083
1110
  type: Boolean,
1084
1111
  required: false,
1085
1112
  default: false
@@ -1088,11 +1115,31 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1088
1115
  type: Boolean,
1089
1116
  required: false
1090
1117
  },
1118
+ showSessionListSkeleton: {
1119
+ type: Boolean,
1120
+ required: false,
1121
+ default: false
1122
+ },
1091
1123
  showEmptyState: {
1092
1124
  type: Boolean,
1093
1125
  required: false,
1094
1126
  default: false
1095
1127
  },
1128
+ showError: {
1129
+ type: Boolean,
1130
+ required: false,
1131
+ default: false
1132
+ },
1133
+ emptyStateText: {
1134
+ type: String,
1135
+ required: false,
1136
+ default: "当前项目暂无会话"
1137
+ },
1138
+ emptyStateActionText: {
1139
+ type: String,
1140
+ required: false,
1141
+ default: "立即创建"
1142
+ },
1096
1143
  iframeSrc: {
1097
1144
  type: String,
1098
1145
  required: false,
@@ -1122,16 +1169,6 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1122
1169
  type: Boolean,
1123
1170
  required: false,
1124
1171
  default: true
1125
- },
1126
- emptyStateText: {
1127
- type: String,
1128
- required: false,
1129
- default: "当前项目暂无会话"
1130
- },
1131
- emptyStateActionText: {
1132
- type: String,
1133
- required: false,
1134
- default: "立即创建"
1135
1172
  }
1136
1173
  },
1137
1174
  emits: [
@@ -1152,7 +1189,8 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1152
1189
  "click-selected-node",
1153
1190
  "remove-selected-node",
1154
1191
  "clear-selected-nodes",
1155
- "empty-action"
1192
+ "empty-action",
1193
+ "frame-loaded"
1156
1194
  ],
1157
1195
  setup(__props, { expose: __expose, emit: __emit }) {
1158
1196
  const props = __props;
@@ -1187,6 +1225,9 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1187
1225
  dialogVisible.value = false;
1188
1226
  if (dialogResolve) dialogResolve(false);
1189
1227
  };
1228
+ const handleFrameLoaded = () => {
1229
+ emit("frame-loaded");
1230
+ };
1190
1231
  __expose({
1191
1232
  showNotification,
1192
1233
  showConfirmDialog
@@ -1277,9 +1318,11 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1277
1318
  selectEnabled: (0, vue.toRef)(props, "selectEnabled"),
1278
1319
  sessionListCollapsed: localSessionListCollapsed,
1279
1320
  sessionKey: (0, vue.toRef)(props, "sessionKey"),
1280
- loading: (0, vue.toRef)(props, "loading"),
1321
+ frameLoading: (0, vue.toRef)(props, "frameLoading"),
1281
1322
  loadingSessionList: (0, vue.toRef)(props, "loadingSessionList"),
1323
+ showSessionListSkeleton: (0, vue.toRef)(props, "showSessionListSkeleton"),
1282
1324
  showEmptyState: (0, vue.toRef)(props, "showEmptyState"),
1325
+ showError: (0, vue.toRef)(props, "showError"),
1283
1326
  emptyStateText: (0, vue.toRef)(props, "emptyStateText"),
1284
1327
  emptyStateActionText: (0, vue.toRef)(props, "emptyStateActionText"),
1285
1328
  showClearAll: (0, vue.toRef)(props, "showClearAll"),
@@ -1302,7 +1345,8 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1302
1345
  handleToggleSelectMode,
1303
1346
  handleClickSelectedNode,
1304
1347
  handleRemoveSelectedNode: (payload) => handleRemoveSelectedNode(payload.item, payload.index, payload.source),
1305
- handleClearSelectedNodes
1348
+ handleClearSelectedNodes,
1349
+ handleFrameLoaded
1306
1350
  });
1307
1351
  const __returned__ = {
1308
1352
  props,
@@ -1328,6 +1372,7 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1328
1372
  showConfirmDialog,
1329
1373
  handleDialogConfirm,
1330
1374
  handleDialogCancel,
1375
+ handleFrameLoaded,
1331
1376
  localSessionListCollapsed,
1332
1377
  buttonActive,
1333
1378
  containerClasses,
@@ -1433,10 +1478,15 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
1433
1478
  fn: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "loading")]),
1434
1479
  key: "1"
1435
1480
  } : void 0,
1481
+ $setup.slots.error ? {
1482
+ name: "error",
1483
+ fn: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "error")]),
1484
+ key: "2"
1485
+ } : void 0,
1436
1486
  $setup.slots.content ? {
1437
1487
  name: "content",
1438
1488
  fn: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "content")]),
1439
- key: "2"
1489
+ key: "3"
1440
1490
  } : void 0
1441
1491
  ]), 1024),
1442
1492
  (0, vue.createVNode)($setup["SelectedNodes"])
@@ -1469,7 +1519,7 @@ __vue_sfc__.render = __vue_render__;
1469
1519
  var open_code_widget_default = __vue_sfc__;
1470
1520
  //#endregion
1471
1521
  //#region es/index.js
1472
- var version = "1.0.12";
1522
+ var version = "1.0.14";
1473
1523
  function install(app, options) {
1474
1524
  [open_code_widget_default].forEach((item) => {
1475
1525
  if (item.install) app.use(item, options);
@@ -1,4 +1,5 @@
1
1
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createStaticVNode, createVNode, defineComponent, inject, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, provide, ref, renderList, renderSlot, toDisplayString, toRef, useSlots, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
2
+ import { truncate } from "@vite-plugin-opencode-assistant/shared";
2
3
  //#region es/open-code-widget/src/context.js
3
4
  var CONTEXT_KEY = /* @__PURE__ */ Symbol("OpenCodeWidgetContext");
4
5
  function provideOpenCodeWidgetContext(context) {
@@ -33,7 +34,7 @@ var __vue_sfc__$7 = /* @__PURE__ */ defineComponent({
33
34
  setup(__props, { expose: __expose }) {
34
35
  __expose();
35
36
  const iframeRef = ref(null);
36
- const { loading, showEmptyState, iframeSource: iframeSrc, emptyStateText, emptyStateActionText, handleEmptyAction, theme, resolvedTheme } = useOpenCodeWidgetContext();
37
+ const { frameLoading, showEmptyState, showError, iframeSource: iframeSrc, emptyStateText, emptyStateActionText, handleEmptyAction, handleFrameLoaded, theme, resolvedTheme } = useOpenCodeWidgetContext();
37
38
  const iframeReady = ref(false);
38
39
  function sendMessageToIframe(type, data) {
39
40
  var _a;
@@ -53,6 +54,7 @@ var __vue_sfc__$7 = /* @__PURE__ */ defineComponent({
53
54
  onMounted(() => {
54
55
  if (iframeRef.value) iframeRef.value.addEventListener("load", () => {
55
56
  iframeReady.value = true;
57
+ handleFrameLoaded();
56
58
  });
57
59
  window.addEventListener("message", handleIframeMessage);
58
60
  });
@@ -61,12 +63,14 @@ var __vue_sfc__$7 = /* @__PURE__ */ defineComponent({
61
63
  });
62
64
  const __returned__ = {
63
65
  iframeRef,
64
- loading,
66
+ frameLoading,
65
67
  showEmptyState,
68
+ showError,
66
69
  iframeSrc,
67
70
  emptyStateText,
68
71
  emptyStateActionText,
69
72
  handleEmptyAction,
73
+ handleFrameLoaded,
70
74
  theme,
71
75
  resolvedTheme,
72
76
  iframeReady,
@@ -107,7 +111,8 @@ function __vue_render__$7(_ctx, _cache, $props, $setup, $data, $options) {
107
111
  onClick: _cache[0] || (_cache[0] = (...args) => $setup.handleEmptyAction && $setup.handleEmptyAction(...args))
108
112
  }, toDisplayString($setup.emptyStateActionText), 1)
109
113
  ])], 2),
110
- createElementVNode("div", { class: normalizeClass(["opencode-loading-overlay", { visible: $setup.loading }]) }, [renderSlot(_ctx.$slots, "loading", {}, () => [_cache[2] || (_cache[2] = createElementVNode("div", { class: "opencode-loading-spinner" }, null, -1)), _cache[3] || (_cache[3] = createElementVNode("div", { class: "opencode-loading-text" }, "加载中...", -1))])], 2),
114
+ createElementVNode("div", { class: normalizeClass(["opencode-loading-overlay", { visible: $setup.frameLoading }]) }, [renderSlot(_ctx.$slots, "loading", {}, () => [_cache[2] || (_cache[2] = createElementVNode("div", { class: "opencode-loading-spinner" }, null, -1)), _cache[3] || (_cache[3] = createElementVNode("div", { class: "opencode-loading-text" }, "加载中...", -1))])], 2),
115
+ createElementVNode("div", { class: normalizeClass(["opencode-error-overlay", { visible: $setup.showError }]) }, [renderSlot(_ctx.$slots, "error")], 2),
111
116
  renderSlot(_ctx.$slots, "content", {}, () => [createElementVNode("iframe", {
112
117
  ref: "iframeRef",
113
118
  class: "opencode-iframe",
@@ -423,7 +428,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ defineComponent({
423
428
  __name: "SessionList",
424
429
  setup(__props, { expose: __expose }) {
425
430
  __expose();
426
- const { sessionListCollapsed: collapsed, sessionItems: sessions, loadingSessionList, handleCreateSession, handleSelectSession, handleDeleteSession, sessionKey } = useOpenCodeWidgetContext();
431
+ const { sessionListCollapsed: collapsed, sessionItems: sessions, loadingSessionList, showSessionListSkeleton, handleCreateSession, handleSelectSession, handleDeleteSession, sessionKey } = useOpenCodeWidgetContext();
427
432
  const isAnimating = ref(false);
428
433
  let animTimer = null;
429
434
  watch(collapsed, () => {
@@ -437,6 +442,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ defineComponent({
437
442
  collapsed,
438
443
  sessions,
439
444
  loadingSessionList,
445
+ showSessionListSkeleton,
440
446
  handleCreateSession,
441
447
  handleSelectSession,
442
448
  handleDeleteSession,
@@ -450,6 +456,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ defineComponent({
450
456
  },
451
457
  showSkeleton: computed(() => {
452
458
  if (isAnimating.value) return true;
459
+ if (showSessionListSkeleton.value) return true;
453
460
  return false;
454
461
  })
455
462
  };
@@ -597,10 +604,6 @@ var __async$1 = (__this, __arguments, generator) => {
597
604
  step((generator = generator.apply(__this, __arguments)).next());
598
605
  });
599
606
  };
600
- function truncate$1(value, maxLength) {
601
- if (value.length <= maxLength) return value;
602
- return `${value.slice(0, maxLength)}...`;
603
- }
604
607
  function getElementKey(element, index) {
605
608
  var _a;
606
609
  if (element.filePath && element.line) return `${element.filePath}:${element.line}:${(_a = element.column) != null ? _a : 0}`;
@@ -614,7 +617,7 @@ function getPanelFileText(element) {
614
617
  var _a, _b;
615
618
  const fileName = ((_a = element.filePath) == null ? void 0 : _a.split("/").pop()) || "未知文件";
616
619
  const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
617
- return `${((_b = element.innerText) == null ? void 0 : _b.trim()) ? `${truncate$1(element.innerText.trim(), 30)} \xB7 ` : ""}${fileName}${lineInfo}`;
620
+ return `${((_b = element.innerText) == null ? void 0 : _b.trim()) ? `${truncate(element.innerText.trim(), 30)} \xB7 ` : ""}${fileName}${lineInfo}`;
618
621
  }
619
622
  function useSelection(options) {
620
623
  const bubbleVisible = computed(() => options.selectMode.value);
@@ -834,10 +837,6 @@ function useWidget(options) {
834
837
  }
835
838
  //#endregion
836
839
  //#region es/open-code-widget/composables/use-inspector.js
837
- function truncate(str, maxLength) {
838
- if (!str) return "";
839
- return str.length > maxLength ? str.substring(0, maxLength) + "..." : str;
840
- }
841
840
  function getDirectText(element) {
842
841
  let text = "";
843
842
  for (let i = 0; i < element.childNodes.length; i++) {
@@ -863,6 +862,32 @@ function getElementDescription(element) {
863
862
  if (href && href !== "#") parts.push(`[href]`);
864
863
  return parts.join("");
865
864
  }
865
+ function getPreciseElementAtPoint(x, y, boundary) {
866
+ var _a, _b;
867
+ const highlight = document.querySelector(".opencode-element-highlight");
868
+ const tooltip = document.querySelector(".opencode-element-tooltip");
869
+ const highlightDisplay = ((_a = highlight == null ? void 0 : highlight.getAttribute("style")) == null ? void 0 : _a.includes("display: block")) ? "block" : "none";
870
+ const tooltipDisplay = ((_b = tooltip == null ? void 0 : tooltip.getAttribute("style")) == null ? void 0 : _b.includes("display: block")) ? "block" : "none";
871
+ if (highlight) highlight.style.display = "none";
872
+ if (tooltip) tooltip.style.display = "none";
873
+ let element = null;
874
+ try {
875
+ const elements = document.elementsFromPoint(x, y);
876
+ for (const el of elements) {
877
+ if (el.closest("#vue-inspector-container")) continue;
878
+ if (el.closest(".opencode-widget")) continue;
879
+ if (el.hasAttribute("data-v-inspector-ignore")) continue;
880
+ if (boundary.contains(el) || el === boundary) {
881
+ element = el;
882
+ break;
883
+ }
884
+ }
885
+ } finally {
886
+ if (highlight) highlight.style.display = highlightDisplay;
887
+ if (tooltip) tooltip.style.display = tooltipDisplay;
888
+ }
889
+ return element;
890
+ }
866
891
  function useInspector(options) {
867
892
  const highlightVisible = ref(false);
868
893
  const highlightStyle = ref({
@@ -888,7 +913,8 @@ function useInspector(options) {
888
913
  if (!inspector) return;
889
914
  const { targetNode, params } = inspector.getTargetNode(e);
890
915
  if (targetNode && params) {
891
- const rect = targetNode.getBoundingClientRect();
916
+ const elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
917
+ const rect = elementToHighlight.getBoundingClientRect();
892
918
  const widget = document.querySelector(".opencode-widget");
893
919
  let primary = "#3b82f6";
894
920
  let primaryBg = "rgba(59, 130, 246, 0.1)";
@@ -906,7 +932,7 @@ function useInspector(options) {
906
932
  border: `2px solid ${primary}`,
907
933
  background: primaryBg
908
934
  };
909
- const description = getElementDescription(targetNode);
935
+ const description = getElementDescription(elementToHighlight);
910
936
  const fileName = params.file ? params.file.split("/").pop() : "";
911
937
  let lineInfo = "";
912
938
  if (params.line) {
@@ -942,8 +968,9 @@ function useInspector(options) {
942
968
  if (options.selectMode.value) {
943
969
  const { targetNode, params } = inspector.getTargetNode(e);
944
970
  if (targetNode && params) {
945
- const innerText = getDirectText(targetNode);
946
- const description = getElementDescription(targetNode);
971
+ const elementToSelect = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
972
+ const innerText = getDirectText(elementToSelect);
973
+ const description = getElementDescription(elementToSelect);
947
974
  const elementInfo = {
948
975
  filePath: (_a = params.file) != null ? _a : null,
949
976
  line: (_b = params.line) != null ? _b : null,
@@ -1075,7 +1102,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1075
1102
  required: false,
1076
1103
  default: "id"
1077
1104
  },
1078
- loading: {
1105
+ frameLoading: {
1079
1106
  type: Boolean,
1080
1107
  required: false,
1081
1108
  default: false
@@ -1084,11 +1111,31 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1084
1111
  type: Boolean,
1085
1112
  required: false
1086
1113
  },
1114
+ showSessionListSkeleton: {
1115
+ type: Boolean,
1116
+ required: false,
1117
+ default: false
1118
+ },
1087
1119
  showEmptyState: {
1088
1120
  type: Boolean,
1089
1121
  required: false,
1090
1122
  default: false
1091
1123
  },
1124
+ showError: {
1125
+ type: Boolean,
1126
+ required: false,
1127
+ default: false
1128
+ },
1129
+ emptyStateText: {
1130
+ type: String,
1131
+ required: false,
1132
+ default: "当前项目暂无会话"
1133
+ },
1134
+ emptyStateActionText: {
1135
+ type: String,
1136
+ required: false,
1137
+ default: "立即创建"
1138
+ },
1092
1139
  iframeSrc: {
1093
1140
  type: String,
1094
1141
  required: false,
@@ -1118,16 +1165,6 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1118
1165
  type: Boolean,
1119
1166
  required: false,
1120
1167
  default: true
1121
- },
1122
- emptyStateText: {
1123
- type: String,
1124
- required: false,
1125
- default: "当前项目暂无会话"
1126
- },
1127
- emptyStateActionText: {
1128
- type: String,
1129
- required: false,
1130
- default: "立即创建"
1131
1168
  }
1132
1169
  },
1133
1170
  emits: [
@@ -1148,7 +1185,8 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1148
1185
  "click-selected-node",
1149
1186
  "remove-selected-node",
1150
1187
  "clear-selected-nodes",
1151
- "empty-action"
1188
+ "empty-action",
1189
+ "frame-loaded"
1152
1190
  ],
1153
1191
  setup(__props, { expose: __expose, emit: __emit }) {
1154
1192
  const props = __props;
@@ -1183,6 +1221,9 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1183
1221
  dialogVisible.value = false;
1184
1222
  if (dialogResolve) dialogResolve(false);
1185
1223
  };
1224
+ const handleFrameLoaded = () => {
1225
+ emit("frame-loaded");
1226
+ };
1186
1227
  __expose({
1187
1228
  showNotification,
1188
1229
  showConfirmDialog
@@ -1273,9 +1314,11 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1273
1314
  selectEnabled: toRef(props, "selectEnabled"),
1274
1315
  sessionListCollapsed: localSessionListCollapsed,
1275
1316
  sessionKey: toRef(props, "sessionKey"),
1276
- loading: toRef(props, "loading"),
1317
+ frameLoading: toRef(props, "frameLoading"),
1277
1318
  loadingSessionList: toRef(props, "loadingSessionList"),
1319
+ showSessionListSkeleton: toRef(props, "showSessionListSkeleton"),
1278
1320
  showEmptyState: toRef(props, "showEmptyState"),
1321
+ showError: toRef(props, "showError"),
1279
1322
  emptyStateText: toRef(props, "emptyStateText"),
1280
1323
  emptyStateActionText: toRef(props, "emptyStateActionText"),
1281
1324
  showClearAll: toRef(props, "showClearAll"),
@@ -1298,7 +1341,8 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1298
1341
  handleToggleSelectMode,
1299
1342
  handleClickSelectedNode,
1300
1343
  handleRemoveSelectedNode: (payload) => handleRemoveSelectedNode(payload.item, payload.index, payload.source),
1301
- handleClearSelectedNodes
1344
+ handleClearSelectedNodes,
1345
+ handleFrameLoaded
1302
1346
  });
1303
1347
  const __returned__ = {
1304
1348
  props,
@@ -1324,6 +1368,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1324
1368
  showConfirmDialog,
1325
1369
  handleDialogConfirm,
1326
1370
  handleDialogCancel,
1371
+ handleFrameLoaded,
1327
1372
  localSessionListCollapsed,
1328
1373
  buttonActive,
1329
1374
  containerClasses,
@@ -1429,10 +1474,15 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
1429
1474
  fn: withCtx(() => [renderSlot(_ctx.$slots, "loading")]),
1430
1475
  key: "1"
1431
1476
  } : void 0,
1477
+ $setup.slots.error ? {
1478
+ name: "error",
1479
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "error")]),
1480
+ key: "2"
1481
+ } : void 0,
1432
1482
  $setup.slots.content ? {
1433
1483
  name: "content",
1434
1484
  fn: withCtx(() => [renderSlot(_ctx.$slots, "content")]),
1435
- key: "2"
1485
+ key: "3"
1436
1486
  } : void 0
1437
1487
  ]), 1024),
1438
1488
  createVNode($setup["SelectedNodes"])
@@ -1465,7 +1515,7 @@ __vue_sfc__.render = __vue_render__;
1465
1515
  var open_code_widget_default = __vue_sfc__;
1466
1516
  //#endregion
1467
1517
  //#region es/index.js
1468
- var version = "1.0.12";
1518
+ var version = "1.0.14";
1469
1519
  function install(app, options) {
1470
1520
  [open_code_widget_default].forEach((item) => {
1471
1521
  if (item.install) app.use(item, options);
@@ -1,7 +1,7 @@
1
1
  .opencode-widget{--oc-bg-main: #ffffff;--oc-bg-secondary: #f8f9fa;--oc-bg-tertiary: #f3f4f6;--oc-overlay-bg: rgba(255, 255, 255, .9);--oc-bg-inverse: #1e1e1e;--oc-text-primary: #282828;--oc-text-secondary: #4b5563;--oc-text-tertiary: #6b7280;--oc-text-placeholder: #9ca3af;--oc-text-inverse: #ffffff;--oc-border-primary: #e5e7eb;--oc-border-secondary: #d1d5db;--oc-primary: #3b82f6;--oc-primary-hover: #2563eb;--oc-primary-bg: rgba(59, 130, 246, .1);--oc-danger: #ef4444;--oc-danger-hover: #dc2626;--oc-danger-active: #b91c1c;--oc-success: #10b981;--oc-overlay: rgba(0, 0, 0, .5);--oc-tooltip-bg: #1e1e1e;--oc-dialog-overlay: rgba(0, 0, 0, .5);--oc-skeleton-bg: #e5e7eb;--oc-skeleton-gradient: linear-gradient(90deg, #e5e7eb 25%, #f3f4f6 50%, #e5e7eb 75%);--oc-shadow-sm: 0 2px 4px rgba(0, 0, 0, .1);--oc-shadow-md: 0 4px 12px rgba(0, 0, 0, .15);--oc-shadow-lg: 0 8px 32px rgba(0, 0, 0, .12);--oc-shadow-xl: 0 20px 60px rgba(0, 0, 0, .3);--oc-shadow-primary: 0 2px 4px rgba(59, 130, 246, .2);--oc-shadow-primary-hover: 0 4px 6px rgba(59, 130, 246, .3);--oc-shadow-danger: 0 4px 12px rgba(239, 68, 68, .3);--oc-trigger-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--oc-trigger-bg-hover: linear-gradient(135deg, #764ba2 0%, #667eea 100%);--oc-trigger-bg-active: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);--oc-trigger-shadow: 0 4px 15px rgba(102, 126, 234, .4);--oc-trigger-shadow-hover: 0 6px 20px rgba(102, 126, 234, .6);--oc-trigger-shadow-active: 0 6px 20px rgba(240, 147, 251, .4);position:fixed;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.opencode-widget.opencode-theme-dark{--oc-bg-main: #1a1a1a;--oc-bg-secondary: #1e1e1e;--oc-bg-tertiary: #282828;--oc-overlay-bg: rgba(26, 26, 26, .9);--oc-bg-inverse: #ffffff;--oc-text-primary: #f3f4f6;--oc-text-secondary: #d1d5db;--oc-text-tertiary: #9ca3af;--oc-text-placeholder: #6b7280;--oc-text-inverse: #282828;--oc-border-primary: #282828;--oc-border-secondary: #4b5563;--oc-primary: #3b82f6;--oc-primary-hover: #2563eb;--oc-primary-bg: rgba(59, 130, 246, .15);--oc-danger: #ef4444;--oc-danger-hover: #dc2626;--oc-danger-active: #b91c1c;--oc-success: #10b981;--oc-overlay: rgba(26, 26, 26, .9);--oc-tooltip-bg: #282828;--oc-dialog-overlay: rgba(0, 0, 0, .7);--oc-skeleton-bg: #151515;--oc-skeleton-gradient: linear-gradient(90deg, #282828 25%, #4b5563 50%, #282828 75%);--oc-shadow-sm: 0 2px 4px rgba(0, 0, 0, .3);--oc-shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--oc-shadow-lg: 0 8px 32px rgba(0, 0, 0, .4);--oc-shadow-xl: 0 20px 60px rgba(0, 0, 0, .6);--oc-shadow-primary: 0 2px 4px rgba(59, 130, 246, .3);--oc-shadow-primary-hover: 0 4px 6px rgba(59, 130, 246, .4);--oc-shadow-danger: 0 4px 12px rgba(239, 68, 68, .4);--oc-trigger-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--oc-trigger-bg-hover: linear-gradient(135deg, #764ba2 0%, #667eea 100%);--oc-trigger-bg-active: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);--oc-trigger-shadow: 0 4px 15px rgba(102, 126, 234, .5);--oc-trigger-shadow-hover: 0 6px 20px rgba(102, 126, 234, .7);--oc-trigger-shadow-active: 0 6px 20px rgba(240, 147, 251, .5)}.opencode-widget.bottom-right{bottom:20px;right:20px}.opencode-widget.bottom-left{bottom:20px;left:20px}.opencode-widget.top-right{top:20px;right:20px}.opencode-widget.top-left{top:20px;left:20px}.opencode-chat{position:absolute;width:700px;height:86vh;background:var(--oc-bg-main);border-radius:16px;box-shadow:var(--oc-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translateY(20px) scale(.95);transition:all .3s ease;display:flex;flex-direction:column}.opencode-chat-content{display:flex;flex:1;overflow:hidden}.opencode-widget.bottom-right .opencode-chat{bottom:56px;right:0}.opencode-widget.bottom-left .opencode-chat{bottom:56px;left:0}.opencode-widget.top-right .opencode-chat{top:56px;right:0}.opencode-widget.top-left .opencode-chat{top:56px;left:0}.opencode-widget.bottom-right .opencode-selected-bubbles{bottom:56px;right:0}.opencode-widget.bottom-left .opencode-selected-bubbles{bottom:56px;left:0}.opencode-widget.top-right .opencode-selected-bubbles{top:56px;bottom:auto;right:0}.opencode-widget.top-left .opencode-selected-bubbles{top:56px;bottom:auto;left:0}.opencode-chat.open{opacity:1;visibility:visible;transform:translateY(0) scale(1)}.opencode-notification{position:absolute;top:20px;left:50%;transform:translate(-50%);padding:12px 24px;background:linear-gradient(135deg,#3b82f6,#2563eb);color:#fff;border-radius:10px;font-size:14px;font-weight:500;box-shadow:0 4px 16px rgba(59,130,246,.4),0 0 0 2px rgba(59,130,246,.2);animation:slideDown .3s ease;z-index:10000000;display:flex;align-items:center;gap:10px}.opencode-notification:before{content:"\1f4a1";font-size:16px}.opencode-dialog-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:var(--oc-dialog-overlay);display:flex;align-items:center;justify-content:center;z-index:9999999;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.opencode-dialog{background:var(--oc-bg-main);border-radius:12px;padding:24px;min-width:320px;max-width:400px;box-shadow:var(--oc-shadow-xl);animation:scaleIn .2s ease}@keyframes scaleIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}.opencode-dialog-content{margin-bottom:20px}.opencode-dialog-message{font-size:15px;color:var(--oc-text-primary);line-height:1.5}.opencode-dialog-actions{display:flex;gap:12px;justify-content:flex-end}.opencode-dialog-btn{padding:10px 20px;border-radius:8px;border:none;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.opencode-dialog-btn.cancel{background:var(--oc-bg-tertiary);color:var(--oc-text-primary)}.opencode-dialog-btn.cancel:hover{background:var(--oc-text-primary);color:var(--oc-bg-main)}.opencode-dialog-btn.confirm{background:var(--oc-danger);color:#fff}.opencode-dialog-btn.confirm:hover{background:var(--oc-danger-hover)}@keyframes slideDown{0%{transform:translate(-50%) translateY(-100%);opacity:0}to{transform:translate(-50%) translateY(0);opacity:1}}.opencode-element-highlight{position:fixed;pointer-events:none;z-index:999998;display:none;transition:all .1s ease;border-radius:4px}#vue-inspector-container{display:none!important}.opencode-element-tooltip{position:fixed;background:var(--oc-tooltip-bg);color:#fff;padding:8px 12px;border-radius:6px;font-size:12px;z-index:9999998;display:none;box-shadow:var(--oc-shadow-md);max-width:300px;pointer-events:none}.opencode-tooltip-tag{font-weight:500;margin-bottom:4px;word-break:break-all}.opencode-tooltip-file{font-size:11px;color:var(--oc-text-placeholder);word-break:break-all}.opencode-element-highlight-temp{position:absolute;pointer-events:none;z-index:999998;border-radius:4px;animation:highlight-pulse 2s ease-out forwards}@keyframes highlight-pulse{0%{opacity:1;transform:scale(1)}50%{opacity:.8;transform:scale(1.02)}to{opacity:0;transform:scale(1)}}@media(max-width:768px){.opencode-chat{width:calc(100vw - 40px);height:calc(100vh - 100px)}}
2
- .opencode-iframe-container{flex:1;position:relative;overflow:hidden;display:flex;flex-direction:column;margin-top:-42px}.opencode-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-overlay-bg);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:10;transition:opacity .3s ease}.opencode-loading-overlay.visible{display:flex}.opencode-loading-spinner{width:40px;height:40px;border:3px solid var(--oc-border-primary);border-top-color:var(--oc-primary);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.opencode-loading-text{margin-top:12px;font-size:14px;color:var(--oc-text-placeholder)}.opencode-empty-state-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-bg-secondary);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:5;transition:opacity .3s ease;margin-top:42px}.opencode-empty-state-overlay.visible{display:flex}.opencode-empty-state-icon{color:var(--oc-text-placeholder);margin-bottom:16px}.opencode-empty-state-text{color:var(--oc-text-primary);font-size:16px;font-weight:500;margin-bottom:24px}.opencode-empty-state-btn{padding:10px 24px;border-radius:8px;border:none;background:var(--oc-primary);color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;box-shadow:var(--oc-shadow-primary)}.opencode-empty-state-btn:hover{background:var(--oc-primary-hover);transform:translateY(-1px);box-shadow:var(--oc-shadow-primary-hover)}.opencode-empty-state-btn:active{transform:translateY(0)}.opencode-iframe{width:100%;height:100%;border:none}
2
+ .opencode-iframe-container{flex:1;position:relative;overflow:hidden;display:flex;flex-direction:column;margin-top:-42px}.opencode-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-overlay-bg);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:10;transition:opacity .3s ease}.opencode-loading-overlay.visible{display:flex}.opencode-loading-spinner{width:40px;height:40px;border:3px solid var(--oc-border-primary);border-top-color:var(--oc-primary);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.opencode-loading-text{margin-top:12px;font-size:14px;color:var(--oc-text-placeholder)}.opencode-error-overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:15;margin-top:42px;display:none}.opencode-error-overlay.visible{display:flex}.opencode-empty-state-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-bg-secondary);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:5;transition:opacity .3s ease;margin-top:42px}.opencode-empty-state-overlay.visible{display:flex}.opencode-empty-state-icon{color:var(--oc-text-placeholder);margin-bottom:16px}.opencode-empty-state-text{color:var(--oc-text-primary);font-size:16px;font-weight:500;margin-bottom:24px}.opencode-empty-state-btn{padding:10px 24px;border-radius:8px;border:none;background:var(--oc-primary);color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;box-shadow:var(--oc-shadow-primary)}.opencode-empty-state-btn:hover{background:var(--oc-primary-hover);transform:translateY(-1px);box-shadow:var(--oc-shadow-primary-hover)}.opencode-empty-state-btn:active{transform:translateY(0)}.opencode-iframe{width:100%;height:100%;border:none}
3
3
  .opencode-chat-header{position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0 12px;height:40px;background:var(--oc-bg-secondary);border-bottom:1px solid var(--oc-border-primary);z-index:5}.opencode-chat-header-left{display:flex;align-items:center;gap:4px}.opencode-chat-header-title{font-size:14px;font-weight:600;color:var(--oc-text-primary);position:absolute;left:50%;transform:translate(-50%)}.opencode-chat-header-actions{display:flex;gap:4px}.opencode-header-btn{width:28px;height:28px;border-radius:6px;border:none;background:transparent;color:var(--oc-text-placeholder);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.opencode-header-btn:hover{background:var(--oc-bg-tertiary);color:var(--oc-text-primary)}.opencode-header-btn.close:hover{background:var(--oc-danger);color:#fff}.opencode-header-btn.select-btn.active,.opencode-header-btn.session-toggle.active{background:var(--oc-primary);color:#fff}
4
- .opencode-select-mode-hint{position:fixed;top:20px;left:50%;transform:translate(-50%);padding:14px 20px;background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;border-radius:12px;font-size:15px;font-weight:500;box-shadow:0 6px 20px rgba(239,68,68,.5),0 0 0 3px rgba(239,68,68,.3);z-index:9999999;display:none;align-items:center;gap:12px;border:2px solid rgba(255,255,255,.3)}.opencode-select-mode-hint.visible{display:flex;animation:slideDown .3s ease,pulseHint 2s ease-in-out infinite}.opencode-hint-shortcut{padding:4px 10px;background:rgba(255,255,255,.25);border-radius:6px;font-size:13px;font-weight:600;border:1px solid rgba(255,255,255,.4)}@keyframes pulseHint{0%,to{box-shadow:0 6px 20px rgba(239,68,68,.5),0 0 0 3px rgba(239,68,68,.3)}50%{box-shadow:0 6px 20px rgba(239,68,68,.6),0 0 0 6px rgba(239,68,68,.4)}}
4
+ .opencode-select-mode-hint{position:fixed;top:20px;left:50%;transform:translate(-50%);padding:10px;background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;border-radius:12px;font-size:14px;font-weight:500;box-shadow:0 6px 20px rgba(239,68,68,.5),0 0 0 3px rgba(239,68,68,.3);z-index:9999999;display:none;align-items:center;gap:12px;border:1px solid rgba(255,255,255,.3)}.opencode-select-mode-hint.visible{display:flex;animation:slideDown .3s ease,pulseHint 2s ease-in-out infinite}.opencode-hint-shortcut{padding:4px 10px;background:rgba(255,255,255,.25);border-radius:6px;font-size:13px;font-weight:600;border:1px solid rgba(255,255,255,.4)}@keyframes pulseHint{0%,to{box-shadow:0 6px 20px rgba(239,68,68,.5),0 0 0 3px rgba(239,68,68,.3)}50%{box-shadow:0 6px 20px rgba(239,68,68,.6),0 0 0 6px rgba(239,68,68,.4)}}
5
5
  .opencode-selected-bubbles{position:absolute;display:none;flex-direction:column;gap:6px;max-width:220px;max-height:300px;overflow-y:auto}.opencode-selected-bubbles.visible{display:flex}.opencode-selected-bubble{display:flex;flex-direction:column;gap:2px;padding:8px 24px 8px 10px;background:var(--oc-bg-main);border:1px solid var(--oc-border-primary);border-radius:8px;font-size:12px;box-shadow:var(--oc-shadow-sm);position:relative;cursor:pointer;transition:all .2s}.opencode-selected-bubble:hover{border-color:var(--oc-primary);box-shadow:var(--oc-shadow-primary)}.opencode-bubble-text{color:var(--oc-text-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-bubble-file{color:var(--oc-text-placeholder);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-bubble-remove{position:absolute;top:8px;right:6px;width:16px;height:16px;border-radius:50%;border:none;background:transparent;color:var(--oc-text-placeholder);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;transition:all .2s}.opencode-bubble-remove:hover{background:var(--oc-danger);color:#fff}.opencode-bubble-empty{padding:8px 12px;background:var(--oc-bg-main);border:1px dashed var(--oc-border-secondary);border-radius:8px;color:var(--oc-text-placeholder);font-size:12px;text-align:center}
6
6
  .opencode-right-toolbar{width:140px;background:var(--oc-bg-secondary);border-left:1px solid var(--oc-border-primary);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease;overflow:hidden}.opencode-right-toolbar.collapsed{width:0;overflow:hidden}.opencode-right-toolbar.collapsed .opencode-selected-nodes-header,.opencode-right-toolbar.collapsed .opencode-selected-nodes,.opencode-right-toolbar.collapsed .opencode-clear-all-btn{display:none}.opencode-selected-nodes-header{padding:12px 8px 8px;border-bottom:1px solid var(--oc-border-primary)}.opencode-selected-nodes-title{font-size:14px;font-weight:600;color:var(--oc-text-primary);margin-bottom:4px}.opencode-selected-nodes-desc{font-size:11px;color:var(--oc-text-placeholder);line-height:1.4}.opencode-selected-nodes{flex:1;display:flex;flex-direction:column;padding:8px;gap:6px;overflow-y:auto;overflow-x:hidden}.opencode-selected-nodes:empty:before{content:"\6682\65e0\9009\4e2d\5143\7d20";color:var(--oc-text-placeholder);font-size:12px;text-align:center;padding:20px 10px}.opencode-selected-node{display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--oc-bg-main);border:1px solid var(--oc-border-primary);border-radius:6px;font-size:12px;transition:all .2s}.opencode-selected-node:hover{border-color:var(--oc-primary);box-shadow:var(--oc-shadow-primary)}.opencode-node-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.opencode-node-text{color:var(--oc-text-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-node-file{color:var(--oc-text-placeholder);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-node-remove{width:18px;height:18px;border-radius:4px;border:none;background:transparent;color:var(--oc-text-placeholder);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;transition:all .2s;flex-shrink:0}.opencode-node-remove:hover{background:var(--oc-danger);color:#fff}.opencode-clear-all-btn{width:calc(100% - 16px);margin:8px;padding:8px 12px;border-radius:6px;border:none;background:var(--oc-danger);color:#fff;font-size:12px;font-weight:500;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:4px;transition:all .2s}.opencode-clear-all-btn:hover{background:var(--oc-danger-hover);transform:scale(1.02)}
7
7
  .opencode-session-list{width:240px;background:var(--oc-bg-secondary);border-right:1px solid var(--oc-border-primary);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease}.opencode-session-list.collapsed{width:0;overflow:hidden}.opencode-session-list.collapsed .opencode-session-list-header,.opencode-session-list.collapsed .opencode-session-list-content{display:none}.opencode-session-list-header{padding:16px;border-bottom:1px solid var(--oc-border-primary);display:flex;justify-content:space-between;align-items:center;font-weight:600;font-size:14px;color:var(--oc-text-primary)}.opencode-new-session-btn{width:28px;height:28px;border-radius:6px;border:none;background:var(--oc-primary);color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.opencode-new-session-btn:hover{background:var(--oc-primary-hover);transform:scale(1.05)}.opencode-session-list-content{flex:1;overflow-y:auto;padding:8px;position:relative}.opencode-session-list-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-overlay-bg);display:flex;align-items:center;justify-content:center;z-index:10;border-radius:8px}.opencode-loading-spinner.small{width:24px;height:24px;border-width:2px}.opencode-session-item{padding:12px;border-radius:8px;cursor:pointer;transition:transform .2s;margin-bottom:4px;color:var(--oc-text-primary)}.opencode-session-item:hover{background:var(--oc-bg-tertiary)}.opencode-session-item.active{background:var(--oc-primary);color:#fff;transition:none}.opencode-session-title{font-size:14px;font-weight:500;margin-bottom:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-session-meta{font-size:12px;opacity:.6}.opencode-session-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.opencode-session-delete-btn{width:20px;height:20px;border-radius:4px;border:none;background:transparent;color:var(--oc-text-placeholder);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;opacity:0;flex-shrink:0}.opencode-session-item:hover .opencode-session-delete-btn{opacity:1}.opencode-session-delete-btn:hover{background:var(--oc-danger);color:#fff}.opencode-session-item.active .opencode-session-delete-btn{color:rgba(255,255,255,.7)}.opencode-session-item.active .opencode-session-delete-btn:hover{background:rgba(255,255,255,.2);color:#fff}.opencode-session-header-skeleton{padding:16px;border-bottom:1px solid var(--oc-border-primary);display:none;justify-content:space-between;align-items:center}.opencode-session-header-skeleton.visible{display:flex}.opencode-skeleton-header-title{height:18px;width:80px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.opencode-skeleton-header-btn{width:28px;height:28px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:6px}.opencode-session-skeleton{flex:1;overflow-y:auto;padding:8px;display:none}.opencode-session-skeleton.visible{display:block}.opencode-skeleton-item{padding:12px;border-radius:8px;margin-bottom:4px;background:var(--oc-skeleton-bg)}.opencode-skeleton-title{height:16px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px;margin-bottom:8px;width:70%}.opencode-skeleton-meta{height:12px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px;width:50%}.opencode-session-empty{padding:32px 16px;text-align:center;color:var(--oc-text-placeholder);font-size:13px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import OpenCodeWidget from './open-code-widget';
2
2
  import type { App } from 'vue';
3
- declare const version = "1.0.12";
3
+ declare const version = "1.0.14";
4
4
  declare function install(app: App<any>, options?: any): void;
5
5
  export { install, version, OpenCodeWidget };
6
6
  export default install;
package/lib/index.js CHANGED
@@ -34,7 +34,7 @@ __export(lib_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(lib_exports);
36
36
  var import_open_code_widget = __toESM(require("./open-code-widget"));
37
- const version = "1.0.12";
37
+ const version = "1.0.14";
38
38
  function install(app, options) {
39
39
  const components = [
40
40
  import_open_code_widget.default