afterbefore 0.2.7 → 0.2.9
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 +1154 -1070
- 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,95 @@ 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);
|
|
491
|
+
const [cursor, setCursor] = useState4("crosshair");
|
|
711
492
|
const mode = useRef2("none");
|
|
712
493
|
const start = useRef2({ x: 0, y: 0 });
|
|
713
494
|
const snapRef = useRef2({ x: 0, y: 0, w: 0, h: 0 });
|
|
714
495
|
const corner = useRef2("br");
|
|
715
|
-
const
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (!magnet) {
|
|
496
|
+
const ratio = useMemo(() => getAspectRatio(aspect), [aspect]);
|
|
497
|
+
const applySnap = useCallback3(
|
|
498
|
+
(nextRect) => {
|
|
499
|
+
if (!magnetEnabled) {
|
|
720
500
|
setSnappedX(false);
|
|
721
|
-
return
|
|
501
|
+
return nextRect;
|
|
722
502
|
}
|
|
723
|
-
const
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
if (Math.abs(centerX - viewCenterX) < SNAP_THRESHOLD) {
|
|
503
|
+
const centerX = nextRect.x + nextRect.w / 2;
|
|
504
|
+
const viewportCenterX = window.innerWidth / 2;
|
|
505
|
+
if (Math.abs(centerX - viewportCenterX) < SNAP_THRESHOLD) {
|
|
727
506
|
setSnappedX(true);
|
|
728
|
-
return { ...
|
|
507
|
+
return { ...nextRect, x: viewportCenterX - nextRect.w / 2 };
|
|
729
508
|
}
|
|
730
509
|
setSnappedX(false);
|
|
731
|
-
return
|
|
510
|
+
return nextRect;
|
|
732
511
|
},
|
|
733
|
-
[
|
|
512
|
+
[magnetEnabled]
|
|
734
513
|
);
|
|
735
514
|
useEffect3(() => {
|
|
736
515
|
const onKey = (e) => {
|
|
737
|
-
if (e.target?.tagName === "INPUT") {
|
|
738
|
-
if (e.key === "Escape") e.target.blur();
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
516
|
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
|
-
});
|
|
517
|
+
onCancel();
|
|
755
518
|
}
|
|
756
519
|
};
|
|
757
520
|
document.addEventListener("keydown", onKey);
|
|
758
521
|
return () => document.removeEventListener("keydown", onKey);
|
|
759
|
-
}, [
|
|
760
|
-
const hitCorner =
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
return c;
|
|
522
|
+
}, [onCancel]);
|
|
523
|
+
const hitCorner = useCallback3((mx, my, currentRect) => {
|
|
524
|
+
const corners = [
|
|
525
|
+
["tl", currentRect.x, currentRect.y],
|
|
526
|
+
["tr", currentRect.x + currentRect.w, currentRect.y],
|
|
527
|
+
["bl", currentRect.x, currentRect.y + currentRect.h],
|
|
528
|
+
["br", currentRect.x + currentRect.w, currentRect.y + currentRect.h]
|
|
529
|
+
];
|
|
530
|
+
for (const [hitCorner2, cx, cy] of corners) {
|
|
531
|
+
if (Math.abs(mx - cx) <= HANDLE_HIT && Math.abs(my - cy) <= HANDLE_HIT) {
|
|
532
|
+
return hitCorner2;
|
|
771
533
|
}
|
|
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,
|
|
534
|
+
}
|
|
535
|
+
return null;
|
|
536
|
+
}, []);
|
|
537
|
+
const hitInside = useCallback3(
|
|
538
|
+
(mx, my, currentRect) => mx >= currentRect.x && mx <= currentRect.x + currentRect.w && my >= currentRect.y && my <= currentRect.y + currentRect.h,
|
|
778
539
|
[]
|
|
779
540
|
);
|
|
780
|
-
const onDown =
|
|
541
|
+
const onDown = useCallback3(
|
|
781
542
|
(e) => {
|
|
782
|
-
if (panelRef.current?.contains(e.target)) return;
|
|
783
543
|
e.preventDefault();
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
if (c) {
|
|
544
|
+
const mx = e.clientX;
|
|
545
|
+
const my = e.clientY;
|
|
546
|
+
if (rect) {
|
|
547
|
+
const activeCorner = hitCorner(mx, my, rect);
|
|
548
|
+
if (activeCorner) {
|
|
790
549
|
mode.current = "resizing";
|
|
791
|
-
corner.current =
|
|
550
|
+
corner.current = activeCorner;
|
|
792
551
|
start.current = { x: mx, y: my };
|
|
793
552
|
snapRef.current = { ...rect };
|
|
794
553
|
return;
|
|
@@ -799,78 +558,96 @@ function Selector({ onSelect, onCancel }) {
|
|
|
799
558
|
snapRef.current = { ...rect };
|
|
800
559
|
return;
|
|
801
560
|
}
|
|
802
|
-
setPlaced(false);
|
|
803
561
|
}
|
|
804
562
|
mode.current = "drawing";
|
|
805
563
|
start.current = { x: mx, y: my };
|
|
806
|
-
|
|
564
|
+
onRectChange({ x: mx, y: my, w: 0, h: 0 });
|
|
807
565
|
},
|
|
808
|
-
[
|
|
566
|
+
[hitCorner, hitInside, onRectChange, rect]
|
|
809
567
|
);
|
|
810
|
-
const onMove =
|
|
568
|
+
const onMove = useCallback3(
|
|
811
569
|
(e) => {
|
|
812
|
-
const mx = e.clientX
|
|
570
|
+
const mx = e.clientX;
|
|
571
|
+
const my = e.clientY;
|
|
572
|
+
if (mode.current === "none") {
|
|
573
|
+
if (rect) {
|
|
574
|
+
const activeCorner = hitCorner(mx, my, rect);
|
|
575
|
+
if (activeCorner) {
|
|
576
|
+
setCursor(
|
|
577
|
+
activeCorner === "tl" || activeCorner === "br" ? "nwse-resize" : "nesw-resize"
|
|
578
|
+
);
|
|
579
|
+
} else if (hitInside(mx, my, rect)) {
|
|
580
|
+
setCursor(CAMERA_CURSOR);
|
|
581
|
+
} else {
|
|
582
|
+
setCursor("crosshair");
|
|
583
|
+
}
|
|
584
|
+
} else {
|
|
585
|
+
setCursor("crosshair");
|
|
586
|
+
}
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
813
589
|
if (mode.current === "drawing") {
|
|
814
|
-
const sx = start.current.x
|
|
815
|
-
|
|
816
|
-
let
|
|
590
|
+
const sx = start.current.x;
|
|
591
|
+
const sy = start.current.y;
|
|
592
|
+
let x = Math.min(sx, mx);
|
|
593
|
+
let y = Math.min(sy, my);
|
|
594
|
+
let w = Math.abs(mx - sx);
|
|
595
|
+
let h = Math.abs(my - sy);
|
|
817
596
|
if (ratio > 0) {
|
|
818
597
|
h = w / ratio;
|
|
819
|
-
if (my < sy)
|
|
598
|
+
if (my < sy) {
|
|
599
|
+
y = sy - h;
|
|
600
|
+
}
|
|
820
601
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
602
|
+
onRectChange(applySnap({ x, y, w, h }));
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
if (mode.current === "moving") {
|
|
606
|
+
const dx = mx - start.current.x;
|
|
607
|
+
const dy = my - start.current.y;
|
|
608
|
+
onRectChange(
|
|
825
609
|
applySnap({
|
|
826
610
|
...snapRef.current,
|
|
827
611
|
x: snapRef.current.x + dx,
|
|
828
612
|
y: snapRef.current.y + dy
|
|
829
613
|
})
|
|
830
614
|
);
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (mode.current === "resizing") {
|
|
618
|
+
const original = snapRef.current;
|
|
619
|
+
const nextRect = { ...original };
|
|
620
|
+
if (corner.current === "br") {
|
|
621
|
+
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
622
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
623
|
+
} else if (corner.current === "bl") {
|
|
624
|
+
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
625
|
+
nextRect.x = original.x + original.w - nextRect.w;
|
|
626
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
627
|
+
} else if (corner.current === "tr") {
|
|
628
|
+
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
629
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
630
|
+
nextRect.y = original.y + original.h - nextRect.h;
|
|
846
631
|
} else {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
632
|
+
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
633
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
634
|
+
nextRect.x = original.x + original.w - nextRect.w;
|
|
635
|
+
nextRect.y = original.y + original.h - nextRect.h;
|
|
851
636
|
}
|
|
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");
|
|
637
|
+
onRectChange(applySnap(nextRect));
|
|
859
638
|
}
|
|
860
639
|
},
|
|
861
|
-
[
|
|
640
|
+
[applySnap, hitCorner, hitInside, onRectChange, ratio, rect]
|
|
862
641
|
);
|
|
863
|
-
const onUp =
|
|
642
|
+
const onUp = useCallback3(
|
|
864
643
|
(e) => {
|
|
865
|
-
const
|
|
866
|
-
if (
|
|
867
|
-
if (rect.w
|
|
868
|
-
|
|
869
|
-
} else {
|
|
870
|
-
setRect(null);
|
|
644
|
+
const previousMode = mode.current;
|
|
645
|
+
if (previousMode === "drawing" && rect) {
|
|
646
|
+
if (rect.w < MIN_SIZE || rect.h < MIN_SIZE) {
|
|
647
|
+
onRectChange(null);
|
|
871
648
|
}
|
|
872
649
|
}
|
|
873
|
-
if (
|
|
650
|
+
if (previousMode === "moving" && rect) {
|
|
874
651
|
const dx = Math.abs(e.clientX - start.current.x);
|
|
875
652
|
const dy = Math.abs(e.clientY - start.current.y);
|
|
876
653
|
if (dx < 3 && dy < 3) {
|
|
@@ -884,51 +661,10 @@ function Selector({ onSelect, onCancel }) {
|
|
|
884
661
|
}
|
|
885
662
|
mode.current = "none";
|
|
886
663
|
},
|
|
887
|
-
[
|
|
664
|
+
[onRectChange, onSelect, rect]
|
|
888
665
|
);
|
|
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]
|
|
900
|
-
);
|
|
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
666
|
const hasRect = rect && rect.w > 0 && rect.h > 0;
|
|
931
|
-
return /* @__PURE__ */
|
|
667
|
+
return /* @__PURE__ */ jsxs2(
|
|
932
668
|
"div",
|
|
933
669
|
{
|
|
934
670
|
"data-afterbefore": "true",
|
|
@@ -938,8 +674,8 @@ function Selector({ onSelect, onCancel }) {
|
|
|
938
674
|
style: {
|
|
939
675
|
position: "fixed",
|
|
940
676
|
inset: 0,
|
|
941
|
-
zIndex:
|
|
942
|
-
cursor
|
|
677
|
+
zIndex: 2147483646,
|
|
678
|
+
cursor
|
|
943
679
|
},
|
|
944
680
|
children: [
|
|
945
681
|
snappedX && /* @__PURE__ */ jsx3(
|
|
@@ -951,34 +687,84 @@ function Selector({ onSelect, onCancel }) {
|
|
|
951
687
|
top: 0,
|
|
952
688
|
bottom: 0,
|
|
953
689
|
width: 0,
|
|
954
|
-
borderLeft: "1px solid rgba(
|
|
690
|
+
borderLeft: "1px solid rgba(56, 189, 248, 0.55)",
|
|
955
691
|
pointerEvents: "none",
|
|
956
692
|
zIndex: 2
|
|
957
693
|
}
|
|
958
694
|
}
|
|
959
695
|
),
|
|
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
|
-
} : {}
|
|
696
|
+
hasRect ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
697
|
+
/* @__PURE__ */ jsx3(
|
|
698
|
+
"div",
|
|
699
|
+
{
|
|
700
|
+
style: {
|
|
701
|
+
position: "absolute",
|
|
702
|
+
left: 0,
|
|
703
|
+
top: 0,
|
|
704
|
+
width: "100%",
|
|
705
|
+
height: rect.y,
|
|
706
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
707
|
+
pointerEvents: "none"
|
|
708
|
+
}
|
|
978
709
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
710
|
+
),
|
|
711
|
+
/* @__PURE__ */ jsx3(
|
|
712
|
+
"div",
|
|
713
|
+
{
|
|
714
|
+
style: {
|
|
715
|
+
position: "absolute",
|
|
716
|
+
left: 0,
|
|
717
|
+
top: rect.y,
|
|
718
|
+
width: rect.x,
|
|
719
|
+
height: rect.h,
|
|
720
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
721
|
+
pointerEvents: "none"
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
/* @__PURE__ */ jsx3(
|
|
726
|
+
"div",
|
|
727
|
+
{
|
|
728
|
+
style: {
|
|
729
|
+
position: "absolute",
|
|
730
|
+
left: rect.x + rect.w,
|
|
731
|
+
top: rect.y,
|
|
732
|
+
width: `calc(100% - ${rect.x + rect.w}px)`,
|
|
733
|
+
height: rect.h,
|
|
734
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
735
|
+
pointerEvents: "none"
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
),
|
|
739
|
+
/* @__PURE__ */ jsx3(
|
|
740
|
+
"div",
|
|
741
|
+
{
|
|
742
|
+
style: {
|
|
743
|
+
position: "absolute",
|
|
744
|
+
left: 0,
|
|
745
|
+
top: rect.y + rect.h,
|
|
746
|
+
width: "100%",
|
|
747
|
+
height: `calc(100% - ${rect.y + rect.h}px)`,
|
|
748
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
749
|
+
pointerEvents: "none"
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
),
|
|
753
|
+
/* @__PURE__ */ jsx3(
|
|
754
|
+
"div",
|
|
755
|
+
{
|
|
756
|
+
style: {
|
|
757
|
+
position: "absolute",
|
|
758
|
+
left: rect.x,
|
|
759
|
+
top: rect.y,
|
|
760
|
+
width: rect.w,
|
|
761
|
+
height: rect.h,
|
|
762
|
+
background: "rgba(125, 211, 252, 0.08)",
|
|
763
|
+
pointerEvents: "none",
|
|
764
|
+
borderRadius: 12
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
),
|
|
982
768
|
/* @__PURE__ */ jsx3(
|
|
983
769
|
"div",
|
|
984
770
|
{
|
|
@@ -989,17 +775,19 @@ function Selector({ onSelect, onCancel }) {
|
|
|
989
775
|
width: rect.w,
|
|
990
776
|
height: rect.h,
|
|
991
777
|
border: "1.5px dashed rgba(255, 255, 255, 0.45)",
|
|
992
|
-
|
|
778
|
+
borderRadius: 12,
|
|
779
|
+
pointerEvents: "none",
|
|
780
|
+
boxShadow: "0 0 0 1px rgba(125, 211, 252, 0.38)"
|
|
993
781
|
}
|
|
994
782
|
}
|
|
995
783
|
),
|
|
996
|
-
|
|
784
|
+
[1, 2].map((line) => /* @__PURE__ */ jsxs2(React3.Fragment, { children: [
|
|
997
785
|
/* @__PURE__ */ jsx3(
|
|
998
786
|
"div",
|
|
999
787
|
{
|
|
1000
788
|
style: {
|
|
1001
789
|
position: "absolute",
|
|
1002
|
-
left: rect.x + rect.w *
|
|
790
|
+
left: rect.x + rect.w * line / 3,
|
|
1003
791
|
top: rect.y,
|
|
1004
792
|
width: 0,
|
|
1005
793
|
height: rect.h,
|
|
@@ -1014,7 +802,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1014
802
|
style: {
|
|
1015
803
|
position: "absolute",
|
|
1016
804
|
left: rect.x,
|
|
1017
|
-
top: rect.y + rect.h *
|
|
805
|
+
top: rect.y + rect.h * line / 3,
|
|
1018
806
|
width: rect.w,
|
|
1019
807
|
height: 0,
|
|
1020
808
|
borderTop: "1px dashed rgba(255, 255, 255, 0.18)",
|
|
@@ -1022,327 +810,521 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1022
810
|
}
|
|
1023
811
|
}
|
|
1024
812
|
)
|
|
1025
|
-
] },
|
|
1026
|
-
|
|
813
|
+
] }, line)),
|
|
814
|
+
[
|
|
1027
815
|
[rect.x, rect.y],
|
|
1028
816
|
[rect.x + rect.w, rect.y],
|
|
1029
817
|
[rect.x, rect.y + rect.h],
|
|
1030
818
|
[rect.x + rect.w, rect.y + rect.h]
|
|
1031
|
-
].map(([cx, cy],
|
|
819
|
+
].map(([cx, cy], index) => /* @__PURE__ */ jsx3(
|
|
820
|
+
"div",
|
|
821
|
+
{
|
|
822
|
+
style: {
|
|
823
|
+
position: "absolute",
|
|
824
|
+
left: cx - HANDLE_R,
|
|
825
|
+
top: cy - HANDLE_R,
|
|
826
|
+
width: HANDLE_R * 2,
|
|
827
|
+
height: HANDLE_R * 2,
|
|
828
|
+
borderRadius: "50%",
|
|
829
|
+
border: "2px solid rgba(255, 255, 255, 0.8)",
|
|
830
|
+
background: "rgba(0, 0, 0, 0.25)",
|
|
831
|
+
pointerEvents: "none"
|
|
832
|
+
}
|
|
833
|
+
},
|
|
834
|
+
index
|
|
835
|
+
))
|
|
836
|
+
] }) : /* @__PURE__ */ jsx3(
|
|
837
|
+
"div",
|
|
838
|
+
{
|
|
839
|
+
style: {
|
|
840
|
+
position: "absolute",
|
|
841
|
+
inset: 0,
|
|
842
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
843
|
+
pointerEvents: "none"
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
)
|
|
847
|
+
]
|
|
848
|
+
}
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// src/overlay/ui/toolbar.tsx
|
|
853
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
854
|
+
var MODES = [
|
|
855
|
+
{ mode: "area", label: "Capture Selected Area", icon: Crop },
|
|
856
|
+
{ mode: "viewport", label: "Capture Viewport", icon: Monitor },
|
|
857
|
+
{ mode: "fullpage", label: "Capture Full Page", icon: FileText },
|
|
858
|
+
{ mode: "component", label: "Capture Component", icon: MousePointer2 }
|
|
859
|
+
];
|
|
860
|
+
function Toolbar({
|
|
861
|
+
selectedMode,
|
|
862
|
+
onModeChange,
|
|
863
|
+
onCapture,
|
|
864
|
+
onCancel,
|
|
865
|
+
magnetEnabled,
|
|
866
|
+
onMagnetChange,
|
|
867
|
+
areaSelectionActive,
|
|
868
|
+
areaRect,
|
|
869
|
+
areaAspect,
|
|
870
|
+
areaPresets,
|
|
871
|
+
onAreaSizeChange,
|
|
872
|
+
onAreaPositionChange,
|
|
873
|
+
onAreaAspectChange,
|
|
874
|
+
onAreaSavePreset,
|
|
875
|
+
onAreaLoadPreset
|
|
876
|
+
}) {
|
|
877
|
+
const [settingsOpen, setSettingsOpen] = useState5(false);
|
|
878
|
+
const [aspectOpen, setAspectOpen] = useState5(false);
|
|
879
|
+
const [savedOpen, setSavedOpen] = useState5(false);
|
|
880
|
+
const showAreaControls = selectedMode === "area" && areaSelectionActive && areaRect !== null;
|
|
881
|
+
const activeAreaRect = showAreaControls ? areaRect : null;
|
|
882
|
+
useEffect4(() => {
|
|
883
|
+
const onKey = (e) => {
|
|
884
|
+
if (e.target?.tagName === "INPUT") {
|
|
885
|
+
if (e.key === "Escape") {
|
|
886
|
+
e.target.blur();
|
|
887
|
+
}
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
if (e.key === "Escape") {
|
|
891
|
+
if (settingsOpen) {
|
|
892
|
+
setSettingsOpen(false);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (aspectOpen) {
|
|
896
|
+
setAspectOpen(false);
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (savedOpen) {
|
|
900
|
+
setSavedOpen(false);
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
onCancel();
|
|
904
|
+
} else if (e.key === "Enter") {
|
|
905
|
+
onCapture(selectedMode);
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
document.addEventListener("keydown", onKey);
|
|
909
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
910
|
+
}, [aspectOpen, onCancel, onCapture, savedOpen, selectedMode, settingsOpen]);
|
|
911
|
+
return /* @__PURE__ */ jsxs3(
|
|
912
|
+
"div",
|
|
913
|
+
{
|
|
914
|
+
"data-afterbefore": "true",
|
|
915
|
+
style: {
|
|
916
|
+
position: "fixed",
|
|
917
|
+
bottom: 48,
|
|
918
|
+
left: "50%",
|
|
919
|
+
transform: "translateX(-50%)",
|
|
920
|
+
zIndex: 2147483647,
|
|
921
|
+
display: "flex",
|
|
922
|
+
alignItems: "center",
|
|
923
|
+
gap: 10,
|
|
924
|
+
flexWrap: "wrap",
|
|
925
|
+
justifyContent: "center",
|
|
926
|
+
maxWidth: "min(calc(100vw - 32px), 1120px)",
|
|
927
|
+
background: "rgba(32, 32, 36, 0.92)",
|
|
928
|
+
backdropFilter: "blur(20px)",
|
|
929
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
930
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
931
|
+
borderRadius: 18,
|
|
932
|
+
padding: "6px 10px",
|
|
933
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
934
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
935
|
+
},
|
|
936
|
+
children: [
|
|
937
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 0 }, children: [
|
|
938
|
+
/* @__PURE__ */ jsx4(CloseButton, { onClick: onCancel }),
|
|
939
|
+
/* @__PURE__ */ jsx4("div", { style: { display: "flex", alignItems: "center", gap: 2, padding: "0 4px" }, children: MODES.map(({ mode, label, icon: Icon2 }) => /* @__PURE__ */ jsx4(
|
|
940
|
+
ModeButton,
|
|
941
|
+
{
|
|
942
|
+
label,
|
|
943
|
+
selected: selectedMode === mode,
|
|
944
|
+
onClick: () => {
|
|
945
|
+
setSettingsOpen(false);
|
|
946
|
+
onModeChange(mode);
|
|
947
|
+
},
|
|
948
|
+
children: /* @__PURE__ */ jsx4(Icon2, { size: 18, strokeWidth: 1.7 })
|
|
949
|
+
},
|
|
950
|
+
mode
|
|
951
|
+
)) }),
|
|
952
|
+
/* @__PURE__ */ jsx4(Separator, {}),
|
|
953
|
+
/* @__PURE__ */ jsx4(
|
|
954
|
+
SettingsButton,
|
|
955
|
+
{
|
|
956
|
+
open: settingsOpen,
|
|
957
|
+
onClick: () => {
|
|
958
|
+
setAspectOpen(false);
|
|
959
|
+
setSavedOpen(false);
|
|
960
|
+
setSettingsOpen((prev) => !prev);
|
|
961
|
+
},
|
|
962
|
+
magnetEnabled,
|
|
963
|
+
onMagnetChange
|
|
964
|
+
}
|
|
965
|
+
),
|
|
966
|
+
!showAreaControls && /* @__PURE__ */ jsx4(
|
|
967
|
+
CaptureButton,
|
|
968
|
+
{
|
|
969
|
+
label: "Capture",
|
|
970
|
+
onClick: () => onCapture(selectedMode)
|
|
971
|
+
}
|
|
972
|
+
)
|
|
973
|
+
] }),
|
|
974
|
+
activeAreaRect && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
975
|
+
/* @__PURE__ */ jsx4(Separator, { vertical: false }),
|
|
976
|
+
/* @__PURE__ */ jsxs3(
|
|
977
|
+
"div",
|
|
978
|
+
{
|
|
979
|
+
style: {
|
|
980
|
+
display: "flex",
|
|
981
|
+
alignItems: "center",
|
|
982
|
+
gap: 8,
|
|
983
|
+
flexWrap: "wrap",
|
|
984
|
+
justifyContent: "center"
|
|
985
|
+
},
|
|
986
|
+
children: [
|
|
987
|
+
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Size", children: [
|
|
988
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.w), onChange: (value) => onAreaSizeChange("w", value) }),
|
|
989
|
+
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
990
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.h), onChange: (value) => onAreaSizeChange("h", value) })
|
|
991
|
+
] }),
|
|
992
|
+
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Position", children: [
|
|
993
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.x), onChange: (value) => onAreaPositionChange("x", value) }),
|
|
994
|
+
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
995
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.y), onChange: (value) => onAreaPositionChange("y", value) })
|
|
996
|
+
] }),
|
|
997
|
+
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
998
|
+
/* @__PURE__ */ jsxs3(
|
|
999
|
+
DropButton,
|
|
1000
|
+
{
|
|
1001
|
+
active: areaAspect !== "Free",
|
|
1002
|
+
onClick: () => {
|
|
1003
|
+
setSavedOpen(false);
|
|
1004
|
+
setAspectOpen((prev) => !prev);
|
|
1005
|
+
},
|
|
1006
|
+
children: [
|
|
1007
|
+
areaAspect,
|
|
1008
|
+
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
1009
|
+
]
|
|
1010
|
+
}
|
|
1011
|
+
),
|
|
1012
|
+
aspectOpen && /* @__PURE__ */ jsx4(DropMenu, { children: AREA_ASPECT_RATIOS.map((item) => /* @__PURE__ */ jsx4(
|
|
1013
|
+
DropItem,
|
|
1014
|
+
{
|
|
1015
|
+
active: item.label === areaAspect,
|
|
1016
|
+
onClick: () => {
|
|
1017
|
+
onAreaAspectChange(item.label);
|
|
1018
|
+
setAspectOpen(false);
|
|
1019
|
+
},
|
|
1020
|
+
children: item.label
|
|
1021
|
+
},
|
|
1022
|
+
item.label
|
|
1023
|
+
)) })
|
|
1024
|
+
] }),
|
|
1025
|
+
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1026
|
+
/* @__PURE__ */ jsxs3(
|
|
1027
|
+
DropButton,
|
|
1028
|
+
{
|
|
1029
|
+
onClick: () => {
|
|
1030
|
+
setAspectOpen(false);
|
|
1031
|
+
setSavedOpen((prev) => !prev);
|
|
1032
|
+
},
|
|
1033
|
+
children: [
|
|
1034
|
+
/* @__PURE__ */ jsx4(Save, { size: 14, strokeWidth: 1.8 }),
|
|
1035
|
+
"Saved",
|
|
1036
|
+
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
1037
|
+
]
|
|
1038
|
+
}
|
|
1039
|
+
),
|
|
1040
|
+
savedOpen && /* @__PURE__ */ jsxs3(DropMenu, { children: [
|
|
1041
|
+
/* @__PURE__ */ jsx4(DropItem, { accent: true, onClick: onAreaSavePreset, children: "Save current" }),
|
|
1042
|
+
areaPresets.length > 0 && /* @__PURE__ */ jsx4(MenuDivider, {}),
|
|
1043
|
+
areaPresets.map((preset) => /* @__PURE__ */ jsx4(
|
|
1044
|
+
DropItem,
|
|
1045
|
+
{
|
|
1046
|
+
onClick: () => {
|
|
1047
|
+
onAreaLoadPreset(preset);
|
|
1048
|
+
setSavedOpen(false);
|
|
1049
|
+
},
|
|
1050
|
+
children: preset.label
|
|
1051
|
+
},
|
|
1052
|
+
preset.label
|
|
1053
|
+
)),
|
|
1054
|
+
areaPresets.length === 0 && /* @__PURE__ */ jsx4(
|
|
1055
|
+
"div",
|
|
1056
|
+
{
|
|
1057
|
+
style: {
|
|
1058
|
+
padding: "6px 12px",
|
|
1059
|
+
color: "rgba(255,255,255,0.3)",
|
|
1060
|
+
fontSize: 12
|
|
1061
|
+
},
|
|
1062
|
+
children: "No saved areas"
|
|
1063
|
+
}
|
|
1064
|
+
)
|
|
1065
|
+
] })
|
|
1066
|
+
] })
|
|
1067
|
+
]
|
|
1068
|
+
}
|
|
1069
|
+
)
|
|
1070
|
+
] })
|
|
1071
|
+
]
|
|
1072
|
+
}
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
function CloseButton({ onClick }) {
|
|
1076
|
+
const [hovered, setHovered] = useState5(false);
|
|
1077
|
+
return /* @__PURE__ */ jsx4(
|
|
1078
|
+
"button",
|
|
1079
|
+
{
|
|
1080
|
+
onClick,
|
|
1081
|
+
onMouseEnter: () => setHovered(true),
|
|
1082
|
+
onMouseLeave: () => setHovered(false),
|
|
1083
|
+
style: circleButtonStyle(hovered, true),
|
|
1084
|
+
children: /* @__PURE__ */ jsx4(X, { size: 18, strokeWidth: 1.9 })
|
|
1085
|
+
}
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
function ModeButton({
|
|
1089
|
+
children,
|
|
1090
|
+
label,
|
|
1091
|
+
selected,
|
|
1092
|
+
onClick
|
|
1093
|
+
}) {
|
|
1094
|
+
const [hovered, setHovered] = useState5(false);
|
|
1095
|
+
return /* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1096
|
+
hovered && /* @__PURE__ */ jsx4(
|
|
1097
|
+
"div",
|
|
1098
|
+
{
|
|
1099
|
+
style: {
|
|
1100
|
+
position: "absolute",
|
|
1101
|
+
left: "50%",
|
|
1102
|
+
bottom: "calc(100% + 10px)",
|
|
1103
|
+
transform: "translateX(-50%)",
|
|
1104
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1105
|
+
backdropFilter: "blur(20px)",
|
|
1106
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
1107
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1108
|
+
borderRadius: 8,
|
|
1109
|
+
padding: "5px 10px",
|
|
1110
|
+
color: "rgba(255, 255, 255, 0.88)",
|
|
1111
|
+
fontSize: 12,
|
|
1112
|
+
whiteSpace: "nowrap",
|
|
1113
|
+
boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
|
|
1114
|
+
pointerEvents: "none"
|
|
1115
|
+
},
|
|
1116
|
+
children: label
|
|
1117
|
+
}
|
|
1118
|
+
),
|
|
1119
|
+
/* @__PURE__ */ jsx4(
|
|
1120
|
+
"button",
|
|
1121
|
+
{
|
|
1122
|
+
onClick,
|
|
1123
|
+
onMouseEnter: () => setHovered(true),
|
|
1124
|
+
onMouseLeave: () => setHovered(false),
|
|
1125
|
+
style: {
|
|
1126
|
+
width: 42,
|
|
1127
|
+
height: 40,
|
|
1128
|
+
borderRadius: 12,
|
|
1129
|
+
border: "none",
|
|
1130
|
+
background: selected ? "rgba(255, 255, 255, 0.15)" : hovered ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
1131
|
+
display: "flex",
|
|
1132
|
+
alignItems: "center",
|
|
1133
|
+
justifyContent: "center",
|
|
1134
|
+
cursor: "pointer",
|
|
1135
|
+
padding: 0,
|
|
1136
|
+
color: selected ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
1137
|
+
transition: "background 0.12s ease, color 0.12s ease"
|
|
1138
|
+
},
|
|
1139
|
+
children
|
|
1140
|
+
}
|
|
1141
|
+
)
|
|
1142
|
+
] });
|
|
1143
|
+
}
|
|
1144
|
+
function SettingsButton({
|
|
1145
|
+
open,
|
|
1146
|
+
onClick,
|
|
1147
|
+
magnetEnabled,
|
|
1148
|
+
onMagnetChange
|
|
1149
|
+
}) {
|
|
1150
|
+
const [hovered, setHovered] = useState5(false);
|
|
1151
|
+
return /* @__PURE__ */ jsxs3("div", { style: { position: "relative", marginRight: 6 }, children: [
|
|
1152
|
+
/* @__PURE__ */ jsx4(
|
|
1153
|
+
"button",
|
|
1154
|
+
{
|
|
1155
|
+
onClick,
|
|
1156
|
+
onMouseEnter: () => setHovered(true),
|
|
1157
|
+
onMouseLeave: () => setHovered(false),
|
|
1158
|
+
style: {
|
|
1159
|
+
...circleButtonStyle(open || hovered, false),
|
|
1160
|
+
color: "rgba(255, 255, 255, 0.58)"
|
|
1161
|
+
},
|
|
1162
|
+
children: /* @__PURE__ */ jsx4(Settings2, { size: 18, strokeWidth: 1.7 })
|
|
1163
|
+
}
|
|
1164
|
+
),
|
|
1165
|
+
open && /* @__PURE__ */ jsxs3(
|
|
1166
|
+
"div",
|
|
1167
|
+
{
|
|
1168
|
+
style: {
|
|
1169
|
+
position: "absolute",
|
|
1170
|
+
left: "50%",
|
|
1171
|
+
bottom: "calc(100% + 12px)",
|
|
1172
|
+
transform: "translateX(-50%)",
|
|
1173
|
+
minWidth: 184,
|
|
1174
|
+
padding: "10px 12px",
|
|
1175
|
+
borderRadius: 12,
|
|
1176
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1177
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1178
|
+
boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
|
|
1179
|
+
backdropFilter: "blur(20px)",
|
|
1180
|
+
WebkitBackdropFilter: "blur(20px)"
|
|
1181
|
+
},
|
|
1182
|
+
children: [
|
|
1183
|
+
/* @__PURE__ */ jsx4(
|
|
1032
1184
|
"div",
|
|
1033
1185
|
{
|
|
1034
1186
|
style: {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
i
|
|
1047
|
-
)),
|
|
1048
|
-
placed && /* @__PURE__ */ jsxs3(
|
|
1049
|
-
"div",
|
|
1187
|
+
fontSize: 11,
|
|
1188
|
+
color: "rgba(255, 255, 255, 0.46)",
|
|
1189
|
+
letterSpacing: "0.03em",
|
|
1190
|
+
textTransform: "uppercase",
|
|
1191
|
+
marginBottom: 10
|
|
1192
|
+
},
|
|
1193
|
+
children: "Area Settings"
|
|
1194
|
+
}
|
|
1195
|
+
),
|
|
1196
|
+
/* @__PURE__ */ jsxs3(
|
|
1197
|
+
"label",
|
|
1050
1198
|
{
|
|
1051
|
-
ref: panelRef,
|
|
1052
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
1053
1199
|
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
1200
|
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
|
|
1201
|
+
alignItems: "center",
|
|
1202
|
+
justifyContent: "space-between",
|
|
1203
|
+
gap: 12,
|
|
1204
|
+
cursor: "pointer"
|
|
1072
1205
|
},
|
|
1073
1206
|
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
1207
|
/* @__PURE__ */ jsxs3(
|
|
1121
|
-
"
|
|
1208
|
+
"span",
|
|
1122
1209
|
{
|
|
1123
|
-
style: {
|
|
1210
|
+
style: {
|
|
1211
|
+
display: "flex",
|
|
1212
|
+
alignItems: "center",
|
|
1213
|
+
gap: 8,
|
|
1214
|
+
color: "rgba(255, 255, 255, 0.88)",
|
|
1215
|
+
fontSize: 13
|
|
1216
|
+
},
|
|
1124
1217
|
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
|
-
] })
|
|
1218
|
+
/* @__PURE__ */ jsx4(Magnet, { size: 15, strokeWidth: 1.8 }),
|
|
1219
|
+
"Magnet snap"
|
|
1212
1220
|
]
|
|
1213
1221
|
}
|
|
1214
1222
|
),
|
|
1215
|
-
/* @__PURE__ */
|
|
1216
|
-
"
|
|
1223
|
+
/* @__PURE__ */ jsx4(
|
|
1224
|
+
"button",
|
|
1217
1225
|
{
|
|
1226
|
+
type: "button",
|
|
1227
|
+
onClick: () => onMagnetChange(!magnetEnabled),
|
|
1218
1228
|
style: {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1229
|
+
width: 38,
|
|
1230
|
+
height: 22,
|
|
1231
|
+
borderRadius: 999,
|
|
1232
|
+
border: "none",
|
|
1233
|
+
background: magnetEnabled ? "#38bdf8" : "rgba(255, 255, 255, 0.18)",
|
|
1234
|
+
position: "relative",
|
|
1235
|
+
cursor: "pointer",
|
|
1236
|
+
padding: 0,
|
|
1237
|
+
transition: "background 0.12s ease"
|
|
1222
1238
|
},
|
|
1223
|
-
children: /* @__PURE__ */
|
|
1224
|
-
|
|
1239
|
+
children: /* @__PURE__ */ jsx4(
|
|
1240
|
+
"span",
|
|
1225
1241
|
{
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1242
|
+
style: {
|
|
1243
|
+
position: "absolute",
|
|
1244
|
+
top: 2,
|
|
1245
|
+
left: magnetEnabled ? 18 : 2,
|
|
1246
|
+
width: 18,
|
|
1247
|
+
height: 18,
|
|
1248
|
+
borderRadius: "50%",
|
|
1249
|
+
background: "#fff",
|
|
1250
|
+
transition: "left 0.12s ease"
|
|
1234
1251
|
}
|
|
1235
1252
|
}
|
|
1236
1253
|
)
|
|
1237
1254
|
}
|
|
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
1255
|
)
|
|
1250
1256
|
]
|
|
1251
1257
|
}
|
|
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
1258
|
)
|
|
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
|
|
1259
|
+
]
|
|
1315
1260
|
}
|
|
1316
|
-
)
|
|
1317
|
-
children
|
|
1261
|
+
)
|
|
1318
1262
|
] });
|
|
1319
1263
|
}
|
|
1320
|
-
function
|
|
1321
|
-
|
|
1322
|
-
|
|
1264
|
+
function CaptureButton({
|
|
1265
|
+
label,
|
|
1266
|
+
onClick
|
|
1267
|
+
}) {
|
|
1268
|
+
const [hovered, setHovered] = useState5(false);
|
|
1269
|
+
return /* @__PURE__ */ jsxs3(
|
|
1270
|
+
"button",
|
|
1323
1271
|
{
|
|
1272
|
+
onClick,
|
|
1273
|
+
onMouseEnter: () => setHovered(true),
|
|
1274
|
+
onMouseLeave: () => setHovered(false),
|
|
1324
1275
|
style: {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1276
|
+
padding: "0 18px",
|
|
1277
|
+
height: 40,
|
|
1278
|
+
borderRadius: 12,
|
|
1279
|
+
border: "none",
|
|
1280
|
+
background: hovered ? "#2f7bf8" : "#3b82f6",
|
|
1281
|
+
color: "white",
|
|
1282
|
+
fontSize: 13,
|
|
1283
|
+
fontWeight: 600,
|
|
1284
|
+
fontFamily: "inherit",
|
|
1285
|
+
cursor: "pointer",
|
|
1286
|
+
whiteSpace: "nowrap",
|
|
1287
|
+
transition: "background 0.12s ease",
|
|
1329
1288
|
flexShrink: 0,
|
|
1330
|
-
|
|
1289
|
+
display: "flex",
|
|
1290
|
+
alignItems: "center",
|
|
1291
|
+
gap: 8
|
|
1331
1292
|
},
|
|
1332
|
-
children:
|
|
1293
|
+
children: [
|
|
1294
|
+
/* @__PURE__ */ jsx4(Camera2, { size: 16, strokeWidth: 1.9 }),
|
|
1295
|
+
label
|
|
1296
|
+
]
|
|
1333
1297
|
}
|
|
1334
1298
|
);
|
|
1335
1299
|
}
|
|
1336
|
-
function
|
|
1337
|
-
|
|
1338
|
-
|
|
1300
|
+
function ControlGroup({
|
|
1301
|
+
label,
|
|
1302
|
+
children
|
|
1303
|
+
}) {
|
|
1304
|
+
return /* @__PURE__ */ jsxs3(
|
|
1305
|
+
"div",
|
|
1339
1306
|
{
|
|
1340
1307
|
style: {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1308
|
+
display: "flex",
|
|
1309
|
+
alignItems: "center",
|
|
1310
|
+
gap: 6,
|
|
1311
|
+
padding: "0 4px"
|
|
1344
1312
|
},
|
|
1345
|
-
children
|
|
1313
|
+
children: [
|
|
1314
|
+
/* @__PURE__ */ jsx4(
|
|
1315
|
+
"span",
|
|
1316
|
+
{
|
|
1317
|
+
style: {
|
|
1318
|
+
fontSize: 11,
|
|
1319
|
+
color: "rgba(255, 255, 255, 0.42)",
|
|
1320
|
+
textTransform: "uppercase",
|
|
1321
|
+
letterSpacing: "0.03em"
|
|
1322
|
+
},
|
|
1323
|
+
children: label
|
|
1324
|
+
}
|
|
1325
|
+
),
|
|
1326
|
+
children
|
|
1327
|
+
]
|
|
1346
1328
|
}
|
|
1347
1329
|
);
|
|
1348
1330
|
}
|
|
@@ -1350,12 +1332,14 @@ function NumInput({
|
|
|
1350
1332
|
value,
|
|
1351
1333
|
onChange
|
|
1352
1334
|
}) {
|
|
1353
|
-
const [editing, setEditing] =
|
|
1354
|
-
const [text, setText] =
|
|
1355
|
-
|
|
1356
|
-
if (!editing)
|
|
1357
|
-
|
|
1358
|
-
|
|
1335
|
+
const [editing, setEditing] = useState5(false);
|
|
1336
|
+
const [text, setText] = useState5(String(value));
|
|
1337
|
+
useEffect4(() => {
|
|
1338
|
+
if (!editing) {
|
|
1339
|
+
setText(String(value));
|
|
1340
|
+
}
|
|
1341
|
+
}, [editing, value]);
|
|
1342
|
+
return /* @__PURE__ */ jsx4(
|
|
1359
1343
|
"input",
|
|
1360
1344
|
{
|
|
1361
1345
|
type: "text",
|
|
@@ -1370,14 +1354,16 @@ function NumInput({
|
|
|
1370
1354
|
},
|
|
1371
1355
|
onChange: (e) => setText(e.target.value),
|
|
1372
1356
|
onKeyDown: (e) => {
|
|
1373
|
-
if (e.key === "Enter")
|
|
1357
|
+
if (e.key === "Enter") {
|
|
1358
|
+
e.target.blur();
|
|
1359
|
+
}
|
|
1374
1360
|
},
|
|
1375
1361
|
style: {
|
|
1376
|
-
width:
|
|
1377
|
-
padding: "
|
|
1362
|
+
width: 54,
|
|
1363
|
+
padding: "4px 6px",
|
|
1378
1364
|
background: "rgba(255, 255, 255, 0.07)",
|
|
1379
1365
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1380
|
-
borderRadius:
|
|
1366
|
+
borderRadius: 7,
|
|
1381
1367
|
color: "rgba(255, 255, 255, 0.9)",
|
|
1382
1368
|
fontSize: 12,
|
|
1383
1369
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
@@ -1387,46 +1373,62 @@ function NumInput({
|
|
|
1387
1373
|
}
|
|
1388
1374
|
);
|
|
1389
1375
|
}
|
|
1390
|
-
function
|
|
1376
|
+
function StaticText({ children }) {
|
|
1377
|
+
return /* @__PURE__ */ jsx4(
|
|
1378
|
+
"span",
|
|
1379
|
+
{
|
|
1380
|
+
style: {
|
|
1381
|
+
fontSize: 11,
|
|
1382
|
+
color: "rgba(255,255,255,0.35)",
|
|
1383
|
+
minWidth: 8,
|
|
1384
|
+
textAlign: "center"
|
|
1385
|
+
},
|
|
1386
|
+
children
|
|
1387
|
+
}
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
function DropButton({
|
|
1391
1391
|
children,
|
|
1392
1392
|
onClick,
|
|
1393
1393
|
active
|
|
1394
1394
|
}) {
|
|
1395
|
-
return /* @__PURE__ */
|
|
1395
|
+
return /* @__PURE__ */ jsx4(
|
|
1396
1396
|
"button",
|
|
1397
1397
|
{
|
|
1398
1398
|
onClick,
|
|
1399
1399
|
style: {
|
|
1400
1400
|
display: "flex",
|
|
1401
1401
|
alignItems: "center",
|
|
1402
|
-
gap:
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1402
|
+
gap: 6,
|
|
1403
|
+
height: 34,
|
|
1404
|
+
padding: "0 10px",
|
|
1405
|
+
borderRadius: 10,
|
|
1406
|
+
border: "1px solid rgba(255,255,255,0.08)",
|
|
1407
|
+
background: "rgba(255,255,255,0.04)",
|
|
1408
|
+
color: active ? "rgba(125, 211, 252, 0.96)" : "rgba(255,255,255,0.78)",
|
|
1406
1409
|
cursor: "pointer",
|
|
1407
|
-
fontSize:
|
|
1408
|
-
fontFamily: "inherit"
|
|
1409
|
-
padding: "2px 0"
|
|
1410
|
+
fontSize: 12,
|
|
1411
|
+
fontFamily: "inherit"
|
|
1410
1412
|
},
|
|
1411
1413
|
children
|
|
1412
1414
|
}
|
|
1413
1415
|
);
|
|
1414
1416
|
}
|
|
1415
1417
|
function DropMenu({ children }) {
|
|
1416
|
-
return /* @__PURE__ */
|
|
1418
|
+
return /* @__PURE__ */ jsx4(
|
|
1417
1419
|
"div",
|
|
1418
1420
|
{
|
|
1419
1421
|
style: {
|
|
1420
1422
|
position: "absolute",
|
|
1421
|
-
bottom: "100%",
|
|
1422
|
-
left:
|
|
1423
|
-
|
|
1424
|
-
|
|
1423
|
+
bottom: "calc(100% + 8px)",
|
|
1424
|
+
left: "50%",
|
|
1425
|
+
transform: "translateX(-50%)",
|
|
1426
|
+
minWidth: 120,
|
|
1427
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1425
1428
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1426
|
-
borderRadius:
|
|
1429
|
+
borderRadius: 10,
|
|
1427
1430
|
padding: "4px 0",
|
|
1428
|
-
|
|
1429
|
-
boxShadow: "0 4px 16px rgba(0, 0, 0, 0.3)",
|
|
1431
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
|
|
1430
1432
|
backdropFilter: "blur(20px)",
|
|
1431
1433
|
WebkitBackdropFilter: "blur(20px)"
|
|
1432
1434
|
},
|
|
@@ -1440,17 +1442,17 @@ function DropItem({
|
|
|
1440
1442
|
active,
|
|
1441
1443
|
accent
|
|
1442
1444
|
}) {
|
|
1443
|
-
return /* @__PURE__ */
|
|
1445
|
+
return /* @__PURE__ */ jsx4(
|
|
1444
1446
|
"button",
|
|
1445
1447
|
{
|
|
1446
1448
|
onClick,
|
|
1447
1449
|
style: {
|
|
1448
1450
|
display: "block",
|
|
1449
1451
|
width: "100%",
|
|
1450
|
-
padding: "
|
|
1451
|
-
background: active ? "rgba(255, 255, 255, 0.08)" : "
|
|
1452
|
+
padding: "7px 12px",
|
|
1453
|
+
background: active ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
1452
1454
|
border: "none",
|
|
1453
|
-
color: accent ? "rgba(
|
|
1455
|
+
color: accent ? "rgba(125, 211, 252, 0.96)" : "rgba(255, 255, 255, 0.86)",
|
|
1454
1456
|
textAlign: "left",
|
|
1455
1457
|
cursor: "pointer",
|
|
1456
1458
|
fontSize: 13,
|
|
@@ -1460,123 +1462,56 @@ function DropItem({
|
|
|
1460
1462
|
}
|
|
1461
1463
|
);
|
|
1462
1464
|
}
|
|
1463
|
-
function
|
|
1464
|
-
return /* @__PURE__ */
|
|
1465
|
-
"
|
|
1465
|
+
function MenuDivider() {
|
|
1466
|
+
return /* @__PURE__ */ jsx4(
|
|
1467
|
+
"div",
|
|
1466
1468
|
{
|
|
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"
|
|
1469
|
+
style: {
|
|
1470
|
+
height: 1,
|
|
1471
|
+
background: "rgba(255,255,255,0.08)",
|
|
1472
|
+
margin: "4px 0"
|
|
1510
1473
|
}
|
|
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
1474
|
}
|
|
1527
|
-
)
|
|
1475
|
+
);
|
|
1528
1476
|
}
|
|
1529
|
-
function
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
}) {
|
|
1533
|
-
return /* @__PURE__ */ jsxs3(
|
|
1534
|
-
"button",
|
|
1477
|
+
function Separator({ vertical = true }) {
|
|
1478
|
+
return /* @__PURE__ */ jsx4(
|
|
1479
|
+
"div",
|
|
1535
1480
|
{
|
|
1536
|
-
onClick: onToggle,
|
|
1537
1481
|
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
|
-
]
|
|
1482
|
+
width: vertical ? 1 : 24,
|
|
1483
|
+
height: vertical ? 24 : 1,
|
|
1484
|
+
background: "rgba(255,255,255,0.12)",
|
|
1485
|
+
flexShrink: 0
|
|
1486
|
+
}
|
|
1553
1487
|
}
|
|
1554
1488
|
);
|
|
1555
1489
|
}
|
|
1556
|
-
function
|
|
1557
|
-
return
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1490
|
+
function circleButtonStyle(active, round) {
|
|
1491
|
+
return {
|
|
1492
|
+
width: 40,
|
|
1493
|
+
height: 40,
|
|
1494
|
+
borderRadius: round ? "50%" : 12,
|
|
1495
|
+
border: "none",
|
|
1496
|
+
background: active ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
1497
|
+
display: "flex",
|
|
1498
|
+
alignItems: "center",
|
|
1499
|
+
justifyContent: "center",
|
|
1500
|
+
cursor: "pointer",
|
|
1501
|
+
padding: 0,
|
|
1502
|
+
transition: "background 0.12s ease, color 0.12s ease",
|
|
1503
|
+
marginRight: round ? 6 : 0
|
|
1504
|
+
};
|
|
1570
1505
|
}
|
|
1571
1506
|
|
|
1572
1507
|
// src/overlay/ui/inspector.tsx
|
|
1573
|
-
import { useEffect as
|
|
1574
|
-
import { Fragment as
|
|
1508
|
+
import { useEffect as useEffect5, useRef as useRef3, useCallback as useCallback4, useState as useState6 } from "react";
|
|
1509
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1575
1510
|
function Inspector({ onSelect, onCancel }) {
|
|
1576
|
-
const [highlight, setHighlight] =
|
|
1511
|
+
const [highlight, setHighlight] = useState6(null);
|
|
1577
1512
|
const hoveredEl = useRef3(null);
|
|
1578
1513
|
const styleEl = useRef3(null);
|
|
1579
|
-
|
|
1514
|
+
useEffect5(() => {
|
|
1580
1515
|
const style = document.createElement("style");
|
|
1581
1516
|
style.setAttribute("data-afterbefore", "true");
|
|
1582
1517
|
style.textContent = "*, *::before, *::after { cursor: crosshair !important; }";
|
|
@@ -1586,7 +1521,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1586
1521
|
style.remove();
|
|
1587
1522
|
};
|
|
1588
1523
|
}, []);
|
|
1589
|
-
const isOverlayElement =
|
|
1524
|
+
const isOverlayElement = useCallback4((el) => {
|
|
1590
1525
|
let node = el;
|
|
1591
1526
|
while (node) {
|
|
1592
1527
|
if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
|
|
@@ -1594,7 +1529,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1594
1529
|
}
|
|
1595
1530
|
return false;
|
|
1596
1531
|
}, []);
|
|
1597
|
-
const handleMouseMove =
|
|
1532
|
+
const handleMouseMove = useCallback4(
|
|
1598
1533
|
(e) => {
|
|
1599
1534
|
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
1600
1535
|
if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {
|
|
@@ -1614,7 +1549,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1614
1549
|
},
|
|
1615
1550
|
[isOverlayElement]
|
|
1616
1551
|
);
|
|
1617
|
-
const handleClick =
|
|
1552
|
+
const handleClick = useCallback4(
|
|
1618
1553
|
(e) => {
|
|
1619
1554
|
e.preventDefault();
|
|
1620
1555
|
e.stopPropagation();
|
|
@@ -1625,7 +1560,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1625
1560
|
},
|
|
1626
1561
|
[onSelect]
|
|
1627
1562
|
);
|
|
1628
|
-
const handleKeyDown =
|
|
1563
|
+
const handleKeyDown = useCallback4(
|
|
1629
1564
|
(e) => {
|
|
1630
1565
|
if (e.key === "Escape") {
|
|
1631
1566
|
onCancel();
|
|
@@ -1633,7 +1568,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1633
1568
|
},
|
|
1634
1569
|
[onCancel]
|
|
1635
1570
|
);
|
|
1636
|
-
|
|
1571
|
+
useEffect5(() => {
|
|
1637
1572
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
1638
1573
|
document.addEventListener("click", handleClick, true);
|
|
1639
1574
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -1644,8 +1579,8 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1644
1579
|
};
|
|
1645
1580
|
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
1646
1581
|
return /* @__PURE__ */ jsxs4("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: [
|
|
1647
|
-
highlight && /* @__PURE__ */ jsxs4(
|
|
1648
|
-
/* @__PURE__ */
|
|
1582
|
+
highlight && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1583
|
+
/* @__PURE__ */ jsx5(
|
|
1649
1584
|
"div",
|
|
1650
1585
|
{
|
|
1651
1586
|
style: {
|
|
@@ -1661,7 +1596,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1661
1596
|
}
|
|
1662
1597
|
}
|
|
1663
1598
|
),
|
|
1664
|
-
/* @__PURE__ */
|
|
1599
|
+
/* @__PURE__ */ jsx5(
|
|
1665
1600
|
"div",
|
|
1666
1601
|
{
|
|
1667
1602
|
style: {
|
|
@@ -1682,7 +1617,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1682
1617
|
}
|
|
1683
1618
|
)
|
|
1684
1619
|
] }),
|
|
1685
|
-
!highlight && /* @__PURE__ */
|
|
1620
|
+
!highlight && /* @__PURE__ */ jsx5(
|
|
1686
1621
|
"div",
|
|
1687
1622
|
{
|
|
1688
1623
|
style: {
|
|
@@ -1706,18 +1641,18 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1706
1641
|
}
|
|
1707
1642
|
|
|
1708
1643
|
// src/overlay/ui/status.tsx
|
|
1709
|
-
import { useState as
|
|
1710
|
-
import { jsx as
|
|
1644
|
+
import { useState as useState7, useRef as useRef4, useEffect as useEffect6, useCallback as useCallback5 } from "react";
|
|
1645
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1711
1646
|
var PANEL_WIDTH = 220;
|
|
1712
1647
|
function Status({ onReset, position, onClose }) {
|
|
1713
1648
|
const panelRef = useRef4(null);
|
|
1714
|
-
const [toast, setToast] =
|
|
1715
|
-
const [pushing, setPushing] =
|
|
1716
|
-
const showToast =
|
|
1649
|
+
const [toast, setToast] = useState7(null);
|
|
1650
|
+
const [pushing, setPushing] = useState7(false);
|
|
1651
|
+
const showToast = useCallback5((message, type) => {
|
|
1717
1652
|
setToast({ message, type });
|
|
1718
1653
|
setTimeout(() => setToast(null), 3e3);
|
|
1719
1654
|
}, []);
|
|
1720
|
-
|
|
1655
|
+
useEffect6(() => {
|
|
1721
1656
|
const handler = (e) => {
|
|
1722
1657
|
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
1723
1658
|
onClose();
|
|
@@ -1726,7 +1661,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1726
1661
|
document.addEventListener("mousedown", handler);
|
|
1727
1662
|
return () => document.removeEventListener("mousedown", handler);
|
|
1728
1663
|
}, [onClose]);
|
|
1729
|
-
|
|
1664
|
+
useEffect6(() => {
|
|
1730
1665
|
const handler = (e) => {
|
|
1731
1666
|
if (e.key === "Escape") onClose();
|
|
1732
1667
|
};
|
|
@@ -1821,7 +1756,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1821
1756
|
overflow: "hidden"
|
|
1822
1757
|
},
|
|
1823
1758
|
children: [
|
|
1824
|
-
/* @__PURE__ */
|
|
1759
|
+
/* @__PURE__ */ jsx6(
|
|
1825
1760
|
"div",
|
|
1826
1761
|
{
|
|
1827
1762
|
style: {
|
|
@@ -1843,7 +1778,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1843
1778
|
onMouseEnter: onEnter,
|
|
1844
1779
|
onMouseLeave: onLeave,
|
|
1845
1780
|
children: [
|
|
1846
|
-
/* @__PURE__ */
|
|
1781
|
+
/* @__PURE__ */ jsx6(FolderIcon, {}),
|
|
1847
1782
|
"Open Folder"
|
|
1848
1783
|
]
|
|
1849
1784
|
}
|
|
@@ -1856,7 +1791,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1856
1791
|
onMouseEnter: onEnter,
|
|
1857
1792
|
onMouseLeave: onLeave,
|
|
1858
1793
|
children: [
|
|
1859
|
-
/* @__PURE__ */
|
|
1794
|
+
/* @__PURE__ */ jsx6(CopyIcon, {}),
|
|
1860
1795
|
"Copy Markdown"
|
|
1861
1796
|
]
|
|
1862
1797
|
}
|
|
@@ -1870,12 +1805,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1870
1805
|
onMouseEnter: onEnter,
|
|
1871
1806
|
onMouseLeave: onLeave,
|
|
1872
1807
|
children: [
|
|
1873
|
-
/* @__PURE__ */
|
|
1808
|
+
/* @__PURE__ */ jsx6(PushIcon, {}),
|
|
1874
1809
|
pushing ? "Pushing..." : "Push to PR"
|
|
1875
1810
|
]
|
|
1876
1811
|
}
|
|
1877
1812
|
),
|
|
1878
|
-
/* @__PURE__ */
|
|
1813
|
+
/* @__PURE__ */ jsx6(
|
|
1879
1814
|
"div",
|
|
1880
1815
|
{
|
|
1881
1816
|
style: {
|
|
@@ -1893,13 +1828,13 @@ function Status({ onReset, position, onClose }) {
|
|
|
1893
1828
|
onMouseEnter: onEnter,
|
|
1894
1829
|
onMouseLeave: onLeave,
|
|
1895
1830
|
children: [
|
|
1896
|
-
/* @__PURE__ */
|
|
1831
|
+
/* @__PURE__ */ jsx6(ResetIcon, {}),
|
|
1897
1832
|
"Reset"
|
|
1898
1833
|
]
|
|
1899
1834
|
}
|
|
1900
1835
|
)
|
|
1901
1836
|
] }),
|
|
1902
|
-
toast && /* @__PURE__ */
|
|
1837
|
+
toast && /* @__PURE__ */ jsx6(
|
|
1903
1838
|
"div",
|
|
1904
1839
|
{
|
|
1905
1840
|
style: {
|
|
@@ -1925,14 +1860,14 @@ function Status({ onReset, position, onClose }) {
|
|
|
1925
1860
|
);
|
|
1926
1861
|
}
|
|
1927
1862
|
function FolderIcon() {
|
|
1928
|
-
return /* @__PURE__ */
|
|
1863
|
+
return /* @__PURE__ */ jsx6(
|
|
1929
1864
|
"svg",
|
|
1930
1865
|
{
|
|
1931
1866
|
width: "14",
|
|
1932
1867
|
height: "14",
|
|
1933
1868
|
viewBox: "0 0 14 14",
|
|
1934
1869
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1935
|
-
children: /* @__PURE__ */
|
|
1870
|
+
children: /* @__PURE__ */ jsx6(
|
|
1936
1871
|
"path",
|
|
1937
1872
|
{
|
|
1938
1873
|
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 +1888,7 @@ function CopyIcon() {
|
|
|
1953
1888
|
viewBox: "0 0 14 14",
|
|
1954
1889
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1955
1890
|
children: [
|
|
1956
|
-
/* @__PURE__ */
|
|
1891
|
+
/* @__PURE__ */ jsx6(
|
|
1957
1892
|
"rect",
|
|
1958
1893
|
{
|
|
1959
1894
|
x: "4",
|
|
@@ -1966,7 +1901,7 @@ function CopyIcon() {
|
|
|
1966
1901
|
strokeWidth: "1.3"
|
|
1967
1902
|
}
|
|
1968
1903
|
),
|
|
1969
|
-
/* @__PURE__ */
|
|
1904
|
+
/* @__PURE__ */ jsx6(
|
|
1970
1905
|
"path",
|
|
1971
1906
|
{
|
|
1972
1907
|
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 +1915,14 @@ function CopyIcon() {
|
|
|
1980
1915
|
);
|
|
1981
1916
|
}
|
|
1982
1917
|
function PushIcon() {
|
|
1983
|
-
return /* @__PURE__ */
|
|
1918
|
+
return /* @__PURE__ */ jsx6(
|
|
1984
1919
|
"svg",
|
|
1985
1920
|
{
|
|
1986
1921
|
width: "14",
|
|
1987
1922
|
height: "14",
|
|
1988
1923
|
viewBox: "0 0 14 14",
|
|
1989
1924
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1990
|
-
children: /* @__PURE__ */
|
|
1925
|
+
children: /* @__PURE__ */ jsx6(
|
|
1991
1926
|
"path",
|
|
1992
1927
|
{
|
|
1993
1928
|
d: "M7 11V3m0 0L4 6m3-3l3 3",
|
|
@@ -2010,7 +1945,7 @@ function ResetIcon() {
|
|
|
2010
1945
|
viewBox: "0 0 14 14",
|
|
2011
1946
|
style: { color: "rgba(255,255,255,0.4)" },
|
|
2012
1947
|
children: [
|
|
2013
|
-
/* @__PURE__ */
|
|
1948
|
+
/* @__PURE__ */ jsx6(
|
|
2014
1949
|
"path",
|
|
2015
1950
|
{
|
|
2016
1951
|
d: "M2.5 7a4.5 4.5 0 118 2.5",
|
|
@@ -2020,7 +1955,7 @@ function ResetIcon() {
|
|
|
2020
1955
|
strokeLinecap: "round"
|
|
2021
1956
|
}
|
|
2022
1957
|
),
|
|
2023
|
-
/* @__PURE__ */
|
|
1958
|
+
/* @__PURE__ */ jsx6(
|
|
2024
1959
|
"path",
|
|
2025
1960
|
{
|
|
2026
1961
|
d: "M2.5 3v4h4",
|
|
@@ -2037,7 +1972,7 @@ function ResetIcon() {
|
|
|
2037
1972
|
}
|
|
2038
1973
|
|
|
2039
1974
|
// src/overlay/index.tsx
|
|
2040
|
-
import { jsx as
|
|
1975
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2041
1976
|
async function saveCapture(type, mode, dataUrl) {
|
|
2042
1977
|
try {
|
|
2043
1978
|
const res = await fetch("/__afterbefore/save", {
|
|
@@ -2055,13 +1990,31 @@ async function saveCapture(type, mode, dataUrl) {
|
|
|
2055
1990
|
}
|
|
2056
1991
|
function AfterBefore() {
|
|
2057
1992
|
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] =
|
|
1993
|
+
const [statusOpen, setStatusOpen] = useState8(false);
|
|
1994
|
+
const [toolbarActive, setToolbarActive] = useState8(false);
|
|
1995
|
+
const [selectorActive, setSelectorActive] = useState8(false);
|
|
1996
|
+
const [inspectorActive, setInspectorActive] = useState8(false);
|
|
1997
|
+
const [loading, setLoading] = useState8(false);
|
|
1998
|
+
const [selectedMode, setSelectedMode] = useState8("area");
|
|
1999
|
+
const [magnetEnabled, setMagnetEnabled] = useState8(true);
|
|
2000
|
+
const [areaRect, setAreaRect] = useState8(null);
|
|
2001
|
+
const [areaAspect, setAreaAspect] = useState8(DEFAULT_AREA_ASPECT);
|
|
2002
|
+
const [areaPresets, setAreaPresets] = useState8([]);
|
|
2063
2003
|
const iconPos = useRef5({ x: 24, y: 0 });
|
|
2064
|
-
|
|
2004
|
+
useEffect7(() => {
|
|
2005
|
+
try {
|
|
2006
|
+
setMagnetEnabled(localStorage.getItem("ab-magnet") !== "false");
|
|
2007
|
+
} catch {
|
|
2008
|
+
setMagnetEnabled(true);
|
|
2009
|
+
}
|
|
2010
|
+
try {
|
|
2011
|
+
const savedPresets = localStorage.getItem("ab-area-presets");
|
|
2012
|
+
setAreaPresets(savedPresets ? JSON.parse(savedPresets) : []);
|
|
2013
|
+
} catch {
|
|
2014
|
+
setAreaPresets([]);
|
|
2015
|
+
}
|
|
2016
|
+
}, []);
|
|
2017
|
+
useEffect7(() => {
|
|
2065
2018
|
if (state.phase === "ready") {
|
|
2066
2019
|
const timer = setTimeout(() => {
|
|
2067
2020
|
reset();
|
|
@@ -2070,24 +2023,33 @@ function AfterBefore() {
|
|
|
2070
2023
|
return () => clearTimeout(timer);
|
|
2071
2024
|
}
|
|
2072
2025
|
}, [state.phase, reset]);
|
|
2073
|
-
const handlePositionChange =
|
|
2026
|
+
const handlePositionChange = useCallback6(
|
|
2074
2027
|
(pos) => {
|
|
2075
2028
|
iconPos.current = pos;
|
|
2076
2029
|
},
|
|
2077
2030
|
[]
|
|
2078
2031
|
);
|
|
2079
|
-
const handleIconClick =
|
|
2032
|
+
const handleIconClick = useCallback6(() => {
|
|
2080
2033
|
if (loading) return;
|
|
2081
2034
|
if (state.phase === "ready") {
|
|
2082
2035
|
setStatusOpen((prev) => !prev);
|
|
2083
|
-
} else {
|
|
2084
|
-
setToolbarActive(
|
|
2036
|
+
} else if (toolbarActive) {
|
|
2037
|
+
setToolbarActive(false);
|
|
2085
2038
|
setSelectorActive(false);
|
|
2086
2039
|
setInspectorActive(false);
|
|
2087
2040
|
setStatusOpen(false);
|
|
2041
|
+
} else {
|
|
2042
|
+
setToolbarActive(true);
|
|
2043
|
+
setInspectorActive(false);
|
|
2044
|
+
setStatusOpen(false);
|
|
2045
|
+
if (selectedMode === "area") {
|
|
2046
|
+
setSelectorActive(true);
|
|
2047
|
+
setAreaRect(createInitialAreaRect());
|
|
2048
|
+
setAreaAspect(DEFAULT_AREA_ASPECT);
|
|
2049
|
+
}
|
|
2088
2050
|
}
|
|
2089
|
-
}, [state.phase, loading]);
|
|
2090
|
-
const performCapture =
|
|
2051
|
+
}, [state.phase, loading, toolbarActive, selectedMode]);
|
|
2052
|
+
const performCapture = useCallback6(
|
|
2091
2053
|
async (mode, area, element) => {
|
|
2092
2054
|
setLoading(true);
|
|
2093
2055
|
try {
|
|
@@ -2107,53 +2069,151 @@ function AfterBefore() {
|
|
|
2107
2069
|
},
|
|
2108
2070
|
[state.phase, captureComplete]
|
|
2109
2071
|
);
|
|
2110
|
-
const handleToolbarCapture =
|
|
2072
|
+
const handleToolbarCapture = useCallback6(
|
|
2111
2073
|
(mode) => {
|
|
2112
|
-
setToolbarActive(false);
|
|
2113
2074
|
if (mode === "area") {
|
|
2114
|
-
|
|
2075
|
+
if (areaRect) {
|
|
2076
|
+
setSelectorActive(false);
|
|
2077
|
+
setToolbarActive(false);
|
|
2078
|
+
performCapture("area", {
|
|
2079
|
+
x: Math.round(areaRect.x),
|
|
2080
|
+
y: Math.round(areaRect.y),
|
|
2081
|
+
width: Math.round(areaRect.w),
|
|
2082
|
+
height: Math.round(areaRect.h)
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
2085
|
+
return;
|
|
2115
2086
|
} else if (mode === "viewport") {
|
|
2087
|
+
setToolbarActive(false);
|
|
2116
2088
|
performCapture("viewport");
|
|
2117
2089
|
} else if (mode === "fullpage") {
|
|
2090
|
+
setToolbarActive(false);
|
|
2118
2091
|
performCapture("fullpage");
|
|
2119
2092
|
} else if (mode === "component") {
|
|
2093
|
+
setToolbarActive(false);
|
|
2120
2094
|
setInspectorActive(true);
|
|
2121
2095
|
}
|
|
2122
2096
|
},
|
|
2123
|
-
[performCapture]
|
|
2097
|
+
[areaRect, performCapture]
|
|
2124
2098
|
);
|
|
2125
|
-
const handleToolbarCancel =
|
|
2099
|
+
const handleToolbarCancel = useCallback6(() => {
|
|
2126
2100
|
setToolbarActive(false);
|
|
2101
|
+
setSelectorActive(false);
|
|
2127
2102
|
}, []);
|
|
2128
|
-
const handleComponentSelect =
|
|
2103
|
+
const handleComponentSelect = useCallback6(
|
|
2129
2104
|
(element) => {
|
|
2130
2105
|
setInspectorActive(false);
|
|
2131
2106
|
performCapture("component", void 0, element);
|
|
2132
2107
|
},
|
|
2133
2108
|
[performCapture]
|
|
2134
2109
|
);
|
|
2135
|
-
const handleComponentCancel =
|
|
2110
|
+
const handleComponentCancel = useCallback6(() => {
|
|
2136
2111
|
setInspectorActive(false);
|
|
2112
|
+
setToolbarActive(true);
|
|
2137
2113
|
}, []);
|
|
2138
|
-
const handleAreaSelect =
|
|
2114
|
+
const handleAreaSelect = useCallback6(
|
|
2139
2115
|
(area) => {
|
|
2140
2116
|
setSelectorActive(false);
|
|
2117
|
+
setToolbarActive(false);
|
|
2141
2118
|
performCapture("area", area);
|
|
2142
2119
|
},
|
|
2143
2120
|
[performCapture]
|
|
2144
2121
|
);
|
|
2145
|
-
const handleAreaCancel =
|
|
2122
|
+
const handleAreaCancel = useCallback6(() => {
|
|
2146
2123
|
setSelectorActive(false);
|
|
2124
|
+
setToolbarActive(true);
|
|
2125
|
+
}, []);
|
|
2126
|
+
const handleMagnetChange = useCallback6((enabled) => {
|
|
2127
|
+
setMagnetEnabled(enabled);
|
|
2128
|
+
try {
|
|
2129
|
+
localStorage.setItem("ab-magnet", String(enabled));
|
|
2130
|
+
} catch {
|
|
2131
|
+
}
|
|
2132
|
+
}, []);
|
|
2133
|
+
const handleModeChange = useCallback6((mode) => {
|
|
2134
|
+
setSelectedMode(mode);
|
|
2135
|
+
if (mode === "area") {
|
|
2136
|
+
setSelectorActive(true);
|
|
2137
|
+
setAreaRect(createInitialAreaRect());
|
|
2138
|
+
setAreaAspect(DEFAULT_AREA_ASPECT);
|
|
2139
|
+
} else {
|
|
2140
|
+
setSelectorActive(false);
|
|
2141
|
+
}
|
|
2142
|
+
}, []);
|
|
2143
|
+
const handleAreaRectChange = useCallback6((nextRect) => {
|
|
2144
|
+
setAreaRect(nextRect);
|
|
2145
|
+
}, []);
|
|
2146
|
+
const handleAreaSizeChange = useCallback6(
|
|
2147
|
+
(field, value) => {
|
|
2148
|
+
const nextValue = parseInt(value, 10);
|
|
2149
|
+
if (Number.isNaN(nextValue) || nextValue < 20 || !areaRect) {
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
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];
|
|
2153
|
+
if (field === "w") {
|
|
2154
|
+
setAreaRect({
|
|
2155
|
+
...areaRect,
|
|
2156
|
+
w: nextValue,
|
|
2157
|
+
h: aspectRatio > 0 ? nextValue / aspectRatio : areaRect.h
|
|
2158
|
+
});
|
|
2159
|
+
} else {
|
|
2160
|
+
setAreaRect({
|
|
2161
|
+
...areaRect,
|
|
2162
|
+
h: nextValue,
|
|
2163
|
+
w: aspectRatio > 0 ? nextValue * aspectRatio : areaRect.w
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
},
|
|
2167
|
+
[areaAspect, areaRect]
|
|
2168
|
+
);
|
|
2169
|
+
const handleAreaPositionChange = useCallback6(
|
|
2170
|
+
(field, value) => {
|
|
2171
|
+
const nextValue = parseInt(value, 10);
|
|
2172
|
+
if (Number.isNaN(nextValue) || !areaRect) {
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
setAreaRect({ ...areaRect, [field]: nextValue });
|
|
2176
|
+
},
|
|
2177
|
+
[areaRect]
|
|
2178
|
+
);
|
|
2179
|
+
const handleAreaAspectChange = useCallback6(
|
|
2180
|
+
(nextAspect) => {
|
|
2181
|
+
setAreaAspect(nextAspect);
|
|
2182
|
+
if (!areaRect || nextAspect === "Free") {
|
|
2183
|
+
return;
|
|
2184
|
+
}
|
|
2185
|
+
const aspectRatio = { "16:9": 16 / 9, "4:3": 4 / 3, "1:1": 1, "3:2": 3 / 2, "21:9": 21 / 9 }[nextAspect];
|
|
2186
|
+
setAreaRect({ ...areaRect, h: areaRect.w / aspectRatio });
|
|
2187
|
+
},
|
|
2188
|
+
[areaRect]
|
|
2189
|
+
);
|
|
2190
|
+
const handleAreaSavePreset = useCallback6(() => {
|
|
2191
|
+
if (!areaRect) {
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
const label = `${Math.round(areaRect.w)}x${Math.round(areaRect.h)}`;
|
|
2195
|
+
const nextPresets = [
|
|
2196
|
+
...areaPresets.filter((preset) => preset.label !== label),
|
|
2197
|
+
{ label, rect: { ...areaRect } }
|
|
2198
|
+
];
|
|
2199
|
+
setAreaPresets(nextPresets);
|
|
2200
|
+
try {
|
|
2201
|
+
localStorage.setItem("ab-area-presets", JSON.stringify(nextPresets));
|
|
2202
|
+
} catch {
|
|
2203
|
+
}
|
|
2204
|
+
}, [areaPresets, areaRect]);
|
|
2205
|
+
const handleAreaLoadPreset = useCallback6((preset) => {
|
|
2206
|
+
setAreaRect({ ...preset.rect });
|
|
2147
2207
|
}, []);
|
|
2148
|
-
const handleReset =
|
|
2208
|
+
const handleReset = useCallback6(() => {
|
|
2149
2209
|
reset();
|
|
2150
2210
|
setStatusOpen(false);
|
|
2151
2211
|
}, [reset]);
|
|
2152
|
-
const handleStatusClose =
|
|
2212
|
+
const handleStatusClose = useCallback6(() => {
|
|
2153
2213
|
setStatusOpen(false);
|
|
2154
2214
|
}, []);
|
|
2155
2215
|
return /* @__PURE__ */ jsxs6("div", { "data-afterbefore": "true", children: [
|
|
2156
|
-
/* @__PURE__ */
|
|
2216
|
+
/* @__PURE__ */ jsx7(
|
|
2157
2217
|
Icon,
|
|
2158
2218
|
{
|
|
2159
2219
|
phase: state.phase,
|
|
@@ -2162,16 +2222,40 @@ function AfterBefore() {
|
|
|
2162
2222
|
onPositionChange: handlePositionChange
|
|
2163
2223
|
}
|
|
2164
2224
|
),
|
|
2165
|
-
toolbarActive && !selectorActive && !inspectorActive && /* @__PURE__ */
|
|
2166
|
-
|
|
2225
|
+
toolbarActive && !selectorActive && !inspectorActive && !loading && /* @__PURE__ */ jsx7(CapturePreview, { mode: selectedMode }),
|
|
2226
|
+
toolbarActive && !inspectorActive && /* @__PURE__ */ jsx7(
|
|
2227
|
+
Toolbar,
|
|
2228
|
+
{
|
|
2229
|
+
selectedMode,
|
|
2230
|
+
onModeChange: handleModeChange,
|
|
2231
|
+
onCapture: handleToolbarCapture,
|
|
2232
|
+
onCancel: handleToolbarCancel,
|
|
2233
|
+
magnetEnabled,
|
|
2234
|
+
onMagnetChange: handleMagnetChange,
|
|
2235
|
+
areaSelectionActive: selectorActive,
|
|
2236
|
+
areaRect,
|
|
2237
|
+
areaAspect,
|
|
2238
|
+
areaPresets,
|
|
2239
|
+
onAreaSizeChange: handleAreaSizeChange,
|
|
2240
|
+
onAreaPositionChange: handleAreaPositionChange,
|
|
2241
|
+
onAreaAspectChange: handleAreaAspectChange,
|
|
2242
|
+
onAreaSavePreset: handleAreaSavePreset,
|
|
2243
|
+
onAreaLoadPreset: handleAreaLoadPreset
|
|
2244
|
+
}
|
|
2245
|
+
),
|
|
2246
|
+
selectorActive && /* @__PURE__ */ jsx7(
|
|
2167
2247
|
Selector,
|
|
2168
2248
|
{
|
|
2249
|
+
rect: areaRect,
|
|
2250
|
+
aspect: areaAspect,
|
|
2251
|
+
onRectChange: handleAreaRectChange,
|
|
2169
2252
|
onSelect: handleAreaSelect,
|
|
2170
|
-
onCancel: handleAreaCancel
|
|
2253
|
+
onCancel: handleAreaCancel,
|
|
2254
|
+
magnetEnabled
|
|
2171
2255
|
}
|
|
2172
2256
|
),
|
|
2173
|
-
inspectorActive && /* @__PURE__ */
|
|
2174
|
-
statusOpen && state.phase === "ready" && /* @__PURE__ */
|
|
2257
|
+
inspectorActive && /* @__PURE__ */ jsx7(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel }),
|
|
2258
|
+
statusOpen && state.phase === "ready" && /* @__PURE__ */ jsx7(
|
|
2175
2259
|
Status,
|
|
2176
2260
|
{
|
|
2177
2261
|
onReset: handleReset,
|