afterbefore 0.2.7 → 0.2.8
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/overlay/index.js +1124 -1066
- package/dist/overlay/index.js.map +1 -1
- package/package.json +3 -2
package/dist/overlay/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/overlay/index.tsx
|
|
4
|
-
import { useState as
|
|
4
|
+
import { useState as useState8, useCallback as useCallback6, useRef as useRef5, useEffect as useEffect7 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/overlay/state.ts
|
|
7
7
|
import { useState, useCallback } from "react";
|
|
@@ -33,7 +33,7 @@ function useOverlayState() {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// src/overlay/capture.ts
|
|
36
|
-
import {
|
|
36
|
+
import { snapdom } from "@zumer/snapdom";
|
|
37
37
|
var DEV_UI_SELECTORS = [
|
|
38
38
|
// Afterbefore overlay
|
|
39
39
|
"[data-afterbefore]",
|
|
@@ -44,53 +44,37 @@ var DEV_UI_SELECTORS = [
|
|
|
44
44
|
"[data-nextjs-dialog-backdrop]",
|
|
45
45
|
"[data-next-badge]",
|
|
46
46
|
"[data-next-mark]"
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
elements.forEach((el) => {
|
|
58
|
-
saved.set(el, el.style.display);
|
|
59
|
-
el.style.display = "none";
|
|
60
|
-
});
|
|
61
|
-
return () => {
|
|
62
|
-
saved.forEach((v, el) => {
|
|
63
|
-
el.style.display = v;
|
|
64
|
-
});
|
|
65
|
-
};
|
|
47
|
+
];
|
|
48
|
+
var SNAPDOM_BASE = {
|
|
49
|
+
scale: window.devicePixelRatio || 1,
|
|
50
|
+
exclude: DEV_UI_SELECTORS,
|
|
51
|
+
excludeMode: "remove"
|
|
52
|
+
};
|
|
53
|
+
async function toPngDataUrl(el, opts) {
|
|
54
|
+
const result = await snapdom(el, { ...SNAPDOM_BASE, ...opts });
|
|
55
|
+
const img = await result.toPng();
|
|
56
|
+
return img.src;
|
|
66
57
|
}
|
|
67
58
|
async function capture(options) {
|
|
68
59
|
const { mode, area, element } = options;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (mode === "area" && area) {
|
|
78
|
-
return await captureArea(area);
|
|
79
|
-
}
|
|
80
|
-
if (mode === "component" && element) {
|
|
81
|
-
return await captureComponent(element);
|
|
82
|
-
}
|
|
83
|
-
throw new Error(`Invalid capture mode: ${mode}`);
|
|
84
|
-
} finally {
|
|
85
|
-
restore();
|
|
60
|
+
if (mode === "viewport") {
|
|
61
|
+
return captureViewport();
|
|
62
|
+
}
|
|
63
|
+
if (mode === "fullpage") {
|
|
64
|
+
return captureFullPage();
|
|
65
|
+
}
|
|
66
|
+
if (mode === "area" && area) {
|
|
67
|
+
return captureArea(area);
|
|
86
68
|
}
|
|
69
|
+
if (mode === "component" && element) {
|
|
70
|
+
return captureComponent(element);
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Invalid capture mode: ${mode}`);
|
|
87
73
|
}
|
|
88
74
|
async function captureViewport() {
|
|
89
|
-
return
|
|
75
|
+
return toPngDataUrl(document.documentElement, {
|
|
90
76
|
width: window.innerWidth,
|
|
91
|
-
height: window.innerHeight
|
|
92
|
-
style: { overflow: "hidden" },
|
|
93
|
-
filter: filterDevUI
|
|
77
|
+
height: window.innerHeight
|
|
94
78
|
});
|
|
95
79
|
}
|
|
96
80
|
async function captureFullPage() {
|
|
@@ -104,17 +88,20 @@ async function captureFullPage() {
|
|
|
104
88
|
html.scrollHeight,
|
|
105
89
|
html.offsetHeight
|
|
106
90
|
);
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
91
|
+
const prevOverflow = html.style.overflow;
|
|
92
|
+
const prevHeight = html.style.height;
|
|
93
|
+
html.style.overflow = "visible";
|
|
94
|
+
html.style.height = `${fullHeight}px`;
|
|
95
|
+
try {
|
|
96
|
+
return await toPngDataUrl(document.documentElement, {
|
|
97
|
+
width: window.innerWidth,
|
|
98
|
+
height: fullHeight
|
|
99
|
+
});
|
|
100
|
+
} finally {
|
|
101
|
+
html.style.overflow = prevOverflow;
|
|
102
|
+
html.style.height = prevHeight;
|
|
103
|
+
window.scrollTo(0, scrollY);
|
|
104
|
+
}
|
|
118
105
|
}
|
|
119
106
|
async function captureArea(area) {
|
|
120
107
|
const fullDataUrl = await captureViewport();
|
|
@@ -138,9 +125,7 @@ async function captureArea(area) {
|
|
|
138
125
|
return canvas.toDataURL("image/png");
|
|
139
126
|
}
|
|
140
127
|
async function captureComponent(element) {
|
|
141
|
-
return
|
|
142
|
-
filter: filterDevUI
|
|
143
|
-
});
|
|
128
|
+
return toPngDataUrl(element);
|
|
144
129
|
}
|
|
145
130
|
function loadImage(src) {
|
|
146
131
|
return new Promise((resolve, reject) => {
|
|
@@ -153,6 +138,7 @@ function loadImage(src) {
|
|
|
153
138
|
|
|
154
139
|
// src/overlay/ui/icon.tsx
|
|
155
140
|
import { useRef, useCallback as useCallback2, useEffect, useState as useState2 } from "react";
|
|
141
|
+
import { Camera, Check, LoaderCircle } from "lucide-react";
|
|
156
142
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
157
143
|
var ICON_SIZE = 40;
|
|
158
144
|
var EDGE_MARGIN = 24;
|
|
@@ -268,38 +254,13 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
268
254
|
}
|
|
269
255
|
),
|
|
270
256
|
loading ? /* @__PURE__ */ jsx(
|
|
271
|
-
|
|
272
|
-
{
|
|
273
|
-
width: "20",
|
|
274
|
-
height: "20",
|
|
275
|
-
viewBox: "0 0 20 20",
|
|
276
|
-
style: { animation: "ab-spin 0.8s linear infinite" },
|
|
277
|
-
children: /* @__PURE__ */ jsx(
|
|
278
|
-
"circle",
|
|
279
|
-
{
|
|
280
|
-
cx: "10",
|
|
281
|
-
cy: "10",
|
|
282
|
-
r: "8",
|
|
283
|
-
fill: "none",
|
|
284
|
-
stroke: "white",
|
|
285
|
-
strokeWidth: "2",
|
|
286
|
-
strokeDasharray: "40",
|
|
287
|
-
strokeDashoffset: "10",
|
|
288
|
-
strokeLinecap: "round"
|
|
289
|
-
}
|
|
290
|
-
)
|
|
291
|
-
}
|
|
292
|
-
) : phase === "ready" ? /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx(
|
|
293
|
-
"path",
|
|
257
|
+
LoaderCircle,
|
|
294
258
|
{
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
strokeWidth: "2.5",
|
|
299
|
-
strokeLinecap: "round",
|
|
300
|
-
strokeLinejoin: "round"
|
|
259
|
+
size: 20,
|
|
260
|
+
strokeWidth: 2,
|
|
261
|
+
style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
|
|
301
262
|
}
|
|
302
|
-
) }) : /* @__PURE__ */ jsxs(
|
|
263
|
+
) : phase === "ready" ? /* @__PURE__ */ jsx(Check, { size: 20, strokeWidth: 2.6, color: "#4ade80" }) : /* @__PURE__ */ jsxs(
|
|
303
264
|
"div",
|
|
304
265
|
{
|
|
305
266
|
style: {
|
|
@@ -310,33 +271,7 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
310
271
|
animation: phase === "captured-before" ? "ab-pulse 2s ease-in-out infinite" : "none"
|
|
311
272
|
},
|
|
312
273
|
children: [
|
|
313
|
-
/* @__PURE__ */
|
|
314
|
-
/* @__PURE__ */ jsx(
|
|
315
|
-
"rect",
|
|
316
|
-
{
|
|
317
|
-
x: "2",
|
|
318
|
-
y: "5",
|
|
319
|
-
width: "16",
|
|
320
|
-
height: "12",
|
|
321
|
-
rx: "2",
|
|
322
|
-
fill: "none",
|
|
323
|
-
stroke: "white",
|
|
324
|
-
strokeWidth: "1.5"
|
|
325
|
-
}
|
|
326
|
-
),
|
|
327
|
-
/* @__PURE__ */ jsx(
|
|
328
|
-
"circle",
|
|
329
|
-
{
|
|
330
|
-
cx: "10",
|
|
331
|
-
cy: "11",
|
|
332
|
-
r: "3",
|
|
333
|
-
fill: "none",
|
|
334
|
-
stroke: "white",
|
|
335
|
-
strokeWidth: "1.5"
|
|
336
|
-
}
|
|
337
|
-
),
|
|
338
|
-
/* @__PURE__ */ jsx("path", { d: "M7 5l1-2h4l1 2", fill: "none", stroke: "white", strokeWidth: "1.5" })
|
|
339
|
-
] }),
|
|
274
|
+
/* @__PURE__ */ jsx(Camera, { size: 20, strokeWidth: 1.9, color: "white" }),
|
|
340
275
|
phase === "captured-before" && /* @__PURE__ */ jsx(
|
|
341
276
|
"div",
|
|
342
277
|
{
|
|
@@ -368,314 +303,155 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
368
303
|
);
|
|
369
304
|
}
|
|
370
305
|
|
|
371
|
-
// src/overlay/ui/
|
|
372
|
-
import {
|
|
373
|
-
import { jsx as jsx2
|
|
374
|
-
var
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
306
|
+
// src/overlay/ui/preview.tsx
|
|
307
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
308
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
309
|
+
var DEFAULT_ASPECT_RATIO = 16 / 9;
|
|
310
|
+
function getAreaPreviewRect() {
|
|
311
|
+
const safeWidth = Math.max(320, window.innerWidth - 120);
|
|
312
|
+
const safeHeight = Math.max(180, window.innerHeight - 220);
|
|
313
|
+
const width = Math.min(window.innerWidth * 0.72, safeHeight * DEFAULT_ASPECT_RATIO, safeWidth);
|
|
314
|
+
const height = width / DEFAULT_ASPECT_RATIO;
|
|
315
|
+
return {
|
|
316
|
+
x: (window.innerWidth - width) / 2,
|
|
317
|
+
y: Math.max(40, (window.innerHeight - height) / 2 - 20),
|
|
318
|
+
width,
|
|
319
|
+
height
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function CapturePreview({ mode }) {
|
|
323
|
+
const [areaRect, setAreaRect] = useState3(null);
|
|
383
324
|
useEffect2(() => {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
325
|
+
if (mode !== "area") {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const syncRect = () => {
|
|
329
|
+
setAreaRect(getAreaPreviewRect());
|
|
387
330
|
};
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
alignItems: "center",
|
|
405
|
-
gap: 8
|
|
406
|
-
},
|
|
407
|
-
children: [
|
|
408
|
-
tooltipLabel && /* @__PURE__ */ jsx2(
|
|
331
|
+
syncRect();
|
|
332
|
+
window.addEventListener("resize", syncRect);
|
|
333
|
+
return () => window.removeEventListener("resize", syncRect);
|
|
334
|
+
}, [mode]);
|
|
335
|
+
if (mode === "area" && areaRect) {
|
|
336
|
+
return /* @__PURE__ */ jsx2(
|
|
337
|
+
"div",
|
|
338
|
+
{
|
|
339
|
+
"data-afterbefore": "true",
|
|
340
|
+
style: {
|
|
341
|
+
position: "fixed",
|
|
342
|
+
inset: 0,
|
|
343
|
+
zIndex: 2147483645,
|
|
344
|
+
pointerEvents: "none"
|
|
345
|
+
},
|
|
346
|
+
children: /* @__PURE__ */ jsx2(
|
|
409
347
|
"div",
|
|
410
348
|
{
|
|
411
349
|
style: {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.3)"
|
|
423
|
-
},
|
|
424
|
-
children: tooltipLabel
|
|
350
|
+
position: "absolute",
|
|
351
|
+
left: areaRect.x,
|
|
352
|
+
top: areaRect.y,
|
|
353
|
+
width: areaRect.width,
|
|
354
|
+
height: areaRect.height,
|
|
355
|
+
background: "rgba(125, 211, 252, 0.16)",
|
|
356
|
+
border: "1.5px solid rgba(125, 211, 252, 0.95)",
|
|
357
|
+
boxShadow: "0 0 0 1px rgba(191, 219, 254, 0.4), 0 0 32px rgba(56, 189, 248, 0.18)",
|
|
358
|
+
borderRadius: 14
|
|
359
|
+
}
|
|
425
360
|
}
|
|
426
|
-
)
|
|
427
|
-
|
|
361
|
+
)
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
if (mode === "viewport" || mode === "fullpage") {
|
|
366
|
+
return /* @__PURE__ */ jsx2(
|
|
367
|
+
"div",
|
|
368
|
+
{
|
|
369
|
+
"data-afterbefore": "true",
|
|
370
|
+
style: {
|
|
371
|
+
position: "fixed",
|
|
372
|
+
inset: 0,
|
|
373
|
+
zIndex: 2147483645,
|
|
374
|
+
pointerEvents: "none",
|
|
375
|
+
background: "rgba(125, 211, 252, 0.15)",
|
|
376
|
+
boxShadow: "inset 0 0 0 1.5px rgba(125, 211, 252, 0.9)"
|
|
377
|
+
},
|
|
378
|
+
children: /* @__PURE__ */ jsx2(
|
|
428
379
|
"div",
|
|
429
380
|
{
|
|
430
381
|
style: {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
382
|
+
position: "absolute",
|
|
383
|
+
top: 36,
|
|
384
|
+
left: "50%",
|
|
385
|
+
transform: "translateX(-50%)",
|
|
386
|
+
padding: "8px 14px",
|
|
387
|
+
borderRadius: 999,
|
|
388
|
+
background: "rgba(125, 211, 252, 0.16)",
|
|
389
|
+
border: "1px solid rgba(125, 211, 252, 0.42)",
|
|
390
|
+
color: "rgba(224, 242, 254, 0.96)",
|
|
391
|
+
fontSize: 12,
|
|
392
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
393
|
+
boxShadow: "0 10px 30px rgba(14, 116, 144, 0.18)"
|
|
442
394
|
},
|
|
443
|
-
children:
|
|
444
|
-
/* @__PURE__ */ jsx2(CloseButton, { onClick: onCancel }),
|
|
445
|
-
/* @__PURE__ */ jsx2("div", { style: { display: "flex", alignItems: "center", gap: 2, padding: "0 4px" }, children: MODES.map(({ mode, label }) => /* @__PURE__ */ jsx2(
|
|
446
|
-
ModeButton,
|
|
447
|
-
{
|
|
448
|
-
mode,
|
|
449
|
-
label,
|
|
450
|
-
selected: selectedMode === mode,
|
|
451
|
-
onClick: () => setSelectedMode(mode),
|
|
452
|
-
onHover: (hovered) => setHoveredMode(hovered ? mode : null)
|
|
453
|
-
},
|
|
454
|
-
mode
|
|
455
|
-
)) }),
|
|
456
|
-
/* @__PURE__ */ jsx2(
|
|
457
|
-
"div",
|
|
458
|
-
{
|
|
459
|
-
style: {
|
|
460
|
-
width: 1,
|
|
461
|
-
height: 24,
|
|
462
|
-
background: "rgba(255, 255, 255, 0.15)",
|
|
463
|
-
margin: "0 6px",
|
|
464
|
-
flexShrink: 0
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
),
|
|
468
|
-
/* @__PURE__ */ jsx2(CaptureButton, { onClick: () => onCapture(selectedMode) })
|
|
469
|
-
]
|
|
395
|
+
children: mode === "fullpage" ? "Full-page capture begins from the current viewport" : "Current viewport capture"
|
|
470
396
|
}
|
|
471
397
|
)
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
function CloseButton({ onClick }) {
|
|
477
|
-
const [hovered, setHovered] = useState3(false);
|
|
398
|
+
}
|
|
399
|
+
);
|
|
400
|
+
}
|
|
478
401
|
return /* @__PURE__ */ jsx2(
|
|
479
|
-
"
|
|
402
|
+
"div",
|
|
480
403
|
{
|
|
481
|
-
|
|
482
|
-
onMouseEnter: () => setHovered(true),
|
|
483
|
-
onMouseLeave: () => setHovered(false),
|
|
404
|
+
"data-afterbefore": "true",
|
|
484
405
|
style: {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
background: hovered ? "rgba(255, 255, 255, 0.12)" : "rgba(255, 255, 255, 0.06)",
|
|
490
|
-
display: "flex",
|
|
491
|
-
alignItems: "center",
|
|
492
|
-
justifyContent: "center",
|
|
493
|
-
cursor: "pointer",
|
|
494
|
-
flexShrink: 0,
|
|
495
|
-
padding: 0,
|
|
496
|
-
transition: "background 0.1s",
|
|
497
|
-
marginRight: 4
|
|
406
|
+
position: "fixed",
|
|
407
|
+
inset: 0,
|
|
408
|
+
zIndex: 2147483645,
|
|
409
|
+
pointerEvents: "none"
|
|
498
410
|
},
|
|
499
|
-
children: /* @__PURE__ */ jsx2(
|
|
500
|
-
"
|
|
411
|
+
children: /* @__PURE__ */ jsx2(
|
|
412
|
+
"div",
|
|
501
413
|
{
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
414
|
+
style: {
|
|
415
|
+
position: "absolute",
|
|
416
|
+
top: 36,
|
|
417
|
+
left: "50%",
|
|
418
|
+
transform: "translateX(-50%)",
|
|
419
|
+
padding: "8px 14px",
|
|
420
|
+
borderRadius: 999,
|
|
421
|
+
background: "rgba(125, 211, 252, 0.16)",
|
|
422
|
+
border: "1px solid rgba(125, 211, 252, 0.42)",
|
|
423
|
+
color: "rgba(224, 242, 254, 0.96)",
|
|
424
|
+
fontSize: 12,
|
|
425
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
426
|
+
boxShadow: "0 10px 30px rgba(14, 116, 144, 0.18)"
|
|
427
|
+
},
|
|
428
|
+
children: "Click Capture, then hover an element to preview it"
|
|
506
429
|
}
|
|
507
|
-
)
|
|
508
|
-
}
|
|
509
|
-
);
|
|
510
|
-
}
|
|
511
|
-
function ModeButton({
|
|
512
|
-
mode,
|
|
513
|
-
label,
|
|
514
|
-
selected,
|
|
515
|
-
onClick,
|
|
516
|
-
onHover
|
|
517
|
-
}) {
|
|
518
|
-
const [hovered, setHovered] = useState3(false);
|
|
519
|
-
return /* @__PURE__ */ jsx2(
|
|
520
|
-
"button",
|
|
521
|
-
{
|
|
522
|
-
onClick,
|
|
523
|
-
onMouseEnter: () => {
|
|
524
|
-
setHovered(true);
|
|
525
|
-
onHover(true);
|
|
526
|
-
},
|
|
527
|
-
onMouseLeave: () => {
|
|
528
|
-
setHovered(false);
|
|
529
|
-
onHover(false);
|
|
530
|
-
},
|
|
531
|
-
title: label,
|
|
532
|
-
style: {
|
|
533
|
-
width: 40,
|
|
534
|
-
height: 34,
|
|
535
|
-
borderRadius: 8,
|
|
536
|
-
border: "none",
|
|
537
|
-
background: selected ? "rgba(255, 255, 255, 0.15)" : hovered ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
538
|
-
display: "flex",
|
|
539
|
-
alignItems: "center",
|
|
540
|
-
justifyContent: "center",
|
|
541
|
-
cursor: "pointer",
|
|
542
|
-
padding: 0,
|
|
543
|
-
color: selected ? "rgba(255, 255, 255, 0.95)" : "rgba(255, 255, 255, 0.45)",
|
|
544
|
-
transition: "background 0.1s, color 0.1s"
|
|
545
|
-
},
|
|
546
|
-
children: /* @__PURE__ */ jsx2(ModeIcon, { mode })
|
|
547
|
-
}
|
|
548
|
-
);
|
|
549
|
-
}
|
|
550
|
-
function CaptureButton({ onClick }) {
|
|
551
|
-
const [hovered, setHovered] = useState3(false);
|
|
552
|
-
return /* @__PURE__ */ jsx2(
|
|
553
|
-
"button",
|
|
554
|
-
{
|
|
555
|
-
onClick,
|
|
556
|
-
onMouseEnter: () => setHovered(true),
|
|
557
|
-
onMouseLeave: () => setHovered(false),
|
|
558
|
-
style: {
|
|
559
|
-
padding: "6px 16px",
|
|
560
|
-
borderRadius: 8,
|
|
561
|
-
border: "none",
|
|
562
|
-
background: hovered ? "#2563eb" : "#3b82f6",
|
|
563
|
-
color: "white",
|
|
564
|
-
fontSize: 13,
|
|
565
|
-
fontWeight: 600,
|
|
566
|
-
fontFamily: "inherit",
|
|
567
|
-
cursor: "pointer",
|
|
568
|
-
whiteSpace: "nowrap",
|
|
569
|
-
transition: "background 0.1s",
|
|
570
|
-
flexShrink: 0
|
|
571
|
-
},
|
|
572
|
-
children: "Capture"
|
|
430
|
+
)
|
|
573
431
|
}
|
|
574
432
|
);
|
|
575
433
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
}
|
|
592
|
-
),
|
|
593
|
-
/* @__PURE__ */ jsx2("line", { x1: "10", y1: "7", x2: "10", y2: "13", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" }),
|
|
594
|
-
/* @__PURE__ */ jsx2("line", { x1: "7", y1: "10", x2: "13", y2: "10", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })
|
|
595
|
-
] });
|
|
596
|
-
case "viewport":
|
|
597
|
-
return /* @__PURE__ */ jsxs2("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
598
|
-
/* @__PURE__ */ jsx2(
|
|
599
|
-
"rect",
|
|
600
|
-
{
|
|
601
|
-
x: "2",
|
|
602
|
-
y: "3",
|
|
603
|
-
width: "16",
|
|
604
|
-
height: "12",
|
|
605
|
-
rx: "1.5",
|
|
606
|
-
stroke: "currentColor",
|
|
607
|
-
strokeWidth: "1.3"
|
|
608
|
-
}
|
|
609
|
-
),
|
|
610
|
-
/* @__PURE__ */ jsx2(
|
|
611
|
-
"line",
|
|
612
|
-
{
|
|
613
|
-
x1: "2",
|
|
614
|
-
y1: "17",
|
|
615
|
-
x2: "18",
|
|
616
|
-
y2: "17",
|
|
617
|
-
stroke: "currentColor",
|
|
618
|
-
strokeWidth: "1.3",
|
|
619
|
-
strokeLinecap: "round"
|
|
620
|
-
}
|
|
621
|
-
)
|
|
622
|
-
] });
|
|
623
|
-
case "fullpage":
|
|
624
|
-
return /* @__PURE__ */ jsxs2("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
625
|
-
/* @__PURE__ */ jsx2(
|
|
626
|
-
"rect",
|
|
627
|
-
{
|
|
628
|
-
x: "4",
|
|
629
|
-
y: "1",
|
|
630
|
-
width: "12",
|
|
631
|
-
height: "18",
|
|
632
|
-
rx: "1.5",
|
|
633
|
-
stroke: "currentColor",
|
|
634
|
-
strokeWidth: "1.3"
|
|
635
|
-
}
|
|
636
|
-
),
|
|
637
|
-
/* @__PURE__ */ jsx2("line", { x1: "7", y1: "5", x2: "13", y2: "5", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" }),
|
|
638
|
-
/* @__PURE__ */ jsx2("line", { x1: "7", y1: "8", x2: "13", y2: "8", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" }),
|
|
639
|
-
/* @__PURE__ */ jsx2("line", { x1: "7", y1: "11", x2: "13", y2: "11", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })
|
|
640
|
-
] });
|
|
641
|
-
case "component":
|
|
642
|
-
return /* @__PURE__ */ jsxs2("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
643
|
-
/* @__PURE__ */ jsx2(
|
|
644
|
-
"path",
|
|
645
|
-
{
|
|
646
|
-
d: "M4 3l3 12 2.5-4.5L14 13 4 3z",
|
|
647
|
-
stroke: "currentColor",
|
|
648
|
-
strokeWidth: "1.2",
|
|
649
|
-
strokeLinejoin: "round",
|
|
650
|
-
strokeLinecap: "round"
|
|
651
|
-
}
|
|
652
|
-
),
|
|
653
|
-
/* @__PURE__ */ jsx2(
|
|
654
|
-
"rect",
|
|
655
|
-
{
|
|
656
|
-
x: "10",
|
|
657
|
-
y: "7",
|
|
658
|
-
width: "7",
|
|
659
|
-
height: "7",
|
|
660
|
-
rx: "1",
|
|
661
|
-
stroke: "currentColor",
|
|
662
|
-
strokeWidth: "1.1",
|
|
663
|
-
strokeDasharray: "2 1.5"
|
|
664
|
-
}
|
|
665
|
-
)
|
|
666
|
-
] });
|
|
667
|
-
}
|
|
668
|
-
}
|
|
434
|
+
|
|
435
|
+
// src/overlay/ui/toolbar.tsx
|
|
436
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
437
|
+
import {
|
|
438
|
+
Camera as Camera2,
|
|
439
|
+
ChevronDown,
|
|
440
|
+
Crop,
|
|
441
|
+
FileText,
|
|
442
|
+
Magnet,
|
|
443
|
+
Monitor,
|
|
444
|
+
MousePointer2,
|
|
445
|
+
Save,
|
|
446
|
+
Settings2,
|
|
447
|
+
X
|
|
448
|
+
} from "lucide-react";
|
|
669
449
|
|
|
670
450
|
// src/overlay/ui/selector.tsx
|
|
671
|
-
import React3, {
|
|
672
|
-
import { Fragment, jsx as jsx3, jsxs as
|
|
673
|
-
var
|
|
674
|
-
var
|
|
675
|
-
var MIN_SIZE = 20;
|
|
676
|
-
var PANEL_HEIGHT_EST = 140;
|
|
677
|
-
var SNAP_THRESHOLD = 8;
|
|
678
|
-
var ASPECT_RATIOS = [
|
|
451
|
+
import React3, { useRef as useRef2, useCallback as useCallback3, useEffect as useEffect3, useMemo, useState as useState4 } from "react";
|
|
452
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
453
|
+
var DEFAULT_AREA_ASPECT = "16:9";
|
|
454
|
+
var AREA_ASPECT_RATIOS = [
|
|
679
455
|
{ label: "Free", value: 0 },
|
|
680
456
|
{ label: "16:9", value: 16 / 9 },
|
|
681
457
|
{ label: "4:3", value: 4 / 3 },
|
|
@@ -683,112 +459,94 @@ var ASPECT_RATIOS = [
|
|
|
683
459
|
{ label: "3:2", value: 3 / 2 },
|
|
684
460
|
{ label: "21:9", value: 21 / 9 }
|
|
685
461
|
];
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
462
|
+
var HANDLE_R = 6;
|
|
463
|
+
var HANDLE_HIT = 16;
|
|
464
|
+
var MIN_SIZE = 20;
|
|
465
|
+
var SNAP_THRESHOLD = 8;
|
|
466
|
+
var CAMERA_CURSOR = `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`;
|
|
467
|
+
function createInitialAreaRect() {
|
|
468
|
+
const safeWidth = Math.max(320, window.innerWidth - 96);
|
|
469
|
+
const safeHeight = Math.max(180, window.innerHeight - 220);
|
|
470
|
+
const w = Math.min(window.innerWidth * 0.72, safeHeight * (16 / 9), safeWidth);
|
|
471
|
+
const h = w / (16 / 9);
|
|
472
|
+
return {
|
|
473
|
+
x: (window.innerWidth - w) / 2,
|
|
474
|
+
y: Math.max(40, (window.innerHeight - h) / 2 - 20),
|
|
475
|
+
w,
|
|
476
|
+
h
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
function getAspectRatio(label) {
|
|
480
|
+
return AREA_ASPECT_RATIOS.find((item) => item.label === label)?.value ?? 0;
|
|
481
|
+
}
|
|
482
|
+
function Selector({
|
|
483
|
+
rect,
|
|
484
|
+
aspect,
|
|
485
|
+
magnetEnabled,
|
|
486
|
+
onRectChange,
|
|
487
|
+
onSelect,
|
|
488
|
+
onCancel
|
|
489
|
+
}) {
|
|
710
490
|
const [snappedX, setSnappedX] = useState4(false);
|
|
711
491
|
const mode = useRef2("none");
|
|
712
492
|
const start = useRef2({ x: 0, y: 0 });
|
|
713
493
|
const snapRef = useRef2({ x: 0, y: 0, w: 0, h: 0 });
|
|
714
494
|
const corner = useRef2("br");
|
|
715
|
-
const
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (!magnet) {
|
|
495
|
+
const ratio = useMemo(() => getAspectRatio(aspect), [aspect]);
|
|
496
|
+
const applySnap = useCallback3(
|
|
497
|
+
(nextRect) => {
|
|
498
|
+
if (!magnetEnabled) {
|
|
720
499
|
setSnappedX(false);
|
|
721
|
-
return
|
|
500
|
+
return nextRect;
|
|
722
501
|
}
|
|
723
|
-
const
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
if (Math.abs(centerX - viewCenterX) < SNAP_THRESHOLD) {
|
|
502
|
+
const centerX = nextRect.x + nextRect.w / 2;
|
|
503
|
+
const viewportCenterX = window.innerWidth / 2;
|
|
504
|
+
if (Math.abs(centerX - viewportCenterX) < SNAP_THRESHOLD) {
|
|
727
505
|
setSnappedX(true);
|
|
728
|
-
return { ...
|
|
506
|
+
return { ...nextRect, x: viewportCenterX - nextRect.w / 2 };
|
|
729
507
|
}
|
|
730
508
|
setSnappedX(false);
|
|
731
|
-
return
|
|
509
|
+
return nextRect;
|
|
732
510
|
},
|
|
733
|
-
[
|
|
511
|
+
[magnetEnabled]
|
|
734
512
|
);
|
|
735
513
|
useEffect3(() => {
|
|
736
514
|
const onKey = (e) => {
|
|
737
|
-
if (e.target?.tagName === "INPUT") {
|
|
738
|
-
if (e.key === "Escape") e.target.blur();
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
515
|
if (e.key === "Escape") {
|
|
742
|
-
|
|
743
|
-
setPlaced(false);
|
|
744
|
-
setRect(null);
|
|
745
|
-
} else {
|
|
746
|
-
onCancel();
|
|
747
|
-
}
|
|
748
|
-
} else if (e.key === "Enter" && placed && rect) {
|
|
749
|
-
onSelect({
|
|
750
|
-
x: Math.round(rect.x),
|
|
751
|
-
y: Math.round(rect.y),
|
|
752
|
-
width: Math.round(rect.w),
|
|
753
|
-
height: Math.round(rect.h)
|
|
754
|
-
});
|
|
516
|
+
onCancel();
|
|
755
517
|
}
|
|
756
518
|
};
|
|
757
519
|
document.addEventListener("keydown", onKey);
|
|
758
520
|
return () => document.removeEventListener("keydown", onKey);
|
|
759
|
-
}, [
|
|
760
|
-
const hitCorner =
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
return c;
|
|
521
|
+
}, [onCancel]);
|
|
522
|
+
const hitCorner = useCallback3((mx, my, currentRect) => {
|
|
523
|
+
const corners = [
|
|
524
|
+
["tl", currentRect.x, currentRect.y],
|
|
525
|
+
["tr", currentRect.x + currentRect.w, currentRect.y],
|
|
526
|
+
["bl", currentRect.x, currentRect.y + currentRect.h],
|
|
527
|
+
["br", currentRect.x + currentRect.w, currentRect.y + currentRect.h]
|
|
528
|
+
];
|
|
529
|
+
for (const [hitCorner2, cx, cy] of corners) {
|
|
530
|
+
if (Math.abs(mx - cx) <= HANDLE_HIT && Math.abs(my - cy) <= HANDLE_HIT) {
|
|
531
|
+
return hitCorner2;
|
|
771
532
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
(mx, my, r) => mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h,
|
|
533
|
+
}
|
|
534
|
+
return null;
|
|
535
|
+
}, []);
|
|
536
|
+
const hitInside = useCallback3(
|
|
537
|
+
(mx, my, currentRect) => mx >= currentRect.x && mx <= currentRect.x + currentRect.w && my >= currentRect.y && my <= currentRect.y + currentRect.h,
|
|
778
538
|
[]
|
|
779
539
|
);
|
|
780
|
-
const onDown =
|
|
540
|
+
const onDown = useCallback3(
|
|
781
541
|
(e) => {
|
|
782
|
-
if (panelRef.current?.contains(e.target)) return;
|
|
783
542
|
e.preventDefault();
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
if (c) {
|
|
543
|
+
const mx = e.clientX;
|
|
544
|
+
const my = e.clientY;
|
|
545
|
+
if (rect) {
|
|
546
|
+
const activeCorner = hitCorner(mx, my, rect);
|
|
547
|
+
if (activeCorner) {
|
|
790
548
|
mode.current = "resizing";
|
|
791
|
-
corner.current =
|
|
549
|
+
corner.current = activeCorner;
|
|
792
550
|
start.current = { x: mx, y: my };
|
|
793
551
|
snapRef.current = { ...rect };
|
|
794
552
|
return;
|
|
@@ -799,78 +557,79 @@ function Selector({ onSelect, onCancel }) {
|
|
|
799
557
|
snapRef.current = { ...rect };
|
|
800
558
|
return;
|
|
801
559
|
}
|
|
802
|
-
setPlaced(false);
|
|
803
560
|
}
|
|
804
561
|
mode.current = "drawing";
|
|
805
562
|
start.current = { x: mx, y: my };
|
|
806
|
-
|
|
563
|
+
onRectChange({ x: mx, y: my, w: 0, h: 0 });
|
|
807
564
|
},
|
|
808
|
-
[
|
|
565
|
+
[hitCorner, hitInside, onRectChange, rect]
|
|
809
566
|
);
|
|
810
|
-
const onMove =
|
|
567
|
+
const onMove = useCallback3(
|
|
811
568
|
(e) => {
|
|
812
|
-
const mx = e.clientX
|
|
569
|
+
const mx = e.clientX;
|
|
570
|
+
const my = e.clientY;
|
|
813
571
|
if (mode.current === "drawing") {
|
|
814
|
-
const sx = start.current.x
|
|
815
|
-
|
|
816
|
-
let
|
|
572
|
+
const sx = start.current.x;
|
|
573
|
+
const sy = start.current.y;
|
|
574
|
+
let x = Math.min(sx, mx);
|
|
575
|
+
let y = Math.min(sy, my);
|
|
576
|
+
let w = Math.abs(mx - sx);
|
|
577
|
+
let h = Math.abs(my - sy);
|
|
817
578
|
if (ratio > 0) {
|
|
818
579
|
h = w / ratio;
|
|
819
|
-
if (my < sy)
|
|
580
|
+
if (my < sy) {
|
|
581
|
+
y = sy - h;
|
|
582
|
+
}
|
|
820
583
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
584
|
+
onRectChange(applySnap({ x, y, w, h }));
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (mode.current === "moving") {
|
|
588
|
+
const dx = mx - start.current.x;
|
|
589
|
+
const dy = my - start.current.y;
|
|
590
|
+
onRectChange(
|
|
825
591
|
applySnap({
|
|
826
592
|
...snapRef.current,
|
|
827
593
|
x: snapRef.current.x + dx,
|
|
828
594
|
y: snapRef.current.y + dy
|
|
829
595
|
})
|
|
830
596
|
);
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (mode.current === "resizing") {
|
|
600
|
+
const original = snapRef.current;
|
|
601
|
+
const nextRect = { ...original };
|
|
602
|
+
if (corner.current === "br") {
|
|
603
|
+
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
604
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
605
|
+
} else if (corner.current === "bl") {
|
|
606
|
+
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
607
|
+
nextRect.x = original.x + original.w - nextRect.w;
|
|
608
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
609
|
+
} else if (corner.current === "tr") {
|
|
610
|
+
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
611
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
612
|
+
nextRect.y = original.y + original.h - nextRect.h;
|
|
846
613
|
} else {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
614
|
+
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
615
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
616
|
+
nextRect.x = original.x + original.w - nextRect.w;
|
|
617
|
+
nextRect.y = original.y + original.h - nextRect.h;
|
|
851
618
|
}
|
|
852
|
-
|
|
853
|
-
} else if (placed && rect) {
|
|
854
|
-
const c = hitCorner(mx, my, rect);
|
|
855
|
-
if (c === "tl" || c === "br") setCursor("nwse-resize");
|
|
856
|
-
else if (c === "tr" || c === "bl") setCursor("nesw-resize");
|
|
857
|
-
else if (hitInside(mx, my, rect)) setCursor("move");
|
|
858
|
-
else setCursor("crosshair");
|
|
619
|
+
onRectChange(applySnap(nextRect));
|
|
859
620
|
}
|
|
860
621
|
},
|
|
861
|
-
[
|
|
622
|
+
[applySnap, onRectChange, ratio]
|
|
862
623
|
);
|
|
863
|
-
const onUp =
|
|
624
|
+
const onUp = useCallback3(
|
|
864
625
|
(e) => {
|
|
865
|
-
const
|
|
866
|
-
if (
|
|
867
|
-
if (rect.w
|
|
868
|
-
|
|
869
|
-
} else {
|
|
870
|
-
setRect(null);
|
|
626
|
+
const previousMode = mode.current;
|
|
627
|
+
if (previousMode === "drawing" && rect) {
|
|
628
|
+
if (rect.w < MIN_SIZE || rect.h < MIN_SIZE) {
|
|
629
|
+
onRectChange(null);
|
|
871
630
|
}
|
|
872
631
|
}
|
|
873
|
-
if (
|
|
632
|
+
if (previousMode === "moving" && rect) {
|
|
874
633
|
const dx = Math.abs(e.clientX - start.current.x);
|
|
875
634
|
const dy = Math.abs(e.clientY - start.current.y);
|
|
876
635
|
if (dx < 3 && dy < 3) {
|
|
@@ -884,51 +643,10 @@ function Selector({ onSelect, onCancel }) {
|
|
|
884
643
|
}
|
|
885
644
|
mode.current = "none";
|
|
886
645
|
},
|
|
887
|
-
[
|
|
888
|
-
);
|
|
889
|
-
const setSize = useCallback4(
|
|
890
|
-
(field, v) => {
|
|
891
|
-
const n = parseInt(v, 10);
|
|
892
|
-
if (isNaN(n) || n < MIN_SIZE || !rect) return;
|
|
893
|
-
if (field === "w") {
|
|
894
|
-
setRect({ ...rect, w: n, h: ratio > 0 ? n / ratio : rect.h });
|
|
895
|
-
} else {
|
|
896
|
-
setRect({ ...rect, h: n, w: ratio > 0 ? n * ratio : rect.w });
|
|
897
|
-
}
|
|
898
|
-
},
|
|
899
|
-
[rect, ratio]
|
|
646
|
+
[onRectChange, onSelect, rect]
|
|
900
647
|
);
|
|
901
|
-
const setPos = useCallback4(
|
|
902
|
-
(field, v) => {
|
|
903
|
-
const n = parseInt(v, 10);
|
|
904
|
-
if (isNaN(n) || !rect) return;
|
|
905
|
-
setRect({ ...rect, [field]: n });
|
|
906
|
-
},
|
|
907
|
-
[rect]
|
|
908
|
-
);
|
|
909
|
-
const savePreset = useCallback4(() => {
|
|
910
|
-
if (!rect) return;
|
|
911
|
-
const label = `${Math.round(rect.w)}\xD7${Math.round(rect.h)}`;
|
|
912
|
-
const next = [
|
|
913
|
-
...presets.filter((p) => p.label !== label),
|
|
914
|
-
{ label, rect: { ...rect } }
|
|
915
|
-
];
|
|
916
|
-
setPresets(next);
|
|
917
|
-
try {
|
|
918
|
-
localStorage.setItem("ab-area-presets", JSON.stringify(next));
|
|
919
|
-
} catch {
|
|
920
|
-
}
|
|
921
|
-
setSavedOpen(false);
|
|
922
|
-
}, [rect, presets]);
|
|
923
|
-
const loadPreset = useCallback4((p) => {
|
|
924
|
-
setRect({ ...p.rect });
|
|
925
|
-
setPlaced(true);
|
|
926
|
-
setSavedOpen(false);
|
|
927
|
-
}, []);
|
|
928
|
-
const activeCursor = mode.current === "moving" ? "move" : mode.current === "resizing" ? "nwse-resize" : mode.current === "drawing" ? "crosshair" : cursor;
|
|
929
|
-
const panelAbove = rect && rect.y + rect.h + PANEL_HEIGHT_EST > window.innerHeight;
|
|
930
648
|
const hasRect = rect && rect.w > 0 && rect.h > 0;
|
|
931
|
-
return /* @__PURE__ */
|
|
649
|
+
return /* @__PURE__ */ jsxs2(
|
|
932
650
|
"div",
|
|
933
651
|
{
|
|
934
652
|
"data-afterbefore": "true",
|
|
@@ -938,8 +656,8 @@ function Selector({ onSelect, onCancel }) {
|
|
|
938
656
|
style: {
|
|
939
657
|
position: "fixed",
|
|
940
658
|
inset: 0,
|
|
941
|
-
zIndex:
|
|
942
|
-
cursor:
|
|
659
|
+
zIndex: 2147483646,
|
|
660
|
+
cursor: CAMERA_CURSOR
|
|
943
661
|
},
|
|
944
662
|
children: [
|
|
945
663
|
snappedX && /* @__PURE__ */ jsx3(
|
|
@@ -951,34 +669,84 @@ function Selector({ onSelect, onCancel }) {
|
|
|
951
669
|
top: 0,
|
|
952
670
|
bottom: 0,
|
|
953
671
|
width: 0,
|
|
954
|
-
borderLeft: "1px solid rgba(
|
|
672
|
+
borderLeft: "1px solid rgba(56, 189, 248, 0.55)",
|
|
955
673
|
pointerEvents: "none",
|
|
956
674
|
zIndex: 2
|
|
957
675
|
}
|
|
958
676
|
}
|
|
959
677
|
),
|
|
960
|
-
/* @__PURE__ */
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
${rect.x + rect.w}px ${rect.y + rect.h}px,
|
|
974
|
-
${rect.x + rect.w}px ${rect.y}px,
|
|
975
|
-
${rect.x}px ${rect.y}px
|
|
976
|
-
)`
|
|
977
|
-
} : {}
|
|
678
|
+
hasRect ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
679
|
+
/* @__PURE__ */ jsx3(
|
|
680
|
+
"div",
|
|
681
|
+
{
|
|
682
|
+
style: {
|
|
683
|
+
position: "absolute",
|
|
684
|
+
left: 0,
|
|
685
|
+
top: 0,
|
|
686
|
+
width: "100%",
|
|
687
|
+
height: rect.y,
|
|
688
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
689
|
+
pointerEvents: "none"
|
|
690
|
+
}
|
|
978
691
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
692
|
+
),
|
|
693
|
+
/* @__PURE__ */ jsx3(
|
|
694
|
+
"div",
|
|
695
|
+
{
|
|
696
|
+
style: {
|
|
697
|
+
position: "absolute",
|
|
698
|
+
left: 0,
|
|
699
|
+
top: rect.y,
|
|
700
|
+
width: rect.x,
|
|
701
|
+
height: rect.h,
|
|
702
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
703
|
+
pointerEvents: "none"
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
),
|
|
707
|
+
/* @__PURE__ */ jsx3(
|
|
708
|
+
"div",
|
|
709
|
+
{
|
|
710
|
+
style: {
|
|
711
|
+
position: "absolute",
|
|
712
|
+
left: rect.x + rect.w,
|
|
713
|
+
top: rect.y,
|
|
714
|
+
width: `calc(100% - ${rect.x + rect.w}px)`,
|
|
715
|
+
height: rect.h,
|
|
716
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
717
|
+
pointerEvents: "none"
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
),
|
|
721
|
+
/* @__PURE__ */ jsx3(
|
|
722
|
+
"div",
|
|
723
|
+
{
|
|
724
|
+
style: {
|
|
725
|
+
position: "absolute",
|
|
726
|
+
left: 0,
|
|
727
|
+
top: rect.y + rect.h,
|
|
728
|
+
width: "100%",
|
|
729
|
+
height: `calc(100% - ${rect.y + rect.h}px)`,
|
|
730
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
731
|
+
pointerEvents: "none"
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
),
|
|
735
|
+
/* @__PURE__ */ jsx3(
|
|
736
|
+
"div",
|
|
737
|
+
{
|
|
738
|
+
style: {
|
|
739
|
+
position: "absolute",
|
|
740
|
+
left: rect.x,
|
|
741
|
+
top: rect.y,
|
|
742
|
+
width: rect.w,
|
|
743
|
+
height: rect.h,
|
|
744
|
+
background: "rgba(125, 211, 252, 0.08)",
|
|
745
|
+
pointerEvents: "none",
|
|
746
|
+
borderRadius: 12
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
),
|
|
982
750
|
/* @__PURE__ */ jsx3(
|
|
983
751
|
"div",
|
|
984
752
|
{
|
|
@@ -989,17 +757,19 @@ function Selector({ onSelect, onCancel }) {
|
|
|
989
757
|
width: rect.w,
|
|
990
758
|
height: rect.h,
|
|
991
759
|
border: "1.5px dashed rgba(255, 255, 255, 0.45)",
|
|
992
|
-
|
|
760
|
+
borderRadius: 12,
|
|
761
|
+
pointerEvents: "none",
|
|
762
|
+
boxShadow: "0 0 0 1px rgba(125, 211, 252, 0.38)"
|
|
993
763
|
}
|
|
994
764
|
}
|
|
995
765
|
),
|
|
996
|
-
|
|
766
|
+
[1, 2].map((line) => /* @__PURE__ */ jsxs2(React3.Fragment, { children: [
|
|
997
767
|
/* @__PURE__ */ jsx3(
|
|
998
768
|
"div",
|
|
999
769
|
{
|
|
1000
770
|
style: {
|
|
1001
771
|
position: "absolute",
|
|
1002
|
-
left: rect.x + rect.w *
|
|
772
|
+
left: rect.x + rect.w * line / 3,
|
|
1003
773
|
top: rect.y,
|
|
1004
774
|
width: 0,
|
|
1005
775
|
height: rect.h,
|
|
@@ -1014,7 +784,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1014
784
|
style: {
|
|
1015
785
|
position: "absolute",
|
|
1016
786
|
left: rect.x,
|
|
1017
|
-
top: rect.y + rect.h *
|
|
787
|
+
top: rect.y + rect.h * line / 3,
|
|
1018
788
|
width: rect.w,
|
|
1019
789
|
height: 0,
|
|
1020
790
|
borderTop: "1px dashed rgba(255, 255, 255, 0.18)",
|
|
@@ -1022,327 +792,521 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1022
792
|
}
|
|
1023
793
|
}
|
|
1024
794
|
)
|
|
1025
|
-
] },
|
|
1026
|
-
|
|
795
|
+
] }, line)),
|
|
796
|
+
[
|
|
1027
797
|
[rect.x, rect.y],
|
|
1028
798
|
[rect.x + rect.w, rect.y],
|
|
1029
799
|
[rect.x, rect.y + rect.h],
|
|
1030
800
|
[rect.x + rect.w, rect.y + rect.h]
|
|
1031
|
-
].map(([cx, cy],
|
|
801
|
+
].map(([cx, cy], index) => /* @__PURE__ */ jsx3(
|
|
802
|
+
"div",
|
|
803
|
+
{
|
|
804
|
+
style: {
|
|
805
|
+
position: "absolute",
|
|
806
|
+
left: cx - HANDLE_R,
|
|
807
|
+
top: cy - HANDLE_R,
|
|
808
|
+
width: HANDLE_R * 2,
|
|
809
|
+
height: HANDLE_R * 2,
|
|
810
|
+
borderRadius: "50%",
|
|
811
|
+
border: "2px solid rgba(255, 255, 255, 0.8)",
|
|
812
|
+
background: "rgba(0, 0, 0, 0.25)",
|
|
813
|
+
pointerEvents: "none"
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
index
|
|
817
|
+
))
|
|
818
|
+
] }) : /* @__PURE__ */ jsx3(
|
|
819
|
+
"div",
|
|
820
|
+
{
|
|
821
|
+
style: {
|
|
822
|
+
position: "absolute",
|
|
823
|
+
inset: 0,
|
|
824
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
825
|
+
pointerEvents: "none"
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
)
|
|
829
|
+
]
|
|
830
|
+
}
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// src/overlay/ui/toolbar.tsx
|
|
835
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
836
|
+
var MODES = [
|
|
837
|
+
{ mode: "area", label: "Capture Selected Area", icon: Crop },
|
|
838
|
+
{ mode: "viewport", label: "Capture Viewport", icon: Monitor },
|
|
839
|
+
{ mode: "fullpage", label: "Capture Full Page", icon: FileText },
|
|
840
|
+
{ mode: "component", label: "Capture Component", icon: MousePointer2 }
|
|
841
|
+
];
|
|
842
|
+
function Toolbar({
|
|
843
|
+
selectedMode,
|
|
844
|
+
onModeChange,
|
|
845
|
+
onCapture,
|
|
846
|
+
onCancel,
|
|
847
|
+
magnetEnabled,
|
|
848
|
+
onMagnetChange,
|
|
849
|
+
areaSelectionActive,
|
|
850
|
+
areaRect,
|
|
851
|
+
areaAspect,
|
|
852
|
+
areaPresets,
|
|
853
|
+
onAreaSizeChange,
|
|
854
|
+
onAreaPositionChange,
|
|
855
|
+
onAreaAspectChange,
|
|
856
|
+
onAreaSavePreset,
|
|
857
|
+
onAreaLoadPreset
|
|
858
|
+
}) {
|
|
859
|
+
const [settingsOpen, setSettingsOpen] = useState5(false);
|
|
860
|
+
const [aspectOpen, setAspectOpen] = useState5(false);
|
|
861
|
+
const [savedOpen, setSavedOpen] = useState5(false);
|
|
862
|
+
const showAreaControls = selectedMode === "area" && areaSelectionActive && areaRect !== null;
|
|
863
|
+
const activeAreaRect = showAreaControls ? areaRect : null;
|
|
864
|
+
useEffect4(() => {
|
|
865
|
+
const onKey = (e) => {
|
|
866
|
+
if (e.target?.tagName === "INPUT") {
|
|
867
|
+
if (e.key === "Escape") {
|
|
868
|
+
e.target.blur();
|
|
869
|
+
}
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (e.key === "Escape") {
|
|
873
|
+
if (settingsOpen) {
|
|
874
|
+
setSettingsOpen(false);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (aspectOpen) {
|
|
878
|
+
setAspectOpen(false);
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (savedOpen) {
|
|
882
|
+
setSavedOpen(false);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
onCancel();
|
|
886
|
+
} else if (e.key === "Enter") {
|
|
887
|
+
onCapture(selectedMode);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
document.addEventListener("keydown", onKey);
|
|
891
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
892
|
+
}, [aspectOpen, onCancel, onCapture, savedOpen, selectedMode, settingsOpen]);
|
|
893
|
+
return /* @__PURE__ */ jsxs3(
|
|
894
|
+
"div",
|
|
895
|
+
{
|
|
896
|
+
"data-afterbefore": "true",
|
|
897
|
+
style: {
|
|
898
|
+
position: "fixed",
|
|
899
|
+
bottom: 48,
|
|
900
|
+
left: "50%",
|
|
901
|
+
transform: "translateX(-50%)",
|
|
902
|
+
zIndex: 2147483647,
|
|
903
|
+
display: "flex",
|
|
904
|
+
alignItems: "center",
|
|
905
|
+
gap: 10,
|
|
906
|
+
flexWrap: "wrap",
|
|
907
|
+
justifyContent: "center",
|
|
908
|
+
maxWidth: "min(calc(100vw - 32px), 1120px)",
|
|
909
|
+
background: "rgba(32, 32, 36, 0.92)",
|
|
910
|
+
backdropFilter: "blur(20px)",
|
|
911
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
912
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
913
|
+
borderRadius: 18,
|
|
914
|
+
padding: "6px 10px",
|
|
915
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
916
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
917
|
+
},
|
|
918
|
+
children: [
|
|
919
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 0 }, children: [
|
|
920
|
+
/* @__PURE__ */ jsx4(CloseButton, { onClick: onCancel }),
|
|
921
|
+
/* @__PURE__ */ jsx4("div", { style: { display: "flex", alignItems: "center", gap: 2, padding: "0 4px" }, children: MODES.map(({ mode, label, icon: Icon2 }) => /* @__PURE__ */ jsx4(
|
|
922
|
+
ModeButton,
|
|
923
|
+
{
|
|
924
|
+
label,
|
|
925
|
+
selected: selectedMode === mode,
|
|
926
|
+
onClick: () => {
|
|
927
|
+
setSettingsOpen(false);
|
|
928
|
+
onModeChange(mode);
|
|
929
|
+
},
|
|
930
|
+
children: /* @__PURE__ */ jsx4(Icon2, { size: 18, strokeWidth: 1.7 })
|
|
931
|
+
},
|
|
932
|
+
mode
|
|
933
|
+
)) }),
|
|
934
|
+
/* @__PURE__ */ jsx4(Separator, {}),
|
|
935
|
+
/* @__PURE__ */ jsx4(
|
|
936
|
+
SettingsButton,
|
|
937
|
+
{
|
|
938
|
+
open: settingsOpen,
|
|
939
|
+
onClick: () => {
|
|
940
|
+
setAspectOpen(false);
|
|
941
|
+
setSavedOpen(false);
|
|
942
|
+
setSettingsOpen((prev) => !prev);
|
|
943
|
+
},
|
|
944
|
+
magnetEnabled,
|
|
945
|
+
onMagnetChange
|
|
946
|
+
}
|
|
947
|
+
),
|
|
948
|
+
/* @__PURE__ */ jsx4(
|
|
949
|
+
CaptureButton,
|
|
950
|
+
{
|
|
951
|
+
label: showAreaControls ? "Capture Area" : "Capture",
|
|
952
|
+
onClick: () => onCapture(selectedMode)
|
|
953
|
+
}
|
|
954
|
+
)
|
|
955
|
+
] }),
|
|
956
|
+
activeAreaRect && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
957
|
+
/* @__PURE__ */ jsx4(Separator, { vertical: false }),
|
|
958
|
+
/* @__PURE__ */ jsxs3(
|
|
959
|
+
"div",
|
|
960
|
+
{
|
|
961
|
+
style: {
|
|
962
|
+
display: "flex",
|
|
963
|
+
alignItems: "center",
|
|
964
|
+
gap: 8,
|
|
965
|
+
flexWrap: "wrap",
|
|
966
|
+
justifyContent: "center"
|
|
967
|
+
},
|
|
968
|
+
children: [
|
|
969
|
+
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Size", children: [
|
|
970
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.w), onChange: (value) => onAreaSizeChange("w", value) }),
|
|
971
|
+
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
972
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.h), onChange: (value) => onAreaSizeChange("h", value) })
|
|
973
|
+
] }),
|
|
974
|
+
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Position", children: [
|
|
975
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.x), onChange: (value) => onAreaPositionChange("x", value) }),
|
|
976
|
+
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
977
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.y), onChange: (value) => onAreaPositionChange("y", value) })
|
|
978
|
+
] }),
|
|
979
|
+
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
980
|
+
/* @__PURE__ */ jsxs3(
|
|
981
|
+
DropButton,
|
|
982
|
+
{
|
|
983
|
+
active: areaAspect !== "Free",
|
|
984
|
+
onClick: () => {
|
|
985
|
+
setSavedOpen(false);
|
|
986
|
+
setAspectOpen((prev) => !prev);
|
|
987
|
+
},
|
|
988
|
+
children: [
|
|
989
|
+
areaAspect,
|
|
990
|
+
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
991
|
+
]
|
|
992
|
+
}
|
|
993
|
+
),
|
|
994
|
+
aspectOpen && /* @__PURE__ */ jsx4(DropMenu, { children: AREA_ASPECT_RATIOS.map((item) => /* @__PURE__ */ jsx4(
|
|
995
|
+
DropItem,
|
|
996
|
+
{
|
|
997
|
+
active: item.label === areaAspect,
|
|
998
|
+
onClick: () => {
|
|
999
|
+
onAreaAspectChange(item.label);
|
|
1000
|
+
setAspectOpen(false);
|
|
1001
|
+
},
|
|
1002
|
+
children: item.label
|
|
1003
|
+
},
|
|
1004
|
+
item.label
|
|
1005
|
+
)) })
|
|
1006
|
+
] }),
|
|
1007
|
+
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1008
|
+
/* @__PURE__ */ jsxs3(
|
|
1009
|
+
DropButton,
|
|
1010
|
+
{
|
|
1011
|
+
onClick: () => {
|
|
1012
|
+
setAspectOpen(false);
|
|
1013
|
+
setSavedOpen((prev) => !prev);
|
|
1014
|
+
},
|
|
1015
|
+
children: [
|
|
1016
|
+
/* @__PURE__ */ jsx4(Save, { size: 14, strokeWidth: 1.8 }),
|
|
1017
|
+
"Saved",
|
|
1018
|
+
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
1019
|
+
]
|
|
1020
|
+
}
|
|
1021
|
+
),
|
|
1022
|
+
savedOpen && /* @__PURE__ */ jsxs3(DropMenu, { children: [
|
|
1023
|
+
/* @__PURE__ */ jsx4(DropItem, { accent: true, onClick: onAreaSavePreset, children: "Save current" }),
|
|
1024
|
+
areaPresets.length > 0 && /* @__PURE__ */ jsx4(MenuDivider, {}),
|
|
1025
|
+
areaPresets.map((preset) => /* @__PURE__ */ jsx4(
|
|
1026
|
+
DropItem,
|
|
1027
|
+
{
|
|
1028
|
+
onClick: () => {
|
|
1029
|
+
onAreaLoadPreset(preset);
|
|
1030
|
+
setSavedOpen(false);
|
|
1031
|
+
},
|
|
1032
|
+
children: preset.label
|
|
1033
|
+
},
|
|
1034
|
+
preset.label
|
|
1035
|
+
)),
|
|
1036
|
+
areaPresets.length === 0 && /* @__PURE__ */ jsx4(
|
|
1037
|
+
"div",
|
|
1038
|
+
{
|
|
1039
|
+
style: {
|
|
1040
|
+
padding: "6px 12px",
|
|
1041
|
+
color: "rgba(255,255,255,0.3)",
|
|
1042
|
+
fontSize: 12
|
|
1043
|
+
},
|
|
1044
|
+
children: "No saved areas"
|
|
1045
|
+
}
|
|
1046
|
+
)
|
|
1047
|
+
] })
|
|
1048
|
+
] })
|
|
1049
|
+
]
|
|
1050
|
+
}
|
|
1051
|
+
)
|
|
1052
|
+
] })
|
|
1053
|
+
]
|
|
1054
|
+
}
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
function CloseButton({ onClick }) {
|
|
1058
|
+
const [hovered, setHovered] = useState5(false);
|
|
1059
|
+
return /* @__PURE__ */ jsx4(
|
|
1060
|
+
"button",
|
|
1061
|
+
{
|
|
1062
|
+
onClick,
|
|
1063
|
+
onMouseEnter: () => setHovered(true),
|
|
1064
|
+
onMouseLeave: () => setHovered(false),
|
|
1065
|
+
style: circleButtonStyle(hovered, true),
|
|
1066
|
+
children: /* @__PURE__ */ jsx4(X, { size: 18, strokeWidth: 1.9 })
|
|
1067
|
+
}
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
function ModeButton({
|
|
1071
|
+
children,
|
|
1072
|
+
label,
|
|
1073
|
+
selected,
|
|
1074
|
+
onClick
|
|
1075
|
+
}) {
|
|
1076
|
+
const [hovered, setHovered] = useState5(false);
|
|
1077
|
+
return /* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1078
|
+
hovered && /* @__PURE__ */ jsx4(
|
|
1079
|
+
"div",
|
|
1080
|
+
{
|
|
1081
|
+
style: {
|
|
1082
|
+
position: "absolute",
|
|
1083
|
+
left: "50%",
|
|
1084
|
+
bottom: "calc(100% + 10px)",
|
|
1085
|
+
transform: "translateX(-50%)",
|
|
1086
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1087
|
+
backdropFilter: "blur(20px)",
|
|
1088
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
1089
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1090
|
+
borderRadius: 8,
|
|
1091
|
+
padding: "5px 10px",
|
|
1092
|
+
color: "rgba(255, 255, 255, 0.88)",
|
|
1093
|
+
fontSize: 12,
|
|
1094
|
+
whiteSpace: "nowrap",
|
|
1095
|
+
boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
|
|
1096
|
+
pointerEvents: "none"
|
|
1097
|
+
},
|
|
1098
|
+
children: label
|
|
1099
|
+
}
|
|
1100
|
+
),
|
|
1101
|
+
/* @__PURE__ */ jsx4(
|
|
1102
|
+
"button",
|
|
1103
|
+
{
|
|
1104
|
+
onClick,
|
|
1105
|
+
onMouseEnter: () => setHovered(true),
|
|
1106
|
+
onMouseLeave: () => setHovered(false),
|
|
1107
|
+
style: {
|
|
1108
|
+
width: 42,
|
|
1109
|
+
height: 40,
|
|
1110
|
+
borderRadius: 12,
|
|
1111
|
+
border: "none",
|
|
1112
|
+
background: selected ? "rgba(255, 255, 255, 0.15)" : hovered ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
1113
|
+
display: "flex",
|
|
1114
|
+
alignItems: "center",
|
|
1115
|
+
justifyContent: "center",
|
|
1116
|
+
cursor: "pointer",
|
|
1117
|
+
padding: 0,
|
|
1118
|
+
color: selected ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
1119
|
+
transition: "background 0.12s ease, color 0.12s ease"
|
|
1120
|
+
},
|
|
1121
|
+
children
|
|
1122
|
+
}
|
|
1123
|
+
)
|
|
1124
|
+
] });
|
|
1125
|
+
}
|
|
1126
|
+
function SettingsButton({
|
|
1127
|
+
open,
|
|
1128
|
+
onClick,
|
|
1129
|
+
magnetEnabled,
|
|
1130
|
+
onMagnetChange
|
|
1131
|
+
}) {
|
|
1132
|
+
const [hovered, setHovered] = useState5(false);
|
|
1133
|
+
return /* @__PURE__ */ jsxs3("div", { style: { position: "relative", marginRight: 6 }, children: [
|
|
1134
|
+
/* @__PURE__ */ jsx4(
|
|
1135
|
+
"button",
|
|
1136
|
+
{
|
|
1137
|
+
onClick,
|
|
1138
|
+
onMouseEnter: () => setHovered(true),
|
|
1139
|
+
onMouseLeave: () => setHovered(false),
|
|
1140
|
+
style: {
|
|
1141
|
+
...circleButtonStyle(open || hovered, false),
|
|
1142
|
+
color: "rgba(255, 255, 255, 0.58)"
|
|
1143
|
+
},
|
|
1144
|
+
children: /* @__PURE__ */ jsx4(Settings2, { size: 18, strokeWidth: 1.7 })
|
|
1145
|
+
}
|
|
1146
|
+
),
|
|
1147
|
+
open && /* @__PURE__ */ jsxs3(
|
|
1148
|
+
"div",
|
|
1149
|
+
{
|
|
1150
|
+
style: {
|
|
1151
|
+
position: "absolute",
|
|
1152
|
+
left: "50%",
|
|
1153
|
+
bottom: "calc(100% + 12px)",
|
|
1154
|
+
transform: "translateX(-50%)",
|
|
1155
|
+
minWidth: 184,
|
|
1156
|
+
padding: "10px 12px",
|
|
1157
|
+
borderRadius: 12,
|
|
1158
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1159
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1160
|
+
boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
|
|
1161
|
+
backdropFilter: "blur(20px)",
|
|
1162
|
+
WebkitBackdropFilter: "blur(20px)"
|
|
1163
|
+
},
|
|
1164
|
+
children: [
|
|
1165
|
+
/* @__PURE__ */ jsx4(
|
|
1032
1166
|
"div",
|
|
1033
1167
|
{
|
|
1034
1168
|
style: {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
i
|
|
1047
|
-
)),
|
|
1048
|
-
placed && /* @__PURE__ */ jsxs3(
|
|
1049
|
-
"div",
|
|
1169
|
+
fontSize: 11,
|
|
1170
|
+
color: "rgba(255, 255, 255, 0.46)",
|
|
1171
|
+
letterSpacing: "0.03em",
|
|
1172
|
+
textTransform: "uppercase",
|
|
1173
|
+
marginBottom: 10
|
|
1174
|
+
},
|
|
1175
|
+
children: "Area Settings"
|
|
1176
|
+
}
|
|
1177
|
+
),
|
|
1178
|
+
/* @__PURE__ */ jsxs3(
|
|
1179
|
+
"label",
|
|
1050
1180
|
{
|
|
1051
|
-
ref: panelRef,
|
|
1052
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
1053
1181
|
style: {
|
|
1054
|
-
position: "absolute",
|
|
1055
|
-
left: rect.x + rect.w / 2,
|
|
1056
|
-
...panelAbove ? { bottom: window.innerHeight - rect.y + 16 } : { top: rect.y + rect.h + 16 },
|
|
1057
|
-
transform: "translateX(-50%)",
|
|
1058
|
-
background: "rgba(32, 32, 36, 0.92)",
|
|
1059
|
-
backdropFilter: "blur(20px)",
|
|
1060
|
-
WebkitBackdropFilter: "blur(20px)",
|
|
1061
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1062
|
-
borderRadius: 10,
|
|
1063
|
-
padding: "10px 14px",
|
|
1064
1182
|
display: "flex",
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
color: "rgba(255, 255, 255, 0.9)",
|
|
1070
|
-
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
1071
|
-
zIndex: 1
|
|
1183
|
+
alignItems: "center",
|
|
1184
|
+
justifyContent: "space-between",
|
|
1185
|
+
gap: 12,
|
|
1186
|
+
cursor: "pointer"
|
|
1072
1187
|
},
|
|
1073
1188
|
children: [
|
|
1074
|
-
/* @__PURE__ */ jsxs3(Row, { label: "Size", children: [
|
|
1075
|
-
/* @__PURE__ */ jsx3(
|
|
1076
|
-
NumInput,
|
|
1077
|
-
{
|
|
1078
|
-
value: Math.round(rect.w),
|
|
1079
|
-
onChange: (v) => setSize("w", v)
|
|
1080
|
-
}
|
|
1081
|
-
),
|
|
1082
|
-
/* @__PURE__ */ jsx3(Sep, { children: "\xD7" }),
|
|
1083
|
-
/* @__PURE__ */ jsx3(
|
|
1084
|
-
NumInput,
|
|
1085
|
-
{
|
|
1086
|
-
value: Math.round(rect.h),
|
|
1087
|
-
onChange: (v) => setSize("h", v)
|
|
1088
|
-
}
|
|
1089
|
-
),
|
|
1090
|
-
/* @__PURE__ */ jsx3(Unit, { children: "px" })
|
|
1091
|
-
] }),
|
|
1092
|
-
/* @__PURE__ */ jsxs3(Row, { label: "Position", children: [
|
|
1093
|
-
/* @__PURE__ */ jsx3(
|
|
1094
|
-
NumInput,
|
|
1095
|
-
{
|
|
1096
|
-
value: Math.round(rect.x),
|
|
1097
|
-
onChange: (v) => setPos("x", v)
|
|
1098
|
-
}
|
|
1099
|
-
),
|
|
1100
|
-
/* @__PURE__ */ jsx3(Sep, {}),
|
|
1101
|
-
/* @__PURE__ */ jsx3(
|
|
1102
|
-
NumInput,
|
|
1103
|
-
{
|
|
1104
|
-
value: Math.round(rect.y),
|
|
1105
|
-
onChange: (v) => setPos("y", v)
|
|
1106
|
-
}
|
|
1107
|
-
),
|
|
1108
|
-
/* @__PURE__ */ jsx3(Unit, { children: "px" })
|
|
1109
|
-
] }),
|
|
1110
|
-
/* @__PURE__ */ jsx3(
|
|
1111
|
-
"div",
|
|
1112
|
-
{
|
|
1113
|
-
style: {
|
|
1114
|
-
height: 1,
|
|
1115
|
-
background: "rgba(255, 255, 255, 0.08)",
|
|
1116
|
-
margin: "1px 0"
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
),
|
|
1120
1189
|
/* @__PURE__ */ jsxs3(
|
|
1121
|
-
"
|
|
1190
|
+
"span",
|
|
1122
1191
|
{
|
|
1123
|
-
style: {
|
|
1192
|
+
style: {
|
|
1193
|
+
display: "flex",
|
|
1194
|
+
alignItems: "center",
|
|
1195
|
+
gap: 8,
|
|
1196
|
+
color: "rgba(255, 255, 255, 0.88)",
|
|
1197
|
+
fontSize: 13
|
|
1198
|
+
},
|
|
1124
1199
|
children: [
|
|
1125
|
-
/* @__PURE__ */
|
|
1126
|
-
|
|
1127
|
-
DropBtn,
|
|
1128
|
-
{
|
|
1129
|
-
active: aspect !== "Free",
|
|
1130
|
-
onClick: () => {
|
|
1131
|
-
setAspectOpen(!aspectOpen);
|
|
1132
|
-
setSavedOpen(false);
|
|
1133
|
-
},
|
|
1134
|
-
children: [
|
|
1135
|
-
/* @__PURE__ */ jsx3(AspectIcon, {}),
|
|
1136
|
-
aspect === "Free" ? "Free" : aspect,
|
|
1137
|
-
/* @__PURE__ */ jsx3(Chevron, {})
|
|
1138
|
-
]
|
|
1139
|
-
}
|
|
1140
|
-
),
|
|
1141
|
-
aspectOpen && /* @__PURE__ */ jsx3(DropMenu, { children: ASPECT_RATIOS.map((ar) => /* @__PURE__ */ jsx3(
|
|
1142
|
-
DropItem,
|
|
1143
|
-
{
|
|
1144
|
-
active: ar.label === aspect,
|
|
1145
|
-
onClick: () => {
|
|
1146
|
-
setAspect(ar.label);
|
|
1147
|
-
setAspectOpen(false);
|
|
1148
|
-
if (ar.value > 0 && rect) {
|
|
1149
|
-
setRect({ ...rect, h: rect.w / ar.value });
|
|
1150
|
-
}
|
|
1151
|
-
},
|
|
1152
|
-
children: ar.label
|
|
1153
|
-
},
|
|
1154
|
-
ar.label
|
|
1155
|
-
)) })
|
|
1156
|
-
] }),
|
|
1157
|
-
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1158
|
-
/* @__PURE__ */ jsxs3(
|
|
1159
|
-
DropBtn,
|
|
1160
|
-
{
|
|
1161
|
-
onClick: () => {
|
|
1162
|
-
setSavedOpen(!savedOpen);
|
|
1163
|
-
setAspectOpen(false);
|
|
1164
|
-
},
|
|
1165
|
-
children: [
|
|
1166
|
-
/* @__PURE__ */ jsx3(SavedIcon, {}),
|
|
1167
|
-
"Saved",
|
|
1168
|
-
/* @__PURE__ */ jsx3(Chevron, {})
|
|
1169
|
-
]
|
|
1170
|
-
}
|
|
1171
|
-
),
|
|
1172
|
-
savedOpen && /* @__PURE__ */ jsxs3(DropMenu, { children: [
|
|
1173
|
-
/* @__PURE__ */ jsx3(
|
|
1174
|
-
DropItem,
|
|
1175
|
-
{
|
|
1176
|
-
accent: true,
|
|
1177
|
-
onClick: savePreset,
|
|
1178
|
-
children: "Save current"
|
|
1179
|
-
}
|
|
1180
|
-
),
|
|
1181
|
-
presets.length > 0 && /* @__PURE__ */ jsx3(
|
|
1182
|
-
"div",
|
|
1183
|
-
{
|
|
1184
|
-
style: {
|
|
1185
|
-
height: 1,
|
|
1186
|
-
background: "rgba(255,255,255,0.08)",
|
|
1187
|
-
margin: "4px 0"
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
),
|
|
1191
|
-
presets.map((p) => /* @__PURE__ */ jsx3(
|
|
1192
|
-
DropItem,
|
|
1193
|
-
{
|
|
1194
|
-
onClick: () => loadPreset(p),
|
|
1195
|
-
children: p.label
|
|
1196
|
-
},
|
|
1197
|
-
p.label
|
|
1198
|
-
)),
|
|
1199
|
-
presets.length === 0 && /* @__PURE__ */ jsx3(
|
|
1200
|
-
"div",
|
|
1201
|
-
{
|
|
1202
|
-
style: {
|
|
1203
|
-
padding: "6px 12px",
|
|
1204
|
-
color: "rgba(255,255,255,0.3)",
|
|
1205
|
-
fontSize: 12
|
|
1206
|
-
},
|
|
1207
|
-
children: "No saved areas"
|
|
1208
|
-
}
|
|
1209
|
-
)
|
|
1210
|
-
] })
|
|
1211
|
-
] })
|
|
1200
|
+
/* @__PURE__ */ jsx4(Magnet, { size: 15, strokeWidth: 1.8 }),
|
|
1201
|
+
"Magnet snap"
|
|
1212
1202
|
]
|
|
1213
1203
|
}
|
|
1214
1204
|
),
|
|
1215
|
-
/* @__PURE__ */
|
|
1216
|
-
"
|
|
1205
|
+
/* @__PURE__ */ jsx4(
|
|
1206
|
+
"button",
|
|
1217
1207
|
{
|
|
1208
|
+
type: "button",
|
|
1209
|
+
onClick: () => onMagnetChange(!magnetEnabled),
|
|
1218
1210
|
style: {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1211
|
+
width: 38,
|
|
1212
|
+
height: 22,
|
|
1213
|
+
borderRadius: 999,
|
|
1214
|
+
border: "none",
|
|
1215
|
+
background: magnetEnabled ? "#38bdf8" : "rgba(255, 255, 255, 0.18)",
|
|
1216
|
+
position: "relative",
|
|
1217
|
+
cursor: "pointer",
|
|
1218
|
+
padding: 0,
|
|
1219
|
+
transition: "background 0.12s ease"
|
|
1222
1220
|
},
|
|
1223
|
-
children: /* @__PURE__ */
|
|
1224
|
-
|
|
1221
|
+
children: /* @__PURE__ */ jsx4(
|
|
1222
|
+
"span",
|
|
1225
1223
|
{
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1224
|
+
style: {
|
|
1225
|
+
position: "absolute",
|
|
1226
|
+
top: 2,
|
|
1227
|
+
left: magnetEnabled ? 18 : 2,
|
|
1228
|
+
width: 18,
|
|
1229
|
+
height: 18,
|
|
1230
|
+
borderRadius: "50%",
|
|
1231
|
+
background: "#fff",
|
|
1232
|
+
transition: "left 0.12s ease"
|
|
1234
1233
|
}
|
|
1235
1234
|
}
|
|
1236
1235
|
)
|
|
1237
1236
|
}
|
|
1238
|
-
),
|
|
1239
|
-
/* @__PURE__ */ jsx3(
|
|
1240
|
-
"div",
|
|
1241
|
-
{
|
|
1242
|
-
style: {
|
|
1243
|
-
fontSize: 10,
|
|
1244
|
-
color: "rgba(255, 255, 255, 0.25)",
|
|
1245
|
-
textAlign: "center"
|
|
1246
|
-
},
|
|
1247
|
-
children: "Click area or Enter to capture \xB7 Esc to cancel"
|
|
1248
|
-
}
|
|
1249
1237
|
)
|
|
1250
1238
|
]
|
|
1251
1239
|
}
|
|
1252
|
-
),
|
|
1253
|
-
!placed && /* @__PURE__ */ jsxs3(
|
|
1254
|
-
"div",
|
|
1255
|
-
{
|
|
1256
|
-
style: {
|
|
1257
|
-
position: "absolute",
|
|
1258
|
-
left: rect.x + rect.w / 2,
|
|
1259
|
-
top: rect.y + rect.h + 8,
|
|
1260
|
-
transform: "translateX(-50%)",
|
|
1261
|
-
background: "rgba(24, 24, 27, 0.9)",
|
|
1262
|
-
color: "rgba(255, 255, 255, 0.9)",
|
|
1263
|
-
fontSize: 11,
|
|
1264
|
-
fontFamily: "system-ui, -apple-system, monospace",
|
|
1265
|
-
padding: "2px 8px",
|
|
1266
|
-
borderRadius: 4,
|
|
1267
|
-
whiteSpace: "nowrap",
|
|
1268
|
-
pointerEvents: "none"
|
|
1269
|
-
},
|
|
1270
|
-
children: [
|
|
1271
|
-
Math.round(rect.w),
|
|
1272
|
-
" \xD7 ",
|
|
1273
|
-
Math.round(rect.h)
|
|
1274
|
-
]
|
|
1275
|
-
}
|
|
1276
1240
|
)
|
|
1277
|
-
]
|
|
1278
|
-
!rect && /* @__PURE__ */ jsx3(
|
|
1279
|
-
"div",
|
|
1280
|
-
{
|
|
1281
|
-
style: {
|
|
1282
|
-
position: "absolute",
|
|
1283
|
-
top: "50%",
|
|
1284
|
-
left: "50%",
|
|
1285
|
-
transform: "translate(-50%, -50%)",
|
|
1286
|
-
color: "rgba(255, 255, 255, 0.7)",
|
|
1287
|
-
fontSize: 14,
|
|
1288
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
1289
|
-
pointerEvents: "none",
|
|
1290
|
-
textShadow: "0 1px 4px rgba(0, 0, 0, 0.5)"
|
|
1291
|
-
},
|
|
1292
|
-
children: "Drag to select an area \xB7 Esc to cancel"
|
|
1293
|
-
}
|
|
1294
|
-
)
|
|
1295
|
-
]
|
|
1296
|
-
}
|
|
1297
|
-
);
|
|
1298
|
-
}
|
|
1299
|
-
function Row({
|
|
1300
|
-
label,
|
|
1301
|
-
children
|
|
1302
|
-
}) {
|
|
1303
|
-
return /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
1304
|
-
/* @__PURE__ */ jsx3(
|
|
1305
|
-
"span",
|
|
1306
|
-
{
|
|
1307
|
-
style: {
|
|
1308
|
-
width: 36,
|
|
1309
|
-
fontSize: 11,
|
|
1310
|
-
color: "rgba(255, 255, 255, 0.4)",
|
|
1311
|
-
fontWeight: 400,
|
|
1312
|
-
flexShrink: 0
|
|
1313
|
-
},
|
|
1314
|
-
children: label
|
|
1241
|
+
]
|
|
1315
1242
|
}
|
|
1316
|
-
)
|
|
1317
|
-
children
|
|
1243
|
+
)
|
|
1318
1244
|
] });
|
|
1319
1245
|
}
|
|
1320
|
-
function
|
|
1321
|
-
|
|
1322
|
-
|
|
1246
|
+
function CaptureButton({
|
|
1247
|
+
label,
|
|
1248
|
+
onClick
|
|
1249
|
+
}) {
|
|
1250
|
+
const [hovered, setHovered] = useState5(false);
|
|
1251
|
+
return /* @__PURE__ */ jsxs3(
|
|
1252
|
+
"button",
|
|
1323
1253
|
{
|
|
1254
|
+
onClick,
|
|
1255
|
+
onMouseEnter: () => setHovered(true),
|
|
1256
|
+
onMouseLeave: () => setHovered(false),
|
|
1324
1257
|
style: {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1258
|
+
padding: "0 18px",
|
|
1259
|
+
height: 40,
|
|
1260
|
+
borderRadius: 12,
|
|
1261
|
+
border: "none",
|
|
1262
|
+
background: hovered ? "#2f7bf8" : "#3b82f6",
|
|
1263
|
+
color: "white",
|
|
1264
|
+
fontSize: 13,
|
|
1265
|
+
fontWeight: 600,
|
|
1266
|
+
fontFamily: "inherit",
|
|
1267
|
+
cursor: "pointer",
|
|
1268
|
+
whiteSpace: "nowrap",
|
|
1269
|
+
transition: "background 0.12s ease",
|
|
1329
1270
|
flexShrink: 0,
|
|
1330
|
-
|
|
1271
|
+
display: "flex",
|
|
1272
|
+
alignItems: "center",
|
|
1273
|
+
gap: 8
|
|
1331
1274
|
},
|
|
1332
|
-
children:
|
|
1275
|
+
children: [
|
|
1276
|
+
/* @__PURE__ */ jsx4(Camera2, { size: 16, strokeWidth: 1.9 }),
|
|
1277
|
+
label
|
|
1278
|
+
]
|
|
1333
1279
|
}
|
|
1334
1280
|
);
|
|
1335
1281
|
}
|
|
1336
|
-
function
|
|
1337
|
-
|
|
1338
|
-
|
|
1282
|
+
function ControlGroup({
|
|
1283
|
+
label,
|
|
1284
|
+
children
|
|
1285
|
+
}) {
|
|
1286
|
+
return /* @__PURE__ */ jsxs3(
|
|
1287
|
+
"div",
|
|
1339
1288
|
{
|
|
1340
1289
|
style: {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1290
|
+
display: "flex",
|
|
1291
|
+
alignItems: "center",
|
|
1292
|
+
gap: 6,
|
|
1293
|
+
padding: "0 4px"
|
|
1344
1294
|
},
|
|
1345
|
-
children
|
|
1295
|
+
children: [
|
|
1296
|
+
/* @__PURE__ */ jsx4(
|
|
1297
|
+
"span",
|
|
1298
|
+
{
|
|
1299
|
+
style: {
|
|
1300
|
+
fontSize: 11,
|
|
1301
|
+
color: "rgba(255, 255, 255, 0.42)",
|
|
1302
|
+
textTransform: "uppercase",
|
|
1303
|
+
letterSpacing: "0.03em"
|
|
1304
|
+
},
|
|
1305
|
+
children: label
|
|
1306
|
+
}
|
|
1307
|
+
),
|
|
1308
|
+
children
|
|
1309
|
+
]
|
|
1346
1310
|
}
|
|
1347
1311
|
);
|
|
1348
1312
|
}
|
|
@@ -1350,12 +1314,14 @@ function NumInput({
|
|
|
1350
1314
|
value,
|
|
1351
1315
|
onChange
|
|
1352
1316
|
}) {
|
|
1353
|
-
const [editing, setEditing] =
|
|
1354
|
-
const [text, setText] =
|
|
1355
|
-
|
|
1356
|
-
if (!editing)
|
|
1357
|
-
|
|
1358
|
-
|
|
1317
|
+
const [editing, setEditing] = useState5(false);
|
|
1318
|
+
const [text, setText] = useState5(String(value));
|
|
1319
|
+
useEffect4(() => {
|
|
1320
|
+
if (!editing) {
|
|
1321
|
+
setText(String(value));
|
|
1322
|
+
}
|
|
1323
|
+
}, [editing, value]);
|
|
1324
|
+
return /* @__PURE__ */ jsx4(
|
|
1359
1325
|
"input",
|
|
1360
1326
|
{
|
|
1361
1327
|
type: "text",
|
|
@@ -1370,14 +1336,16 @@ function NumInput({
|
|
|
1370
1336
|
},
|
|
1371
1337
|
onChange: (e) => setText(e.target.value),
|
|
1372
1338
|
onKeyDown: (e) => {
|
|
1373
|
-
if (e.key === "Enter")
|
|
1339
|
+
if (e.key === "Enter") {
|
|
1340
|
+
e.target.blur();
|
|
1341
|
+
}
|
|
1374
1342
|
},
|
|
1375
1343
|
style: {
|
|
1376
|
-
width:
|
|
1377
|
-
padding: "
|
|
1344
|
+
width: 54,
|
|
1345
|
+
padding: "4px 6px",
|
|
1378
1346
|
background: "rgba(255, 255, 255, 0.07)",
|
|
1379
1347
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1380
|
-
borderRadius:
|
|
1348
|
+
borderRadius: 7,
|
|
1381
1349
|
color: "rgba(255, 255, 255, 0.9)",
|
|
1382
1350
|
fontSize: 12,
|
|
1383
1351
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
@@ -1387,46 +1355,62 @@ function NumInput({
|
|
|
1387
1355
|
}
|
|
1388
1356
|
);
|
|
1389
1357
|
}
|
|
1390
|
-
function
|
|
1358
|
+
function StaticText({ children }) {
|
|
1359
|
+
return /* @__PURE__ */ jsx4(
|
|
1360
|
+
"span",
|
|
1361
|
+
{
|
|
1362
|
+
style: {
|
|
1363
|
+
fontSize: 11,
|
|
1364
|
+
color: "rgba(255,255,255,0.35)",
|
|
1365
|
+
minWidth: 8,
|
|
1366
|
+
textAlign: "center"
|
|
1367
|
+
},
|
|
1368
|
+
children
|
|
1369
|
+
}
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
function DropButton({
|
|
1391
1373
|
children,
|
|
1392
1374
|
onClick,
|
|
1393
1375
|
active
|
|
1394
1376
|
}) {
|
|
1395
|
-
return /* @__PURE__ */
|
|
1377
|
+
return /* @__PURE__ */ jsx4(
|
|
1396
1378
|
"button",
|
|
1397
1379
|
{
|
|
1398
1380
|
onClick,
|
|
1399
1381
|
style: {
|
|
1400
1382
|
display: "flex",
|
|
1401
1383
|
alignItems: "center",
|
|
1402
|
-
gap:
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1384
|
+
gap: 6,
|
|
1385
|
+
height: 34,
|
|
1386
|
+
padding: "0 10px",
|
|
1387
|
+
borderRadius: 10,
|
|
1388
|
+
border: "1px solid rgba(255,255,255,0.08)",
|
|
1389
|
+
background: "rgba(255,255,255,0.04)",
|
|
1390
|
+
color: active ? "rgba(125, 211, 252, 0.96)" : "rgba(255,255,255,0.78)",
|
|
1406
1391
|
cursor: "pointer",
|
|
1407
|
-
fontSize:
|
|
1408
|
-
fontFamily: "inherit"
|
|
1409
|
-
padding: "2px 0"
|
|
1392
|
+
fontSize: 12,
|
|
1393
|
+
fontFamily: "inherit"
|
|
1410
1394
|
},
|
|
1411
1395
|
children
|
|
1412
1396
|
}
|
|
1413
1397
|
);
|
|
1414
1398
|
}
|
|
1415
1399
|
function DropMenu({ children }) {
|
|
1416
|
-
return /* @__PURE__ */
|
|
1400
|
+
return /* @__PURE__ */ jsx4(
|
|
1417
1401
|
"div",
|
|
1418
1402
|
{
|
|
1419
1403
|
style: {
|
|
1420
1404
|
position: "absolute",
|
|
1421
|
-
bottom: "100%",
|
|
1422
|
-
left:
|
|
1423
|
-
|
|
1424
|
-
|
|
1405
|
+
bottom: "calc(100% + 8px)",
|
|
1406
|
+
left: "50%",
|
|
1407
|
+
transform: "translateX(-50%)",
|
|
1408
|
+
minWidth: 120,
|
|
1409
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1425
1410
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1426
|
-
borderRadius:
|
|
1411
|
+
borderRadius: 10,
|
|
1427
1412
|
padding: "4px 0",
|
|
1428
|
-
|
|
1429
|
-
boxShadow: "0 4px 16px rgba(0, 0, 0, 0.3)",
|
|
1413
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
|
|
1430
1414
|
backdropFilter: "blur(20px)",
|
|
1431
1415
|
WebkitBackdropFilter: "blur(20px)"
|
|
1432
1416
|
},
|
|
@@ -1440,17 +1424,17 @@ function DropItem({
|
|
|
1440
1424
|
active,
|
|
1441
1425
|
accent
|
|
1442
1426
|
}) {
|
|
1443
|
-
return /* @__PURE__ */
|
|
1427
|
+
return /* @__PURE__ */ jsx4(
|
|
1444
1428
|
"button",
|
|
1445
1429
|
{
|
|
1446
1430
|
onClick,
|
|
1447
1431
|
style: {
|
|
1448
1432
|
display: "block",
|
|
1449
1433
|
width: "100%",
|
|
1450
|
-
padding: "
|
|
1451
|
-
background: active ? "rgba(255, 255, 255, 0.08)" : "
|
|
1434
|
+
padding: "7px 12px",
|
|
1435
|
+
background: active ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
1452
1436
|
border: "none",
|
|
1453
|
-
color: accent ? "rgba(
|
|
1437
|
+
color: accent ? "rgba(125, 211, 252, 0.96)" : "rgba(255, 255, 255, 0.86)",
|
|
1454
1438
|
textAlign: "left",
|
|
1455
1439
|
cursor: "pointer",
|
|
1456
1440
|
fontSize: 13,
|
|
@@ -1460,123 +1444,56 @@ function DropItem({
|
|
|
1460
1444
|
}
|
|
1461
1445
|
);
|
|
1462
1446
|
}
|
|
1463
|
-
function
|
|
1464
|
-
return /* @__PURE__ */
|
|
1465
|
-
"
|
|
1447
|
+
function MenuDivider() {
|
|
1448
|
+
return /* @__PURE__ */ jsx4(
|
|
1449
|
+
"div",
|
|
1466
1450
|
{
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
) });
|
|
1472
|
-
}
|
|
1473
|
-
function AspectIcon() {
|
|
1474
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1475
|
-
/* @__PURE__ */ jsx3(
|
|
1476
|
-
"rect",
|
|
1477
|
-
{
|
|
1478
|
-
x: "2",
|
|
1479
|
-
y: "4",
|
|
1480
|
-
width: "12",
|
|
1481
|
-
height: "8",
|
|
1482
|
-
rx: "1.5",
|
|
1483
|
-
stroke: "currentColor",
|
|
1484
|
-
strokeWidth: "1.2",
|
|
1485
|
-
strokeDasharray: "2 1.5"
|
|
1486
|
-
}
|
|
1487
|
-
),
|
|
1488
|
-
/* @__PURE__ */ jsx3(
|
|
1489
|
-
"line",
|
|
1490
|
-
{
|
|
1491
|
-
x1: "6.33",
|
|
1492
|
-
y1: "4",
|
|
1493
|
-
x2: "6.33",
|
|
1494
|
-
y2: "12",
|
|
1495
|
-
stroke: "currentColor",
|
|
1496
|
-
strokeWidth: "0.8",
|
|
1497
|
-
strokeDasharray: "1.5 1"
|
|
1498
|
-
}
|
|
1499
|
-
),
|
|
1500
|
-
/* @__PURE__ */ jsx3(
|
|
1501
|
-
"line",
|
|
1502
|
-
{
|
|
1503
|
-
x1: "9.67",
|
|
1504
|
-
y1: "4",
|
|
1505
|
-
x2: "9.67",
|
|
1506
|
-
y2: "12",
|
|
1507
|
-
stroke: "currentColor",
|
|
1508
|
-
strokeWidth: "0.8",
|
|
1509
|
-
strokeDasharray: "1.5 1"
|
|
1451
|
+
style: {
|
|
1452
|
+
height: 1,
|
|
1453
|
+
background: "rgba(255,255,255,0.08)",
|
|
1454
|
+
margin: "4px 0"
|
|
1510
1455
|
}
|
|
1511
|
-
)
|
|
1512
|
-
] });
|
|
1513
|
-
}
|
|
1514
|
-
function SavedIcon() {
|
|
1515
|
-
return /* @__PURE__ */ jsx3("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx3(
|
|
1516
|
-
"rect",
|
|
1517
|
-
{
|
|
1518
|
-
x: "2",
|
|
1519
|
-
y: "3",
|
|
1520
|
-
width: "12",
|
|
1521
|
-
height: "10",
|
|
1522
|
-
rx: "1.5",
|
|
1523
|
-
stroke: "currentColor",
|
|
1524
|
-
strokeWidth: "1.2",
|
|
1525
|
-
strokeDasharray: "2 1.5"
|
|
1526
1456
|
}
|
|
1527
|
-
)
|
|
1457
|
+
);
|
|
1528
1458
|
}
|
|
1529
|
-
function
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
}) {
|
|
1533
|
-
return /* @__PURE__ */ jsxs3(
|
|
1534
|
-
"button",
|
|
1459
|
+
function Separator({ vertical = true }) {
|
|
1460
|
+
return /* @__PURE__ */ jsx4(
|
|
1461
|
+
"div",
|
|
1535
1462
|
{
|
|
1536
|
-
onClick: onToggle,
|
|
1537
1463
|
style: {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
color: enabled ? "rgba(147, 130, 220, 0.9)" : "rgba(255, 255, 255, 0.35)",
|
|
1544
|
-
cursor: "pointer",
|
|
1545
|
-
fontSize: 11,
|
|
1546
|
-
fontFamily: "inherit",
|
|
1547
|
-
padding: "2px 0"
|
|
1548
|
-
},
|
|
1549
|
-
children: [
|
|
1550
|
-
/* @__PURE__ */ jsx3(MagnetIcon, {}),
|
|
1551
|
-
"Magnet"
|
|
1552
|
-
]
|
|
1464
|
+
width: vertical ? 1 : 24,
|
|
1465
|
+
height: vertical ? 24 : 1,
|
|
1466
|
+
background: "rgba(255,255,255,0.12)",
|
|
1467
|
+
flexShrink: 0
|
|
1468
|
+
}
|
|
1553
1469
|
}
|
|
1554
1470
|
);
|
|
1555
1471
|
}
|
|
1556
|
-
function
|
|
1557
|
-
return
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1472
|
+
function circleButtonStyle(active, round) {
|
|
1473
|
+
return {
|
|
1474
|
+
width: 40,
|
|
1475
|
+
height: 40,
|
|
1476
|
+
borderRadius: round ? "50%" : 12,
|
|
1477
|
+
border: "none",
|
|
1478
|
+
background: active ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
1479
|
+
display: "flex",
|
|
1480
|
+
alignItems: "center",
|
|
1481
|
+
justifyContent: "center",
|
|
1482
|
+
cursor: "pointer",
|
|
1483
|
+
padding: 0,
|
|
1484
|
+
transition: "background 0.12s ease, color 0.12s ease",
|
|
1485
|
+
marginRight: round ? 6 : 0
|
|
1486
|
+
};
|
|
1570
1487
|
}
|
|
1571
1488
|
|
|
1572
1489
|
// src/overlay/ui/inspector.tsx
|
|
1573
|
-
import { useEffect as
|
|
1574
|
-
import { Fragment as
|
|
1490
|
+
import { useEffect as useEffect5, useRef as useRef3, useCallback as useCallback4, useState as useState6 } from "react";
|
|
1491
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1575
1492
|
function Inspector({ onSelect, onCancel }) {
|
|
1576
|
-
const [highlight, setHighlight] =
|
|
1493
|
+
const [highlight, setHighlight] = useState6(null);
|
|
1577
1494
|
const hoveredEl = useRef3(null);
|
|
1578
1495
|
const styleEl = useRef3(null);
|
|
1579
|
-
|
|
1496
|
+
useEffect5(() => {
|
|
1580
1497
|
const style = document.createElement("style");
|
|
1581
1498
|
style.setAttribute("data-afterbefore", "true");
|
|
1582
1499
|
style.textContent = "*, *::before, *::after { cursor: crosshair !important; }";
|
|
@@ -1586,7 +1503,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1586
1503
|
style.remove();
|
|
1587
1504
|
};
|
|
1588
1505
|
}, []);
|
|
1589
|
-
const isOverlayElement =
|
|
1506
|
+
const isOverlayElement = useCallback4((el) => {
|
|
1590
1507
|
let node = el;
|
|
1591
1508
|
while (node) {
|
|
1592
1509
|
if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
|
|
@@ -1594,7 +1511,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1594
1511
|
}
|
|
1595
1512
|
return false;
|
|
1596
1513
|
}, []);
|
|
1597
|
-
const handleMouseMove =
|
|
1514
|
+
const handleMouseMove = useCallback4(
|
|
1598
1515
|
(e) => {
|
|
1599
1516
|
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
1600
1517
|
if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {
|
|
@@ -1614,7 +1531,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1614
1531
|
},
|
|
1615
1532
|
[isOverlayElement]
|
|
1616
1533
|
);
|
|
1617
|
-
const handleClick =
|
|
1534
|
+
const handleClick = useCallback4(
|
|
1618
1535
|
(e) => {
|
|
1619
1536
|
e.preventDefault();
|
|
1620
1537
|
e.stopPropagation();
|
|
@@ -1625,7 +1542,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1625
1542
|
},
|
|
1626
1543
|
[onSelect]
|
|
1627
1544
|
);
|
|
1628
|
-
const handleKeyDown =
|
|
1545
|
+
const handleKeyDown = useCallback4(
|
|
1629
1546
|
(e) => {
|
|
1630
1547
|
if (e.key === "Escape") {
|
|
1631
1548
|
onCancel();
|
|
@@ -1633,7 +1550,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1633
1550
|
},
|
|
1634
1551
|
[onCancel]
|
|
1635
1552
|
);
|
|
1636
|
-
|
|
1553
|
+
useEffect5(() => {
|
|
1637
1554
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
1638
1555
|
document.addEventListener("click", handleClick, true);
|
|
1639
1556
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -1644,8 +1561,8 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1644
1561
|
};
|
|
1645
1562
|
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
1646
1563
|
return /* @__PURE__ */ jsxs4("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: [
|
|
1647
|
-
highlight && /* @__PURE__ */ jsxs4(
|
|
1648
|
-
/* @__PURE__ */
|
|
1564
|
+
highlight && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1565
|
+
/* @__PURE__ */ jsx5(
|
|
1649
1566
|
"div",
|
|
1650
1567
|
{
|
|
1651
1568
|
style: {
|
|
@@ -1661,7 +1578,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1661
1578
|
}
|
|
1662
1579
|
}
|
|
1663
1580
|
),
|
|
1664
|
-
/* @__PURE__ */
|
|
1581
|
+
/* @__PURE__ */ jsx5(
|
|
1665
1582
|
"div",
|
|
1666
1583
|
{
|
|
1667
1584
|
style: {
|
|
@@ -1682,7 +1599,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1682
1599
|
}
|
|
1683
1600
|
)
|
|
1684
1601
|
] }),
|
|
1685
|
-
!highlight && /* @__PURE__ */
|
|
1602
|
+
!highlight && /* @__PURE__ */ jsx5(
|
|
1686
1603
|
"div",
|
|
1687
1604
|
{
|
|
1688
1605
|
style: {
|
|
@@ -1706,18 +1623,18 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1706
1623
|
}
|
|
1707
1624
|
|
|
1708
1625
|
// src/overlay/ui/status.tsx
|
|
1709
|
-
import { useState as
|
|
1710
|
-
import { jsx as
|
|
1626
|
+
import { useState as useState7, useRef as useRef4, useEffect as useEffect6, useCallback as useCallback5 } from "react";
|
|
1627
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1711
1628
|
var PANEL_WIDTH = 220;
|
|
1712
1629
|
function Status({ onReset, position, onClose }) {
|
|
1713
1630
|
const panelRef = useRef4(null);
|
|
1714
|
-
const [toast, setToast] =
|
|
1715
|
-
const [pushing, setPushing] =
|
|
1716
|
-
const showToast =
|
|
1631
|
+
const [toast, setToast] = useState7(null);
|
|
1632
|
+
const [pushing, setPushing] = useState7(false);
|
|
1633
|
+
const showToast = useCallback5((message, type) => {
|
|
1717
1634
|
setToast({ message, type });
|
|
1718
1635
|
setTimeout(() => setToast(null), 3e3);
|
|
1719
1636
|
}, []);
|
|
1720
|
-
|
|
1637
|
+
useEffect6(() => {
|
|
1721
1638
|
const handler = (e) => {
|
|
1722
1639
|
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
1723
1640
|
onClose();
|
|
@@ -1726,7 +1643,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1726
1643
|
document.addEventListener("mousedown", handler);
|
|
1727
1644
|
return () => document.removeEventListener("mousedown", handler);
|
|
1728
1645
|
}, [onClose]);
|
|
1729
|
-
|
|
1646
|
+
useEffect6(() => {
|
|
1730
1647
|
const handler = (e) => {
|
|
1731
1648
|
if (e.key === "Escape") onClose();
|
|
1732
1649
|
};
|
|
@@ -1821,7 +1738,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1821
1738
|
overflow: "hidden"
|
|
1822
1739
|
},
|
|
1823
1740
|
children: [
|
|
1824
|
-
/* @__PURE__ */
|
|
1741
|
+
/* @__PURE__ */ jsx6(
|
|
1825
1742
|
"div",
|
|
1826
1743
|
{
|
|
1827
1744
|
style: {
|
|
@@ -1843,7 +1760,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1843
1760
|
onMouseEnter: onEnter,
|
|
1844
1761
|
onMouseLeave: onLeave,
|
|
1845
1762
|
children: [
|
|
1846
|
-
/* @__PURE__ */
|
|
1763
|
+
/* @__PURE__ */ jsx6(FolderIcon, {}),
|
|
1847
1764
|
"Open Folder"
|
|
1848
1765
|
]
|
|
1849
1766
|
}
|
|
@@ -1856,7 +1773,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1856
1773
|
onMouseEnter: onEnter,
|
|
1857
1774
|
onMouseLeave: onLeave,
|
|
1858
1775
|
children: [
|
|
1859
|
-
/* @__PURE__ */
|
|
1776
|
+
/* @__PURE__ */ jsx6(CopyIcon, {}),
|
|
1860
1777
|
"Copy Markdown"
|
|
1861
1778
|
]
|
|
1862
1779
|
}
|
|
@@ -1870,12 +1787,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1870
1787
|
onMouseEnter: onEnter,
|
|
1871
1788
|
onMouseLeave: onLeave,
|
|
1872
1789
|
children: [
|
|
1873
|
-
/* @__PURE__ */
|
|
1790
|
+
/* @__PURE__ */ jsx6(PushIcon, {}),
|
|
1874
1791
|
pushing ? "Pushing..." : "Push to PR"
|
|
1875
1792
|
]
|
|
1876
1793
|
}
|
|
1877
1794
|
),
|
|
1878
|
-
/* @__PURE__ */
|
|
1795
|
+
/* @__PURE__ */ jsx6(
|
|
1879
1796
|
"div",
|
|
1880
1797
|
{
|
|
1881
1798
|
style: {
|
|
@@ -1893,13 +1810,13 @@ function Status({ onReset, position, onClose }) {
|
|
|
1893
1810
|
onMouseEnter: onEnter,
|
|
1894
1811
|
onMouseLeave: onLeave,
|
|
1895
1812
|
children: [
|
|
1896
|
-
/* @__PURE__ */
|
|
1813
|
+
/* @__PURE__ */ jsx6(ResetIcon, {}),
|
|
1897
1814
|
"Reset"
|
|
1898
1815
|
]
|
|
1899
1816
|
}
|
|
1900
1817
|
)
|
|
1901
1818
|
] }),
|
|
1902
|
-
toast && /* @__PURE__ */
|
|
1819
|
+
toast && /* @__PURE__ */ jsx6(
|
|
1903
1820
|
"div",
|
|
1904
1821
|
{
|
|
1905
1822
|
style: {
|
|
@@ -1925,14 +1842,14 @@ function Status({ onReset, position, onClose }) {
|
|
|
1925
1842
|
);
|
|
1926
1843
|
}
|
|
1927
1844
|
function FolderIcon() {
|
|
1928
|
-
return /* @__PURE__ */
|
|
1845
|
+
return /* @__PURE__ */ jsx6(
|
|
1929
1846
|
"svg",
|
|
1930
1847
|
{
|
|
1931
1848
|
width: "14",
|
|
1932
1849
|
height: "14",
|
|
1933
1850
|
viewBox: "0 0 14 14",
|
|
1934
1851
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1935
|
-
children: /* @__PURE__ */
|
|
1852
|
+
children: /* @__PURE__ */ jsx6(
|
|
1936
1853
|
"path",
|
|
1937
1854
|
{
|
|
1938
1855
|
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",
|
|
@@ -1953,7 +1870,7 @@ function CopyIcon() {
|
|
|
1953
1870
|
viewBox: "0 0 14 14",
|
|
1954
1871
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1955
1872
|
children: [
|
|
1956
|
-
/* @__PURE__ */
|
|
1873
|
+
/* @__PURE__ */ jsx6(
|
|
1957
1874
|
"rect",
|
|
1958
1875
|
{
|
|
1959
1876
|
x: "4",
|
|
@@ -1966,7 +1883,7 @@ function CopyIcon() {
|
|
|
1966
1883
|
strokeWidth: "1.3"
|
|
1967
1884
|
}
|
|
1968
1885
|
),
|
|
1969
|
-
/* @__PURE__ */
|
|
1886
|
+
/* @__PURE__ */ jsx6(
|
|
1970
1887
|
"path",
|
|
1971
1888
|
{
|
|
1972
1889
|
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",
|
|
@@ -1980,14 +1897,14 @@ function CopyIcon() {
|
|
|
1980
1897
|
);
|
|
1981
1898
|
}
|
|
1982
1899
|
function PushIcon() {
|
|
1983
|
-
return /* @__PURE__ */
|
|
1900
|
+
return /* @__PURE__ */ jsx6(
|
|
1984
1901
|
"svg",
|
|
1985
1902
|
{
|
|
1986
1903
|
width: "14",
|
|
1987
1904
|
height: "14",
|
|
1988
1905
|
viewBox: "0 0 14 14",
|
|
1989
1906
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1990
|
-
children: /* @__PURE__ */
|
|
1907
|
+
children: /* @__PURE__ */ jsx6(
|
|
1991
1908
|
"path",
|
|
1992
1909
|
{
|
|
1993
1910
|
d: "M7 11V3m0 0L4 6m3-3l3 3",
|
|
@@ -2010,7 +1927,7 @@ function ResetIcon() {
|
|
|
2010
1927
|
viewBox: "0 0 14 14",
|
|
2011
1928
|
style: { color: "rgba(255,255,255,0.4)" },
|
|
2012
1929
|
children: [
|
|
2013
|
-
/* @__PURE__ */
|
|
1930
|
+
/* @__PURE__ */ jsx6(
|
|
2014
1931
|
"path",
|
|
2015
1932
|
{
|
|
2016
1933
|
d: "M2.5 7a4.5 4.5 0 118 2.5",
|
|
@@ -2020,7 +1937,7 @@ function ResetIcon() {
|
|
|
2020
1937
|
strokeLinecap: "round"
|
|
2021
1938
|
}
|
|
2022
1939
|
),
|
|
2023
|
-
/* @__PURE__ */
|
|
1940
|
+
/* @__PURE__ */ jsx6(
|
|
2024
1941
|
"path",
|
|
2025
1942
|
{
|
|
2026
1943
|
d: "M2.5 3v4h4",
|
|
@@ -2037,7 +1954,7 @@ function ResetIcon() {
|
|
|
2037
1954
|
}
|
|
2038
1955
|
|
|
2039
1956
|
// src/overlay/index.tsx
|
|
2040
|
-
import { jsx as
|
|
1957
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2041
1958
|
async function saveCapture(type, mode, dataUrl) {
|
|
2042
1959
|
try {
|
|
2043
1960
|
const res = await fetch("/__afterbefore/save", {
|
|
@@ -2055,13 +1972,31 @@ async function saveCapture(type, mode, dataUrl) {
|
|
|
2055
1972
|
}
|
|
2056
1973
|
function AfterBefore() {
|
|
2057
1974
|
const { state, captureComplete, reset } = useOverlayState();
|
|
2058
|
-
const [statusOpen, setStatusOpen] =
|
|
2059
|
-
const [toolbarActive, setToolbarActive] =
|
|
2060
|
-
const [selectorActive, setSelectorActive] =
|
|
2061
|
-
const [inspectorActive, setInspectorActive] =
|
|
2062
|
-
const [loading, setLoading] =
|
|
1975
|
+
const [statusOpen, setStatusOpen] = useState8(false);
|
|
1976
|
+
const [toolbarActive, setToolbarActive] = useState8(false);
|
|
1977
|
+
const [selectorActive, setSelectorActive] = useState8(false);
|
|
1978
|
+
const [inspectorActive, setInspectorActive] = useState8(false);
|
|
1979
|
+
const [loading, setLoading] = useState8(false);
|
|
1980
|
+
const [selectedMode, setSelectedMode] = useState8("area");
|
|
1981
|
+
const [magnetEnabled, setMagnetEnabled] = useState8(true);
|
|
1982
|
+
const [areaRect, setAreaRect] = useState8(null);
|
|
1983
|
+
const [areaAspect, setAreaAspect] = useState8(DEFAULT_AREA_ASPECT);
|
|
1984
|
+
const [areaPresets, setAreaPresets] = useState8([]);
|
|
2063
1985
|
const iconPos = useRef5({ x: 24, y: 0 });
|
|
2064
|
-
|
|
1986
|
+
useEffect7(() => {
|
|
1987
|
+
try {
|
|
1988
|
+
setMagnetEnabled(localStorage.getItem("ab-magnet") !== "false");
|
|
1989
|
+
} catch {
|
|
1990
|
+
setMagnetEnabled(true);
|
|
1991
|
+
}
|
|
1992
|
+
try {
|
|
1993
|
+
const savedPresets = localStorage.getItem("ab-area-presets");
|
|
1994
|
+
setAreaPresets(savedPresets ? JSON.parse(savedPresets) : []);
|
|
1995
|
+
} catch {
|
|
1996
|
+
setAreaPresets([]);
|
|
1997
|
+
}
|
|
1998
|
+
}, []);
|
|
1999
|
+
useEffect7(() => {
|
|
2065
2000
|
if (state.phase === "ready") {
|
|
2066
2001
|
const timer = setTimeout(() => {
|
|
2067
2002
|
reset();
|
|
@@ -2070,13 +2005,13 @@ function AfterBefore() {
|
|
|
2070
2005
|
return () => clearTimeout(timer);
|
|
2071
2006
|
}
|
|
2072
2007
|
}, [state.phase, reset]);
|
|
2073
|
-
const handlePositionChange =
|
|
2008
|
+
const handlePositionChange = useCallback6(
|
|
2074
2009
|
(pos) => {
|
|
2075
2010
|
iconPos.current = pos;
|
|
2076
2011
|
},
|
|
2077
2012
|
[]
|
|
2078
2013
|
);
|
|
2079
|
-
const handleIconClick =
|
|
2014
|
+
const handleIconClick = useCallback6(() => {
|
|
2080
2015
|
if (loading) return;
|
|
2081
2016
|
if (state.phase === "ready") {
|
|
2082
2017
|
setStatusOpen((prev) => !prev);
|
|
@@ -2087,7 +2022,7 @@ function AfterBefore() {
|
|
|
2087
2022
|
setStatusOpen(false);
|
|
2088
2023
|
}
|
|
2089
2024
|
}, [state.phase, loading]);
|
|
2090
|
-
const performCapture =
|
|
2025
|
+
const performCapture = useCallback6(
|
|
2091
2026
|
async (mode, area, element) => {
|
|
2092
2027
|
setLoading(true);
|
|
2093
2028
|
try {
|
|
@@ -2107,53 +2042,152 @@ function AfterBefore() {
|
|
|
2107
2042
|
},
|
|
2108
2043
|
[state.phase, captureComplete]
|
|
2109
2044
|
);
|
|
2110
|
-
const handleToolbarCapture =
|
|
2045
|
+
const handleToolbarCapture = useCallback6(
|
|
2111
2046
|
(mode) => {
|
|
2112
|
-
setToolbarActive(false);
|
|
2113
2047
|
if (mode === "area") {
|
|
2048
|
+
if (selectorActive && areaRect) {
|
|
2049
|
+
setSelectorActive(false);
|
|
2050
|
+
setToolbarActive(false);
|
|
2051
|
+
performCapture("area", {
|
|
2052
|
+
x: Math.round(areaRect.x),
|
|
2053
|
+
y: Math.round(areaRect.y),
|
|
2054
|
+
width: Math.round(areaRect.w),
|
|
2055
|
+
height: Math.round(areaRect.h)
|
|
2056
|
+
});
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
setSelectedMode("area");
|
|
2060
|
+
setAreaAspect(DEFAULT_AREA_ASPECT);
|
|
2061
|
+
setAreaRect(createInitialAreaRect());
|
|
2114
2062
|
setSelectorActive(true);
|
|
2063
|
+
setToolbarActive(true);
|
|
2115
2064
|
} else if (mode === "viewport") {
|
|
2065
|
+
setToolbarActive(false);
|
|
2116
2066
|
performCapture("viewport");
|
|
2117
2067
|
} else if (mode === "fullpage") {
|
|
2068
|
+
setToolbarActive(false);
|
|
2118
2069
|
performCapture("fullpage");
|
|
2119
2070
|
} else if (mode === "component") {
|
|
2071
|
+
setToolbarActive(false);
|
|
2120
2072
|
setInspectorActive(true);
|
|
2121
2073
|
}
|
|
2122
2074
|
},
|
|
2123
|
-
[performCapture]
|
|
2075
|
+
[areaRect, performCapture, selectorActive]
|
|
2124
2076
|
);
|
|
2125
|
-
const handleToolbarCancel =
|
|
2077
|
+
const handleToolbarCancel = useCallback6(() => {
|
|
2126
2078
|
setToolbarActive(false);
|
|
2079
|
+
setSelectorActive(false);
|
|
2127
2080
|
}, []);
|
|
2128
|
-
const handleComponentSelect =
|
|
2081
|
+
const handleComponentSelect = useCallback6(
|
|
2129
2082
|
(element) => {
|
|
2130
2083
|
setInspectorActive(false);
|
|
2131
2084
|
performCapture("component", void 0, element);
|
|
2132
2085
|
},
|
|
2133
2086
|
[performCapture]
|
|
2134
2087
|
);
|
|
2135
|
-
const handleComponentCancel =
|
|
2088
|
+
const handleComponentCancel = useCallback6(() => {
|
|
2136
2089
|
setInspectorActive(false);
|
|
2090
|
+
setToolbarActive(true);
|
|
2137
2091
|
}, []);
|
|
2138
|
-
const handleAreaSelect =
|
|
2092
|
+
const handleAreaSelect = useCallback6(
|
|
2139
2093
|
(area) => {
|
|
2140
2094
|
setSelectorActive(false);
|
|
2095
|
+
setToolbarActive(false);
|
|
2141
2096
|
performCapture("area", area);
|
|
2142
2097
|
},
|
|
2143
2098
|
[performCapture]
|
|
2144
2099
|
);
|
|
2145
|
-
const handleAreaCancel =
|
|
2100
|
+
const handleAreaCancel = useCallback6(() => {
|
|
2146
2101
|
setSelectorActive(false);
|
|
2102
|
+
setToolbarActive(true);
|
|
2103
|
+
}, []);
|
|
2104
|
+
const handleMagnetChange = useCallback6((enabled) => {
|
|
2105
|
+
setMagnetEnabled(enabled);
|
|
2106
|
+
try {
|
|
2107
|
+
localStorage.setItem("ab-magnet", String(enabled));
|
|
2108
|
+
} catch {
|
|
2109
|
+
}
|
|
2110
|
+
}, []);
|
|
2111
|
+
const handleModeChange = useCallback6((mode) => {
|
|
2112
|
+
setSelectedMode(mode);
|
|
2113
|
+
if (mode !== "area") {
|
|
2114
|
+
setSelectorActive(false);
|
|
2115
|
+
}
|
|
2116
|
+
}, []);
|
|
2117
|
+
const handleAreaRectChange = useCallback6((nextRect) => {
|
|
2118
|
+
setAreaRect(nextRect);
|
|
2119
|
+
}, []);
|
|
2120
|
+
const handleAreaSizeChange = useCallback6(
|
|
2121
|
+
(field, value) => {
|
|
2122
|
+
const nextValue = parseInt(value, 10);
|
|
2123
|
+
if (Number.isNaN(nextValue) || nextValue < 20 || !areaRect) {
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2126
|
+
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];
|
|
2127
|
+
if (field === "w") {
|
|
2128
|
+
setAreaRect({
|
|
2129
|
+
...areaRect,
|
|
2130
|
+
w: nextValue,
|
|
2131
|
+
h: aspectRatio > 0 ? nextValue / aspectRatio : areaRect.h
|
|
2132
|
+
});
|
|
2133
|
+
} else {
|
|
2134
|
+
setAreaRect({
|
|
2135
|
+
...areaRect,
|
|
2136
|
+
h: nextValue,
|
|
2137
|
+
w: aspectRatio > 0 ? nextValue * aspectRatio : areaRect.w
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
},
|
|
2141
|
+
[areaAspect, areaRect]
|
|
2142
|
+
);
|
|
2143
|
+
const handleAreaPositionChange = useCallback6(
|
|
2144
|
+
(field, value) => {
|
|
2145
|
+
const nextValue = parseInt(value, 10);
|
|
2146
|
+
if (Number.isNaN(nextValue) || !areaRect) {
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
setAreaRect({ ...areaRect, [field]: nextValue });
|
|
2150
|
+
},
|
|
2151
|
+
[areaRect]
|
|
2152
|
+
);
|
|
2153
|
+
const handleAreaAspectChange = useCallback6(
|
|
2154
|
+
(nextAspect) => {
|
|
2155
|
+
setAreaAspect(nextAspect);
|
|
2156
|
+
if (!areaRect || nextAspect === "Free") {
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
const aspectRatio = { "16:9": 16 / 9, "4:3": 4 / 3, "1:1": 1, "3:2": 3 / 2, "21:9": 21 / 9 }[nextAspect];
|
|
2160
|
+
setAreaRect({ ...areaRect, h: areaRect.w / aspectRatio });
|
|
2161
|
+
},
|
|
2162
|
+
[areaRect]
|
|
2163
|
+
);
|
|
2164
|
+
const handleAreaSavePreset = useCallback6(() => {
|
|
2165
|
+
if (!areaRect) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
const label = `${Math.round(areaRect.w)}x${Math.round(areaRect.h)}`;
|
|
2169
|
+
const nextPresets = [
|
|
2170
|
+
...areaPresets.filter((preset) => preset.label !== label),
|
|
2171
|
+
{ label, rect: { ...areaRect } }
|
|
2172
|
+
];
|
|
2173
|
+
setAreaPresets(nextPresets);
|
|
2174
|
+
try {
|
|
2175
|
+
localStorage.setItem("ab-area-presets", JSON.stringify(nextPresets));
|
|
2176
|
+
} catch {
|
|
2177
|
+
}
|
|
2178
|
+
}, [areaPresets, areaRect]);
|
|
2179
|
+
const handleAreaLoadPreset = useCallback6((preset) => {
|
|
2180
|
+
setAreaRect({ ...preset.rect });
|
|
2147
2181
|
}, []);
|
|
2148
|
-
const handleReset =
|
|
2182
|
+
const handleReset = useCallback6(() => {
|
|
2149
2183
|
reset();
|
|
2150
2184
|
setStatusOpen(false);
|
|
2151
2185
|
}, [reset]);
|
|
2152
|
-
const handleStatusClose =
|
|
2186
|
+
const handleStatusClose = useCallback6(() => {
|
|
2153
2187
|
setStatusOpen(false);
|
|
2154
2188
|
}, []);
|
|
2155
2189
|
return /* @__PURE__ */ jsxs6("div", { "data-afterbefore": "true", children: [
|
|
2156
|
-
/* @__PURE__ */
|
|
2190
|
+
/* @__PURE__ */ jsx7(
|
|
2157
2191
|
Icon,
|
|
2158
2192
|
{
|
|
2159
2193
|
phase: state.phase,
|
|
@@ -2162,16 +2196,40 @@ function AfterBefore() {
|
|
|
2162
2196
|
onPositionChange: handlePositionChange
|
|
2163
2197
|
}
|
|
2164
2198
|
),
|
|
2165
|
-
toolbarActive && !selectorActive && !inspectorActive && /* @__PURE__ */
|
|
2166
|
-
|
|
2199
|
+
toolbarActive && !selectorActive && !inspectorActive && !loading && /* @__PURE__ */ jsx7(CapturePreview, { mode: selectedMode }),
|
|
2200
|
+
toolbarActive && !inspectorActive && /* @__PURE__ */ jsx7(
|
|
2201
|
+
Toolbar,
|
|
2202
|
+
{
|
|
2203
|
+
selectedMode,
|
|
2204
|
+
onModeChange: handleModeChange,
|
|
2205
|
+
onCapture: handleToolbarCapture,
|
|
2206
|
+
onCancel: handleToolbarCancel,
|
|
2207
|
+
magnetEnabled,
|
|
2208
|
+
onMagnetChange: handleMagnetChange,
|
|
2209
|
+
areaSelectionActive: selectorActive,
|
|
2210
|
+
areaRect,
|
|
2211
|
+
areaAspect,
|
|
2212
|
+
areaPresets,
|
|
2213
|
+
onAreaSizeChange: handleAreaSizeChange,
|
|
2214
|
+
onAreaPositionChange: handleAreaPositionChange,
|
|
2215
|
+
onAreaAspectChange: handleAreaAspectChange,
|
|
2216
|
+
onAreaSavePreset: handleAreaSavePreset,
|
|
2217
|
+
onAreaLoadPreset: handleAreaLoadPreset
|
|
2218
|
+
}
|
|
2219
|
+
),
|
|
2220
|
+
selectorActive && /* @__PURE__ */ jsx7(
|
|
2167
2221
|
Selector,
|
|
2168
2222
|
{
|
|
2223
|
+
rect: areaRect,
|
|
2224
|
+
aspect: areaAspect,
|
|
2225
|
+
onRectChange: handleAreaRectChange,
|
|
2169
2226
|
onSelect: handleAreaSelect,
|
|
2170
|
-
onCancel: handleAreaCancel
|
|
2227
|
+
onCancel: handleAreaCancel,
|
|
2228
|
+
magnetEnabled
|
|
2171
2229
|
}
|
|
2172
2230
|
),
|
|
2173
|
-
inspectorActive && /* @__PURE__ */
|
|
2174
|
-
statusOpen && state.phase === "ready" && /* @__PURE__ */
|
|
2231
|
+
inspectorActive && /* @__PURE__ */ jsx7(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel }),
|
|
2232
|
+
statusOpen && state.phase === "ready" && /* @__PURE__ */ jsx7(
|
|
2175
2233
|
Status,
|
|
2176
2234
|
{
|
|
2177
2235
|
onReset: handleReset,
|