@vite-plugin-opencode-assistant/components 1.0.26 → 1.0.28

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 (41) 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 +118 -79
  4. package/es/open-code-widget/composables/use-persist-state.d.ts +24 -0
  5. package/es/open-code-widget/composables/use-persist-state.js +59 -0
  6. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -1
  7. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +2 -2
  8. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +37 -21
  9. package/es/open-code-widget/src/components/SessionList-sfc.css +1 -1
  10. package/es/open-code-widget/src/components/SessionList.vue.js +27 -16
  11. package/es/open-code-widget/src/components/Trigger-sfc.css +1 -1
  12. package/es/open-code-widget/src/components/Trigger.vue.d.ts +0 -2
  13. package/es/open-code-widget/src/components/Trigger.vue.js +10 -27
  14. package/es/open-code-widget/src/context.d.ts +5 -1
  15. package/es/open-code-widget/src/index-sfc.css +1 -1
  16. package/es/open-code-widget/src/index.vue.d.ts +11 -11
  17. package/es/open-code-widget/src/index.vue.js +113 -30
  18. package/es/open-code-widget/src/types.d.ts +1 -1
  19. package/lib/@vite-plugin-opencode-assistant/components.cjs.js +340 -153
  20. package/lib/@vite-plugin-opencode-assistant/components.es.js +341 -154
  21. package/lib/components.css +4 -4
  22. package/lib/index.d.ts +1 -1
  23. package/lib/index.js +1 -1
  24. package/lib/open-code-widget/composables/use-inspector.js +118 -79
  25. package/lib/open-code-widget/composables/use-persist-state.d.ts +24 -0
  26. package/lib/open-code-widget/composables/use-persist-state.js +78 -0
  27. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -1
  28. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +2 -2
  29. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +37 -21
  30. package/lib/open-code-widget/src/components/SessionList-sfc.css +1 -1
  31. package/lib/open-code-widget/src/components/SessionList.vue.js +26 -15
  32. package/lib/open-code-widget/src/components/Trigger-sfc.css +1 -1
  33. package/lib/open-code-widget/src/components/Trigger.vue.d.ts +0 -2
  34. package/lib/open-code-widget/src/components/Trigger.vue.js +10 -27
  35. package/lib/open-code-widget/src/context.d.ts +5 -1
  36. package/lib/open-code-widget/src/index-sfc.css +1 -1
  37. package/lib/open-code-widget/src/index.vue.d.ts +11 -11
  38. package/lib/open-code-widget/src/index.vue.js +112 -29
  39. package/lib/open-code-widget/src/types.d.ts +1 -1
  40. package/lib/web-types.json +1 -1
  41. package/package.json +2 -2
@@ -37,7 +37,8 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
37
37
  handleCreateSession,
38
38
  handleSelectSession,
39
39
  handleDeleteSession,
40
- sessionKey
40
+ sessionKey,
41
+ sessionStates
41
42
  } = (0, import_context.useOpenCodeWidgetContext)();
42
43
  const isAnimating = (0, import_vue2.ref)(false);
43
44
  let animTimer = null;
@@ -53,11 +54,16 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
53
54
  if (showSessionListSkeleton.value) return true;
54
55
  return false;
55
56
  });
56
- const __returned__ = { collapsed, sessions, loadingSessionList, showSessionListSkeleton, handleCreateSession, handleSelectSession, handleDeleteSession, sessionKey, isAnimating, get animTimer() {
57
+ function isSessionThinking(sessionId) {
58
+ var _a, _b;
59
+ if (!(sessionStates == null ? void 0 : sessionStates.value) || !sessionId) return false;
60
+ return (_b = (_a = sessionStates.value[sessionId]) == null ? void 0 : _a.thinking) != null ? _b : false;
61
+ }
62
+ const __returned__ = { collapsed, sessions, loadingSessionList, showSessionListSkeleton, handleCreateSession, handleSelectSession, handleDeleteSession, sessionKey, sessionStates, isAnimating, get animTimer() {
57
63
  return animTimer;
58
64
  }, set animTimer(v) {
59
65
  animTimer = v;
60
- }, showSkeleton };
66
+ }, showSkeleton, isSessionThinking };
61
67
  Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
62
68
  return __returned__;
63
69
  }
