@promakeai/inspector 0.0.4 → 0.1.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 +280 -62
- package/dist/hook.d.ts +38 -5
- package/dist/hook.d.ts.map +1 -1
- package/dist/hook.js +75 -13
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +597 -18
- package/dist/types.d.ts +25 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
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)
|
|
@@ -299,6 +339,27 @@ export function inspectorPlugin() {
|
|
|
299
339
|
textSubmit.addEventListener('click', (e) => {
|
|
300
340
|
e.stopPropagation();
|
|
301
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
|
+
|
|
302
363
|
if (window.parent !== window) {
|
|
303
364
|
const message = JSON.stringify({
|
|
304
365
|
type: 'INSPECTOR_TEXT_UPDATED',
|
|
@@ -347,31 +408,276 @@ export function inspectorPlugin() {
|
|
|
347
408
|
}
|
|
348
409
|
}
|
|
349
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
|
+
|
|
350
635
|
// Adjust control box position based on content
|
|
351
636
|
function adjustControlBoxPosition() {
|
|
352
637
|
if (!controlBox || !selectedElement) return;
|
|
353
638
|
|
|
354
639
|
const rect = selectedElement.getBoundingClientRect();
|
|
355
|
-
const
|
|
356
|
-
const centerLeft = rect.left + (rect.width / 2) - (boxWidth / 2);
|
|
640
|
+
const viewportWidth = window.innerWidth;
|
|
357
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
|
|
358
654
|
const spaceBelow = viewportHeight - rect.bottom;
|
|
359
655
|
const spaceAbove = rect.top;
|
|
360
656
|
|
|
361
|
-
// Get actual box height
|
|
657
|
+
// Get actual box height and apply max height
|
|
362
658
|
const boxHeight = controlBox.offsetHeight;
|
|
659
|
+
const maxBoxHeight = Math.min(400, viewportHeight - (padding * 4));
|
|
363
660
|
|
|
364
|
-
//
|
|
661
|
+
// Determine position with viewport bounds
|
|
365
662
|
let topPosition;
|
|
366
|
-
if (spaceBelow < boxHeight +
|
|
367
|
-
|
|
663
|
+
if (spaceBelow < boxHeight + padding && spaceAbove > spaceBelow) {
|
|
664
|
+
// Show above element
|
|
665
|
+
topPosition = Math.max(padding, rect.top - maxBoxHeight - 10);
|
|
368
666
|
controlBox.setAttribute('data-position', 'above');
|
|
369
667
|
} else {
|
|
668
|
+
// Show below element
|
|
370
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
|
+
}
|
|
371
674
|
controlBox.setAttribute('data-position', 'below');
|
|
372
675
|
}
|
|
373
676
|
|
|
374
677
|
controlBox.style.top = topPosition + 'px';
|
|
678
|
+
controlBox.style.left = centerLeft + 'px';
|
|
679
|
+
controlBox.style.width = boxWidth + 'px';
|
|
680
|
+
controlBox.style.maxHeight = maxBoxHeight + 'px';
|
|
375
681
|
}
|
|
376
682
|
|
|
377
683
|
// Pause inspection
|
|
@@ -518,6 +824,23 @@ export function inspectorPlugin() {
|
|
|
518
824
|
}
|
|
519
825
|
}
|
|
520
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
|
+
|
|
521
844
|
// Handle click
|
|
522
845
|
function handleClick(e) {
|
|
523
846
|
if (!inspectMode) return;
|
|
@@ -549,6 +872,10 @@ export function inspectorPlugin() {
|
|
|
549
872
|
const isTextNode = element.textContent && element.children.length === 0;
|
|
550
873
|
const textContent = isTextNode ? element.textContent.trim() : '';
|
|
551
874
|
|
|
875
|
+
// Check if element is an image node
|
|
876
|
+
const isImageNode = element.tagName === 'IMG';
|
|
877
|
+
const imageUrl = isImageNode ? element.src : '';
|
|
878
|
+
|
|
552
879
|
const elementData = {
|
|
553
880
|
tagName: element.tagName,
|
|
554
881
|
className: element.className,
|
|
@@ -561,7 +888,9 @@ export function inspectorPlugin() {
|
|
|
561
888
|
height: element.getBoundingClientRect().height
|
|
562
889
|
},
|
|
563
890
|
isTextNode: isTextNode,
|
|
564
|
-
textContent: textContent
|
|
891
|
+
textContent: textContent,
|
|
892
|
+
isImageNode: isImageNode,
|
|
893
|
+
imageUrl: imageUrl
|
|
565
894
|
};
|
|
566
895
|
|
|
567
896
|
// Send info to parent window
|
|
@@ -596,6 +925,7 @@ export function inspectorPlugin() {
|
|
|
596
925
|
document.addEventListener('mousemove', handleMouseMove, true);
|
|
597
926
|
document.addEventListener('click', handleClick, true);
|
|
598
927
|
document.addEventListener('scroll', handleScroll, true);
|
|
928
|
+
window.addEventListener('resize', handleResize, true);
|
|
599
929
|
} else {
|
|
600
930
|
// Clean up everything
|
|
601
931
|
clearHighlight();
|
|
@@ -604,6 +934,13 @@ export function inspectorPlugin() {
|
|
|
604
934
|
document.removeEventListener('mousemove', handleMouseMove, true);
|
|
605
935
|
document.removeEventListener('click', handleClick, true);
|
|
606
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
|
+
}, '*');
|
|
607
944
|
}
|
|
608
945
|
}
|
|
609
946
|
|
|
@@ -622,10 +959,184 @@ export function inspectorPlugin() {
|
|
|
622
959
|
theme = { ...theme, ...event.data.theme };
|
|
623
960
|
}
|
|
624
961
|
} else if (event.data.type === 'SHOW_CONTENT_INPUT') {
|
|
962
|
+
updateTextImmediately = event.data.updateImmediately || false;
|
|
625
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);
|
|
626
972
|
}
|
|
627
973
|
});
|
|
628
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
|
+
|
|
629
1140
|
// Track URL changes
|
|
630
1141
|
let lastUrl = location.href;
|
|
631
1142
|
|
|
@@ -727,6 +1238,74 @@ export function inspectorPlugin() {
|
|
|
727
1238
|
originalConsoleError.apply(console, args);
|
|
728
1239
|
};
|
|
729
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
|
+
|
|
1248
|
+
// 🖼️ Auto cache-bust all images on page load
|
|
1249
|
+
// This ensures images are always fresh when page is refreshed/reloaded
|
|
1250
|
+
function cacheBustAllImages() {
|
|
1251
|
+
const timestamp = Date.now();
|
|
1252
|
+
let imageCount = 0;
|
|
1253
|
+
|
|
1254
|
+
// Cache-bust all <img> tags
|
|
1255
|
+
const images = document.querySelectorAll('img');
|
|
1256
|
+
images.forEach((img) => {
|
|
1257
|
+
if (img.src && !img.src.startsWith('data:')) {
|
|
1258
|
+
try {
|
|
1259
|
+
const url = new URL(img.src);
|
|
1260
|
+
// Remove old cache busting params
|
|
1261
|
+
url.searchParams.delete('_t');
|
|
1262
|
+
url.searchParams.delete('_cache_bust');
|
|
1263
|
+
url.searchParams.delete('v');
|
|
1264
|
+
// Add new timestamp
|
|
1265
|
+
url.searchParams.set('_t', timestamp.toString());
|
|
1266
|
+
img.src = url.toString();
|
|
1267
|
+
imageCount++;
|
|
1268
|
+
} catch (e) {
|
|
1269
|
+
// Ignore invalid URLs
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
// Cache-bust background images
|
|
1275
|
+
const allElements = document.querySelectorAll('*');
|
|
1276
|
+
allElements.forEach((el) => {
|
|
1277
|
+
const bgImage = window.getComputedStyle(el).backgroundImage;
|
|
1278
|
+
if (bgImage && bgImage !== 'none' && bgImage.includes('url(')) {
|
|
1279
|
+
const urlMatch = bgImage.match(/url\(['"]?([^'"]+)['"]?\)/);
|
|
1280
|
+
if (urlMatch && urlMatch[1] && !urlMatch[1].startsWith('data:')) {
|
|
1281
|
+
try {
|
|
1282
|
+
const url = new URL(urlMatch[1], window.location.origin);
|
|
1283
|
+
url.searchParams.delete('_t');
|
|
1284
|
+
url.searchParams.delete('_cache_bust');
|
|
1285
|
+
url.searchParams.delete('v');
|
|
1286
|
+
url.searchParams.set('_t', timestamp.toString());
|
|
1287
|
+
(el as HTMLElement).style.backgroundImage = 'url("' + url.toString() + '")';
|
|
1288
|
+
imageCount++;
|
|
1289
|
+
} catch (e) {
|
|
1290
|
+
// Ignore invalid URLs
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
});
|
|
1295
|
+
|
|
1296
|
+
if (imageCount > 0) {
|
|
1297
|
+
console.log('🖼️ [INSPECTOR] Cache-busted ' + imageCount + ' images on page load');
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// Run cache-bust after DOM is fully loaded
|
|
1302
|
+
if (document.readyState === 'loading') {
|
|
1303
|
+
document.addEventListener('DOMContentLoaded', cacheBustAllImages);
|
|
1304
|
+
} else {
|
|
1305
|
+
// DOM already loaded, run immediately
|
|
1306
|
+
cacheBustAllImages();
|
|
1307
|
+
}
|
|
1308
|
+
|
|
730
1309
|
console.log('🔍 Inspector plugin loaded');
|
|
731
1310
|
})();
|
|
732
1311
|
`,
|