@vite-plugin-opencode-assistant/components 1.0.25 → 1.0.27

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 (33) 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 -3
  8. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +50 -60
  9. package/es/open-code-widget/src/components/Trigger.vue.d.ts +2 -5
  10. package/es/open-code-widget/src/components/Trigger.vue.js +10 -38
  11. package/es/open-code-widget/src/context.d.ts +3 -0
  12. package/es/open-code-widget/src/index-sfc.css +1 -1
  13. package/es/open-code-widget/src/index.vue.d.ts +10 -10
  14. package/es/open-code-widget/src/index.vue.js +143 -28
  15. package/lib/@vite-plugin-opencode-assistant/components.cjs.js +359 -200
  16. package/lib/@vite-plugin-opencode-assistant/components.es.js +360 -201
  17. package/lib/components.css +2 -2
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.js +1 -1
  20. package/lib/open-code-widget/composables/use-inspector.js +118 -79
  21. package/lib/open-code-widget/composables/use-persist-state.d.ts +24 -0
  22. package/lib/open-code-widget/composables/use-persist-state.js +78 -0
  23. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -1
  24. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +2 -3
  25. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +49 -59
  26. package/lib/open-code-widget/src/components/Trigger.vue.d.ts +2 -5
  27. package/lib/open-code-widget/src/components/Trigger.vue.js +9 -37
  28. package/lib/open-code-widget/src/context.d.ts +3 -0
  29. package/lib/open-code-widget/src/index-sfc.css +1 -1
  30. package/lib/open-code-widget/src/index.vue.d.ts +10 -10
  31. package/lib/open-code-widget/src/index.vue.js +141 -26
  32. package/lib/web-types.json +1 -1
  33. package/package.json +2 -2
@@ -1,12 +1,11 @@
1
1
  import "./Trigger-sfc.css";
2
2
  import { defineComponent as _defineComponent } from "vue";
3
- import { ref, computed, onMounted } from "vue";
3
+ import { ref, watch } from "vue";
4
4
  import { useOpenCodeWidgetContext } from "../context";
5
5
  import FloatingBubble from "./FloatingBubble/FloatingBubble.vue.js";
6
- const STORAGE_KEY = "opencode-bubble-offset";
7
6
  const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
8
7
  __name: "Trigger",
