afterbefore 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/overlay/index.js +1135 -990
- 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
|
-
|
|
257
|
+
LoaderCircle,
|
|
272
258
|
{
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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",
|
|
294
|
-
{
|
|
295
|
-
d: "M4 10l4 4 8-8",
|
|
296
|
-
fill: "none",
|
|
297
|
-
stroke: "#4ade80",
|
|
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,15 +303,155 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
368
303
|
);
|
|
369
304
|
}
|
|
370
305
|
|
|
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);
|
|
324
|
+
useEffect2(() => {
|
|
325
|
+
if (mode !== "area") {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const syncRect = () => {
|
|
329
|
+
setAreaRect(getAreaPreviewRect());
|
|
330
|
+
};
|
|
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(
|
|
347
|
+
"div",
|
|
348
|
+
{
|
|
349
|
+
style: {
|
|
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
|
+
}
|
|
360
|
+
}
|
|
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(
|
|
379
|
+
"div",
|
|
380
|
+
{
|
|
381
|
+
style: {
|
|
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)"
|
|
394
|
+
},
|
|
395
|
+
children: mode === "fullpage" ? "Full-page capture begins from the current viewport" : "Current viewport capture"
|
|
396
|
+
}
|
|
397
|
+
)
|
|
398
|
+
}
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
return /* @__PURE__ */ jsx2(
|
|
402
|
+
"div",
|
|
403
|
+
{
|
|
404
|
+
"data-afterbefore": "true",
|
|
405
|
+
style: {
|
|
406
|
+
position: "fixed",
|
|
407
|
+
inset: 0,
|
|
408
|
+
zIndex: 2147483645,
|
|
409
|
+
pointerEvents: "none"
|
|
410
|
+
},
|
|
411
|
+
children: /* @__PURE__ */ jsx2(
|
|
412
|
+
"div",
|
|
413
|
+
{
|
|
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"
|
|
429
|
+
}
|
|
430
|
+
)
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
}
|
|
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";
|
|
449
|
+
|
|
371
450
|
// src/overlay/ui/selector.tsx
|
|
372
|
-
import
|
|
373
|
-
import { Fragment, jsx as
|
|
374
|
-
var
|
|
375
|
-
var
|
|
376
|
-
var MIN_SIZE = 20;
|
|
377
|
-
var PANEL_HEIGHT_EST = 140;
|
|
378
|
-
var SNAP_THRESHOLD = 8;
|
|
379
|
-
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 = [
|
|
380
455
|
{ label: "Free", value: 0 },
|
|
381
456
|
{ label: "16:9", value: 16 / 9 },
|
|
382
457
|
{ label: "4:3", value: 4 / 3 },
|
|
@@ -384,112 +459,94 @@ var ASPECT_RATIOS = [
|
|
|
384
459
|
{ label: "3:2", value: 3 / 2 },
|
|
385
460
|
{ label: "21:9", value: 21 / 9 }
|
|
386
461
|
];
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
+
}) {
|
|
490
|
+
const [snappedX, setSnappedX] = useState4(false);
|
|
412
491
|
const mode = useRef2("none");
|
|
413
492
|
const start = useRef2({ x: 0, y: 0 });
|
|
414
493
|
const snapRef = useRef2({ x: 0, y: 0, w: 0, h: 0 });
|
|
415
494
|
const corner = useRef2("br");
|
|
416
|
-
const
|
|
417
|
-
const ratio = ASPECT_RATIOS.find((a) => a.label === aspect)?.value ?? 0;
|
|
495
|
+
const ratio = useMemo(() => getAspectRatio(aspect), [aspect]);
|
|
418
496
|
const applySnap = useCallback3(
|
|
419
|
-
(
|
|
420
|
-
if (!
|
|
497
|
+
(nextRect) => {
|
|
498
|
+
if (!magnetEnabled) {
|
|
421
499
|
setSnappedX(false);
|
|
422
|
-
return
|
|
500
|
+
return nextRect;
|
|
423
501
|
}
|
|
424
|
-
const
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
if (Math.abs(centerX - viewCenterX) < SNAP_THRESHOLD) {
|
|
502
|
+
const centerX = nextRect.x + nextRect.w / 2;
|
|
503
|
+
const viewportCenterX = window.innerWidth / 2;
|
|
504
|
+
if (Math.abs(centerX - viewportCenterX) < SNAP_THRESHOLD) {
|
|
428
505
|
setSnappedX(true);
|
|
429
|
-
return { ...
|
|
506
|
+
return { ...nextRect, x: viewportCenterX - nextRect.w / 2 };
|
|
430
507
|
}
|
|
431
508
|
setSnappedX(false);
|
|
432
|
-
return
|
|
509
|
+
return nextRect;
|
|
433
510
|
},
|
|
434
|
-
[
|
|
511
|
+
[magnetEnabled]
|
|
435
512
|
);
|
|
436
|
-
|
|
513
|
+
useEffect3(() => {
|
|
437
514
|
const onKey = (e) => {
|
|
438
|
-
if (e.target?.tagName === "INPUT") {
|
|
439
|
-
if (e.key === "Escape") e.target.blur();
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
515
|
if (e.key === "Escape") {
|
|
443
|
-
|
|
444
|
-
setPlaced(false);
|
|
445
|
-
setRect(null);
|
|
446
|
-
} else {
|
|
447
|
-
onCancel();
|
|
448
|
-
}
|
|
449
|
-
} else if (e.key === "Enter" && placed && rect) {
|
|
450
|
-
onSelect({
|
|
451
|
-
x: Math.round(rect.x),
|
|
452
|
-
y: Math.round(rect.y),
|
|
453
|
-
width: Math.round(rect.w),
|
|
454
|
-
height: Math.round(rect.h)
|
|
455
|
-
});
|
|
516
|
+
onCancel();
|
|
456
517
|
}
|
|
457
518
|
};
|
|
458
519
|
document.addEventListener("keydown", onKey);
|
|
459
520
|
return () => document.removeEventListener("keydown", onKey);
|
|
460
|
-
}, [
|
|
461
|
-
const hitCorner = useCallback3(
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
return c;
|
|
521
|
+
}, [onCancel]);
|
|
522
|
+
const hitCorner = useCallback3((mx, my, currentRect) => {
|
|
523
|
+
const corners = [
|
|
524
|
+
["tl", currentRect.x, currentRect.y],
|
|
525
|
+
["tr", currentRect.x + currentRect.w, currentRect.y],
|
|
526
|
+
["bl", currentRect.x, currentRect.y + currentRect.h],
|
|
527
|
+
["br", currentRect.x + currentRect.w, currentRect.y + currentRect.h]
|
|
528
|
+
];
|
|
529
|
+
for (const [hitCorner2, cx, cy] of corners) {
|
|
530
|
+
if (Math.abs(mx - cx) <= HANDLE_HIT && Math.abs(my - cy) <= HANDLE_HIT) {
|
|
531
|
+
return hitCorner2;
|
|
472
532
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
);
|
|
533
|
+
}
|
|
534
|
+
return null;
|
|
535
|
+
}, []);
|
|
477
536
|
const hitInside = useCallback3(
|
|
478
|
-
(mx, my,
|
|
537
|
+
(mx, my, currentRect) => mx >= currentRect.x && mx <= currentRect.x + currentRect.w && my >= currentRect.y && my <= currentRect.y + currentRect.h,
|
|
479
538
|
[]
|
|
480
539
|
);
|
|
481
540
|
const onDown = useCallback3(
|
|
482
541
|
(e) => {
|
|
483
|
-
if (panelRef.current?.contains(e.target)) return;
|
|
484
542
|
e.preventDefault();
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
if (c) {
|
|
543
|
+
const mx = e.clientX;
|
|
544
|
+
const my = e.clientY;
|
|
545
|
+
if (rect) {
|
|
546
|
+
const activeCorner = hitCorner(mx, my, rect);
|
|
547
|
+
if (activeCorner) {
|
|
491
548
|
mode.current = "resizing";
|
|
492
|
-
corner.current =
|
|
549
|
+
corner.current = activeCorner;
|
|
493
550
|
start.current = { x: mx, y: my };
|
|
494
551
|
snapRef.current = { ...rect };
|
|
495
552
|
return;
|
|
@@ -500,78 +557,79 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
500
557
|
snapRef.current = { ...rect };
|
|
501
558
|
return;
|
|
502
559
|
}
|
|
503
|
-
setPlaced(false);
|
|
504
560
|
}
|
|
505
561
|
mode.current = "drawing";
|
|
506
562
|
start.current = { x: mx, y: my };
|
|
507
|
-
|
|
563
|
+
onRectChange({ x: mx, y: my, w: 0, h: 0 });
|
|
508
564
|
},
|
|
509
|
-
[
|
|
565
|
+
[hitCorner, hitInside, onRectChange, rect]
|
|
510
566
|
);
|
|
511
567
|
const onMove = useCallback3(
|
|
512
568
|
(e) => {
|
|
513
|
-
const mx = e.clientX
|
|
569
|
+
const mx = e.clientX;
|
|
570
|
+
const my = e.clientY;
|
|
514
571
|
if (mode.current === "drawing") {
|
|
515
|
-
const sx = start.current.x
|
|
516
|
-
|
|
517
|
-
let
|
|
572
|
+
const sx = start.current.x;
|
|
573
|
+
const sy = start.current.y;
|
|
574
|
+
let x = Math.min(sx, mx);
|
|
575
|
+
let y = Math.min(sy, my);
|
|
576
|
+
let w = Math.abs(mx - sx);
|
|
577
|
+
let h = Math.abs(my - sy);
|
|
518
578
|
if (ratio > 0) {
|
|
519
579
|
h = w / ratio;
|
|
520
|
-
if (my < sy)
|
|
580
|
+
if (my < sy) {
|
|
581
|
+
y = sy - h;
|
|
582
|
+
}
|
|
521
583
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
584
|
+
onRectChange(applySnap({ x, y, w, h }));
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (mode.current === "moving") {
|
|
588
|
+
const dx = mx - start.current.x;
|
|
589
|
+
const dy = my - start.current.y;
|
|
590
|
+
onRectChange(
|
|
526
591
|
applySnap({
|
|
527
592
|
...snapRef.current,
|
|
528
593
|
x: snapRef.current.x + dx,
|
|
529
594
|
y: snapRef.current.y + dy
|
|
530
595
|
})
|
|
531
596
|
);
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (mode.current === "resizing") {
|
|
600
|
+
const original = snapRef.current;
|
|
601
|
+
const nextRect = { ...original };
|
|
602
|
+
if (corner.current === "br") {
|
|
603
|
+
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
604
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
605
|
+
} else if (corner.current === "bl") {
|
|
606
|
+
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
607
|
+
nextRect.x = original.x + original.w - nextRect.w;
|
|
608
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);
|
|
609
|
+
} else if (corner.current === "tr") {
|
|
610
|
+
nextRect.w = Math.max(MIN_SIZE, mx - original.x);
|
|
611
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
612
|
+
nextRect.y = original.y + original.h - nextRect.h;
|
|
547
613
|
} else {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
614
|
+
nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);
|
|
615
|
+
nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, original.y + original.h - my);
|
|
616
|
+
nextRect.x = original.x + original.w - nextRect.w;
|
|
617
|
+
nextRect.y = original.y + original.h - nextRect.h;
|
|
552
618
|
}
|
|
553
|
-
|
|
554
|
-
} else if (placed && rect) {
|
|
555
|
-
const c = hitCorner(mx, my, rect);
|
|
556
|
-
if (c === "tl" || c === "br") setCursor("nwse-resize");
|
|
557
|
-
else if (c === "tr" || c === "bl") setCursor("nesw-resize");
|
|
558
|
-
else if (hitInside(mx, my, rect)) setCursor("move");
|
|
559
|
-
else setCursor("crosshair");
|
|
619
|
+
onRectChange(applySnap(nextRect));
|
|
560
620
|
}
|
|
561
621
|
},
|
|
562
|
-
[
|
|
622
|
+
[applySnap, onRectChange, ratio]
|
|
563
623
|
);
|
|
564
624
|
const onUp = useCallback3(
|
|
565
625
|
(e) => {
|
|
566
|
-
const
|
|
567
|
-
if (
|
|
568
|
-
if (rect.w
|
|
569
|
-
|
|
570
|
-
} else {
|
|
571
|
-
setRect(null);
|
|
626
|
+
const previousMode = mode.current;
|
|
627
|
+
if (previousMode === "drawing" && rect) {
|
|
628
|
+
if (rect.w < MIN_SIZE || rect.h < MIN_SIZE) {
|
|
629
|
+
onRectChange(null);
|
|
572
630
|
}
|
|
573
631
|
}
|
|
574
|
-
if (
|
|
632
|
+
if (previousMode === "moving" && rect) {
|
|
575
633
|
const dx = Math.abs(e.clientX - start.current.x);
|
|
576
634
|
const dy = Math.abs(e.clientY - start.current.y);
|
|
577
635
|
if (dx < 3 && dy < 3) {
|
|
@@ -585,49 +643,8 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
585
643
|
}
|
|
586
644
|
mode.current = "none";
|
|
587
645
|
},
|
|
588
|
-
[
|
|
589
|
-
);
|
|
590
|
-
const setSize = useCallback3(
|
|
591
|
-
(field, v) => {
|
|
592
|
-
const n = parseInt(v, 10);
|
|
593
|
-
if (isNaN(n) || n < MIN_SIZE || !rect) return;
|
|
594
|
-
if (field === "w") {
|
|
595
|
-
setRect({ ...rect, w: n, h: ratio > 0 ? n / ratio : rect.h });
|
|
596
|
-
} else {
|
|
597
|
-
setRect({ ...rect, h: n, w: ratio > 0 ? n * ratio : rect.w });
|
|
598
|
-
}
|
|
599
|
-
},
|
|
600
|
-
[rect, ratio]
|
|
601
|
-
);
|
|
602
|
-
const setPos = useCallback3(
|
|
603
|
-
(field, v) => {
|
|
604
|
-
const n = parseInt(v, 10);
|
|
605
|
-
if (isNaN(n) || !rect) return;
|
|
606
|
-
setRect({ ...rect, [field]: n });
|
|
607
|
-
},
|
|
608
|
-
[rect]
|
|
646
|
+
[onRectChange, onSelect, rect]
|
|
609
647
|
);
|
|
610
|
-
const savePreset = useCallback3(() => {
|
|
611
|
-
if (!rect) return;
|
|
612
|
-
const label = `${Math.round(rect.w)}\xD7${Math.round(rect.h)}`;
|
|
613
|
-
const next = [
|
|
614
|
-
...presets.filter((p) => p.label !== label),
|
|
615
|
-
{ label, rect: { ...rect } }
|
|
616
|
-
];
|
|
617
|
-
setPresets(next);
|
|
618
|
-
try {
|
|
619
|
-
localStorage.setItem("ab-area-presets", JSON.stringify(next));
|
|
620
|
-
} catch {
|
|
621
|
-
}
|
|
622
|
-
setSavedOpen(false);
|
|
623
|
-
}, [rect, presets]);
|
|
624
|
-
const loadPreset = useCallback3((p) => {
|
|
625
|
-
setRect({ ...p.rect });
|
|
626
|
-
setPlaced(true);
|
|
627
|
-
setSavedOpen(false);
|
|
628
|
-
}, []);
|
|
629
|
-
const activeCursor = mode.current === "moving" ? "move" : mode.current === "resizing" ? "nwse-resize" : mode.current === "drawing" ? "crosshair" : cursor;
|
|
630
|
-
const panelAbove = rect && rect.y + rect.h + PANEL_HEIGHT_EST > window.innerHeight;
|
|
631
648
|
const hasRect = rect && rect.w > 0 && rect.h > 0;
|
|
632
649
|
return /* @__PURE__ */ jsxs2(
|
|
633
650
|
"div",
|
|
@@ -639,11 +656,11 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
639
656
|
style: {
|
|
640
657
|
position: "fixed",
|
|
641
658
|
inset: 0,
|
|
642
|
-
zIndex:
|
|
643
|
-
cursor:
|
|
659
|
+
zIndex: 2147483646,
|
|
660
|
+
cursor: CAMERA_CURSOR
|
|
644
661
|
},
|
|
645
662
|
children: [
|
|
646
|
-
snappedX && /* @__PURE__ */
|
|
663
|
+
snappedX && /* @__PURE__ */ jsx3(
|
|
647
664
|
"div",
|
|
648
665
|
{
|
|
649
666
|
style: {
|
|
@@ -652,35 +669,85 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
652
669
|
top: 0,
|
|
653
670
|
bottom: 0,
|
|
654
671
|
width: 0,
|
|
655
|
-
borderLeft: "1px solid rgba(
|
|
672
|
+
borderLeft: "1px solid rgba(56, 189, 248, 0.55)",
|
|
656
673
|
pointerEvents: "none",
|
|
657
674
|
zIndex: 2
|
|
658
675
|
}
|
|
659
676
|
}
|
|
660
677
|
),
|
|
661
|
-
/* @__PURE__ */
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
${rect.x + rect.w}px ${rect.y + rect.h}px,
|
|
675
|
-
${rect.x + rect.w}px ${rect.y}px,
|
|
676
|
-
${rect.x}px ${rect.y}px
|
|
677
|
-
)`
|
|
678
|
-
} : {}
|
|
678
|
+
hasRect ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
679
|
+
/* @__PURE__ */ jsx3(
|
|
680
|
+
"div",
|
|
681
|
+
{
|
|
682
|
+
style: {
|
|
683
|
+
position: "absolute",
|
|
684
|
+
left: 0,
|
|
685
|
+
top: 0,
|
|
686
|
+
width: "100%",
|
|
687
|
+
height: rect.y,
|
|
688
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
689
|
+
pointerEvents: "none"
|
|
690
|
+
}
|
|
679
691
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
692
|
+
),
|
|
693
|
+
/* @__PURE__ */ jsx3(
|
|
694
|
+
"div",
|
|
695
|
+
{
|
|
696
|
+
style: {
|
|
697
|
+
position: "absolute",
|
|
698
|
+
left: 0,
|
|
699
|
+
top: rect.y,
|
|
700
|
+
width: rect.x,
|
|
701
|
+
height: rect.h,
|
|
702
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
703
|
+
pointerEvents: "none"
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
),
|
|
707
|
+
/* @__PURE__ */ jsx3(
|
|
708
|
+
"div",
|
|
709
|
+
{
|
|
710
|
+
style: {
|
|
711
|
+
position: "absolute",
|
|
712
|
+
left: rect.x + rect.w,
|
|
713
|
+
top: rect.y,
|
|
714
|
+
width: `calc(100% - ${rect.x + rect.w}px)`,
|
|
715
|
+
height: rect.h,
|
|
716
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
717
|
+
pointerEvents: "none"
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
),
|
|
721
|
+
/* @__PURE__ */ jsx3(
|
|
722
|
+
"div",
|
|
723
|
+
{
|
|
724
|
+
style: {
|
|
725
|
+
position: "absolute",
|
|
726
|
+
left: 0,
|
|
727
|
+
top: rect.y + rect.h,
|
|
728
|
+
width: "100%",
|
|
729
|
+
height: `calc(100% - ${rect.y + rect.h}px)`,
|
|
730
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
731
|
+
pointerEvents: "none"
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
),
|
|
735
|
+
/* @__PURE__ */ jsx3(
|
|
736
|
+
"div",
|
|
737
|
+
{
|
|
738
|
+
style: {
|
|
739
|
+
position: "absolute",
|
|
740
|
+
left: rect.x,
|
|
741
|
+
top: rect.y,
|
|
742
|
+
width: rect.w,
|
|
743
|
+
height: rect.h,
|
|
744
|
+
background: "rgba(125, 211, 252, 0.08)",
|
|
745
|
+
pointerEvents: "none",
|
|
746
|
+
borderRadius: 12
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
),
|
|
750
|
+
/* @__PURE__ */ jsx3(
|
|
684
751
|
"div",
|
|
685
752
|
{
|
|
686
753
|
style: {
|
|
@@ -690,17 +757,19 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
690
757
|
width: rect.w,
|
|
691
758
|
height: rect.h,
|
|
692
759
|
border: "1.5px dashed rgba(255, 255, 255, 0.45)",
|
|
693
|
-
|
|
760
|
+
borderRadius: 12,
|
|
761
|
+
pointerEvents: "none",
|
|
762
|
+
boxShadow: "0 0 0 1px rgba(125, 211, 252, 0.38)"
|
|
694
763
|
}
|
|
695
764
|
}
|
|
696
765
|
),
|
|
697
|
-
|
|
698
|
-
/* @__PURE__ */
|
|
766
|
+
[1, 2].map((line) => /* @__PURE__ */ jsxs2(React3.Fragment, { children: [
|
|
767
|
+
/* @__PURE__ */ jsx3(
|
|
699
768
|
"div",
|
|
700
769
|
{
|
|
701
770
|
style: {
|
|
702
771
|
position: "absolute",
|
|
703
|
-
left: rect.x + rect.w *
|
|
772
|
+
left: rect.x + rect.w * line / 3,
|
|
704
773
|
top: rect.y,
|
|
705
774
|
width: 0,
|
|
706
775
|
height: rect.h,
|
|
@@ -709,13 +778,13 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
709
778
|
}
|
|
710
779
|
}
|
|
711
780
|
),
|
|
712
|
-
/* @__PURE__ */
|
|
781
|
+
/* @__PURE__ */ jsx3(
|
|
713
782
|
"div",
|
|
714
783
|
{
|
|
715
784
|
style: {
|
|
716
785
|
position: "absolute",
|
|
717
786
|
left: rect.x,
|
|
718
|
-
top: rect.y + rect.h *
|
|
787
|
+
top: rect.y + rect.h * line / 3,
|
|
719
788
|
width: rect.w,
|
|
720
789
|
height: 0,
|
|
721
790
|
borderTop: "1px dashed rgba(255, 255, 255, 0.18)",
|
|
@@ -723,13 +792,13 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
723
792
|
}
|
|
724
793
|
}
|
|
725
794
|
)
|
|
726
|
-
] },
|
|
727
|
-
|
|
795
|
+
] }, line)),
|
|
796
|
+
[
|
|
728
797
|
[rect.x, rect.y],
|
|
729
798
|
[rect.x + rect.w, rect.y],
|
|
730
799
|
[rect.x, rect.y + rect.h],
|
|
731
800
|
[rect.x + rect.w, rect.y + rect.h]
|
|
732
|
-
].map(([cx, cy],
|
|
801
|
+
].map(([cx, cy], index) => /* @__PURE__ */ jsx3(
|
|
733
802
|
"div",
|
|
734
803
|
{
|
|
735
804
|
style: {
|
|
@@ -744,382 +813,500 @@ function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
|
744
813
|
pointerEvents: "none"
|
|
745
814
|
}
|
|
746
815
|
},
|
|
747
|
-
|
|
748
|
-
))
|
|
749
|
-
|
|
816
|
+
index
|
|
817
|
+
))
|
|
818
|
+
] }) : /* @__PURE__ */ jsx3(
|
|
819
|
+
"div",
|
|
820
|
+
{
|
|
821
|
+
style: {
|
|
822
|
+
position: "absolute",
|
|
823
|
+
inset: 0,
|
|
824
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
825
|
+
pointerEvents: "none"
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
)
|
|
829
|
+
]
|
|
830
|
+
}
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// src/overlay/ui/toolbar.tsx
|
|
835
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
836
|
+
var MODES = [
|
|
837
|
+
{ mode: "area", label: "Capture Selected Area", icon: Crop },
|
|
838
|
+
{ mode: "viewport", label: "Capture Viewport", icon: Monitor },
|
|
839
|
+
{ mode: "fullpage", label: "Capture Full Page", icon: FileText },
|
|
840
|
+
{ mode: "component", label: "Capture Component", icon: MousePointer2 }
|
|
841
|
+
];
|
|
842
|
+
function Toolbar({
|
|
843
|
+
selectedMode,
|
|
844
|
+
onModeChange,
|
|
845
|
+
onCapture,
|
|
846
|
+
onCancel,
|
|
847
|
+
magnetEnabled,
|
|
848
|
+
onMagnetChange,
|
|
849
|
+
areaSelectionActive,
|
|
850
|
+
areaRect,
|
|
851
|
+
areaAspect,
|
|
852
|
+
areaPresets,
|
|
853
|
+
onAreaSizeChange,
|
|
854
|
+
onAreaPositionChange,
|
|
855
|
+
onAreaAspectChange,
|
|
856
|
+
onAreaSavePreset,
|
|
857
|
+
onAreaLoadPreset
|
|
858
|
+
}) {
|
|
859
|
+
const [settingsOpen, setSettingsOpen] = useState5(false);
|
|
860
|
+
const [aspectOpen, setAspectOpen] = useState5(false);
|
|
861
|
+
const [savedOpen, setSavedOpen] = useState5(false);
|
|
862
|
+
const showAreaControls = selectedMode === "area" && areaSelectionActive && areaRect !== null;
|
|
863
|
+
const activeAreaRect = showAreaControls ? areaRect : null;
|
|
864
|
+
useEffect4(() => {
|
|
865
|
+
const onKey = (e) => {
|
|
866
|
+
if (e.target?.tagName === "INPUT") {
|
|
867
|
+
if (e.key === "Escape") {
|
|
868
|
+
e.target.blur();
|
|
869
|
+
}
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (e.key === "Escape") {
|
|
873
|
+
if (settingsOpen) {
|
|
874
|
+
setSettingsOpen(false);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (aspectOpen) {
|
|
878
|
+
setAspectOpen(false);
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (savedOpen) {
|
|
882
|
+
setSavedOpen(false);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
onCancel();
|
|
886
|
+
} else if (e.key === "Enter") {
|
|
887
|
+
onCapture(selectedMode);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
document.addEventListener("keydown", onKey);
|
|
891
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
892
|
+
}, [aspectOpen, onCancel, onCapture, savedOpen, selectedMode, settingsOpen]);
|
|
893
|
+
return /* @__PURE__ */ jsxs3(
|
|
894
|
+
"div",
|
|
895
|
+
{
|
|
896
|
+
"data-afterbefore": "true",
|
|
897
|
+
style: {
|
|
898
|
+
position: "fixed",
|
|
899
|
+
bottom: 48,
|
|
900
|
+
left: "50%",
|
|
901
|
+
transform: "translateX(-50%)",
|
|
902
|
+
zIndex: 2147483647,
|
|
903
|
+
display: "flex",
|
|
904
|
+
alignItems: "center",
|
|
905
|
+
gap: 10,
|
|
906
|
+
flexWrap: "wrap",
|
|
907
|
+
justifyContent: "center",
|
|
908
|
+
maxWidth: "min(calc(100vw - 32px), 1120px)",
|
|
909
|
+
background: "rgba(32, 32, 36, 0.92)",
|
|
910
|
+
backdropFilter: "blur(20px)",
|
|
911
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
912
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
913
|
+
borderRadius: 18,
|
|
914
|
+
padding: "6px 10px",
|
|
915
|
+
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
916
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
917
|
+
},
|
|
918
|
+
children: [
|
|
919
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 0 }, children: [
|
|
920
|
+
/* @__PURE__ */ jsx4(CloseButton, { onClick: onCancel }),
|
|
921
|
+
/* @__PURE__ */ jsx4("div", { style: { display: "flex", alignItems: "center", gap: 2, padding: "0 4px" }, children: MODES.map(({ mode, label, icon: Icon2 }) => /* @__PURE__ */ jsx4(
|
|
922
|
+
ModeButton,
|
|
923
|
+
{
|
|
924
|
+
label,
|
|
925
|
+
selected: selectedMode === mode,
|
|
926
|
+
onClick: () => {
|
|
927
|
+
setSettingsOpen(false);
|
|
928
|
+
onModeChange(mode);
|
|
929
|
+
},
|
|
930
|
+
children: /* @__PURE__ */ jsx4(Icon2, { size: 18, strokeWidth: 1.7 })
|
|
931
|
+
},
|
|
932
|
+
mode
|
|
933
|
+
)) }),
|
|
934
|
+
/* @__PURE__ */ jsx4(Separator, {}),
|
|
935
|
+
/* @__PURE__ */ jsx4(
|
|
936
|
+
SettingsButton,
|
|
937
|
+
{
|
|
938
|
+
open: settingsOpen,
|
|
939
|
+
onClick: () => {
|
|
940
|
+
setAspectOpen(false);
|
|
941
|
+
setSavedOpen(false);
|
|
942
|
+
setSettingsOpen((prev) => !prev);
|
|
943
|
+
},
|
|
944
|
+
magnetEnabled,
|
|
945
|
+
onMagnetChange
|
|
946
|
+
}
|
|
947
|
+
),
|
|
948
|
+
/* @__PURE__ */ jsx4(
|
|
949
|
+
CaptureButton,
|
|
950
|
+
{
|
|
951
|
+
label: showAreaControls ? "Capture Area" : "Capture",
|
|
952
|
+
onClick: () => onCapture(selectedMode)
|
|
953
|
+
}
|
|
954
|
+
)
|
|
955
|
+
] }),
|
|
956
|
+
activeAreaRect && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
957
|
+
/* @__PURE__ */ jsx4(Separator, { vertical: false }),
|
|
958
|
+
/* @__PURE__ */ jsxs3(
|
|
750
959
|
"div",
|
|
751
960
|
{
|
|
752
|
-
ref: panelRef,
|
|
753
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
754
961
|
style: {
|
|
755
|
-
position: "absolute",
|
|
756
|
-
left: rect.x + rect.w / 2,
|
|
757
|
-
...panelAbove ? { bottom: window.innerHeight - rect.y + 16 } : { top: rect.y + rect.h + 16 },
|
|
758
|
-
transform: "translateX(-50%)",
|
|
759
|
-
background: "rgba(32, 32, 36, 0.92)",
|
|
760
|
-
backdropFilter: "blur(20px)",
|
|
761
|
-
WebkitBackdropFilter: "blur(20px)",
|
|
762
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
763
|
-
borderRadius: 10,
|
|
764
|
-
padding: "10px 14px",
|
|
765
962
|
display: "flex",
|
|
766
|
-
|
|
767
|
-
gap:
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
color: "rgba(255, 255, 255, 0.9)",
|
|
771
|
-
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
772
|
-
zIndex: 1
|
|
963
|
+
alignItems: "center",
|
|
964
|
+
gap: 8,
|
|
965
|
+
flexWrap: "wrap",
|
|
966
|
+
justifyContent: "center"
|
|
773
967
|
},
|
|
774
968
|
children: [
|
|
775
|
-
/* @__PURE__ */
|
|
776
|
-
/* @__PURE__ */
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
),
|
|
783
|
-
/* @__PURE__ */
|
|
784
|
-
/* @__PURE__ */ jsx2(
|
|
785
|
-
NumInput,
|
|
786
|
-
{
|
|
787
|
-
value: Math.round(rect.h),
|
|
788
|
-
onChange: (v) => setSize("h", v)
|
|
789
|
-
}
|
|
790
|
-
),
|
|
791
|
-
/* @__PURE__ */ jsx2(Unit, { children: "px" })
|
|
969
|
+
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Size", children: [
|
|
970
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.w), onChange: (value) => onAreaSizeChange("w", value) }),
|
|
971
|
+
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
972
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.h), onChange: (value) => onAreaSizeChange("h", value) })
|
|
973
|
+
] }),
|
|
974
|
+
/* @__PURE__ */ jsxs3(ControlGroup, { label: "Position", children: [
|
|
975
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.x), onChange: (value) => onAreaPositionChange("x", value) }),
|
|
976
|
+
/* @__PURE__ */ jsx4(StaticText, { children: "x" }),
|
|
977
|
+
/* @__PURE__ */ jsx4(NumInput, { value: Math.round(activeAreaRect.y), onChange: (value) => onAreaPositionChange("y", value) })
|
|
792
978
|
] }),
|
|
793
|
-
/* @__PURE__ */
|
|
794
|
-
/* @__PURE__ */
|
|
795
|
-
|
|
979
|
+
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
980
|
+
/* @__PURE__ */ jsxs3(
|
|
981
|
+
DropButton,
|
|
796
982
|
{
|
|
797
|
-
|
|
798
|
-
|
|
983
|
+
active: areaAspect !== "Free",
|
|
984
|
+
onClick: () => {
|
|
985
|
+
setSavedOpen(false);
|
|
986
|
+
setAspectOpen((prev) => !prev);
|
|
987
|
+
},
|
|
988
|
+
children: [
|
|
989
|
+
areaAspect,
|
|
990
|
+
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
991
|
+
]
|
|
799
992
|
}
|
|
800
993
|
),
|
|
801
|
-
/* @__PURE__ */
|
|
802
|
-
|
|
803
|
-
NumInput,
|
|
994
|
+
aspectOpen && /* @__PURE__ */ jsx4(DropMenu, { children: AREA_ASPECT_RATIOS.map((item) => /* @__PURE__ */ jsx4(
|
|
995
|
+
DropItem,
|
|
804
996
|
{
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
997
|
+
active: item.label === areaAspect,
|
|
998
|
+
onClick: () => {
|
|
999
|
+
onAreaAspectChange(item.label);
|
|
1000
|
+
setAspectOpen(false);
|
|
1001
|
+
},
|
|
1002
|
+
children: item.label
|
|
1003
|
+
},
|
|
1004
|
+
item.label
|
|
1005
|
+
)) })
|
|
810
1006
|
] }),
|
|
811
|
-
/* @__PURE__ */
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
style: {
|
|
815
|
-
height: 1,
|
|
816
|
-
background: "rgba(255, 255, 255, 0.08)",
|
|
817
|
-
margin: "1px 0"
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
),
|
|
821
|
-
/* @__PURE__ */ jsxs2(
|
|
822
|
-
"div",
|
|
823
|
-
{
|
|
824
|
-
style: { display: "flex", alignItems: "center", gap: 12 },
|
|
825
|
-
children: [
|
|
826
|
-
/* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
827
|
-
/* @__PURE__ */ jsxs2(
|
|
828
|
-
DropBtn,
|
|
829
|
-
{
|
|
830
|
-
active: aspect !== "Free",
|
|
831
|
-
onClick: () => {
|
|
832
|
-
setAspectOpen(!aspectOpen);
|
|
833
|
-
setSavedOpen(false);
|
|
834
|
-
},
|
|
835
|
-
children: [
|
|
836
|
-
/* @__PURE__ */ jsx2(AspectIcon, {}),
|
|
837
|
-
aspect === "Free" ? "Free" : aspect,
|
|
838
|
-
/* @__PURE__ */ jsx2(Chevron, {})
|
|
839
|
-
]
|
|
840
|
-
}
|
|
841
|
-
),
|
|
842
|
-
aspectOpen && /* @__PURE__ */ jsx2(DropMenu, { children: ASPECT_RATIOS.map((ar) => /* @__PURE__ */ jsx2(
|
|
843
|
-
DropItem,
|
|
844
|
-
{
|
|
845
|
-
active: ar.label === aspect,
|
|
846
|
-
onClick: () => {
|
|
847
|
-
setAspect(ar.label);
|
|
848
|
-
setAspectOpen(false);
|
|
849
|
-
if (ar.value > 0 && rect) {
|
|
850
|
-
setRect({ ...rect, h: rect.w / ar.value });
|
|
851
|
-
}
|
|
852
|
-
},
|
|
853
|
-
children: ar.label
|
|
854
|
-
},
|
|
855
|
-
ar.label
|
|
856
|
-
)) })
|
|
857
|
-
] }),
|
|
858
|
-
/* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
859
|
-
/* @__PURE__ */ jsxs2(
|
|
860
|
-
DropBtn,
|
|
861
|
-
{
|
|
862
|
-
onClick: () => {
|
|
863
|
-
setSavedOpen(!savedOpen);
|
|
864
|
-
setAspectOpen(false);
|
|
865
|
-
},
|
|
866
|
-
children: [
|
|
867
|
-
/* @__PURE__ */ jsx2(SavedIcon, {}),
|
|
868
|
-
"Saved",
|
|
869
|
-
/* @__PURE__ */ jsx2(Chevron, {})
|
|
870
|
-
]
|
|
871
|
-
}
|
|
872
|
-
),
|
|
873
|
-
savedOpen && /* @__PURE__ */ jsxs2(DropMenu, { children: [
|
|
874
|
-
/* @__PURE__ */ jsx2(
|
|
875
|
-
DropItem,
|
|
876
|
-
{
|
|
877
|
-
accent: true,
|
|
878
|
-
onClick: savePreset,
|
|
879
|
-
children: "Save current"
|
|
880
|
-
}
|
|
881
|
-
),
|
|
882
|
-
presets.length > 0 && /* @__PURE__ */ jsx2(
|
|
883
|
-
"div",
|
|
884
|
-
{
|
|
885
|
-
style: {
|
|
886
|
-
height: 1,
|
|
887
|
-
background: "rgba(255,255,255,0.08)",
|
|
888
|
-
margin: "4px 0"
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
),
|
|
892
|
-
presets.map((p) => /* @__PURE__ */ jsx2(
|
|
893
|
-
DropItem,
|
|
894
|
-
{
|
|
895
|
-
onClick: () => loadPreset(p),
|
|
896
|
-
children: p.label
|
|
897
|
-
},
|
|
898
|
-
p.label
|
|
899
|
-
)),
|
|
900
|
-
presets.length === 0 && /* @__PURE__ */ jsx2(
|
|
901
|
-
"div",
|
|
902
|
-
{
|
|
903
|
-
style: {
|
|
904
|
-
padding: "6px 12px",
|
|
905
|
-
color: "rgba(255,255,255,0.3)",
|
|
906
|
-
fontSize: 12
|
|
907
|
-
},
|
|
908
|
-
children: "No saved areas"
|
|
909
|
-
}
|
|
910
|
-
)
|
|
911
|
-
] })
|
|
912
|
-
] })
|
|
913
|
-
]
|
|
914
|
-
}
|
|
915
|
-
),
|
|
916
|
-
(onViewport || onFullPage || onComponent) && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
917
|
-
/* @__PURE__ */ jsx2(
|
|
918
|
-
"div",
|
|
919
|
-
{
|
|
920
|
-
style: {
|
|
921
|
-
height: 1,
|
|
922
|
-
background: "rgba(255, 255, 255, 0.08)",
|
|
923
|
-
margin: "1px 0"
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
),
|
|
927
|
-
/* @__PURE__ */ jsxs2(
|
|
928
|
-
"div",
|
|
1007
|
+
/* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1008
|
+
/* @__PURE__ */ jsxs3(
|
|
1009
|
+
DropButton,
|
|
929
1010
|
{
|
|
930
|
-
|
|
1011
|
+
onClick: () => {
|
|
1012
|
+
setAspectOpen(false);
|
|
1013
|
+
setSavedOpen((prev) => !prev);
|
|
1014
|
+
},
|
|
931
1015
|
children: [
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
] }),
|
|
936
|
-
onFullPage && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onFullPage, children: [
|
|
937
|
-
/* @__PURE__ */ jsx2(FullPageIcon, {}),
|
|
938
|
-
"Full Page"
|
|
939
|
-
] }),
|
|
940
|
-
onComponent && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onComponent, children: [
|
|
941
|
-
/* @__PURE__ */ jsx2(ComponentIcon, {}),
|
|
942
|
-
"Component"
|
|
943
|
-
] })
|
|
1016
|
+
/* @__PURE__ */ jsx4(Save, { size: 14, strokeWidth: 1.8 }),
|
|
1017
|
+
"Saved",
|
|
1018
|
+
/* @__PURE__ */ jsx4(ChevronDown, { size: 14, strokeWidth: 1.8 })
|
|
944
1019
|
]
|
|
945
1020
|
}
|
|
946
|
-
)
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
display: "flex",
|
|
953
|
-
alignItems: "center",
|
|
954
|
-
gap: 6
|
|
955
|
-
},
|
|
956
|
-
children: /* @__PURE__ */ jsx2(
|
|
957
|
-
MagnetToggle,
|
|
1021
|
+
),
|
|
1022
|
+
savedOpen && /* @__PURE__ */ jsxs3(DropMenu, { children: [
|
|
1023
|
+
/* @__PURE__ */ jsx4(DropItem, { accent: true, onClick: onAreaSavePreset, children: "Save current" }),
|
|
1024
|
+
areaPresets.length > 0 && /* @__PURE__ */ jsx4(MenuDivider, {}),
|
|
1025
|
+
areaPresets.map((preset) => /* @__PURE__ */ jsx4(
|
|
1026
|
+
DropItem,
|
|
958
1027
|
{
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1028
|
+
onClick: () => {
|
|
1029
|
+
onAreaLoadPreset(preset);
|
|
1030
|
+
setSavedOpen(false);
|
|
1031
|
+
},
|
|
1032
|
+
children: preset.label
|
|
1033
|
+
},
|
|
1034
|
+
preset.label
|
|
1035
|
+
)),
|
|
1036
|
+
areaPresets.length === 0 && /* @__PURE__ */ jsx4(
|
|
1037
|
+
"div",
|
|
1038
|
+
{
|
|
1039
|
+
style: {
|
|
1040
|
+
padding: "6px 12px",
|
|
1041
|
+
color: "rgba(255,255,255,0.3)",
|
|
1042
|
+
fontSize: 12
|
|
1043
|
+
},
|
|
1044
|
+
children: "No saved areas"
|
|
968
1045
|
}
|
|
969
1046
|
)
|
|
970
|
-
}
|
|
971
|
-
)
|
|
972
|
-
/* @__PURE__ */ jsx2(
|
|
973
|
-
"div",
|
|
974
|
-
{
|
|
975
|
-
style: {
|
|
976
|
-
fontSize: 10,
|
|
977
|
-
color: "rgba(255, 255, 255, 0.25)",
|
|
978
|
-
textAlign: "center"
|
|
979
|
-
},
|
|
980
|
-
children: "Click area or Enter to capture \xB7 Esc to cancel"
|
|
981
|
-
}
|
|
982
|
-
)
|
|
983
|
-
]
|
|
984
|
-
}
|
|
985
|
-
),
|
|
986
|
-
!placed && /* @__PURE__ */ jsxs2(
|
|
987
|
-
"div",
|
|
988
|
-
{
|
|
989
|
-
style: {
|
|
990
|
-
position: "absolute",
|
|
991
|
-
left: rect.x + rect.w / 2,
|
|
992
|
-
top: rect.y + rect.h + 8,
|
|
993
|
-
transform: "translateX(-50%)",
|
|
994
|
-
background: "rgba(24, 24, 27, 0.9)",
|
|
995
|
-
color: "rgba(255, 255, 255, 0.9)",
|
|
996
|
-
fontSize: 11,
|
|
997
|
-
fontFamily: "system-ui, -apple-system, monospace",
|
|
998
|
-
padding: "2px 8px",
|
|
999
|
-
borderRadius: 4,
|
|
1000
|
-
whiteSpace: "nowrap",
|
|
1001
|
-
pointerEvents: "none"
|
|
1002
|
-
},
|
|
1003
|
-
children: [
|
|
1004
|
-
Math.round(rect.w),
|
|
1005
|
-
" \xD7 ",
|
|
1006
|
-
Math.round(rect.h)
|
|
1047
|
+
] })
|
|
1048
|
+
] })
|
|
1007
1049
|
]
|
|
1008
1050
|
}
|
|
1009
1051
|
)
|
|
1010
|
-
] })
|
|
1011
|
-
!rect && /* @__PURE__ */ jsxs2(
|
|
1012
|
-
"div",
|
|
1013
|
-
{
|
|
1014
|
-
style: {
|
|
1015
|
-
position: "absolute",
|
|
1016
|
-
top: "50%",
|
|
1017
|
-
left: "50%",
|
|
1018
|
-
transform: "translate(-50%, -50%)",
|
|
1019
|
-
display: "flex",
|
|
1020
|
-
flexDirection: "column",
|
|
1021
|
-
alignItems: "center",
|
|
1022
|
-
gap: 16,
|
|
1023
|
-
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
1024
|
-
},
|
|
1025
|
-
children: [
|
|
1026
|
-
/* @__PURE__ */ jsx2(
|
|
1027
|
-
"div",
|
|
1028
|
-
{
|
|
1029
|
-
style: {
|
|
1030
|
-
color: "rgba(255, 255, 255, 0.7)",
|
|
1031
|
-
fontSize: 14,
|
|
1032
|
-
pointerEvents: "none",
|
|
1033
|
-
textShadow: "0 1px 4px rgba(0, 0, 0, 0.5)"
|
|
1034
|
-
},
|
|
1035
|
-
children: "Drag to select an area \xB7 Esc to cancel"
|
|
1036
|
-
}
|
|
1037
|
-
),
|
|
1038
|
-
(onViewport || onFullPage || onComponent) && /* @__PURE__ */ jsxs2(
|
|
1039
|
-
"div",
|
|
1040
|
-
{
|
|
1041
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
1042
|
-
style: {
|
|
1043
|
-
display: "flex",
|
|
1044
|
-
alignItems: "center",
|
|
1045
|
-
gap: 4,
|
|
1046
|
-
background: "rgba(32, 32, 36, 0.92)",
|
|
1047
|
-
backdropFilter: "blur(20px)",
|
|
1048
|
-
WebkitBackdropFilter: "blur(20px)",
|
|
1049
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1050
|
-
borderRadius: 8,
|
|
1051
|
-
padding: "6px 8px"
|
|
1052
|
-
},
|
|
1053
|
-
children: [
|
|
1054
|
-
onViewport && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onViewport, children: [
|
|
1055
|
-
/* @__PURE__ */ jsx2(ViewportIcon, {}),
|
|
1056
|
-
"Viewport"
|
|
1057
|
-
] }),
|
|
1058
|
-
onFullPage && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onFullPage, children: [
|
|
1059
|
-
/* @__PURE__ */ jsx2(FullPageIcon, {}),
|
|
1060
|
-
"Full Page"
|
|
1061
|
-
] }),
|
|
1062
|
-
onComponent && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onComponent, children: [
|
|
1063
|
-
/* @__PURE__ */ jsx2(ComponentIcon, {}),
|
|
1064
|
-
"Component"
|
|
1065
|
-
] })
|
|
1066
|
-
]
|
|
1067
|
-
}
|
|
1068
|
-
)
|
|
1069
|
-
]
|
|
1070
|
-
}
|
|
1071
|
-
)
|
|
1052
|
+
] })
|
|
1072
1053
|
]
|
|
1073
1054
|
}
|
|
1074
1055
|
);
|
|
1075
1056
|
}
|
|
1076
|
-
function
|
|
1057
|
+
function CloseButton({ onClick }) {
|
|
1058
|
+
const [hovered, setHovered] = useState5(false);
|
|
1059
|
+
return /* @__PURE__ */ jsx4(
|
|
1060
|
+
"button",
|
|
1061
|
+
{
|
|
1062
|
+
onClick,
|
|
1063
|
+
onMouseEnter: () => setHovered(true),
|
|
1064
|
+
onMouseLeave: () => setHovered(false),
|
|
1065
|
+
style: circleButtonStyle(hovered, true),
|
|
1066
|
+
children: /* @__PURE__ */ jsx4(X, { size: 18, strokeWidth: 1.9 })
|
|
1067
|
+
}
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
function ModeButton({
|
|
1071
|
+
children,
|
|
1077
1072
|
label,
|
|
1078
|
-
|
|
1073
|
+
selected,
|
|
1074
|
+
onClick
|
|
1079
1075
|
}) {
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1076
|
+
const [hovered, setHovered] = useState5(false);
|
|
1077
|
+
return /* @__PURE__ */ jsxs3("div", { style: { position: "relative" }, children: [
|
|
1078
|
+
hovered && /* @__PURE__ */ jsx4(
|
|
1079
|
+
"div",
|
|
1083
1080
|
{
|
|
1084
1081
|
style: {
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1082
|
+
position: "absolute",
|
|
1083
|
+
left: "50%",
|
|
1084
|
+
bottom: "calc(100% + 10px)",
|
|
1085
|
+
transform: "translateX(-50%)",
|
|
1086
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1087
|
+
backdropFilter: "blur(20px)",
|
|
1088
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
1089
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1090
|
+
borderRadius: 8,
|
|
1091
|
+
padding: "5px 10px",
|
|
1092
|
+
color: "rgba(255, 255, 255, 0.88)",
|
|
1093
|
+
fontSize: 12,
|
|
1094
|
+
whiteSpace: "nowrap",
|
|
1095
|
+
boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
|
|
1096
|
+
pointerEvents: "none"
|
|
1090
1097
|
},
|
|
1091
1098
|
children: label
|
|
1092
1099
|
}
|
|
1093
|
-
),
|
|
1094
|
-
|
|
1100
|
+
),
|
|
1101
|
+
/* @__PURE__ */ jsx4(
|
|
1102
|
+
"button",
|
|
1103
|
+
{
|
|
1104
|
+
onClick,
|
|
1105
|
+
onMouseEnter: () => setHovered(true),
|
|
1106
|
+
onMouseLeave: () => setHovered(false),
|
|
1107
|
+
style: {
|
|
1108
|
+
width: 42,
|
|
1109
|
+
height: 40,
|
|
1110
|
+
borderRadius: 12,
|
|
1111
|
+
border: "none",
|
|
1112
|
+
background: selected ? "rgba(255, 255, 255, 0.15)" : hovered ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
1113
|
+
display: "flex",
|
|
1114
|
+
alignItems: "center",
|
|
1115
|
+
justifyContent: "center",
|
|
1116
|
+
cursor: "pointer",
|
|
1117
|
+
padding: 0,
|
|
1118
|
+
color: selected ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
1119
|
+
transition: "background 0.12s ease, color 0.12s ease"
|
|
1120
|
+
},
|
|
1121
|
+
children
|
|
1122
|
+
}
|
|
1123
|
+
)
|
|
1124
|
+
] });
|
|
1125
|
+
}
|
|
1126
|
+
function SettingsButton({
|
|
1127
|
+
open,
|
|
1128
|
+
onClick,
|
|
1129
|
+
magnetEnabled,
|
|
1130
|
+
onMagnetChange
|
|
1131
|
+
}) {
|
|
1132
|
+
const [hovered, setHovered] = useState5(false);
|
|
1133
|
+
return /* @__PURE__ */ jsxs3("div", { style: { position: "relative", marginRight: 6 }, children: [
|
|
1134
|
+
/* @__PURE__ */ jsx4(
|
|
1135
|
+
"button",
|
|
1136
|
+
{
|
|
1137
|
+
onClick,
|
|
1138
|
+
onMouseEnter: () => setHovered(true),
|
|
1139
|
+
onMouseLeave: () => setHovered(false),
|
|
1140
|
+
style: {
|
|
1141
|
+
...circleButtonStyle(open || hovered, false),
|
|
1142
|
+
color: "rgba(255, 255, 255, 0.58)"
|
|
1143
|
+
},
|
|
1144
|
+
children: /* @__PURE__ */ jsx4(Settings2, { size: 18, strokeWidth: 1.7 })
|
|
1145
|
+
}
|
|
1146
|
+
),
|
|
1147
|
+
open && /* @__PURE__ */ jsxs3(
|
|
1148
|
+
"div",
|
|
1149
|
+
{
|
|
1150
|
+
style: {
|
|
1151
|
+
position: "absolute",
|
|
1152
|
+
left: "50%",
|
|
1153
|
+
bottom: "calc(100% + 12px)",
|
|
1154
|
+
transform: "translateX(-50%)",
|
|
1155
|
+
minWidth: 184,
|
|
1156
|
+
padding: "10px 12px",
|
|
1157
|
+
borderRadius: 12,
|
|
1158
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1159
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1160
|
+
boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
|
|
1161
|
+
backdropFilter: "blur(20px)",
|
|
1162
|
+
WebkitBackdropFilter: "blur(20px)"
|
|
1163
|
+
},
|
|
1164
|
+
children: [
|
|
1165
|
+
/* @__PURE__ */ jsx4(
|
|
1166
|
+
"div",
|
|
1167
|
+
{
|
|
1168
|
+
style: {
|
|
1169
|
+
fontSize: 11,
|
|
1170
|
+
color: "rgba(255, 255, 255, 0.46)",
|
|
1171
|
+
letterSpacing: "0.03em",
|
|
1172
|
+
textTransform: "uppercase",
|
|
1173
|
+
marginBottom: 10
|
|
1174
|
+
},
|
|
1175
|
+
children: "Area Settings"
|
|
1176
|
+
}
|
|
1177
|
+
),
|
|
1178
|
+
/* @__PURE__ */ jsxs3(
|
|
1179
|
+
"label",
|
|
1180
|
+
{
|
|
1181
|
+
style: {
|
|
1182
|
+
display: "flex",
|
|
1183
|
+
alignItems: "center",
|
|
1184
|
+
justifyContent: "space-between",
|
|
1185
|
+
gap: 12,
|
|
1186
|
+
cursor: "pointer"
|
|
1187
|
+
},
|
|
1188
|
+
children: [
|
|
1189
|
+
/* @__PURE__ */ jsxs3(
|
|
1190
|
+
"span",
|
|
1191
|
+
{
|
|
1192
|
+
style: {
|
|
1193
|
+
display: "flex",
|
|
1194
|
+
alignItems: "center",
|
|
1195
|
+
gap: 8,
|
|
1196
|
+
color: "rgba(255, 255, 255, 0.88)",
|
|
1197
|
+
fontSize: 13
|
|
1198
|
+
},
|
|
1199
|
+
children: [
|
|
1200
|
+
/* @__PURE__ */ jsx4(Magnet, { size: 15, strokeWidth: 1.8 }),
|
|
1201
|
+
"Magnet snap"
|
|
1202
|
+
]
|
|
1203
|
+
}
|
|
1204
|
+
),
|
|
1205
|
+
/* @__PURE__ */ jsx4(
|
|
1206
|
+
"button",
|
|
1207
|
+
{
|
|
1208
|
+
type: "button",
|
|
1209
|
+
onClick: () => onMagnetChange(!magnetEnabled),
|
|
1210
|
+
style: {
|
|
1211
|
+
width: 38,
|
|
1212
|
+
height: 22,
|
|
1213
|
+
borderRadius: 999,
|
|
1214
|
+
border: "none",
|
|
1215
|
+
background: magnetEnabled ? "#38bdf8" : "rgba(255, 255, 255, 0.18)",
|
|
1216
|
+
position: "relative",
|
|
1217
|
+
cursor: "pointer",
|
|
1218
|
+
padding: 0,
|
|
1219
|
+
transition: "background 0.12s ease"
|
|
1220
|
+
},
|
|
1221
|
+
children: /* @__PURE__ */ jsx4(
|
|
1222
|
+
"span",
|
|
1223
|
+
{
|
|
1224
|
+
style: {
|
|
1225
|
+
position: "absolute",
|
|
1226
|
+
top: 2,
|
|
1227
|
+
left: magnetEnabled ? 18 : 2,
|
|
1228
|
+
width: 18,
|
|
1229
|
+
height: 18,
|
|
1230
|
+
borderRadius: "50%",
|
|
1231
|
+
background: "#fff",
|
|
1232
|
+
transition: "left 0.12s ease"
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
)
|
|
1236
|
+
}
|
|
1237
|
+
)
|
|
1238
|
+
]
|
|
1239
|
+
}
|
|
1240
|
+
)
|
|
1241
|
+
]
|
|
1242
|
+
}
|
|
1243
|
+
)
|
|
1095
1244
|
] });
|
|
1096
1245
|
}
|
|
1097
|
-
function
|
|
1098
|
-
|
|
1099
|
-
|
|
1246
|
+
function CaptureButton({
|
|
1247
|
+
label,
|
|
1248
|
+
onClick
|
|
1249
|
+
}) {
|
|
1250
|
+
const [hovered, setHovered] = useState5(false);
|
|
1251
|
+
return /* @__PURE__ */ jsxs3(
|
|
1252
|
+
"button",
|
|
1100
1253
|
{
|
|
1254
|
+
onClick,
|
|
1255
|
+
onMouseEnter: () => setHovered(true),
|
|
1256
|
+
onMouseLeave: () => setHovered(false),
|
|
1101
1257
|
style: {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1258
|
+
padding: "0 18px",
|
|
1259
|
+
height: 40,
|
|
1260
|
+
borderRadius: 12,
|
|
1261
|
+
border: "none",
|
|
1262
|
+
background: hovered ? "#2f7bf8" : "#3b82f6",
|
|
1263
|
+
color: "white",
|
|
1264
|
+
fontSize: 13,
|
|
1265
|
+
fontWeight: 600,
|
|
1266
|
+
fontFamily: "inherit",
|
|
1267
|
+
cursor: "pointer",
|
|
1268
|
+
whiteSpace: "nowrap",
|
|
1269
|
+
transition: "background 0.12s ease",
|
|
1106
1270
|
flexShrink: 0,
|
|
1107
|
-
|
|
1271
|
+
display: "flex",
|
|
1272
|
+
alignItems: "center",
|
|
1273
|
+
gap: 8
|
|
1108
1274
|
},
|
|
1109
|
-
children:
|
|
1275
|
+
children: [
|
|
1276
|
+
/* @__PURE__ */ jsx4(Camera2, { size: 16, strokeWidth: 1.9 }),
|
|
1277
|
+
label
|
|
1278
|
+
]
|
|
1110
1279
|
}
|
|
1111
1280
|
);
|
|
1112
1281
|
}
|
|
1113
|
-
function
|
|
1114
|
-
|
|
1115
|
-
|
|
1282
|
+
function ControlGroup({
|
|
1283
|
+
label,
|
|
1284
|
+
children
|
|
1285
|
+
}) {
|
|
1286
|
+
return /* @__PURE__ */ jsxs3(
|
|
1287
|
+
"div",
|
|
1116
1288
|
{
|
|
1117
1289
|
style: {
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1290
|
+
display: "flex",
|
|
1291
|
+
alignItems: "center",
|
|
1292
|
+
gap: 6,
|
|
1293
|
+
padding: "0 4px"
|
|
1121
1294
|
},
|
|
1122
|
-
children
|
|
1295
|
+
children: [
|
|
1296
|
+
/* @__PURE__ */ jsx4(
|
|
1297
|
+
"span",
|
|
1298
|
+
{
|
|
1299
|
+
style: {
|
|
1300
|
+
fontSize: 11,
|
|
1301
|
+
color: "rgba(255, 255, 255, 0.42)",
|
|
1302
|
+
textTransform: "uppercase",
|
|
1303
|
+
letterSpacing: "0.03em"
|
|
1304
|
+
},
|
|
1305
|
+
children: label
|
|
1306
|
+
}
|
|
1307
|
+
),
|
|
1308
|
+
children
|
|
1309
|
+
]
|
|
1123
1310
|
}
|
|
1124
1311
|
);
|
|
1125
1312
|
}
|
|
@@ -1127,12 +1314,14 @@ function NumInput({
|
|
|
1127
1314
|
value,
|
|
1128
1315
|
onChange
|
|
1129
1316
|
}) {
|
|
1130
|
-
const [editing, setEditing] =
|
|
1131
|
-
const [text, setText] =
|
|
1132
|
-
|
|
1133
|
-
if (!editing)
|
|
1134
|
-
|
|
1135
|
-
|
|
1317
|
+
const [editing, setEditing] = useState5(false);
|
|
1318
|
+
const [text, setText] = useState5(String(value));
|
|
1319
|
+
useEffect4(() => {
|
|
1320
|
+
if (!editing) {
|
|
1321
|
+
setText(String(value));
|
|
1322
|
+
}
|
|
1323
|
+
}, [editing, value]);
|
|
1324
|
+
return /* @__PURE__ */ jsx4(
|
|
1136
1325
|
"input",
|
|
1137
1326
|
{
|
|
1138
1327
|
type: "text",
|
|
@@ -1147,14 +1336,16 @@ function NumInput({
|
|
|
1147
1336
|
},
|
|
1148
1337
|
onChange: (e) => setText(e.target.value),
|
|
1149
1338
|
onKeyDown: (e) => {
|
|
1150
|
-
if (e.key === "Enter")
|
|
1339
|
+
if (e.key === "Enter") {
|
|
1340
|
+
e.target.blur();
|
|
1341
|
+
}
|
|
1151
1342
|
},
|
|
1152
1343
|
style: {
|
|
1153
|
-
width:
|
|
1154
|
-
padding: "
|
|
1344
|
+
width: 54,
|
|
1345
|
+
padding: "4px 6px",
|
|
1155
1346
|
background: "rgba(255, 255, 255, 0.07)",
|
|
1156
1347
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1157
|
-
borderRadius:
|
|
1348
|
+
borderRadius: 7,
|
|
1158
1349
|
color: "rgba(255, 255, 255, 0.9)",
|
|
1159
1350
|
fontSize: 12,
|
|
1160
1351
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
@@ -1164,46 +1355,62 @@ function NumInput({
|
|
|
1164
1355
|
}
|
|
1165
1356
|
);
|
|
1166
1357
|
}
|
|
1167
|
-
function
|
|
1358
|
+
function StaticText({ children }) {
|
|
1359
|
+
return /* @__PURE__ */ jsx4(
|
|
1360
|
+
"span",
|
|
1361
|
+
{
|
|
1362
|
+
style: {
|
|
1363
|
+
fontSize: 11,
|
|
1364
|
+
color: "rgba(255,255,255,0.35)",
|
|
1365
|
+
minWidth: 8,
|
|
1366
|
+
textAlign: "center"
|
|
1367
|
+
},
|
|
1368
|
+
children
|
|
1369
|
+
}
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
function DropButton({
|
|
1168
1373
|
children,
|
|
1169
1374
|
onClick,
|
|
1170
1375
|
active
|
|
1171
1376
|
}) {
|
|
1172
|
-
return /* @__PURE__ */
|
|
1377
|
+
return /* @__PURE__ */ jsx4(
|
|
1173
1378
|
"button",
|
|
1174
1379
|
{
|
|
1175
1380
|
onClick,
|
|
1176
1381
|
style: {
|
|
1177
1382
|
display: "flex",
|
|
1178
1383
|
alignItems: "center",
|
|
1179
|
-
gap:
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1384
|
+
gap: 6,
|
|
1385
|
+
height: 34,
|
|
1386
|
+
padding: "0 10px",
|
|
1387
|
+
borderRadius: 10,
|
|
1388
|
+
border: "1px solid rgba(255,255,255,0.08)",
|
|
1389
|
+
background: "rgba(255,255,255,0.04)",
|
|
1390
|
+
color: active ? "rgba(125, 211, 252, 0.96)" : "rgba(255,255,255,0.78)",
|
|
1183
1391
|
cursor: "pointer",
|
|
1184
|
-
fontSize:
|
|
1185
|
-
fontFamily: "inherit"
|
|
1186
|
-
padding: "2px 0"
|
|
1392
|
+
fontSize: 12,
|
|
1393
|
+
fontFamily: "inherit"
|
|
1187
1394
|
},
|
|
1188
1395
|
children
|
|
1189
1396
|
}
|
|
1190
1397
|
);
|
|
1191
1398
|
}
|
|
1192
1399
|
function DropMenu({ children }) {
|
|
1193
|
-
return /* @__PURE__ */
|
|
1400
|
+
return /* @__PURE__ */ jsx4(
|
|
1194
1401
|
"div",
|
|
1195
1402
|
{
|
|
1196
1403
|
style: {
|
|
1197
1404
|
position: "absolute",
|
|
1198
|
-
bottom: "100%",
|
|
1199
|
-
left:
|
|
1200
|
-
|
|
1201
|
-
|
|
1405
|
+
bottom: "calc(100% + 8px)",
|
|
1406
|
+
left: "50%",
|
|
1407
|
+
transform: "translateX(-50%)",
|
|
1408
|
+
minWidth: 120,
|
|
1409
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1202
1410
|
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1203
|
-
borderRadius:
|
|
1411
|
+
borderRadius: 10,
|
|
1204
1412
|
padding: "4px 0",
|
|
1205
|
-
|
|
1206
|
-
boxShadow: "0 4px 16px rgba(0, 0, 0, 0.3)",
|
|
1413
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
|
|
1207
1414
|
backdropFilter: "blur(20px)",
|
|
1208
1415
|
WebkitBackdropFilter: "blur(20px)"
|
|
1209
1416
|
},
|
|
@@ -1217,17 +1424,17 @@ function DropItem({
|
|
|
1217
1424
|
active,
|
|
1218
1425
|
accent
|
|
1219
1426
|
}) {
|
|
1220
|
-
return /* @__PURE__ */
|
|
1427
|
+
return /* @__PURE__ */ jsx4(
|
|
1221
1428
|
"button",
|
|
1222
1429
|
{
|
|
1223
1430
|
onClick,
|
|
1224
1431
|
style: {
|
|
1225
1432
|
display: "block",
|
|
1226
1433
|
width: "100%",
|
|
1227
|
-
padding: "
|
|
1228
|
-
background: active ? "rgba(255, 255, 255, 0.08)" : "
|
|
1434
|
+
padding: "7px 12px",
|
|
1435
|
+
background: active ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
1229
1436
|
border: "none",
|
|
1230
|
-
color: accent ? "rgba(
|
|
1437
|
+
color: accent ? "rgba(125, 211, 252, 0.96)" : "rgba(255, 255, 255, 0.86)",
|
|
1231
1438
|
textAlign: "left",
|
|
1232
1439
|
cursor: "pointer",
|
|
1233
1440
|
fontSize: 13,
|
|
@@ -1237,266 +1444,56 @@ function DropItem({
|
|
|
1237
1444
|
}
|
|
1238
1445
|
);
|
|
1239
1446
|
}
|
|
1240
|
-
function
|
|
1241
|
-
return /* @__PURE__ */
|
|
1242
|
-
"
|
|
1243
|
-
{
|
|
1244
|
-
d: "M3 4l2 2.5L7 4",
|
|
1245
|
-
stroke: "currentColor",
|
|
1246
|
-
strokeWidth: "1.2"
|
|
1247
|
-
}
|
|
1248
|
-
) });
|
|
1249
|
-
}
|
|
1250
|
-
function AspectIcon() {
|
|
1251
|
-
return /* @__PURE__ */ jsxs2("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1252
|
-
/* @__PURE__ */ jsx2(
|
|
1253
|
-
"rect",
|
|
1254
|
-
{
|
|
1255
|
-
x: "2",
|
|
1256
|
-
y: "4",
|
|
1257
|
-
width: "12",
|
|
1258
|
-
height: "8",
|
|
1259
|
-
rx: "1.5",
|
|
1260
|
-
stroke: "currentColor",
|
|
1261
|
-
strokeWidth: "1.2",
|
|
1262
|
-
strokeDasharray: "2 1.5"
|
|
1263
|
-
}
|
|
1264
|
-
),
|
|
1265
|
-
/* @__PURE__ */ jsx2(
|
|
1266
|
-
"line",
|
|
1267
|
-
{
|
|
1268
|
-
x1: "6.33",
|
|
1269
|
-
y1: "4",
|
|
1270
|
-
x2: "6.33",
|
|
1271
|
-
y2: "12",
|
|
1272
|
-
stroke: "currentColor",
|
|
1273
|
-
strokeWidth: "0.8",
|
|
1274
|
-
strokeDasharray: "1.5 1"
|
|
1275
|
-
}
|
|
1276
|
-
),
|
|
1277
|
-
/* @__PURE__ */ jsx2(
|
|
1278
|
-
"line",
|
|
1279
|
-
{
|
|
1280
|
-
x1: "9.67",
|
|
1281
|
-
y1: "4",
|
|
1282
|
-
x2: "9.67",
|
|
1283
|
-
y2: "12",
|
|
1284
|
-
stroke: "currentColor",
|
|
1285
|
-
strokeWidth: "0.8",
|
|
1286
|
-
strokeDasharray: "1.5 1"
|
|
1287
|
-
}
|
|
1288
|
-
)
|
|
1289
|
-
] });
|
|
1290
|
-
}
|
|
1291
|
-
function SavedIcon() {
|
|
1292
|
-
return /* @__PURE__ */ jsx2("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx2(
|
|
1293
|
-
"rect",
|
|
1294
|
-
{
|
|
1295
|
-
x: "2",
|
|
1296
|
-
y: "3",
|
|
1297
|
-
width: "12",
|
|
1298
|
-
height: "10",
|
|
1299
|
-
rx: "1.5",
|
|
1300
|
-
stroke: "currentColor",
|
|
1301
|
-
strokeWidth: "1.2",
|
|
1302
|
-
strokeDasharray: "2 1.5"
|
|
1303
|
-
}
|
|
1304
|
-
) });
|
|
1305
|
-
}
|
|
1306
|
-
function ModeBtn({
|
|
1307
|
-
children,
|
|
1308
|
-
onClick
|
|
1309
|
-
}) {
|
|
1310
|
-
return /* @__PURE__ */ jsx2(
|
|
1311
|
-
"button",
|
|
1447
|
+
function MenuDivider() {
|
|
1448
|
+
return /* @__PURE__ */ jsx4(
|
|
1449
|
+
"div",
|
|
1312
1450
|
{
|
|
1313
|
-
onClick,
|
|
1314
1451
|
style: {
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
border: "1px solid rgba(255, 255, 255, 0.08)",
|
|
1320
|
-
borderRadius: 6,
|
|
1321
|
-
color: "rgba(255, 255, 255, 0.55)",
|
|
1322
|
-
cursor: "pointer",
|
|
1323
|
-
fontSize: 11,
|
|
1324
|
-
fontFamily: "inherit",
|
|
1325
|
-
padding: "4px 8px",
|
|
1326
|
-
transition: "background 0.1s, color 0.1s"
|
|
1327
|
-
},
|
|
1328
|
-
onMouseEnter: (e) => {
|
|
1329
|
-
const btn = e.currentTarget;
|
|
1330
|
-
btn.style.background = "rgba(255, 255, 255, 0.12)";
|
|
1331
|
-
btn.style.color = "rgba(255, 255, 255, 0.85)";
|
|
1332
|
-
},
|
|
1333
|
-
onMouseLeave: (e) => {
|
|
1334
|
-
const btn = e.currentTarget;
|
|
1335
|
-
btn.style.background = "rgba(255, 255, 255, 0.06)";
|
|
1336
|
-
btn.style.color = "rgba(255, 255, 255, 0.55)";
|
|
1337
|
-
},
|
|
1338
|
-
children
|
|
1452
|
+
height: 1,
|
|
1453
|
+
background: "rgba(255,255,255,0.08)",
|
|
1454
|
+
margin: "4px 0"
|
|
1455
|
+
}
|
|
1339
1456
|
}
|
|
1340
1457
|
);
|
|
1341
1458
|
}
|
|
1342
|
-
function
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
}) {
|
|
1346
|
-
return /* @__PURE__ */ jsxs2(
|
|
1347
|
-
"button",
|
|
1459
|
+
function Separator({ vertical = true }) {
|
|
1460
|
+
return /* @__PURE__ */ jsx4(
|
|
1461
|
+
"div",
|
|
1348
1462
|
{
|
|
1349
|
-
onClick: onToggle,
|
|
1350
1463
|
style: {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
color: enabled ? "rgba(147, 130, 220, 0.9)" : "rgba(255, 255, 255, 0.35)",
|
|
1357
|
-
cursor: "pointer",
|
|
1358
|
-
fontSize: 11,
|
|
1359
|
-
fontFamily: "inherit",
|
|
1360
|
-
padding: "2px 0"
|
|
1361
|
-
},
|
|
1362
|
-
children: [
|
|
1363
|
-
/* @__PURE__ */ jsx2(MagnetIcon, {}),
|
|
1364
|
-
"Magnet"
|
|
1365
|
-
]
|
|
1464
|
+
width: vertical ? 1 : 24,
|
|
1465
|
+
height: vertical ? 24 : 1,
|
|
1466
|
+
background: "rgba(255,255,255,0.12)",
|
|
1467
|
+
flexShrink: 0
|
|
1468
|
+
}
|
|
1366
1469
|
}
|
|
1367
1470
|
);
|
|
1368
1471
|
}
|
|
1369
|
-
function
|
|
1370
|
-
return
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
}
|
|
1384
|
-
function ViewportIcon() {
|
|
1385
|
-
return /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1386
|
-
/* @__PURE__ */ jsx2(
|
|
1387
|
-
"rect",
|
|
1388
|
-
{
|
|
1389
|
-
x: "1",
|
|
1390
|
-
y: "2",
|
|
1391
|
-
width: "14",
|
|
1392
|
-
height: "11",
|
|
1393
|
-
rx: "1.5",
|
|
1394
|
-
stroke: "currentColor",
|
|
1395
|
-
strokeWidth: "1.3"
|
|
1396
|
-
}
|
|
1397
|
-
),
|
|
1398
|
-
/* @__PURE__ */ jsx2(
|
|
1399
|
-
"line",
|
|
1400
|
-
{
|
|
1401
|
-
x1: "1",
|
|
1402
|
-
y1: "14",
|
|
1403
|
-
x2: "15",
|
|
1404
|
-
y2: "14",
|
|
1405
|
-
stroke: "currentColor",
|
|
1406
|
-
strokeWidth: "1.3",
|
|
1407
|
-
strokeLinecap: "round"
|
|
1408
|
-
}
|
|
1409
|
-
)
|
|
1410
|
-
] });
|
|
1411
|
-
}
|
|
1412
|
-
function FullPageIcon() {
|
|
1413
|
-
return /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1414
|
-
/* @__PURE__ */ jsx2(
|
|
1415
|
-
"rect",
|
|
1416
|
-
{
|
|
1417
|
-
x: "3",
|
|
1418
|
-
y: "1",
|
|
1419
|
-
width: "10",
|
|
1420
|
-
height: "14",
|
|
1421
|
-
rx: "1.5",
|
|
1422
|
-
stroke: "currentColor",
|
|
1423
|
-
strokeWidth: "1.3"
|
|
1424
|
-
}
|
|
1425
|
-
),
|
|
1426
|
-
/* @__PURE__ */ jsx2(
|
|
1427
|
-
"line",
|
|
1428
|
-
{
|
|
1429
|
-
x1: "5.5",
|
|
1430
|
-
y1: "4",
|
|
1431
|
-
x2: "10.5",
|
|
1432
|
-
y2: "4",
|
|
1433
|
-
stroke: "currentColor",
|
|
1434
|
-
strokeWidth: "1",
|
|
1435
|
-
strokeLinecap: "round"
|
|
1436
|
-
}
|
|
1437
|
-
),
|
|
1438
|
-
/* @__PURE__ */ jsx2(
|
|
1439
|
-
"line",
|
|
1440
|
-
{
|
|
1441
|
-
x1: "5.5",
|
|
1442
|
-
y1: "6.5",
|
|
1443
|
-
x2: "10.5",
|
|
1444
|
-
y2: "6.5",
|
|
1445
|
-
stroke: "currentColor",
|
|
1446
|
-
strokeWidth: "1",
|
|
1447
|
-
strokeLinecap: "round"
|
|
1448
|
-
}
|
|
1449
|
-
),
|
|
1450
|
-
/* @__PURE__ */ jsx2(
|
|
1451
|
-
"line",
|
|
1452
|
-
{
|
|
1453
|
-
x1: "5.5",
|
|
1454
|
-
y1: "9",
|
|
1455
|
-
x2: "10.5",
|
|
1456
|
-
y2: "9",
|
|
1457
|
-
stroke: "currentColor",
|
|
1458
|
-
strokeWidth: "1",
|
|
1459
|
-
strokeLinecap: "round"
|
|
1460
|
-
}
|
|
1461
|
-
)
|
|
1462
|
-
] });
|
|
1463
|
-
}
|
|
1464
|
-
function ComponentIcon() {
|
|
1465
|
-
return /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1466
|
-
/* @__PURE__ */ jsx2(
|
|
1467
|
-
"path",
|
|
1468
|
-
{
|
|
1469
|
-
d: "M3 2l2.5 10 2-3.5L11 11 3 2z",
|
|
1470
|
-
stroke: "currentColor",
|
|
1471
|
-
strokeWidth: "1.2",
|
|
1472
|
-
strokeLinejoin: "round",
|
|
1473
|
-
strokeLinecap: "round"
|
|
1474
|
-
}
|
|
1475
|
-
),
|
|
1476
|
-
/* @__PURE__ */ jsx2(
|
|
1477
|
-
"rect",
|
|
1478
|
-
{
|
|
1479
|
-
x: "8",
|
|
1480
|
-
y: "5",
|
|
1481
|
-
width: "6.5",
|
|
1482
|
-
height: "6.5",
|
|
1483
|
-
rx: "1",
|
|
1484
|
-
stroke: "currentColor",
|
|
1485
|
-
strokeWidth: "1.1",
|
|
1486
|
-
strokeDasharray: "2 1.5"
|
|
1487
|
-
}
|
|
1488
|
-
)
|
|
1489
|
-
] });
|
|
1472
|
+
function circleButtonStyle(active, round) {
|
|
1473
|
+
return {
|
|
1474
|
+
width: 40,
|
|
1475
|
+
height: 40,
|
|
1476
|
+
borderRadius: round ? "50%" : 12,
|
|
1477
|
+
border: "none",
|
|
1478
|
+
background: active ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
1479
|
+
display: "flex",
|
|
1480
|
+
alignItems: "center",
|
|
1481
|
+
justifyContent: "center",
|
|
1482
|
+
cursor: "pointer",
|
|
1483
|
+
padding: 0,
|
|
1484
|
+
transition: "background 0.12s ease, color 0.12s ease",
|
|
1485
|
+
marginRight: round ? 6 : 0
|
|
1486
|
+
};
|
|
1490
1487
|
}
|
|
1491
1488
|
|
|
1492
1489
|
// src/overlay/ui/inspector.tsx
|
|
1493
|
-
import { useEffect as
|
|
1494
|
-
import { Fragment as
|
|
1490
|
+
import { useEffect as useEffect5, useRef as useRef3, useCallback as useCallback4, useState as useState6 } from "react";
|
|
1491
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1495
1492
|
function Inspector({ onSelect, onCancel }) {
|
|
1496
|
-
const [highlight, setHighlight] =
|
|
1493
|
+
const [highlight, setHighlight] = useState6(null);
|
|
1497
1494
|
const hoveredEl = useRef3(null);
|
|
1498
1495
|
const styleEl = useRef3(null);
|
|
1499
|
-
|
|
1496
|
+
useEffect5(() => {
|
|
1500
1497
|
const style = document.createElement("style");
|
|
1501
1498
|
style.setAttribute("data-afterbefore", "true");
|
|
1502
1499
|
style.textContent = "*, *::before, *::after { cursor: crosshair !important; }";
|
|
@@ -1553,7 +1550,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1553
1550
|
},
|
|
1554
1551
|
[onCancel]
|
|
1555
1552
|
);
|
|
1556
|
-
|
|
1553
|
+
useEffect5(() => {
|
|
1557
1554
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
1558
1555
|
document.addEventListener("click", handleClick, true);
|
|
1559
1556
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -1563,9 +1560,9 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1563
1560
|
document.removeEventListener("keydown", handleKeyDown);
|
|
1564
1561
|
};
|
|
1565
1562
|
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
1566
|
-
return /* @__PURE__ */
|
|
1567
|
-
highlight && /* @__PURE__ */
|
|
1568
|
-
/* @__PURE__ */
|
|
1563
|
+
return /* @__PURE__ */ jsxs4("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: [
|
|
1564
|
+
highlight && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1565
|
+
/* @__PURE__ */ jsx5(
|
|
1569
1566
|
"div",
|
|
1570
1567
|
{
|
|
1571
1568
|
style: {
|
|
@@ -1581,7 +1578,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1581
1578
|
}
|
|
1582
1579
|
}
|
|
1583
1580
|
),
|
|
1584
|
-
/* @__PURE__ */
|
|
1581
|
+
/* @__PURE__ */ jsx5(
|
|
1585
1582
|
"div",
|
|
1586
1583
|
{
|
|
1587
1584
|
style: {
|
|
@@ -1602,7 +1599,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1602
1599
|
}
|
|
1603
1600
|
)
|
|
1604
1601
|
] }),
|
|
1605
|
-
!highlight && /* @__PURE__ */
|
|
1602
|
+
!highlight && /* @__PURE__ */ jsx5(
|
|
1606
1603
|
"div",
|
|
1607
1604
|
{
|
|
1608
1605
|
style: {
|
|
@@ -1626,18 +1623,18 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1626
1623
|
}
|
|
1627
1624
|
|
|
1628
1625
|
// src/overlay/ui/status.tsx
|
|
1629
|
-
import { useState as
|
|
1630
|
-
import { jsx as
|
|
1626
|
+
import { useState as useState7, useRef as useRef4, useEffect as useEffect6, useCallback as useCallback5 } from "react";
|
|
1627
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1631
1628
|
var PANEL_WIDTH = 220;
|
|
1632
1629
|
function Status({ onReset, position, onClose }) {
|
|
1633
1630
|
const panelRef = useRef4(null);
|
|
1634
|
-
const [toast, setToast] =
|
|
1635
|
-
const [pushing, setPushing] =
|
|
1631
|
+
const [toast, setToast] = useState7(null);
|
|
1632
|
+
const [pushing, setPushing] = useState7(false);
|
|
1636
1633
|
const showToast = useCallback5((message, type) => {
|
|
1637
1634
|
setToast({ message, type });
|
|
1638
1635
|
setTimeout(() => setToast(null), 3e3);
|
|
1639
1636
|
}, []);
|
|
1640
|
-
|
|
1637
|
+
useEffect6(() => {
|
|
1641
1638
|
const handler = (e) => {
|
|
1642
1639
|
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
1643
1640
|
onClose();
|
|
@@ -1646,7 +1643,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1646
1643
|
document.addEventListener("mousedown", handler);
|
|
1647
1644
|
return () => document.removeEventListener("mousedown", handler);
|
|
1648
1645
|
}, [onClose]);
|
|
1649
|
-
|
|
1646
|
+
useEffect6(() => {
|
|
1650
1647
|
const handler = (e) => {
|
|
1651
1648
|
if (e.key === "Escape") onClose();
|
|
1652
1649
|
};
|
|
@@ -1722,7 +1719,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1722
1719
|
const onLeave = (e) => {
|
|
1723
1720
|
e.currentTarget.style.background = "transparent";
|
|
1724
1721
|
};
|
|
1725
|
-
return /* @__PURE__ */
|
|
1722
|
+
return /* @__PURE__ */ jsxs5(
|
|
1726
1723
|
"div",
|
|
1727
1724
|
{
|
|
1728
1725
|
ref: panelRef,
|
|
@@ -1741,7 +1738,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1741
1738
|
overflow: "hidden"
|
|
1742
1739
|
},
|
|
1743
1740
|
children: [
|
|
1744
|
-
/* @__PURE__ */
|
|
1741
|
+
/* @__PURE__ */ jsx6(
|
|
1745
1742
|
"div",
|
|
1746
1743
|
{
|
|
1747
1744
|
style: {
|
|
@@ -1754,8 +1751,8 @@ function Status({ onReset, position, onClose }) {
|
|
|
1754
1751
|
children: "Before & After captured"
|
|
1755
1752
|
}
|
|
1756
1753
|
),
|
|
1757
|
-
/* @__PURE__ */
|
|
1758
|
-
/* @__PURE__ */
|
|
1754
|
+
/* @__PURE__ */ jsxs5("div", { style: { padding: "0 4px 4px" }, children: [
|
|
1755
|
+
/* @__PURE__ */ jsxs5(
|
|
1759
1756
|
"button",
|
|
1760
1757
|
{
|
|
1761
1758
|
style: buttonStyle,
|
|
@@ -1763,12 +1760,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1763
1760
|
onMouseEnter: onEnter,
|
|
1764
1761
|
onMouseLeave: onLeave,
|
|
1765
1762
|
children: [
|
|
1766
|
-
/* @__PURE__ */
|
|
1763
|
+
/* @__PURE__ */ jsx6(FolderIcon, {}),
|
|
1767
1764
|
"Open Folder"
|
|
1768
1765
|
]
|
|
1769
1766
|
}
|
|
1770
1767
|
),
|
|
1771
|
-
/* @__PURE__ */
|
|
1768
|
+
/* @__PURE__ */ jsxs5(
|
|
1772
1769
|
"button",
|
|
1773
1770
|
{
|
|
1774
1771
|
style: buttonStyle,
|
|
@@ -1776,12 +1773,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1776
1773
|
onMouseEnter: onEnter,
|
|
1777
1774
|
onMouseLeave: onLeave,
|
|
1778
1775
|
children: [
|
|
1779
|
-
/* @__PURE__ */
|
|
1776
|
+
/* @__PURE__ */ jsx6(CopyIcon, {}),
|
|
1780
1777
|
"Copy Markdown"
|
|
1781
1778
|
]
|
|
1782
1779
|
}
|
|
1783
1780
|
),
|
|
1784
|
-
/* @__PURE__ */
|
|
1781
|
+
/* @__PURE__ */ jsxs5(
|
|
1785
1782
|
"button",
|
|
1786
1783
|
{
|
|
1787
1784
|
style: buttonStyle,
|
|
@@ -1790,12 +1787,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1790
1787
|
onMouseEnter: onEnter,
|
|
1791
1788
|
onMouseLeave: onLeave,
|
|
1792
1789
|
children: [
|
|
1793
|
-
/* @__PURE__ */
|
|
1790
|
+
/* @__PURE__ */ jsx6(PushIcon, {}),
|
|
1794
1791
|
pushing ? "Pushing..." : "Push to PR"
|
|
1795
1792
|
]
|
|
1796
1793
|
}
|
|
1797
1794
|
),
|
|
1798
|
-
/* @__PURE__ */
|
|
1795
|
+
/* @__PURE__ */ jsx6(
|
|
1799
1796
|
"div",
|
|
1800
1797
|
{
|
|
1801
1798
|
style: {
|
|
@@ -1805,7 +1802,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1805
1802
|
}
|
|
1806
1803
|
}
|
|
1807
1804
|
),
|
|
1808
|
-
/* @__PURE__ */
|
|
1805
|
+
/* @__PURE__ */ jsxs5(
|
|
1809
1806
|
"button",
|
|
1810
1807
|
{
|
|
1811
1808
|
style: { ...buttonStyle, color: "rgba(255,255,255,0.5)" },
|
|
@@ -1813,13 +1810,13 @@ function Status({ onReset, position, onClose }) {
|
|
|
1813
1810
|
onMouseEnter: onEnter,
|
|
1814
1811
|
onMouseLeave: onLeave,
|
|
1815
1812
|
children: [
|
|
1816
|
-
/* @__PURE__ */
|
|
1813
|
+
/* @__PURE__ */ jsx6(ResetIcon, {}),
|
|
1817
1814
|
"Reset"
|
|
1818
1815
|
]
|
|
1819
1816
|
}
|
|
1820
1817
|
)
|
|
1821
1818
|
] }),
|
|
1822
|
-
toast && /* @__PURE__ */
|
|
1819
|
+
toast && /* @__PURE__ */ jsx6(
|
|
1823
1820
|
"div",
|
|
1824
1821
|
{
|
|
1825
1822
|
style: {
|
|
@@ -1845,14 +1842,14 @@ function Status({ onReset, position, onClose }) {
|
|
|
1845
1842
|
);
|
|
1846
1843
|
}
|
|
1847
1844
|
function FolderIcon() {
|
|
1848
|
-
return /* @__PURE__ */
|
|
1845
|
+
return /* @__PURE__ */ jsx6(
|
|
1849
1846
|
"svg",
|
|
1850
1847
|
{
|
|
1851
1848
|
width: "14",
|
|
1852
1849
|
height: "14",
|
|
1853
1850
|
viewBox: "0 0 14 14",
|
|
1854
1851
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1855
|
-
children: /* @__PURE__ */
|
|
1852
|
+
children: /* @__PURE__ */ jsx6(
|
|
1856
1853
|
"path",
|
|
1857
1854
|
{
|
|
1858
1855
|
d: "M1.5 3A1.5 1.5 0 013 1.5h2.38a1 1 0 01.72.3L7 2.72a1 1 0 00.72.3H11A1.5 1.5 0 0112.5 4.5v6A1.5 1.5 0 0111 12H3A1.5 1.5 0 011.5 10.5V3z",
|
|
@@ -1865,7 +1862,7 @@ function FolderIcon() {
|
|
|
1865
1862
|
);
|
|
1866
1863
|
}
|
|
1867
1864
|
function CopyIcon() {
|
|
1868
|
-
return /* @__PURE__ */
|
|
1865
|
+
return /* @__PURE__ */ jsxs5(
|
|
1869
1866
|
"svg",
|
|
1870
1867
|
{
|
|
1871
1868
|
width: "14",
|
|
@@ -1873,7 +1870,7 @@ function CopyIcon() {
|
|
|
1873
1870
|
viewBox: "0 0 14 14",
|
|
1874
1871
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1875
1872
|
children: [
|
|
1876
|
-
/* @__PURE__ */
|
|
1873
|
+
/* @__PURE__ */ jsx6(
|
|
1877
1874
|
"rect",
|
|
1878
1875
|
{
|
|
1879
1876
|
x: "4",
|
|
@@ -1886,7 +1883,7 @@ function CopyIcon() {
|
|
|
1886
1883
|
strokeWidth: "1.3"
|
|
1887
1884
|
}
|
|
1888
1885
|
),
|
|
1889
|
-
/* @__PURE__ */
|
|
1886
|
+
/* @__PURE__ */ jsx6(
|
|
1890
1887
|
"path",
|
|
1891
1888
|
{
|
|
1892
1889
|
d: "M10 4V2.5A1.5 1.5 0 008.5 1h-6A1.5 1.5 0 001 2.5v6A1.5 1.5 0 002.5 10H4",
|
|
@@ -1900,14 +1897,14 @@ function CopyIcon() {
|
|
|
1900
1897
|
);
|
|
1901
1898
|
}
|
|
1902
1899
|
function PushIcon() {
|
|
1903
|
-
return /* @__PURE__ */
|
|
1900
|
+
return /* @__PURE__ */ jsx6(
|
|
1904
1901
|
"svg",
|
|
1905
1902
|
{
|
|
1906
1903
|
width: "14",
|
|
1907
1904
|
height: "14",
|
|
1908
1905
|
viewBox: "0 0 14 14",
|
|
1909
1906
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1910
|
-
children: /* @__PURE__ */
|
|
1907
|
+
children: /* @__PURE__ */ jsx6(
|
|
1911
1908
|
"path",
|
|
1912
1909
|
{
|
|
1913
1910
|
d: "M7 11V3m0 0L4 6m3-3l3 3",
|
|
@@ -1922,7 +1919,7 @@ function PushIcon() {
|
|
|
1922
1919
|
);
|
|
1923
1920
|
}
|
|
1924
1921
|
function ResetIcon() {
|
|
1925
|
-
return /* @__PURE__ */
|
|
1922
|
+
return /* @__PURE__ */ jsxs5(
|
|
1926
1923
|
"svg",
|
|
1927
1924
|
{
|
|
1928
1925
|
width: "14",
|
|
@@ -1930,7 +1927,7 @@ function ResetIcon() {
|
|
|
1930
1927
|
viewBox: "0 0 14 14",
|
|
1931
1928
|
style: { color: "rgba(255,255,255,0.4)" },
|
|
1932
1929
|
children: [
|
|
1933
|
-
/* @__PURE__ */
|
|
1930
|
+
/* @__PURE__ */ jsx6(
|
|
1934
1931
|
"path",
|
|
1935
1932
|
{
|
|
1936
1933
|
d: "M2.5 7a4.5 4.5 0 118 2.5",
|
|
@@ -1940,7 +1937,7 @@ function ResetIcon() {
|
|
|
1940
1937
|
strokeLinecap: "round"
|
|
1941
1938
|
}
|
|
1942
1939
|
),
|
|
1943
|
-
/* @__PURE__ */
|
|
1940
|
+
/* @__PURE__ */ jsx6(
|
|
1944
1941
|
"path",
|
|
1945
1942
|
{
|
|
1946
1943
|
d: "M2.5 3v4h4",
|
|
@@ -1957,7 +1954,7 @@ function ResetIcon() {
|
|
|
1957
1954
|
}
|
|
1958
1955
|
|
|
1959
1956
|
// src/overlay/index.tsx
|
|
1960
|
-
import { jsx as
|
|
1957
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1961
1958
|
async function saveCapture(type, mode, dataUrl) {
|
|
1962
1959
|
try {
|
|
1963
1960
|
const res = await fetch("/__afterbefore/save", {
|
|
@@ -1975,12 +1972,31 @@ async function saveCapture(type, mode, dataUrl) {
|
|
|
1975
1972
|
}
|
|
1976
1973
|
function AfterBefore() {
|
|
1977
1974
|
const { state, captureComplete, reset } = useOverlayState();
|
|
1978
|
-
const [statusOpen, setStatusOpen] =
|
|
1979
|
-
const [
|
|
1980
|
-
const [
|
|
1981
|
-
const [
|
|
1975
|
+
const [statusOpen, setStatusOpen] = useState8(false);
|
|
1976
|
+
const [toolbarActive, setToolbarActive] = useState8(false);
|
|
1977
|
+
const [selectorActive, setSelectorActive] = useState8(false);
|
|
1978
|
+
const [inspectorActive, setInspectorActive] = useState8(false);
|
|
1979
|
+
const [loading, setLoading] = useState8(false);
|
|
1980
|
+
const [selectedMode, setSelectedMode] = useState8("area");
|
|
1981
|
+
const [magnetEnabled, setMagnetEnabled] = useState8(true);
|
|
1982
|
+
const [areaRect, setAreaRect] = useState8(null);
|
|
1983
|
+
const [areaAspect, setAreaAspect] = useState8(DEFAULT_AREA_ASPECT);
|
|
1984
|
+
const [areaPresets, setAreaPresets] = useState8([]);
|
|
1982
1985
|
const iconPos = useRef5({ x: 24, y: 0 });
|
|
1983
|
-
|
|
1986
|
+
useEffect7(() => {
|
|
1987
|
+
try {
|
|
1988
|
+
setMagnetEnabled(localStorage.getItem("ab-magnet") !== "false");
|
|
1989
|
+
} catch {
|
|
1990
|
+
setMagnetEnabled(true);
|
|
1991
|
+
}
|
|
1992
|
+
try {
|
|
1993
|
+
const savedPresets = localStorage.getItem("ab-area-presets");
|
|
1994
|
+
setAreaPresets(savedPresets ? JSON.parse(savedPresets) : []);
|
|
1995
|
+
} catch {
|
|
1996
|
+
setAreaPresets([]);
|
|
1997
|
+
}
|
|
1998
|
+
}, []);
|
|
1999
|
+
useEffect7(() => {
|
|
1984
2000
|
if (state.phase === "ready") {
|
|
1985
2001
|
const timer = setTimeout(() => {
|
|
1986
2002
|
reset();
|
|
@@ -2000,7 +2016,9 @@ function AfterBefore() {
|
|
|
2000
2016
|
if (state.phase === "ready") {
|
|
2001
2017
|
setStatusOpen((prev) => !prev);
|
|
2002
2018
|
} else {
|
|
2003
|
-
|
|
2019
|
+
setToolbarActive((prev) => !prev);
|
|
2020
|
+
setSelectorActive(false);
|
|
2021
|
+
setInspectorActive(false);
|
|
2004
2022
|
setStatusOpen(false);
|
|
2005
2023
|
}
|
|
2006
2024
|
}, [state.phase, loading]);
|
|
@@ -2024,17 +2042,41 @@ function AfterBefore() {
|
|
|
2024
2042
|
},
|
|
2025
2043
|
[state.phase, captureComplete]
|
|
2026
2044
|
);
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2045
|
+
const handleToolbarCapture = useCallback6(
|
|
2046
|
+
(mode) => {
|
|
2047
|
+
if (mode === "area") {
|
|
2048
|
+
if (selectorActive && areaRect) {
|
|
2049
|
+
setSelectorActive(false);
|
|
2050
|
+
setToolbarActive(false);
|
|
2051
|
+
performCapture("area", {
|
|
2052
|
+
x: Math.round(areaRect.x),
|
|
2053
|
+
y: Math.round(areaRect.y),
|
|
2054
|
+
width: Math.round(areaRect.w),
|
|
2055
|
+
height: Math.round(areaRect.h)
|
|
2056
|
+
});
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
2059
|
+
setSelectedMode("area");
|
|
2060
|
+
setAreaAspect(DEFAULT_AREA_ASPECT);
|
|
2061
|
+
setAreaRect(createInitialAreaRect());
|
|
2062
|
+
setSelectorActive(true);
|
|
2063
|
+
setToolbarActive(true);
|
|
2064
|
+
} else if (mode === "viewport") {
|
|
2065
|
+
setToolbarActive(false);
|
|
2066
|
+
performCapture("viewport");
|
|
2067
|
+
} else if (mode === "fullpage") {
|
|
2068
|
+
setToolbarActive(false);
|
|
2069
|
+
performCapture("fullpage");
|
|
2070
|
+
} else if (mode === "component") {
|
|
2071
|
+
setToolbarActive(false);
|
|
2072
|
+
setInspectorActive(true);
|
|
2073
|
+
}
|
|
2074
|
+
},
|
|
2075
|
+
[areaRect, performCapture, selectorActive]
|
|
2076
|
+
);
|
|
2077
|
+
const handleToolbarCancel = useCallback6(() => {
|
|
2078
|
+
setToolbarActive(false);
|
|
2036
2079
|
setSelectorActive(false);
|
|
2037
|
-
setInspectorActive(true);
|
|
2038
2080
|
}, []);
|
|
2039
2081
|
const handleComponentSelect = useCallback6(
|
|
2040
2082
|
(element) => {
|
|
@@ -2045,16 +2087,97 @@ function AfterBefore() {
|
|
|
2045
2087
|
);
|
|
2046
2088
|
const handleComponentCancel = useCallback6(() => {
|
|
2047
2089
|
setInspectorActive(false);
|
|
2090
|
+
setToolbarActive(true);
|
|
2048
2091
|
}, []);
|
|
2049
2092
|
const handleAreaSelect = useCallback6(
|
|
2050
2093
|
(area) => {
|
|
2051
2094
|
setSelectorActive(false);
|
|
2095
|
+
setToolbarActive(false);
|
|
2052
2096
|
performCapture("area", area);
|
|
2053
2097
|
},
|
|
2054
2098
|
[performCapture]
|
|
2055
2099
|
);
|
|
2056
2100
|
const handleAreaCancel = useCallback6(() => {
|
|
2057
2101
|
setSelectorActive(false);
|
|
2102
|
+
setToolbarActive(true);
|
|
2103
|
+
}, []);
|
|
2104
|
+
const handleMagnetChange = useCallback6((enabled) => {
|
|
2105
|
+
setMagnetEnabled(enabled);
|
|
2106
|
+
try {
|
|
2107
|
+
localStorage.setItem("ab-magnet", String(enabled));
|
|
2108
|
+
} catch {
|
|
2109
|
+
}
|
|
2110
|
+
}, []);
|
|
2111
|
+
const handleModeChange = useCallback6((mode) => {
|
|
2112
|
+
setSelectedMode(mode);
|
|
2113
|
+
if (mode !== "area") {
|
|
2114
|
+
setSelectorActive(false);
|
|
2115
|
+
}
|
|
2116
|
+
}, []);
|
|
2117
|
+
const handleAreaRectChange = useCallback6((nextRect) => {
|
|
2118
|
+
setAreaRect(nextRect);
|
|
2119
|
+
}, []);
|
|
2120
|
+
const handleAreaSizeChange = useCallback6(
|
|
2121
|
+
(field, value) => {
|
|
2122
|
+
const nextValue = parseInt(value, 10);
|
|
2123
|
+
if (Number.isNaN(nextValue) || nextValue < 20 || !areaRect) {
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2126
|
+
const aspectRatio = areaAspect === "Free" ? 0 : { "16:9": 16 / 9, "4:3": 4 / 3, "1:1": 1, "3:2": 3 / 2, "21:9": 21 / 9 }[areaAspect];
|
|
2127
|
+
if (field === "w") {
|
|
2128
|
+
setAreaRect({
|
|
2129
|
+
...areaRect,
|
|
2130
|
+
w: nextValue,
|
|
2131
|
+
h: aspectRatio > 0 ? nextValue / aspectRatio : areaRect.h
|
|
2132
|
+
});
|
|
2133
|
+
} else {
|
|
2134
|
+
setAreaRect({
|
|
2135
|
+
...areaRect,
|
|
2136
|
+
h: nextValue,
|
|
2137
|
+
w: aspectRatio > 0 ? nextValue * aspectRatio : areaRect.w
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
},
|
|
2141
|
+
[areaAspect, areaRect]
|
|
2142
|
+
);
|
|
2143
|
+
const handleAreaPositionChange = useCallback6(
|
|
2144
|
+
(field, value) => {
|
|
2145
|
+
const nextValue = parseInt(value, 10);
|
|
2146
|
+
if (Number.isNaN(nextValue) || !areaRect) {
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
setAreaRect({ ...areaRect, [field]: nextValue });
|
|
2150
|
+
},
|
|
2151
|
+
[areaRect]
|
|
2152
|
+
);
|
|
2153
|
+
const handleAreaAspectChange = useCallback6(
|
|
2154
|
+
(nextAspect) => {
|
|
2155
|
+
setAreaAspect(nextAspect);
|
|
2156
|
+
if (!areaRect || nextAspect === "Free") {
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
const aspectRatio = { "16:9": 16 / 9, "4:3": 4 / 3, "1:1": 1, "3:2": 3 / 2, "21:9": 21 / 9 }[nextAspect];
|
|
2160
|
+
setAreaRect({ ...areaRect, h: areaRect.w / aspectRatio });
|
|
2161
|
+
},
|
|
2162
|
+
[areaRect]
|
|
2163
|
+
);
|
|
2164
|
+
const handleAreaSavePreset = useCallback6(() => {
|
|
2165
|
+
if (!areaRect) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
const label = `${Math.round(areaRect.w)}x${Math.round(areaRect.h)}`;
|
|
2169
|
+
const nextPresets = [
|
|
2170
|
+
...areaPresets.filter((preset) => preset.label !== label),
|
|
2171
|
+
{ label, rect: { ...areaRect } }
|
|
2172
|
+
];
|
|
2173
|
+
setAreaPresets(nextPresets);
|
|
2174
|
+
try {
|
|
2175
|
+
localStorage.setItem("ab-area-presets", JSON.stringify(nextPresets));
|
|
2176
|
+
} catch {
|
|
2177
|
+
}
|
|
2178
|
+
}, [areaPresets, areaRect]);
|
|
2179
|
+
const handleAreaLoadPreset = useCallback6((preset) => {
|
|
2180
|
+
setAreaRect({ ...preset.rect });
|
|
2058
2181
|
}, []);
|
|
2059
2182
|
const handleReset = useCallback6(() => {
|
|
2060
2183
|
reset();
|
|
@@ -2063,8 +2186,8 @@ function AfterBefore() {
|
|
|
2063
2186
|
const handleStatusClose = useCallback6(() => {
|
|
2064
2187
|
setStatusOpen(false);
|
|
2065
2188
|
}, []);
|
|
2066
|
-
return /* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
2189
|
+
return /* @__PURE__ */ jsxs6("div", { "data-afterbefore": "true", children: [
|
|
2190
|
+
/* @__PURE__ */ jsx7(
|
|
2068
2191
|
Icon,
|
|
2069
2192
|
{
|
|
2070
2193
|
phase: state.phase,
|
|
@@ -2073,18 +2196,40 @@ function AfterBefore() {
|
|
|
2073
2196
|
onPositionChange: handlePositionChange
|
|
2074
2197
|
}
|
|
2075
2198
|
),
|
|
2076
|
-
selectorActive && /* @__PURE__ */
|
|
2199
|
+
toolbarActive && !selectorActive && !inspectorActive && !loading && /* @__PURE__ */ jsx7(CapturePreview, { mode: selectedMode }),
|
|
2200
|
+
toolbarActive && !inspectorActive && /* @__PURE__ */ jsx7(
|
|
2201
|
+
Toolbar,
|
|
2202
|
+
{
|
|
2203
|
+
selectedMode,
|
|
2204
|
+
onModeChange: handleModeChange,
|
|
2205
|
+
onCapture: handleToolbarCapture,
|
|
2206
|
+
onCancel: handleToolbarCancel,
|
|
2207
|
+
magnetEnabled,
|
|
2208
|
+
onMagnetChange: handleMagnetChange,
|
|
2209
|
+
areaSelectionActive: selectorActive,
|
|
2210
|
+
areaRect,
|
|
2211
|
+
areaAspect,
|
|
2212
|
+
areaPresets,
|
|
2213
|
+
onAreaSizeChange: handleAreaSizeChange,
|
|
2214
|
+
onAreaPositionChange: handleAreaPositionChange,
|
|
2215
|
+
onAreaAspectChange: handleAreaAspectChange,
|
|
2216
|
+
onAreaSavePreset: handleAreaSavePreset,
|
|
2217
|
+
onAreaLoadPreset: handleAreaLoadPreset
|
|
2218
|
+
}
|
|
2219
|
+
),
|
|
2220
|
+
selectorActive && /* @__PURE__ */ jsx7(
|
|
2077
2221
|
Selector,
|
|
2078
2222
|
{
|
|
2223
|
+
rect: areaRect,
|
|
2224
|
+
aspect: areaAspect,
|
|
2225
|
+
onRectChange: handleAreaRectChange,
|
|
2079
2226
|
onSelect: handleAreaSelect,
|
|
2080
2227
|
onCancel: handleAreaCancel,
|
|
2081
|
-
|
|
2082
|
-
onFullPage: handleFullPageCapture,
|
|
2083
|
-
onComponent: handleComponentMode
|
|
2228
|
+
magnetEnabled
|
|
2084
2229
|
}
|
|
2085
2230
|
),
|
|
2086
|
-
inspectorActive && /* @__PURE__ */
|
|
2087
|
-
statusOpen && state.phase === "ready" && /* @__PURE__ */
|
|
2231
|
+
inspectorActive && /* @__PURE__ */ jsx7(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel }),
|
|
2232
|
+
statusOpen && state.phase === "ready" && /* @__PURE__ */ jsx7(
|
|
2088
2233
|
Status,
|
|
2089
2234
|
{
|
|
2090
2235
|
onReset: handleReset,
|