fixdog 0.0.1
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/README.md +478 -0
- package/USAGE.md +77 -0
- package/dist/client/index.d.mts +110 -0
- package/dist/client/index.d.ts +110 -0
- package/dist/client/index.js +1601 -0
- package/dist/client/index.mjs +1582 -0
- package/dist/client/init.d.mts +67 -0
- package/dist/client/init.d.ts +67 -0
- package/dist/client/init.js +1609 -0
- package/dist/client/init.mjs +1593 -0
- package/dist/index.d.mts +158 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.js +1635 -0
- package/dist/index.mjs +1606 -0
- package/package.json +57 -0
- package/src/api/client.ts +141 -0
- package/src/client/index.ts +75 -0
- package/src/client/init.tsx +78 -0
- package/src/components/ConversationalInputReact.tsx +406 -0
- package/src/components/ElementInfoDisplayReact.tsx +84 -0
- package/src/components/UiDogSidebarReact.tsx +49 -0
- package/src/element-detector.ts +186 -0
- package/src/index.ts +228 -0
- package/src/instrument.ts +171 -0
- package/src/sidebar-initializer.ts +171 -0
- package/src/source-resolver.ts +121 -0
- package/src/styles/sidebarStyles.ts +597 -0
- package/src/types/css.d.ts +9 -0
- package/src/types/sidebar.ts +56 -0
- package/src/types.ts +119 -0
- package/tsconfig.json +23 -0
- package/tsup.config.ts +40 -0
|
@@ -0,0 +1,1601 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/client/index.ts
|
|
21
|
+
var client_exports = {};
|
|
22
|
+
__export(client_exports, {
|
|
23
|
+
configureUiDogNext: () => configureUiDogNext,
|
|
24
|
+
disableAutoInit: () => disableAutoInit,
|
|
25
|
+
initializeUiDogNext: () => initializeUiDogNext
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(client_exports);
|
|
28
|
+
var import_bippy2 = require("bippy");
|
|
29
|
+
|
|
30
|
+
// src/instrument.ts
|
|
31
|
+
var import_bippy = require("bippy");
|
|
32
|
+
var import_source = require("bippy/source");
|
|
33
|
+
var isInstrumented = false;
|
|
34
|
+
function setupBippyInstrumentation() {
|
|
35
|
+
if (isInstrumented)
|
|
36
|
+
return;
|
|
37
|
+
if (typeof window === "undefined")
|
|
38
|
+
return;
|
|
39
|
+
isInstrumented = true;
|
|
40
|
+
(0, import_bippy.instrument)(
|
|
41
|
+
(0, import_bippy.secure)({
|
|
42
|
+
onCommitFiberRoot: (_rendererID, _fiberRoot) => {
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
async function getSourceFromElement(element) {
|
|
48
|
+
try {
|
|
49
|
+
const fiber = (0, import_bippy.getFiberFromHostInstance)(element);
|
|
50
|
+
if (!fiber) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const source = await (0, import_source.getSource)(fiber);
|
|
54
|
+
if (source && source.fileName) {
|
|
55
|
+
if (source.fileName.includes("node_modules") || source.fileName.includes("react-dom") || source.fileName.includes("react/")) {
|
|
56
|
+
return await findUserSourceFromFiber(fiber);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
fileName: source.fileName,
|
|
60
|
+
lineNumber: source.lineNumber ?? 1,
|
|
61
|
+
columnNumber: source.columnNumber ?? 1,
|
|
62
|
+
functionName: source.functionName ?? void 0
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return await findUserSourceFromFiber(fiber);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.warn("[UiDog Next] Error getting source from element:", error);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function findUserSourceFromFiber(startFiber) {
|
|
72
|
+
let result = null;
|
|
73
|
+
(0, import_bippy.traverseFiber)(
|
|
74
|
+
startFiber,
|
|
75
|
+
async (fiber) => {
|
|
76
|
+
if ((0, import_bippy.isCompositeFiber)(fiber)) {
|
|
77
|
+
try {
|
|
78
|
+
const source = await (0, import_source.getSource)(fiber);
|
|
79
|
+
if (source && source.fileName) {
|
|
80
|
+
if (!source.fileName.includes("node_modules") && !source.fileName.includes("react-dom") && !source.fileName.includes("react/")) {
|
|
81
|
+
result = {
|
|
82
|
+
fileName: source.fileName,
|
|
83
|
+
lineNumber: source.lineNumber ?? 1,
|
|
84
|
+
columnNumber: source.columnNumber ?? 1,
|
|
85
|
+
functionName: source.functionName ?? (0, import_bippy.getDisplayName)(fiber) ?? void 0
|
|
86
|
+
};
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
},
|
|
95
|
+
true
|
|
96
|
+
// Traverse upward (toward root)
|
|
97
|
+
);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
function getComponentNameFromFiber(fiber) {
|
|
101
|
+
if (!fiber)
|
|
102
|
+
return "Unknown";
|
|
103
|
+
const displayName = (0, import_bippy.getDisplayName)(fiber);
|
|
104
|
+
if (displayName && displayName !== "Unknown") {
|
|
105
|
+
return displayName;
|
|
106
|
+
}
|
|
107
|
+
let componentName = "Unknown";
|
|
108
|
+
(0, import_bippy.traverseFiber)(
|
|
109
|
+
fiber,
|
|
110
|
+
(f) => {
|
|
111
|
+
if ((0, import_bippy.isCompositeFiber)(f)) {
|
|
112
|
+
const name = (0, import_bippy.getDisplayName)(f);
|
|
113
|
+
if (name && name !== "Unknown") {
|
|
114
|
+
componentName = name;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
},
|
|
120
|
+
true
|
|
121
|
+
// Traverse upward
|
|
122
|
+
);
|
|
123
|
+
return componentName;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/source-resolver.ts
|
|
127
|
+
var EDITOR_SCHEMES = {
|
|
128
|
+
vscode: "vscode://file/{path}:{line}:{column}",
|
|
129
|
+
"vscode-insiders": "vscode-insiders://file/{path}:{line}:{column}",
|
|
130
|
+
cursor: "cursor://file/{path}:{line}:{column}",
|
|
131
|
+
webstorm: "webstorm://open?file={path}&line={line}&column={column}",
|
|
132
|
+
atom: "atom://core/open/file?filename={path}&line={line}&column={column}",
|
|
133
|
+
sublime: "subl://open?url=file://{path}&line={line}&column={column}"
|
|
134
|
+
};
|
|
135
|
+
function buildEditorUrl(source, editor = "cursor", projectPath = "") {
|
|
136
|
+
const template = EDITOR_SCHEMES[editor] || EDITOR_SCHEMES.cursor;
|
|
137
|
+
let fullPath = normalizeFileName(source.fileName);
|
|
138
|
+
if (projectPath && !fullPath.startsWith("/")) {
|
|
139
|
+
const normalizedProjectPath = projectPath.endsWith("/") ? projectPath.slice(0, -1) : projectPath;
|
|
140
|
+
fullPath = `${normalizedProjectPath}/${fullPath}`;
|
|
141
|
+
}
|
|
142
|
+
return template.replace("{path}", fullPath).replace("{line}", String(source.lineNumber || 1)).replace("{column}", String(source.columnNumber || 1));
|
|
143
|
+
}
|
|
144
|
+
function normalizeFileName(fileName) {
|
|
145
|
+
if (!fileName)
|
|
146
|
+
return "";
|
|
147
|
+
let normalized = fileName;
|
|
148
|
+
const prefixPatterns = [
|
|
149
|
+
/^webpack:\/\/[^/]*\//,
|
|
150
|
+
/^webpack-internal:\/\/\//,
|
|
151
|
+
/^file:\/\//,
|
|
152
|
+
/^about:react/,
|
|
153
|
+
/^\.\//,
|
|
154
|
+
/^https?:\/\/localhost:\d+\//,
|
|
155
|
+
/^https?:\/\/[^/]+\/@fs\//,
|
|
156
|
+
/^https?:\/\/[^/]+\//,
|
|
157
|
+
/^\/@fs\//,
|
|
158
|
+
/^@fs\//
|
|
159
|
+
];
|
|
160
|
+
for (const pattern of prefixPatterns) {
|
|
161
|
+
normalized = normalized.replace(pattern, "");
|
|
162
|
+
}
|
|
163
|
+
normalized = normalized.split("?")[0].split("#")[0];
|
|
164
|
+
normalized = normalized.replace(/^\/+/, "/");
|
|
165
|
+
return normalized;
|
|
166
|
+
}
|
|
167
|
+
function isSourceFile(fileName) {
|
|
168
|
+
if (!fileName)
|
|
169
|
+
return false;
|
|
170
|
+
const normalized = normalizeFileName(fileName);
|
|
171
|
+
const excludePatterns = [
|
|
172
|
+
/node_modules/,
|
|
173
|
+
/react-dom/,
|
|
174
|
+
/^react\//,
|
|
175
|
+
/\.next\//,
|
|
176
|
+
/_next\//,
|
|
177
|
+
/webpack/,
|
|
178
|
+
/@vite\//,
|
|
179
|
+
/vite\/client/,
|
|
180
|
+
/\[eval\]/,
|
|
181
|
+
/<anonymous>/
|
|
182
|
+
];
|
|
183
|
+
for (const pattern of excludePatterns) {
|
|
184
|
+
if (pattern.test(normalized)) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const includeExtensions = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
|
|
189
|
+
return includeExtensions.some(
|
|
190
|
+
(ext) => normalized.toLowerCase().endsWith(ext)
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/element-detector.ts
|
|
195
|
+
var detectorCleanup = null;
|
|
196
|
+
var isSetup = false;
|
|
197
|
+
function setupElementDetector(options) {
|
|
198
|
+
const { onElementSelected, modifier = "alt" } = options;
|
|
199
|
+
if (detectorCleanup) {
|
|
200
|
+
detectorCleanup();
|
|
201
|
+
}
|
|
202
|
+
isSetup = true;
|
|
203
|
+
const handleClick = async (event) => {
|
|
204
|
+
const modifierPressed = modifier === "alt" && event.altKey || modifier === "ctrl" && event.ctrlKey || modifier === "meta" && event.metaKey || modifier === "shift" && event.shiftKey;
|
|
205
|
+
if (!modifierPressed)
|
|
206
|
+
return;
|
|
207
|
+
event.preventDefault();
|
|
208
|
+
event.stopPropagation();
|
|
209
|
+
const target = event.target;
|
|
210
|
+
try {
|
|
211
|
+
const source = await getSourceFromElement(target);
|
|
212
|
+
if (source && source.fileName && isSourceFile(source.fileName)) {
|
|
213
|
+
const fiber = (0, import_bippy.getFiberFromHostInstance)(target);
|
|
214
|
+
const componentName = fiber ? getComponentNameFromFiber(fiber) : "Unknown";
|
|
215
|
+
const enrichedSource = {
|
|
216
|
+
...source,
|
|
217
|
+
functionName: source.functionName || componentName
|
|
218
|
+
};
|
|
219
|
+
onElementSelected(enrichedSource, target);
|
|
220
|
+
} else {
|
|
221
|
+
console.info(
|
|
222
|
+
"[UiDog Next] Could not find source for element. Falling back to DOM snapshot (likely server component or library code)."
|
|
223
|
+
);
|
|
224
|
+
onElementSelected(null, target);
|
|
225
|
+
}
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.warn("[UiDog Next] Error detecting element source:", error);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const handleMouseMove = (event) => {
|
|
231
|
+
const modifierPressed = modifier === "alt" && event.altKey || modifier === "ctrl" && event.ctrlKey || modifier === "meta" && event.metaKey || modifier === "shift" && event.shiftKey;
|
|
232
|
+
if (!modifierPressed) {
|
|
233
|
+
removeHighlight();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const target = event.target;
|
|
237
|
+
highlightElement(target);
|
|
238
|
+
};
|
|
239
|
+
const handleKeyUp = (event) => {
|
|
240
|
+
const relevantKey = modifier === "alt" && event.key === "Alt" || modifier === "ctrl" && event.key === "Control" || modifier === "meta" && event.key === "Meta" || modifier === "shift" && event.key === "Shift";
|
|
241
|
+
if (relevantKey) {
|
|
242
|
+
removeHighlight();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
document.addEventListener("click", handleClick, true);
|
|
246
|
+
document.addEventListener("mousemove", handleMouseMove, true);
|
|
247
|
+
document.addEventListener("keyup", handleKeyUp, true);
|
|
248
|
+
detectorCleanup = () => {
|
|
249
|
+
document.removeEventListener("click", handleClick, true);
|
|
250
|
+
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
251
|
+
document.removeEventListener("keyup", handleKeyUp, true);
|
|
252
|
+
removeHighlight();
|
|
253
|
+
isSetup = false;
|
|
254
|
+
};
|
|
255
|
+
return detectorCleanup;
|
|
256
|
+
}
|
|
257
|
+
var currentHighlight = null;
|
|
258
|
+
var highlightOverlay = null;
|
|
259
|
+
function highlightElement(element) {
|
|
260
|
+
if (element === highlightOverlay || highlightOverlay?.contains(element)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (!highlightOverlay) {
|
|
264
|
+
highlightOverlay = document.createElement("div");
|
|
265
|
+
highlightOverlay.id = "uidog-highlight-overlay";
|
|
266
|
+
highlightOverlay.style.cssText = `
|
|
267
|
+
position: fixed;
|
|
268
|
+
pointer-events: none;
|
|
269
|
+
background: rgba(59, 130, 246, 0.2);
|
|
270
|
+
border: 2px solid rgba(59, 130, 246, 0.8);
|
|
271
|
+
border-radius: 4px;
|
|
272
|
+
z-index: 999998;
|
|
273
|
+
transition: all 0.1s ease-out;
|
|
274
|
+
`;
|
|
275
|
+
document.body.appendChild(highlightOverlay);
|
|
276
|
+
}
|
|
277
|
+
const rect = element.getBoundingClientRect();
|
|
278
|
+
highlightOverlay.style.top = `${rect.top}px`;
|
|
279
|
+
highlightOverlay.style.left = `${rect.left}px`;
|
|
280
|
+
highlightOverlay.style.width = `${rect.width}px`;
|
|
281
|
+
highlightOverlay.style.height = `${rect.height}px`;
|
|
282
|
+
highlightOverlay.style.display = "block";
|
|
283
|
+
currentHighlight = element;
|
|
284
|
+
}
|
|
285
|
+
function removeHighlight() {
|
|
286
|
+
if (highlightOverlay) {
|
|
287
|
+
highlightOverlay.style.display = "none";
|
|
288
|
+
}
|
|
289
|
+
currentHighlight = null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// src/sidebar-initializer.ts
|
|
293
|
+
var import_client2 = require("react-dom/client");
|
|
294
|
+
var import_react3 = require("react");
|
|
295
|
+
|
|
296
|
+
// src/components/UiDogSidebarReact.tsx
|
|
297
|
+
var import_react2 = require("react");
|
|
298
|
+
|
|
299
|
+
// src/components/ElementInfoDisplayReact.tsx
|
|
300
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
301
|
+
function ElementInfoDisplayReact(props) {
|
|
302
|
+
const isDomSnapshot = props.elementInfo.kind === "dom";
|
|
303
|
+
if (isDomSnapshot) {
|
|
304
|
+
const dom = props.elementInfo.domSnapshot;
|
|
305
|
+
const outerHTML = dom?.outerHTML || "No HTML available";
|
|
306
|
+
const text = dom?.text || "";
|
|
307
|
+
const attributes = dom?.attributes || {};
|
|
308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uidog-element-info", children: [
|
|
309
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uidog-element-info-content", children: [
|
|
310
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uidog-file-location", children: "Server-rendered DOM (no source available)" }),
|
|
311
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
312
|
+
"button",
|
|
313
|
+
{
|
|
314
|
+
className: "uidog-close-btn",
|
|
315
|
+
onClick: props.onClose,
|
|
316
|
+
title: "Close sidebar (ESC)",
|
|
317
|
+
"aria-label": "Close sidebar",
|
|
318
|
+
children: "\xD7"
|
|
319
|
+
}
|
|
320
|
+
)
|
|
321
|
+
] }),
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uidog-dom-snapshot", children: [
|
|
323
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uidog-dom-label", children: "outerHTML (trimmed):" }),
|
|
324
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { className: "uidog-dom-snippet", children: outerHTML }),
|
|
325
|
+
text && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
326
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uidog-dom-label", children: "textContent (trimmed):" }),
|
|
327
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { className: "uidog-dom-snippet", children: text })
|
|
328
|
+
] }),
|
|
329
|
+
Object.keys(attributes).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uidog-dom-attributes", children: [
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uidog-dom-label", children: "attributes:" }),
|
|
331
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { children: Object.entries(attributes).map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: key }),
|
|
333
|
+
"=",
|
|
334
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: value })
|
|
335
|
+
] }, key)) })
|
|
336
|
+
] }),
|
|
337
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uidog-dom-hint", children: "To see file/line info, render this DOM through a small client boundary." })
|
|
338
|
+
] })
|
|
339
|
+
] });
|
|
340
|
+
}
|
|
341
|
+
const fileName = props.elementInfo.filePath?.split("/").pop() || "";
|
|
342
|
+
const fileLocation = `Selected element at ${fileName}`;
|
|
343
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uidog-element-info", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uidog-element-info-content", children: [
|
|
344
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "uidog-file-location", children: fileLocation }),
|
|
345
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
346
|
+
"button",
|
|
347
|
+
{
|
|
348
|
+
className: "uidog-close-btn",
|
|
349
|
+
onClick: props.onClose,
|
|
350
|
+
title: "Close sidebar (ESC)",
|
|
351
|
+
"aria-label": "Close sidebar",
|
|
352
|
+
children: "\xD7"
|
|
353
|
+
}
|
|
354
|
+
)
|
|
355
|
+
] }) });
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/components/ConversationalInputReact.tsx
|
|
359
|
+
var import_react = require("react");
|
|
360
|
+
|
|
361
|
+
// src/api/client.ts
|
|
362
|
+
async function sendChatPrompt(request, apiEndpoint = "http://localhost:3000") {
|
|
363
|
+
try {
|
|
364
|
+
const response = await fetch(`${apiEndpoint}/chat`, {
|
|
365
|
+
method: "POST",
|
|
366
|
+
headers: {
|
|
367
|
+
"Content-Type": "application/json"
|
|
368
|
+
},
|
|
369
|
+
body: JSON.stringify(request)
|
|
370
|
+
});
|
|
371
|
+
if (!response.ok) {
|
|
372
|
+
const errorData = await response.json().catch(() => ({ error: response.statusText }));
|
|
373
|
+
return {
|
|
374
|
+
ok: false,
|
|
375
|
+
message: "",
|
|
376
|
+
error: errorData.error || `API error (${response.status})`
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
return await response.json();
|
|
380
|
+
} catch (error) {
|
|
381
|
+
if (error instanceof Error) {
|
|
382
|
+
return {
|
|
383
|
+
ok: false,
|
|
384
|
+
message: "",
|
|
385
|
+
error: error.message
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
ok: false,
|
|
390
|
+
message: "",
|
|
391
|
+
error: "Unknown error occurred"
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
async function sendToDeveloper(request, apiEndpoint = "http://localhost:3000") {
|
|
396
|
+
try {
|
|
397
|
+
const response = await fetch(`${apiEndpoint}/send-to-dev`, {
|
|
398
|
+
method: "POST",
|
|
399
|
+
headers: {
|
|
400
|
+
"Content-Type": "application/json"
|
|
401
|
+
},
|
|
402
|
+
body: JSON.stringify(request)
|
|
403
|
+
});
|
|
404
|
+
if (!response.ok) {
|
|
405
|
+
const errorData = await response.json().catch(() => ({ error: response.statusText }));
|
|
406
|
+
return {
|
|
407
|
+
ok: false,
|
|
408
|
+
error: errorData.error || `API error (${response.status})`
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
return await response.json();
|
|
412
|
+
} catch (error) {
|
|
413
|
+
if (error instanceof Error) {
|
|
414
|
+
return {
|
|
415
|
+
ok: false,
|
|
416
|
+
error: error.message
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
ok: false,
|
|
421
|
+
error: "Unknown error occurred"
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/components/ConversationalInputReact.tsx
|
|
427
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
428
|
+
function ConversationalInputReact(props) {
|
|
429
|
+
const [userInput, setUserInput] = (0, import_react.useState)("");
|
|
430
|
+
const [messages, setMessages] = (0, import_react.useState)([]);
|
|
431
|
+
const [isLoading, setIsLoading] = (0, import_react.useState)(false);
|
|
432
|
+
const [sessionId, setSessionId] = (0, import_react.useState)(void 0);
|
|
433
|
+
const [isCreatingPR, setIsCreatingPR] = (0, import_react.useState)(false);
|
|
434
|
+
const [prUrl, setPrUrl] = (0, import_react.useState)(null);
|
|
435
|
+
const textareaRef = (0, import_react.useRef)(null);
|
|
436
|
+
const messagesEndRef = (0, import_react.useRef)(null);
|
|
437
|
+
(0, import_react.useEffect)(() => {
|
|
438
|
+
textareaRef.current?.focus();
|
|
439
|
+
}, []);
|
|
440
|
+
(0, import_react.useEffect)(() => {
|
|
441
|
+
const textarea = textareaRef.current;
|
|
442
|
+
if (textarea) {
|
|
443
|
+
textarea.style.height = "auto";
|
|
444
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
|
|
445
|
+
}
|
|
446
|
+
}, [userInput]);
|
|
447
|
+
(0, import_react.useEffect)(() => {
|
|
448
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
449
|
+
}, [messages]);
|
|
450
|
+
const handleSubmit = async () => {
|
|
451
|
+
const input = userInput.trim();
|
|
452
|
+
if (!input || isLoading)
|
|
453
|
+
return;
|
|
454
|
+
const userMessage = {
|
|
455
|
+
id: `user-${Date.now()}`,
|
|
456
|
+
role: "user",
|
|
457
|
+
content: input,
|
|
458
|
+
timestamp: Date.now()
|
|
459
|
+
};
|
|
460
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
461
|
+
setUserInput("");
|
|
462
|
+
setIsLoading(true);
|
|
463
|
+
const loadingMessageId = `loading-${Date.now()}`;
|
|
464
|
+
const loadingMessage = {
|
|
465
|
+
id: loadingMessageId,
|
|
466
|
+
role: "assistant",
|
|
467
|
+
content: "",
|
|
468
|
+
timestamp: Date.now(),
|
|
469
|
+
isLoading: true
|
|
470
|
+
};
|
|
471
|
+
setMessages((prev) => [...prev, loadingMessage]);
|
|
472
|
+
const request = {
|
|
473
|
+
prompt: `The component selected by the user: ${props.editorUrl}
|
|
474
|
+
User request: ${input}
|
|
475
|
+
Update multiple files (if necessary) to achieve the user's request.`,
|
|
476
|
+
sessionId
|
|
477
|
+
};
|
|
478
|
+
try {
|
|
479
|
+
const result = await sendChatPrompt(
|
|
480
|
+
request,
|
|
481
|
+
props.apiEndpoint
|
|
482
|
+
);
|
|
483
|
+
if (result.sessionId && !sessionId) {
|
|
484
|
+
setSessionId(result.sessionId);
|
|
485
|
+
}
|
|
486
|
+
setMessages((prev) => {
|
|
487
|
+
const filtered = prev.filter((msg) => msg.id !== loadingMessageId);
|
|
488
|
+
const assistantMessage = {
|
|
489
|
+
id: `assistant-${Date.now()}`,
|
|
490
|
+
role: "assistant",
|
|
491
|
+
content: result.ok ? result.message : result.error || "Request failed",
|
|
492
|
+
timestamp: Date.now(),
|
|
493
|
+
error: !result.ok ? result.error : void 0
|
|
494
|
+
};
|
|
495
|
+
return [...filtered, assistantMessage];
|
|
496
|
+
});
|
|
497
|
+
} catch (err) {
|
|
498
|
+
setMessages((prev) => {
|
|
499
|
+
const filtered = prev.filter((msg) => msg.id !== loadingMessageId);
|
|
500
|
+
const errorMessage = {
|
|
501
|
+
id: `error-${Date.now()}`,
|
|
502
|
+
role: "assistant",
|
|
503
|
+
content: err instanceof Error ? err.message : "Unknown error occurred",
|
|
504
|
+
timestamp: Date.now(),
|
|
505
|
+
error: err instanceof Error ? err.message : "Unknown error occurred"
|
|
506
|
+
};
|
|
507
|
+
return [...filtered, errorMessage];
|
|
508
|
+
});
|
|
509
|
+
} finally {
|
|
510
|
+
setIsLoading(false);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
const handleKeyDown = (e) => {
|
|
514
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
515
|
+
e.preventDefault();
|
|
516
|
+
handleSubmit();
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
const handleSendToDeveloper = async () => {
|
|
520
|
+
if (!sessionId || isCreatingPR)
|
|
521
|
+
return;
|
|
522
|
+
setIsCreatingPR(true);
|
|
523
|
+
setPrUrl(null);
|
|
524
|
+
try {
|
|
525
|
+
const result = await sendToDeveloper(
|
|
526
|
+
{ sessionId },
|
|
527
|
+
props.apiEndpoint
|
|
528
|
+
);
|
|
529
|
+
if (result.ok && result.prUrl) {
|
|
530
|
+
setPrUrl(result.prUrl);
|
|
531
|
+
const successMessage = {
|
|
532
|
+
id: `pr-success-${Date.now()}`,
|
|
533
|
+
role: "assistant",
|
|
534
|
+
content: `Pull request created successfully!`,
|
|
535
|
+
timestamp: Date.now()
|
|
536
|
+
};
|
|
537
|
+
setMessages((prev) => [...prev, successMessage]);
|
|
538
|
+
} else {
|
|
539
|
+
const errorMessage = {
|
|
540
|
+
id: `pr-error-${Date.now()}`,
|
|
541
|
+
role: "assistant",
|
|
542
|
+
content: result.error || "Failed to create pull request",
|
|
543
|
+
timestamp: Date.now(),
|
|
544
|
+
error: result.error || "Failed to create pull request"
|
|
545
|
+
};
|
|
546
|
+
setMessages((prev) => [...prev, errorMessage]);
|
|
547
|
+
}
|
|
548
|
+
} catch (err) {
|
|
549
|
+
const errorMessage = {
|
|
550
|
+
id: `pr-error-${Date.now()}`,
|
|
551
|
+
role: "assistant",
|
|
552
|
+
content: err instanceof Error ? err.message : "Unknown error occurred",
|
|
553
|
+
timestamp: Date.now(),
|
|
554
|
+
error: err instanceof Error ? err.message : "Unknown error occurred"
|
|
555
|
+
};
|
|
556
|
+
setMessages((prev) => [...prev, errorMessage]);
|
|
557
|
+
} finally {
|
|
558
|
+
setIsCreatingPR(false);
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
const handleRetry = async (messageId) => {
|
|
562
|
+
const errorIndex = messages.findIndex((msg) => msg.id === messageId);
|
|
563
|
+
if (errorIndex === -1)
|
|
564
|
+
return;
|
|
565
|
+
let userMessageIndex = -1;
|
|
566
|
+
for (let i = errorIndex - 1; i >= 0; i--) {
|
|
567
|
+
if (messages[i].role === "user") {
|
|
568
|
+
userMessageIndex = i;
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (userMessageIndex === -1)
|
|
573
|
+
return;
|
|
574
|
+
const userMessage = messages[userMessageIndex];
|
|
575
|
+
const input = userMessage.content;
|
|
576
|
+
setMessages((prev) => prev.filter((msg) => msg.id !== messageId));
|
|
577
|
+
setIsLoading(true);
|
|
578
|
+
const loadingMessageId = `loading-${Date.now()}`;
|
|
579
|
+
const loadingMessage = {
|
|
580
|
+
id: loadingMessageId,
|
|
581
|
+
role: "assistant",
|
|
582
|
+
content: "",
|
|
583
|
+
timestamp: Date.now(),
|
|
584
|
+
isLoading: true
|
|
585
|
+
};
|
|
586
|
+
setMessages((prev) => [...prev, loadingMessage]);
|
|
587
|
+
const request = {
|
|
588
|
+
prompt: `The component selected by the user: ${props.editorUrl}
|
|
589
|
+
User request: ${input}
|
|
590
|
+
Update multiple files (if necessary) to achieve the user's request.`,
|
|
591
|
+
sessionId
|
|
592
|
+
};
|
|
593
|
+
try {
|
|
594
|
+
const result = await sendChatPrompt(
|
|
595
|
+
request,
|
|
596
|
+
props.apiEndpoint
|
|
597
|
+
);
|
|
598
|
+
if (result.sessionId && !sessionId) {
|
|
599
|
+
setSessionId(result.sessionId);
|
|
600
|
+
}
|
|
601
|
+
setMessages((prev) => {
|
|
602
|
+
const filtered = prev.filter((msg) => msg.id !== loadingMessageId);
|
|
603
|
+
const assistantMessage = {
|
|
604
|
+
id: `assistant-${Date.now()}`,
|
|
605
|
+
role: "assistant",
|
|
606
|
+
content: result.ok ? result.message : result.error || "Request failed",
|
|
607
|
+
timestamp: Date.now(),
|
|
608
|
+
error: !result.ok ? result.error : void 0
|
|
609
|
+
};
|
|
610
|
+
return [...filtered, assistantMessage];
|
|
611
|
+
});
|
|
612
|
+
} catch (err) {
|
|
613
|
+
setMessages((prev) => {
|
|
614
|
+
const filtered = prev.filter((msg) => msg.id !== loadingMessageId);
|
|
615
|
+
const errorMessage = {
|
|
616
|
+
id: `error-${Date.now()}`,
|
|
617
|
+
role: "assistant",
|
|
618
|
+
content: err instanceof Error ? err.message : "Unknown error occurred",
|
|
619
|
+
timestamp: Date.now(),
|
|
620
|
+
error: err instanceof Error ? err.message : "Unknown error occurred"
|
|
621
|
+
};
|
|
622
|
+
return [...filtered, errorMessage];
|
|
623
|
+
});
|
|
624
|
+
} finally {
|
|
625
|
+
setIsLoading(false);
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
629
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "uidog-messages-container", children: [
|
|
630
|
+
messages.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-empty-state", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-empty-state-text", children: "What changes would you like to make?" }) }),
|
|
631
|
+
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
632
|
+
"div",
|
|
633
|
+
{
|
|
634
|
+
className: `uidog-message uidog-message-${message.role}`,
|
|
635
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-message-bubble", children: message.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "uidog-message-loading", children: [
|
|
636
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-spinner" }),
|
|
637
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Processing your request..." })
|
|
638
|
+
] }) : message.error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
639
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-message-content uidog-message-error", children: message.content }),
|
|
640
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
641
|
+
"button",
|
|
642
|
+
{
|
|
643
|
+
className: "uidog-retry-btn",
|
|
644
|
+
onClick: () => handleRetry(message.id),
|
|
645
|
+
children: "Retry"
|
|
646
|
+
}
|
|
647
|
+
)
|
|
648
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-message-content", children: message.content }) })
|
|
649
|
+
},
|
|
650
|
+
message.id
|
|
651
|
+
)),
|
|
652
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: messagesEndRef })
|
|
653
|
+
] }),
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "uidog-input-footer-fixed", children: [
|
|
655
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "uidog-input-wrapper", children: [
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
657
|
+
"textarea",
|
|
658
|
+
{
|
|
659
|
+
id: "uidog-textarea",
|
|
660
|
+
ref: textareaRef,
|
|
661
|
+
className: "uidog-textarea",
|
|
662
|
+
placeholder: "Describe the changes you want...",
|
|
663
|
+
value: userInput,
|
|
664
|
+
onChange: (e) => setUserInput(e.target.value),
|
|
665
|
+
onKeyDown: handleKeyDown,
|
|
666
|
+
disabled: isLoading
|
|
667
|
+
}
|
|
668
|
+
),
|
|
669
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
670
|
+
"button",
|
|
671
|
+
{
|
|
672
|
+
className: "uidog-submit-btn",
|
|
673
|
+
onClick: handleSubmit,
|
|
674
|
+
disabled: !userInput.trim() || isLoading,
|
|
675
|
+
title: "Send message (Cmd/Ctrl + Enter)",
|
|
676
|
+
children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-spinner-small" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
677
|
+
"svg",
|
|
678
|
+
{
|
|
679
|
+
width: "16",
|
|
680
|
+
height: "16",
|
|
681
|
+
viewBox: "0 0 16 16",
|
|
682
|
+
fill: "none",
|
|
683
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
684
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
685
|
+
"path",
|
|
686
|
+
{
|
|
687
|
+
d: "M8 2L8 14M8 2L2 8M8 2L14 8",
|
|
688
|
+
stroke: "currentColor",
|
|
689
|
+
strokeWidth: "2",
|
|
690
|
+
strokeLinecap: "round",
|
|
691
|
+
strokeLinejoin: "round"
|
|
692
|
+
}
|
|
693
|
+
)
|
|
694
|
+
}
|
|
695
|
+
)
|
|
696
|
+
}
|
|
697
|
+
)
|
|
698
|
+
] }),
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-input-hint", children: "Cmd/Ctrl + Enter to submit" }),
|
|
700
|
+
sessionId && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "uidog-send-to-dev-section", children: [
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
702
|
+
"button",
|
|
703
|
+
{
|
|
704
|
+
className: "uidog-send-to-dev-btn",
|
|
705
|
+
onClick: handleSendToDeveloper,
|
|
706
|
+
disabled: isCreatingPR || isLoading,
|
|
707
|
+
title: "Create PR with changes",
|
|
708
|
+
children: isCreatingPR ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
709
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "uidog-spinner-small" }),
|
|
710
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Creating PR..." })
|
|
711
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
712
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
713
|
+
"svg",
|
|
714
|
+
{
|
|
715
|
+
width: "16",
|
|
716
|
+
height: "16",
|
|
717
|
+
viewBox: "0 0 16 16",
|
|
718
|
+
fill: "none",
|
|
719
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
720
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
721
|
+
"path",
|
|
722
|
+
{
|
|
723
|
+
d: "M8 1L8 15M8 1L1 8M8 1L15 8",
|
|
724
|
+
stroke: "currentColor",
|
|
725
|
+
strokeWidth: "2",
|
|
726
|
+
strokeLinecap: "round",
|
|
727
|
+
strokeLinejoin: "round"
|
|
728
|
+
}
|
|
729
|
+
)
|
|
730
|
+
}
|
|
731
|
+
),
|
|
732
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Submit to Developer" })
|
|
733
|
+
] })
|
|
734
|
+
}
|
|
735
|
+
),
|
|
736
|
+
prUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
737
|
+
"a",
|
|
738
|
+
{
|
|
739
|
+
href: prUrl,
|
|
740
|
+
target: "_blank",
|
|
741
|
+
rel: "noopener noreferrer",
|
|
742
|
+
className: "uidog-pr-link",
|
|
743
|
+
children: "View PR \u2192"
|
|
744
|
+
}
|
|
745
|
+
)
|
|
746
|
+
] })
|
|
747
|
+
] })
|
|
748
|
+
] });
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// src/components/UiDogSidebarReact.tsx
|
|
752
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
753
|
+
function UiDogSidebarReact(props) {
|
|
754
|
+
(0, import_react2.useEffect)(() => {
|
|
755
|
+
const handleEscapeKey = (e) => {
|
|
756
|
+
if (e.key === "Escape") {
|
|
757
|
+
props.onClose();
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
document.addEventListener("keydown", handleEscapeKey);
|
|
761
|
+
return () => {
|
|
762
|
+
document.removeEventListener("keydown", handleEscapeKey);
|
|
763
|
+
};
|
|
764
|
+
}, [props]);
|
|
765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "uidog-sidebar-overlay", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "uidog-sidebar", children: [
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "uidog-element-info-section", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
767
|
+
ElementInfoDisplayReact,
|
|
768
|
+
{
|
|
769
|
+
elementInfo: props.elementInfo,
|
|
770
|
+
onClose: props.onClose
|
|
771
|
+
}
|
|
772
|
+
) }),
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "uidog-chat-container", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
774
|
+
ConversationalInputReact,
|
|
775
|
+
{
|
|
776
|
+
elementInfo: props.elementInfo,
|
|
777
|
+
editorUrl: props.editorUrl,
|
|
778
|
+
apiEndpoint: props.apiEndpoint
|
|
779
|
+
}
|
|
780
|
+
) })
|
|
781
|
+
] }) });
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// src/styles/sidebarStyles.ts
|
|
785
|
+
var sidebarStyles = `/* UiDog Sidebar Styles */
|
|
786
|
+
|
|
787
|
+
/* Overlay */
|
|
788
|
+
.uidog-sidebar-overlay {
|
|
789
|
+
position: fixed;
|
|
790
|
+
top: 0;
|
|
791
|
+
right: 0;
|
|
792
|
+
bottom: 0;
|
|
793
|
+
left: 0;
|
|
794
|
+
z-index: 999999;
|
|
795
|
+
pointer-events: none;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/* Main Sidebar Container */
|
|
799
|
+
.uidog-sidebar {
|
|
800
|
+
position: fixed;
|
|
801
|
+
right: 0;
|
|
802
|
+
top: 0;
|
|
803
|
+
width: 420px;
|
|
804
|
+
max-width: 100vw;
|
|
805
|
+
height: 100vh;
|
|
806
|
+
background: #13140a;
|
|
807
|
+
box-shadow: -4px 0 24px rgba(0, 0, 0, 0.5);
|
|
808
|
+
display: flex;
|
|
809
|
+
flex-direction: column;
|
|
810
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
811
|
+
font-size: 14px;
|
|
812
|
+
color: #ffffff;
|
|
813
|
+
pointer-events: auto;
|
|
814
|
+
animation: uidog-slide-in 0.3s ease-out;
|
|
815
|
+
overflow: hidden;
|
|
816
|
+
border-left: 1px solid rgba(255, 255, 255, 0.1);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
@keyframes uidog-slide-in {
|
|
820
|
+
from {
|
|
821
|
+
transform: translateX(100%);
|
|
822
|
+
}
|
|
823
|
+
to {
|
|
824
|
+
transform: translateX(0);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/* Header */
|
|
829
|
+
.uidog-sidebar-header {
|
|
830
|
+
display: flex;
|
|
831
|
+
align-items: center;
|
|
832
|
+
justify-content: flex-end;
|
|
833
|
+
padding: 20px 24px;
|
|
834
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
|
835
|
+
background: rgba(0, 0, 0, 0.3);
|
|
836
|
+
flex-shrink: 0;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.uidog-sidebar-title {
|
|
840
|
+
margin: 0;
|
|
841
|
+
font-size: 18px;
|
|
842
|
+
font-weight: 600;
|
|
843
|
+
color: #ffffff;
|
|
844
|
+
letter-spacing: -0.01em;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
.uidog-close-btn {
|
|
848
|
+
width: 32px;
|
|
849
|
+
height: 32px;
|
|
850
|
+
border: none;
|
|
851
|
+
background: transparent;
|
|
852
|
+
font-size: 28px;
|
|
853
|
+
line-height: 1;
|
|
854
|
+
color: rgba(255, 255, 255, 0.7);
|
|
855
|
+
cursor: pointer;
|
|
856
|
+
border-radius: 4px;
|
|
857
|
+
display: flex;
|
|
858
|
+
align-items: center;
|
|
859
|
+
justify-content: center;
|
|
860
|
+
transition: all 0.2s;
|
|
861
|
+
flex-shrink: 0;
|
|
862
|
+
margin-left: 12px;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
.uidog-close-btn:hover {
|
|
866
|
+
background: rgba(255, 255, 255, 0.1);
|
|
867
|
+
color: #ffffff;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/* Content Area */
|
|
871
|
+
.uidog-sidebar-content {
|
|
872
|
+
flex: 1;
|
|
873
|
+
overflow-y: auto;
|
|
874
|
+
overflow-x: hidden;
|
|
875
|
+
padding: 24px;
|
|
876
|
+
scrollbar-width: thin;
|
|
877
|
+
scrollbar-color: rgba(255, 255, 255, 0.2) transparent;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.uidog-sidebar-content::-webkit-scrollbar {
|
|
881
|
+
width: 8px;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.uidog-sidebar-content::-webkit-scrollbar-track {
|
|
885
|
+
background: transparent;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
.uidog-sidebar-content::-webkit-scrollbar-thumb {
|
|
889
|
+
background: rgba(255, 255, 255, 0.2);
|
|
890
|
+
border-radius: 4px;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.uidog-sidebar-content::-webkit-scrollbar-thumb:hover {
|
|
894
|
+
background: rgba(255, 255, 255, 0.3);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/* Element Info Section */
|
|
898
|
+
.uidog-element-info-section {
|
|
899
|
+
padding: 20px 24px;
|
|
900
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
|
901
|
+
flex-shrink: 0;
|
|
902
|
+
background: rgba(0, 0, 0, 0.2);
|
|
903
|
+
margin-top: 0;
|
|
904
|
+
padding-top: 20px;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/* Element Info Section */
|
|
908
|
+
.uidog-element-info {
|
|
909
|
+
margin-bottom: 0;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.uidog-element-info-header {
|
|
913
|
+
display: flex;
|
|
914
|
+
align-items: center;
|
|
915
|
+
justify-content: space-between;
|
|
916
|
+
margin-bottom: 12px;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.uidog-element-info-title {
|
|
920
|
+
margin: 0;
|
|
921
|
+
font-size: 14px;
|
|
922
|
+
font-weight: 600;
|
|
923
|
+
color: rgba(255, 255, 255, 0.9);
|
|
924
|
+
text-transform: uppercase;
|
|
925
|
+
letter-spacing: 0.05em;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.uidog-toggle-view-btn {
|
|
929
|
+
padding: 6px 14px;
|
|
930
|
+
font-size: 12px;
|
|
931
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
932
|
+
background: rgba(255, 255, 255, 0.1);
|
|
933
|
+
color: #ffffff;
|
|
934
|
+
border-radius: 6px;
|
|
935
|
+
cursor: pointer;
|
|
936
|
+
transition: all 0.2s;
|
|
937
|
+
font-weight: 500;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.uidog-toggle-view-btn:hover {
|
|
941
|
+
background: rgba(255, 255, 255, 0.2);
|
|
942
|
+
border-color: rgba(255, 255, 255, 0.3);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
.uidog-element-info-content {
|
|
946
|
+
background: rgba(0, 0, 0, 0.3);
|
|
947
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
948
|
+
border-radius: 8px;
|
|
949
|
+
padding: 16px;
|
|
950
|
+
display: flex;
|
|
951
|
+
align-items: center;
|
|
952
|
+
justify-content: space-between;
|
|
953
|
+
position: relative;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
.uidog-file-location {
|
|
957
|
+
font-family: "SF Mono", Monaco, Menlo, Consolas, monospace;
|
|
958
|
+
font-size: 13px;
|
|
959
|
+
color: #ffffff;
|
|
960
|
+
word-break: break-word;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
.uidog-info-row {
|
|
964
|
+
display: flex;
|
|
965
|
+
margin-bottom: 12px;
|
|
966
|
+
line-height: 1.6;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
.uidog-info-row:last-of-type {
|
|
970
|
+
margin-bottom: 0;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
.uidog-info-row:last-child {
|
|
974
|
+
margin-bottom: 0;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.uidog-info-label {
|
|
978
|
+
flex-shrink: 0;
|
|
979
|
+
width: 100px;
|
|
980
|
+
font-weight: 500;
|
|
981
|
+
color: rgba(255, 255, 255, 0.75);
|
|
982
|
+
font-size: 13px;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
.uidog-info-value {
|
|
986
|
+
flex: 1;
|
|
987
|
+
color: #ffffff;
|
|
988
|
+
word-break: break-word;
|
|
989
|
+
font-size: 13px;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.uidog-component-name {
|
|
993
|
+
font-weight: 600;
|
|
994
|
+
color: #60a5fa;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.uidog-file-path {
|
|
998
|
+
font-family: "SF Mono", Monaco, Menlo, Consolas, monospace;
|
|
999
|
+
font-size: 12px;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
.uidog-dom-snapshot {
|
|
1003
|
+
margin-top: 16px;
|
|
1004
|
+
background: rgba(255, 255, 255, 0.03);
|
|
1005
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
1006
|
+
border-radius: 8px;
|
|
1007
|
+
padding: 12px;
|
|
1008
|
+
display: flex;
|
|
1009
|
+
flex-direction: column;
|
|
1010
|
+
gap: 8px;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
.uidog-dom-label {
|
|
1014
|
+
color: rgba(255, 255, 255, 0.7);
|
|
1015
|
+
font-size: 12px;
|
|
1016
|
+
text-transform: uppercase;
|
|
1017
|
+
letter-spacing: 0.05em;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.uidog-dom-snippet {
|
|
1021
|
+
margin: 0;
|
|
1022
|
+
background: rgba(0, 0, 0, 0.4);
|
|
1023
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
1024
|
+
border-radius: 6px;
|
|
1025
|
+
padding: 10px;
|
|
1026
|
+
color: rgba(255, 255, 255, 0.85);
|
|
1027
|
+
font-family: "SF Mono", Monaco, Menlo, Consolas, monospace;
|
|
1028
|
+
font-size: 12px;
|
|
1029
|
+
white-space: pre-wrap;
|
|
1030
|
+
word-break: break-word;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
.uidog-dom-attributes ul {
|
|
1034
|
+
margin: 6px 0 0 0;
|
|
1035
|
+
padding-left: 16px;
|
|
1036
|
+
color: rgba(255, 255, 255, 0.85);
|
|
1037
|
+
font-family: "SF Mono", Monaco, Menlo, Consolas, monospace;
|
|
1038
|
+
font-size: 12px;
|
|
1039
|
+
word-break: break-word;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.uidog-dom-attributes code {
|
|
1043
|
+
background: rgba(255, 255, 255, 0.08);
|
|
1044
|
+
padding: 2px 4px;
|
|
1045
|
+
border-radius: 4px;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.uidog-dom-hint {
|
|
1049
|
+
color: rgba(255, 255, 255, 0.6);
|
|
1050
|
+
font-size: 12px;
|
|
1051
|
+
line-height: 1.5;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.uidog-mono {
|
|
1055
|
+
font-family: "SF Mono", Monaco, Menlo, Consolas, monospace;
|
|
1056
|
+
font-size: 12px;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.uidog-detailed-section {
|
|
1060
|
+
margin-top: 12px;
|
|
1061
|
+
padding-top: 12px;
|
|
1062
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.uidog-code-preview {
|
|
1066
|
+
flex-direction: column;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
.uidog-code-placeholder {
|
|
1070
|
+
margin-top: 6px;
|
|
1071
|
+
padding: 8px;
|
|
1072
|
+
background: rgba(0, 0, 0, 0.3);
|
|
1073
|
+
color: rgba(255, 255, 255, 0.8);
|
|
1074
|
+
border-radius: 4px;
|
|
1075
|
+
font-family: "SF Mono", Monaco, Menlo, Consolas, monospace;
|
|
1076
|
+
font-size: 12px;
|
|
1077
|
+
white-space: pre-wrap;
|
|
1078
|
+
word-break: break-word;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/* Chat Container */
|
|
1082
|
+
.uidog-chat-container {
|
|
1083
|
+
flex: 1;
|
|
1084
|
+
display: flex;
|
|
1085
|
+
flex-direction: column;
|
|
1086
|
+
overflow: hidden;
|
|
1087
|
+
min-height: 0;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/* Messages Container */
|
|
1091
|
+
.uidog-messages-container {
|
|
1092
|
+
flex: 1;
|
|
1093
|
+
overflow-y: auto;
|
|
1094
|
+
overflow-x: hidden;
|
|
1095
|
+
padding: 20px 24px;
|
|
1096
|
+
scrollbar-width: thin;
|
|
1097
|
+
scrollbar-color: rgba(255, 255, 255, 0.2) transparent;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
.uidog-dom-banner {
|
|
1101
|
+
margin-bottom: 12px;
|
|
1102
|
+
padding: 12px 14px;
|
|
1103
|
+
background: rgba(255, 255, 255, 0.08);
|
|
1104
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
1105
|
+
border-radius: 8px;
|
|
1106
|
+
color: rgba(255, 255, 255, 0.85);
|
|
1107
|
+
font-size: 13px;
|
|
1108
|
+
line-height: 1.5;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.uidog-messages-container::-webkit-scrollbar {
|
|
1112
|
+
width: 8px;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
.uidog-messages-container::-webkit-scrollbar-track {
|
|
1116
|
+
background: transparent;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
.uidog-messages-container::-webkit-scrollbar-thumb {
|
|
1120
|
+
background: rgba(255, 255, 255, 0.2);
|
|
1121
|
+
border-radius: 4px;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.uidog-messages-container::-webkit-scrollbar-thumb:hover {
|
|
1125
|
+
background: rgba(255, 255, 255, 0.3);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
/* Empty State */
|
|
1129
|
+
.uidog-empty-state {
|
|
1130
|
+
display: flex;
|
|
1131
|
+
align-items: center;
|
|
1132
|
+
justify-content: center;
|
|
1133
|
+
height: 100%;
|
|
1134
|
+
min-height: 200px;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
.uidog-empty-state-text {
|
|
1138
|
+
color: rgba(255, 255, 255, 0.6);
|
|
1139
|
+
font-size: 14px;
|
|
1140
|
+
text-align: center;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/* Messages */
|
|
1144
|
+
.uidog-message {
|
|
1145
|
+
margin-bottom: 16px;
|
|
1146
|
+
display: flex;
|
|
1147
|
+
animation: uidog-message-fade-in 0.2s ease-out;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
@keyframes uidog-message-fade-in {
|
|
1151
|
+
from {
|
|
1152
|
+
opacity: 0;
|
|
1153
|
+
transform: translateY(4px);
|
|
1154
|
+
}
|
|
1155
|
+
to {
|
|
1156
|
+
opacity: 1;
|
|
1157
|
+
transform: translateY(0);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
.uidog-message-user {
|
|
1162
|
+
justify-content: flex-end;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.uidog-message-assistant {
|
|
1166
|
+
justify-content: flex-start;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/* Message Bubbles */
|
|
1170
|
+
.uidog-message-bubble {
|
|
1171
|
+
max-width: 80%;
|
|
1172
|
+
padding: 12px 16px;
|
|
1173
|
+
border-radius: 12px;
|
|
1174
|
+
word-wrap: break-word;
|
|
1175
|
+
overflow-wrap: break-word;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
.uidog-message-user .uidog-message-bubble {
|
|
1179
|
+
background: rgba(59, 130, 246, 0.2);
|
|
1180
|
+
border: 1px solid rgba(59, 130, 246, 0.3);
|
|
1181
|
+
color: #93c5fd;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
.uidog-message-assistant .uidog-message-bubble {
|
|
1185
|
+
background: rgba(255, 255, 255, 0.08);
|
|
1186
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
1187
|
+
color: rgba(255, 255, 255, 0.9);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.uidog-message-content {
|
|
1191
|
+
line-height: 1.6;
|
|
1192
|
+
white-space: pre-wrap;
|
|
1193
|
+
word-break: break-word;
|
|
1194
|
+
font-size: 14px;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
.uidog-message-content.uidog-message-error {
|
|
1198
|
+
color: #fca5a5;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
/* Loading Message */
|
|
1202
|
+
.uidog-message-loading {
|
|
1203
|
+
display: flex;
|
|
1204
|
+
align-items: center;
|
|
1205
|
+
gap: 10px;
|
|
1206
|
+
color: rgba(255, 255, 255, 0.7);
|
|
1207
|
+
font-size: 14px;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
.uidog-spinner {
|
|
1211
|
+
width: 16px;
|
|
1212
|
+
height: 16px;
|
|
1213
|
+
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
1214
|
+
border-top-color: rgba(255, 255, 255, 0.8);
|
|
1215
|
+
border-radius: 50%;
|
|
1216
|
+
animation: uidog-spin 0.8s linear infinite;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.uidog-spinner-small {
|
|
1220
|
+
width: 14px;
|
|
1221
|
+
height: 14px;
|
|
1222
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
1223
|
+
border-top-color: #ffffff;
|
|
1224
|
+
border-radius: 50%;
|
|
1225
|
+
animation: uidog-spin 0.8s linear infinite;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
@keyframes uidog-spin {
|
|
1229
|
+
to {
|
|
1230
|
+
transform: rotate(360deg);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/* Fixed Input Footer */
|
|
1235
|
+
.uidog-input-footer-fixed {
|
|
1236
|
+
flex-shrink: 0;
|
|
1237
|
+
padding: 16px 24px;
|
|
1238
|
+
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
|
1239
|
+
background: rgba(0, 0, 0, 0.3);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
.uidog-input-wrapper {
|
|
1243
|
+
position: relative;
|
|
1244
|
+
margin-bottom: 8px;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
.uidog-textarea {
|
|
1248
|
+
width: 100%;
|
|
1249
|
+
padding: 10px 60px 10px 14px;
|
|
1250
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
1251
|
+
border-radius: 8px;
|
|
1252
|
+
font-family: inherit;
|
|
1253
|
+
font-size: 14px;
|
|
1254
|
+
line-height: 1.5;
|
|
1255
|
+
resize: none;
|
|
1256
|
+
min-height: 44px;
|
|
1257
|
+
max-height: 200px;
|
|
1258
|
+
background: rgba(0, 0, 0, 0.4);
|
|
1259
|
+
color: #ffffff;
|
|
1260
|
+
transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
|
|
1261
|
+
box-sizing: border-box;
|
|
1262
|
+
overflow-wrap: break-word;
|
|
1263
|
+
word-wrap: break-word;
|
|
1264
|
+
overflow-y: auto;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
.uidog-textarea::placeholder {
|
|
1268
|
+
color: rgba(255, 255, 255, 0.5);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
.uidog-textarea:focus {
|
|
1272
|
+
outline: none;
|
|
1273
|
+
border-color: #60a5fa;
|
|
1274
|
+
background: rgba(0, 0, 0, 0.5);
|
|
1275
|
+
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.15);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
.uidog-textarea:disabled {
|
|
1279
|
+
background: rgba(0, 0, 0, 0.2);
|
|
1280
|
+
color: rgba(255, 255, 255, 0.5);
|
|
1281
|
+
cursor: not-allowed;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
.uidog-submit-btn {
|
|
1285
|
+
position: absolute;
|
|
1286
|
+
bottom: 10px;
|
|
1287
|
+
right: 6px;
|
|
1288
|
+
width: 32px;
|
|
1289
|
+
height: 32px;
|
|
1290
|
+
display: flex;
|
|
1291
|
+
align-items: center;
|
|
1292
|
+
justify-content: center;
|
|
1293
|
+
padding: 0;
|
|
1294
|
+
font-size: 14px;
|
|
1295
|
+
font-weight: 500;
|
|
1296
|
+
color: #ffffff;
|
|
1297
|
+
background: #3b82f6;
|
|
1298
|
+
border: none;
|
|
1299
|
+
border-radius: 6px;
|
|
1300
|
+
cursor: pointer;
|
|
1301
|
+
transition: all 0.2s;
|
|
1302
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
.uidog-submit-btn:active {
|
|
1306
|
+
transform: translateY(1px);
|
|
1307
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
.uidog-submit-btn:hover:not(:disabled) {
|
|
1311
|
+
background: #2563eb;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
.uidog-submit-btn:disabled {
|
|
1315
|
+
background: rgba(255, 255, 255, 0.1);
|
|
1316
|
+
color: rgba(255, 255, 255, 0.3);
|
|
1317
|
+
cursor: not-allowed;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
.uidog-submit-btn svg {
|
|
1321
|
+
stroke: currentColor;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
.uidog-input-hint {
|
|
1325
|
+
font-size: 11px;
|
|
1326
|
+
color: rgba(255, 255, 255, 0.5);
|
|
1327
|
+
text-align: center;
|
|
1328
|
+
margin-top: 4px;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
.uidog-retry-btn {
|
|
1332
|
+
margin-top: 8px;
|
|
1333
|
+
padding: 6px 12px;
|
|
1334
|
+
font-size: 12px;
|
|
1335
|
+
font-weight: 500;
|
|
1336
|
+
color: #ffffff;
|
|
1337
|
+
background: #ef4444;
|
|
1338
|
+
border: none;
|
|
1339
|
+
border-radius: 6px;
|
|
1340
|
+
cursor: pointer;
|
|
1341
|
+
transition: background 0.2s;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
.uidog-retry-btn:hover {
|
|
1345
|
+
background: #dc2626;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/* Footer */
|
|
1349
|
+
.uidog-sidebar-footer {
|
|
1350
|
+
padding: 16px 24px;
|
|
1351
|
+
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
|
1352
|
+
background: rgba(0, 0, 0, 0.3);
|
|
1353
|
+
text-align: center;
|
|
1354
|
+
flex-shrink: 0;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
.uidog-footer-text {
|
|
1358
|
+
font-size: 12px;
|
|
1359
|
+
color: rgba(255, 255, 255, 0.7);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
.uidog-footer-link {
|
|
1363
|
+
color: #60a5fa;
|
|
1364
|
+
text-decoration: none;
|
|
1365
|
+
font-weight: 500;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
.uidog-footer-link:hover {
|
|
1369
|
+
text-decoration: underline;
|
|
1370
|
+
color: #93c5fd;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
/* Mobile Responsive */
|
|
1374
|
+
@media (max-width: 768px) {
|
|
1375
|
+
.uidog-sidebar {
|
|
1376
|
+
width: 100vw;
|
|
1377
|
+
}
|
|
1378
|
+
}`;
|
|
1379
|
+
var sidebarStyles_default = sidebarStyles;
|
|
1380
|
+
|
|
1381
|
+
// src/sidebar-initializer.ts
|
|
1382
|
+
var sidebarRoot = null;
|
|
1383
|
+
var sidebarContainer = null;
|
|
1384
|
+
var shadowRoot = null;
|
|
1385
|
+
var config = { apiEndpoint: "https://api.ui.dog" };
|
|
1386
|
+
var currentState = {
|
|
1387
|
+
isOpen: false,
|
|
1388
|
+
elementInfo: null,
|
|
1389
|
+
editorUrl: ""
|
|
1390
|
+
};
|
|
1391
|
+
function initializeSidebar(sidebarConfig) {
|
|
1392
|
+
if (typeof window === "undefined")
|
|
1393
|
+
return;
|
|
1394
|
+
config = sidebarConfig;
|
|
1395
|
+
if (document.getElementById("uidog-next-sidebar-root")) {
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
sidebarContainer = document.createElement("div");
|
|
1399
|
+
sidebarContainer.id = "uidog-next-sidebar-root";
|
|
1400
|
+
document.body.appendChild(sidebarContainer);
|
|
1401
|
+
shadowRoot = sidebarContainer.attachShadow({ mode: "open" });
|
|
1402
|
+
const styleElement = document.createElement("style");
|
|
1403
|
+
styleElement.textContent = sidebarStyles_default;
|
|
1404
|
+
shadowRoot.appendChild(styleElement);
|
|
1405
|
+
const mountPoint = document.createElement("div");
|
|
1406
|
+
mountPoint.id = "uidog-sidebar-mount";
|
|
1407
|
+
shadowRoot.appendChild(mountPoint);
|
|
1408
|
+
sidebarRoot = (0, import_client2.createRoot)(mountPoint);
|
|
1409
|
+
render();
|
|
1410
|
+
}
|
|
1411
|
+
function render() {
|
|
1412
|
+
if (!sidebarRoot)
|
|
1413
|
+
return;
|
|
1414
|
+
const { isOpen, elementInfo, editorUrl } = currentState;
|
|
1415
|
+
if (!isOpen || !elementInfo) {
|
|
1416
|
+
sidebarRoot.render(null);
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
sidebarRoot.render(
|
|
1420
|
+
(0, import_react3.createElement)(UiDogSidebarReact, {
|
|
1421
|
+
elementInfo,
|
|
1422
|
+
editorUrl,
|
|
1423
|
+
onClose: closeSidebar,
|
|
1424
|
+
apiEndpoint: config.apiEndpoint
|
|
1425
|
+
})
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
function openSidebar(elementInfo, editorUrl) {
|
|
1429
|
+
currentState = {
|
|
1430
|
+
isOpen: true,
|
|
1431
|
+
elementInfo,
|
|
1432
|
+
editorUrl
|
|
1433
|
+
};
|
|
1434
|
+
if (typeof window !== "undefined") {
|
|
1435
|
+
window.__UIDOG_SIDEBAR__ = {
|
|
1436
|
+
isOpen: true,
|
|
1437
|
+
elementInfo,
|
|
1438
|
+
editorUrl
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
render();
|
|
1442
|
+
}
|
|
1443
|
+
function closeSidebar() {
|
|
1444
|
+
currentState = {
|
|
1445
|
+
isOpen: false,
|
|
1446
|
+
elementInfo: null,
|
|
1447
|
+
editorUrl: ""
|
|
1448
|
+
};
|
|
1449
|
+
if (typeof window !== "undefined") {
|
|
1450
|
+
window.__UIDOG_SIDEBAR__ = {
|
|
1451
|
+
isOpen: false,
|
|
1452
|
+
elementInfo: null,
|
|
1453
|
+
editorUrl: null
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
render();
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// src/index.ts
|
|
1460
|
+
var isInitialized = false;
|
|
1461
|
+
function initializeUiDogNext(options = {}) {
|
|
1462
|
+
if (typeof window === "undefined")
|
|
1463
|
+
return;
|
|
1464
|
+
if (isInitialized) {
|
|
1465
|
+
console.warn("[UiDog Next] Already initialized");
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
if (process.env.NODE_ENV === "production") {
|
|
1469
|
+
console.warn(
|
|
1470
|
+
"[UiDog Next] Running in production mode. Element source detection may not work as _debugSource is stripped in production builds."
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
const {
|
|
1474
|
+
editor = "cursor",
|
|
1475
|
+
projectPath = "",
|
|
1476
|
+
modifier = "alt",
|
|
1477
|
+
enableSidebar = true,
|
|
1478
|
+
apiEndpoint = "https://api.ui.dog"
|
|
1479
|
+
} = options;
|
|
1480
|
+
isInitialized = true;
|
|
1481
|
+
window.__UIDOG_NEXT_INITIALIZED__ = true;
|
|
1482
|
+
setupBippyInstrumentation();
|
|
1483
|
+
if (enableSidebar) {
|
|
1484
|
+
initializeSidebar({ apiEndpoint });
|
|
1485
|
+
}
|
|
1486
|
+
setupElementDetector({
|
|
1487
|
+
modifier,
|
|
1488
|
+
onElementSelected: (source, element) => {
|
|
1489
|
+
const rect = element.getBoundingClientRect ? element.getBoundingClientRect() : null;
|
|
1490
|
+
const buildDomSnapshot = () => {
|
|
1491
|
+
const outerHTML = element.outerHTML || "";
|
|
1492
|
+
const text = (element.textContent || "").trim();
|
|
1493
|
+
const attributes = {};
|
|
1494
|
+
Array.from(element.attributes || []).forEach((attr) => {
|
|
1495
|
+
attributes[attr.name] = attr.value;
|
|
1496
|
+
});
|
|
1497
|
+
return {
|
|
1498
|
+
outerHTML: outerHTML.length > 4e3 ? `${outerHTML.slice(0, 4e3)}\u2026` : outerHTML,
|
|
1499
|
+
text: text.length > 1e3 ? `${text.slice(0, 1e3)}\u2026` : text,
|
|
1500
|
+
attributes
|
|
1501
|
+
};
|
|
1502
|
+
};
|
|
1503
|
+
if (source) {
|
|
1504
|
+
const editorUrl = buildEditorUrl(source, editor, projectPath);
|
|
1505
|
+
console.info(
|
|
1506
|
+
"[UiDog Next] Source detected:",
|
|
1507
|
+
normalizeFileName(source.fileName),
|
|
1508
|
+
"line",
|
|
1509
|
+
source.lineNumber,
|
|
1510
|
+
"column",
|
|
1511
|
+
source.columnNumber
|
|
1512
|
+
);
|
|
1513
|
+
if (enableSidebar) {
|
|
1514
|
+
const elementInfo = {
|
|
1515
|
+
kind: "source",
|
|
1516
|
+
componentName: source.functionName || "Unknown",
|
|
1517
|
+
filePath: normalizeFileName(source.fileName),
|
|
1518
|
+
line: source.lineNumber,
|
|
1519
|
+
column: source.columnNumber,
|
|
1520
|
+
box: rect ? {
|
|
1521
|
+
x: rect.x,
|
|
1522
|
+
y: rect.y,
|
|
1523
|
+
width: rect.width,
|
|
1524
|
+
height: rect.height
|
|
1525
|
+
} : void 0
|
|
1526
|
+
};
|
|
1527
|
+
openSidebar(elementInfo, editorUrl);
|
|
1528
|
+
} else {
|
|
1529
|
+
console.log("[UiDog Next] Element selected:");
|
|
1530
|
+
console.log(" Component:", source.functionName || "Unknown");
|
|
1531
|
+
console.log(" File:", source.fileName);
|
|
1532
|
+
console.log(" Line:", source.lineNumber);
|
|
1533
|
+
console.log(" Column:", source.columnNumber);
|
|
1534
|
+
console.log(" Editor URL:", editorUrl);
|
|
1535
|
+
}
|
|
1536
|
+
} else {
|
|
1537
|
+
const domSnapshot = buildDomSnapshot();
|
|
1538
|
+
console.info("[UiDog Next] DOM snapshot (no source):", {
|
|
1539
|
+
outerHTML: domSnapshot.outerHTML,
|
|
1540
|
+
text: domSnapshot.text,
|
|
1541
|
+
attributes: domSnapshot.attributes,
|
|
1542
|
+
box: rect ? {
|
|
1543
|
+
x: rect.x,
|
|
1544
|
+
y: rect.y,
|
|
1545
|
+
width: rect.width,
|
|
1546
|
+
height: rect.height
|
|
1547
|
+
} : void 0
|
|
1548
|
+
});
|
|
1549
|
+
const elementInfo = {
|
|
1550
|
+
kind: "dom",
|
|
1551
|
+
componentName: "Server-rendered element",
|
|
1552
|
+
domSnapshot,
|
|
1553
|
+
box: rect ? {
|
|
1554
|
+
x: rect.x,
|
|
1555
|
+
y: rect.y,
|
|
1556
|
+
width: rect.width,
|
|
1557
|
+
height: rect.height
|
|
1558
|
+
} : void 0
|
|
1559
|
+
};
|
|
1560
|
+
if (enableSidebar) {
|
|
1561
|
+
openSidebar(elementInfo, "");
|
|
1562
|
+
} else {
|
|
1563
|
+
console.log("[UiDog Next] Element selected (DOM snapshot):");
|
|
1564
|
+
console.log(" outerHTML:", domSnapshot.outerHTML);
|
|
1565
|
+
console.log(" text:", domSnapshot.text);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
console.log(
|
|
1571
|
+
`[UiDog Next] Initialized (${modifier}+click to select elements)`
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// src/client/index.ts
|
|
1576
|
+
var pendingOptions = {};
|
|
1577
|
+
var isAutoInitEnabled = true;
|
|
1578
|
+
function configureUiDogNext(options) {
|
|
1579
|
+
pendingOptions = { ...pendingOptions, ...options };
|
|
1580
|
+
}
|
|
1581
|
+
function disableAutoInit() {
|
|
1582
|
+
isAutoInitEnabled = false;
|
|
1583
|
+
}
|
|
1584
|
+
function initialize() {
|
|
1585
|
+
if (!isAutoInitEnabled)
|
|
1586
|
+
return;
|
|
1587
|
+
initializeUiDogNext(pendingOptions);
|
|
1588
|
+
}
|
|
1589
|
+
if (typeof window !== "undefined") {
|
|
1590
|
+
if (document.readyState === "loading") {
|
|
1591
|
+
document.addEventListener("DOMContentLoaded", initialize);
|
|
1592
|
+
} else {
|
|
1593
|
+
setTimeout(initialize, 0);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1597
|
+
0 && (module.exports = {
|
|
1598
|
+
configureUiDogNext,
|
|
1599
|
+
disableAutoInit,
|
|
1600
|
+
initializeUiDogNext
|
|
1601
|
+
});
|