@uxbertlabs/reportly 1.0.18 → 1.0.19
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/dist/features/n8n-integration.d.ts +8 -4
- package/dist/features/n8n-integration.d.ts.map +1 -1
- package/dist/reportly.cjs.js +140 -123
- package/dist/reportly.cjs.js.map +1 -1
- package/dist/reportly.esm.js +140 -123
- package/dist/reportly.esm.js.map +1 -1
- package/dist/reportly.js +140 -123
- package/dist/reportly.js.map +1 -1
- package/dist/reportly.min.js +2 -2
- package/dist/reportly.min.js.map +1 -1
- package/dist/ui/modal.d.ts +3 -3
- package/dist/ui/modal.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/reportly.esm.js
CHANGED
@@ -182,11 +182,11 @@ class Modal {
|
|
182
182
|
}
|
183
183
|
create() {
|
184
184
|
// Create overlay
|
185
|
-
this.overlay = document.createElement(
|
186
|
-
this.overlay.className =
|
185
|
+
this.overlay = document.createElement("div");
|
186
|
+
this.overlay.className = "uxbert-overlay";
|
187
187
|
// Create modal
|
188
|
-
this.modal = document.createElement(
|
189
|
-
this.modal.className =
|
188
|
+
this.modal = document.createElement("div");
|
189
|
+
this.modal.className = "uxbert-modal";
|
190
190
|
// Modal HTML
|
191
191
|
this.modal.innerHTML = `
|
192
192
|
<div class="uxbert-modal-header">
|
@@ -231,12 +231,13 @@ class Modal {
|
|
231
231
|
|
232
232
|
<div class="uxbert-form-group">
|
233
233
|
<label class="uxbert-form-label" for="uxbert-priority">Priority</label>
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
</
|
234
|
+
<select id="uxbert-priority" class="uxbert-form-select">
|
235
|
+
<option value="5" selected>Lowest</option>
|
236
|
+
<option value="4">Low</option>
|
237
|
+
<option value="3" selected>Medium</option>
|
238
|
+
<option value="2">High</option>
|
239
|
+
<option value="1">Highest</option>
|
240
|
+
</select>
|
240
241
|
</div>
|
241
242
|
|
242
243
|
<div class="uxbert-capture-action" id="uxbert-capture-action">
|
@@ -280,67 +281,67 @@ class Modal {
|
|
280
281
|
if (!this.modal)
|
281
282
|
return;
|
282
283
|
// Close button
|
283
|
-
const closeBtn = this.modal.querySelector(
|
284
|
-
closeBtn.addEventListener(
|
284
|
+
const closeBtn = this.modal.querySelector(".uxbert-modal-close");
|
285
|
+
closeBtn.addEventListener("click", () => this.close());
|
285
286
|
// Cancel button
|
286
|
-
const cancelBtn = this.modal.querySelector(
|
287
|
-
cancelBtn.addEventListener(
|
287
|
+
const cancelBtn = this.modal.querySelector("#uxbert-cancel-btn");
|
288
|
+
cancelBtn.addEventListener("click", () => this.close());
|
288
289
|
// Overlay click to close
|
289
|
-
this.overlay?.addEventListener(
|
290
|
+
this.overlay?.addEventListener("click", (e) => {
|
290
291
|
if (e.target === this.overlay) {
|
291
292
|
this.close();
|
292
293
|
}
|
293
294
|
});
|
294
295
|
// Form submit
|
295
|
-
const form = this.modal.querySelector(
|
296
|
-
form.addEventListener(
|
296
|
+
const form = this.modal.querySelector("#uxbert-issue-form");
|
297
|
+
form.addEventListener("submit", (e) => {
|
297
298
|
e.preventDefault();
|
298
299
|
this.handleSubmit();
|
299
300
|
});
|
300
301
|
// Capture button
|
301
|
-
const captureBtn = this.modal.querySelector(
|
302
|
-
captureBtn.addEventListener(
|
302
|
+
const captureBtn = this.modal.querySelector("#uxbert-capture-btn");
|
303
|
+
captureBtn.addEventListener("click", () => {
|
303
304
|
if (this.callbacks.onCapture) {
|
304
305
|
this.callbacks.onCapture();
|
305
306
|
}
|
306
307
|
});
|
307
308
|
// Annotate button
|
308
|
-
const annotateBtn = this.modal.querySelector(
|
309
|
-
annotateBtn.addEventListener(
|
309
|
+
const annotateBtn = this.modal.querySelector("#uxbert-annotate-btn");
|
310
|
+
annotateBtn.addEventListener("click", () => {
|
310
311
|
if (this.callbacks.onAnnotate) {
|
311
312
|
this.callbacks.onAnnotate();
|
312
313
|
}
|
313
314
|
});
|
314
315
|
// Retake button
|
315
|
-
const retakeBtn = this.modal.querySelector(
|
316
|
-
retakeBtn.addEventListener(
|
316
|
+
const retakeBtn = this.modal.querySelector("#uxbert-retake-btn");
|
317
|
+
retakeBtn.addEventListener("click", () => {
|
317
318
|
if (this.callbacks.onRetake) {
|
318
319
|
this.callbacks.onRetake();
|
319
320
|
}
|
320
321
|
});
|
321
322
|
// n8n button
|
322
|
-
const n8nBtn = this.modal.querySelector(
|
323
|
-
n8nBtn.addEventListener(
|
323
|
+
const n8nBtn = this.modal.querySelector("#uxbert-n8n-btn");
|
324
|
+
n8nBtn.addEventListener("click", () => {
|
324
325
|
this.handleN8nSubmit();
|
325
326
|
});
|
326
327
|
}
|
327
328
|
handleN8nSubmit() {
|
328
329
|
if (!this.modal)
|
329
330
|
return;
|
330
|
-
const titleInput = this.modal.querySelector(
|
331
|
-
const descriptionInput = this.modal.querySelector(
|
332
|
-
const prioritySelect = this.modal.querySelector(
|
331
|
+
const titleInput = this.modal.querySelector("#uxbert-title");
|
332
|
+
const descriptionInput = this.modal.querySelector("#uxbert-description");
|
333
|
+
const prioritySelect = this.modal.querySelector("#uxbert-priority");
|
333
334
|
const title = titleInput.value;
|
334
335
|
const description = descriptionInput.value;
|
335
336
|
const priority = prioritySelect.value;
|
336
337
|
if (!title.trim()) {
|
337
|
-
alert(
|
338
|
+
alert("Please enter an issue title");
|
338
339
|
return;
|
339
340
|
}
|
340
341
|
const issueData = {
|
341
342
|
title: title.trim(),
|
342
343
|
description: description.trim(),
|
343
|
-
priority
|
344
|
+
priority,
|
344
345
|
};
|
345
346
|
if (this.callbacks.onSendToN8n) {
|
346
347
|
this.callbacks.onSendToN8n(issueData);
|
@@ -349,30 +350,34 @@ class Modal {
|
|
349
350
|
handleSubmit() {
|
350
351
|
if (!this.modal)
|
351
352
|
return;
|
352
|
-
const titleInput = this.modal.querySelector(
|
353
|
-
const descriptionInput = this.modal.querySelector(
|
354
|
-
const prioritySelect = this.modal.querySelector(
|
353
|
+
const titleInput = this.modal.querySelector("#uxbert-title");
|
354
|
+
const descriptionInput = this.modal.querySelector("#uxbert-description");
|
355
|
+
const prioritySelect = this.modal.querySelector("#uxbert-priority");
|
355
356
|
const title = titleInput.value;
|
356
357
|
const description = descriptionInput.value;
|
357
358
|
const priority = prioritySelect.value;
|
358
359
|
if (!title.trim()) {
|
359
|
-
alert(
|
360
|
+
alert("Please enter an issue title");
|
360
361
|
return;
|
361
362
|
}
|
362
363
|
const issueData = {
|
363
364
|
title: title.trim(),
|
364
365
|
description: description.trim(),
|
365
|
-
priority
|
366
|
+
priority,
|
366
367
|
};
|
367
368
|
if (this.callbacks.onSubmit) {
|
368
369
|
this.callbacks.onSubmit(issueData);
|
369
370
|
}
|
370
371
|
}
|
371
372
|
open() {
|
372
|
-
this.overlay?.classList.add(
|
373
|
+
this.overlay?.classList.add("active");
|
374
|
+
// Prevent body scroll when modal is open
|
375
|
+
document.body.style.overflow = "hidden";
|
373
376
|
}
|
374
377
|
close() {
|
375
|
-
this.overlay?.classList.remove(
|
378
|
+
this.overlay?.classList.remove("active");
|
379
|
+
// Restore body scroll when modal is closed
|
380
|
+
document.body.style.overflow = "";
|
376
381
|
this.reset();
|
377
382
|
if (this.callbacks.onClose) {
|
378
383
|
this.callbacks.onClose();
|
@@ -381,47 +386,49 @@ class Modal {
|
|
381
386
|
setScreenshot(screenshot) {
|
382
387
|
if (!this.modal)
|
383
388
|
return;
|
384
|
-
const container = this.modal.querySelector(
|
385
|
-
const img = this.modal.querySelector(
|
386
|
-
const captureAction = this.modal.querySelector(
|
387
|
-
const submitBtn = this.modal.querySelector(
|
389
|
+
const container = this.modal.querySelector("#uxbert-screenshot-container");
|
390
|
+
const img = this.modal.querySelector("#uxbert-screenshot-img");
|
391
|
+
const captureAction = this.modal.querySelector("#uxbert-capture-action");
|
392
|
+
const submitBtn = this.modal.querySelector("#uxbert-submit-btn");
|
388
393
|
if (screenshot) {
|
389
394
|
img.src = screenshot;
|
390
|
-
container.style.display =
|
391
|
-
captureAction.style.display =
|
395
|
+
container.style.display = "block";
|
396
|
+
captureAction.style.display = "none";
|
392
397
|
submitBtn.disabled = false;
|
393
398
|
}
|
394
399
|
else {
|
395
|
-
container.style.display =
|
396
|
-
captureAction.style.display =
|
400
|
+
container.style.display = "none";
|
401
|
+
captureAction.style.display = "block";
|
397
402
|
submitBtn.disabled = true;
|
398
403
|
}
|
399
404
|
}
|
400
405
|
getCaptureMode() {
|
401
406
|
if (!this.modal)
|
402
|
-
return
|
403
|
-
const viewportRadio = this.modal.querySelector(
|
404
|
-
return viewportRadio.checked ?
|
407
|
+
return "viewport";
|
408
|
+
const viewportRadio = this.modal.querySelector("#uxbert-capture-viewport");
|
409
|
+
return viewportRadio.checked ? "viewport" : "fullpage";
|
405
410
|
}
|
406
411
|
setN8nButtonVisible(visible) {
|
407
412
|
if (!this.modal)
|
408
413
|
return;
|
409
|
-
const n8nBtn = this.modal.querySelector(
|
414
|
+
const n8nBtn = this.modal.querySelector("#uxbert-n8n-btn");
|
410
415
|
if (n8nBtn) {
|
411
|
-
n8nBtn.style.display = visible ?
|
416
|
+
n8nBtn.style.display = visible ? "inline-block" : "none";
|
412
417
|
}
|
413
418
|
}
|
414
419
|
reset() {
|
415
420
|
if (!this.modal)
|
416
421
|
return;
|
417
|
-
this.modal.querySelector(
|
418
|
-
this.modal.querySelector(
|
419
|
-
this.modal.querySelector(
|
422
|
+
this.modal.querySelector("#uxbert-title").value = "";
|
423
|
+
this.modal.querySelector("#uxbert-description").value = "";
|
424
|
+
this.modal.querySelector("#uxbert-priority").value = "Medium";
|
420
425
|
this.setScreenshot(null);
|
421
426
|
}
|
422
427
|
destroy() {
|
423
428
|
if (this.overlay && this.overlay.parentNode) {
|
424
429
|
this.overlay.parentNode.removeChild(this.overlay);
|
430
|
+
// Restore body scroll when destroying modal
|
431
|
+
document.body.style.overflow = "";
|
425
432
|
this.overlay = null;
|
426
433
|
this.modal = null;
|
427
434
|
}
|
@@ -10220,24 +10227,23 @@ class N8nIntegration {
|
|
10220
10227
|
if (!this.config || !this.config.webhookUrl) {
|
10221
10228
|
return {
|
10222
10229
|
success: false,
|
10223
|
-
message:
|
10224
|
-
error:
|
10230
|
+
message: "n8n webhook URL is not configured",
|
10231
|
+
error: "MISSING_CONFIG",
|
10225
10232
|
};
|
10226
10233
|
}
|
10227
10234
|
if (!this.config.enabled) {
|
10228
10235
|
return {
|
10229
10236
|
success: false,
|
10230
|
-
message:
|
10231
|
-
error:
|
10237
|
+
message: "n8n integration is disabled",
|
10238
|
+
error: "DISABLED",
|
10232
10239
|
};
|
10233
10240
|
}
|
10234
10241
|
try {
|
10235
|
-
// Prepare
|
10236
|
-
const
|
10237
|
-
// Setup request headers
|
10242
|
+
// Prepare FormData with binary screenshot
|
10243
|
+
const formData = await this.prepareFormData(issueData);
|
10244
|
+
// Setup request headers (don't set Content-Type - browser will set it with boundary for FormData)
|
10238
10245
|
const headers = {
|
10239
|
-
|
10240
|
-
...this.config.headers
|
10246
|
+
...this.config.headers,
|
10241
10247
|
};
|
10242
10248
|
// Setup timeout
|
10243
10249
|
const timeout = this.config.timeout || 30000; // 30 seconds default
|
@@ -10245,19 +10251,19 @@ class N8nIntegration {
|
|
10245
10251
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
10246
10252
|
// Send request
|
10247
10253
|
const response = await fetch(this.config.webhookUrl, {
|
10248
|
-
method:
|
10254
|
+
method: "POST",
|
10249
10255
|
headers,
|
10250
|
-
body:
|
10251
|
-
signal: controller.signal
|
10256
|
+
body: formData,
|
10257
|
+
signal: controller.signal,
|
10252
10258
|
});
|
10253
10259
|
clearTimeout(timeoutId);
|
10254
10260
|
// Check response
|
10255
10261
|
if (!response.ok) {
|
10256
|
-
const errorText = await response.text().catch(() =>
|
10262
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
10257
10263
|
return {
|
10258
10264
|
success: false,
|
10259
10265
|
message: `n8n webhook request failed: ${response.status} ${response.statusText}`,
|
10260
|
-
error: errorText
|
10266
|
+
error: errorText,
|
10261
10267
|
};
|
10262
10268
|
}
|
10263
10269
|
// Parse response
|
@@ -10267,76 +10273,87 @@ class N8nIntegration {
|
|
10267
10273
|
}
|
10268
10274
|
catch (e) {
|
10269
10275
|
// Some webhooks don't return JSON
|
10270
|
-
responseData = { message:
|
10276
|
+
responseData = { message: "Success" };
|
10271
10277
|
}
|
10272
10278
|
return {
|
10273
10279
|
success: true,
|
10274
|
-
message:
|
10275
|
-
workflowId: responseData.workflowId || responseData.executionId
|
10280
|
+
message: "Issue sent to n8n successfully",
|
10281
|
+
workflowId: responseData.workflowId || responseData.executionId,
|
10276
10282
|
};
|
10277
10283
|
}
|
10278
10284
|
catch (error) {
|
10279
10285
|
if (error instanceof Error) {
|
10280
|
-
if (error.name ===
|
10286
|
+
if (error.name === "AbortError") {
|
10281
10287
|
return {
|
10282
10288
|
success: false,
|
10283
|
-
message:
|
10284
|
-
error:
|
10289
|
+
message: "Request to n8n webhook timed out",
|
10290
|
+
error: "TIMEOUT",
|
10285
10291
|
};
|
10286
10292
|
}
|
10287
10293
|
return {
|
10288
10294
|
success: false,
|
10289
10295
|
message: `Failed to send issue to n8n: ${error.message}`,
|
10290
|
-
error: error.message
|
10296
|
+
error: error.message,
|
10291
10297
|
};
|
10292
10298
|
}
|
10293
10299
|
return {
|
10294
10300
|
success: false,
|
10295
|
-
message:
|
10296
|
-
error:
|
10301
|
+
message: "Unknown error occurred while sending to n8n",
|
10302
|
+
error: "UNKNOWN",
|
10297
10303
|
};
|
10298
10304
|
}
|
10299
10305
|
}
|
10300
10306
|
/**
|
10301
|
-
*
|
10302
|
-
* This formats the data in a structure that's easy to work with in n8n
|
10307
|
+
* Convert base64 data URL to Blob
|
10303
10308
|
*/
|
10304
|
-
|
10305
|
-
|
10306
|
-
|
10307
|
-
|
10308
|
-
|
10309
|
-
|
10310
|
-
|
10311
|
-
|
10312
|
-
|
10313
|
-
|
10314
|
-
|
10315
|
-
|
10316
|
-
|
10317
|
-
|
10318
|
-
|
10319
|
-
|
10320
|
-
|
10321
|
-
|
10322
|
-
|
10323
|
-
|
10324
|
-
|
10325
|
-
|
10326
|
-
|
10327
|
-
|
10328
|
-
|
10329
|
-
|
10330
|
-
|
10331
|
-
|
10332
|
-
|
10333
|
-
|
10334
|
-
|
10335
|
-
|
10336
|
-
|
10337
|
-
|
10338
|
-
|
10339
|
-
|
10309
|
+
base64ToBlob(base64Data) {
|
10310
|
+
// Extract the base64 string and mime type
|
10311
|
+
const matches = base64Data.match(/^data:([^;]+);base64,(.+)$/);
|
10312
|
+
if (!matches) {
|
10313
|
+
throw new Error("Invalid base64 data URL");
|
10314
|
+
}
|
10315
|
+
const mimeType = matches[1];
|
10316
|
+
const base64String = matches[2];
|
10317
|
+
// Decode base64
|
10318
|
+
const byteCharacters = atob(base64String);
|
10319
|
+
const byteNumbers = new Array(byteCharacters.length);
|
10320
|
+
for (let i = 0; i < byteCharacters.length; i++) {
|
10321
|
+
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
10322
|
+
}
|
10323
|
+
const byteArray = new Uint8Array(byteNumbers);
|
10324
|
+
return new Blob([byteArray], { type: mimeType });
|
10325
|
+
}
|
10326
|
+
/**
|
10327
|
+
* Prepare FormData payload for n8n webhook
|
10328
|
+
* This sends the screenshot as a binary file instead of base64 JSON
|
10329
|
+
*/
|
10330
|
+
async prepareFormData(issueData) {
|
10331
|
+
const formData = new FormData();
|
10332
|
+
// Add issue data as JSON string
|
10333
|
+
formData.append("title", issueData.title);
|
10334
|
+
formData.append("description", issueData.description);
|
10335
|
+
formData.append("priority", issueData.priority);
|
10336
|
+
formData.append("createdAt", issueData.createdAt);
|
10337
|
+
// Convert base64 screenshot to binary Blob and add as file
|
10338
|
+
const screenshotBlob = this.base64ToBlob(issueData.screenshot);
|
10339
|
+
const filename = `screenshot-${Date.now()}.png`;
|
10340
|
+
formData.append("screenshot", screenshotBlob, filename);
|
10341
|
+
// Add device info as individual fields
|
10342
|
+
formData.append("browser", issueData.deviceInfo.browser);
|
10343
|
+
formData.append("os", issueData.deviceInfo.os);
|
10344
|
+
formData.append("screenResolution", issueData.deviceInfo.screenResolution);
|
10345
|
+
formData.append("viewport", issueData.deviceInfo.viewport);
|
10346
|
+
formData.append("url", issueData.deviceInfo.url);
|
10347
|
+
formData.append("userAgent", issueData.deviceInfo.userAgent);
|
10348
|
+
formData.append("language", issueData.deviceInfo.language || "");
|
10349
|
+
formData.append("platform", issueData.deviceInfo.platform);
|
10350
|
+
formData.append("cookiesEnabled", String(issueData.deviceInfo.cookiesEnabled));
|
10351
|
+
formData.append("onLine", String(issueData.deviceInfo.onLine));
|
10352
|
+
formData.append("timestamp", issueData.deviceInfo.timestamp);
|
10353
|
+
// Add metadata
|
10354
|
+
formData.append("source", "uxbert-reportly");
|
10355
|
+
formData.append("version", "1.0.0");
|
10356
|
+
return formData;
|
10340
10357
|
}
|
10341
10358
|
/**
|
10342
10359
|
* Test connection to n8n webhook
|
@@ -10345,28 +10362,28 @@ class N8nIntegration {
|
|
10345
10362
|
if (!this.config || !this.config.webhookUrl) {
|
10346
10363
|
return {
|
10347
10364
|
success: false,
|
10348
|
-
message:
|
10349
|
-
error:
|
10365
|
+
message: "n8n webhook URL is not configured",
|
10366
|
+
error: "MISSING_CONFIG",
|
10350
10367
|
};
|
10351
10368
|
}
|
10352
10369
|
try {
|
10353
10370
|
const controller = new AbortController();
|
10354
10371
|
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout for test
|
10355
10372
|
await fetch(this.config.webhookUrl, {
|
10356
|
-
method:
|
10357
|
-
signal: controller.signal
|
10373
|
+
method: "HEAD",
|
10374
|
+
signal: controller.signal,
|
10358
10375
|
});
|
10359
10376
|
clearTimeout(timeoutId);
|
10360
10377
|
return {
|
10361
10378
|
success: true,
|
10362
|
-
message:
|
10379
|
+
message: "n8n webhook is reachable",
|
10363
10380
|
};
|
10364
10381
|
}
|
10365
10382
|
catch (error) {
|
10366
10383
|
return {
|
10367
10384
|
success: false,
|
10368
|
-
message:
|
10369
|
-
error: error instanceof Error ? error.message :
|
10385
|
+
message: "Failed to reach n8n webhook",
|
10386
|
+
error: error instanceof Error ? error.message : "UNKNOWN",
|
10370
10387
|
};
|
10371
10388
|
}
|
10372
10389
|
}
|
@@ -10383,7 +10400,7 @@ class N8nIntegration {
|
|
10383
10400
|
if (!this.config) {
|
10384
10401
|
this.config = {
|
10385
10402
|
webhookUrl: url,
|
10386
|
-
enabled: true
|
10403
|
+
enabled: true,
|
10387
10404
|
};
|
10388
10405
|
}
|
10389
10406
|
else {
|
@@ -10549,7 +10566,7 @@ function styleInject(css, ref) {
|
|
10549
10566
|
}
|
10550
10567
|
}
|
10551
10568
|
|
10552
|
-
var css_248z = ":root{--uxbert-primary:#4f46e5;--uxbert-primary-hover:#4338ca;--uxbert-danger:#ef4444;--uxbert-success:#10b981;--uxbert-bg:#fff;--uxbert-text:#1f2937;--uxbert-border:#e5e7eb;--uxbert-shadow:0 10px 25px rgba(0,0,0,.1);--uxbert-z-button:999999;--uxbert-z-modal:1000000;--uxbert-z-canvas:1000001;--uxbert-z-toolbar:1000002}[data-theme=dark]{--uxbert-bg:#1f2937;--uxbert-text:#f9fafb;--uxbert-border:#374151}.uxbert-fab{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:flex;font-size:24px;height:56px;justify-content:center;position:fixed;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-button)}.uxbert-fab:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-fab.bottom-right{bottom:24px;right:24px}.uxbert-fab.bottom-left{bottom:24px;left:24px}.uxbert-fab.top-right{right:24px;top:24px}.uxbert-fab.top-left{left:24px;top:24px}.uxbert-overlay{align-items:center;animation:fadeIn .3s ease;background:rgba(0,0,0,.5);display:none;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:var(--uxbert-z-modal)}.uxbert-overlay.active{display:flex}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.uxbert-modal{animation:slideUp .3s ease;background:var(--uxbert-bg);border-radius:12px;box-shadow:var(--uxbert-shadow);color:var(--uxbert-text);max-height:90vh;max-width:600px;overflow-y:auto;padding:24px;width:90%}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.uxbert-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:20px}.uxbert-modal-title{font-size:20px;font-weight:600;margin:0}.uxbert-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:24px;height:32px;justify-content:center;padding:0;width:32px}.uxbert-modal-close:hover{background:var(--uxbert-border)}.uxbert-form-group{margin-bottom:16px}.uxbert-form-label{display:block;font-size:14px;font-weight:500;margin-bottom:8px}.uxbert-capture-mode{display:flex;flex-wrap:wrap;gap:12px}.uxbert-radio-label{align-items:center;border:2px solid var(--uxbert-border);border-radius:8px;cursor:pointer;display:flex;flex:1;gap:8px;min-width:140px;padding:10px 16px;transition:all .2s ease}.uxbert-radio-label:hover{background:rgba(79,70,229,.05);border-color:var(--uxbert-primary)}.uxbert-radio-label input[type=radio]{cursor:pointer;height:18px;margin:0;width:18px}.uxbert-radio-label input[type=radio]:checked{accent-color:var(--uxbert-primary)}.uxbert-radio-label:has(input[type=radio]:checked){background:rgba(79,70,229,.1);border-color:var(--uxbert-primary)}.uxbert-radio-label span{flex:1;font-size:14px;font-weight:500}.uxbert-form-input,.uxbert-form-select,.uxbert-form-textarea{background:var(--uxbert-bg);border:1px solid var(--uxbert-border);border-radius:6px;box-sizing:border-box;color:var(--uxbert-text);font-family:inherit;font-size:14px;padding:10px;width:100%}.uxbert-form-textarea{min-height:100px;resize:vertical}.uxbert-form-input:focus,.uxbert-form-select:focus,.uxbert-form-textarea:focus{border-color:var(--uxbert-primary);outline:none}.uxbert-capture-action{margin:16px 0;text-align:center}.uxbert-capture-action .uxbert-btn{min-width:200px}.uxbert-screenshot-preview{border:1px solid var(--uxbert-border);border-radius:8px;margin:16px 0;overflow:hidden}.uxbert-screenshot-preview img{display:block;width:100%}.uxbert-screenshot-actions{background:var(--uxbert-border);display:flex;gap:8px;padding:12px}.uxbert-btn{align-items:center;border:none;border-radius:6px;cursor:pointer;display:inline-flex;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all .2s ease}.uxbert-btn-primary{background:var(--uxbert-primary);color:#fff}.uxbert-btn-primary:hover{background:var(--uxbert-primary-hover)}.uxbert-btn-secondary{background:var(--uxbert-border);color:var(--uxbert-text)}.uxbert-btn-secondary:hover{background:#d1d5db}.uxbert-btn-success{background:var(--uxbert-success);color:#fff}.uxbert-btn-success:hover{background:#059669}.uxbert-btn-danger{background:var(--uxbert-danger);color:#fff}.uxbert-btn-danger:hover{background:#dc2626}.uxbert-modal-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:20px}.uxbert-toolbar-toggle{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;bottom:24px;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:none;font-size:24px;height:56px;justify-content:center;position:fixed;right:24px;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar-toggle.active{display:flex}.uxbert-toolbar-toggle.hidden{opacity:0;pointer-events:none;transform:scale(.8)}.uxbert-toolbar-toggle:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-toolbar{background:var(--uxbert-bg);border-radius:12px;bottom:24px;box-shadow:var(--uxbert-shadow);display:none;flex-direction:column;gap:8px;max-height:80vh;opacity:0;overflow-y:auto;padding:16px;pointer-events:none;position:fixed;right:24px;transform:translateY(20px);transition:all .3s ease;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar.active{display:flex}.uxbert-toolbar.expanded{opacity:1;pointer-events:all;transform:translateY(0)}.uxbert-toolbar-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:8px}.uxbert-toolbar-title{flex:1;font-size:14px;font-weight:600}.uxbert-toolbar-exit,.uxbert-toolbar-minimize{align-items:center;background:var(--uxbert-border);border:none;border-radius:6px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:20px;font-weight:700;height:32px;justify-content:center;transition:all .2s ease;width:32px}.uxbert-toolbar-exit{background:var(--uxbert-danger);color:#fff}.uxbert-toolbar-minimize:hover{background:#d1d5db;transform:scale(1.1)}.uxbert-toolbar-exit:hover{background:#dc2626;transform:scale(1.1)}.uxbert-toolbar-tools{display:flex;flex-wrap:wrap;gap:8px}.uxbert-tool-btn{align-items:center;background:var(--uxbert-bg);border:2px solid var(--uxbert-border);border-radius:6px;cursor:pointer;display:flex;font-family:Arial,sans-serif;font-size:18px;font-weight:700;height:40px;justify-content:center;transition:all .2s ease;width:40px}.uxbert-tool-btn.active,.uxbert-tool-btn:hover{background:var(--uxbert-primary);border-color:var(--uxbert-primary);color:#fff}.uxbert-color-picker{display:flex;gap:6px;margin:8px 0}.uxbert-color-option{border:2px solid var(--uxbert-border);border-radius:50%;cursor:pointer;height:32px;transition:transform .2s ease;width:32px}.uxbert-color-option:hover{transform:scale(1.1)}.uxbert-color-option.active{border:3px solid var(--uxbert-text)}.uxbert-canvas-overlay{cursor:crosshair;display:none;left:0;position:absolute;top:0;z-index:var(--uxbert-z-canvas)}.uxbert-canvas-overlay.active{display:block}.uxbert-canvas-overlay.viewport-mode{left:0;position:fixed;top:0}.uxbert-text-input{background:hsla(0,0%,100%,.95);border:2px solid var(--uxbert-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--uxbert-text);font-family:Arial,sans-serif;font-size:16px;font-weight:700;min-width:200px;outline:none;padding:8px 12px;z-index:var(--uxbert-z-toolbar)}.uxbert-text-input:focus{border-color:var(--uxbert-primary-hover);box-shadow:0 4px 16px rgba(79,70,229,.3)}.uxbert-text-input::placeholder{color:#9ca3af;font-weight:400}@media (max-width:768px){.uxbert-modal{max-height:95vh;padding:16px;width:95%}.uxbert-toolbar{bottom:90px;left:16px;max-height:60vh;right:16px;width:auto}.uxbert-toolbar-toggle{bottom:16px;height:56px;right:16px;width:56px}.uxbert-fab{font-size:20px;height:48px;width:48px}.uxbert-color-picker,.uxbert-toolbar-tools{justify-content:center}}";
|
10569
|
+
var css_248z = ":root{--uxbert-primary:#4f46e5;--uxbert-primary-hover:#4338ca;--uxbert-danger:#ef4444;--uxbert-success:#10b981;--uxbert-bg:#fff;--uxbert-text:#1f2937;--uxbert-border:#e5e7eb;--uxbert-shadow:0 10px 25px rgba(0,0,0,.1);--uxbert-z-button:999999;--uxbert-z-modal:1000000;--uxbert-z-canvas:1000001;--uxbert-z-toolbar:1000002}[data-theme=dark]{--uxbert-bg:#1f2937;--uxbert-text:#f9fafb;--uxbert-border:#374151}.uxbert-fab{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:flex;font-size:24px;height:56px;justify-content:center;position:fixed;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-button)}.uxbert-fab:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-fab.bottom-right{bottom:24px;right:24px}.uxbert-fab.bottom-left{bottom:24px;left:24px}.uxbert-fab.top-right{right:24px;top:24px}.uxbert-fab.top-left{left:24px;top:24px}.uxbert-overlay{align-items:center;animation:fadeIn .3s ease;background:rgba(0,0,0,.5);display:none;height:100%;justify-content:center;left:0;overflow:hidden;position:fixed;top:0;width:100%;z-index:var(--uxbert-z-modal)}.uxbert-overlay.active{display:flex}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.uxbert-modal{animation:slideUp .3s ease;background:var(--uxbert-bg);border-radius:12px;box-shadow:var(--uxbert-shadow);color:var(--uxbert-text);max-height:90vh;max-width:600px;overflow-y:auto;padding:24px;width:90%}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.uxbert-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:20px}.uxbert-modal-title{font-size:20px;font-weight:600;margin:0}.uxbert-modal-close{align-items:center;background:none;border:none;border-radius:4px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:24px;height:32px;justify-content:center;padding:0;width:32px}.uxbert-modal-close:hover{background:var(--uxbert-border)}.uxbert-form-group{margin-bottom:16px}.uxbert-form-label{display:block;font-size:14px;font-weight:500;margin-bottom:8px}.uxbert-capture-mode{display:flex;flex-wrap:wrap;gap:12px}.uxbert-radio-label{align-items:center;border:2px solid var(--uxbert-border);border-radius:8px;cursor:pointer;display:flex;flex:1;gap:8px;min-width:140px;padding:10px 16px;transition:all .2s ease}.uxbert-radio-label:hover{background:rgba(79,70,229,.05);border-color:var(--uxbert-primary)}.uxbert-radio-label input[type=radio]{cursor:pointer;height:18px;margin:0;width:18px}.uxbert-radio-label input[type=radio]:checked{accent-color:var(--uxbert-primary)}.uxbert-radio-label:has(input[type=radio]:checked){background:rgba(79,70,229,.1);border-color:var(--uxbert-primary)}.uxbert-radio-label span{flex:1;font-size:14px;font-weight:500}.uxbert-form-input,.uxbert-form-select,.uxbert-form-textarea{background:var(--uxbert-bg);border:1px solid var(--uxbert-border);border-radius:6px;box-sizing:border-box;color:var(--uxbert-text);font-family:inherit;font-size:14px;padding:10px;width:100%}.uxbert-form-textarea{min-height:100px;resize:vertical}.uxbert-form-input:focus,.uxbert-form-select:focus,.uxbert-form-textarea:focus{border-color:var(--uxbert-primary);outline:none}.uxbert-capture-action{margin:16px 0;text-align:center}.uxbert-capture-action .uxbert-btn{min-width:200px}.uxbert-screenshot-preview{border:1px solid var(--uxbert-border);border-radius:8px;margin:16px 0;overflow:hidden}.uxbert-screenshot-preview img{display:block;width:100%}.uxbert-screenshot-actions{background:var(--uxbert-border);display:flex;gap:8px;padding:12px}.uxbert-btn{align-items:center;border:none;border-radius:6px;cursor:pointer;display:inline-flex;font-size:14px;font-weight:500;gap:8px;padding:10px 20px;transition:all .2s ease}.uxbert-btn-primary{background:var(--uxbert-primary);color:#fff}.uxbert-btn-primary:hover{background:var(--uxbert-primary-hover)}.uxbert-btn-secondary{background:var(--uxbert-border);color:var(--uxbert-text)}.uxbert-btn-secondary:hover{background:#d1d5db}.uxbert-btn-success{background:var(--uxbert-success);color:#fff}.uxbert-btn-success:hover{background:#059669}.uxbert-btn-danger{background:var(--uxbert-danger);color:#fff}.uxbert-btn-danger:hover{background:#dc2626}.uxbert-modal-actions{display:flex;gap:12px;justify-content:flex-end;margin-top:20px}.uxbert-toolbar-toggle{align-items:center;background:var(--uxbert-primary);border:none;border-radius:50%;bottom:24px;box-shadow:var(--uxbert-shadow);color:#fff;cursor:pointer;display:none;font-size:24px;height:56px;justify-content:center;position:fixed;right:24px;transition:all .3s ease;width:56px;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar-toggle.active{display:flex}.uxbert-toolbar-toggle.hidden{opacity:0;pointer-events:none;transform:scale(.8)}.uxbert-toolbar-toggle:hover{background:var(--uxbert-primary-hover);transform:scale(1.1)}.uxbert-toolbar{background:var(--uxbert-bg);border-radius:12px;bottom:24px;box-shadow:var(--uxbert-shadow);display:none;flex-direction:column;gap:8px;max-height:80vh;opacity:0;overflow-y:auto;padding:16px;pointer-events:none;position:fixed;right:24px;transform:translateY(20px);transition:all .3s ease;z-index:var(--uxbert-z-toolbar)}.uxbert-toolbar.active{display:flex}.uxbert-toolbar.expanded{opacity:1;pointer-events:all;transform:translateY(0)}.uxbert-toolbar-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:8px}.uxbert-toolbar-title{flex:1;font-size:14px;font-weight:600}.uxbert-toolbar-exit,.uxbert-toolbar-minimize{align-items:center;background:var(--uxbert-border);border:none;border-radius:6px;color:var(--uxbert-text);cursor:pointer;display:flex;font-size:20px;font-weight:700;height:32px;justify-content:center;transition:all .2s ease;width:32px}.uxbert-toolbar-exit{background:var(--uxbert-danger);color:#fff}.uxbert-toolbar-minimize:hover{background:#d1d5db;transform:scale(1.1)}.uxbert-toolbar-exit:hover{background:#dc2626;transform:scale(1.1)}.uxbert-toolbar-tools{display:flex;flex-wrap:wrap;gap:8px}.uxbert-tool-btn{align-items:center;background:var(--uxbert-bg);border:2px solid var(--uxbert-border);border-radius:6px;cursor:pointer;display:flex;font-family:Arial,sans-serif;font-size:18px;font-weight:700;height:40px;justify-content:center;transition:all .2s ease;width:40px}.uxbert-tool-btn.active,.uxbert-tool-btn:hover{background:var(--uxbert-primary);border-color:var(--uxbert-primary);color:#fff}.uxbert-color-picker{display:flex;gap:6px;margin:8px 0}.uxbert-color-option{border:2px solid var(--uxbert-border);border-radius:50%;cursor:pointer;height:32px;transition:transform .2s ease;width:32px}.uxbert-color-option:hover{transform:scale(1.1)}.uxbert-color-option.active{border:3px solid var(--uxbert-text)}.uxbert-canvas-overlay{cursor:crosshair;display:none;left:0;position:absolute;top:0;z-index:var(--uxbert-z-canvas)}.uxbert-canvas-overlay.active{display:block}.uxbert-canvas-overlay.viewport-mode{left:0;position:fixed;top:0}.uxbert-text-input{background:hsla(0,0%,100%,.95);border:2px solid var(--uxbert-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--uxbert-text);font-family:Arial,sans-serif;font-size:16px;font-weight:700;min-width:200px;outline:none;padding:8px 12px;z-index:var(--uxbert-z-toolbar)}.uxbert-text-input:focus{border-color:var(--uxbert-primary-hover);box-shadow:0 4px 16px rgba(79,70,229,.3)}.uxbert-text-input::placeholder{color:#9ca3af;font-weight:400}@media (max-width:768px){.uxbert-modal{max-height:95vh;padding:16px;width:95%}.uxbert-toolbar{bottom:90px;left:16px;max-height:60vh;right:16px;width:auto}.uxbert-toolbar-toggle{bottom:16px;height:56px;right:16px;width:56px}.uxbert-fab{font-size:20px;height:48px;width:48px}.uxbert-color-picker,.uxbert-toolbar-tools{justify-content:center}}";
|
10553
10570
|
styleInject(css_248z);
|
10554
10571
|
|
10555
10572
|
// Main initialization file
|