9
- emits: ["offset-change", "drag-start", "drag-end"],
8
+ emits: ["drag-start", "drag-end"],
10
9
  setup(__props, { expose: __expose, emit: __emit }) {
11
10
  const {
12
11
  buttonActive: active,
@@ -14,50 +13,23 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
14
13
  hotkeyLabel,
15
14
  thinking,
16
15
  resolvedTheme,
17
- handleToggle
16
+ handleToggle,
17
+ bubbleOffset,
18
+ handleBubbleOffsetChange
18
19
  } = useOpenCodeWidgetContext();
19
- const loadOffset = () => {
20
- try {
21
- const saved = localStorage.getItem(STORAGE_KEY);
22
- if (saved) {
23
- const parsed = JSON.parse(saved);
24
- if (parsed && (parsed.x !== 0 || parsed.y !== 0)) {
25
- return parsed;
26
- }
27
- }
28
- } catch (e) {
29
- }
30
- return { x: 0, y: 0 };
31
- };
32
- const offset = ref(loadOffset());
20
+ const offset = ref(bubbleOffset.value);
33
21
  const emit = __emit;
34
- const saveOffset = (value) => {
35
- try {
36
- localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
37
- } catch (e) {
38
- }
39
- };
40
22
  const handleOffsetChange = (value) => {
41
23
  offset.value = value;
42
- saveOffset(value);
43
- emit("offset-change", value);
24
+ handleBubbleOffsetChange(value);
44
25
  };
45
- const bubbleRef = ref(null);
46
- const isOnRightSide = computed(() => {
47
- if (typeof window === "undefined") return true;
48
- const centerX = window.innerWidth / 2;
49
- return offset.value.x > centerX;
50
- });
51
- onMounted(() => {
52
- if (offset.value.x !== 0 || offset.value.y !== 0) {
53
- emit("offset-change", offset.value);
54
- }
26
+ watch(bubbleOffset, (newOffset) => {
27
+ offset.value = newOffset;
55
28
  });
56
29
  __expose({
57
- isOnRightSide,
58
30
  offset
59
31
  });
60
- const __returned__ = { active, open, hotkeyLabel, thinking, resolvedTheme, handleToggle, STORAGE_KEY, loadOffset, offset, emit, saveOffset, handleOffsetChange, bubbleRef, isOnRightSide, FloatingBubble };
32
+ const __returned__ = { active, open, hotkeyLabel, thinking, resolvedTheme, handleToggle, bubbleOffset, handleBubbleOffsetChange, offset, emit, handleOffsetChange, FloatingBubble };
61
33
  Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
62
34
  return __returned__;
63
35
  }
@@ -1,5 +1,6 @@
1
1
  import { type Ref } from "vue";
2
2
  import type { OpenCodeWidgetSessionItem, OpenCodeSelectedElementItem, OpenCodeRemoveSelectedPayload } 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,7 @@ export interface OpenCodeWidgetContext {
22
23
  thinking: Ref<boolean>;
23
24
  minimized: Ref<boolean>;
24
25
  promptDockVisible: Ref<boolean>;
26
+ bubbleOffset: Ref<FloatingBubbleOffset | undefined>;
25
27
  iframeSource: Ref<string>;
26
28
  buttonActive: Ref<boolean>;
27
29
  sessionListTitle: Ref<string>;
@@ -48,6 +50,7 @@ export interface OpenCodeWidgetContext {
48
50
  }) => void;
49
51
  handleClearSelectedNodes: () => void;
50
52
  handleFrameLoaded: () => void;
53
+ handleBubbleOffsetChange: (offset: FloatingBubbleOffset | undefined) => void;
51
54
  }
52
55
  export declare function provideOpenCodeWidgetContext(context: OpenCodeWidgetContext): void;
53
56
  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:translateY(20px) 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: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-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?: {
@@ -18,8 +18,8 @@ var __spreadValues = (a, b) => {
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
  import "./index-sfc.css";
21
- import { defineComponent as _defineComponent } from "vue";
22
- import { useSlots, toRef, ref, watch, computed } from "vue";
21
+ import { useCssVars as _useCssVars, defineComponent as _defineComponent } from "vue";
22
+ import { useSlots, toRef, ref, watch, computed, nextTick, onMounted, onUnmounted } from "vue";
23
23
  import Frame from "./components/Frame.vue.js";
24
24
  import Header from "./components/Header.vue.js";
25
25
  import SelectHint from "./components/SelectHint.vue.js";
@@ -30,6 +30,7 @@ import { useSelection } from "../composables/use-selection";
30
30
  import { useSession } from "../composables/use-session";
31
31
  import { useWidget } from "../composables/use-widget";
32
32
  import { useInspector } from "../composables/use-inspector";
33
+ import { usePersistState } from "../composables/use-persist-state";
33
34
  import { provideOpenCodeWidgetContext } from "./context";
34
35
  const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValues({}, {
35
36
  name: "OpencodeWidget"
@@ -61,6 +62,10 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
61
62
  },
62
63
  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"],
63
64
  setup(__props, { expose: __expose, emit: __emit }) {
65
+ _useCssVars((_ctx) => ({
66
+ "-chatAnimationOrigin.x": chatAnimationOrigin.value.x,
67
+ "-chatAnimationOrigin.y": chatAnimationOrigin.value.y
68
+ }));
64
69
  const props = __props;
65
70
  const emit = __emit;
66
71
  const slots = useSlots();
@@ -102,17 +107,26 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
102
107
  var _a;
103
108
  (_a = frameRef.value) == null ? void 0 : _a.sendMessageToIframe(type, data);
104
109
  };
110
+ const localSessionListCollapsed = ref(props.sessionListCollapsed);
111
+ const minimized = ref(false);
112
+ const promptDockVisible = ref(true);
113
+ const isRestoring = ref(true);
114
+ const iframeLoaded = ref(false);
115
+ const syncStateToIframe = () => {
116
+ if (!iframeLoaded.value) return;
117
+ sendMessageToIframe("prompt-dock-visibility-change", { visible: promptDockVisible.value });
118
+ sendMessageToIframe("minimize-state-change", { minimized: minimized.value });
119
+ };
105
120
  const handleFrameLoaded = () => {
106
121
  emit("frame-loaded");
122
+ iframeLoaded.value = true;
123
+ syncStateToIframe();
107
124
  };
108
125
  __expose({
109
126
  showNotification,
110
127
  showConfirmDialog,
111
128
  sendMessageToIframe
112
129
  });
113
- const localSessionListCollapsed = ref(props.sessionListCollapsed);
114
- const minimized = ref(false);
115
- const promptDockVisible = ref(true);
116
130
  watch(
117
131
  () => props.sessionListCollapsed,
118
132
  (val) => {
@@ -209,6 +223,53 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
209
223
  emit("toggle-select-mode", false);
210
224
  }
211
225
  });
226
+ const bubbleOffset = ref(void 0);
227
+ usePersistState({
228
+ open: toRef(props, "open"),
229
+ minimized,
230
+ promptDockVisible,
231
+ bubbleOffset,
232
+ theme: toRef(props, "theme"),
233
+ sessionListCollapsed: localSessionListCollapsed,
234
+ onRestore: (state) => {
235
+ if (state.open !== void 0 && state.open !== props.open) {
236
+ emit("update:open", state.open);
237
+ emit("toggle", state.open);
238
+ }
239
+ if (state.minimized !== void 0) {
240
+ minimized.value = state.minimized;
241
+ }
242
+ if (state.bubbleOffset !== void 0) {
243
+ const bubbleSize = 44;
244
+ const margin = 10;
245
+ const maxX = window.innerWidth - bubbleSize - margin;
246
+ const maxY = window.innerHeight - bubbleSize - margin;
247
+ bubbleOffset.value = {
248
+ x: Math.max(margin, Math.min(state.bubbleOffset.x, maxX)),
249
+ y: Math.max(margin, Math.min(state.bubbleOffset.y, maxY))
250
+ };
251
+ }
252
+ if (state.theme !== void 0 && state.theme !== props.theme) {
253
+ emit("update:theme", state.theme);
254
+ emit("toggle-theme", state.theme);
255
+ }
256
+ if (state.sessionListCollapsed !== void 0 && state.sessionListCollapsed !== props.sessionListCollapsed) {
257
+ localSessionListCollapsed.value = state.sessionListCollapsed;
258
+ emit("update:sessionListCollapsed", state.sessionListCollapsed);
259
+ }
260
+ if (state.promptDockVisible !== void 0) {
261
+ promptDockVisible.value = state.promptDockVisible;
262
+ } else if (minimized.value) {
263
+ promptDockVisible.value = false;
264
+ }
265
+ nextTick(() => {
266
+ syncStateToIframe();
267
+ setTimeout(() => {
268
+ isRestoring.value = false;
269
+ }, 50);
270
+ });
271
+ }
272
+ });
212
273
  const handleToggleMinimize = () => {
213
274
  minimized.value = !minimized.value;
214
275
  promptDockVisible.value = !minimized.value;
@@ -219,41 +280,84 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
219
280
  promptDockVisible.value = !promptDockVisible.value;
220
281
  sendMessageToIframe("prompt-dock-visibility-change", { visible: promptDockVisible.value });
221
282
  };
222
- const bubbleOffset = ref({ x: 0, y: 0 });
283
+ const windowWidth = ref(typeof window !== "undefined" ? window.innerWidth : 0);
284
+ const windowHeight = ref(typeof window !== "undefined" ? window.innerHeight : 0);
285
+ const handleWindowResize = () => {
286
+ if (typeof window !== "undefined") {
287
+ windowWidth.value = window.innerWidth;
288
+ windowHeight.value = window.innerHeight;
289
+ }
290
+ };
291
+ onMounted(() => {
292
+ if (typeof window !== "undefined") {
293
+ window.addEventListener("resize", handleWindowResize);
294
+ }
295
+ });
296
+ onUnmounted(() => {
297
+ if (typeof window !== "undefined") {
298
+ window.removeEventListener("resize", handleWindowResize);
299
+ }
300
+ });
301
+ const bubbleQuadrant = computed(() => {
302
+ var _a, _b, _c, _d;
303
+ if (typeof window === "undefined") return "bottom-right";
304
+ const centerX = windowWidth.value / 2;
305
+ const centerY = windowHeight.value / 2;
306
+ const bubbleSize = 44;
307
+ const currentOffset = (_b = (_a = triggerRef.value) == null ? void 0 : _a.offset) != null ? _b : bubbleOffset.value;
308
+ const effectiveX = ((_c = currentOffset == null ? void 0 : currentOffset.x) != null ? _c : windowWidth.value - bubbleSize - 24) + bubbleSize / 2;
309
+ const effectiveY = ((_d = currentOffset == null ? void 0 : currentOffset.y) != null ? _d : windowHeight.value - bubbleSize - 24) + bubbleSize / 2;
310
+ if (effectiveX >= centerX && effectiveY >= centerY) {
311
+ return "bottom-right";
312
+ } else if (effectiveX < centerX && effectiveY >= centerY) {
313
+ return "bottom-left";
314
+ } else if (effectiveX >= centerX && effectiveY < centerY) {
315
+ return "top-right";
316
+ } else {
317
+ return "top-left";
318
+ }
319
+ });
223
320
  const isBubbleOnRightSide = computed(() => {
224
- if (typeof window === "undefined") return true;
225
- const centerX = window.innerWidth / 2;
226
- return bubbleOffset.value.x > centerX;
321
+ const quadrant = bubbleQuadrant.value;
322
+ return quadrant === "top-right" || quadrant === "bottom-right";
227
323
  });
228
324
  const chatPositionStyle = computed(() => {
325
+ var _a, _b, _c;
229
326
  if (typeof window === "undefined") return {};
230
- const windowWidth = window.innerWidth;
231
- const windowHeight = window.innerHeight;
232
327
  const chatWidth = minimized.value ? 300 : 700;
233
- const chatHeight = minimized.value ? 300 : Math.min(windowHeight * 0.86, windowHeight - 40);
328
+ const chatHeight = minimized.value ? 300 : Math.min(windowHeight.value * 0.86, windowHeight.value - 40);
234
329
  const gap = 24;
235
330
  const bubbleSize = 44;
236
331
  const screenMargin = 20;
332
+ 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 };
237
333
  const style = {};
238
334
  if (isBubbleOnRightSide.value) {
239
- let rightPos = windowWidth - bubbleOffset.value.x + gap;
240
- const maxRight = windowWidth - chatWidth - screenMargin;
335
+ let rightPos = windowWidth.value - effectiveOffset.x + gap;
336
+ const minRight = screenMargin;
337
+ const maxRight = windowWidth.value - chatWidth - screenMargin;
241
338
  if (rightPos > maxRight) {
242
339
  rightPos = maxRight;
243
340
  }
341
+ if (rightPos < minRight) {
342
+ rightPos = minRight;
343
+ }
244
344
  style.right = `${rightPos}px`;
245
345
  style.left = "auto";
246
346
  } else {
247
- let leftPos = bubbleOffset.value.x + bubbleSize + gap;
248
- const maxLeft = windowWidth - chatWidth - screenMargin;
347
+ let leftPos = effectiveOffset.x + bubbleSize + gap;
348
+ const minLeft = screenMargin;
349
+ const maxLeft = windowWidth.value - chatWidth - screenMargin;
249
350
  if (leftPos > maxLeft) {
250
351
  leftPos = maxLeft;
251
352
  }
353
+ if (leftPos < minLeft) {
354
+ leftPos = minLeft;
355
+ }
252
356
  style.left = `${leftPos}px`;
253
357
  style.right = "auto";
254
358
  }
255
- let bottomPos = windowHeight - bubbleOffset.value.y - bubbleSize;
256
- const maxBottom = windowHeight - chatHeight - screenMargin;
359
+ let bottomPos = windowHeight.value - effectiveOffset.y - bubbleSize;
360
+ const maxBottom = windowHeight.value - chatHeight - screenMargin;
257
361
  if (bottomPos > maxBottom) {
258
362
  bottomPos = maxBottom;
259
363
  }
@@ -266,6 +370,20 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
266
370
  const handleBubbleOffsetChange = (offset) => {
267
371
  bubbleOffset.value = offset;
268
372
  };
373
+ const chatAnimationOrigin = computed(() => {
374
+ const quadrant = bubbleQuadrant.value;
375
+ switch (quadrant) {
376
+ case "top-left":
377
+ return { x: "-20px", y: "-20px" };
378
+ case "top-right":
379
+ return { x: "20px", y: "-20px" };
380
+ case "bottom-left":
381
+ return { x: "-20px", y: "20px" };
382
+ case "bottom-right":
383
+ default:
384
+ return { x: "20px", y: "20px" };
385
+ }
386
+ });
269
387
  const isDragging = ref(false);
270
388
  let wasOpenBeforeDrag = false;
271
389
  const handleDragStart = () => {
@@ -303,6 +421,7 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
303
421
  thinking: toRef(props, "thinking"),
304
422
  minimized,
305
423
  promptDockVisible,
424
+ bubbleOffset,
306
425
  iframeSource,
307
426
  buttonActive,
308
427
  sessionListTitle,
@@ -324,7 +443,8 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
324
443
  handleClickSelectedNode,
325
444
  handleRemoveSelectedNode: (payload) => handleRemoveSelectedNode(payload.item, payload.index, payload.source),
326
445
  handleClearSelectedNodes,
327
- handleFrameLoaded
446
+ handleFrameLoaded,
447
+ handleBubbleOffsetChange
328
448
  });
329
449
  const __returned__ = { props, emit, slots, notificationMessage, notificationVisible, notificationMode, get notificationTimer() {
330
450
  return notificationTimer;
@@ -334,7 +454,7 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
334
454
  return dialogResolve;
335
455
  }, set dialogResolve(v) {
336
456
  dialogResolve = v;
337
- }, 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, isBubbleOnRightSide, chatPositionStyle, handleBubbleOffsetChange, isDragging, get wasOpenBeforeDrag() {
457
+ }, 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() {
338
458
  return wasOpenBeforeDrag;
339
459
  }, set wasOpenBeforeDrag(v) {
340
460
  wasOpenBeforeDrag = v;
@@ -379,7 +499,6 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
379
499
  $setup["Trigger"],
380
500
  {
381
501
  ref: "triggerRef",
382
- onOffsetChange: $setup.handleBubbleOffsetChange,
383
502
  onDragStart: $setup.handleDragStart,
384
503
  onDragEnd: $setup.handleDragEnd
385
504
  },
@@ -401,7 +520,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
401
520
  _withDirectives(_createElementVNode(
402
521
  "div",
403
522
  {
404
- class: _normalizeClass(["opencode-chat", { open: $props.open, minimized: $setup.minimized, dragging: $setup.isDragging }]),
523
+ class: _normalizeClass(["opencode-chat", { open: $props.open, minimized: $setup.minimized, dragging: $setup.isDragging, "no-transition": $setup.isRestoring }]),
405
524
  style: _normalizeStyle($setup.chatPositionStyle)
406
525
  },
407
526
  [
@@ -512,9 +631,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
512
631
  "div",
513
632
  {
514
633
  class: "opencode-element-highlight",
515
- style: _normalizeStyle(__spreadValues({
516
- display: $setup.highlightVisible ? "block" : "none"
517
- }, $setup.highlightStyle))
634
+ style: _normalizeStyle($setup.highlightStyle)
518
635
  },
519
636
  null,
520
637
  4
@@ -526,9 +643,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
526
643
  "div",
527
644
  {
528
645
  class: "opencode-element-tooltip",
529
- style: _normalizeStyle(__spreadValues({
530
- display: $setup.tooltipVisible ? "block" : "none"
531
- }, $setup.tooltipStyle))
646
+ style: _normalizeStyle($setup.tooltipStyle)
532
647
  },
533
648
  [
534
649
  _createElementVNode(