draply-dev 1.4.1 → 1.4.3
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/bin/cli.js +27 -2
- package/package.json +1 -1
- package/src/overlay.js +24 -14
package/bin/cli.js
CHANGED
|
@@ -80,6 +80,19 @@ const server = http.createServer((req, res) => {
|
|
|
80
80
|
});
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
|
+
// ── Serve assets_draply ───────────────────────────────────────────────────
|
|
84
|
+
if (req.url.startsWith('/assets_draply/')) {
|
|
85
|
+
const filePath = path.join(process.cwd(), req.url.split('?')[0]);
|
|
86
|
+
if (fs.existsSync(filePath)) {
|
|
87
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
88
|
+
const mime = { '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.webp': 'image/webp' };
|
|
89
|
+
res.writeHead(200, { 'Content-Type': mime[ext] || 'application/octet-stream' });
|
|
90
|
+
fs.createReadStream(filePath).pipe(res);
|
|
91
|
+
} else {
|
|
92
|
+
res.writeHead(404); res.end();
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
83
96
|
|
|
84
97
|
// ── Config endpoint (get/set API key) ───────────────────────────────────────
|
|
85
98
|
const configPath = path.join(process.cwd(), 'draply.config.json');
|
|
@@ -198,13 +211,23 @@ const server = http.createServer((req, res) => {
|
|
|
198
211
|
if (ctxEnd === -1 || e > ctxEnd) ctxEnd = e;
|
|
199
212
|
}
|
|
200
213
|
}
|
|
214
|
+
if (ctxStart === -1 && items.some(c => c.type === 'create')) {
|
|
215
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
216
|
+
if (lines[i].includes('</body>')) {
|
|
217
|
+
ctxStart = Math.max(0, i - 20);
|
|
218
|
+
ctxEnd = Math.min(lines.length - 1, i + 20);
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
201
223
|
if (ctxStart === -1) { ctxStart = 0; ctxEnd = Math.min(lines.length - 1, 150); }
|
|
202
224
|
|
|
203
225
|
const snippet = lines.slice(ctxStart, ctxEnd + 1).join('\n');
|
|
204
226
|
|
|
205
227
|
items.forEach(item => {
|
|
206
228
|
const propsStr = Object.entries(item.props).map(([k, v]) => ` ${k}: ${v}`).join('\n');
|
|
207
|
-
changesBlock += `\nTarget Selector: ${item.selector}\nChanges:\n${propsStr}\n`;
|
|
229
|
+
changesBlock += `\nTarget Selector: ${item.selector}\nType: ${item.type}\nChanges:\n${propsStr}\n`;
|
|
230
|
+
if (item.type === 'create') changesBlock += `HTML to Insert: ${item.outerHTML}\n`;
|
|
208
231
|
});
|
|
209
232
|
|
|
210
233
|
const prompt = `You are a strict code editor applying style changes to a file.
|
|
@@ -223,8 +246,10 @@ Rules:
|
|
|
223
246
|
- The content inside <search> must be an EXACT substring from the file snippet above (including indentation).
|
|
224
247
|
- Update HTML/JSX inline styles or Tailwind classes appropriately.
|
|
225
248
|
- REPLACE old style values if they exist, DO NOT duplicate keys!
|
|
226
|
-
- If 'innerText' is provided in Changes, update the text content inside the target HTML element! Use ONLY the exact text provided in the request. DO NOT add signatures, names, attributions, or "complete" the text based on context.
|
|
249
|
+
- If 'innerText' or 'innerHTML' is provided in Changes, update the text content inside the target HTML element! Use ONLY the exact text provided in the request (preserving internal HTML tags like spans for colors/styles if present). DO NOT add signatures, names, attributions, or "complete" the text based on context.
|
|
227
250
|
- If 'src' is provided in Changes, update the src attribute of the target HTML element!
|
|
251
|
+
- If a change is marked for a new element (type: create) and you cannot find the target selector, INSERT the provided 'outerHTML' before the closing </body> tag or in an appropriate container.
|
|
252
|
+
|
|
228
253
|
|
|
229
254
|
Example response:
|
|
230
255
|
<patch>
|
package/package.json
CHANGED
package/src/overlay.js
CHANGED
|
@@ -435,7 +435,7 @@
|
|
|
435
435
|
|
|
436
436
|
/* ── PLACED ASSETS ────────────────────────────────── */
|
|
437
437
|
.ps-asset-placed {
|
|
438
|
-
position:
|
|
438
|
+
position: absolute;
|
|
439
439
|
z-index: 999990;
|
|
440
440
|
cursor: grab;
|
|
441
441
|
user-select: none;
|
|
@@ -1165,14 +1165,14 @@
|
|
|
1165
1165
|
// Make text directly editable
|
|
1166
1166
|
if (!el.isContentEditable) {
|
|
1167
1167
|
el.contentEditable = 'true';
|
|
1168
|
-
el.dataset.origText = el.
|
|
1168
|
+
el.dataset.origText = el.innerHTML || '';
|
|
1169
1169
|
el.focus();
|
|
1170
1170
|
|
|
1171
1171
|
const finishEdit = () => {
|
|
1172
1172
|
el.contentEditable = 'false';
|
|
1173
1173
|
el.removeEventListener('blur', finishEdit);
|
|
1174
|
-
if (el.
|
|
1175
|
-
rec(el, {
|
|
1174
|
+
if (el.innerHTML !== el.dataset.origText) {
|
|
1175
|
+
rec(el, { innerHTML: el.innerHTML }, { innerHTML: el.dataset.origText });
|
|
1176
1176
|
toast('Text updated!');
|
|
1177
1177
|
}
|
|
1178
1178
|
};
|
|
@@ -1410,7 +1410,7 @@
|
|
|
1410
1410
|
width: w + 'px',
|
|
1411
1411
|
height: h + 'px',
|
|
1412
1412
|
'z-index': '1',
|
|
1413
|
-
});
|
|
1413
|
+
}, null, true); // true = isCreate
|
|
1414
1414
|
|
|
1415
1415
|
toast('✦ Placed — drag to reposition');
|
|
1416
1416
|
selectPlaced(wrap);
|
|
@@ -1494,7 +1494,7 @@
|
|
|
1494
1494
|
// Full history — every individual action
|
|
1495
1495
|
const history = [];
|
|
1496
1496
|
|
|
1497
|
-
function rec(el, props, prevPropsOverride) {
|
|
1497
|
+
function rec(el, props, prevPropsOverride, isCreate = false) {
|
|
1498
1498
|
const selector = el.dataset.pixelshiftId ? null : gsel(el);
|
|
1499
1499
|
const key = el.dataset.pixelshiftId || selector;
|
|
1500
1500
|
|
|
@@ -1524,19 +1524,22 @@
|
|
|
1524
1524
|
|
|
1525
1525
|
// Merge into state.changes (for save/apply)
|
|
1526
1526
|
const ch = {
|
|
1527
|
-
type: el.dataset.pixelshiftId ? 'inline' : 'css',
|
|
1527
|
+
type: isCreate ? 'create' : (el.dataset.pixelshiftId ? 'inline' : 'css'),
|
|
1528
|
+
isCreate,
|
|
1528
1529
|
pixelshiftId: el.dataset.pixelshiftId || null,
|
|
1529
1530
|
selector,
|
|
1530
1531
|
exactFile: getReactSource(el),
|
|
1531
1532
|
file: el.dataset.pixelshiftFile || null,
|
|
1532
|
-
props
|
|
1533
|
+
props,
|
|
1534
|
+
tagName: el.tagName.toLowerCase(),
|
|
1535
|
+
outerHTML: el.outerHTML // Send the whole element for 'create' actions
|
|
1533
1536
|
};
|
|
1534
1537
|
const i = state.changes.findIndex(c => (c.pixelshiftId || c.selector) === key);
|
|
1535
1538
|
if (i >= 0) Object.assign(state.changes[i].props, props); else state.changes.push(ch);
|
|
1536
1539
|
|
|
1537
1540
|
// Push to history
|
|
1538
1541
|
const hid = Date.now() + Math.random();
|
|
1539
|
-
history.push({ hid, el, props, prevProps, selector: key });
|
|
1542
|
+
history.push({ hid, el, props, prevProps, selector: key, isCreate });
|
|
1540
1543
|
|
|
1541
1544
|
updateUnsUI();
|
|
1542
1545
|
}
|
|
@@ -1565,11 +1568,18 @@
|
|
|
1565
1568
|
}
|
|
1566
1569
|
|
|
1567
1570
|
function revertChange(h) {
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1571
|
+
if (h.isCreate) {
|
|
1572
|
+
h.el.remove();
|
|
1573
|
+
} else {
|
|
1574
|
+
// Re-apply previous inline values
|
|
1575
|
+
Object.entries(h.prevProps).forEach(([prop, val]) => {
|
|
1576
|
+
const camel = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
1577
|
+
h.el.style[camel] = val;
|
|
1578
|
+
});
|
|
1579
|
+
// Also handle text/html
|
|
1580
|
+
if (h.prevProps.innerHTML !== undefined) h.el.innerHTML = h.prevProps.innerHTML;
|
|
1581
|
+
if (h.prevProps.innerText !== undefined) h.el.innerText = h.prevProps.innerText;
|
|
1582
|
+
}
|
|
1573
1583
|
// Remove from history
|
|
1574
1584
|
const idx = history.findIndex(x => x.hid === h.hid);
|
|
1575
1585
|
if (idx >= 0) history.splice(idx, 1);
|