afterbefore 0.2.11 → 0.2.13
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/{chunk-BFC2HVPX.js → chunk-N33DB2F6.js} +20 -43
- package/dist/chunk-N33DB2F6.js.map +1 -0
- package/dist/overlay/index.js +716 -1310
- package/dist/overlay/index.js.map +1 -1
- package/dist/server/middleware.js +1 -1
- package/dist/server/route.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-BFC2HVPX.js.map +0 -1
package/dist/overlay/index.js
CHANGED
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/overlay/index.tsx
|
|
4
|
-
import { useState as
|
|
4
|
+
import { useState as useState6, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect5 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/overlay/state.ts
|
|
7
7
|
import { useState, useCallback } from "react";
|
|
8
8
|
var initialState = {
|
|
9
9
|
phase: "idle",
|
|
10
|
-
|
|
11
|
-
after: null
|
|
10
|
+
lastCapture: null
|
|
12
11
|
};
|
|
13
12
|
function useOverlayState() {
|
|
14
13
|
const [state, setState] = useState(initialState);
|
|
15
14
|
const captureComplete = useCallback(
|
|
16
15
|
(result) => {
|
|
17
|
-
setState(
|
|
18
|
-
if (prev.phase === "idle") {
|
|
19
|
-
return { ...prev, phase: "captured-before", before: result };
|
|
20
|
-
}
|
|
21
|
-
if (prev.phase === "captured-before") {
|
|
22
|
-
return { ...prev, phase: "ready", after: result };
|
|
23
|
-
}
|
|
24
|
-
return prev;
|
|
25
|
-
});
|
|
16
|
+
setState({ phase: "ready", lastCapture: result });
|
|
26
17
|
},
|
|
27
18
|
[]
|
|
28
19
|
);
|
|
@@ -34,6 +25,20 @@ function useOverlayState() {
|
|
|
34
25
|
|
|
35
26
|
// src/overlay/capture.ts
|
|
36
27
|
import { snapdom } from "@zumer/snapdom";
|
|
28
|
+
var DEFAULT_FRAME_SETTINGS = {
|
|
29
|
+
enabled: false,
|
|
30
|
+
size: { w: 1920, h: 1080 },
|
|
31
|
+
bgType: "color",
|
|
32
|
+
bgColor: "#000000",
|
|
33
|
+
bgImage: null,
|
|
34
|
+
padding: 40
|
|
35
|
+
};
|
|
36
|
+
var FRAME_SIZE_PRESETS = [
|
|
37
|
+
{ label: "1920 x 1080", w: 1920, h: 1080 },
|
|
38
|
+
{ label: "1080 x 1080", w: 1080, h: 1080 },
|
|
39
|
+
{ label: "1200 x 630", w: 1200, h: 630 },
|
|
40
|
+
{ label: "1080 x 1920", w: 1080, h: 1920 }
|
|
41
|
+
];
|
|
37
42
|
var DEV_UI_SELECTORS = [
|
|
38
43
|
// Afterbefore overlay
|
|
39
44
|
"[data-afterbefore]",
|
|
@@ -55,18 +60,15 @@ async function toPngDataUrl(el, opts) {
|
|
|
55
60
|
return img.src;
|
|
56
61
|
}
|
|
57
62
|
async function capture(options) {
|
|
58
|
-
const { mode,
|
|
63
|
+
const { mode, element } = options;
|
|
59
64
|
if (mode === "viewport") {
|
|
60
65
|
return captureViewport();
|
|
61
66
|
}
|
|
62
67
|
if (mode === "fullpage") {
|
|
63
68
|
return captureFullPage();
|
|
64
69
|
}
|
|
65
|
-
if (mode === "area" && area) {
|
|
66
|
-
return captureArea(area);
|
|
67
|
-
}
|
|
68
70
|
if (mode === "component" && element) {
|
|
69
|
-
return captureComponent(element, options.
|
|
71
|
+
return captureComponent(element, options.frameSettings);
|
|
70
72
|
}
|
|
71
73
|
throw new Error(`Invalid capture mode: ${mode}`);
|
|
72
74
|
}
|
|
@@ -120,39 +122,18 @@ async function captureFullPage() {
|
|
|
120
122
|
window.scrollTo(0, scrollY);
|
|
121
123
|
}
|
|
122
124
|
}
|
|
123
|
-
async function
|
|
124
|
-
const fullDataUrl = await captureViewport();
|
|
125
|
-
const img = await loadImage(fullDataUrl);
|
|
126
|
-
const dpr = window.devicePixelRatio || 1;
|
|
127
|
-
const canvas = document.createElement("canvas");
|
|
128
|
-
canvas.width = area.width * dpr;
|
|
129
|
-
canvas.height = area.height * dpr;
|
|
130
|
-
const ctx = canvas.getContext("2d");
|
|
131
|
-
ctx.drawImage(
|
|
132
|
-
img,
|
|
133
|
-
area.x * dpr,
|
|
134
|
-
area.y * dpr,
|
|
135
|
-
area.width * dpr,
|
|
136
|
-
area.height * dpr,
|
|
137
|
-
0,
|
|
138
|
-
0,
|
|
139
|
-
area.width * dpr,
|
|
140
|
-
area.height * dpr
|
|
141
|
-
);
|
|
142
|
-
return canvas.toDataURL("image/png");
|
|
143
|
-
}
|
|
144
|
-
async function captureComponent(element, frameOnBlack) {
|
|
125
|
+
async function captureComponent(element, frameSettings) {
|
|
145
126
|
const dataUrl = await toPngDataUrl(element);
|
|
146
|
-
if (!
|
|
127
|
+
if (!frameSettings?.enabled) {
|
|
147
128
|
return dataUrl;
|
|
148
129
|
}
|
|
149
130
|
const img = await loadImage(dataUrl);
|
|
150
131
|
const dpr = window.devicePixelRatio || 1;
|
|
151
|
-
const FRAME_W =
|
|
152
|
-
const FRAME_H =
|
|
132
|
+
const FRAME_W = frameSettings.size.w;
|
|
133
|
+
const FRAME_H = frameSettings.size.h;
|
|
134
|
+
const padding = frameSettings.padding;
|
|
153
135
|
const compW = img.width / dpr;
|
|
154
136
|
const compH = img.height / dpr;
|
|
155
|
-
const padding = 40;
|
|
156
137
|
const maxW = FRAME_W - padding * 2;
|
|
157
138
|
const maxH = FRAME_H - padding * 2;
|
|
158
139
|
const scale = Math.min(1, maxW / compW, maxH / compH);
|
|
@@ -162,13 +143,31 @@ async function captureComponent(element, frameOnBlack) {
|
|
|
162
143
|
canvas.width = FRAME_W * dpr;
|
|
163
144
|
canvas.height = FRAME_H * dpr;
|
|
164
145
|
const ctx = canvas.getContext("2d");
|
|
165
|
-
|
|
166
|
-
|
|
146
|
+
if (frameSettings.bgType === "image" && frameSettings.bgImage) {
|
|
147
|
+
try {
|
|
148
|
+
const bgImg = await loadImage(frameSettings.bgImage);
|
|
149
|
+
drawCover(ctx, bgImg, canvas.width, canvas.height);
|
|
150
|
+
} catch {
|
|
151
|
+
ctx.fillStyle = frameSettings.bgColor;
|
|
152
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
ctx.fillStyle = frameSettings.bgColor;
|
|
156
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
157
|
+
}
|
|
167
158
|
const dx = (canvas.width - drawW) / 2;
|
|
168
159
|
const dy = (canvas.height - drawH) / 2;
|
|
169
160
|
ctx.drawImage(img, dx, dy, drawW, drawH);
|
|
170
161
|
return canvas.toDataURL("image/png");
|
|
171
162
|
}
|
|
163
|
+
function drawCover(ctx, img, cw, ch) {
|
|
164
|
+
const scale = Math.max(cw / img.width, ch / img.height);
|
|
165
|
+
const sw = cw / scale;
|
|
166
|
+
const sh = ch / scale;
|
|
167
|
+
const sx = (img.width - sw) / 2;
|
|
168
|
+
const sy = (img.height - sh) / 2;
|
|
169
|
+
ctx.drawImage(img, sx, sy, sw, sh, 0, 0, cw, ch);
|
|
170
|
+
}
|
|
172
171
|
function loadImage(src) {
|
|
173
172
|
return new Promise((resolve, reject) => {
|
|
174
173
|
const img = new Image();
|
|
@@ -182,23 +181,25 @@ function loadImage(src) {
|
|
|
182
181
|
import { useRef, useCallback as useCallback2, useEffect, useState as useState2 } from "react";
|
|
183
182
|
import { Camera, Check, LoaderCircle } from "lucide-react";
|
|
184
183
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
185
|
-
var ICON_SIZE =
|
|
184
|
+
var ICON_SIZE = 32;
|
|
186
185
|
var EDGE_MARGIN = 24;
|
|
187
186
|
function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
188
187
|
const ref = useRef(null);
|
|
189
|
-
const [pos, setPos] = useState2({ x:
|
|
188
|
+
const [pos, setPos] = useState2({ x: -1, y: -1 });
|
|
190
189
|
const dragState = useRef(null);
|
|
191
190
|
useEffect(() => {
|
|
192
191
|
setPos((prev) => {
|
|
193
|
-
if (prev.y === -1) {
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
if (prev.x === -1 || prev.y === -1) {
|
|
193
|
+
return {
|
|
194
|
+
x: window.innerWidth - ICON_SIZE - EDGE_MARGIN,
|
|
195
|
+
y: window.innerHeight - ICON_SIZE - EDGE_MARGIN
|
|
196
|
+
};
|
|
196
197
|
}
|
|
197
198
|
return prev;
|
|
198
199
|
});
|
|
199
200
|
}, []);
|
|
200
201
|
useEffect(() => {
|
|
201
|
-
if (pos.y !== -1) {
|
|
202
|
+
if (pos.x !== -1 && pos.y !== -1) {
|
|
202
203
|
onPositionChange?.({ x: pos.x, y: pos.y });
|
|
203
204
|
}
|
|
204
205
|
}, [pos, onPositionChange]);
|
|
@@ -248,7 +249,7 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
248
249
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
249
250
|
};
|
|
250
251
|
}, [onClick]);
|
|
251
|
-
if (pos.y === -1) return null;
|
|
252
|
+
if (pos.x === -1 || pos.y === -1) return null;
|
|
252
253
|
return /* @__PURE__ */ jsxs(
|
|
253
254
|
"div",
|
|
254
255
|
{
|
|
@@ -262,21 +263,24 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
262
263
|
width: ICON_SIZE,
|
|
263
264
|
height: ICON_SIZE,
|
|
264
265
|
borderRadius: "50%",
|
|
265
|
-
background: "rgba(
|
|
266
|
+
background: "rgba(32, 32, 36, 0.92)",
|
|
267
|
+
backdropFilter: "blur(20px)",
|
|
268
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
269
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
266
270
|
display: "flex",
|
|
267
271
|
alignItems: "center",
|
|
268
272
|
justifyContent: "center",
|
|
269
273
|
cursor: "grab",
|
|
270
274
|
zIndex: 2147483647,
|
|
271
|
-
boxShadow: "0
|
|
275
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
272
276
|
transition: "background 0.15s",
|
|
273
277
|
userSelect: "none"
|
|
274
278
|
},
|
|
275
279
|
onMouseEnter: (e) => {
|
|
276
|
-
e.currentTarget.style.background = "rgba(
|
|
280
|
+
e.currentTarget.style.background = "rgba(32, 32, 36, 0.98)";
|
|
277
281
|
},
|
|
278
282
|
onMouseLeave: (e) => {
|
|
279
|
-
e.currentTarget.style.background = "rgba(
|
|
283
|
+
e.currentTarget.style.background = "rgba(32, 32, 36, 0.92)";
|
|
280
284
|
},
|
|
281
285
|
children: [
|
|
282
286
|
/* @__PURE__ */ jsx(
|
|
@@ -284,10 +288,6 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
284
288
|
{
|
|
285
289
|
dangerouslySetInnerHTML: {
|
|
286
290
|
__html: `
|
|
287
|
-
@keyframes ab-pulse {
|
|
288
|
-
0%, 100% { transform: scale(1); opacity: 1; }
|
|
289
|
-
50% { transform: scale(1.08); opacity: 0.85; }
|
|
290
|
-
}
|
|
291
291
|
@keyframes ab-spin {
|
|
292
292
|
0% { transform: rotate(0deg); }
|
|
293
293
|
100% { transform: rotate(360deg); }
|
|
@@ -298,113 +298,20 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
298
298
|
loading ? /* @__PURE__ */ jsx(
|
|
299
299
|
LoaderCircle,
|
|
300
300
|
{
|
|
301
|
-
size:
|
|
301
|
+
size: 16,
|
|
302
302
|
strokeWidth: 2,
|
|
303
303
|
style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
|
|
304
304
|
}
|
|
305
|
-
) : phase === "ready" ? /* @__PURE__ */ jsx(Check, { size:
|
|
306
|
-
"div",
|
|
307
|
-
{
|
|
308
|
-
style: {
|
|
309
|
-
position: "relative",
|
|
310
|
-
display: "flex",
|
|
311
|
-
alignItems: "center",
|
|
312
|
-
justifyContent: "center",
|
|
313
|
-
animation: phase === "captured-before" ? "ab-pulse 2s ease-in-out infinite" : "none"
|
|
314
|
-
},
|
|
315
|
-
children: [
|
|
316
|
-
/* @__PURE__ */ jsx(Camera, { size: 20, strokeWidth: 1.9, color: "white" }),
|
|
317
|
-
phase === "captured-before" && /* @__PURE__ */ jsx(
|
|
318
|
-
"div",
|
|
319
|
-
{
|
|
320
|
-
style: {
|
|
321
|
-
position: "absolute",
|
|
322
|
-
top: -6,
|
|
323
|
-
right: -8,
|
|
324
|
-
width: 14,
|
|
325
|
-
height: 14,
|
|
326
|
-
borderRadius: "50%",
|
|
327
|
-
background: "#3b82f6",
|
|
328
|
-
color: "white",
|
|
329
|
-
fontSize: "9px",
|
|
330
|
-
fontWeight: 700,
|
|
331
|
-
display: "flex",
|
|
332
|
-
alignItems: "center",
|
|
333
|
-
justifyContent: "center",
|
|
334
|
-
lineHeight: 1,
|
|
335
|
-
fontFamily: "system-ui, sans-serif"
|
|
336
|
-
},
|
|
337
|
-
children: "1"
|
|
338
|
-
}
|
|
339
|
-
)
|
|
340
|
-
]
|
|
341
|
-
}
|
|
342
|
-
)
|
|
305
|
+
) : phase === "ready" ? /* @__PURE__ */ jsx(Check, { size: 16, strokeWidth: 2.6, color: "#4ade80" }) : /* @__PURE__ */ jsx(Camera, { size: 16, strokeWidth: 1.9, color: "white" })
|
|
343
306
|
]
|
|
344
307
|
}
|
|
345
308
|
);
|
|
346
309
|
}
|
|
347
310
|
|
|
348
311
|
// src/overlay/ui/preview.tsx
|
|
349
|
-
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
350
312
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
351
|
-
var DEFAULT_ASPECT_RATIO = 16 / 9;
|
|
352
|
-
function getAreaPreviewRect() {
|
|
353
|
-
const safeWidth = Math.max(320, window.innerWidth - 120);
|
|
354
|
-
const safeHeight = Math.max(180, window.innerHeight - 220);
|
|
355
|
-
const width = Math.min(window.innerWidth * 0.72, safeHeight * DEFAULT_ASPECT_RATIO, safeWidth);
|
|
356
|
-
const height = width / DEFAULT_ASPECT_RATIO;
|
|
357
|
-
return {
|
|
358
|
-
x: (window.innerWidth - width) / 2,
|
|
359
|
-
y: Math.max(40, (window.innerHeight - height) / 2 - 20),
|
|
360
|
-
width,
|
|
361
|
-
height
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
313
|
var CAMERA_CURSOR = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z'/%3E%3Ccircle cx='12' cy='13' r='3'/%3E%3C/svg%3E") 16 16, pointer`;
|
|
365
314
|
function CapturePreview({ mode, onClick }) {
|
|
366
|
-
const [areaRect, setAreaRect] = useState3(null);
|
|
367
|
-
useEffect2(() => {
|
|
368
|
-
if (mode !== "area") {
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
const syncRect = () => {
|
|
372
|
-
setAreaRect(getAreaPreviewRect());
|
|
373
|
-
};
|
|
374
|
-
syncRect();
|
|
375
|
-
window.addEventListener("resize", syncRect);
|
|
376
|
-
return () => window.removeEventListener("resize", syncRect);
|
|
377
|
-
}, [mode]);
|
|
378
|
-
if (mode === "area" && areaRect) {
|
|
379
|
-
return /* @__PURE__ */ jsx2(
|
|
380
|
-
"div",
|
|
381
|
-
{
|
|
382
|
-
"data-afterbefore": "true",
|
|
383
|
-
style: {
|
|
384
|
-
position: "fixed",
|
|
385
|
-
inset: 0,
|
|
386
|
-
zIndex: 2147483645,
|
|
387
|
-
pointerEvents: "none"
|
|
388
|
-
},
|
|
389
|
-
children: /* @__PURE__ */ jsx2(
|
|
390
|
-
"div",
|
|
391
|
-
{
|
|
392
|
-
style: {
|
|
393
|
-
position: "absolute",
|
|
394
|
-
left: areaRect.x,
|
|
395
|
-
top: areaRect.y,
|
|
396
|
-
width: areaRect.width,
|
|
397
|
-
height: areaRect.height,
|
|
398
|
-
background: "rgba(125, 211, 252, 0.16)",
|
|
399
|
-
border: "1.5px solid rgba(125, 211, 252, 0.95)",
|
|
400
|
-
boxShadow: "0 0 0 1px rgba(191, 219, 254, 0.4), 0 0 32px rgba(56, 189, 248, 0.18)",
|
|
401
|
-
borderRadius: 14
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
)
|
|
405
|
-
}
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
315
|
if (mode === "viewport" || mode === "fullpage") {
|
|
409
316
|
return /* @__PURE__ */ jsx2(
|
|
410
317
|
"div",
|
|
@@ -416,518 +323,47 @@ function CapturePreview({ mode, onClick }) {
|
|
|
416
323
|
inset: 0,
|
|
417
324
|
zIndex: 2147483645,
|
|
418
325
|
cursor: CAMERA_CURSOR,
|
|
419
|
-
background: "rgba(
|
|
420
|
-
boxShadow: "inset 0 0 0
|
|
421
|
-
}
|
|
422
|
-
children: /* @__PURE__ */ jsx2(
|
|
423
|
-
"div",
|
|
424
|
-
{
|
|
425
|
-
style: {
|
|
426
|
-
position: "absolute",
|
|
427
|
-
top: 36,
|
|
428
|
-
left: "50%",
|
|
429
|
-
transform: "translateX(-50%)",
|
|
430
|
-
padding: "8px 14px",
|
|
431
|
-
borderRadius: 999,
|
|
432
|
-
background: "rgba(125, 211, 252, 0.16)",
|
|
433
|
-
border: "1px solid rgba(125, 211, 252, 0.42)",
|
|
434
|
-
color: "rgba(224, 242, 254, 0.96)",
|
|
435
|
-
fontSize: 12,
|
|
436
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
437
|
-
boxShadow: "0 10px 30px rgba(14, 116, 144, 0.18)",
|
|
438
|
-
pointerEvents: "none"
|
|
439
|
-
},
|
|
440
|
-
children: mode === "fullpage" ? "Click to capture full page" : "Click to capture viewport"
|
|
441
|
-
}
|
|
442
|
-
)
|
|
326
|
+
background: "rgba(59, 130, 246, 0.15)",
|
|
327
|
+
boxShadow: "inset 0 0 0 2px rgba(59, 130, 246, 0.7)"
|
|
328
|
+
}
|
|
443
329
|
}
|
|
444
330
|
);
|
|
445
331
|
}
|
|
446
|
-
return
|
|
447
|
-
"div",
|
|
448
|
-
{
|
|
449
|
-
"data-afterbefore": "true",
|
|
450
|
-
style: {
|
|
451
|
-
position: "fixed",
|
|
452
|
-
inset: 0,
|
|
453
|
-
zIndex: 2147483645,
|
|
454
|
-
pointerEvents: "none"
|
|
455
|
-
},
|
|
456
|
-
children: /* @__PURE__ */ jsx2(
|
|
457
|
-
"div",
|
|
458
|
-
{
|
|
459
|
-
style: {
|
|
460
|
-
position: "absolute",
|
|
461
|
-
top: 36,
|
|
462
|
-
left: "50%",
|
|
463
|
-
transform: "translateX(-50%)",
|
|
464
|
-
padding: "8px 14px",
|
|
465
|
-
borderRadius: 999,
|
|
466
|
-
background: "rgba(125, 211, 252, 0.16)",
|
|
467
|
-
border: "1px solid rgba(125, 211, 252, 0.42)",
|
|
468
|
-
color: "rgba(224, 242, 254, 0.96)",
|
|
469
|
-
fontSize: 12,
|
|
470
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
471
|
-
boxShadow: "0 10px 30px rgba(14, 116, 144, 0.18)"
|
|
472
|
-
},
|
|
473
|
-
children: "Click Capture, then hover an element to preview it"
|
|
474
|
-
}
|
|
475
|
-
)
|
|
476
|
-
}
|
|
477
|
-
);
|
|
332
|
+
return null;
|
|
478
333
|
}
|
|
479
334
|
|
|
480
335
|
// src/overlay/ui/toolbar.tsx
|
|
481
|
-
import { useEffect as
|
|
336
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
482
337
|
import {
|
|
483
338
|
ChevronDown,
|
|
484
|
-
|
|
485
|
-
FileText,
|
|
339
|
+
Maximize,
|
|
486
340
|
FolderOpen,
|
|
487
341
|
Frame,
|
|
488
|
-
|
|
342
|
+
ImageIcon,
|
|
489
343
|
Monitor,
|
|
490
344
|
MousePointer2,
|
|
491
|
-
|
|
492
|
-
|
|
345
|
+
Palette,
|
|
346
|
+
Settings,
|
|
347
|
+
Trash2,
|
|
348
|
+
Upload,
|
|
493
349
|
X
|
|
494
350
|
} from "lucide-react";
|
|
495
|
-
|
|
496
|
-
// src/overlay/ui/selector.tsx
|
|
497
|
-
import React3, { useRef as useRef2, useCallback as useCallback3, useEffect as useEffect3, useMemo, useState as useState4 } from "react";
|
|
498
351
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
499
|
-
var DEFAULT_AREA_ASPECT = "16:9";
|
|
500
|
-
var AREA_ASPECT_RATIOS = [
|
|
501
|
-
{ label: "Free", value: 0 },
|
|
502
|
-
{ label: "16:9", value: 16 / 9 },
|
|
503
|
-
{ label: "4:3", value: 4 / 3 },
|
|
504
|
-
{ label: "1:1", value: 1 },
|
|
505
|
-
{ label: "3:2", value: 3 / 2 },
|
|
506
|
-
{ label: "21:9", value: 21 / 9 }
|
|
507
|
-
];
|
|
508
|
-
var HANDLE_R = 6;
|
|
509
|
-
var HANDLE_HIT = 16;
|
|
510
|
-
var MIN_SIZE = 20;
|
|
511
|
-
var SNAP_THRESHOLD = 8;
|
|
512
|
-
var CAMERA_CURSOR2 = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='%23e0f2fe' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7h3l1.5-2h7L17 7h3a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2Z'/%3E%3Ccircle cx='12' cy='13' r='4'/%3E%3C/svg%3E") 12 12, crosshair`;
|
|
513
|
-
function createInitialAreaRect() {
|
|
514
|
-
const safeWidth = Math.max(320, window.innerWidth - 96);
|
|
515
|
-
const safeHeight = Math.max(180, window.innerHeight - 220);
|
|
516
|
-
const w = Math.min(window.innerWidth * 0.72, safeHeight * (16 / 9), safeWidth);
|
|
517
|
-
const h = w / (16 / 9);
|
|
518
|
-
return {
|
|
519
|
-
x: (window.innerWidth - w) / 2,
|
|
520
|
-
y: Math.max(40, (window.innerHeight - h) / 2 - 20),
|
|
521
|
-
w,
|
|
522
|
-
h
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
function getAspectRatio(label) {
|
|
526
|
-
return AREA_ASPECT_RATIOS.find((item) => item.label === label)?.value ?? 0;
|
|
527
|
-
}
|
|
528
|
-
function Selector({
|
|
529
|
-
rect,
|
|
530
|
-
aspect,
|
|
531
|
-
magnetEnabled,
|
|
532
|
-
onRectChange,
|
|
533
|
-
onSelect,
|
|
534
|
-
onCancel
|
|
535
|
-
}) {
|
|
536
|
-
const [snappedX, setSnappedX] = useState4(false);
|
|
537
|
-
const [cursor, setCursor] = useState4("crosshair");
|
|
538
|
-
const mode = useRef2("none");
|
|
539
|
-
const start = useRef2({ x: 0, y: 0 });
|
|
540
|
-
const snapRef = useRef2({ x: 0, y: 0, w: 0, h: 0 });
|
|
541
|
-
const corner = useRef2("br");
|
|
542
|
-
const ratio = useMemo(() => getAspectRatio(aspect), [aspect]);
|
|
543
|
-
const applySnap = useCallback3(
|
|
544
|
-
(nextRect) => {
|
|
545
|
-
if (!magnetEnabled) {
|
|
546
|
-
setSnappedX(false);
|
|
547
|
-
return nextRect;
|
|
548
|
-
}
|
|
549
|
-
const centerX = nextRect.x + nextRect.w / 2;
|
|
550
|
-
const viewportCenterX = window.innerWidth / 2;
|
|
551
|
-
if (Math.abs(centerX - viewportCenterX) < SNAP_THRESHOLD) {
|
|
552
|
-
setSnappedX(true);
|
|
553
|
-
return { ...nextRect, x: viewportCenterX - nextRect.w / 2 };
|
|
554
|
-
}
|
|
555
|
-
setSnappedX(false);
|
|
556
|
-
return nextRect;
|
|
557
|
-
},
|
|
558
|
-
[magnetEnabled]
|
|
559
|
-
);
|
|
560
|
-
useEffect3(() => {
|
|
561
|
-
const onKey = (e) => {
|
|
562
|
-
if (e.key === "Escape") {
|
|
563
|
-
onCancel();
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
document.addEventListener("keydown", onKey);
|
|
567
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
568
|
-
}, [onCancel]);
|
|
569
|
-
const hitCorner = useCallback3((mx, my, currentRect) => {
|
|
570
|
-
const corners = [
|
|
571
|
-
["tl", currentRect.x, currentRect.y],
|
|
572
|
-
["tr", currentRect.x + currentRect.w, currentRect.y],
|
|
573
|
-
["bl", currentRect.x, currentRect.y + currentRect.h],
|
|
574
|
-
["br", currentRect.x + currentRect.w, currentRect.y + currentRect.h]
|
|
575
|
-
];
|
|
576
|
-
for (const [hitCorner2, cx, cy] of corners) {
|
|
577
|
-
if (Math.abs(mx - cx) <= HANDLE_HIT && Math.abs(my - cy) <= HANDLE_HIT) {
|
|
578
|
-
return hitCorner2;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
return null;
|
|
582
|
-
}, []);
|
|
583
|
-
const hitInside = useCallback3(
|
|
584
|
-
(mx, my, currentRect) => mx >= currentRect.x && mx <= currentRect.x + currentRect.w && my >= currentRect.y && my <= currentRect.y + currentRect.h,
|
|
585
|
-
[]
|
|
586
|
-
);
|
|
587
|
-
const onDown = useCallback3(
|
|
588
|
-
(e) => {
|
|
589
|
-
e.preventDefault();
|
|
590
|
-
const mx = e.clientX;
|
|
591
|
-
const my = e.clientY;
|
|
592
|
-
if (rect) {
|
|
593
|
-
const activeCorner = hitCorner(mx, my, rect);
|
|
594
|
-
if (activeCorner) {
|
|
595
|
-
mode.current = "resizing";
|
|
596
|
-
corner.current = activeCorner;
|
|
597
|
-
start.current = { x: mx, y: my };
|
|
598
|
-
snapRef.current = { ...rect };
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
if (hitInside(mx, my, rect)) {
|
|
602
|
-
mode.current = "moving";
|
|
603
|
-
start.current = { x: mx, y: my };
|
|
604
|
-
snapRef.current = { ...rect };
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
mode.current = "drawing";
|
|
609
|
-
start.current = { x: mx, y: my };
|
|
610
|
-
onRectChange({ x: mx, y: my, w: 0, h: 0 });
|
|
611
|
-
},
|
|
612
|
-
[hitCorner, hitInside, onRectChange, rect]
|
|
613
|
-
);
|
|
614
|
-
const onMove = useCallback3(
|
|
615
|
-
(e) => {
|
|
616
|
-
const mx = e.clientX;
|
|
617
|
-
const my = e.clientY;
|
|
618
|
-
if (mode.current === "none") {
|
|
619
|
-
if (rect) {
|
|
620
|
-
const activeCorner = hitCorner(mx, my, rect);
|
|
621
|
-
if (activeCorner) {
|
|
622
|
-
setCursor(
|
|
623
|
-
activeCorner === "tl" || activeCorner === "br" ? "nwse-resize" : "nesw-resize"
|
|
624
|
-
);
|
|
625
|
-
} else if (hitInside(mx, my, rect)) {
|
|
626
|
-
setCursor(CAMERA_CURSOR2);
|
|
627
|
-
} else {
|
|
628
|
-
setCursor("crosshair");
|
|
629
|
-
}
|
|
630
|
-
} else {
|
|
631
|
-
setCursor("crosshair");
|
|
632
|
-
}
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
if (mode.current === "drawing") {
|
|
636
|
-
const sx = start.current.x;
|
|
637
|
-
const sy = start.current.y;
|
|
638
|
-
let x = Math.min(sx, mx);
|
|
639
|
-
let y = Math.min(sy, my);
|
|
640
|
-
let w = Math.abs(mx - sx);
|
|
641
|
-
let h = Math.abs(my - sy);
|
|
642
|
-
if (ratio > 0) {
|
|
643
|
-
h = w / ratio;
|
|
644
|
-
if (my < sy) {
|
|
645
|
-
y = sy - h;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
onRectChange(applySnap({ x, y, w, h }));
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
if (mode.current === "moving") {
|
|
652
|
-
const dx = mx - start.current.x;
|
|
653
|
-
const dy = my - start.current.y;
|
|
654
|
-
onRectChange(
|
|
655
|
-
applySnap({
|
|
656
|
-
...snapRef.current,
|
|
657
|
-
x: snapRef.current.x + dx,
|
|
658
|
-
y: snapRef.current.y + dy
|
|
659
|
-
})
|
|
660
|
-
);
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
if (mode.current === "resizing") {
|
|
664
|
-
const original = snapRef.current;
|
|
665
|
-
const nextRect = { ...original };
|
|
666
|
-
if (corner.current === "br") {
|
|
667
|
-
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
668
|
-
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
669
|
-
} else if (corner.current === "bl") {
|
|
670
|
-
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
671
|
-
nextRect.x = original.x + original.w - nextRect.w;
|
|
672
|
-
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
673
|
-
} else if (corner.current === "tr") {
|
|
674
|
-
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
675
|
-
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
676
|
-
nextRect.y = original.y + original.h - nextRect.h;
|
|
677
|
-
} else {
|
|
678
|
-
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
679
|
-
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
680
|
-
nextRect.x = original.x + original.w - nextRect.w;
|
|
681
|
-
nextRect.y = original.y + original.h - nextRect.h;
|
|
682
|
-
}
|
|
683
|
-
onRectChange(applySnap(nextRect));
|
|
684
|
-
}
|
|
685
|
-
},
|
|
686
|
-
[applySnap, hitCorner, hitInside, onRectChange, ratio, rect]
|
|
687
|
-
);
|
|
688
|
-
const onUp = useCallback3(
|
|
689
|
-
(e) => {
|
|
690
|
-
const previousMode = mode.current;
|
|
691
|
-
if (previousMode === "drawing" && rect) {
|
|
692
|
-
if (rect.w < MIN_SIZE || rect.h < MIN_SIZE) {
|
|
693
|
-
onRectChange(null);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
if (previousMode === "moving" && rect) {
|
|
697
|
-
const dx = Math.abs(e.clientX - start.current.x);
|
|
698
|
-
const dy = Math.abs(e.clientY - start.current.y);
|
|
699
|
-
if (dx < 3 && dy < 3) {
|
|
700
|
-
onSelect({
|
|
701
|
-
x: Math.round(rect.x),
|
|
702
|
-
y: Math.round(rect.y),
|
|
703
|
-
width: Math.round(rect.w),
|
|
704
|
-
height: Math.round(rect.h)
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
mode.current = "none";
|
|
709
|
-
},
|
|
710
|
-
[onRectChange, onSelect, rect]
|
|
711
|
-
);
|
|
712
|
-
const hasRect = rect && rect.w > 0 && rect.h > 0;
|
|
713
|
-
return /* @__PURE__ */ jsxs2(
|
|
714
|
-
"div",
|
|
715
|
-
{
|
|
716
|
-
"data-afterbefore": "true",
|
|
717
|
-
onMouseDown: onDown,
|
|
718
|
-
onMouseMove: onMove,
|
|
719
|
-
onMouseUp: onUp,
|
|
720
|
-
style: {
|
|
721
|
-
position: "fixed",
|
|
722
|
-
inset: 0,
|
|
723
|
-
zIndex: 2147483646,
|
|
724
|
-
cursor
|
|
725
|
-
},
|
|
726
|
-
children: [
|
|
727
|
-
snappedX && /* @__PURE__ */ jsx3(
|
|
728
|
-
"div",
|
|
729
|
-
{
|
|
730
|
-
style: {
|
|
731
|
-
position: "absolute",
|
|
732
|
-
left: "50%",
|
|
733
|
-
top: 0,
|
|
734
|
-
bottom: 0,
|
|
735
|
-
width: 0,
|
|
736
|
-
borderLeft: "1px solid rgba(56, 189, 248, 0.55)",
|
|
737
|
-
pointerEvents: "none",
|
|
738
|
-
zIndex: 2
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
),
|
|
742
|
-
hasRect ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
743
|
-
/* @__PURE__ */ jsx3(
|
|
744
|
-
"div",
|
|
745
|
-
{
|
|
746
|
-
style: {
|
|
747
|
-
position: "absolute",
|
|
748
|
-
left: 0,
|
|
749
|
-
top: 0,
|
|
750
|
-
width: "100%",
|
|
751
|
-
height: rect.y,
|
|
752
|
-
background: "rgba(0, 0, 0, 0.5)",
|
|
753
|
-
pointerEvents: "none"
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
),
|
|
757
|
-
/* @__PURE__ */ jsx3(
|
|
758
|
-
"div",
|
|
759
|
-
{
|
|
760
|
-
style: {
|
|
761
|
-
position: "absolute",
|
|
762
|
-
left: 0,
|
|
763
|
-
top: rect.y,
|
|
764
|
-
width: rect.x,
|
|
765
|
-
height: rect.h,
|
|
766
|
-
background: "rgba(0, 0, 0, 0.5)",
|
|
767
|
-
pointerEvents: "none"
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
),
|
|
771
|
-
/* @__PURE__ */ jsx3(
|
|
772
|
-
"div",
|
|
773
|
-
{
|
|
774
|
-
style: {
|
|
775
|
-
position: "absolute",
|
|
776
|
-
left: rect.x + rect.w,
|
|
777
|
-
top: rect.y,
|
|
778
|
-
width: `calc(100% - ${rect.x + rect.w}px)`,
|
|
779
|
-
height: rect.h,
|
|
780
|
-
background: "rgba(0, 0, 0, 0.5)",
|
|
781
|
-
pointerEvents: "none"
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
),
|
|
785
|
-
/* @__PURE__ */ jsx3(
|
|
786
|
-
"div",
|
|
787
|
-
{
|
|
788
|
-
style: {
|
|
789
|
-
position: "absolute",
|
|
790
|
-
left: 0,
|
|
791
|
-
top: rect.y + rect.h,
|
|
792
|
-
width: "100%",
|
|
793
|
-
height: `calc(100% - ${rect.y + rect.h}px)`,
|
|
794
|
-
background: "rgba(0, 0, 0, 0.5)",
|
|
795
|
-
pointerEvents: "none"
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
),
|
|
799
|
-
/* @__PURE__ */ jsx3(
|
|
800
|
-
"div",
|
|
801
|
-
{
|
|
802
|
-
style: {
|
|
803
|
-
position: "absolute",
|
|
804
|
-
left: rect.x,
|
|
805
|
-
top: rect.y,
|
|
806
|
-
width: rect.w,
|
|
807
|
-
height: rect.h,
|
|
808
|
-
background: "rgba(125, 211, 252, 0.08)",
|
|
809
|
-
pointerEvents: "none",
|
|
810
|
-
borderRadius: 12
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
),
|
|
814
|
-
/* @__PURE__ */ jsx3(
|
|
815
|
-
"div",
|
|
816
|
-
{
|
|
817
|
-
style: {
|
|
818
|
-
position: "absolute",
|
|
819
|
-
left: rect.x,
|
|
820
|
-
top: rect.y,
|
|
821
|
-
width: rect.w,
|
|
822
|
-
height: rect.h,
|
|
823
|
-
border: "1.5px dashed rgba(255, 255, 255, 0.45)",
|
|
824
|
-
borderRadius: 12,
|
|
825
|
-
pointerEvents: "none",
|
|
826
|
-
boxShadow: "0 0 0 1px rgba(125, 211, 252, 0.38)"
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
),
|
|
830
|
-
[1, 2].map((line) => /* @__PURE__ */ jsxs2(React3.Fragment, { children: [
|
|
831
|
-
/* @__PURE__ */ jsx3(
|
|
832
|
-
"div",
|
|
833
|
-
{
|
|
834
|
-
style: {
|
|
835
|
-
position: "absolute",
|
|
836
|
-
left: rect.x + rect.w * line / 3,
|
|
837
|
-
top: rect.y,
|
|
838
|
-
width: 0,
|
|
839
|
-
height: rect.h,
|
|
840
|
-
borderLeft: "1px dashed rgba(255, 255, 255, 0.18)",
|
|
841
|
-
pointerEvents: "none"
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
),
|
|
845
|
-
/* @__PURE__ */ jsx3(
|
|
846
|
-
"div",
|
|
847
|
-
{
|
|
848
|
-
style: {
|
|
849
|
-
position: "absolute",
|
|
850
|
-
left: rect.x,
|
|
851
|
-
top: rect.y + rect.h * line / 3,
|
|
852
|
-
width: rect.w,
|
|
853
|
-
height: 0,
|
|
854
|
-
borderTop: "1px dashed rgba(255, 255, 255, 0.18)",
|
|
855
|
-
pointerEvents: "none"
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
)
|
|
859
|
-
] }, line)),
|
|
860
|
-
[
|
|
861
|
-
[rect.x, rect.y],
|
|
862
|
-
[rect.x + rect.w, rect.y],
|
|
863
|
-
[rect.x, rect.y + rect.h],
|
|
864
|
-
[rect.x + rect.w, rect.y + rect.h]
|
|
865
|
-
].map(([cx, cy], index) => /* @__PURE__ */ jsx3(
|
|
866
|
-
"div",
|
|
867
|
-
{
|
|
868
|
-
style: {
|
|
869
|
-
position: "absolute",
|
|
870
|
-
left: cx - HANDLE_R,
|
|
871
|
-
top: cy - HANDLE_R,
|
|
872
|
-
width: HANDLE_R * 2,
|
|
873
|
-
height: HANDLE_R * 2,
|
|
874
|
-
borderRadius: "50%",
|
|
875
|
-
border: "2px solid rgba(255, 255, 255, 0.8)",
|
|
876
|
-
background: "rgba(0, 0, 0, 0.25)",
|
|
877
|
-
pointerEvents: "none"
|
|
878
|
-
}
|
|
879
|
-
},
|
|
880
|
-
index
|
|
881
|
-
))
|
|
882
|
-
] }) : /* @__PURE__ */ jsx3(
|
|
883
|
-
"div",
|
|
884
|
-
{
|
|
885
|
-
style: {
|
|
886
|
-
position: "absolute",
|
|
887
|
-
inset: 0,
|
|
888
|
-
background: "rgba(0, 0, 0, 0.5)",
|
|
889
|
-
pointerEvents: "none"
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
)
|
|
893
|
-
]
|
|
894
|
-
}
|
|
895
|
-
);
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
// src/overlay/ui/toolbar.tsx
|
|
899
|
-
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
900
352
|
var MODES = [
|
|
901
353
|
{ mode: "component", label: "Capture Component", icon: MousePointer2 },
|
|
902
|
-
{ mode: "area", label: "Capture Selected Area", icon: Crop },
|
|
903
354
|
{ mode: "viewport", label: "Capture Viewport", icon: Monitor },
|
|
904
|
-
{ mode: "fullpage", label: "Capture Full Page", icon:
|
|
355
|
+
{ mode: "fullpage", label: "Capture Full Page", icon: Maximize }
|
|
905
356
|
];
|
|
906
357
|
function Toolbar({
|
|
907
358
|
selectedMode,
|
|
908
359
|
onModeChange,
|
|
909
360
|
onCapture,
|
|
910
361
|
onCancel,
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
areaSelectionActive,
|
|
914
|
-
areaRect,
|
|
915
|
-
areaAspect,
|
|
916
|
-
areaPresets,
|
|
917
|
-
onAreaSizeChange,
|
|
918
|
-
onAreaPositionChange,
|
|
919
|
-
onAreaAspectChange,
|
|
920
|
-
onAreaSavePreset,
|
|
921
|
-
onAreaLoadPreset,
|
|
922
|
-
frameOnBlackEnabled,
|
|
923
|
-
onFrameOnBlackChange
|
|
362
|
+
frameSettings,
|
|
363
|
+
onFrameSettingsChange
|
|
924
364
|
}) {
|
|
925
|
-
const [settingsOpen, setSettingsOpen] =
|
|
926
|
-
|
|
927
|
-
const [savedOpen, setSavedOpen] = useState5(false);
|
|
928
|
-
const showAreaControls = selectedMode === "area" && areaSelectionActive && areaRect !== null;
|
|
929
|
-
const activeAreaRect = showAreaControls ? areaRect : null;
|
|
930
|
-
useEffect4(() => {
|
|
365
|
+
const [settingsOpen, setSettingsOpen] = useState3(false);
|
|
366
|
+
useEffect2(() => {
|
|
931
367
|
const onKey = (e) => {
|
|
932
368
|
if (e.target?.tagName === "INPUT") {
|
|
933
369
|
if (e.key === "Escape") {
|
|
@@ -940,14 +376,6 @@ function Toolbar({
|
|
|
940
376
|
setSettingsOpen(false);
|
|
941
377
|
return;
|
|
942
378
|
}
|
|
943
|
-
if (aspectOpen) {
|
|
944
|
-
setAspectOpen(false);
|
|
945
|
-
return;
|
|
946
|
-
}
|
|
947
|
-
if (savedOpen) {
|
|
948
|
-
setSavedOpen(false);
|
|
949
|
-
return;
|
|
950
|
-
}
|
|
951
379
|
onCancel();
|
|
952
380
|
} else if (e.key === "Enter") {
|
|
953
381
|
onCapture(selectedMode);
|
|
@@ -955,8 +383,8 @@ function Toolbar({
|
|
|
955
383
|
};
|
|
956
384
|
document.addEventListener("keydown", onKey);
|
|
957
385
|
return () => document.removeEventListener("keydown", onKey);
|
|
958
|
-
}, [
|
|
959
|
-
return /* @__PURE__ */
|
|
386
|
+
}, [onCancel, onCapture, selectedMode, settingsOpen]);
|
|
387
|
+
return /* @__PURE__ */ jsx3(
|
|
960
388
|
"div",
|
|
961
389
|
{
|
|
962
390
|
"data-afterbefore": "true",
|
|
@@ -976,156 +404,64 @@ function Toolbar({
|
|
|
976
404
|
backdropFilter: "blur(20px)",
|
|
977
405
|
WebkitBackdropFilter: "blur(20px)",
|
|
978
406
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
979
|
-
borderRadius:
|
|
980
|
-
padding:
|
|
407
|
+
borderRadius: 999,
|
|
408
|
+
padding: 6,
|
|
981
409
|
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
982
410
|
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
983
411
|
},
|
|
984
|
-
children: [
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
onModeChange(mode);
|
|
995
|
-
},
|
|
996
|
-
children: /* @__PURE__ */ jsx4(Icon2, { size: 18, strokeWidth: 1.7 })
|
|
412
|
+
children: /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 0 }, children: [
|
|
413
|
+
/* @__PURE__ */ jsx3(CloseButton, { onClick: onCancel }),
|
|
414
|
+
/* @__PURE__ */ jsx3("div", { style: { display: "flex", alignItems: "center", gap: 2, padding: "0 4px" }, children: MODES.map(({ mode, label, icon: Icon2 }) => /* @__PURE__ */ jsx3(
|
|
415
|
+
ModeButton,
|
|
416
|
+
{
|
|
417
|
+
label,
|
|
418
|
+
selected: selectedMode === mode,
|
|
419
|
+
onClick: () => {
|
|
420
|
+
setSettingsOpen(false);
|
|
421
|
+
onModeChange(mode);
|
|
997
422
|
},
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
onFrameOnBlackChange
|
|
1015
|
-
}
|
|
1016
|
-
)
|
|
1017
|
-
] }),
|
|
1018
|
-
activeAreaRect && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1019
|
-
/* @__PURE__ */ jsx4(Separator, { vertical: false }),
|
|
1020
|
-
/* @__PURE__ */ jsxs3(
|
|
1021
|
-
"div",
|
|
1022
|
-
{
|
|
1023
|
-
style: {
|
|
1024
|
-
display: "flex",
|
|
1025
|
-
alignItems: "center",
|
|
1026
|
-
gap: 8,
|
|
1027
|
-
flexWrap: "wrap",
|
|
1028
|
-
justifyContent: "center"
|
|
1029
|
-
},
|
|
1030
|
-
children: [
|
|
1031
|
-
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Size", children: [
|
|
1032
|
-
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.w), onChange: (value) => onAreaSizeChange("w", value) }),
|
|
1033
|
-
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
1034
|
-
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.h), onChange: (value) => onAreaSizeChange("h", value) })
|
|
1035
|
-
] }),
|
|
1036
|
-
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Position", children: [
|
|
1037
|
-
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.x), onChange: (value) => onAreaPositionChange("x", value) }),
|
|
1038
|
-
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
1039
|
-
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.y), onChange: (value) => onAreaPositionChange("y", value) })
|
|
1040
|
-
] }),
|
|
1041
|
-
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1042
|
-
/* @__PURE__ */ jsxs3(
|
|
1043
|
-
DropButton,
|
|
1044
|
-
{
|
|
1045
|
-
active: areaAspect !== "Free",
|
|
1046
|
-
onClick: () => {
|
|
1047
|
-
setSavedOpen(false);
|
|
1048
|
-
setAspectOpen((prev) => !prev);
|
|
1049
|
-
},
|
|
1050
|
-
children: [
|
|
1051
|
-
areaAspect,
|
|
1052
|
-
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
1053
|
-
]
|
|
1054
|
-
}
|
|
1055
|
-
),
|
|
1056
|
-
aspectOpen && /* @__PURE__ */ jsx4(DropMenu, { children: AREA_ASPECT_RATIOS.map((item) => /* @__PURE__ */ jsx4(
|
|
1057
|
-
DropItem,
|
|
1058
|
-
{
|
|
1059
|
-
active: item.label === areaAspect,
|
|
1060
|
-
onClick: () => {
|
|
1061
|
-
onAreaAspectChange(item.label);
|
|
1062
|
-
setAspectOpen(false);
|
|
1063
|
-
},
|
|
1064
|
-
children: item.label
|
|
1065
|
-
},
|
|
1066
|
-
item.label
|
|
1067
|
-
)) })
|
|
1068
|
-
] }),
|
|
1069
|
-
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1070
|
-
/* @__PURE__ */ jsxs3(
|
|
1071
|
-
DropButton,
|
|
1072
|
-
{
|
|
1073
|
-
onClick: () => {
|
|
1074
|
-
setAspectOpen(false);
|
|
1075
|
-
setSavedOpen((prev) => !prev);
|
|
1076
|
-
},
|
|
1077
|
-
children: [
|
|
1078
|
-
/* @__PURE__ */ jsx4(Save, { size: 14, strokeWidth: 1.8 }),
|
|
1079
|
-
"Saved",
|
|
1080
|
-
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
1081
|
-
]
|
|
1082
|
-
}
|
|
1083
|
-
),
|
|
1084
|
-
savedOpen && /* @__PURE__ */ jsxs3(DropMenu, { children: [
|
|
1085
|
-
/* @__PURE__ */ jsx4(DropItem, { accent: true, onClick: onAreaSavePreset, children: "Save current" }),
|
|
1086
|
-
areaPresets.length > 0 && /* @__PURE__ */ jsx4(MenuDivider, {}),
|
|
1087
|
-
areaPresets.map((preset) => /* @__PURE__ */ jsx4(
|
|
1088
|
-
DropItem,
|
|
1089
|
-
{
|
|
1090
|
-
onClick: () => {
|
|
1091
|
-
onAreaLoadPreset(preset);
|
|
1092
|
-
setSavedOpen(false);
|
|
1093
|
-
},
|
|
1094
|
-
children: preset.label
|
|
1095
|
-
},
|
|
1096
|
-
preset.label
|
|
1097
|
-
)),
|
|
1098
|
-
areaPresets.length === 0 && /* @__PURE__ */ jsx4(
|
|
1099
|
-
"div",
|
|
1100
|
-
{
|
|
1101
|
-
style: {
|
|
1102
|
-
padding: "6px 12px",
|
|
1103
|
-
color: "rgba(255,255,255,0.3)",
|
|
1104
|
-
fontSize: 12
|
|
1105
|
-
},
|
|
1106
|
-
children: "No saved areas"
|
|
1107
|
-
}
|
|
1108
|
-
)
|
|
1109
|
-
] })
|
|
1110
|
-
] })
|
|
1111
|
-
]
|
|
1112
|
-
}
|
|
1113
|
-
)
|
|
1114
|
-
] })
|
|
1115
|
-
]
|
|
423
|
+
children: /* @__PURE__ */ jsx3(Icon2, { size: 16, strokeWidth: 1.7 })
|
|
424
|
+
},
|
|
425
|
+
mode
|
|
426
|
+
)) }),
|
|
427
|
+
/* @__PURE__ */ jsx3(Separator, {}),
|
|
428
|
+
/* @__PURE__ */ jsx3(
|
|
429
|
+
SettingsButton,
|
|
430
|
+
{
|
|
431
|
+
open: settingsOpen,
|
|
432
|
+
onClick: () => setSettingsOpen((prev) => !prev),
|
|
433
|
+
selectedMode,
|
|
434
|
+
frameSettings,
|
|
435
|
+
onFrameSettingsChange
|
|
436
|
+
}
|
|
437
|
+
)
|
|
438
|
+
] })
|
|
1116
439
|
}
|
|
1117
440
|
);
|
|
1118
441
|
}
|
|
1119
442
|
function CloseButton({ onClick }) {
|
|
1120
|
-
const [hovered, setHovered] =
|
|
1121
|
-
return /* @__PURE__ */
|
|
443
|
+
const [hovered, setHovered] = useState3(false);
|
|
444
|
+
return /* @__PURE__ */ jsx3(
|
|
1122
445
|
"button",
|
|
1123
446
|
{
|
|
1124
447
|
onClick,
|
|
1125
448
|
onMouseEnter: () => setHovered(true),
|
|
1126
449
|
onMouseLeave: () => setHovered(false),
|
|
1127
|
-
style:
|
|
1128
|
-
|
|
450
|
+
style: {
|
|
451
|
+
width: 32,
|
|
452
|
+
height: 32,
|
|
453
|
+
borderRadius: 10,
|
|
454
|
+
border: "none",
|
|
455
|
+
background: hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
456
|
+
display: "flex",
|
|
457
|
+
alignItems: "center",
|
|
458
|
+
justifyContent: "center",
|
|
459
|
+
cursor: "pointer",
|
|
460
|
+
padding: 0,
|
|
461
|
+
color: hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
462
|
+
transition: "background 0.12s ease, color 0.12s ease"
|
|
463
|
+
},
|
|
464
|
+
children: /* @__PURE__ */ jsx3(X, { size: 16, strokeWidth: 1.7 })
|
|
1129
465
|
}
|
|
1130
466
|
);
|
|
1131
467
|
}
|
|
@@ -1135,9 +471,9 @@ function ModeButton({
|
|
|
1135
471
|
selected,
|
|
1136
472
|
onClick
|
|
1137
473
|
}) {
|
|
1138
|
-
const [hovered, setHovered] =
|
|
1139
|
-
return /* @__PURE__ */
|
|
1140
|
-
hovered && /* @__PURE__ */
|
|
474
|
+
const [hovered, setHovered] = useState3(false);
|
|
475
|
+
return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
476
|
+
hovered && /* @__PURE__ */ jsx3(
|
|
1141
477
|
"div",
|
|
1142
478
|
{
|
|
1143
479
|
style: {
|
|
@@ -1160,24 +496,24 @@ function ModeButton({
|
|
|
1160
496
|
children: label
|
|
1161
497
|
}
|
|
1162
498
|
),
|
|
1163
|
-
/* @__PURE__ */
|
|
499
|
+
/* @__PURE__ */ jsx3(
|
|
1164
500
|
"button",
|
|
1165
501
|
{
|
|
1166
502
|
onClick,
|
|
1167
503
|
onMouseEnter: () => setHovered(true),
|
|
1168
504
|
onMouseLeave: () => setHovered(false),
|
|
1169
505
|
style: {
|
|
1170
|
-
width:
|
|
1171
|
-
height:
|
|
1172
|
-
borderRadius:
|
|
506
|
+
width: 32,
|
|
507
|
+
height: 32,
|
|
508
|
+
borderRadius: 10,
|
|
1173
509
|
border: "none",
|
|
1174
|
-
background: selected
|
|
510
|
+
background: selected || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
1175
511
|
display: "flex",
|
|
1176
512
|
alignItems: "center",
|
|
1177
513
|
justifyContent: "center",
|
|
1178
514
|
cursor: "pointer",
|
|
1179
515
|
padding: 0,
|
|
1180
|
-
color: selected ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
516
|
+
color: selected || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
1181
517
|
transition: "background 0.12s ease, color 0.12s ease"
|
|
1182
518
|
},
|
|
1183
519
|
children
|
|
@@ -1185,126 +521,465 @@ function ModeButton({
|
|
|
1185
521
|
)
|
|
1186
522
|
] });
|
|
1187
523
|
}
|
|
1188
|
-
function SettingsButton({
|
|
1189
|
-
open,
|
|
1190
|
-
onClick,
|
|
1191
|
-
selectedMode,
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
524
|
+
function SettingsButton({
|
|
525
|
+
open,
|
|
526
|
+
onClick,
|
|
527
|
+
selectedMode,
|
|
528
|
+
frameSettings,
|
|
529
|
+
onFrameSettingsChange
|
|
530
|
+
}) {
|
|
531
|
+
const [hovered, setHovered] = useState3(false);
|
|
532
|
+
const [saveDir, setSaveDir] = useState3(null);
|
|
533
|
+
const [picking, setPicking] = useState3(false);
|
|
534
|
+
useEffect2(() => {
|
|
535
|
+
if (!open) return;
|
|
536
|
+
fetch("/__afterbefore/config").then((r) => r.json()).then((data) => setSaveDir(data.saveDir)).catch(() => {
|
|
537
|
+
});
|
|
538
|
+
}, [open]);
|
|
539
|
+
const handlePickFolder = async () => {
|
|
540
|
+
setPicking(true);
|
|
541
|
+
try {
|
|
542
|
+
const res = await fetch("/__afterbefore/pick-folder", { method: "POST" });
|
|
543
|
+
const data = await res.json();
|
|
544
|
+
if (data.folder) {
|
|
545
|
+
await fetch("/__afterbefore/config", {
|
|
546
|
+
method: "POST",
|
|
547
|
+
headers: { "Content-Type": "application/json" },
|
|
548
|
+
body: JSON.stringify({ saveDir: data.folder })
|
|
549
|
+
});
|
|
550
|
+
setSaveDir(data.folder);
|
|
551
|
+
}
|
|
552
|
+
} catch {
|
|
553
|
+
} finally {
|
|
554
|
+
setPicking(false);
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
const shortDir = saveDir ? saveDir.replace(/^\/Users\/[^/]+/, "~") : "~/Desktop";
|
|
558
|
+
return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
559
|
+
/* @__PURE__ */ jsx3(
|
|
560
|
+
"button",
|
|
561
|
+
{
|
|
562
|
+
onClick,
|
|
563
|
+
onMouseEnter: () => setHovered(true),
|
|
564
|
+
onMouseLeave: () => setHovered(false),
|
|
565
|
+
style: {
|
|
566
|
+
width: 32,
|
|
567
|
+
height: 32,
|
|
568
|
+
borderRadius: "50%",
|
|
569
|
+
border: "none",
|
|
570
|
+
background: open || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
571
|
+
display: "flex",
|
|
572
|
+
alignItems: "center",
|
|
573
|
+
justifyContent: "center",
|
|
574
|
+
cursor: "pointer",
|
|
575
|
+
padding: 0,
|
|
576
|
+
color: open || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
577
|
+
transition: "background 0.12s ease, color 0.12s ease"
|
|
578
|
+
},
|
|
579
|
+
children: /* @__PURE__ */ jsx3(Settings, { size: 16, strokeWidth: 1.7 })
|
|
580
|
+
}
|
|
581
|
+
),
|
|
582
|
+
open && /* @__PURE__ */ jsxs2(
|
|
583
|
+
"div",
|
|
584
|
+
{
|
|
585
|
+
style: {
|
|
586
|
+
position: "absolute",
|
|
587
|
+
left: "50%",
|
|
588
|
+
bottom: "calc(100% + 12px)",
|
|
589
|
+
transform: "translateX(-50%)",
|
|
590
|
+
minWidth: 260,
|
|
591
|
+
padding: "10px 12px",
|
|
592
|
+
borderRadius: 12,
|
|
593
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
594
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
595
|
+
boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
|
|
596
|
+
backdropFilter: "blur(20px)",
|
|
597
|
+
WebkitBackdropFilter: "blur(20px)"
|
|
598
|
+
},
|
|
599
|
+
children: [
|
|
600
|
+
/* @__PURE__ */ jsx3(
|
|
601
|
+
"div",
|
|
602
|
+
{
|
|
603
|
+
style: {
|
|
604
|
+
fontSize: 11,
|
|
605
|
+
color: "rgba(255, 255, 255, 0.46)",
|
|
606
|
+
letterSpacing: "0.03em",
|
|
607
|
+
textTransform: "uppercase",
|
|
608
|
+
marginBottom: 10
|
|
609
|
+
},
|
|
610
|
+
children: "Settings"
|
|
611
|
+
}
|
|
612
|
+
),
|
|
613
|
+
selectedMode === "component" && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
614
|
+
/* @__PURE__ */ jsx3(
|
|
615
|
+
ToggleRow,
|
|
616
|
+
{
|
|
617
|
+
icon: /* @__PURE__ */ jsx3(Frame, { size: 15, strokeWidth: 1.8 }),
|
|
618
|
+
label: "Frame",
|
|
619
|
+
enabled: frameSettings.enabled,
|
|
620
|
+
onChange: () => onFrameSettingsChange({ ...frameSettings, enabled: !frameSettings.enabled })
|
|
621
|
+
}
|
|
622
|
+
),
|
|
623
|
+
frameSettings.enabled && /* @__PURE__ */ jsxs2("div", { style: { marginTop: 8, display: "flex", flexDirection: "column", gap: 10 }, children: [
|
|
624
|
+
/* @__PURE__ */ jsx3(
|
|
625
|
+
FrameSizeControl,
|
|
626
|
+
{
|
|
627
|
+
size: frameSettings.size,
|
|
628
|
+
onChange: (size) => onFrameSettingsChange({ ...frameSettings, size })
|
|
629
|
+
}
|
|
630
|
+
),
|
|
631
|
+
/* @__PURE__ */ jsx3(
|
|
632
|
+
FrameBackgroundControl,
|
|
633
|
+
{
|
|
634
|
+
bgType: frameSettings.bgType,
|
|
635
|
+
bgColor: frameSettings.bgColor,
|
|
636
|
+
bgImage: frameSettings.bgImage,
|
|
637
|
+
frameSize: frameSettings.size,
|
|
638
|
+
onChange: (updates) => onFrameSettingsChange({ ...frameSettings, ...updates })
|
|
639
|
+
}
|
|
640
|
+
)
|
|
641
|
+
] })
|
|
642
|
+
] }),
|
|
643
|
+
selectedMode === "component" && /* @__PURE__ */ jsx3("div", { style: { height: 1, background: "rgba(255,255,255,0.08)", margin: "8px 0" } }),
|
|
644
|
+
/* @__PURE__ */ jsx3(
|
|
645
|
+
SaveLocationRow,
|
|
646
|
+
{
|
|
647
|
+
dir: shortDir,
|
|
648
|
+
picking,
|
|
649
|
+
onPick: handlePickFolder
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
)
|
|
655
|
+
] });
|
|
656
|
+
}
|
|
657
|
+
function FrameSizeControl({
|
|
658
|
+
size,
|
|
659
|
+
onChange
|
|
660
|
+
}) {
|
|
661
|
+
const [sizeOpen, setSizeOpen] = useState3(false);
|
|
662
|
+
const currentPreset = FRAME_SIZE_PRESETS.find((p) => p.w === size.w && p.h === size.h);
|
|
663
|
+
const isCustom = !currentPreset;
|
|
664
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
665
|
+
/* @__PURE__ */ jsx3(SettingsLabel, { children: "Size" }),
|
|
666
|
+
/* @__PURE__ */ jsx3("div", { style: { display: "flex", alignItems: "center", gap: 6, marginTop: 4 }, children: /* @__PURE__ */ jsxs2("div", { style: { position: "relative", flex: 1 }, children: [
|
|
667
|
+
/* @__PURE__ */ jsxs2(
|
|
668
|
+
"button",
|
|
669
|
+
{
|
|
670
|
+
onClick: () => setSizeOpen((prev) => !prev),
|
|
671
|
+
style: {
|
|
672
|
+
display: "flex",
|
|
673
|
+
alignItems: "center",
|
|
674
|
+
justifyContent: "space-between",
|
|
675
|
+
gap: 6,
|
|
676
|
+
width: "100%",
|
|
677
|
+
height: 30,
|
|
678
|
+
padding: "0 8px",
|
|
679
|
+
borderRadius: 7,
|
|
680
|
+
border: "1px solid rgba(255,255,255,0.1)",
|
|
681
|
+
background: "rgba(255,255,255,0.07)",
|
|
682
|
+
color: "rgba(255,255,255,0.88)",
|
|
683
|
+
cursor: "pointer",
|
|
684
|
+
fontSize: 12,
|
|
685
|
+
fontFamily: "inherit"
|
|
686
|
+
},
|
|
687
|
+
children: [
|
|
688
|
+
currentPreset ? currentPreset.label : "Custom",
|
|
689
|
+
/* @__PURE__ */ jsx3(ChevronDown, { size: 12, strokeWidth: 2 })
|
|
690
|
+
]
|
|
691
|
+
}
|
|
692
|
+
),
|
|
693
|
+
sizeOpen && /* @__PURE__ */ jsxs2(
|
|
694
|
+
"div",
|
|
695
|
+
{
|
|
696
|
+
style: {
|
|
697
|
+
position: "absolute",
|
|
698
|
+
bottom: "calc(100% + 4px)",
|
|
699
|
+
left: 0,
|
|
700
|
+
right: 0,
|
|
701
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
702
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
703
|
+
borderRadius: 8,
|
|
704
|
+
padding: "4px 0",
|
|
705
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
|
|
706
|
+
backdropFilter: "blur(20px)",
|
|
707
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
708
|
+
zIndex: 1
|
|
709
|
+
},
|
|
710
|
+
children: [
|
|
711
|
+
FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsx3(
|
|
712
|
+
DropItem,
|
|
713
|
+
{
|
|
714
|
+
active: !isCustom && preset.w === size.w && preset.h === size.h,
|
|
715
|
+
onClick: () => {
|
|
716
|
+
onChange({ w: preset.w, h: preset.h });
|
|
717
|
+
setSizeOpen(false);
|
|
718
|
+
},
|
|
719
|
+
children: preset.label
|
|
720
|
+
},
|
|
721
|
+
preset.label
|
|
722
|
+
)),
|
|
723
|
+
/* @__PURE__ */ jsx3(DropItem, { active: isCustom, onClick: () => setSizeOpen(false), children: "Custom" })
|
|
724
|
+
]
|
|
725
|
+
}
|
|
726
|
+
)
|
|
727
|
+
] }) }),
|
|
728
|
+
isCustom && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 6 }, children: [
|
|
729
|
+
/* @__PURE__ */ jsx3(
|
|
730
|
+
NumInput,
|
|
731
|
+
{
|
|
732
|
+
value: size.w,
|
|
733
|
+
onChange: (v) => {
|
|
734
|
+
const n = parseInt(v, 10);
|
|
735
|
+
if (!Number.isNaN(n) && n > 0) onChange({ ...size, w: n });
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
),
|
|
739
|
+
/* @__PURE__ */ jsx3(StaticText, { children: "x" }),
|
|
740
|
+
/* @__PURE__ */ jsx3(
|
|
741
|
+
NumInput,
|
|
742
|
+
{
|
|
743
|
+
value: size.h,
|
|
744
|
+
onChange: (v) => {
|
|
745
|
+
const n = parseInt(v, 10);
|
|
746
|
+
if (!Number.isNaN(n) && n > 0) onChange({ ...size, h: n });
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
)
|
|
750
|
+
] })
|
|
751
|
+
] });
|
|
752
|
+
}
|
|
753
|
+
function FrameBackgroundControl({
|
|
754
|
+
bgType,
|
|
755
|
+
bgColor,
|
|
756
|
+
bgImage,
|
|
757
|
+
frameSize,
|
|
758
|
+
onChange
|
|
759
|
+
}) {
|
|
760
|
+
const fileInputRef = useRef2(null);
|
|
761
|
+
const handleFileSelect = (e) => {
|
|
762
|
+
const file = e.target.files?.[0];
|
|
763
|
+
if (!file) return;
|
|
764
|
+
const reader = new FileReader();
|
|
765
|
+
reader.onload = () => {
|
|
766
|
+
const dataUrl = reader.result;
|
|
767
|
+
if (dataUrl.length > 2 * 1024 * 1024) {
|
|
768
|
+
downscaleImage(dataUrl, frameSize.w, frameSize.h).then((scaled) => {
|
|
769
|
+
onChange({ bgType: "image", bgImage: scaled });
|
|
770
|
+
});
|
|
771
|
+
} else {
|
|
772
|
+
onChange({ bgType: "image", bgImage: dataUrl });
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
reader.readAsDataURL(file);
|
|
776
|
+
e.target.value = "";
|
|
777
|
+
};
|
|
778
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
779
|
+
/* @__PURE__ */ jsx3(SettingsLabel, { children: "Background" }),
|
|
780
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 2, marginTop: 4 }, children: [
|
|
781
|
+
/* @__PURE__ */ jsxs2(
|
|
782
|
+
SegmentButton,
|
|
783
|
+
{
|
|
784
|
+
active: bgType === "color",
|
|
785
|
+
onClick: () => onChange({ bgType: "color" }),
|
|
786
|
+
style: { borderRadius: "6px 0 0 6px" },
|
|
787
|
+
children: [
|
|
788
|
+
/* @__PURE__ */ jsx3(Palette, { size: 12, strokeWidth: 2 }),
|
|
789
|
+
"Color"
|
|
790
|
+
]
|
|
791
|
+
}
|
|
792
|
+
),
|
|
793
|
+
/* @__PURE__ */ jsxs2(
|
|
794
|
+
SegmentButton,
|
|
795
|
+
{
|
|
796
|
+
active: bgType === "image",
|
|
797
|
+
onClick: () => onChange({ bgType: "image" }),
|
|
798
|
+
style: { borderRadius: "0 6px 6px 0" },
|
|
799
|
+
children: [
|
|
800
|
+
/* @__PURE__ */ jsx3(ImageIcon, { size: 12, strokeWidth: 2 }),
|
|
801
|
+
"Image"
|
|
802
|
+
]
|
|
803
|
+
}
|
|
804
|
+
)
|
|
805
|
+
] }),
|
|
806
|
+
bgType === "color" && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 }, children: [
|
|
807
|
+
/* @__PURE__ */ jsx3(ColorSwatch, { color: bgColor, onChange: (c) => onChange({ bgColor: c }) }),
|
|
808
|
+
/* @__PURE__ */ jsx3("span", { style: { fontSize: 12, color: "rgba(255,255,255,0.6)" }, children: bgColor })
|
|
809
|
+
] }),
|
|
810
|
+
bgType === "image" && /* @__PURE__ */ jsxs2("div", { style: { marginTop: 6 }, children: [
|
|
811
|
+
/* @__PURE__ */ jsx3(
|
|
812
|
+
"input",
|
|
813
|
+
{
|
|
814
|
+
ref: fileInputRef,
|
|
815
|
+
type: "file",
|
|
816
|
+
accept: "image/*",
|
|
817
|
+
onChange: handleFileSelect,
|
|
818
|
+
style: { display: "none" }
|
|
819
|
+
}
|
|
820
|
+
),
|
|
821
|
+
bgImage ? /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
822
|
+
/* @__PURE__ */ jsx3(
|
|
823
|
+
"img",
|
|
824
|
+
{
|
|
825
|
+
src: bgImage,
|
|
826
|
+
alt: "",
|
|
827
|
+
style: {
|
|
828
|
+
width: 48,
|
|
829
|
+
height: 28,
|
|
830
|
+
borderRadius: 4,
|
|
831
|
+
objectFit: "cover",
|
|
832
|
+
border: "1px solid rgba(255,255,255,0.12)"
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
),
|
|
836
|
+
/* @__PURE__ */ jsxs2(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
|
|
837
|
+
/* @__PURE__ */ jsx3(Upload, { size: 11, strokeWidth: 2 }),
|
|
838
|
+
"Replace"
|
|
839
|
+
] }),
|
|
840
|
+
/* @__PURE__ */ jsx3(SmallButton, { onClick: () => onChange({ bgImage: null }), children: /* @__PURE__ */ jsx3(Trash2, { size: 11, strokeWidth: 2 }) })
|
|
841
|
+
] }) : /* @__PURE__ */ jsxs2(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
|
|
842
|
+
/* @__PURE__ */ jsx3(Upload, { size: 11, strokeWidth: 2 }),
|
|
843
|
+
"Upload image"
|
|
844
|
+
] })
|
|
845
|
+
] })
|
|
846
|
+
] });
|
|
847
|
+
}
|
|
848
|
+
function SettingsLabel({ children }) {
|
|
849
|
+
return /* @__PURE__ */ jsx3(
|
|
850
|
+
"div",
|
|
851
|
+
{
|
|
852
|
+
style: {
|
|
853
|
+
fontSize: 11,
|
|
854
|
+
color: "rgba(255, 255, 255, 0.42)",
|
|
855
|
+
letterSpacing: "0.02em"
|
|
856
|
+
},
|
|
857
|
+
children
|
|
858
|
+
}
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
function SegmentButton({
|
|
862
|
+
children,
|
|
863
|
+
active,
|
|
864
|
+
onClick,
|
|
865
|
+
style
|
|
866
|
+
}) {
|
|
867
|
+
return /* @__PURE__ */ jsx3(
|
|
868
|
+
"button",
|
|
869
|
+
{
|
|
870
|
+
onClick,
|
|
871
|
+
style: {
|
|
872
|
+
display: "flex",
|
|
873
|
+
alignItems: "center",
|
|
874
|
+
gap: 4,
|
|
875
|
+
height: 26,
|
|
876
|
+
padding: "0 10px",
|
|
877
|
+
border: "1px solid rgba(255,255,255,0.1)",
|
|
878
|
+
background: active ? "rgba(255,255,255,0.14)" : "rgba(255,255,255,0.04)",
|
|
879
|
+
color: active ? "rgba(255,255,255,0.92)" : "rgba(255,255,255,0.5)",
|
|
880
|
+
cursor: "pointer",
|
|
881
|
+
fontSize: 11,
|
|
882
|
+
fontFamily: "inherit",
|
|
883
|
+
transition: "background 0.12s ease, color 0.12s ease",
|
|
884
|
+
...style
|
|
885
|
+
},
|
|
886
|
+
children
|
|
887
|
+
}
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
function ColorSwatch({
|
|
891
|
+
color,
|
|
892
|
+
onChange
|
|
1196
893
|
}) {
|
|
1197
|
-
const
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
useEffect4(() => {
|
|
1201
|
-
if (!open) return;
|
|
1202
|
-
fetch("/__afterbefore/config").then((r) => r.json()).then((data) => setSaveDir(data.saveDir)).catch(() => {
|
|
1203
|
-
});
|
|
1204
|
-
}, [open]);
|
|
1205
|
-
const handlePickFolder = async () => {
|
|
1206
|
-
setPicking(true);
|
|
1207
|
-
try {
|
|
1208
|
-
const res = await fetch("/__afterbefore/pick-folder", { method: "POST" });
|
|
1209
|
-
const data = await res.json();
|
|
1210
|
-
if (data.folder) {
|
|
1211
|
-
await fetch("/__afterbefore/config", {
|
|
1212
|
-
method: "POST",
|
|
1213
|
-
headers: { "Content-Type": "application/json" },
|
|
1214
|
-
body: JSON.stringify({ saveDir: data.folder })
|
|
1215
|
-
});
|
|
1216
|
-
setSaveDir(data.folder);
|
|
1217
|
-
}
|
|
1218
|
-
} catch {
|
|
1219
|
-
} finally {
|
|
1220
|
-
setPicking(false);
|
|
1221
|
-
}
|
|
1222
|
-
};
|
|
1223
|
-
const shortDir = saveDir ? saveDir.replace(/^\/Users\/[^/]+/, "~") : "~/Desktop";
|
|
1224
|
-
return /* @__PURE__ */ jsxs3("div", { style: { position: "relative", marginRight: 6 }, children: [
|
|
1225
|
-
/* @__PURE__ */ jsx4(
|
|
894
|
+
const inputRef = useRef2(null);
|
|
895
|
+
return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
896
|
+
/* @__PURE__ */ jsx3(
|
|
1226
897
|
"button",
|
|
1227
898
|
{
|
|
1228
|
-
onClick,
|
|
1229
|
-
onMouseEnter: () => setHovered(true),
|
|
1230
|
-
onMouseLeave: () => setHovered(false),
|
|
899
|
+
onClick: () => inputRef.current?.click(),
|
|
1231
900
|
style: {
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
901
|
+
width: 24,
|
|
902
|
+
height: 24,
|
|
903
|
+
borderRadius: 6,
|
|
904
|
+
border: "1px solid rgba(255,255,255,0.18)",
|
|
905
|
+
background: color,
|
|
906
|
+
cursor: "pointer",
|
|
907
|
+
padding: 0
|
|
908
|
+
}
|
|
1236
909
|
}
|
|
1237
910
|
),
|
|
1238
|
-
|
|
1239
|
-
"
|
|
911
|
+
/* @__PURE__ */ jsx3(
|
|
912
|
+
"input",
|
|
1240
913
|
{
|
|
914
|
+
ref: inputRef,
|
|
915
|
+
type: "color",
|
|
916
|
+
value: color,
|
|
917
|
+
onChange: (e) => onChange(e.target.value),
|
|
1241
918
|
style: {
|
|
1242
919
|
position: "absolute",
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1251
|
-
boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
|
|
1252
|
-
backdropFilter: "blur(20px)",
|
|
1253
|
-
WebkitBackdropFilter: "blur(20px)"
|
|
1254
|
-
},
|
|
1255
|
-
children: [
|
|
1256
|
-
/* @__PURE__ */ jsx4(
|
|
1257
|
-
"div",
|
|
1258
|
-
{
|
|
1259
|
-
style: {
|
|
1260
|
-
fontSize: 11,
|
|
1261
|
-
color: "rgba(255, 255, 255, 0.46)",
|
|
1262
|
-
letterSpacing: "0.03em",
|
|
1263
|
-
textTransform: "uppercase",
|
|
1264
|
-
marginBottom: 10
|
|
1265
|
-
},
|
|
1266
|
-
children: "Settings"
|
|
1267
|
-
}
|
|
1268
|
-
),
|
|
1269
|
-
selectedMode === "area" && /* @__PURE__ */ jsx4(
|
|
1270
|
-
ToggleRow,
|
|
1271
|
-
{
|
|
1272
|
-
icon: /* @__PURE__ */ jsx4(Magnet, { size: 15, strokeWidth: 1.8 }),
|
|
1273
|
-
label: "Magnet snap",
|
|
1274
|
-
enabled: magnetEnabled,
|
|
1275
|
-
onChange: () => onMagnetChange(!magnetEnabled)
|
|
1276
|
-
}
|
|
1277
|
-
),
|
|
1278
|
-
selectedMode === "component" && /* @__PURE__ */ jsx4(
|
|
1279
|
-
ToggleRow,
|
|
1280
|
-
{
|
|
1281
|
-
icon: /* @__PURE__ */ jsx4(Frame, { size: 15, strokeWidth: 1.8 }),
|
|
1282
|
-
label: "1920 x 1080 frame",
|
|
1283
|
-
enabled: frameOnBlackEnabled,
|
|
1284
|
-
onChange: () => onFrameOnBlackChange(!frameOnBlackEnabled)
|
|
1285
|
-
}
|
|
1286
|
-
),
|
|
1287
|
-
(selectedMode === "area" || selectedMode === "component") && /* @__PURE__ */ jsx4("div", { style: { height: 1, background: "rgba(255,255,255,0.08)", margin: "8px 0" } }),
|
|
1288
|
-
/* @__PURE__ */ jsx4(
|
|
1289
|
-
SaveLocationRow,
|
|
1290
|
-
{
|
|
1291
|
-
dir: shortDir,
|
|
1292
|
-
picking,
|
|
1293
|
-
onPick: handlePickFolder
|
|
1294
|
-
}
|
|
1295
|
-
)
|
|
1296
|
-
]
|
|
920
|
+
top: 0,
|
|
921
|
+
left: 0,
|
|
922
|
+
width: 0,
|
|
923
|
+
height: 0,
|
|
924
|
+
opacity: 0,
|
|
925
|
+
pointerEvents: "none"
|
|
926
|
+
}
|
|
1297
927
|
}
|
|
1298
928
|
)
|
|
1299
929
|
] });
|
|
1300
930
|
}
|
|
931
|
+
function SmallButton({
|
|
932
|
+
children,
|
|
933
|
+
onClick
|
|
934
|
+
}) {
|
|
935
|
+
const [hovered, setHovered] = useState3(false);
|
|
936
|
+
return /* @__PURE__ */ jsx3(
|
|
937
|
+
"button",
|
|
938
|
+
{
|
|
939
|
+
onClick,
|
|
940
|
+
onMouseEnter: () => setHovered(true),
|
|
941
|
+
onMouseLeave: () => setHovered(false),
|
|
942
|
+
style: {
|
|
943
|
+
display: "flex",
|
|
944
|
+
alignItems: "center",
|
|
945
|
+
gap: 4,
|
|
946
|
+
padding: "3px 8px",
|
|
947
|
+
borderRadius: 6,
|
|
948
|
+
border: "1px solid rgba(255,255,255,0.12)",
|
|
949
|
+
background: hovered ? "rgba(255,255,255,0.12)" : "rgba(255,255,255,0.06)",
|
|
950
|
+
color: "rgba(255,255,255,0.78)",
|
|
951
|
+
fontSize: 11,
|
|
952
|
+
cursor: "pointer",
|
|
953
|
+
fontFamily: "inherit",
|
|
954
|
+
transition: "background 0.12s ease"
|
|
955
|
+
},
|
|
956
|
+
children
|
|
957
|
+
}
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
async function downscaleImage(dataUrl, maxW, maxH) {
|
|
961
|
+
return new Promise((resolve) => {
|
|
962
|
+
const img = new Image();
|
|
963
|
+
img.onload = () => {
|
|
964
|
+
const canvas = document.createElement("canvas");
|
|
965
|
+
const scale = Math.min(maxW / img.width, maxH / img.height, 1);
|
|
966
|
+
canvas.width = img.width * scale;
|
|
967
|
+
canvas.height = img.height * scale;
|
|
968
|
+
const ctx = canvas.getContext("2d");
|
|
969
|
+
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
970
|
+
resolve(canvas.toDataURL("image/jpeg", 0.85));
|
|
971
|
+
};
|
|
972
|
+
img.onerror = () => resolve(dataUrl);
|
|
973
|
+
img.src = dataUrl;
|
|
974
|
+
});
|
|
975
|
+
}
|
|
1301
976
|
function SaveLocationRow({
|
|
1302
977
|
dir,
|
|
1303
978
|
picking,
|
|
1304
979
|
onPick
|
|
1305
980
|
}) {
|
|
1306
|
-
const [btnHovered, setBtnHovered] =
|
|
1307
|
-
return /* @__PURE__ */
|
|
981
|
+
const [btnHovered, setBtnHovered] = useState3(false);
|
|
982
|
+
return /* @__PURE__ */ jsx3("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: /* @__PURE__ */ jsxs2(
|
|
1308
983
|
"div",
|
|
1309
984
|
{
|
|
1310
985
|
style: {
|
|
@@ -1315,8 +990,8 @@ function SaveLocationRow({
|
|
|
1315
990
|
fontSize: 13
|
|
1316
991
|
},
|
|
1317
992
|
children: [
|
|
1318
|
-
/* @__PURE__ */
|
|
1319
|
-
/* @__PURE__ */
|
|
993
|
+
/* @__PURE__ */ jsx3(FolderOpen, { size: 15, strokeWidth: 1.8, style: { flexShrink: 0 } }),
|
|
994
|
+
/* @__PURE__ */ jsx3(
|
|
1320
995
|
"span",
|
|
1321
996
|
{
|
|
1322
997
|
style: {
|
|
@@ -1330,7 +1005,7 @@ function SaveLocationRow({
|
|
|
1330
1005
|
children: dir
|
|
1331
1006
|
}
|
|
1332
1007
|
),
|
|
1333
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsx3(
|
|
1334
1009
|
"button",
|
|
1335
1010
|
{
|
|
1336
1011
|
onClick: onPick,
|
|
@@ -1362,7 +1037,7 @@ function ToggleRow({
|
|
|
1362
1037
|
enabled,
|
|
1363
1038
|
onChange
|
|
1364
1039
|
}) {
|
|
1365
|
-
return /* @__PURE__ */
|
|
1040
|
+
return /* @__PURE__ */ jsxs2(
|
|
1366
1041
|
"label",
|
|
1367
1042
|
{
|
|
1368
1043
|
style: {
|
|
@@ -1373,7 +1048,7 @@ function ToggleRow({
|
|
|
1373
1048
|
cursor: "pointer"
|
|
1374
1049
|
},
|
|
1375
1050
|
children: [
|
|
1376
|
-
/* @__PURE__ */
|
|
1051
|
+
/* @__PURE__ */ jsxs2(
|
|
1377
1052
|
"span",
|
|
1378
1053
|
{
|
|
1379
1054
|
style: {
|
|
@@ -1390,7 +1065,7 @@ function ToggleRow({
|
|
|
1390
1065
|
]
|
|
1391
1066
|
}
|
|
1392
1067
|
),
|
|
1393
|
-
/* @__PURE__ */
|
|
1068
|
+
/* @__PURE__ */ jsx3(
|
|
1394
1069
|
"button",
|
|
1395
1070
|
{
|
|
1396
1071
|
type: "button",
|
|
@@ -1407,7 +1082,7 @@ function ToggleRow({
|
|
|
1407
1082
|
flexShrink: 0,
|
|
1408
1083
|
transition: "background 0.12s ease"
|
|
1409
1084
|
},
|
|
1410
|
-
children: /* @__PURE__ */
|
|
1085
|
+
children: /* @__PURE__ */ jsx3(
|
|
1411
1086
|
"span",
|
|
1412
1087
|
{
|
|
1413
1088
|
style: {
|
|
@@ -1428,49 +1103,18 @@ function ToggleRow({
|
|
|
1428
1103
|
}
|
|
1429
1104
|
);
|
|
1430
1105
|
}
|
|
1431
|
-
function ControlGroup({
|
|
1432
|
-
label,
|
|
1433
|
-
children
|
|
1434
|
-
}) {
|
|
1435
|
-
return /* @__PURE__ */ jsxs3(
|
|
1436
|
-
"div",
|
|
1437
|
-
{
|
|
1438
|
-
style: {
|
|
1439
|
-
display: "flex",
|
|
1440
|
-
alignItems: "center",
|
|
1441
|
-
gap: 6,
|
|
1442
|
-
padding: "0 4px"
|
|
1443
|
-
},
|
|
1444
|
-
children: [
|
|
1445
|
-
/* @__PURE__ */ jsx4(
|
|
1446
|
-
"span",
|
|
1447
|
-
{
|
|
1448
|
-
style: {
|
|
1449
|
-
fontSize: 11,
|
|
1450
|
-
color: "rgba(255, 255, 255, 0.42)",
|
|
1451
|
-
textTransform: "uppercase",
|
|
1452
|
-
letterSpacing: "0.03em"
|
|
1453
|
-
},
|
|
1454
|
-
children: label
|
|
1455
|
-
}
|
|
1456
|
-
),
|
|
1457
|
-
children
|
|
1458
|
-
]
|
|
1459
|
-
}
|
|
1460
|
-
);
|
|
1461
|
-
}
|
|
1462
1106
|
function NumInput({
|
|
1463
1107
|
value,
|
|
1464
1108
|
onChange
|
|
1465
1109
|
}) {
|
|
1466
|
-
const [editing, setEditing] =
|
|
1467
|
-
const [text, setText] =
|
|
1468
|
-
|
|
1110
|
+
const [editing, setEditing] = useState3(false);
|
|
1111
|
+
const [text, setText] = useState3(String(value));
|
|
1112
|
+
useEffect2(() => {
|
|
1469
1113
|
if (!editing) {
|
|
1470
1114
|
setText(String(value));
|
|
1471
1115
|
}
|
|
1472
1116
|
}, [editing, value]);
|
|
1473
|
-
return /* @__PURE__ */
|
|
1117
|
+
return /* @__PURE__ */ jsx3(
|
|
1474
1118
|
"input",
|
|
1475
1119
|
{
|
|
1476
1120
|
type: "text",
|
|
@@ -1505,7 +1149,7 @@ function NumInput({
|
|
|
1505
1149
|
);
|
|
1506
1150
|
}
|
|
1507
1151
|
function StaticText({ children }) {
|
|
1508
|
-
return /* @__PURE__ */
|
|
1152
|
+
return /* @__PURE__ */ jsx3(
|
|
1509
1153
|
"span",
|
|
1510
1154
|
{
|
|
1511
1155
|
style: {
|
|
@@ -1518,62 +1162,13 @@ function StaticText({ children }) {
|
|
|
1518
1162
|
}
|
|
1519
1163
|
);
|
|
1520
1164
|
}
|
|
1521
|
-
function DropButton({
|
|
1522
|
-
children,
|
|
1523
|
-
onClick,
|
|
1524
|
-
active
|
|
1525
|
-
}) {
|
|
1526
|
-
return /* @__PURE__ */ jsx4(
|
|
1527
|
-
"button",
|
|
1528
|
-
{
|
|
1529
|
-
onClick,
|
|
1530
|
-
style: {
|
|
1531
|
-
display: "flex",
|
|
1532
|
-
alignItems: "center",
|
|
1533
|
-
gap: 6,
|
|
1534
|
-
height: 34,
|
|
1535
|
-
padding: "0 10px",
|
|
1536
|
-
borderRadius: 10,
|
|
1537
|
-
border: "1px solid rgba(255,255,255,0.08)",
|
|
1538
|
-
background: "rgba(255,255,255,0.04)",
|
|
1539
|
-
color: active ? "rgba(125, 211, 252, 0.96)" : "rgba(255,255,255,0.78)",
|
|
1540
|
-
cursor: "pointer",
|
|
1541
|
-
fontSize: 12,
|
|
1542
|
-
fontFamily: "inherit"
|
|
1543
|
-
},
|
|
1544
|
-
children
|
|
1545
|
-
}
|
|
1546
|
-
);
|
|
1547
|
-
}
|
|
1548
|
-
function DropMenu({ children }) {
|
|
1549
|
-
return /* @__PURE__ */ jsx4(
|
|
1550
|
-
"div",
|
|
1551
|
-
{
|
|
1552
|
-
style: {
|
|
1553
|
-
position: "absolute",
|
|
1554
|
-
bottom: "calc(100% + 8px)",
|
|
1555
|
-
left: "50%",
|
|
1556
|
-
transform: "translateX(-50%)",
|
|
1557
|
-
minWidth: 120,
|
|
1558
|
-
background: "rgba(32, 32, 36, 0.96)",
|
|
1559
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1560
|
-
borderRadius: 10,
|
|
1561
|
-
padding: "4px 0",
|
|
1562
|
-
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
|
|
1563
|
-
backdropFilter: "blur(20px)",
|
|
1564
|
-
WebkitBackdropFilter: "blur(20px)"
|
|
1565
|
-
},
|
|
1566
|
-
children
|
|
1567
|
-
}
|
|
1568
|
-
);
|
|
1569
|
-
}
|
|
1570
1165
|
function DropItem({
|
|
1571
1166
|
children,
|
|
1572
1167
|
onClick,
|
|
1573
1168
|
active,
|
|
1574
1169
|
accent
|
|
1575
1170
|
}) {
|
|
1576
|
-
return /* @__PURE__ */
|
|
1171
|
+
return /* @__PURE__ */ jsx3(
|
|
1577
1172
|
"button",
|
|
1578
1173
|
{
|
|
1579
1174
|
onClick,
|
|
@@ -1593,56 +1188,29 @@ function DropItem({
|
|
|
1593
1188
|
}
|
|
1594
1189
|
);
|
|
1595
1190
|
}
|
|
1596
|
-
function MenuDivider() {
|
|
1597
|
-
return /* @__PURE__ */ jsx4(
|
|
1598
|
-
"div",
|
|
1599
|
-
{
|
|
1600
|
-
style: {
|
|
1601
|
-
height: 1,
|
|
1602
|
-
background: "rgba(255,255,255,0.08)",
|
|
1603
|
-
margin: "4px 0"
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
);
|
|
1607
|
-
}
|
|
1608
1191
|
function Separator({ vertical = true }) {
|
|
1609
|
-
return /* @__PURE__ */
|
|
1192
|
+
return /* @__PURE__ */ jsx3(
|
|
1610
1193
|
"div",
|
|
1611
1194
|
{
|
|
1612
1195
|
style: {
|
|
1613
1196
|
width: vertical ? 1 : 24,
|
|
1614
|
-
height: vertical ?
|
|
1197
|
+
height: vertical ? 18 : 1,
|
|
1615
1198
|
background: "rgba(255,255,255,0.12)",
|
|
1616
|
-
flexShrink: 0
|
|
1199
|
+
flexShrink: 0,
|
|
1200
|
+
margin: vertical ? "0 6px" : "6px 0"
|
|
1617
1201
|
}
|
|
1618
1202
|
}
|
|
1619
1203
|
);
|
|
1620
1204
|
}
|
|
1621
|
-
function circleButtonStyle(active, round) {
|
|
1622
|
-
return {
|
|
1623
|
-
width: 40,
|
|
1624
|
-
height: 40,
|
|
1625
|
-
borderRadius: round ? "50%" : 12,
|
|
1626
|
-
border: "none",
|
|
1627
|
-
background: active ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
1628
|
-
display: "flex",
|
|
1629
|
-
alignItems: "center",
|
|
1630
|
-
justifyContent: "center",
|
|
1631
|
-
cursor: "pointer",
|
|
1632
|
-
padding: 0,
|
|
1633
|
-
transition: "background 0.12s ease, color 0.12s ease",
|
|
1634
|
-
marginRight: round ? 6 : 0
|
|
1635
|
-
};
|
|
1636
|
-
}
|
|
1637
1205
|
|
|
1638
1206
|
// src/overlay/ui/inspector.tsx
|
|
1639
|
-
import { useEffect as
|
|
1640
|
-
import { Fragment as
|
|
1207
|
+
import { useEffect as useEffect3, useRef as useRef3, useCallback as useCallback3, useState as useState4 } from "react";
|
|
1208
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1641
1209
|
function Inspector({ onSelect, onCancel }) {
|
|
1642
|
-
const [highlight, setHighlight] =
|
|
1210
|
+
const [highlight, setHighlight] = useState4(null);
|
|
1643
1211
|
const hoveredEl = useRef3(null);
|
|
1644
1212
|
const styleEl = useRef3(null);
|
|
1645
|
-
|
|
1213
|
+
useEffect3(() => {
|
|
1646
1214
|
const style = document.createElement("style");
|
|
1647
1215
|
style.setAttribute("data-afterbefore", "true");
|
|
1648
1216
|
style.textContent = "*, *::before, *::after { cursor: crosshair !important; }";
|
|
@@ -1652,7 +1220,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1652
1220
|
style.remove();
|
|
1653
1221
|
};
|
|
1654
1222
|
}, []);
|
|
1655
|
-
const isOverlayElement =
|
|
1223
|
+
const isOverlayElement = useCallback3((el) => {
|
|
1656
1224
|
let node = el;
|
|
1657
1225
|
while (node) {
|
|
1658
1226
|
if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
|
|
@@ -1660,7 +1228,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1660
1228
|
}
|
|
1661
1229
|
return false;
|
|
1662
1230
|
}, []);
|
|
1663
|
-
const handleMouseMove =
|
|
1231
|
+
const handleMouseMove = useCallback3(
|
|
1664
1232
|
(e) => {
|
|
1665
1233
|
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
1666
1234
|
if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {
|
|
@@ -1680,8 +1248,9 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1680
1248
|
},
|
|
1681
1249
|
[isOverlayElement]
|
|
1682
1250
|
);
|
|
1683
|
-
const handleClick =
|
|
1251
|
+
const handleClick = useCallback3(
|
|
1684
1252
|
(e) => {
|
|
1253
|
+
if (isOverlayElement(e.target)) return;
|
|
1685
1254
|
e.preventDefault();
|
|
1686
1255
|
e.stopPropagation();
|
|
1687
1256
|
e.stopImmediatePropagation();
|
|
@@ -1689,9 +1258,9 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1689
1258
|
onSelect(hoveredEl.current);
|
|
1690
1259
|
}
|
|
1691
1260
|
},
|
|
1692
|
-
[onSelect]
|
|
1261
|
+
[onSelect, isOverlayElement]
|
|
1693
1262
|
);
|
|
1694
|
-
const handleKeyDown =
|
|
1263
|
+
const handleKeyDown = useCallback3(
|
|
1695
1264
|
(e) => {
|
|
1696
1265
|
if (e.key === "Escape") {
|
|
1697
1266
|
onCancel();
|
|
@@ -1699,7 +1268,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1699
1268
|
},
|
|
1700
1269
|
[onCancel]
|
|
1701
1270
|
);
|
|
1702
|
-
|
|
1271
|
+
useEffect3(() => {
|
|
1703
1272
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
1704
1273
|
document.addEventListener("click", handleClick, true);
|
|
1705
1274
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -1709,81 +1278,59 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1709
1278
|
document.removeEventListener("keydown", handleKeyDown);
|
|
1710
1279
|
};
|
|
1711
1280
|
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
1712
|
-
return /* @__PURE__ */
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
{
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
pointerEvents: "none"
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
),
|
|
1730
|
-
/* @__PURE__ */ jsx5(
|
|
1731
|
-
"div",
|
|
1732
|
-
{
|
|
1733
|
-
style: {
|
|
1734
|
-
position: "fixed",
|
|
1735
|
-
left: highlight.x,
|
|
1736
|
-
top: Math.max(0, highlight.y - 24),
|
|
1737
|
-
background: "rgba(59, 130, 246, 0.9)",
|
|
1738
|
-
color: "#fff",
|
|
1739
|
-
fontSize: 11,
|
|
1740
|
-
fontFamily: "system-ui, -apple-system, monospace",
|
|
1741
|
-
padding: "2px 6px",
|
|
1742
|
-
borderRadius: 3,
|
|
1743
|
-
pointerEvents: "none",
|
|
1744
|
-
whiteSpace: "nowrap",
|
|
1745
|
-
lineHeight: "18px"
|
|
1746
|
-
},
|
|
1747
|
-
children: highlight.tag
|
|
1281
|
+
return /* @__PURE__ */ jsx4("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: highlight && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1282
|
+
/* @__PURE__ */ jsx4(
|
|
1283
|
+
"div",
|
|
1284
|
+
{
|
|
1285
|
+
style: {
|
|
1286
|
+
position: "fixed",
|
|
1287
|
+
left: highlight.x,
|
|
1288
|
+
top: highlight.y,
|
|
1289
|
+
width: highlight.width,
|
|
1290
|
+
height: highlight.height,
|
|
1291
|
+
background: "rgba(59, 130, 246, 0.15)",
|
|
1292
|
+
border: "2px solid rgba(59, 130, 246, 0.7)",
|
|
1293
|
+
borderRadius: 2,
|
|
1294
|
+
pointerEvents: "none"
|
|
1748
1295
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1296
|
+
}
|
|
1297
|
+
),
|
|
1298
|
+
/* @__PURE__ */ jsx4(
|
|
1752
1299
|
"div",
|
|
1753
1300
|
{
|
|
1754
1301
|
style: {
|
|
1755
1302
|
position: "fixed",
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
color: "
|
|
1760
|
-
fontSize:
|
|
1761
|
-
fontFamily: "system-ui, -apple-system,
|
|
1303
|
+
left: highlight.x,
|
|
1304
|
+
top: Math.max(0, highlight.y - 24),
|
|
1305
|
+
background: "rgba(59, 130, 246, 0.9)",
|
|
1306
|
+
color: "#fff",
|
|
1307
|
+
fontSize: 11,
|
|
1308
|
+
fontFamily: "system-ui, -apple-system, monospace",
|
|
1309
|
+
padding: "2px 6px",
|
|
1310
|
+
borderRadius: 3,
|
|
1762
1311
|
pointerEvents: "none",
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
padding: "8px 16px",
|
|
1766
|
-
borderRadius: 8
|
|
1312
|
+
whiteSpace: "nowrap",
|
|
1313
|
+
lineHeight: "18px"
|
|
1767
1314
|
},
|
|
1768
|
-
children:
|
|
1315
|
+
children: highlight.tag
|
|
1769
1316
|
}
|
|
1770
1317
|
)
|
|
1771
|
-
] });
|
|
1318
|
+
] }) });
|
|
1772
1319
|
}
|
|
1773
1320
|
|
|
1774
1321
|
// src/overlay/ui/status.tsx
|
|
1775
|
-
import { useState as
|
|
1776
|
-
import { jsx as
|
|
1322
|
+
import { useState as useState5, useRef as useRef4, useEffect as useEffect4, useCallback as useCallback4 } from "react";
|
|
1323
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1777
1324
|
var PANEL_WIDTH = 220;
|
|
1778
1325
|
function Status({ onReset, position, onClose }) {
|
|
1779
1326
|
const panelRef = useRef4(null);
|
|
1780
|
-
const [toast, setToast] =
|
|
1781
|
-
const [pushing, setPushing] =
|
|
1782
|
-
const showToast =
|
|
1327
|
+
const [toast, setToast] = useState5(null);
|
|
1328
|
+
const [pushing, setPushing] = useState5(false);
|
|
1329
|
+
const showToast = useCallback4((message, type) => {
|
|
1783
1330
|
setToast({ message, type });
|
|
1784
1331
|
setTimeout(() => setToast(null), 3e3);
|
|
1785
1332
|
}, []);
|
|
1786
|
-
|
|
1333
|
+
useEffect4(() => {
|
|
1787
1334
|
const handler = (e) => {
|
|
1788
1335
|
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
1789
1336
|
onClose();
|
|
@@ -1792,7 +1339,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1792
1339
|
document.addEventListener("mousedown", handler);
|
|
1793
1340
|
return () => document.removeEventListener("mousedown", handler);
|
|
1794
1341
|
}, [onClose]);
|
|
1795
|
-
|
|
1342
|
+
useEffect4(() => {
|
|
1796
1343
|
const handler = (e) => {
|
|
1797
1344
|
if (e.key === "Escape") onClose();
|
|
1798
1345
|
};
|
|
@@ -1868,7 +1415,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1868
1415
|
const onLeave = (e) => {
|
|
1869
1416
|
e.currentTarget.style.background = "transparent";
|
|
1870
1417
|
};
|
|
1871
|
-
return /* @__PURE__ */
|
|
1418
|
+
return /* @__PURE__ */ jsxs4(
|
|
1872
1419
|
"div",
|
|
1873
1420
|
{
|
|
1874
1421
|
ref: panelRef,
|
|
@@ -1887,7 +1434,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1887
1434
|
overflow: "hidden"
|
|
1888
1435
|
},
|
|
1889
1436
|
children: [
|
|
1890
|
-
/* @__PURE__ */
|
|
1437
|
+
/* @__PURE__ */ jsx5(
|
|
1891
1438
|
"div",
|
|
1892
1439
|
{
|
|
1893
1440
|
style: {
|
|
@@ -1897,11 +1444,11 @@ function Status({ onReset, position, onClose }) {
|
|
|
1897
1444
|
color: "rgba(255,255,255,0.5)",
|
|
1898
1445
|
letterSpacing: "0.02em"
|
|
1899
1446
|
},
|
|
1900
|
-
children: "
|
|
1447
|
+
children: "Screenshot captured"
|
|
1901
1448
|
}
|
|
1902
1449
|
),
|
|
1903
|
-
/* @__PURE__ */
|
|
1904
|
-
/* @__PURE__ */
|
|
1450
|
+
/* @__PURE__ */ jsxs4("div", { style: { padding: "0 4px 4px" }, children: [
|
|
1451
|
+
/* @__PURE__ */ jsxs4(
|
|
1905
1452
|
"button",
|
|
1906
1453
|
{
|
|
1907
1454
|
style: buttonStyle,
|
|
@@ -1909,12 +1456,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1909
1456
|
onMouseEnter: onEnter,
|
|
1910
1457
|
onMouseLeave: onLeave,
|
|
1911
1458
|
children: [
|
|
1912
|
-
/* @__PURE__ */
|
|
1459
|
+
/* @__PURE__ */ jsx5(FolderIcon, {}),
|
|
1913
1460
|
"Open Folder"
|
|
1914
1461
|
]
|
|
1915
1462
|
}
|
|
1916
1463
|
),
|
|
1917
|
-
/* @__PURE__ */
|
|
1464
|
+
/* @__PURE__ */ jsxs4(
|
|
1918
1465
|
"button",
|
|
1919
1466
|
{
|
|
1920
1467
|
style: buttonStyle,
|
|
@@ -1922,12 +1469,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1922
1469
|
onMouseEnter: onEnter,
|
|
1923
1470
|
onMouseLeave: onLeave,
|
|
1924
1471
|
children: [
|
|
1925
|
-
/* @__PURE__ */
|
|
1472
|
+
/* @__PURE__ */ jsx5(CopyIcon, {}),
|
|
1926
1473
|
"Copy Markdown"
|
|
1927
1474
|
]
|
|
1928
1475
|
}
|
|
1929
1476
|
),
|
|
1930
|
-
/* @__PURE__ */
|
|
1477
|
+
/* @__PURE__ */ jsxs4(
|
|
1931
1478
|
"button",
|
|
1932
1479
|
{
|
|
1933
1480
|
style: buttonStyle,
|
|
@@ -1936,12 +1483,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1936
1483
|
onMouseEnter: onEnter,
|
|
1937
1484
|
onMouseLeave: onLeave,
|
|
1938
1485
|
children: [
|
|
1939
|
-
/* @__PURE__ */
|
|
1486
|
+
/* @__PURE__ */ jsx5(PushIcon, {}),
|
|
1940
1487
|
pushing ? "Pushing..." : "Push to PR"
|
|
1941
1488
|
]
|
|
1942
1489
|
}
|
|
1943
1490
|
),
|
|
1944
|
-
/* @__PURE__ */
|
|
1491
|
+
/* @__PURE__ */ jsx5(
|
|
1945
1492
|
"div",
|
|
1946
1493
|
{
|
|
1947
1494
|
style: {
|
|
@@ -1951,7 +1498,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1951
1498
|
}
|
|
1952
1499
|
}
|
|
1953
1500
|
),
|
|
1954
|
-
/* @__PURE__ */
|
|
1501
|
+
/* @__PURE__ */ jsxs4(
|
|
1955
1502
|
"button",
|
|
1956
1503
|
{
|
|
1957
1504
|
style: { ...buttonStyle, color: "rgba(255,255,255,0.5)" },
|
|
@@ -1959,13 +1506,13 @@ function Status({ onReset, position, onClose }) {
|
|
|
1959
1506
|
onMouseEnter: onEnter,
|
|
1960
1507
|
onMouseLeave: onLeave,
|
|
1961
1508
|
children: [
|
|
1962
|
-
/* @__PURE__ */
|
|
1509
|
+
/* @__PURE__ */ jsx5(ResetIcon, {}),
|
|
1963
1510
|
"Reset"
|
|
1964
1511
|
]
|
|
1965
1512
|
}
|
|
1966
1513
|
)
|
|
1967
1514
|
] }),
|
|
1968
|
-
toast && /* @__PURE__ */
|
|
1515
|
+
toast && /* @__PURE__ */ jsx5(
|
|
1969
1516
|
"div",
|
|
1970
1517
|
{
|
|
1971
1518
|
style: {
|
|
@@ -1991,14 +1538,14 @@ function Status({ onReset, position, onClose }) {
|
|
|
1991
1538
|
);
|
|
1992
1539
|
}
|
|
1993
1540
|
function FolderIcon() {
|
|
1994
|
-
return /* @__PURE__ */
|
|
1541
|
+
return /* @__PURE__ */ jsx5(
|
|
1995
1542
|
"svg",
|
|
1996
1543
|
{
|
|
1997
1544
|
width: "14",
|
|
1998
1545
|
height: "14",
|
|
1999
1546
|
viewBox: "0 0 14 14",
|
|
2000
1547
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
2001
|
-
children: /* @__PURE__ */
|
|
1548
|
+
children: /* @__PURE__ */ jsx5(
|
|
2002
1549
|
"path",
|
|
2003
1550
|
{
|
|
2004
1551
|
d: "M1.5 3A1.5 1.5 0 013 1.5h2.38a1 1 0 01.72.3L7 2.72a1 1 0 00.72.3H11A1.5 1.5 0 0112.5 4.5v6A1.5 1.5 0 0111 12H3A1.5 1.5 0 011.5 10.5V3z",
|
|
@@ -2011,7 +1558,7 @@ function FolderIcon() {
|
|
|
2011
1558
|
);
|
|
2012
1559
|
}
|
|
2013
1560
|
function CopyIcon() {
|
|
2014
|
-
return /* @__PURE__ */
|
|
1561
|
+
return /* @__PURE__ */ jsxs4(
|
|
2015
1562
|
"svg",
|
|
2016
1563
|
{
|
|
2017
1564
|
width: "14",
|
|
@@ -2019,7 +1566,7 @@ function CopyIcon() {
|
|
|
2019
1566
|
viewBox: "0 0 14 14",
|
|
2020
1567
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
2021
1568
|
children: [
|
|
2022
|
-
/* @__PURE__ */
|
|
1569
|
+
/* @__PURE__ */ jsx5(
|
|
2023
1570
|
"rect",
|
|
2024
1571
|
{
|
|
2025
1572
|
x: "4",
|
|
@@ -2032,7 +1579,7 @@ function CopyIcon() {
|
|
|
2032
1579
|
strokeWidth: "1.3"
|
|
2033
1580
|
}
|
|
2034
1581
|
),
|
|
2035
|
-
/* @__PURE__ */
|
|
1582
|
+
/* @__PURE__ */ jsx5(
|
|
2036
1583
|
"path",
|
|
2037
1584
|
{
|
|
2038
1585
|
d: "M10 4V2.5A1.5 1.5 0 008.5 1h-6A1.5 1.5 0 001 2.5v6A1.5 1.5 0 002.5 10H4",
|
|
@@ -2046,14 +1593,14 @@ function CopyIcon() {
|
|
|
2046
1593
|
);
|
|
2047
1594
|
}
|
|
2048
1595
|
function PushIcon() {
|
|
2049
|
-
return /* @__PURE__ */
|
|
1596
|
+
return /* @__PURE__ */ jsx5(
|
|
2050
1597
|
"svg",
|
|
2051
1598
|
{
|
|
2052
1599
|
width: "14",
|
|
2053
1600
|
height: "14",
|
|
2054
1601
|
viewBox: "0 0 14 14",
|
|
2055
1602
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
2056
|
-
children: /* @__PURE__ */
|
|
1603
|
+
children: /* @__PURE__ */ jsx5(
|
|
2057
1604
|
"path",
|
|
2058
1605
|
{
|
|
2059
1606
|
d: "M7 11V3m0 0L4 6m3-3l3 3",
|
|
@@ -2068,7 +1615,7 @@ function PushIcon() {
|
|
|
2068
1615
|
);
|
|
2069
1616
|
}
|
|
2070
1617
|
function ResetIcon() {
|
|
2071
|
-
return /* @__PURE__ */
|
|
1618
|
+
return /* @__PURE__ */ jsxs4(
|
|
2072
1619
|
"svg",
|
|
2073
1620
|
{
|
|
2074
1621
|
width: "14",
|
|
@@ -2076,7 +1623,7 @@ function ResetIcon() {
|
|
|
2076
1623
|
viewBox: "0 0 14 14",
|
|
2077
1624
|
style: { color: "rgba(255,255,255,0.4)" },
|
|
2078
1625
|
children: [
|
|
2079
|
-
/* @__PURE__ */
|
|
1626
|
+
/* @__PURE__ */ jsx5(
|
|
2080
1627
|
"path",
|
|
2081
1628
|
{
|
|
2082
1629
|
d: "M2.5 7a4.5 4.5 0 118 2.5",
|
|
@@ -2086,7 +1633,7 @@ function ResetIcon() {
|
|
|
2086
1633
|
strokeLinecap: "round"
|
|
2087
1634
|
}
|
|
2088
1635
|
),
|
|
2089
|
-
/* @__PURE__ */
|
|
1636
|
+
/* @__PURE__ */ jsx5(
|
|
2090
1637
|
"path",
|
|
2091
1638
|
{
|
|
2092
1639
|
d: "M2.5 3v4h4",
|
|
@@ -2103,55 +1650,47 @@ function ResetIcon() {
|
|
|
2103
1650
|
}
|
|
2104
1651
|
|
|
2105
1652
|
// src/overlay/index.tsx
|
|
2106
|
-
import { jsx as
|
|
2107
|
-
async function saveCapture(
|
|
1653
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1654
|
+
async function saveCapture(mode, dataUrl) {
|
|
2108
1655
|
try {
|
|
2109
1656
|
const res = await fetch("/__afterbefore/save", {
|
|
2110
1657
|
method: "POST",
|
|
2111
1658
|
headers: { "Content-Type": "application/json" },
|
|
2112
|
-
body: JSON.stringify({
|
|
1659
|
+
body: JSON.stringify({ mode, image: dataUrl })
|
|
2113
1660
|
});
|
|
2114
1661
|
if (!res.ok) throw new Error("Save failed");
|
|
2115
1662
|
} catch {
|
|
2116
1663
|
const link = document.createElement("a");
|
|
2117
|
-
link.download =
|
|
1664
|
+
link.download = "screenshot.png";
|
|
2118
1665
|
link.href = dataUrl;
|
|
2119
1666
|
link.click();
|
|
2120
1667
|
}
|
|
2121
1668
|
}
|
|
2122
1669
|
function AfterBefore() {
|
|
2123
1670
|
const { state, captureComplete, reset } = useOverlayState();
|
|
2124
|
-
const [statusOpen, setStatusOpen] =
|
|
2125
|
-
const [toolbarActive, setToolbarActive] =
|
|
2126
|
-
const [
|
|
2127
|
-
const [
|
|
2128
|
-
const [
|
|
2129
|
-
const [
|
|
2130
|
-
const [magnetEnabled, setMagnetEnabled] = useState8(true);
|
|
2131
|
-
const [areaRect, setAreaRect] = useState8(null);
|
|
2132
|
-
const [areaAspect, setAreaAspect] = useState8(DEFAULT_AREA_ASPECT);
|
|
2133
|
-
const [areaPresets, setAreaPresets] = useState8([]);
|
|
2134
|
-
const [frameOnBlackEnabled, setFrameOnBlackEnabled] = useState8(false);
|
|
1671
|
+
const [statusOpen, setStatusOpen] = useState6(false);
|
|
1672
|
+
const [toolbarActive, setToolbarActive] = useState6(false);
|
|
1673
|
+
const [inspectorActive, setInspectorActive] = useState6(false);
|
|
1674
|
+
const [loading, setLoading] = useState6(false);
|
|
1675
|
+
const [selectedMode, setSelectedMode] = useState6("component");
|
|
1676
|
+
const [frameSettings, setFrameSettings] = useState6(DEFAULT_FRAME_SETTINGS);
|
|
2135
1677
|
const iconPos = useRef5({ x: 24, y: 0 });
|
|
2136
|
-
|
|
2137
|
-
try {
|
|
2138
|
-
setMagnetEnabled(localStorage.getItem("ab-magnet") !== "false");
|
|
2139
|
-
} catch {
|
|
2140
|
-
setMagnetEnabled(true);
|
|
2141
|
-
}
|
|
2142
|
-
try {
|
|
2143
|
-
const savedPresets = localStorage.getItem("ab-area-presets");
|
|
2144
|
-
setAreaPresets(savedPresets ? JSON.parse(savedPresets) : []);
|
|
2145
|
-
} catch {
|
|
2146
|
-
setAreaPresets([]);
|
|
2147
|
-
}
|
|
1678
|
+
useEffect5(() => {
|
|
2148
1679
|
try {
|
|
2149
|
-
|
|
1680
|
+
const stored = localStorage.getItem("ab-frame-settings");
|
|
1681
|
+
if (stored) {
|
|
1682
|
+
setFrameSettings({ ...DEFAULT_FRAME_SETTINGS, ...JSON.parse(stored) });
|
|
1683
|
+
} else if (localStorage.getItem("ab-frame-black") === "true") {
|
|
1684
|
+
const migrated = { ...DEFAULT_FRAME_SETTINGS, enabled: true };
|
|
1685
|
+
setFrameSettings(migrated);
|
|
1686
|
+
localStorage.setItem("ab-frame-settings", JSON.stringify(migrated));
|
|
1687
|
+
localStorage.removeItem("ab-frame-black");
|
|
1688
|
+
}
|
|
2150
1689
|
} catch {
|
|
2151
|
-
|
|
1690
|
+
setFrameSettings(DEFAULT_FRAME_SETTINGS);
|
|
2152
1691
|
}
|
|
2153
1692
|
}, []);
|
|
2154
|
-
|
|
1693
|
+
useEffect5(() => {
|
|
2155
1694
|
if (state.phase === "ready") {
|
|
2156
1695
|
const timer = setTimeout(() => {
|
|
2157
1696
|
reset();
|
|
@@ -2160,43 +1699,37 @@ function AfterBefore() {
|
|
|
2160
1699
|
return () => clearTimeout(timer);
|
|
2161
1700
|
}
|
|
2162
1701
|
}, [state.phase, reset]);
|
|
2163
|
-
const handlePositionChange =
|
|
1702
|
+
const handlePositionChange = useCallback5(
|
|
2164
1703
|
(pos) => {
|
|
2165
1704
|
iconPos.current = pos;
|
|
2166
1705
|
},
|
|
2167
1706
|
[]
|
|
2168
1707
|
);
|
|
2169
|
-
const handleIconClick =
|
|
1708
|
+
const handleIconClick = useCallback5(() => {
|
|
2170
1709
|
if (loading) return;
|
|
2171
1710
|
if (state.phase === "ready") {
|
|
2172
1711
|
setStatusOpen((prev) => !prev);
|
|
2173
1712
|
} else if (toolbarActive || inspectorActive) {
|
|
2174
1713
|
setToolbarActive(false);
|
|
2175
|
-
setSelectorActive(false);
|
|
2176
1714
|
setInspectorActive(false);
|
|
2177
1715
|
setStatusOpen(false);
|
|
2178
1716
|
} else {
|
|
2179
1717
|
setStatusOpen(false);
|
|
2180
1718
|
if (selectedMode === "component") {
|
|
1719
|
+
setToolbarActive(true);
|
|
2181
1720
|
setInspectorActive(true);
|
|
2182
1721
|
} else {
|
|
2183
1722
|
setToolbarActive(true);
|
|
2184
1723
|
setInspectorActive(false);
|
|
2185
|
-
if (selectedMode === "area") {
|
|
2186
|
-
setSelectorActive(true);
|
|
2187
|
-
setAreaRect(createInitialAreaRect());
|
|
2188
|
-
setAreaAspect(DEFAULT_AREA_ASPECT);
|
|
2189
|
-
}
|
|
2190
1724
|
}
|
|
2191
1725
|
}
|
|
2192
1726
|
}, [state.phase, loading, toolbarActive, inspectorActive, selectedMode]);
|
|
2193
|
-
const performCapture =
|
|
2194
|
-
async (mode,
|
|
1727
|
+
const performCapture = useCallback5(
|
|
1728
|
+
async (mode, element) => {
|
|
2195
1729
|
setLoading(true);
|
|
2196
1730
|
try {
|
|
2197
|
-
const dataUrl = await capture({ mode,
|
|
2198
|
-
|
|
2199
|
-
await saveCapture(type, mode, dataUrl);
|
|
1731
|
+
const dataUrl = await capture({ mode, element, frameSettings });
|
|
1732
|
+
await saveCapture(mode, dataUrl);
|
|
2200
1733
|
captureComplete({
|
|
2201
1734
|
dataUrl,
|
|
2202
1735
|
mode,
|
|
@@ -2208,164 +1741,59 @@ function AfterBefore() {
|
|
|
2208
1741
|
setLoading(false);
|
|
2209
1742
|
}
|
|
2210
1743
|
},
|
|
2211
|
-
[
|
|
1744
|
+
[captureComplete, frameSettings]
|
|
2212
1745
|
);
|
|
2213
|
-
const handleToolbarCapture =
|
|
1746
|
+
const handleToolbarCapture = useCallback5(
|
|
2214
1747
|
(mode) => {
|
|
2215
|
-
if (mode === "
|
|
2216
|
-
if (areaRect) {
|
|
2217
|
-
setSelectorActive(false);
|
|
2218
|
-
setToolbarActive(false);
|
|
2219
|
-
performCapture("area", {
|
|
2220
|
-
x: Math.round(areaRect.x),
|
|
2221
|
-
y: Math.round(areaRect.y),
|
|
2222
|
-
width: Math.round(areaRect.w),
|
|
2223
|
-
height: Math.round(areaRect.h)
|
|
2224
|
-
});
|
|
2225
|
-
}
|
|
2226
|
-
return;
|
|
2227
|
-
} else if (mode === "viewport") {
|
|
1748
|
+
if (mode === "viewport") {
|
|
2228
1749
|
setToolbarActive(false);
|
|
2229
1750
|
performCapture("viewport");
|
|
2230
1751
|
} else if (mode === "fullpage") {
|
|
2231
1752
|
setToolbarActive(false);
|
|
2232
1753
|
performCapture("fullpage");
|
|
2233
1754
|
} else if (mode === "component") {
|
|
2234
|
-
setToolbarActive(false);
|
|
2235
1755
|
setInspectorActive(true);
|
|
2236
1756
|
}
|
|
2237
1757
|
},
|
|
2238
|
-
[
|
|
1758
|
+
[performCapture]
|
|
2239
1759
|
);
|
|
2240
|
-
const handleToolbarCancel =
|
|
1760
|
+
const handleToolbarCancel = useCallback5(() => {
|
|
2241
1761
|
setToolbarActive(false);
|
|
2242
|
-
setSelectorActive(false);
|
|
2243
1762
|
}, []);
|
|
2244
|
-
const handleComponentSelect =
|
|
1763
|
+
const handleComponentSelect = useCallback5(
|
|
2245
1764
|
(element) => {
|
|
2246
1765
|
setInspectorActive(false);
|
|
2247
|
-
performCapture("component", void 0, element);
|
|
2248
|
-
},
|
|
2249
|
-
[performCapture]
|
|
2250
|
-
);
|
|
2251
|
-
const handleComponentCancel = useCallback6(() => {
|
|
2252
|
-
setInspectorActive(false);
|
|
2253
|
-
setToolbarActive(true);
|
|
2254
|
-
}, []);
|
|
2255
|
-
const handleAreaSelect = useCallback6(
|
|
2256
|
-
(area) => {
|
|
2257
|
-
setSelectorActive(false);
|
|
2258
1766
|
setToolbarActive(false);
|
|
2259
|
-
performCapture("
|
|
1767
|
+
performCapture("component", element);
|
|
2260
1768
|
},
|
|
2261
1769
|
[performCapture]
|
|
2262
1770
|
);
|
|
2263
|
-
const
|
|
2264
|
-
|
|
1771
|
+
const handleComponentCancel = useCallback5(() => {
|
|
1772
|
+
setInspectorActive(false);
|
|
2265
1773
|
setToolbarActive(true);
|
|
2266
1774
|
}, []);
|
|
2267
|
-
const
|
|
2268
|
-
|
|
2269
|
-
try {
|
|
2270
|
-
localStorage.setItem("ab-magnet", String(enabled));
|
|
2271
|
-
} catch {
|
|
2272
|
-
}
|
|
2273
|
-
}, []);
|
|
2274
|
-
const handleFrameOnBlackChange = useCallback6((enabled) => {
|
|
2275
|
-
setFrameOnBlackEnabled(enabled);
|
|
1775
|
+
const handleFrameSettingsChange = useCallback5((next) => {
|
|
1776
|
+
setFrameSettings(next);
|
|
2276
1777
|
try {
|
|
2277
|
-
localStorage.setItem("ab-frame-
|
|
1778
|
+
localStorage.setItem("ab-frame-settings", JSON.stringify(next));
|
|
2278
1779
|
} catch {
|
|
2279
1780
|
}
|
|
2280
1781
|
}, []);
|
|
2281
|
-
const handleModeChange =
|
|
1782
|
+
const handleModeChange = useCallback5((mode) => {
|
|
2282
1783
|
setSelectedMode(mode);
|
|
2283
|
-
if (mode === "
|
|
2284
|
-
setSelectorActive(true);
|
|
2285
|
-
setAreaRect(createInitialAreaRect());
|
|
2286
|
-
setAreaAspect(DEFAULT_AREA_ASPECT);
|
|
2287
|
-
} else if (mode === "component") {
|
|
2288
|
-
setSelectorActive(false);
|
|
2289
|
-
setToolbarActive(false);
|
|
1784
|
+
if (mode === "component") {
|
|
2290
1785
|
setInspectorActive(true);
|
|
2291
|
-
} else {
|
|
2292
|
-
setSelectorActive(false);
|
|
2293
|
-
}
|
|
2294
|
-
}, []);
|
|
2295
|
-
const handleAreaRectChange = useCallback6((nextRect) => {
|
|
2296
|
-
setAreaRect(nextRect);
|
|
2297
|
-
}, []);
|
|
2298
|
-
const handleAreaSizeChange = useCallback6(
|
|
2299
|
-
(field, value) => {
|
|
2300
|
-
const nextValue = parseInt(value, 10);
|
|
2301
|
-
if (Number.isNaN(nextValue) || nextValue < 20 || !areaRect) {
|
|
2302
|
-
return;
|
|
2303
|
-
}
|
|
2304
|
-
const aspectRatio = areaAspect === "Free" ? 0 : { "16:9": 16 / 9, "4:3": 4 / 3, "1:1": 1, "3:2": 3 / 2, "21:9": 21 / 9 }[areaAspect];
|
|
2305
|
-
if (field === "w") {
|
|
2306
|
-
setAreaRect({
|
|
2307
|
-
...areaRect,
|
|
2308
|
-
w: nextValue,
|
|
2309
|
-
h: aspectRatio > 0 ? nextValue / aspectRatio : areaRect.h
|
|
2310
|
-
});
|
|
2311
|
-
} else {
|
|
2312
|
-
setAreaRect({
|
|
2313
|
-
...areaRect,
|
|
2314
|
-
h: nextValue,
|
|
2315
|
-
w: aspectRatio > 0 ? nextValue * aspectRatio : areaRect.w
|
|
2316
|
-
});
|
|
2317
|
-
}
|
|
2318
|
-
},
|
|
2319
|
-
[areaAspect, areaRect]
|
|
2320
|
-
);
|
|
2321
|
-
const handleAreaPositionChange = useCallback6(
|
|
2322
|
-
(field, value) => {
|
|
2323
|
-
const nextValue = parseInt(value, 10);
|
|
2324
|
-
if (Number.isNaN(nextValue) || !areaRect) {
|
|
2325
|
-
return;
|
|
2326
|
-
}
|
|
2327
|
-
setAreaRect({ ...areaRect, [field]: nextValue });
|
|
2328
|
-
},
|
|
2329
|
-
[areaRect]
|
|
2330
|
-
);
|
|
2331
|
-
const handleAreaAspectChange = useCallback6(
|
|
2332
|
-
(nextAspect) => {
|
|
2333
|
-
setAreaAspect(nextAspect);
|
|
2334
|
-
if (!areaRect || nextAspect === "Free") {
|
|
2335
|
-
return;
|
|
2336
|
-
}
|
|
2337
|
-
const aspectRatio = { "16:9": 16 / 9, "4:3": 4 / 3, "1:1": 1, "3:2": 3 / 2, "21:9": 21 / 9 }[nextAspect];
|
|
2338
|
-
setAreaRect({ ...areaRect, h: areaRect.w / aspectRatio });
|
|
2339
|
-
},
|
|
2340
|
-
[areaRect]
|
|
2341
|
-
);
|
|
2342
|
-
const handleAreaSavePreset = useCallback6(() => {
|
|
2343
|
-
if (!areaRect) {
|
|
2344
|
-
return;
|
|
2345
|
-
}
|
|
2346
|
-
const label = `${Math.round(areaRect.w)}x${Math.round(areaRect.h)}`;
|
|
2347
|
-
const nextPresets = [
|
|
2348
|
-
...areaPresets.filter((preset) => preset.label !== label),
|
|
2349
|
-
{ label, rect: { ...areaRect } }
|
|
2350
|
-
];
|
|
2351
|
-
setAreaPresets(nextPresets);
|
|
2352
|
-
try {
|
|
2353
|
-
localStorage.setItem("ab-area-presets", JSON.stringify(nextPresets));
|
|
2354
|
-
} catch {
|
|
2355
1786
|
}
|
|
2356
|
-
}, [areaPresets, areaRect]);
|
|
2357
|
-
const handleAreaLoadPreset = useCallback6((preset) => {
|
|
2358
|
-
setAreaRect({ ...preset.rect });
|
|
2359
1787
|
}, []);
|
|
2360
|
-
const handleReset =
|
|
1788
|
+
const handleReset = useCallback5(() => {
|
|
2361
1789
|
reset();
|
|
2362
1790
|
setStatusOpen(false);
|
|
2363
1791
|
}, [reset]);
|
|
2364
|
-
const handleStatusClose =
|
|
1792
|
+
const handleStatusClose = useCallback5(() => {
|
|
2365
1793
|
setStatusOpen(false);
|
|
2366
1794
|
}, []);
|
|
2367
|
-
return /* @__PURE__ */
|
|
2368
|
-
/* @__PURE__ */
|
|
1795
|
+
return /* @__PURE__ */ jsxs5("div", { "data-afterbefore": "true", children: [
|
|
1796
|
+
/* @__PURE__ */ jsx6(
|
|
2369
1797
|
Icon,
|
|
2370
1798
|
{
|
|
2371
1799
|
phase: state.phase,
|
|
@@ -2374,48 +1802,26 @@ function AfterBefore() {
|
|
|
2374
1802
|
onPositionChange: handlePositionChange
|
|
2375
1803
|
}
|
|
2376
1804
|
),
|
|
2377
|
-
toolbarActive && !
|
|
1805
|
+
toolbarActive && !inspectorActive && !loading && /* @__PURE__ */ jsx6(
|
|
2378
1806
|
CapturePreview,
|
|
2379
1807
|
{
|
|
2380
1808
|
mode: selectedMode,
|
|
2381
1809
|
onClick: () => handleToolbarCapture(selectedMode)
|
|
2382
1810
|
}
|
|
2383
1811
|
),
|
|
2384
|
-
toolbarActive &&
|
|
1812
|
+
toolbarActive && /* @__PURE__ */ jsx6(
|
|
2385
1813
|
Toolbar,
|
|
2386
1814
|
{
|
|
2387
1815
|
selectedMode,
|
|
2388
1816
|
onModeChange: handleModeChange,
|
|
2389
1817
|
onCapture: handleToolbarCapture,
|
|
2390
1818
|
onCancel: handleToolbarCancel,
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
areaSelectionActive: selectorActive,
|
|
2394
|
-
areaRect,
|
|
2395
|
-
areaAspect,
|
|
2396
|
-
areaPresets,
|
|
2397
|
-
onAreaSizeChange: handleAreaSizeChange,
|
|
2398
|
-
onAreaPositionChange: handleAreaPositionChange,
|
|
2399
|
-
onAreaAspectChange: handleAreaAspectChange,
|
|
2400
|
-
onAreaSavePreset: handleAreaSavePreset,
|
|
2401
|
-
onAreaLoadPreset: handleAreaLoadPreset,
|
|
2402
|
-
frameOnBlackEnabled,
|
|
2403
|
-
onFrameOnBlackChange: handleFrameOnBlackChange
|
|
2404
|
-
}
|
|
2405
|
-
),
|
|
2406
|
-
selectorActive && /* @__PURE__ */ jsx7(
|
|
2407
|
-
Selector,
|
|
2408
|
-
{
|
|
2409
|
-
rect: areaRect,
|
|
2410
|
-
aspect: areaAspect,
|
|
2411
|
-
onRectChange: handleAreaRectChange,
|
|
2412
|
-
onSelect: handleAreaSelect,
|
|
2413
|
-
onCancel: handleAreaCancel,
|
|
2414
|
-
magnetEnabled
|
|
1819
|
+
frameSettings,
|
|
1820
|
+
onFrameSettingsChange: handleFrameSettingsChange
|
|
2415
1821
|
}
|
|
2416
1822
|
),
|
|
2417
|
-
inspectorActive && /* @__PURE__ */
|
|
2418
|
-
statusOpen && state.phase === "ready" && /* @__PURE__ */
|
|
1823
|
+
inspectorActive && /* @__PURE__ */ jsx6(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel }),
|
|
1824
|
+
statusOpen && state.phase === "ready" && /* @__PURE__ */ jsx6(
|
|
2419
1825
|
Status,
|
|
2420
1826
|
{
|
|
2421
1827
|
onReset: handleReset,
|