@promakeai/inspector 0.0.3 → 0.1.0
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 +285 -80
- package/dist/hook.d.ts +38 -5
- package/dist/hook.d.ts.map +1 -1
- package/dist/hook.js +89 -14
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +575 -29
- package/dist/types.d.ts +26 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
package/dist/plugin.js
CHANGED
|
@@ -61,13 +61,23 @@ export function inspectorPlugin() {
|
|
|
61
61
|
let selectedElementData = null;
|
|
62
62
|
let overlay = null;
|
|
63
63
|
let controlBox = null;
|
|
64
|
+
let promakeBadge = null;
|
|
65
|
+
|
|
66
|
+
// Immediate update flags
|
|
67
|
+
let updateTextImmediately = false;
|
|
68
|
+
let updateImageImmediately = false;
|
|
64
69
|
|
|
65
70
|
// Customizable labels
|
|
66
71
|
let labels = {
|
|
67
72
|
editText: 'Edit Text',
|
|
68
73
|
textPlaceholder: 'Enter text...',
|
|
69
74
|
updateText: 'Update',
|
|
70
|
-
promptPlaceholder: 'Ask Promake for changes...'
|
|
75
|
+
promptPlaceholder: 'Ask Promake for changes...',
|
|
76
|
+
editImage: 'Change Image',
|
|
77
|
+
imageUploadTitle: 'Select Image',
|
|
78
|
+
imageUploadHint: 'Click or drag',
|
|
79
|
+
updateImage: 'Update Image',
|
|
80
|
+
badgeText: 'Built with Promake'
|
|
71
81
|
};
|
|
72
82
|
|
|
73
83
|
// Customizable theme colors
|
|
@@ -78,7 +88,10 @@ export function inspectorPlugin() {
|
|
|
78
88
|
buttonTextColor: '#ffffff',
|
|
79
89
|
inputBackgroundColor: '#f9fafb',
|
|
80
90
|
inputTextColor: '#111827',
|
|
81
|
-
inputBorderColor: '#d1d5db'
|
|
91
|
+
inputBorderColor: '#d1d5db',
|
|
92
|
+
badgeGradientStart: '#411E93',
|
|
93
|
+
badgeGradientEnd: '#E87C85',
|
|
94
|
+
badgeTextColor: '#ffffff'
|
|
82
95
|
};
|
|
83
96
|
|
|
84
97
|
// Create overlay for highlighting
|
|
@@ -114,37 +127,63 @@ export function inspectorPlugin() {
|
|
|
114
127
|
const isTextElement = element.textContent && element.children.length === 0;
|
|
115
128
|
const currentText = isTextElement ? element.textContent.trim() : '';
|
|
116
129
|
|
|
117
|
-
//
|
|
130
|
+
// Check if element is an image
|
|
131
|
+
const isImageElement = element.tagName === 'IMG';
|
|
132
|
+
const currentImageUrl = isImageElement ? element.src : '';
|
|
133
|
+
|
|
134
|
+
// Store element info in data attributes for later use
|
|
118
135
|
controlBox.setAttribute('data-is-text-element', isTextElement);
|
|
119
136
|
controlBox.setAttribute('data-current-text', currentText);
|
|
137
|
+
controlBox.setAttribute('data-is-image-element', isImageElement);
|
|
138
|
+
controlBox.setAttribute('data-current-image-url', currentImageUrl);
|
|
120
139
|
|
|
121
|
-
// Calculate position
|
|
122
|
-
const
|
|
123
|
-
const centerLeft = rect.left + (rect.width / 2) - (boxWidth / 2);
|
|
140
|
+
// Calculate position with viewport bounds
|
|
141
|
+
const viewportWidth = window.innerWidth;
|
|
124
142
|
const viewportHeight = window.innerHeight;
|
|
143
|
+
const padding = 10; // Minimum padding from viewport edges
|
|
144
|
+
|
|
145
|
+
// Calculate box width (responsive, between 320 and 600px, but never wider than viewport)
|
|
146
|
+
const maxWidth = Math.min(600, viewportWidth - (padding * 2));
|
|
147
|
+
const minWidth = Math.min(320, maxWidth);
|
|
148
|
+
const boxWidth = Math.max(minWidth, Math.min(rect.width, maxWidth));
|
|
149
|
+
|
|
150
|
+
// Calculate horizontal position (centered on element, but within viewport)
|
|
151
|
+
let centerLeft = rect.left + (rect.width / 2) - (boxWidth / 2);
|
|
152
|
+
// Ensure box doesn't overflow left or right
|
|
153
|
+
centerLeft = Math.max(padding, Math.min(centerLeft, viewportWidth - boxWidth - padding));
|
|
154
|
+
|
|
155
|
+
// Calculate vertical position
|
|
125
156
|
const spaceBelow = viewportHeight - rect.bottom;
|
|
126
157
|
const spaceAbove = rect.top;
|
|
127
158
|
|
|
128
159
|
// Estimate box height (only prompt input now, smaller)
|
|
129
160
|
const estimatedBoxHeight = 100;
|
|
130
161
|
|
|
131
|
-
//
|
|
162
|
+
// Calculate available space and max height
|
|
163
|
+
const maxBoxHeight = Math.min(400, viewportHeight - (padding * 4)); // Max 400px or viewport - padding
|
|
164
|
+
|
|
165
|
+
// Determine if box should be above or below element
|
|
132
166
|
let topPosition;
|
|
133
|
-
if (spaceBelow < estimatedBoxHeight && spaceAbove > spaceBelow) {
|
|
134
|
-
// Show above element
|
|
135
|
-
topPosition = rect.top -
|
|
167
|
+
if (spaceBelow < estimatedBoxHeight + padding && spaceAbove > spaceBelow) {
|
|
168
|
+
// Show above element
|
|
169
|
+
topPosition = Math.max(padding, rect.top - maxBoxHeight - 10);
|
|
136
170
|
controlBox.setAttribute('data-position', 'above');
|
|
137
171
|
} else {
|
|
138
172
|
// Show below element
|
|
139
173
|
topPosition = rect.bottom + 10;
|
|
174
|
+
// Ensure box fits in viewport
|
|
175
|
+
if (topPosition + maxBoxHeight > viewportHeight - padding) {
|
|
176
|
+
topPosition = Math.max(padding, viewportHeight - maxBoxHeight - padding);
|
|
177
|
+
}
|
|
140
178
|
controlBox.setAttribute('data-position', 'below');
|
|
141
179
|
}
|
|
142
180
|
|
|
143
181
|
controlBox.style.cssText = \`
|
|
144
182
|
position: fixed;
|
|
145
183
|
top: \${topPosition}px;
|
|
146
|
-
left: \${
|
|
184
|
+
left: \${centerLeft}px;
|
|
147
185
|
width: \${boxWidth}px;
|
|
186
|
+
max-height: \${maxBoxHeight}px;
|
|
148
187
|
background: \${theme.backgroundColor};
|
|
149
188
|
border: 1px solid #e5e7eb;
|
|
150
189
|
border-radius: 14px;
|
|
@@ -156,6 +195,7 @@ export function inspectorPlugin() {
|
|
|
156
195
|
display: flex;
|
|
157
196
|
flex-direction: column;
|
|
158
197
|
gap: 0;
|
|
198
|
+
overflow-y: auto;
|
|
159
199
|
\`;
|
|
160
200
|
|
|
161
201
|
// Only prompt input and buttons (always shown)
|
|
@@ -208,13 +248,14 @@ export function inspectorPlugin() {
|
|
|
208
248
|
const prompt = promptInput.value.trim();
|
|
209
249
|
if (prompt) {
|
|
210
250
|
if (window.parent !== window) {
|
|
211
|
-
|
|
251
|
+
const message = JSON.stringify({
|
|
212
252
|
type: 'INSPECTOR_PROMPT_SUBMITTED',
|
|
213
253
|
data: {
|
|
214
254
|
prompt: prompt,
|
|
215
255
|
element: elementData
|
|
216
256
|
}
|
|
217
|
-
}
|
|
257
|
+
});
|
|
258
|
+
window.parent.postMessage(message, '*');
|
|
218
259
|
}
|
|
219
260
|
console.log('Prompt submitted:', elementData);
|
|
220
261
|
|
|
@@ -298,15 +339,37 @@ export function inspectorPlugin() {
|
|
|
298
339
|
textSubmit.addEventListener('click', (e) => {
|
|
299
340
|
e.stopPropagation();
|
|
300
341
|
const newText = textInput.value;
|
|
342
|
+
|
|
343
|
+
// Update DOM immediately if requested
|
|
344
|
+
if (updateTextImmediately && selectedElement) {
|
|
345
|
+
// Find all text nodes and update them
|
|
346
|
+
const updateTextNodes = (element) => {
|
|
347
|
+
for (let i = 0; i < element.childNodes.length; i++) {
|
|
348
|
+
const node = element.childNodes[i];
|
|
349
|
+
if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
|
|
350
|
+
node.textContent = newText;
|
|
351
|
+
break; // Update only the first text node
|
|
352
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
353
|
+
// Skip inspector elements
|
|
354
|
+
if (!node.id || !node.id.startsWith('inspector-')) {
|
|
355
|
+
updateTextNodes(node);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
updateTextNodes(selectedElement);
|
|
361
|
+
}
|
|
362
|
+
|
|
301
363
|
if (window.parent !== window) {
|
|
302
|
-
|
|
364
|
+
const message = JSON.stringify({
|
|
303
365
|
type: 'INSPECTOR_TEXT_UPDATED',
|
|
304
366
|
data: {
|
|
305
367
|
text: newText,
|
|
306
368
|
originalText: currentText,
|
|
307
369
|
element: selectedElementData
|
|
308
370
|
}
|
|
309
|
-
}
|
|
371
|
+
});
|
|
372
|
+
window.parent.postMessage(message, '*');
|
|
310
373
|
}
|
|
311
374
|
console.log('Text updated:', newText);
|
|
312
375
|
|
|
@@ -345,31 +408,276 @@ export function inspectorPlugin() {
|
|
|
345
408
|
}
|
|
346
409
|
}
|
|
347
410
|
|
|
411
|
+
// Show or hide image input section
|
|
412
|
+
function toggleImageInput(show) {
|
|
413
|
+
if (!controlBox) return;
|
|
414
|
+
|
|
415
|
+
const isImageElement = controlBox.getAttribute('data-is-image-element') === 'true';
|
|
416
|
+
const currentImageUrl = controlBox.getAttribute('data-current-image-url') || '';
|
|
417
|
+
|
|
418
|
+
// Check if image input already exists
|
|
419
|
+
let imageSection = controlBox.querySelector('#inspector-image-section');
|
|
420
|
+
|
|
421
|
+
if (show && !imageSection && isImageElement) {
|
|
422
|
+
// Create image input section
|
|
423
|
+
imageSection = document.createElement('div');
|
|
424
|
+
imageSection.id = 'inspector-image-section';
|
|
425
|
+
imageSection.style.cssText = 'margin-bottom: 12px;';
|
|
426
|
+
|
|
427
|
+
imageSection.innerHTML = \`
|
|
428
|
+
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
|
|
429
|
+
<label style="font-weight: 500; color: \${theme.textColor}; font-size: 13px;">
|
|
430
|
+
\${labels.editImage}
|
|
431
|
+
</label>
|
|
432
|
+
</div>
|
|
433
|
+
<input
|
|
434
|
+
type="file"
|
|
435
|
+
id="inspector-image-input"
|
|
436
|
+
accept="image/*"
|
|
437
|
+
style="display: none;"
|
|
438
|
+
/>
|
|
439
|
+
<div
|
|
440
|
+
id="inspector-image-upload-box"
|
|
441
|
+
style="
|
|
442
|
+
width: 100%;
|
|
443
|
+
min-height: 100px;
|
|
444
|
+
border: 2px dashed \${theme.inputBorderColor};
|
|
445
|
+
border-radius: 12px;
|
|
446
|
+
background: \${theme.inputBackgroundColor};
|
|
447
|
+
cursor: pointer;
|
|
448
|
+
transition: all 0.2s;
|
|
449
|
+
display: flex;
|
|
450
|
+
align-items: center;
|
|
451
|
+
justify-content: center;
|
|
452
|
+
flex-direction: column;
|
|
453
|
+
gap: 8px;
|
|
454
|
+
padding: 16px;
|
|
455
|
+
margin-bottom: 8px;
|
|
456
|
+
position: relative;
|
|
457
|
+
overflow: hidden;
|
|
458
|
+
"
|
|
459
|
+
onmouseover="this.style.borderColor='#9ca3af'; this.style.background='#ffffff';"
|
|
460
|
+
onmouseout="this.style.borderColor='\${theme.inputBorderColor}'; this.style.background='\${theme.inputBackgroundColor}';"
|
|
461
|
+
>
|
|
462
|
+
<div id="inspector-upload-placeholder" style="text-align: center; pointer-events: none;">
|
|
463
|
+
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" style="margin: 0 auto 8px; opacity: 0.5;">
|
|
464
|
+
<path d="M21 15V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V15M17 8L12 3M12 3L7 8M12 3V15" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
465
|
+
</svg>
|
|
466
|
+
<div style="font-size: 13px; color: #6b7280; font-weight: 500;">\${labels.imageUploadTitle}</div>
|
|
467
|
+
<div style="font-size: 11px; color: #9ca3af; margin-top: 2px;">\${labels.imageUploadHint}</div>
|
|
468
|
+
</div>
|
|
469
|
+
<img
|
|
470
|
+
id="inspector-image-preview-img"
|
|
471
|
+
src=""
|
|
472
|
+
alt="Preview"
|
|
473
|
+
style="
|
|
474
|
+
display: none;
|
|
475
|
+
width: 100%;
|
|
476
|
+
height: auto;
|
|
477
|
+
max-height: 100px;
|
|
478
|
+
object-fit: contain;
|
|
479
|
+
border-radius: 8px;
|
|
480
|
+
pointer-events: none;
|
|
481
|
+
"
|
|
482
|
+
/>
|
|
483
|
+
</div>
|
|
484
|
+
<div style="margin-top: 8px;">
|
|
485
|
+
<button
|
|
486
|
+
id="inspector-image-submit"
|
|
487
|
+
style="width: 100%; padding: 10px 16px; background: \${theme.buttonColor}; color: \${theme.buttonTextColor}; border: none; border-radius: 14px; cursor: pointer; font-weight: 500; font-size: 14px; transition: all 0.2s; opacity: 0.5;"
|
|
488
|
+
onmouseover="if(!this.disabled) this.style.opacity='0.85';"
|
|
489
|
+
onmouseout="if(!this.disabled) this.style.opacity='1';"
|
|
490
|
+
title="\${labels.updateImage}"
|
|
491
|
+
disabled
|
|
492
|
+
>
|
|
493
|
+
\${labels.updateImage}
|
|
494
|
+
</button>
|
|
495
|
+
</div>
|
|
496
|
+
<div style="border-top: 1px solid #e5e7eb; margin-top: 12px; margin-bottom: 12px;"></div>
|
|
497
|
+
\`;
|
|
498
|
+
|
|
499
|
+
// Insert at the beginning of controlBox
|
|
500
|
+
const promptSection = controlBox.querySelector('#inspector-prompt-section');
|
|
501
|
+
controlBox.insertBefore(imageSection, promptSection);
|
|
502
|
+
|
|
503
|
+
// Add event listeners
|
|
504
|
+
const imageInput = imageSection.querySelector('#inspector-image-input');
|
|
505
|
+
const imageSubmit = imageSection.querySelector('#inspector-image-submit');
|
|
506
|
+
const uploadBox = imageSection.querySelector('#inspector-image-upload-box');
|
|
507
|
+
const uploadPlaceholder = imageSection.querySelector('#inspector-upload-placeholder');
|
|
508
|
+
const imagePreviewImg = imageSection.querySelector('#inspector-image-preview-img');
|
|
509
|
+
|
|
510
|
+
let selectedFile = null;
|
|
511
|
+
let imageData = null;
|
|
512
|
+
|
|
513
|
+
// Handle file selection
|
|
514
|
+
const handleFile = (file) => {
|
|
515
|
+
if (file && file.type.startsWith('image/')) {
|
|
516
|
+
selectedFile = file;
|
|
517
|
+
|
|
518
|
+
// Read file as base64
|
|
519
|
+
const reader = new FileReader();
|
|
520
|
+
reader.onload = (evt) => {
|
|
521
|
+
imageData = evt.target.result;
|
|
522
|
+
imagePreviewImg.src = imageData;
|
|
523
|
+
imagePreviewImg.style.display = 'block';
|
|
524
|
+
uploadPlaceholder.style.display = 'none';
|
|
525
|
+
imageSubmit.disabled = false;
|
|
526
|
+
imageSubmit.style.opacity = '1';
|
|
527
|
+
imageSubmit.style.cursor = 'pointer';
|
|
528
|
+
};
|
|
529
|
+
reader.readAsDataURL(file);
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
// Click to select file
|
|
534
|
+
uploadBox.addEventListener('click', (e) => {
|
|
535
|
+
e.stopPropagation();
|
|
536
|
+
imageInput.click();
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// File input change
|
|
540
|
+
imageInput.addEventListener('change', (e) => {
|
|
541
|
+
e.stopPropagation();
|
|
542
|
+
const file = e.target.files[0];
|
|
543
|
+
handleFile(file);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// Drag and drop support
|
|
547
|
+
uploadBox.addEventListener('dragover', (e) => {
|
|
548
|
+
e.preventDefault();
|
|
549
|
+
e.stopPropagation();
|
|
550
|
+
uploadBox.style.borderColor = '#4417db';
|
|
551
|
+
uploadBox.style.background = '#f0ebff';
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
uploadBox.addEventListener('dragleave', (e) => {
|
|
555
|
+
e.preventDefault();
|
|
556
|
+
e.stopPropagation();
|
|
557
|
+
uploadBox.style.borderColor = theme.inputBorderColor;
|
|
558
|
+
uploadBox.style.background = theme.inputBackgroundColor;
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
uploadBox.addEventListener('drop', (e) => {
|
|
562
|
+
e.preventDefault();
|
|
563
|
+
e.stopPropagation();
|
|
564
|
+
uploadBox.style.borderColor = theme.inputBorderColor;
|
|
565
|
+
uploadBox.style.background = theme.inputBackgroundColor;
|
|
566
|
+
|
|
567
|
+
const file = e.dataTransfer.files[0];
|
|
568
|
+
handleFile(file);
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// Submit image update
|
|
572
|
+
imageSubmit.addEventListener('click', (e) => {
|
|
573
|
+
e.stopPropagation();
|
|
574
|
+
|
|
575
|
+
if (!selectedFile || !imageData) return;
|
|
576
|
+
|
|
577
|
+
// Update DOM immediately if requested
|
|
578
|
+
if (updateImageImmediately && selectedElement) {
|
|
579
|
+
// If it's an img element, update src directly
|
|
580
|
+
if (selectedElement.tagName.toLowerCase() === 'img') {
|
|
581
|
+
selectedElement.src = imageData;
|
|
582
|
+
}
|
|
583
|
+
// If element has background-image, update it
|
|
584
|
+
else if (window.getComputedStyle(selectedElement).backgroundImage !== 'none') {
|
|
585
|
+
selectedElement.style.backgroundImage = \`url("\${imageData}")\`;
|
|
586
|
+
}
|
|
587
|
+
// Try to find img child
|
|
588
|
+
else {
|
|
589
|
+
const imgChild = selectedElement.querySelector('img');
|
|
590
|
+
if (imgChild) {
|
|
591
|
+
imgChild.src = imageData;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (window.parent !== window) {
|
|
597
|
+
const message = JSON.stringify({
|
|
598
|
+
type: 'INSPECTOR_IMAGE_UPDATED',
|
|
599
|
+
data: {
|
|
600
|
+
imageData: imageData,
|
|
601
|
+
imageFile: {
|
|
602
|
+
name: selectedFile.name,
|
|
603
|
+
size: selectedFile.size,
|
|
604
|
+
type: selectedFile.type
|
|
605
|
+
},
|
|
606
|
+
originalImageUrl: currentImageUrl,
|
|
607
|
+
element: selectedElementData
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
window.parent.postMessage(message, '*');
|
|
611
|
+
}
|
|
612
|
+
console.log('Image updated:', selectedFile.name);
|
|
613
|
+
|
|
614
|
+
// Turn off inspect mode after updating
|
|
615
|
+
toggleInspectMode(false);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// Adjust box height
|
|
619
|
+
adjustControlBoxPosition();
|
|
620
|
+
} else if (!show && imageSection) {
|
|
621
|
+
// Remove image input section
|
|
622
|
+
imageSection.remove();
|
|
623
|
+
|
|
624
|
+
// Refocus prompt input
|
|
625
|
+
const promptInput = controlBox.querySelector('#inspector-prompt-input');
|
|
626
|
+
if (promptInput) {
|
|
627
|
+
setTimeout(() => promptInput.focus(), 100);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Adjust box height
|
|
631
|
+
adjustControlBoxPosition();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
348
635
|
// Adjust control box position based on content
|
|
349
636
|
function adjustControlBoxPosition() {
|
|
350
637
|
if (!controlBox || !selectedElement) return;
|
|
351
638
|
|
|
352
639
|
const rect = selectedElement.getBoundingClientRect();
|
|
353
|
-
const
|
|
354
|
-
const centerLeft = rect.left + (rect.width / 2) - (boxWidth / 2);
|
|
640
|
+
const viewportWidth = window.innerWidth;
|
|
355
641
|
const viewportHeight = window.innerHeight;
|
|
642
|
+
const padding = 10;
|
|
643
|
+
|
|
644
|
+
// Calculate box width with viewport bounds
|
|
645
|
+
const maxWidth = Math.min(600, viewportWidth - (padding * 2));
|
|
646
|
+
const minWidth = Math.min(320, maxWidth);
|
|
647
|
+
const boxWidth = Math.max(minWidth, Math.min(rect.width, maxWidth));
|
|
648
|
+
|
|
649
|
+
// Calculate horizontal position with viewport bounds
|
|
650
|
+
let centerLeft = rect.left + (rect.width / 2) - (boxWidth / 2);
|
|
651
|
+
centerLeft = Math.max(padding, Math.min(centerLeft, viewportWidth - boxWidth - padding));
|
|
652
|
+
|
|
653
|
+
// Calculate vertical position
|
|
356
654
|
const spaceBelow = viewportHeight - rect.bottom;
|
|
357
655
|
const spaceAbove = rect.top;
|
|
358
656
|
|
|
359
|
-
// Get actual box height
|
|
657
|
+
// Get actual box height and apply max height
|
|
360
658
|
const boxHeight = controlBox.offsetHeight;
|
|
659
|
+
const maxBoxHeight = Math.min(400, viewportHeight - (padding * 4));
|
|
361
660
|
|
|
362
|
-
//
|
|
661
|
+
// Determine position with viewport bounds
|
|
363
662
|
let topPosition;
|
|
364
|
-
if (spaceBelow < boxHeight +
|
|
365
|
-
|
|
663
|
+
if (spaceBelow < boxHeight + padding && spaceAbove > spaceBelow) {
|
|
664
|
+
// Show above element
|
|
665
|
+
topPosition = Math.max(padding, rect.top - maxBoxHeight - 10);
|
|
366
666
|
controlBox.setAttribute('data-position', 'above');
|
|
367
667
|
} else {
|
|
668
|
+
// Show below element
|
|
368
669
|
topPosition = rect.bottom + 10;
|
|
670
|
+
// Ensure box fits in viewport
|
|
671
|
+
if (topPosition + maxBoxHeight > viewportHeight - padding) {
|
|
672
|
+
topPosition = Math.max(padding, viewportHeight - maxBoxHeight - padding);
|
|
673
|
+
}
|
|
369
674
|
controlBox.setAttribute('data-position', 'below');
|
|
370
675
|
}
|
|
371
676
|
|
|
372
677
|
controlBox.style.top = topPosition + 'px';
|
|
678
|
+
controlBox.style.left = centerLeft + 'px';
|
|
679
|
+
controlBox.style.width = boxWidth + 'px';
|
|
680
|
+
controlBox.style.maxHeight = maxBoxHeight + 'px';
|
|
373
681
|
}
|
|
374
682
|
|
|
375
683
|
// Pause inspection
|
|
@@ -499,6 +807,40 @@ export function inspectorPlugin() {
|
|
|
499
807
|
highlightElement(hoveredElement);
|
|
500
808
|
}
|
|
501
809
|
|
|
810
|
+
// Handle scroll - update highlight position
|
|
811
|
+
function handleScroll() {
|
|
812
|
+
if (!inspectMode) return;
|
|
813
|
+
|
|
814
|
+
if (isPaused && selectedElement) {
|
|
815
|
+
// Update overlay for selected element
|
|
816
|
+
highlightElement(selectedElement);
|
|
817
|
+
// Update control box position
|
|
818
|
+
if (controlBox) {
|
|
819
|
+
adjustControlBoxPosition();
|
|
820
|
+
}
|
|
821
|
+
} else if (hoveredElement) {
|
|
822
|
+
// Update overlay for hovered element
|
|
823
|
+
highlightElement(hoveredElement);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// Handle resize - update control box position
|
|
828
|
+
function handleResize() {
|
|
829
|
+
if (!inspectMode) return;
|
|
830
|
+
|
|
831
|
+
if (isPaused && selectedElement) {
|
|
832
|
+
// Update overlay for selected element
|
|
833
|
+
highlightElement(selectedElement);
|
|
834
|
+
// Update control box position
|
|
835
|
+
if (controlBox) {
|
|
836
|
+
adjustControlBoxPosition();
|
|
837
|
+
}
|
|
838
|
+
} else if (hoveredElement) {
|
|
839
|
+
// Update overlay for hovered element
|
|
840
|
+
highlightElement(hoveredElement);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
502
844
|
// Handle click
|
|
503
845
|
function handleClick(e) {
|
|
504
846
|
if (!inspectMode) return;
|
|
@@ -528,6 +870,11 @@ export function inspectorPlugin() {
|
|
|
528
870
|
|
|
529
871
|
// Check if element is a text node
|
|
530
872
|
const isTextNode = element.textContent && element.children.length === 0;
|
|
873
|
+
const textContent = isTextNode ? element.textContent.trim() : '';
|
|
874
|
+
|
|
875
|
+
// Check if element is an image node
|
|
876
|
+
const isImageNode = element.tagName === 'IMG';
|
|
877
|
+
const imageUrl = isImageNode ? element.src : '';
|
|
531
878
|
|
|
532
879
|
const elementData = {
|
|
533
880
|
tagName: element.tagName,
|
|
@@ -540,22 +887,28 @@ export function inspectorPlugin() {
|
|
|
540
887
|
width: element.getBoundingClientRect().width,
|
|
541
888
|
height: element.getBoundingClientRect().height
|
|
542
889
|
},
|
|
543
|
-
isTextNode: isTextNode
|
|
890
|
+
isTextNode: isTextNode,
|
|
891
|
+
textContent: textContent,
|
|
892
|
+
isImageNode: isImageNode,
|
|
893
|
+
imageUrl: imageUrl
|
|
544
894
|
};
|
|
545
895
|
|
|
546
896
|
// Send info to parent window
|
|
547
897
|
if (window.parent !== window) {
|
|
548
|
-
|
|
898
|
+
// Use JSON.stringify to ensure all properties are serialized correctly
|
|
899
|
+
const message = JSON.stringify({
|
|
549
900
|
type: 'INSPECTOR_ELEMENT_SELECTED',
|
|
550
901
|
data: elementData
|
|
551
|
-
}
|
|
902
|
+
});
|
|
903
|
+
window.parent.postMessage(message, '*');
|
|
552
904
|
}
|
|
553
905
|
|
|
554
906
|
// Log for debugging
|
|
555
907
|
console.log('Element selected:', {
|
|
556
908
|
element,
|
|
557
909
|
componentInfo,
|
|
558
|
-
isTextNode
|
|
910
|
+
isTextNode,
|
|
911
|
+
textContent
|
|
559
912
|
});
|
|
560
913
|
|
|
561
914
|
// Pause inspection and show control box
|
|
@@ -571,6 +924,8 @@ export function inspectorPlugin() {
|
|
|
571
924
|
document.body.style.cursor = 'crosshair';
|
|
572
925
|
document.addEventListener('mousemove', handleMouseMove, true);
|
|
573
926
|
document.addEventListener('click', handleClick, true);
|
|
927
|
+
document.addEventListener('scroll', handleScroll, true);
|
|
928
|
+
window.addEventListener('resize', handleResize, true);
|
|
574
929
|
} else {
|
|
575
930
|
// Clean up everything
|
|
576
931
|
clearHighlight();
|
|
@@ -578,6 +933,14 @@ export function inspectorPlugin() {
|
|
|
578
933
|
document.body.style.cursor = '';
|
|
579
934
|
document.removeEventListener('mousemove', handleMouseMove, true);
|
|
580
935
|
document.removeEventListener('click', handleClick, true);
|
|
936
|
+
document.removeEventListener('scroll', handleScroll, true);
|
|
937
|
+
window.removeEventListener('resize', handleResize, true);
|
|
938
|
+
|
|
939
|
+
// Notify parent that inspector is closed
|
|
940
|
+
window.parent.postMessage({
|
|
941
|
+
type: 'INSPECTOR_CLOSED',
|
|
942
|
+
source: 'inspector'
|
|
943
|
+
}, '*');
|
|
581
944
|
}
|
|
582
945
|
}
|
|
583
946
|
|
|
@@ -596,10 +959,184 @@ export function inspectorPlugin() {
|
|
|
596
959
|
theme = { ...theme, ...event.data.theme };
|
|
597
960
|
}
|
|
598
961
|
} else if (event.data.type === 'SHOW_CONTENT_INPUT') {
|
|
962
|
+
updateTextImmediately = event.data.updateImmediately || false;
|
|
599
963
|
toggleContentInput(event.data.show);
|
|
964
|
+
} else if (event.data.type === 'SHOW_IMAGE_INPUT') {
|
|
965
|
+
updateImageImmediately = event.data.updateImmediately || false;
|
|
966
|
+
toggleImageInput(event.data.show);
|
|
967
|
+
} else if (event.data.type === 'SET_BADGE_VISIBLE') {
|
|
968
|
+
if (event.data.badgeText) {
|
|
969
|
+
labels.badgeText = event.data.badgeText;
|
|
970
|
+
}
|
|
971
|
+
setBadgeVisible(event.data.visible);
|
|
600
972
|
}
|
|
601
973
|
});
|
|
602
974
|
|
|
975
|
+
// Create Promake badge
|
|
976
|
+
function createPromakeBadge() {
|
|
977
|
+
if (promakeBadge) return;
|
|
978
|
+
|
|
979
|
+
promakeBadge = document.createElement('div');
|
|
980
|
+
promakeBadge.id = 'promake-badge';
|
|
981
|
+
promakeBadge.setAttribute('data-inspector-ignore', 'true');
|
|
982
|
+
promakeBadge.style.cssText = \`
|
|
983
|
+
position: fixed;
|
|
984
|
+
bottom: 20px;
|
|
985
|
+
right: 20px;
|
|
986
|
+
background: linear-gradient(135deg, \${theme.badgeGradientStart} 0%, \${theme.badgeGradientEnd} 100%);
|
|
987
|
+
color: \${theme.badgeTextColor};
|
|
988
|
+
padding: 10px 16px;
|
|
989
|
+
border-radius: 25px;
|
|
990
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
991
|
+
font-size: 13px;
|
|
992
|
+
font-weight: 600;
|
|
993
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
|
994
|
+
cursor: pointer;
|
|
995
|
+
z-index: 999999;
|
|
996
|
+
display: flex;
|
|
997
|
+
align-items: center;
|
|
998
|
+
gap: 8px;
|
|
999
|
+
transition: all 0.3s ease;
|
|
1000
|
+
text-decoration: none;
|
|
1001
|
+
opacity: 0;
|
|
1002
|
+
transform: translateY(10px);
|
|
1003
|
+
\`;
|
|
1004
|
+
|
|
1005
|
+
promakeBadge.innerHTML = \`
|
|
1006
|
+
<svg width="18" height="18" viewBox="0 0 380 380" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1007
|
+
<path d="M251.207 64.1165C237.318 55.3491 219.31 53.3822 203.749 56.7106C188.186 60.0395 175.085 68.6608 170.995 81.0528L170.995 81.0537C167.196 92.5423 168.03 106.257 170.817 120.204C173.603 134.149 178.341 148.32 182.349 160.724L182.439 160.941L182.392 160.96L182.345 160.979C177.201 148.366 169.529 136.94 159.801 127.405C150.073 117.87 138.497 110.428 125.784 105.537L125.784 105.536L125.437 105.425C114.066 102.063 101.905 102.529 90.8242 106.749C79.7511 110.966 70.3677 118.699 64.1131 128.762L64.1203 128.77C55.3499 142.664 53.3822 160.676 56.71 176.238C60.0383 191.802 68.6596 204.902 81.0519 208.992C92.5485 212.789 106.795 212.017 121.273 209.292C135.749 206.567 150.449 201.891 162.852 197.883L162.853 197.884L162.856 197.883L162.89 197.976C150.273 203.12 136.95 210.452 127.415 220.177C117.879 229.903 110.435 241.479 105.542 254.19L105.43 254.54C102.068 265.911 102.533 278.071 106.753 289.153C110.841 299.888 118.234 309.034 127.851 315.282L128.788 315.878C142.683 324.648 160.692 326.615 176.253 323.286C191.816 319.957 204.916 311.336 209.011 298.946C212.811 287.456 210.342 273.716 205.916 259.738C203.703 252.75 201.002 245.705 198.354 238.855C195.705 232.005 193.108 225.35 191.105 219.144L191.191 219.097L191.192 219.098L191.193 219.098C191.193 219.099 191.194 219.101 191.195 219.102C191.198 219.105 191.2 219.11 191.205 219.115C191.214 219.127 191.229 219.143 191.247 219.166C191.284 219.212 191.338 219.28 191.41 219.369C191.553 219.546 191.766 219.808 192.039 220.145C192.585 220.818 193.377 221.79 194.357 222.987C196.317 225.381 199.031 228.671 202.05 232.26C208.088 239.439 215.34 247.808 220.204 252.576C229.929 262.112 241.502 269.559 254.212 274.458L254.211 274.457L254.544 274.574L254.543 274.574C265.915 277.93 278.075 277.463 289.156 273.245C299.891 269.158 309.041 261.77 315.295 252.157L315.891 251.22C324.659 237.331 326.624 219.325 323.295 203.765C319.966 188.203 311.344 175.104 298.955 171.008C287.458 167.212 273.211 167.95 258.732 170.641C244.254 173.332 229.55 177.973 217.141 181.979L217.107 181.885C229.723 176.739 243.054 169.544 252.586 159.819C262.121 150.092 269.563 138.516 274.455 125.804L274.567 125.453L274.568 125.453C277.921 114.082 277.451 101.925 273.232 90.8464C269.013 79.767 261.276 70.3771 251.208 64.117L251.207 64.1165ZM196.312 178.439C199.375 180.118 201.646 182.945 202.625 186.298C203.604 189.65 203.211 193.255 201.532 196.318C199.854 199.381 197.027 201.653 193.674 202.632C190.321 203.61 186.716 203.217 183.653 201.539C180.59 199.86 178.32 197.033 177.34 193.681C176.362 190.328 176.754 186.722 178.433 183.659C180.112 180.596 182.939 178.326 186.292 177.347C189.645 176.368 193.249 176.761 196.312 178.439Z" fill="url(#promake-gradient)" stroke="white" stroke-width="0.1"/>
|
|
1008
|
+
<path d="M248.582 92.4298C249.573 90.6498 251.841 89.9883 253.443 91.2462C254.876 92.3714 256.175 93.6632 257.313 95.0972C259.216 97.4972 260.628 100.249 261.468 103.194C262.308 106.14 262.56 109.222 262.209 112.265C261.999 114.083 261.576 115.866 260.952 117.578C260.255 119.491 257.979 120.126 256.199 119.136V119.136C254.419 118.146 253.826 115.902 254.381 113.943C254.615 113.118 254.783 112.275 254.881 111.419C255.121 109.339 254.949 107.231 254.375 105.217C253.801 103.203 252.835 101.322 251.534 99.6805C250.999 99.0059 250.411 98.3775 249.778 97.8004C248.272 96.4288 247.592 94.2098 248.582 92.4298V92.4298Z" fill="white"/>
|
|
1009
|
+
<path d="M215.025 79.7402C213.937 78.0186 214.443 75.7101 216.314 74.9064C217.988 74.1876 219.744 73.6656 221.548 73.3541C224.566 72.8328 227.658 72.9111 230.646 73.5845C233.634 74.258 236.46 75.5134 238.963 77.2791C240.459 78.3341 241.822 79.559 243.025 80.9264C244.371 82.4552 243.838 84.7576 242.116 85.846V85.846C240.395 86.9343 238.141 86.3802 236.687 84.9538C236.076 84.3537 235.415 83.8025 234.712 83.3062C233 82.0989 231.068 81.2405 229.024 80.78C226.981 80.3195 224.867 80.2659 222.803 80.6224C221.955 80.7689 221.122 80.9835 220.312 81.2632C218.387 81.9281 216.113 81.4619 215.025 79.7402V79.7402Z" fill="white"/>
|
|
1010
|
+
<defs>
|
|
1011
|
+
<radialGradient id="promake-gradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(158.467 247.082) rotate(-57.462) scale(150.285 150.298)">
|
|
1012
|
+
<stop stop-color="#4417DB"/>
|
|
1013
|
+
<stop offset="1" stop-color="#DA738C"/>
|
|
1014
|
+
</radialGradient>
|
|
1015
|
+
</defs>
|
|
1016
|
+
</svg>
|
|
1017
|
+
<span>\${labels.badgeText}</span>
|
|
1018
|
+
<button id="promake-badge-close" style="
|
|
1019
|
+
position: absolute;
|
|
1020
|
+
top: -6px;
|
|
1021
|
+
right: -6px;
|
|
1022
|
+
width: 20px;
|
|
1023
|
+
height: 20px;
|
|
1024
|
+
border-radius: 50%;
|
|
1025
|
+
background: rgba(0, 0, 0, 0.6);
|
|
1026
|
+
color: white;
|
|
1027
|
+
border: 2px solid white;
|
|
1028
|
+
display: flex;
|
|
1029
|
+
align-items: center;
|
|
1030
|
+
justify-content: center;
|
|
1031
|
+
cursor: pointer;
|
|
1032
|
+
font-size: 12px;
|
|
1033
|
+
font-weight: bold;
|
|
1034
|
+
opacity: 0;
|
|
1035
|
+
transition: all 0.2s ease;
|
|
1036
|
+
padding: 0;
|
|
1037
|
+
line-height: 1;
|
|
1038
|
+
">×</button>
|
|
1039
|
+
\`;
|
|
1040
|
+
|
|
1041
|
+
// Get close button
|
|
1042
|
+
const closeButton = promakeBadge.querySelector('#promake-badge-close');
|
|
1043
|
+
|
|
1044
|
+
// Hover effect - show close button on hover
|
|
1045
|
+
promakeBadge.addEventListener('mouseenter', () => {
|
|
1046
|
+
promakeBadge.style.transform = 'translateY(-2px)';
|
|
1047
|
+
promakeBadge.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.6)';
|
|
1048
|
+
if (closeButton) {
|
|
1049
|
+
closeButton.style.opacity = '1';
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
promakeBadge.addEventListener('mouseleave', () => {
|
|
1054
|
+
promakeBadge.style.transform = 'translateY(0)';
|
|
1055
|
+
promakeBadge.style.boxShadow = '0 4px 12px rgba(102, 126, 234, 0.4)';
|
|
1056
|
+
if (closeButton) {
|
|
1057
|
+
closeButton.style.opacity = '0';
|
|
1058
|
+
}
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
// Close button click handler
|
|
1062
|
+
if (closeButton) {
|
|
1063
|
+
closeButton.addEventListener('click', (e) => {
|
|
1064
|
+
e.stopPropagation(); // Prevent badge click event
|
|
1065
|
+
setBadgeVisible(false);
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
// Hover effect for close button
|
|
1069
|
+
closeButton.addEventListener('mouseenter', () => {
|
|
1070
|
+
closeButton.style.background = 'rgba(0, 0, 0, 0.8)';
|
|
1071
|
+
closeButton.style.transform = 'scale(1.1)';
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
closeButton.addEventListener('mouseleave', () => {
|
|
1075
|
+
closeButton.style.background = 'rgba(0, 0, 0, 0.6)';
|
|
1076
|
+
closeButton.style.transform = 'scale(1)';
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// Click to open Promake website (optional)
|
|
1081
|
+
promakeBadge.addEventListener('click', () => {
|
|
1082
|
+
window.open('https://promake.ai', '_blank');
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
document.body.appendChild(promakeBadge);
|
|
1086
|
+
|
|
1087
|
+
// Animate in
|
|
1088
|
+
setTimeout(() => {
|
|
1089
|
+
promakeBadge.style.opacity = '1';
|
|
1090
|
+
promakeBadge.style.transform = 'translateY(0)';
|
|
1091
|
+
}, 100);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// Update badge text
|
|
1095
|
+
function updateBadgeText() {
|
|
1096
|
+
if (promakeBadge) {
|
|
1097
|
+
const textSpan = promakeBadge.querySelector('span');
|
|
1098
|
+
if (textSpan) {
|
|
1099
|
+
textSpan.textContent = labels.badgeText;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// Update badge colors
|
|
1105
|
+
function updateBadgeColors() {
|
|
1106
|
+
if (promakeBadge) {
|
|
1107
|
+
promakeBadge.style.background = \`linear-gradient(135deg, \${theme.badgeGradientStart} 0%, \${theme.badgeGradientEnd} 100%)\`;
|
|
1108
|
+
promakeBadge.style.color = theme.badgeTextColor;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// Set badge visibility
|
|
1113
|
+
function setBadgeVisible(visible) {
|
|
1114
|
+
if (visible) {
|
|
1115
|
+
if (!promakeBadge) {
|
|
1116
|
+
createPromakeBadge();
|
|
1117
|
+
} else {
|
|
1118
|
+
// Update text and colors if badge already exists
|
|
1119
|
+
updateBadgeText();
|
|
1120
|
+
updateBadgeColors();
|
|
1121
|
+
promakeBadge.style.display = 'flex';
|
|
1122
|
+
setTimeout(() => {
|
|
1123
|
+
promakeBadge.style.opacity = '1';
|
|
1124
|
+
promakeBadge.style.transform = 'translateY(0)';
|
|
1125
|
+
}, 50);
|
|
1126
|
+
}
|
|
1127
|
+
} else {
|
|
1128
|
+
if (promakeBadge) {
|
|
1129
|
+
promakeBadge.style.opacity = '0';
|
|
1130
|
+
promakeBadge.style.transform = 'translateY(10px)';
|
|
1131
|
+
setTimeout(() => {
|
|
1132
|
+
if (promakeBadge) {
|
|
1133
|
+
promakeBadge.style.display = 'none';
|
|
1134
|
+
}
|
|
1135
|
+
}, 300);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
|
|
603
1140
|
// Track URL changes
|
|
604
1141
|
let lastUrl = location.href;
|
|
605
1142
|
|
|
@@ -609,7 +1146,7 @@ export function inspectorPlugin() {
|
|
|
609
1146
|
lastUrl = newUrl;
|
|
610
1147
|
|
|
611
1148
|
if (window.parent !== window) {
|
|
612
|
-
|
|
1149
|
+
const message = JSON.stringify({
|
|
613
1150
|
type: 'URL_CHANGED',
|
|
614
1151
|
data: {
|
|
615
1152
|
url: newUrl,
|
|
@@ -617,7 +1154,8 @@ export function inspectorPlugin() {
|
|
|
617
1154
|
search: location.search,
|
|
618
1155
|
hash: location.hash
|
|
619
1156
|
}
|
|
620
|
-
}
|
|
1157
|
+
});
|
|
1158
|
+
window.parent.postMessage(message, '*');
|
|
621
1159
|
}
|
|
622
1160
|
}
|
|
623
1161
|
}
|
|
@@ -650,10 +1188,11 @@ export function inspectorPlugin() {
|
|
|
650
1188
|
|
|
651
1189
|
function sendError(errorData) {
|
|
652
1190
|
if (window.parent !== window) {
|
|
653
|
-
|
|
1191
|
+
const message = JSON.stringify({
|
|
654
1192
|
type: 'INSPECTOR_ERROR',
|
|
655
1193
|
data: errorData
|
|
656
|
-
}
|
|
1194
|
+
});
|
|
1195
|
+
window.parent.postMessage(message, '*');
|
|
657
1196
|
}
|
|
658
1197
|
// Use original console.error to avoid infinite loop
|
|
659
1198
|
originalConsoleError.call(console, '🔍 Inspector Error:', errorData);
|
|
@@ -699,6 +1238,13 @@ export function inspectorPlugin() {
|
|
|
699
1238
|
originalConsoleError.apply(console, args);
|
|
700
1239
|
};
|
|
701
1240
|
|
|
1241
|
+
// Auto-show badge in preview.promake.ai environment (when not in iframe)
|
|
1242
|
+
if (window.parent === window && window.location.href.includes('preview.promake.ai')) {
|
|
1243
|
+
// Not in iframe and in preview environment - show badge automatically
|
|
1244
|
+
setBadgeVisible(true);
|
|
1245
|
+
console.log('🏷️ Badge auto-enabled for preview.promake.ai');
|
|
1246
|
+
}
|
|
1247
|
+
|
|
702
1248
|
console.log('🔍 Inspector plugin loaded');
|
|
703
1249
|
})();
|
|
704
1250
|
`,
|