@vite-plugin-opencode-assistant/components 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/env.d.ts +10 -0
- package/es/index.d.ts +6 -0
- package/es/index.js +21 -0
- package/es/open-code-widget/composables/use-inspector.d.ts +52 -0
- package/es/open-code-widget/composables/use-inspector.js +188 -0
- package/es/open-code-widget/composables/use-selection.d.ts +19 -0
- package/es/open-code-widget/composables/use-selection.js +142 -0
- package/es/open-code-widget/composables/use-session.d.ts +16 -0
- package/es/open-code-widget/composables/use-session.js +68 -0
- package/es/open-code-widget/composables/use-widget.d.ts +24 -0
- package/es/open-code-widget/composables/use-widget.js +44 -0
- package/es/open-code-widget/index.d.ts +3 -0
- package/es/open-code-widget/index.js +6 -0
- package/es/open-code-widget/src/components/Frame-sfc.css +1 -0
- package/es/open-code-widget/src/components/Frame.vue.d.ts +16 -0
- package/es/open-code-widget/src/components/Frame.vue.js +120 -0
- package/es/open-code-widget/src/components/Header-sfc.css +1 -0
- package/es/open-code-widget/src/components/Header.vue.d.ts +16 -0
- package/es/open-code-widget/src/components/Header.vue.js +140 -0
- package/es/open-code-widget/src/components/SelectHint-sfc.css +1 -0
- package/es/open-code-widget/src/components/SelectHint.vue.d.ts +2 -0
- package/es/open-code-widget/src/components/SelectHint.vue.js +46 -0
- package/es/open-code-widget/src/components/SelectedBubbles-sfc.css +1 -0
- package/es/open-code-widget/src/components/SelectedBubbles.vue.d.ts +2 -0
- package/es/open-code-widget/src/components/SelectedBubbles.vue.js +84 -0
- package/es/open-code-widget/src/components/SelectedNodes-sfc.css +1 -0
- package/es/open-code-widget/src/components/SelectedNodes.vue.d.ts +2 -0
- package/es/open-code-widget/src/components/SelectedNodes.vue.js +103 -0
- package/es/open-code-widget/src/components/SessionList-sfc.css +1 -0
- package/es/open-code-widget/src/components/SessionList.vue.d.ts +12 -0
- package/es/open-code-widget/src/components/SessionList.vue.js +209 -0
- package/es/open-code-widget/src/components/Trigger-sfc.css +1 -0
- package/es/open-code-widget/src/components/Trigger.vue.d.ts +12 -0
- package/es/open-code-widget/src/components/Trigger.vue.js +66 -0
- package/es/open-code-widget/src/context.d.ts +42 -0
- package/es/open-code-widget/src/context.js +16 -0
- package/es/open-code-widget/src/index-sfc.css +1 -0
- package/es/open-code-widget/src/index.vue.d.ts +83 -0
- package/es/open-code-widget/src/index.vue.js +464 -0
- package/es/open-code-widget/src/types.d.ts +74 -0
- package/es/open-code-widget/src/types.js +0 -0
- package/es/open-code-widget/style/index-pure.d.ts +0 -0
- package/es/open-code-widget/style/index-pure.js +0 -0
- package/es/open-code-widget/style/index.d.ts +0 -0
- package/es/open-code-widget/style/index.js +0 -0
- package/es/open-code-widget/style/less-pure.d.ts +0 -0
- package/es/open-code-widget/style/less-pure.js +0 -0
- package/es/open-code-widget/style/less.d.ts +0 -0
- package/es/open-code-widget/style/less.js +0 -0
- package/lib/@vite-plugin-opencode-assistant/components.cjs.js +1322 -0
- package/lib/@vite-plugin-opencode-assistant/components.es.js +1315 -0
- package/lib/components.css +9 -0
- package/lib/env.d.ts +10 -0
- package/lib/index.css +0 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +50 -0
- package/lib/index.less +0 -0
- package/lib/open-code-widget/composables/use-inspector.d.ts +52 -0
- package/lib/open-code-widget/composables/use-inspector.js +207 -0
- package/lib/open-code-widget/composables/use-selection.d.ts +19 -0
- package/lib/open-code-widget/composables/use-selection.js +161 -0
- package/lib/open-code-widget/composables/use-session.d.ts +16 -0
- package/lib/open-code-widget/composables/use-session.js +87 -0
- package/lib/open-code-widget/composables/use-widget.d.ts +24 -0
- package/lib/open-code-widget/composables/use-widget.js +63 -0
- package/lib/open-code-widget/index.d.ts +3 -0
- package/lib/open-code-widget/index.js +36 -0
- package/lib/open-code-widget/src/components/Frame-sfc.css +1 -0
- package/lib/open-code-widget/src/components/Frame.vue.d.ts +16 -0
- package/lib/open-code-widget/src/components/Frame.vue.js +139 -0
- package/lib/open-code-widget/src/components/Header-sfc.css +1 -0
- package/lib/open-code-widget/src/components/Header.vue.d.ts +16 -0
- package/lib/open-code-widget/src/components/Header.vue.js +159 -0
- package/lib/open-code-widget/src/components/SelectHint-sfc.css +1 -0
- package/lib/open-code-widget/src/components/SelectHint.vue.d.ts +2 -0
- package/lib/open-code-widget/src/components/SelectHint.vue.js +65 -0
- package/lib/open-code-widget/src/components/SelectedBubbles-sfc.css +1 -0
- package/lib/open-code-widget/src/components/SelectedBubbles.vue.d.ts +2 -0
- package/lib/open-code-widget/src/components/SelectedBubbles.vue.js +103 -0
- package/lib/open-code-widget/src/components/SelectedNodes-sfc.css +1 -0
- package/lib/open-code-widget/src/components/SelectedNodes.vue.d.ts +2 -0
- package/lib/open-code-widget/src/components/SelectedNodes.vue.js +122 -0
- package/lib/open-code-widget/src/components/SessionList-sfc.css +1 -0
- package/lib/open-code-widget/src/components/SessionList.vue.d.ts +12 -0
- package/lib/open-code-widget/src/components/SessionList.vue.js +228 -0
- package/lib/open-code-widget/src/components/Trigger-sfc.css +1 -0
- package/lib/open-code-widget/src/components/Trigger.vue.d.ts +12 -0
- package/lib/open-code-widget/src/components/Trigger.vue.js +85 -0
- package/lib/open-code-widget/src/context.d.ts +42 -0
- package/lib/open-code-widget/src/context.js +35 -0
- package/lib/open-code-widget/src/index-sfc.css +1 -0
- package/lib/open-code-widget/src/index.vue.d.ts +83 -0
- package/lib/open-code-widget/src/index.vue.js +491 -0
- package/lib/open-code-widget/src/types.d.ts +74 -0
- package/lib/open-code-widget/src/types.js +15 -0
- package/lib/open-code-widget/style/index-pure.d.ts +0 -0
- package/lib/open-code-widget/style/index-pure.js +0 -0
- package/lib/open-code-widget/style/index.d.ts +0 -0
- package/lib/open-code-widget/style/index.js +0 -0
- package/lib/open-code-widget/style/less-pure.d.ts +0 -0
- package/lib/open-code-widget/style/less-pure.js +0 -0
- package/lib/open-code-widget/style/less.d.ts +0 -0
- package/lib/open-code-widget/style/less.js +0 -0
- package/lib/web-types.json +1 -0
- package/package.json +46 -0
package/es/env.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/// <reference lib="dom.iterable" />
|
|
3
|
+
|
|
4
|
+
declare module "*.vue" {
|
|
5
|
+
import type { DefineComponent } from "vue";
|
|
6
|
+
|
|
7
|
+
const component: DefineComponent<Record<string, never>, Record<string, never>, unknown>;
|
|
8
|
+
|
|
9
|
+
export default component;
|
|
10
|
+
}
|
package/es/index.d.ts
ADDED
package/es/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import OpenCodeWidget from "./open-code-widget";
|
|
2
|
+
const version = "1.0.5";
|
|
3
|
+
function install(app, options) {
|
|
4
|
+
const components = [
|
|
5
|
+
OpenCodeWidget
|
|
6
|
+
];
|
|
7
|
+
components.forEach((item) => {
|
|
8
|
+
if (item.install) {
|
|
9
|
+
app.use(item, options);
|
|
10
|
+
} else if (item.name) {
|
|
11
|
+
app.component(item.name, item);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
var es_default = install;
|
|
16
|
+
export {
|
|
17
|
+
OpenCodeWidget,
|
|
18
|
+
es_default as default,
|
|
19
|
+
install,
|
|
20
|
+
version
|
|
21
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { OpenCodeSelectedElement } from "../src/types";
|
|
3
|
+
interface VueInspector {
|
|
4
|
+
getTargetNode: (e: MouseEvent) => {
|
|
5
|
+
targetNode: Element | null;
|
|
6
|
+
params: {
|
|
7
|
+
file?: string;
|
|
8
|
+
line?: number;
|
|
9
|
+
column?: number;
|
|
10
|
+
} | null;
|
|
11
|
+
};
|
|
12
|
+
handleClick: (e: MouseEvent) => void;
|
|
13
|
+
enable: () => void;
|
|
14
|
+
disable: () => void;
|
|
15
|
+
__opencode_hooked?: boolean;
|
|
16
|
+
}
|
|
17
|
+
declare global {
|
|
18
|
+
interface Window {
|
|
19
|
+
__VUE_INSPECTOR__?: VueInspector;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
interface UseInspectorOptions {
|
|
23
|
+
selectMode: Ref<boolean>;
|
|
24
|
+
onAddSelectedNode: (element: OpenCodeSelectedElement) => void;
|
|
25
|
+
onExitSelectMode: () => void;
|
|
26
|
+
}
|
|
27
|
+
export declare function useInspector(options: UseInspectorOptions): {
|
|
28
|
+
highlightVisible: Ref<boolean, boolean>;
|
|
29
|
+
highlightStyle: Ref<Record<string, string>, Record<string, string>>;
|
|
30
|
+
tooltipVisible: Ref<boolean, boolean>;
|
|
31
|
+
tooltipStyle: Ref<{
|
|
32
|
+
top: string;
|
|
33
|
+
left: string;
|
|
34
|
+
}, {
|
|
35
|
+
top: string;
|
|
36
|
+
left: string;
|
|
37
|
+
} | {
|
|
38
|
+
top: string;
|
|
39
|
+
left: string;
|
|
40
|
+
}>;
|
|
41
|
+
tooltipContent: Ref<{
|
|
42
|
+
description: string;
|
|
43
|
+
fileInfo: string;
|
|
44
|
+
}, {
|
|
45
|
+
description: string;
|
|
46
|
+
fileInfo: string;
|
|
47
|
+
} | {
|
|
48
|
+
description: string;
|
|
49
|
+
fileInfo: string;
|
|
50
|
+
}>;
|
|
51
|
+
};
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { ref, watch, onMounted, onUnmounted } from "vue";
|
|
2
|
+
function truncate(str, maxLength) {
|
|
3
|
+
if (!str) return "";
|
|
4
|
+
return str.length > maxLength ? str.substring(0, maxLength) + "..." : str;
|
|
5
|
+
}
|
|
6
|
+
function getDirectText(element) {
|
|
7
|
+
let text = "";
|
|
8
|
+
for (let i = 0; i < element.childNodes.length; i++) {
|
|
9
|
+
const child = element.childNodes[i];
|
|
10
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
11
|
+
text += child.textContent || "";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return text.trim();
|
|
15
|
+
}
|
|
16
|
+
function getElementDescription(element) {
|
|
17
|
+
const tag = element.tagName.toLowerCase();
|
|
18
|
+
const parts = [tag];
|
|
19
|
+
const id = element.id;
|
|
20
|
+
if (id) parts.push(`#${id}`);
|
|
21
|
+
if (typeof element.className === "string") {
|
|
22
|
+
const className = element.className.trim().split(/\s+/).filter(Boolean).slice(0, 2).join(".");
|
|
23
|
+
if (className) parts.push(`.${className}`);
|
|
24
|
+
}
|
|
25
|
+
const name = element.getAttribute("name");
|
|
26
|
+
if (name) parts.push(`[name="${name}"]`);
|
|
27
|
+
const placeholder = element.getAttribute("placeholder");
|
|
28
|
+
if (placeholder) parts.push(`[placeholder="${placeholder.substring(0, 20)}"]`);
|
|
29
|
+
const src = element.getAttribute("src");
|
|
30
|
+
if (src) parts.push(`[src]`);
|
|
31
|
+
const href = element.getAttribute("href");
|
|
32
|
+
if (href && href !== "#") parts.push(`[href]`);
|
|
33
|
+
return parts.join("");
|
|
34
|
+
}
|
|
35
|
+
function useInspector(options) {
|
|
36
|
+
const highlightVisible = ref(false);
|
|
37
|
+
const highlightStyle = ref({
|
|
38
|
+
top: "0px",
|
|
39
|
+
left: "0px",
|
|
40
|
+
width: "0px",
|
|
41
|
+
height: "0px"
|
|
42
|
+
});
|
|
43
|
+
const tooltipVisible = ref(false);
|
|
44
|
+
const tooltipStyle = ref({ top: "0px", left: "0px" });
|
|
45
|
+
const tooltipContent = ref({ description: "", fileInfo: "" });
|
|
46
|
+
const INSPECTOR_CHECK_INTERVAL = 500;
|
|
47
|
+
let inspectorCheckTimer = null;
|
|
48
|
+
function handleMouseMove(e) {
|
|
49
|
+
if (!options.selectMode.value) return;
|
|
50
|
+
const inspector = window.__VUE_INSPECTOR__;
|
|
51
|
+
if (!inspector) return;
|
|
52
|
+
const { targetNode, params } = inspector.getTargetNode(e);
|
|
53
|
+
if (targetNode && params) {
|
|
54
|
+
const rect = targetNode.getBoundingClientRect();
|
|
55
|
+
const widget = document.querySelector(".opencode-widget");
|
|
56
|
+
let primary = "#3b82f6";
|
|
57
|
+
let primaryBg = "rgba(59, 130, 246, 0.1)";
|
|
58
|
+
if (widget) {
|
|
59
|
+
const style = getComputedStyle(widget);
|
|
60
|
+
primary = style.getPropertyValue("--oc-primary").trim() || primary;
|
|
61
|
+
primaryBg = style.getPropertyValue("--oc-primary-bg").trim() || primaryBg;
|
|
62
|
+
}
|
|
63
|
+
highlightVisible.value = true;
|
|
64
|
+
highlightStyle.value = {
|
|
65
|
+
top: `${rect.top}px`,
|
|
66
|
+
left: `${rect.left}px`,
|
|
67
|
+
width: `${rect.width}px`,
|
|
68
|
+
height: `${rect.height}px`,
|
|
69
|
+
border: `2px solid ${primary}`,
|
|
70
|
+
background: primaryBg
|
|
71
|
+
};
|
|
72
|
+
const description = getElementDescription(targetNode);
|
|
73
|
+
const fileName = params.file ? params.file.split("/").pop() : "";
|
|
74
|
+
let lineInfo = "";
|
|
75
|
+
if (params.line) {
|
|
76
|
+
lineInfo = `:${params.line}`;
|
|
77
|
+
if (params.column) {
|
|
78
|
+
lineInfo += `:${params.column}`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
tooltipContent.value = {
|
|
82
|
+
description,
|
|
83
|
+
fileInfo: fileName ? `${fileName}${lineInfo}` : ""
|
|
84
|
+
};
|
|
85
|
+
tooltipVisible.value = true;
|
|
86
|
+
const tooltipHeight = 50;
|
|
87
|
+
const tooltipWidth = 200;
|
|
88
|
+
let tooltipTop = rect.top - tooltipHeight - 8;
|
|
89
|
+
let tooltipLeft = rect.left;
|
|
90
|
+
if (tooltipTop < 10) {
|
|
91
|
+
tooltipTop = rect.bottom + 8;
|
|
92
|
+
}
|
|
93
|
+
if (tooltipLeft + tooltipWidth > window.innerWidth - 10) {
|
|
94
|
+
tooltipLeft = window.innerWidth - tooltipWidth - 10;
|
|
95
|
+
}
|
|
96
|
+
tooltipStyle.value = {
|
|
97
|
+
top: `${tooltipTop}px`,
|
|
98
|
+
left: `${tooltipLeft}px`
|
|
99
|
+
};
|
|
100
|
+
} else {
|
|
101
|
+
highlightVisible.value = false;
|
|
102
|
+
tooltipVisible.value = false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function setupInspectorHook() {
|
|
106
|
+
const inspector = window.__VUE_INSPECTOR__;
|
|
107
|
+
if (!inspector || inspector.__opencode_hooked) return;
|
|
108
|
+
const originalHandleClick = inspector.handleClick.bind(inspector);
|
|
109
|
+
inspector.handleClick = function(e) {
|
|
110
|
+
var _a, _b, _c;
|
|
111
|
+
if (options.selectMode.value) {
|
|
112
|
+
const { targetNode, params } = inspector.getTargetNode(e);
|
|
113
|
+
if (targetNode && params) {
|
|
114
|
+
const innerText = getDirectText(targetNode);
|
|
115
|
+
const description = getElementDescription(targetNode);
|
|
116
|
+
const elementInfo = {
|
|
117
|
+
filePath: (_a = params.file) != null ? _a : null,
|
|
118
|
+
line: (_b = params.line) != null ? _b : null,
|
|
119
|
+
column: (_c = params.column) != null ? _c : null,
|
|
120
|
+
innerText: truncate(innerText, 200),
|
|
121
|
+
description
|
|
122
|
+
};
|
|
123
|
+
options.onAddSelectedNode(elementInfo);
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
return originalHandleClick.call(inspector, e);
|
|
128
|
+
};
|
|
129
|
+
inspector.__opencode_hooked = true;
|
|
130
|
+
}
|
|
131
|
+
function handleKeydown(e) {
|
|
132
|
+
if (e.key === "Escape" && options.selectMode.value) {
|
|
133
|
+
e.preventDefault();
|
|
134
|
+
e.stopPropagation();
|
|
135
|
+
options.onExitSelectMode();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
watch(options.selectMode, (newVal) => {
|
|
139
|
+
const inspector = window.__VUE_INSPECTOR__;
|
|
140
|
+
if (newVal) {
|
|
141
|
+
if (inspector) {
|
|
142
|
+
inspector.enable();
|
|
143
|
+
}
|
|
144
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
145
|
+
document.addEventListener("keydown", handleKeydown, true);
|
|
146
|
+
} else {
|
|
147
|
+
if (inspector) {
|
|
148
|
+
inspector.disable();
|
|
149
|
+
}
|
|
150
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
151
|
+
document.removeEventListener("keydown", handleKeydown, true);
|
|
152
|
+
highlightVisible.value = false;
|
|
153
|
+
tooltipVisible.value = false;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
onMounted(() => {
|
|
157
|
+
if (window.__VUE_INSPECTOR__) {
|
|
158
|
+
setupInspectorHook();
|
|
159
|
+
} else {
|
|
160
|
+
inspectorCheckTimer = window.setInterval(() => {
|
|
161
|
+
if (window.__VUE_INSPECTOR__) {
|
|
162
|
+
setupInspectorHook();
|
|
163
|
+
if (inspectorCheckTimer) {
|
|
164
|
+
window.clearInterval(inspectorCheckTimer);
|
|
165
|
+
inspectorCheckTimer = null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}, INSPECTOR_CHECK_INTERVAL);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
onUnmounted(() => {
|
|
172
|
+
if (inspectorCheckTimer) {
|
|
173
|
+
window.clearInterval(inspectorCheckTimer);
|
|
174
|
+
}
|
|
175
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
176
|
+
document.removeEventListener("keydown", handleKeydown, true);
|
|
177
|
+
});
|
|
178
|
+
return {
|
|
179
|
+
highlightVisible,
|
|
180
|
+
highlightStyle,
|
|
181
|
+
tooltipVisible,
|
|
182
|
+
tooltipStyle,
|
|
183
|
+
tooltipContent
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
export {
|
|
187
|
+
useInspector
|
|
188
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { OpenCodeRemoveSelectedPayload, OpenCodeSelectedElement, OpenCodeSelectedElementItem } from "../src/types";
|
|
3
|
+
export interface UseSelectionOptions {
|
|
4
|
+
selectMode: Ref<boolean>;
|
|
5
|
+
selectedElements: Ref<OpenCodeSelectedElement[]>;
|
|
6
|
+
onToggleSelectMode: (mode: boolean) => void;
|
|
7
|
+
onRemoveSelectedNode: (payload: OpenCodeRemoveSelectedPayload) => void;
|
|
8
|
+
onClearSelectedNodes: () => void;
|
|
9
|
+
showConfirmDialog: (message: string) => Promise<boolean>;
|
|
10
|
+
}
|
|
11
|
+
export declare function useSelection(options: UseSelectionOptions): {
|
|
12
|
+
bubbleVisible: import("vue").ComputedRef<boolean>;
|
|
13
|
+
hasSelectedElements: import("vue").ComputedRef<boolean>;
|
|
14
|
+
selectedElementItems: import("vue").ComputedRef<OpenCodeSelectedElementItem[]>;
|
|
15
|
+
handleClearSelectedNodes: () => Promise<void>;
|
|
16
|
+
handleClickSelectedNode: (item: OpenCodeSelectedElementItem) => void;
|
|
17
|
+
handleRemoveSelectedNode: (item: OpenCodeSelectedElementItem, index: number, source: OpenCodeRemoveSelectedPayload["source"]) => void;
|
|
18
|
+
handleToggleSelectMode: () => void;
|
|
19
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import { computed } from "vue";
|
|
22
|
+
function truncate(value, maxLength) {
|
|
23
|
+
if (value.length <= maxLength) {
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
return `${value.slice(0, maxLength)}...`;
|
|
27
|
+
}
|
|
28
|
+
function getElementKey(element, index) {
|
|
29
|
+
var _a;
|
|
30
|
+
if (element.filePath && element.line) {
|
|
31
|
+
return `${element.filePath}:${element.line}:${(_a = element.column) != null ? _a : 0}`;
|
|
32
|
+
}
|
|
33
|
+
return `${element.description}-${index}`;
|
|
34
|
+
}
|
|
35
|
+
function getBubbleFileText(element) {
|
|
36
|
+
var _a;
|
|
37
|
+
const fileName = ((_a = element.filePath) == null ? void 0 : _a.split("/").pop()) || "";
|
|
38
|
+
const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
|
|
39
|
+
return `${fileName}${lineInfo}`;
|
|
40
|
+
}
|
|
41
|
+
function getPanelFileText(element) {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const fileName = ((_a = element.filePath) == null ? void 0 : _a.split("/").pop()) || "\u672A\u77E5\u6587\u4EF6";
|
|
44
|
+
const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
|
|
45
|
+
const textPreview = ((_b = element.innerText) == null ? void 0 : _b.trim()) ? `${truncate(element.innerText.trim(), 30)} \xB7 ` : "";
|
|
46
|
+
return `${textPreview}${fileName}${lineInfo}`;
|
|
47
|
+
}
|
|
48
|
+
function useSelection(options) {
|
|
49
|
+
const bubbleVisible = computed(() => options.selectMode.value);
|
|
50
|
+
const selectedElementItems = computed(
|
|
51
|
+
() => (options.selectedElements.value || []).map(
|
|
52
|
+
(element, index) => ({
|
|
53
|
+
key: getElementKey(element, index),
|
|
54
|
+
description: element.description || "\u672A\u77E5\u5143\u7D20",
|
|
55
|
+
bubbleFileText: getBubbleFileText(element),
|
|
56
|
+
panelFileText: getPanelFileText(element),
|
|
57
|
+
element
|
|
58
|
+
})
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
const hasSelectedElements = computed(() => selectedElementItems.value.length > 0);
|
|
62
|
+
function handleToggleSelectMode() {
|
|
63
|
+
options.onToggleSelectMode(!options.selectMode.value);
|
|
64
|
+
}
|
|
65
|
+
function handleClickSelectedNode(item) {
|
|
66
|
+
const description = item.element.description;
|
|
67
|
+
if (!description) return;
|
|
68
|
+
let targetElement = null;
|
|
69
|
+
if (description.includes("#")) {
|
|
70
|
+
const idMatch = description.match(/#([^.[\s]+)/);
|
|
71
|
+
if (idMatch) {
|
|
72
|
+
targetElement = document.getElementById(idMatch[1]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!targetElement && description.includes(".")) {
|
|
76
|
+
const classMatch = description.match(/^([a-z]+)\.([^[\s]+)/i);
|
|
77
|
+
if (classMatch) {
|
|
78
|
+
const tagName = classMatch[1];
|
|
79
|
+
const classes = classMatch[2].split(".").filter(Boolean);
|
|
80
|
+
const selector = `${tagName}.${classes.join(".")}`;
|
|
81
|
+
targetElement = document.querySelector(selector);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!targetElement) {
|
|
85
|
+
const tagMatch = description.match(/^([a-z]+)/i);
|
|
86
|
+
if (tagMatch) {
|
|
87
|
+
const simpleSelector = description.split(/[.[\s]/)[0];
|
|
88
|
+
targetElement = document.querySelector(simpleSelector);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (targetElement) {
|
|
92
|
+
targetElement.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
93
|
+
const highlightOverlay = document.createElement("div");
|
|
94
|
+
highlightOverlay.className = "opencode-element-highlight-temp";
|
|
95
|
+
const widget = document.querySelector(".opencode-widget");
|
|
96
|
+
let primary = "#3b82f6";
|
|
97
|
+
let primaryBg = "rgba(59, 130, 246, 0.1)";
|
|
98
|
+
if (widget) {
|
|
99
|
+
const style = getComputedStyle(widget);
|
|
100
|
+
primary = style.getPropertyValue("--oc-primary").trim() || primary;
|
|
101
|
+
primaryBg = style.getPropertyValue("--oc-primary-bg").trim() || primaryBg;
|
|
102
|
+
}
|
|
103
|
+
highlightOverlay.style.border = `2px solid ${primary}`;
|
|
104
|
+
highlightOverlay.style.background = primaryBg;
|
|
105
|
+
const rect = targetElement.getBoundingClientRect();
|
|
106
|
+
highlightOverlay.style.top = `${rect.top + window.scrollY}px`;
|
|
107
|
+
highlightOverlay.style.left = `${rect.left + window.scrollX}px`;
|
|
108
|
+
highlightOverlay.style.width = `${rect.width}px`;
|
|
109
|
+
highlightOverlay.style.height = `${rect.height}px`;
|
|
110
|
+
document.body.appendChild(highlightOverlay);
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
highlightOverlay.remove();
|
|
113
|
+
}, 2e3);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function handleRemoveSelectedNode(item, index, source) {
|
|
117
|
+
options.onRemoveSelectedNode({ element: item.element, index, source });
|
|
118
|
+
}
|
|
119
|
+
function handleClearSelectedNodes() {
|
|
120
|
+
return __async(this, null, function* () {
|
|
121
|
+
if (!options.selectedElements.value || options.selectedElements.value.length === 0) return;
|
|
122
|
+
const confirmed = yield options.showConfirmDialog(
|
|
123
|
+
`\u786E\u5B9A\u8981\u6E05\u7A7A\u6240\u6709 ${options.selectedElements.value.length} \u4E2A\u5DF2\u9009\u8282\u70B9\u5417\uFF1F`
|
|
124
|
+
);
|
|
125
|
+
if (confirmed) {
|
|
126
|
+
options.onClearSelectedNodes();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
bubbleVisible,
|
|
132
|
+
hasSelectedElements,
|
|
133
|
+
selectedElementItems,
|
|
134
|
+
handleClearSelectedNodes,
|
|
135
|
+
handleClickSelectedNode,
|
|
136
|
+
handleRemoveSelectedNode,
|
|
137
|
+
handleToggleSelectMode
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
useSelection
|
|
142
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { OpenCodeWidgetSession, OpenCodeWidgetSessionItem } from "../src/types";
|
|
3
|
+
export interface UseSessionOptions {
|
|
4
|
+
sessions: Ref<OpenCodeWidgetSession[]>;
|
|
5
|
+
currentSessionId: Ref<string | number | null>;
|
|
6
|
+
onCreateSession: () => void;
|
|
7
|
+
onSelectSession: (session: OpenCodeWidgetSession) => void;
|
|
8
|
+
onDeleteSession: (session: OpenCodeWidgetSession) => void;
|
|
9
|
+
showConfirmDialog: (message: string) => Promise<boolean>;
|
|
10
|
+
}
|
|
11
|
+
export declare function useSession(options: UseSessionOptions): {
|
|
12
|
+
sessionItems: import("vue").ComputedRef<OpenCodeWidgetSessionItem[]>;
|
|
13
|
+
handleCreateSession: () => void;
|
|
14
|
+
handleDeleteSession: (item: OpenCodeWidgetSessionItem) => Promise<void>;
|
|
15
|
+
handleSelectSession: (item: OpenCodeWidgetSessionItem) => void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import { computed } from "vue";
|
|
22
|
+
function formatSessionMeta(session) {
|
|
23
|
+
if (session.meta) {
|
|
24
|
+
return session.meta;
|
|
25
|
+
}
|
|
26
|
+
if (!session.updatedAt) {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
const date = new Date(session.updatedAt);
|
|
30
|
+
if (Number.isNaN(date.getTime())) {
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
|
34
|
+
}
|
|
35
|
+
function useSession(options) {
|
|
36
|
+
const sessionItems = computed(
|
|
37
|
+
() => (options.sessions.value || []).map((session) => ({
|
|
38
|
+
key: session.id,
|
|
39
|
+
title: session.title || "\u65B0\u4F1A\u8BDD",
|
|
40
|
+
meta: formatSessionMeta(session),
|
|
41
|
+
active: session.id === options.currentSessionId.value,
|
|
42
|
+
session
|
|
43
|
+
}))
|
|
44
|
+
);
|
|
45
|
+
function handleCreateSession() {
|
|
46
|
+
options.onCreateSession();
|
|
47
|
+
}
|
|
48
|
+
function handleSelectSession(item) {
|
|
49
|
+
options.onSelectSession(item.session);
|
|
50
|
+
}
|
|
51
|
+
function handleDeleteSession(item) {
|
|
52
|
+
return __async(this, null, function* () {
|
|
53
|
+
const confirmed = yield options.showConfirmDialog(`\u786E\u5B9A\u8981\u5220\u9664\u4F1A\u8BDD "${item.title}" \u5417\uFF1F`);
|
|
54
|
+
if (confirmed) {
|
|
55
|
+
options.onDeleteSession(item.session);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
sessionItems,
|
|
61
|
+
handleCreateSession,
|
|
62
|
+
handleDeleteSession,
|
|
63
|
+
handleSelectSession
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
useSession
|
|
68
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
export interface UseWidgetOptions {
|
|
3
|
+
position: Ref<string>;
|
|
4
|
+
theme: Ref<string>;
|
|
5
|
+
open: Ref<boolean>;
|
|
6
|
+
selectMode: Ref<boolean>;
|
|
7
|
+
iframeSrc: Ref<string>;
|
|
8
|
+
sessionListCollapsed: Ref<boolean>;
|
|
9
|
+
onToggle: (nextOpen: boolean) => void;
|
|
10
|
+
onToggleSelectMode?: (mode: boolean) => void;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
onToggleSessionList: (collapsed: boolean) => void;
|
|
13
|
+
onEmptyAction: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function useWidget(options: UseWidgetOptions): {
|
|
16
|
+
buttonActive: import("vue").ComputedRef<boolean>;
|
|
17
|
+
containerClasses: import("vue").ComputedRef<string[]>;
|
|
18
|
+
iframeSource: import("vue").ComputedRef<string>;
|
|
19
|
+
sessionListTitle: import("vue").ComputedRef<"展开会话列表" | "折叠会话列表">;
|
|
20
|
+
handleClose: () => void;
|
|
21
|
+
handleEmptyAction: () => void;
|
|
22
|
+
handleToggle: () => void;
|
|
23
|
+
handleToggleSessionList: () => void;
|
|
24
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
function useWidget(options) {
|
|
3
|
+
const containerClasses = computed(() => [
|
|
4
|
+
"opencode-widget",
|
|
5
|
+
options.position.value,
|
|
6
|
+
`opencode-theme-${options.theme.value}`
|
|
7
|
+
]);
|
|
8
|
+
const buttonActive = computed(() => !!(options.open.value || options.selectMode.value));
|
|
9
|
+
const iframeSource = computed(() => options.iframeSrc.value || "about:blank");
|
|
10
|
+
const sessionListTitle = computed(
|
|
11
|
+
() => options.sessionListCollapsed.value ? "\u5C55\u5F00\u4F1A\u8BDD\u5217\u8868" : "\u6298\u53E0\u4F1A\u8BDD\u5217\u8868"
|
|
12
|
+
);
|
|
13
|
+
function handleToggle() {
|
|
14
|
+
var _a;
|
|
15
|
+
if (options.selectMode.value) {
|
|
16
|
+
(_a = options.onToggleSelectMode) == null ? void 0 : _a.call(options, false);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const nextOpen = !options.open.value;
|
|
20
|
+
options.onToggle(nextOpen);
|
|
21
|
+
}
|
|
22
|
+
function handleClose() {
|
|
23
|
+
options.onClose();
|
|
24
|
+
}
|
|
25
|
+
function handleToggleSessionList() {
|
|
26
|
+
options.onToggleSessionList(!options.sessionListCollapsed.value);
|
|
27
|
+
}
|
|
28
|
+
function handleEmptyAction() {
|
|
29
|
+
options.onEmptyAction();
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
buttonActive,
|
|
33
|
+
containerClasses,
|
|
34
|
+
iframeSource,
|
|
35
|
+
sessionListTitle,
|
|
36
|
+
handleClose,
|
|
37
|
+
handleEmptyAction,
|
|
38
|
+
handleToggle,
|
|
39
|
+
handleToggleSessionList
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
useWidget
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.opencode-iframe-container{flex:1;position:relative;overflow:hidden;display:flex;flex-direction:column;margin-top:-42px}.opencode-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-overlay-bg);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:10;transition:opacity .3s ease}.opencode-loading-overlay.visible{display:flex}.opencode-loading-spinner{width:40px;height:40px;border:3px solid var(--oc-border-primary);border-top-color:var(--oc-primary);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.opencode-loading-text{margin-top:12px;font-size:14px;color:var(--oc-text-placeholder)}.opencode-empty-state-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-bg-secondary);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:5;transition:opacity .3s ease;margin-top:42px}.opencode-empty-state-overlay.visible{display:flex}.opencode-empty-state-icon{color:var(--oc-text-placeholder);margin-bottom:16px}.opencode-empty-state-text{color:var(--oc-text-primary);font-size:16px;font-weight:500;margin-bottom:24px}.opencode-empty-state-btn{padding:10px 24px;border-radius:8px;border:none;background:var(--oc-primary);color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;box-shadow:var(--oc-shadow-primary)}.opencode-empty-state-btn:hover{background:var(--oc-primary-hover);transform:translateY(-1px);box-shadow:var(--oc-shadow-primary-hover)}.opencode-empty-state-btn:active{transform:translateY(0)}.opencode-iframe{width:100%;height:100%;border:none}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
'empty-state'?: (props: typeof __VLS_1) => any;
|
|
4
|
+
} & {
|
|
5
|
+
loading?: (props: typeof __VLS_3) => any;
|
|
6
|
+
} & {
|
|
7
|
+
content?: (props: typeof __VLS_5) => any;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
11
|
+
export default _default;
|
|
12
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
13
|
+
new (): {
|
|
14
|
+
$slots: S;
|
|
15
|
+
};
|
|
16
|
+
};
|