@@ -82,8 +88,12 @@ const _hoisted_4 = {
82
88
  const _hoisted_5 = ["aria-selected", "onClick"];
83
89
  const _hoisted_6 = { class: "opencode-session-header" };
84
90
  const _hoisted_7 = { class: "opencode-session-title" };
85
- const _hoisted_8 = ["aria-label", "onClick"];
86
- const _hoisted_9 = { class: "opencode-session-meta" };
91
+ const _hoisted_8 = {
92
+ key: 0,
93
+ class: "opencode-thinking-loading"
94
+ };
95
+ const _hoisted_9 = ["aria-label", "onClick"];
96
+ const _hoisted_10 = { class: "opencode-session-meta" };
87
97
  function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
88
98
  return (0, import_vue3.openBlock)(), (0, import_vue3.createElementBlock)(
89
99
  "div",
@@ -176,29 +186,30 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
176
186
  (0, import_vue3.renderList)($setup.sessions, (item) => {
177
187
  return (0, import_vue3.openBlock)(), (0, import_vue3.createElementBlock)("div", {
178
188
  key: item[$setup.sessionKey],
179
- class: (0, import_vue3.normalizeClass)(["opencode-session-item", { active: item.active }]),
189
+ class: (0, import_vue3.normalizeClass)(["opencode-session-item", { active: item.active, thinking: $setup.isSessionThinking(item.id) }]),
180
190
  role: "option",
181
191
  "aria-selected": item.active,
182
192
  onClick: ($event) => $setup.handleSelectSession(item)
183
193
  }, [
184
194
  (0, import_vue3.createElementVNode)("div", _hoisted_6, [
185
- (0, import_vue3.createElementVNode)(
186
- "div",
187
- _hoisted_7,
188
- (0, import_vue3.toDisplayString)(item.title),
189
- 1
190
- /* TEXT */
191
- ),
195
+ (0, import_vue3.createElementVNode)("div", _hoisted_7, [
196
+ $setup.isSessionThinking(item.id) ? ((0, import_vue3.openBlock)(), (0, import_vue3.createElementBlock)("span", _hoisted_8)) : (0, import_vue3.createCommentVNode)("v-if", true),
197
+ (0, import_vue3.createTextVNode)(
198
+ " " + (0, import_vue3.toDisplayString)(item.title),
199
+ 1
200
+ /* TEXT */
201
+ )
202
+ ]),
192
203
  (0, import_vue3.createElementVNode)("button", {
193
204
  class: "opencode-session-delete-btn",
194
205
  type: "button",
195
206
  "aria-label": `\u5220\u9664\u4F1A\u8BDD: ${item.title}`,
196
207
  onClick: (0, import_vue3.withModifiers)(($event) => $setup.handleDeleteSession(item), ["stop"])
197
- }, " \xD7 ", 8, _hoisted_8)
208
+ }, " \xD7 ", 8, _hoisted_9)
198
209
  ]),
199
210
  (0, import_vue3.createElementVNode)(
200
211
  "div",
201
- _hoisted_9,
212
+ _hoisted_10,
202
213
  (0, import_vue3.toDisplayString)(item.meta),
203
214
  1
204
215
  /* TEXT */
@@ -1 +1 @@
1
- .opencode-button{width:42px;height:42px;border-radius:50%;background:#fff;border:none;cursor:pointer;box-shadow:0 4px 12px rgba(102,126,234,.4);transition:all .3s ease;display:flex;align-items:center;justify-content:center;padding:0;position:relative}.opencode-button svg{transform:rotate(180deg) scale(1.1);transition:transform .3s ease;width:100%;height:100%;display:block}.opencode-button:hover svg{transform:rotate(180deg) scale(1.1)}.opencode-button:hover{transform:scale(1.1);box-shadow:0 6px 16px rgba(102,126,234,.5)}.opencode-button.thinking{background:linear-gradient(135deg,#667eea,#764ba2);animation:thinking-glow 1.5s ease-in-out infinite,thinking-pulse 1.5s ease-in-out infinite;box-shadow:0 0 20px rgba(102,126,234,.6),0 0 40px rgba(118,75,162,.4),0 0 60px rgba(102,126,234,.2)}.opencode-button.thinking svg path{fill:#fff}.opencode-button.thinking:before{content:"";position:absolute;top:-2px;right:-2px;bottom:-2px;left:-2px;border-radius:50%;background:linear-gradient(135deg,#8b9cf5,#9d6bc7);z-index:-1}.opencode-button.thinking:after{content:"";position:absolute;top:-3px;right:-3px;bottom:-3px;left:-3px;border-radius:50%;background:conic-gradient(from 180deg,transparent,rgba(102,126,234,.3),transparent,rgba(118,75,162,.3),transparent);z-index:-2;animation:thinking-rotate 2s linear infinite reverse;filter:blur(8px)}@keyframes thinking-glow{0%,to{box-shadow:0 0 20px rgba(102,126,234,.6),0 0 40px rgba(118,75,162,.4),0 0 60px rgba(102,126,234,.2)}50%{box-shadow:0 0 30px rgba(102,126,234,.8),0 0 60px rgba(118,75,162,.6),0 0 90px rgba(102,126,234,.3)}}@keyframes thinking-rotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes thinking-pulse{0%,to{transform:scale(1)}50%{transform:scale(.95)}}.opencode-button.opencode-theme-dark{background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 4px 12px rgba(102,126,234,.3)}.opencode-button.opencode-theme-dark:before{content:"";position:absolute;top:-2px;right:-2px;bottom:-2px;left:-2px;border-radius:50%;background:linear-gradient(135deg,#8b9cf5,#9d6bc7);z-index:-1}.opencode-button.opencode-theme-dark:hover{box-shadow:0 6px 16px rgba(102,126,234,.4)}.opencode-button.opencode-theme-dark svg path{fill:#fff}
1
+ .opencode-button{width:42px;height:42px;border-radius:50%;background:#fff;border:none;cursor:pointer;box-shadow:0 4px 12px rgba(102,126,234,.4);transition:all .3s ease;display:flex;align-items:center;justify-content:center;padding:0;position:relative}.opencode-button svg{transform:rotate(180deg) scale(1.1);transition:transform .3s ease;width:100%;height:100%;display:block}.opencode-button:hover svg{transform:rotate(180deg) scale(1.1)}.opencode-button:hover{transform:scale(1.1);box-shadow:0 6px 16px rgba(102,126,234,.5)}.opencode-button.thinking{background:linear-gradient(135deg,#667eea,#764ba2);animation:thinking-glow 1.5s ease-in-out infinite,thinking-pulse 1.5s ease-in-out infinite;box-shadow:0 0 20px rgba(102,126,234,.6),0 0 40px rgba(118,75,162,.4),0 0 60px rgba(102,126,234,.2)}.opencode-button.thinking svg path{fill:#fff}.opencode-button.thinking:before{content:"";position:absolute;top:-2px;right:-2px;bottom:-2px;left:-2px;border-radius:50%;background:linear-gradient(135deg,#8b9cf5,#9d6bc7);z-index:-1}.opencode-button.thinking:after{content:"";position:absolute;top:-3px;right:-3px;bottom:-3px;left:-3px;border-radius:50%;background:conic-gradient(from 180deg,transparent,rgba(102,126,234,.3),transparent,rgba(118,75,162,.3),transparent);z-index:-2;animation:thinking-rotate 2s linear infinite reverse;filter:blur(8px)}@keyframes thinking-glow{0%,to{box-shadow:0 0 20px rgba(102,126,234,.6),0 0 40px rgba(118,75,162,.4),0 0 60px rgba(102,126,234,.2)}50%{box-shadow:0 0 30px rgba(102,126,234,.8),0 0 60px rgba(118,75,162,.6),0 0 90px rgba(102,126,234,.3)}}@keyframes thinking-rotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes thinking-pulse{0%,to{transform:scale(1)}50%{transform:scale(.85)}}.opencode-button.opencode-theme-dark{background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 4px 12px rgba(102,126,234,.3)}.opencode-button.opencode-theme-dark:before{content:"";position:absolute;top:-2px;right:-2px;bottom:-2px;left:-2px;border-radius:50%;background:linear-gradient(135deg,#8b9cf5,#9d6bc7);z-index:-1}.opencode-button.opencode-theme-dark:hover{box-shadow:0 6px 16px rgba(102,126,234,.4)}.opencode-button.opencode-theme-dark svg path{fill:#fff}
@@ -12,11 +12,9 @@ declare const __VLS_component: import("vue").DefineComponent<{}, {
12
12
  y: number;
13
13
  } | undefined>;
14
14
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
15
- "offset-change": (offset: FloatingBubbleOffset | undefined) => any;
16
15
  "drag-start": () => any;
17
16
  "drag-end": () => any;
18
17
  }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
19
- "onOffset-change"?: ((offset: FloatingBubbleOffset | undefined) => any) | undefined;
20
18
  "onDrag-start"?: (() => any) | undefined;
21
19
  "onDrag-end"?: (() => any) | undefined;
22
20
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -36,10 +36,9 @@ var import_vue2 = require("vue");
36
36
  var import_context = require("../context");
37
37
  var import_FloatingBubble_vue = __toESM(require("./FloatingBubble/FloatingBubble.vue.js"));
38
38
  var import_vue3 = require("vue");
39
- const STORAGE_KEY = "opencode-bubble-offset";
40
39
  const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
41
40
  __name: "Trigger",
42
- emits: ["offset-change", "drag-start", "drag-end"],
41
+ emits: ["drag-start", "drag-end"],
43
42
  setup(__props, { expose: __expose, emit: __emit }) {
44
43
  const {
45
44
  buttonActive: active,
@@ -47,39 +46,23 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
47
46
  hotkeyLabel,
48
47
  thinking,
49
48
  resolvedTheme,
50
- handleToggle
49
+ handleToggle,
50
+ bubbleOffset,
51
+ handleBubbleOffsetChange
51
52
  } = (0, import_context.useOpenCodeWidgetContext)();
52
- const loadOffset = () => {
53
- try {
54
- const saved = localStorage.getItem(STORAGE_KEY);
55
- if (saved) {
56
- const parsed = JSON.parse(saved);
57
- if (parsed && (parsed.x !== 0 || parsed.y !== 0)) {
58
- return parsed;
59
- }
60
- }
61
- } catch (e) {
62
- }
63
- return void 0;
64
- };
65
- const offset = (0, import_vue2.ref)(loadOffset());
53
+ const offset = (0, import_vue2.ref)(bubbleOffset.value);
66
54
  const emit = __emit;
67
- const saveOffset = (value) => {
68
- try {
69
- localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
70
- } catch (e) {
71
- }
72
- };
73
55
  const handleOffsetChange = (value) => {
74
56
  offset.value = value;
75
- saveOffset(value);
76
- emit("offset-change", value);
57
+ handleBubbleOffsetChange(value);
77
58
  };
78
- (0, import_vue2.watch)(offset, handleOffsetChange, { immediate: true });
59
+ (0, import_vue2.watch)(bubbleOffset, (newOffset) => {
60
+ offset.value = newOffset;
61
+ });
79
62
  __expose({
80
63
  offset
81
64
  });
82
- const __returned__ = { active, open, hotkeyLabel, thinking, resolvedTheme, handleToggle, STORAGE_KEY, loadOffset, offset, emit, saveOffset, handleOffsetChange, FloatingBubble: import_FloatingBubble_vue.default };
65
+ const __returned__ = { active, open, hotkeyLabel, thinking, resolvedTheme, handleToggle, bubbleOffset, handleBubbleOffsetChange, offset, emit, handleOffsetChange, FloatingBubble: import_FloatingBubble_vue.default };
83
66
  Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
84
67
  return __returned__;
85
68
  }
@@ -1,5 +1,6 @@
1
1
  import { type Ref } from "vue";
2
- import type { OpenCodeWidgetSessionItem, OpenCodeSelectedElementItem, OpenCodeRemoveSelectedPayload } from "./types";
2
+ import type { OpenCodeWidgetSessionItem, OpenCodeSelectedElementItem, OpenCodeRemoveSelectedPayload, OpencodeSessionThinkingState } from "./types";
3
+ import type { FloatingBubbleOffset } from "./components/FloatingBubble/types";
3
4
  export interface OpenCodeWidgetContext {
4
5
  theme: Ref<string>;
5
6
  resolvedTheme: Ref<"light" | "dark">;
@@ -22,6 +23,8 @@ export interface OpenCodeWidgetContext {
22
23
  thinking: Ref<boolean>;
23
24
  minimized: Ref<boolean>;
24
25
  promptDockVisible: Ref<boolean>;
26
+ bubbleOffset: Ref<FloatingBubbleOffset | undefined>;
27
+ sessionStates: Ref<Record<string, OpencodeSessionThinkingState>>;
25
28
  iframeSource: Ref<string>;
26
29
  buttonActive: Ref<boolean>;
27
30
  sessionListTitle: Ref<string>;
@@ -48,6 +51,7 @@ export interface OpenCodeWidgetContext {
48
51
  }) => void;
49
52
  handleClearSelectedNodes: () => void;
50
53
  handleFrameLoaded: () => void;
54
+ handleBubbleOffsetChange: (offset: FloatingBubbleOffset | undefined) => void;
51
55
  }
52
56
  export declare function provideOpenCodeWidgetContext(context: OpenCodeWidgetContext): void;
53
57
  export declare function useOpenCodeWidgetContext(): OpenCodeWidgetContext;
@@ -1 +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-thinking-gradient-1: #10b981;--oc-thinking-gradient-2: #059669;--oc-thinking-glow: rgba(16, 185, 129, .3);--oc-thinking-glow-strong: rgba(16, 185, 129, .6);--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: #3b82f6;--oc-trigger-bg-hover: #2563eb;--oc-trigger-bg-active: #1d4ed8;--oc-trigger-shadow: 0 2px 8px rgba(59, 130, 246, .3);--oc-trigger-shadow-hover: 0 4px 12px rgba(59, 130, 246, .4);--oc-trigger-shadow-active: 0 4px 12px rgba(59, 130, 246, .5);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-thinking-gradient-1: #34d399;--oc-thinking-gradient-2: #10b981;--oc-thinking-glow: rgba(52, 211, 153, .3);--oc-thinking-glow-strong: rgba(52, 211, 153, .6);--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: #60a5fa;--oc-trigger-bg-hover: #3b82f6;--oc-trigger-bg-active: #2563eb;--oc-trigger-shadow: 0 2px 8px rgba(96, 165, 250, .4);--oc-trigger-shadow-hover: 0 4px 12px rgba(96, 165, 250, .5);--oc-trigger-shadow-active: 0 4px 12px rgba(96, 165, 250, .6)}.opencode-chat{position:fixed;bottom:20px;width:700px;height:86vh;max-height:calc(100vh - 40px);background:var(--oc-bg-main);border-radius:16px;box-shadow:var(--oc-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translate3d(var(---chatAnimationOrigin\.x),var(---chatAnimationOrigin\.y),0) scale(.95);transition:all .3s ease;display:flex;flex-direction:column;z-index:99999}.opencode-chat.minimized{width:300px;height:300px}.opencode-chat.minimized .opencode-iframe-container{margin-top:-146px}.opencode-chat-content{display:flex;flex:1;overflow:hidden}.opencode-chat.open{opacity:1;visibility:visible;transform:translateZ(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-page-notification{position:fixed;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:2147483647;display:flex;align-items:center;gap:10px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.opencode-page-notification:before{content:"\1f4a1";font-size:16px}.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)}}
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-thinking-gradient-1: #10b981;--oc-thinking-gradient-2: #059669;--oc-thinking-glow: rgba(16, 185, 129, .3);--oc-thinking-glow-strong: rgba(16, 185, 129, .6);--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: #3b82f6;--oc-trigger-bg-hover: #2563eb;--oc-trigger-bg-active: #1d4ed8;--oc-trigger-shadow: 0 2px 8px rgba(59, 130, 246, .3);--oc-trigger-shadow-hover: 0 4px 12px rgba(59, 130, 246, .4);--oc-trigger-shadow-active: 0 4px 12px rgba(59, 130, 246, .5);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-thinking-gradient-1: #34d399;--oc-thinking-gradient-2: #10b981;--oc-thinking-glow: rgba(52, 211, 153, .3);--oc-thinking-glow-strong: rgba(52, 211, 153, .6);--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: #60a5fa;--oc-trigger-bg-hover: #3b82f6;--oc-trigger-bg-active: #2563eb;--oc-trigger-shadow: 0 2px 8px rgba(96, 165, 250, .4);--oc-trigger-shadow-hover: 0 4px 12px rgba(96, 165, 250, .5);--oc-trigger-shadow-active: 0 4px 12px rgba(96, 165, 250, .6)}.opencode-chat{position:fixed;bottom:20px;width:700px;height:86vh;max-height:calc(100vh - 40px);background:var(--oc-bg-main);border-radius:16px;box-shadow:var(--oc-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translate3d(var(---chatAnimationOrigin\.x),var(---chatAnimationOrigin\.y),0) scale(.95);transition:all .3s ease;display:flex;flex-direction:column;z-index:99999}.opencode-chat.open{opacity:1;visibility:visible;transform:translateZ(0) scale(1)}.opencode-chat.no-transition,.opencode-chat.no-transition.open{transition:none!important}.opencode-chat.minimized{width:300px;height:300px}.opencode-chat.minimized .opencode-iframe-container{margin-top:-146px}.opencode-chat-content{display:flex;flex:1;overflow:hidden}.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-page-notification{position:fixed;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:2147483647;display:flex;align-items:center;gap:10px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.opencode-page-notification:before{content:"\1f4a1";font-size:16px}.opencode-element-highlight{position:fixed;pointer-events:none;z-index:999998;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;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)}}
@@ -1,23 +1,23 @@
1
1
  import type { OpenCodeWidgetProps } from "./types";
2
- declare var __VLS_12: {}, __VLS_17: {}, __VLS_19: {}, __VLS_21: {}, __VLS_26: {}, __VLS_33: {}, __VLS_35: {}, __VLS_37: {}, __VLS_39: {};
2
+ declare var __VLS_11: {}, __VLS_16: {}, __VLS_18: {}, __VLS_20: {}, __VLS_25: {}, __VLS_32: {}, __VLS_34: {}, __VLS_36: {}, __VLS_38: {};
3
3
  type __VLS_Slots = {} & {
4
- 'button-icon'?: (props: typeof __VLS_12) => any;
4
+ 'button-icon'?: (props: typeof __VLS_11) => any;
5
5
  } & {
6
- 'session-toggle-icon'?: (props: typeof __VLS_17) => any;
6
+ 'session-toggle-icon'?: (props: typeof __VLS_16) => any;
7
7
  } & {
8
- 'select-icon'?: (props: typeof __VLS_19) => any;
8
+ 'select-icon'?: (props: typeof __VLS_18) => any;
9
9
  } & {
10
- 'close-icon'?: (props: typeof __VLS_21) => any;
10
+ 'close-icon'?: (props: typeof __VLS_20) => any;
11
11
  } & {
12
- 'sessions-empty'?: (props: typeof __VLS_26) => any;
12
+ 'sessions-empty'?: (props: typeof __VLS_25) => any;
13
13
  } & {
14
- 'empty-state'?: (props: typeof __VLS_33) => any;
14
+ 'empty-state'?: (props: typeof __VLS_32) => any;
15
15
  } & {
16
- loading?: (props: typeof __VLS_35) => any;
16
+ loading?: (props: typeof __VLS_34) => any;
17
17
  } & {
18
- error?: (props: typeof __VLS_37) => any;
18
+ error?: (props: typeof __VLS_36) => any;
19
19
  } & {
20
- content?: (props: typeof __VLS_39) => any;
20
+ content?: (props: typeof __VLS_38) => any;
21
21
  };
22
22
  declare const __VLS_component: import("vue").DefineComponent<OpenCodeWidgetProps, {
23
23
  showNotification: (message: string, options?: {
@@ -87,9 +87,9 @@ declare const __VLS_component: import("vue").DefineComponent<OpenCodeWidgetProps
87
87
  showSessionListSkeleton: boolean;
88
88
  sessionKey: string;
89
89
  sessions: import("@vite-plugin-opencode-assistant/shared").OpenCodeWidgetSession[];
90
+ thinking: boolean;
90
91
  open: boolean;
91
92
  hotkeyLabel: string;
92
- thinking: boolean;
93
93
  currentSessionId: string | null;
94
94
  selectedElements: import("@vite-plugin-opencode-assistant/shared").OpenCodeSelectedElement[];
95
95
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -60,6 +60,7 @@ var import_use_selection = require("../composables/use-selection");
60
60
  var import_use_session = require("../composables/use-session");
61
61
  var import_use_widget = require("../composables/use-widget");
62
62
  var import_use_inspector = require("../composables/use-inspector");
63
+ var import_use_persist_state = require("../composables/use-persist-state");
63
64
  var import_context = require("./context");
64
65
  var import_vue3 = require("vue");
65
66
  const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProps(__spreadValues({}, {
@@ -88,7 +89,8 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
88
89
  selectedElements: { type: Array, required: false, default: () => [] },
89
90
  showClearAll: { type: Boolean, required: false, default: true },
90
91
  selectEnabled: { type: Boolean, required: false, default: true },
91
- thinking: { type: Boolean, required: false, default: false }
92
+ thinking: { type: Boolean, required: false, default: false },
93
+ sessionStates: { type: Object, required: false }
92
94
  },
93
95
  emits: ["update:open", "update:selectMode", "update:sessionListCollapsed", "update:currentSessionId", "update:selectedElements", "update:theme", "update:thinking", "toggle", "close", "toggle-session-list", "toggle-select-mode", "toggle-theme", "create-session", "select-session", "delete-session", "click-selected-node", "remove-selected-node", "clear-selected-nodes", "empty-action", "frame-loaded", "thinking-change"],
94
96
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -137,17 +139,26 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
137
139
  var _a;
138
140
  (_a = frameRef.value) == null ? void 0 : _a.sendMessageToIframe(type, data);
139
141
  };
142
+ const localSessionListCollapsed = (0, import_vue2.ref)(props.sessionListCollapsed);
143
+ const minimized = (0, import_vue2.ref)(false);
144
+ const promptDockVisible = (0, import_vue2.ref)(true);
145
+ const isRestoring = (0, import_vue2.ref)(true);
146
+ const iframeLoaded = (0, import_vue2.ref)(false);
147
+ const syncStateToIframe = () => {
148
+ if (!iframeLoaded.value) return;
149
+ sendMessageToIframe("prompt-dock-visibility-change", { visible: promptDockVisible.value });
150
+ sendMessageToIframe("minimize-state-change", { minimized: minimized.value });
151
+ };
140
152
  const handleFrameLoaded = () => {
141
153
  emit("frame-loaded");
154
+ iframeLoaded.value = true;
155
+ syncStateToIframe();
142
156
  };
143
157
  __expose({
144
158
  showNotification,
145
159
  showConfirmDialog,
146
160
  sendMessageToIframe
147
161
  });
148
- const localSessionListCollapsed = (0, import_vue2.ref)(props.sessionListCollapsed);
149
- const minimized = (0, import_vue2.ref)(false);
150
- const promptDockVisible = (0, import_vue2.ref)(true);
151
162
  (0, import_vue2.watch)(
152
163
  () => props.sessionListCollapsed,
153
164
  (val) => {
@@ -244,6 +255,53 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
244
255
  emit("toggle-select-mode", false);
245
256
  }
246
257
  });
258
+ const bubbleOffset = (0, import_vue2.ref)(void 0);
259
+ (0, import_use_persist_state.usePersistState)({
260
+ open: (0, import_vue2.toRef)(props, "open"),
261
+ minimized,
262
+ promptDockVisible,
263
+ bubbleOffset,
264
+ theme: (0, import_vue2.toRef)(props, "theme"),
265
+ sessionListCollapsed: localSessionListCollapsed,
266
+ onRestore: (state) => {
267
+ if (state.open !== void 0 && state.open !== props.open) {
268
+ emit("update:open", state.open);
269
+ emit("toggle", state.open);
270
+ }
271
+ if (state.minimized !== void 0) {
272
+ minimized.value = state.minimized;
273
+ }
274
+ if (state.bubbleOffset !== void 0) {
275
+ const bubbleSize = 44;
276
+ const margin = 10;
277
+ const maxX = window.innerWidth - bubbleSize - margin;
278
+ const maxY = window.innerHeight - bubbleSize - margin;
279
+ bubbleOffset.value = {
280
+ x: Math.max(margin, Math.min(state.bubbleOffset.x, maxX)),
281
+ y: Math.max(margin, Math.min(state.bubbleOffset.y, maxY))
282
+ };
283
+ }
284
+ if (state.theme !== void 0 && state.theme !== props.theme) {
285
+ emit("update:theme", state.theme);
286
+ emit("toggle-theme", state.theme);
287
+ }
288
+ if (state.sessionListCollapsed !== void 0 && state.sessionListCollapsed !== props.sessionListCollapsed) {
289
+ localSessionListCollapsed.value = state.sessionListCollapsed;
290
+ emit("update:sessionListCollapsed", state.sessionListCollapsed);
291
+ }
292
+ if (state.promptDockVisible !== void 0) {
293
+ promptDockVisible.value = state.promptDockVisible;
294
+ } else if (minimized.value) {
295
+ promptDockVisible.value = false;
296
+ }
297
+ (0, import_vue2.nextTick)(() => {
298
+ syncStateToIframe();
299
+ setTimeout(() => {
300
+ isRestoring.value = false;
301
+ }, 50);
302
+ });
303
+ }
304
+ });
247
305
  const handleToggleMinimize = () => {
248
306
  minimized.value = !minimized.value;
249
307
  promptDockVisible.value = !minimized.value;
@@ -254,15 +312,33 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
254
312
  promptDockVisible.value = !promptDockVisible.value;
255
313
  sendMessageToIframe("prompt-dock-visibility-change", { visible: promptDockVisible.value });
256
314
  };
257
- const bubbleOffset = (0, import_vue2.ref)(void 0);
315
+ const windowWidth = (0, import_vue2.ref)(typeof window !== "undefined" ? window.innerWidth : 0);
316
+ const windowHeight = (0, import_vue2.ref)(typeof window !== "undefined" ? window.innerHeight : 0);
317
+ const handleWindowResize = () => {
318
+ if (typeof window !== "undefined") {
319
+ windowWidth.value = window.innerWidth;
320
+ windowHeight.value = window.innerHeight;
321
+ }
322
+ };
323
+ (0, import_vue2.onMounted)(() => {
324
+ if (typeof window !== "undefined") {
325
+ window.addEventListener("resize", handleWindowResize);
326
+ }
327
+ });
328
+ (0, import_vue2.onUnmounted)(() => {
329
+ if (typeof window !== "undefined") {
330
+ window.removeEventListener("resize", handleWindowResize);
331
+ }
332
+ });
258
333
  const bubbleQuadrant = (0, import_vue2.computed)(() => {
259
334
  var _a, _b, _c, _d;
260
335
  if (typeof window === "undefined") return "bottom-right";
261
- const centerX = window.innerWidth / 2;
262
- const centerY = window.innerHeight / 2;
336
+ const centerX = windowWidth.value / 2;
337
+ const centerY = windowHeight.value / 2;
263
338
  const bubbleSize = 44;
264
- const effectiveX = ((_b = (_a = bubbleOffset.value) == null ? void 0 : _a.x) != null ? _b : window.innerWidth - bubbleSize - 24) + bubbleSize / 2;
265
- const effectiveY = ((_d = (_c = bubbleOffset.value) == null ? void 0 : _c.y) != null ? _d : window.innerHeight - bubbleSize - 24) + bubbleSize / 2;
339
+ const currentOffset = (_b = (_a = triggerRef.value) == null ? void 0 : _a.offset) != null ? _b : bubbleOffset.value;
340
+ const effectiveX = ((_c = currentOffset == null ? void 0 : currentOffset.x) != null ? _c : windowWidth.value - bubbleSize - 24) + bubbleSize / 2;
341
+ const effectiveY = ((_d = currentOffset == null ? void 0 : currentOffset.y) != null ? _d : windowHeight.value - bubbleSize - 24) + bubbleSize / 2;
266
342
  if (effectiveX >= centerX && effectiveY >= centerY) {
267
343
  return "bottom-right";
268
344
  } else if (effectiveX < centerX && effectiveY >= centerY) {
@@ -278,36 +354,42 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
278
354
  return quadrant === "top-right" || quadrant === "bottom-right";
279
355
  });
280
356
  const chatPositionStyle = (0, import_vue2.computed)(() => {
281
- var _a;
357
+ var _a, _b, _c;
282
358
  if (typeof window === "undefined") return {};
283
- const windowWidth = window.innerWidth;
284
- const windowHeight = window.innerHeight;
285
359
  const chatWidth = minimized.value ? 300 : 700;
286
- const chatHeight = minimized.value ? 300 : Math.min(windowHeight * 0.86, windowHeight - 40);
360
+ const chatHeight = minimized.value ? 300 : Math.min(windowHeight.value * 0.86, windowHeight.value - 40);
287
361
  const gap = 24;
288
362
  const bubbleSize = 44;
289
363
  const screenMargin = 20;
290
- const effectiveOffset = (_a = bubbleOffset.value) != null ? _a : { x: windowWidth - bubbleSize - gap, y: windowHeight - bubbleSize - gap };
364
+ const effectiveOffset = (_c = (_b = (_a = triggerRef.value) == null ? void 0 : _a.offset) != null ? _b : bubbleOffset.value) != null ? _c : { x: windowWidth.value - bubbleSize - gap, y: windowHeight.value - bubbleSize - gap };
291
365
  const style = {};
292
366
  if (isBubbleOnRightSide.value) {
293
- let rightPos = windowWidth - effectiveOffset.x + gap;
294
- const maxRight = windowWidth - chatWidth - screenMargin;
367
+ let rightPos = windowWidth.value - effectiveOffset.x + gap;
368
+ const minRight = screenMargin;
369
+ const maxRight = windowWidth.value - chatWidth - screenMargin;
295
370
  if (rightPos > maxRight) {
296
371
  rightPos = maxRight;
297
372
  }
373
+ if (rightPos < minRight) {
374
+ rightPos = minRight;
375
+ }
298
376
  style.right = `${rightPos}px`;
299
377
  style.left = "auto";
300
378
  } else {
301
379
  let leftPos = effectiveOffset.x + bubbleSize + gap;
302
- const maxLeft = windowWidth - chatWidth - screenMargin;
380
+ const minLeft = screenMargin;
381
+ const maxLeft = windowWidth.value - chatWidth - screenMargin;
303
382
  if (leftPos > maxLeft) {
304
383
  leftPos = maxLeft;
305
384
  }
385
+ if (leftPos < minLeft) {
386
+ leftPos = minLeft;
387
+ }
306
388
  style.left = `${leftPos}px`;
307
389
  style.right = "auto";
308
390
  }
309
- let bottomPos = windowHeight - effectiveOffset.y - bubbleSize;
310
- const maxBottom = windowHeight - chatHeight - screenMargin;
391
+ let bottomPos = windowHeight.value - effectiveOffset.y - bubbleSize;
392
+ const maxBottom = windowHeight.value - chatHeight - screenMargin;
311
393
  if (bottomPos > maxBottom) {
312
394
  bottomPos = maxBottom;
313
395
  }
@@ -371,6 +453,11 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
371
453
  thinking: (0, import_vue2.toRef)(props, "thinking"),
372
454
  minimized,
373
455
  promptDockVisible,
456
+ bubbleOffset,
457
+ sessionStates: (0, import_vue2.computed)(() => {
458
+ var _a;
459
+ return (_a = props.sessionStates) != null ? _a : {};
460
+ }),
374
461
  iframeSource,
375
462
  buttonActive,
376
463
  sessionListTitle,
@@ -392,7 +479,8 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
392
479
  handleClickSelectedNode,
393
480
  handleRemoveSelectedNode: (payload) => handleRemoveSelectedNode(payload.item, payload.index, payload.source),
394
481
  handleClearSelectedNodes,
395
- handleFrameLoaded
482
+ handleFrameLoaded,
483
+ handleBubbleOffsetChange
396
484
  });
397
485
  const __returned__ = { props, emit, slots, notificationMessage, notificationVisible, notificationMode, get notificationTimer() {
398
486
  return notificationTimer;
@@ -402,7 +490,7 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)(__spreadProp
402
490
  return dialogResolve;
403
491
  }, set dialogResolve(v) {
404
492
  dialogResolve = v;
405
- }, showConfirmDialog, handleDialogConfirm, handleDialogCancel, frameRef, triggerRef, sendMessageToIframe, handleFrameLoaded, localSessionListCollapsed, minimized, promptDockVisible, buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme, sessionItems, handleCreateSession, handleDeleteSession, handleSelectSession, bubbleVisible, hasSelectedElements, selectedElementItems, handleClearSelectedNodes, handleClickSelectedNode, handleRemoveSelectedNode, handleToggleSelectMode, highlightVisible, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent, handleToggleMinimize, handleTogglePromptDock, bubbleOffset, bubbleQuadrant, isBubbleOnRightSide, chatPositionStyle, handleBubbleOffsetChange, chatAnimationOrigin, isDragging, get wasOpenBeforeDrag() {
493
+ }, showConfirmDialog, handleDialogConfirm, handleDialogCancel, frameRef, triggerRef, sendMessageToIframe, localSessionListCollapsed, minimized, promptDockVisible, isRestoring, iframeLoaded, syncStateToIframe, handleFrameLoaded, buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme, sessionItems, handleCreateSession, handleDeleteSession, handleSelectSession, bubbleVisible, hasSelectedElements, selectedElementItems, handleClearSelectedNodes, handleClickSelectedNode, handleRemoveSelectedNode, handleToggleSelectMode, highlightVisible, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent, bubbleOffset, handleToggleMinimize, handleTogglePromptDock, windowWidth, windowHeight, handleWindowResize, bubbleQuadrant, isBubbleOnRightSide, chatPositionStyle, handleBubbleOffsetChange, chatAnimationOrigin, isDragging, get wasOpenBeforeDrag() {
406
494
  return wasOpenBeforeDrag;
407
495
  }, set wasOpenBeforeDrag(v) {
408
496
  wasOpenBeforeDrag = v;
@@ -446,7 +534,6 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
446
534
  $setup["Trigger"],
447
535
  {
448
536
  ref: "triggerRef",
449
- onOffsetChange: $setup.handleBubbleOffsetChange,
450
537
  onDragStart: $setup.handleDragStart,
451
538
  onDragEnd: $setup.handleDragEnd
452
539
  },
@@ -468,7 +555,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
468
555
  (0, import_vue3.withDirectives)((0, import_vue3.createElementVNode)(
469
556
  "div",
470
557
  {
471
- class: (0, import_vue3.normalizeClass)(["opencode-chat", { open: $props.open, minimized: $setup.minimized, dragging: $setup.isDragging }]),
558
+ class: (0, import_vue3.normalizeClass)(["opencode-chat", { open: $props.open, minimized: $setup.minimized, dragging: $setup.isDragging, "no-transition": $setup.isRestoring }]),
472
559
  style: (0, import_vue3.normalizeStyle)($setup.chatPositionStyle)
473
560
  },
474
561
  [
@@ -579,9 +666,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
579
666
  "div",
580
667
  {
581
668
  class: "opencode-element-highlight",
582
- style: (0, import_vue3.normalizeStyle)(__spreadValues({
583
- display: $setup.highlightVisible ? "block" : "none"
584
- }, $setup.highlightStyle))
669
+ style: (0, import_vue3.normalizeStyle)($setup.highlightStyle)
585
670
  },
586
671
  null,
587
672
  4
@@ -593,9 +678,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
593
678
  "div",
594
679
  {
595
680
  class: "opencode-element-tooltip",
596
- style: (0, import_vue3.normalizeStyle)(__spreadValues({
597
- display: $setup.tooltipVisible ? "block" : "none"
598
- }, $setup.tooltipStyle))
681
+ style: (0, import_vue3.normalizeStyle)($setup.tooltipStyle)
599
682
  },
600
683
  [
601
684
  (0, import_vue3.createElementVNode)(
@@ -1,2 +1,2 @@
1
- export type { OpenCodeWidgetTheme, OpenCodeWidgetSession, OpenCodeSelectedElement, OpenCodeRemoveSelectedPayload, OpenCodeWidgetSessionItem, OpenCodeSelectedElementItem, OpenCodeWidgetProps, OpenCodeWidgetEmits, } from "@vite-plugin-opencode-assistant/shared";
1
+ export type { OpenCodeWidgetTheme, OpenCodeWidgetSession, OpenCodeSelectedElement, OpenCodeRemoveSelectedPayload, OpenCodeWidgetSessionItem, OpenCodeSelectedElementItem, OpenCodeWidgetProps, OpenCodeWidgetEmits, OpencodeSessionThinkingState, } from "@vite-plugin-opencode-assistant/shared";
2
2
  export type OpenCodeWidgetThemeLocal = "light" | "dark" | "auto";
@@ -1 +1 @@
1
- {"$schema":"https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json","framework":"vue","name":"@vite-plugin-opencode-assistant/components","version":"1.0.26","contributions":{"html":{"tags":[{"name":"open-code","attributes":[{"name":"","default":"`'bottom-right'`","description":"挂件显示的位置","value":{"type":"`'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'`","kind":"expression"}},{"name":"","default":"`false`","description":"挂件是否打开","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`'auto'`","description":"主题模式","value":{"type":"`'light' | 'dark' | 'auto'`","kind":"expression"}},{"name":"","default":"`'AI 助手'`","description":"助手头部显示的标题","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`'Ctrl+K'`","description":"快捷键提示文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`'按 ESC 或 Ctrl+P 退出'`","description":"选择模式快捷键提示文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`false`","description":"是否进入选择页面元素模式","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`true`","description":"会话列表是否折叠","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`'id'`","description":"会话列表项的唯一键字段","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`false`","description":"iframe 是否显示加载状态","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`undefined`","description":"会话列表是否加载中","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示会话列表骨架屏","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示空状态","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示错误状态","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`'当前项目暂无会话'`","description":"空状态显示的文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`'立即创建'`","description":"空状态操作按钮文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`''`","description":"Web UI 的 URL 来源","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`[]`","description":"会话列表数据","value":{"type":"`OpenCodeWidgetSession[]`","kind":"expression"}},{"name":"","default":"`null`","description":"当前选中的会话 ID","value":{"type":"`string | null`","kind":"expression"}},{"name":"","default":"`[]`","description":"已选中的元素列表","value":{"type":"`OpenCodeSelectedElement[]`","kind":"expression"}},{"name":"","default":"`true`","description":"是否显示\"一键清空\"按钮","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`true`","description":"是否启用选择模式","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示思考状态(加载中)","value":{"type":"`boolean`","kind":"expression"}}],"events":[{"name":"`update:open`","description":"当挂件打开或关闭时触发","arguments":[{"name":"open","type":"en"},{"name":"boolean"}]},{"name":"`update:selectMode`","description":"当选择模式切换时触发","arguments":[{"name":"mode","type":"de"},{"name":"boolean"}]},{"name":"`update:sessionListCollapsed`","description":"当会话列表折叠状态改变时触发","arguments":[{"name":"collapsed","type":"ed"},{"name":"boolean"}]},{"name":"`update:currentSessionId`","description":"当选中的会话 ID 改变时触发","arguments":[{"name":"sessionId","type":"Id"},{"name":"string | null"}]},{"name":"`update:selectedElements`","description":"当已选中的元素列表改变时触发","arguments":[{"name":"elements","type":"ts"},{"name":"OpenCodeSelectedElement[]"}]},{"name":"`update:theme`","description":"当主题模式改变时触发","arguments":[{"name":"theme","type":"me"},{"name":"'light' | 'dark' | 'auto'"}]},{"name":"`update:thinking`","description":"当思考状态改变时触发","arguments":[{"name":"thinking","type":"ng"},{"name":"boolean"}]},{"name":"","description":"点击触发挂件开关","arguments":[{"name":"open","type":"en"},{"name":"boolean"}]},{"name":"","description":"点击关闭按钮时触发","arguments":[]},{"name":"`toggle-session-list`","description":"点击会话列表切换按钮时触发","arguments":[{"name":"collapsed","type":"ed"},{"name":"boolean"}]},{"name":"`toggle-select-mode`","description":"点击选择模式切换按钮时触发","arguments":[{"name":"mode","type":"de"},{"name":"boolean"}]},{"name":"`toggle-theme`","description":"点击主题切换按钮时触发","arguments":[{"name":"theme","type":"me"},{"name":"'light' | 'dark' | 'auto'"}]},{"name":"`create-session`","description":"点击创建新会话时触发","arguments":[]},{"name":"`select-session`","description":"选中某个历史会话时触发","arguments":[{"name":"session","type":"on"},{"name":"OpenCodeWidgetSession"}]},{"name":"`delete-session`","description":"删除某个历史会话时触发","arguments":[{"name":"session","type":"on"},{"name":"OpenCodeWidgetSession"}]},{"name":"`click-selected-node`","description":"点击已选中的气泡或节点卡片时触发","arguments":[{"name":"element","type":"nt"},{"name":"OpenCodeSelectedElement"}]},{"name":"`remove-selected-node`","description":"删除已选中的元素时触发","arguments":[{"name":"payload","type":"ad"},{"name":"OpenCodeRemoveSelectedPayload"}]},{"name":"`clear-selected-nodes`","description":"清空所有选中元素时触发","arguments":[]},{"name":"`empty-action`","description":"点击空状态操作按钮时触发","arguments":[]},{"name":"`frame-loaded`","description":"iframe 加载完成时触发","arguments":[]},{"name":"`thinking-change`","description":"思考状态改变时触发(用于显示加载动画)","arguments":[{"name":"thinking","type":"ng"},{"name":"boolean"}]}],"slots":[{"name":"`button-icon`","description":"自定义触发按钮图标"},{"name":"`session-toggle-icon`","description":"自定义会话列表切换图标"},{"name":"`select-icon`","description":"自定义选择模式切换图标"},{"name":"`close-icon`","description":"自定义关闭按钮图标"},{"name":"`theme-icon`","description":"自定义主题切换图标"},{"name":"`sessions-empty`","description":"自定义会话列表空状态"},{"name":"`empty-state`","description":"自定义 iframe 空状态"},{"name":"","description":"自定义 iframe 加载状态"},{"name":"","description":"自定义错误状态"},{"name":"","description":"自定义 iframe 内容"}]}],"attributes":[]}},"js-types-syntax":"typescript"}
1
+ {"$schema":"https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json","framework":"vue","name":"@vite-plugin-opencode-assistant/components","version":"1.0.28","contributions":{"html":{"tags":[{"name":"open-code","attributes":[{"name":"","default":"`'bottom-right'`","description":"挂件显示的位置","value":{"type":"`'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'`","kind":"expression"}},{"name":"","default":"`false`","description":"挂件是否打开","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`'auto'`","description":"主题模式","value":{"type":"`'light' | 'dark' | 'auto'`","kind":"expression"}},{"name":"","default":"`'AI 助手'`","description":"助手头部显示的标题","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`'Ctrl+K'`","description":"快捷键提示文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`'按 ESC 或 Ctrl+P 退出'`","description":"选择模式快捷键提示文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`false`","description":"是否进入选择页面元素模式","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`true`","description":"会话列表是否折叠","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`'id'`","description":"会话列表项的唯一键字段","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`false`","description":"iframe 是否显示加载状态","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`undefined`","description":"会话列表是否加载中","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示会话列表骨架屏","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示空状态","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示错误状态","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`'当前项目暂无会话'`","description":"空状态显示的文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`'立即创建'`","description":"空状态操作按钮文本","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`''`","description":"Web UI 的 URL 来源","value":{"type":"`string`","kind":"expression"}},{"name":"","default":"`[]`","description":"会话列表数据","value":{"type":"`OpenCodeWidgetSession[]`","kind":"expression"}},{"name":"","default":"`null`","description":"当前选中的会话 ID","value":{"type":"`string | null`","kind":"expression"}},{"name":"","default":"`[]`","description":"已选中的元素列表","value":{"type":"`OpenCodeSelectedElement[]`","kind":"expression"}},{"name":"","default":"`true`","description":"是否显示\"一键清空\"按钮","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`true`","description":"是否启用选择模式","value":{"type":"`boolean`","kind":"expression"}},{"name":"","default":"`false`","description":"是否显示思考状态(加载中)","value":{"type":"`boolean`","kind":"expression"}}],"events":[{"name":"`update:open`","description":"当挂件打开或关闭时触发","arguments":[{"name":"open","type":"en"},{"name":"boolean"}]},{"name":"`update:selectMode`","description":"当选择模式切换时触发","arguments":[{"name":"mode","type":"de"},{"name":"boolean"}]},{"name":"`update:sessionListCollapsed`","description":"当会话列表折叠状态改变时触发","arguments":[{"name":"collapsed","type":"ed"},{"name":"boolean"}]},{"name":"`update:currentSessionId`","description":"当选中的会话 ID 改变时触发","arguments":[{"name":"sessionId","type":"Id"},{"name":"string | null"}]},{"name":"`update:selectedElements`","description":"当已选中的元素列表改变时触发","arguments":[{"name":"elements","type":"ts"},{"name":"OpenCodeSelectedElement[]"}]},{"name":"`update:theme`","description":"当主题模式改变时触发","arguments":[{"name":"theme","type":"me"},{"name":"'light' | 'dark' | 'auto'"}]},{"name":"`update:thinking`","description":"当思考状态改变时触发","arguments":[{"name":"thinking","type":"ng"},{"name":"boolean"}]},{"name":"","description":"点击触发挂件开关","arguments":[{"name":"open","type":"en"},{"name":"boolean"}]},{"name":"","description":"点击关闭按钮时触发","arguments":[]},{"name":"`toggle-session-list`","description":"点击会话列表切换按钮时触发","arguments":[{"name":"collapsed","type":"ed"},{"name":"boolean"}]},{"name":"`toggle-select-mode`","description":"点击选择模式切换按钮时触发","arguments":[{"name":"mode","type":"de"},{"name":"boolean"}]},{"name":"`toggle-theme`","description":"点击主题切换按钮时触发","arguments":[{"name":"theme","type":"me"},{"name":"'light' | 'dark' | 'auto'"}]},{"name":"`create-session`","description":"点击创建新会话时触发","arguments":[]},{"name":"`select-session`","description":"选中某个历史会话时触发","arguments":[{"name":"session","type":"on"},{"name":"OpenCodeWidgetSession"}]},{"name":"`delete-session`","description":"删除某个历史会话时触发","arguments":[{"name":"session","type":"on"},{"name":"OpenCodeWidgetSession"}]},{"name":"`click-selected-node`","description":"点击已选中的气泡或节点卡片时触发","arguments":[{"name":"element","type":"nt"},{"name":"OpenCodeSelectedElement"}]},{"name":"`remove-selected-node`","description":"删除已选中的元素时触发","arguments":[{"name":"payload","type":"ad"},{"name":"OpenCodeRemoveSelectedPayload"}]},{"name":"`clear-selected-nodes`","description":"清空所有选中元素时触发","arguments":[]},{"name":"`empty-action`","description":"点击空状态操作按钮时触发","arguments":[]},{"name":"`frame-loaded`","description":"iframe 加载完成时触发","arguments":[]},{"name":"`thinking-change`","description":"思考状态改变时触发(用于显示加载动画)","arguments":[{"name":"thinking","type":"ng"},{"name":"boolean"}]}],"slots":[{"name":"`button-icon`","description":"自定义触发按钮图标"},{"name":"`session-toggle-icon`","description":"自定义会话列表切换图标"},{"name":"`select-icon`","description":"自定义选择模式切换图标"},{"name":"`close-icon`","description":"自定义关闭按钮图标"},{"name":"`theme-icon`","description":"自定义主题切换图标"},{"name":"`sessions-empty`","description":"自定义会话列表空状态"},{"name":"`empty-state`","description":"自定义 iframe 空状态"},{"name":"","description":"自定义 iframe 加载状态"},{"name":"","description":"自定义错误状态"},{"name":"","description":"自定义 iframe 内容"}]}],"attributes":[]}},"js-types-syntax":"typescript"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vite-plugin-opencode-assistant/components",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "description": "Reusable OpenCode widget components built with Pagoda CLI",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "css-selector-generator": "^3.9.1",
34
- "@vite-plugin-opencode-assistant/shared": "1.0.26"
34
+ "@vite-plugin-opencode-assistant/shared": "1.0.28"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@vitejs/plugin-vue": "^6.0.5",