afterbefore 0.2.23 → 0.2.25
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 +1695 -1357
- package/dist/overlay/index.js.map +1 -1
- package/package.json +1 -1
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 useState6, useCallback as useCallback5, useEffect as useEffect5 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/overlay/state.ts
|
|
7
7
|
import { useState, useCallback } from "react";
|
|
@@ -25,15 +25,32 @@ function useOverlayState() {
|
|
|
25
25
|
|
|
26
26
|
// src/overlay/capture.ts
|
|
27
27
|
import { snapdom } from "@zumer/snapdom";
|
|
28
|
+
var GRADIENT_PRESETS = [
|
|
29
|
+
"linear-gradient(135deg, #a78bfa 0%, #f472b6 100%)",
|
|
30
|
+
"linear-gradient(135deg, #3b82f6 0%, #06b6d4 100%)",
|
|
31
|
+
"linear-gradient(135deg, #34d399 0%, #6ee7b7 100%)",
|
|
32
|
+
"linear-gradient(135deg, #f97316 0%, #ef4444 100%)",
|
|
33
|
+
"linear-gradient(180deg, #1e293b 0%, #0f172a 100%)"
|
|
34
|
+
];
|
|
35
|
+
var COLOR_PRESETS = [
|
|
36
|
+
"#FFFFFF",
|
|
37
|
+
"#F5F5F5",
|
|
38
|
+
"#F8F4ED",
|
|
39
|
+
"#1E1E1E",
|
|
40
|
+
"#000000"
|
|
41
|
+
];
|
|
28
42
|
var DEFAULT_FRAME_SETTINGS = {
|
|
29
43
|
enabled: false,
|
|
30
44
|
size: { w: 1920, h: 1080 },
|
|
31
45
|
bgType: "color",
|
|
32
|
-
bgColor: "#
|
|
46
|
+
bgColor: "#F5F5F5",
|
|
47
|
+
bgGradient: GRADIENT_PRESETS[0],
|
|
33
48
|
bgImage: null,
|
|
34
49
|
padding: 40,
|
|
35
50
|
browserChrome: false,
|
|
36
|
-
browserTheme: "dark"
|
|
51
|
+
browserTheme: "dark",
|
|
52
|
+
browserPadding: 20,
|
|
53
|
+
browserUrl: "localhost"
|
|
37
54
|
};
|
|
38
55
|
var FRAME_SIZE_PRESETS = [
|
|
39
56
|
{ label: "1920 x 1080", hint: "Desktop / HD", w: 1920, h: 1080 },
|
|
@@ -101,9 +118,9 @@ async function captureViewport(frameSettings) {
|
|
|
101
118
|
return viewportDataUrl;
|
|
102
119
|
}
|
|
103
120
|
const viewportImg = await loadImage(viewportDataUrl);
|
|
104
|
-
return drawBrowserChrome(viewportImg, frameSettings.browserTheme, dpr);
|
|
121
|
+
return drawBrowserChrome(viewportImg, frameSettings.browserTheme, dpr, frameSettings.browserUrl);
|
|
105
122
|
}
|
|
106
|
-
function drawBrowserChrome(img, theme, dpr) {
|
|
123
|
+
function drawBrowserChrome(img, theme, dpr, url = "localhost") {
|
|
107
124
|
const TITLE_BAR_H = 40;
|
|
108
125
|
const URL_BAR_H = 28;
|
|
109
126
|
const URL_BAR_MARGIN_TOP = 6;
|
|
@@ -150,7 +167,7 @@ function drawBrowserChrome(img, theme, dpr) {
|
|
|
150
167
|
ctx.font = `${11 * dpr}px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`;
|
|
151
168
|
ctx.textAlign = "center";
|
|
152
169
|
ctx.textBaseline = "middle";
|
|
153
|
-
ctx.fillText(
|
|
170
|
+
ctx.fillText(url, canvas.width / 2, urlBarY + urlBarH / 2);
|
|
154
171
|
ctx.drawImage(img, 0, CHROME_H * dpr);
|
|
155
172
|
return canvas.toDataURL("image/png");
|
|
156
173
|
}
|
|
@@ -202,12 +219,12 @@ async function captureComponent(element, frameSettings) {
|
|
|
202
219
|
const dpr = window.devicePixelRatio || 1;
|
|
203
220
|
const FRAME_W = frameSettings.size.w;
|
|
204
221
|
const FRAME_H = frameSettings.size.h;
|
|
205
|
-
const
|
|
222
|
+
const pad = frameSettings.browserChrome ? frameSettings.browserPadding ?? 20 : frameSettings.padding ?? 40;
|
|
206
223
|
const compW = img.width / dpr;
|
|
207
224
|
const compH = img.height / dpr;
|
|
208
|
-
const maxW = FRAME_W -
|
|
209
|
-
const maxH = FRAME_H -
|
|
210
|
-
const scale = Math.min(
|
|
225
|
+
const maxW = FRAME_W - pad * 2;
|
|
226
|
+
const maxH = FRAME_H - pad * 2;
|
|
227
|
+
const scale = Math.min(maxW / compW, maxH / compH, 1);
|
|
211
228
|
const drawW = compW * scale * dpr;
|
|
212
229
|
const drawH = compH * scale * dpr;
|
|
213
230
|
const canvas = document.createElement("canvas");
|
|
@@ -222,7 +239,9 @@ async function captureComponent(element, frameSettings) {
|
|
|
222
239
|
ctx.fillStyle = frameSettings.bgColor;
|
|
223
240
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
224
241
|
}
|
|
225
|
-
} else {
|
|
242
|
+
} else if (frameSettings.bgType === "gradient") {
|
|
243
|
+
fillCssGradient(ctx, frameSettings.bgGradient, canvas.width, canvas.height);
|
|
244
|
+
} else if (frameSettings.bgColor !== "transparent") {
|
|
226
245
|
ctx.fillStyle = frameSettings.bgColor;
|
|
227
246
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
228
247
|
}
|
|
@@ -247,6 +266,34 @@ function loadImage(src) {
|
|
|
247
266
|
img.src = src;
|
|
248
267
|
});
|
|
249
268
|
}
|
|
269
|
+
function fillCssGradient(ctx, css, w, h) {
|
|
270
|
+
const match = css.match(
|
|
271
|
+
/linear-gradient\(\s*([\d.]+)deg\s*,\s*(.+)\)/
|
|
272
|
+
);
|
|
273
|
+
if (!match) {
|
|
274
|
+
ctx.fillStyle = "#000";
|
|
275
|
+
ctx.fillRect(0, 0, w, h);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const angle = parseFloat(match[1]) * Math.PI / 180;
|
|
279
|
+
const stopsRaw = match[2].split(/,\s*(?=#|\w)/).map((s) => s.trim());
|
|
280
|
+
const cx = w / 2;
|
|
281
|
+
const cy = h / 2;
|
|
282
|
+
const len = Math.abs(w * Math.sin(angle)) + Math.abs(h * Math.cos(angle));
|
|
283
|
+
const x0 = cx - Math.sin(angle) * len / 2;
|
|
284
|
+
const y0 = cy + Math.cos(angle) * len / 2;
|
|
285
|
+
const x1 = cx + Math.sin(angle) * len / 2;
|
|
286
|
+
const y1 = cy - Math.cos(angle) * len / 2;
|
|
287
|
+
const grad = ctx.createLinearGradient(x0, y0, x1, y1);
|
|
288
|
+
for (const stop of stopsRaw) {
|
|
289
|
+
const parts = stop.match(/^(.+?)\s+([\d.]+)%$/);
|
|
290
|
+
if (parts) {
|
|
291
|
+
grad.addColorStop(parseFloat(parts[2]) / 100, parts[1]);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
ctx.fillStyle = grad;
|
|
295
|
+
ctx.fillRect(0, 0, w, h);
|
|
296
|
+
}
|
|
250
297
|
|
|
251
298
|
// src/overlay/font.ts
|
|
252
299
|
var FONT_FAMILY = "'Inter var', 'Inter', system-ui, -apple-system, sans-serif";
|
|
@@ -307,37 +354,85 @@ function injectInterFont() {
|
|
|
307
354
|
}
|
|
308
355
|
|
|
309
356
|
// src/overlay/ui/toolbar.tsx
|
|
310
|
-
import { useCallback as
|
|
311
|
-
import { createPortal } from "react-dom";
|
|
357
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
|
|
312
358
|
import {
|
|
313
|
-
ArrowUp,
|
|
314
|
-
Camera,
|
|
315
|
-
Check,
|
|
316
359
|
ChevronDown as ChevronDown2,
|
|
317
|
-
Image as Image2,
|
|
318
|
-
FolderOpen,
|
|
319
360
|
LoaderCircle,
|
|
320
361
|
FileText,
|
|
321
|
-
Monitor
|
|
322
|
-
MousePointer2,
|
|
323
|
-
Trash2 as Trash22,
|
|
324
|
-
X as X2
|
|
362
|
+
Monitor
|
|
325
363
|
} from "lucide-react";
|
|
326
364
|
|
|
365
|
+
// src/overlay/ui/icons.tsx
|
|
366
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
367
|
+
function CameraIcon({ size = 32, color }) {
|
|
368
|
+
return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 32 32", fill: "none", style: { color }, children: /* @__PURE__ */ jsx(
|
|
369
|
+
"path",
|
|
370
|
+
{
|
|
371
|
+
d: "M23.2119 13.8662C23.8759 13.8662 24.4228 13.3193 24.4228 12.6553C24.4228 11.9814 23.8759 11.4443 23.2119 11.4443C22.538 11.4443 22.0009 11.9814 22.0009 12.6553C22.0009 13.3193 22.538 13.8662 23.2119 13.8662ZM6.89356 24.999H24.7451C26.7763 24.999 27.8115 23.9834 27.8115 21.9717V11.7471C27.8115 9.73536 26.7763 8.7295 24.7451 8.7295H21.9521C21.1806 8.7295 20.9462 8.57325 20.5068 8.08496L19.7255 7.20605C19.2373 6.66895 18.7392 6.37598 17.7333 6.37598H13.8369C12.8311 6.37598 12.333 6.66895 11.8447 7.20605L11.0635 8.08496C10.624 8.56348 10.3799 8.7295 9.61817 8.7295H6.89356C4.85254 8.7295 3.82715 9.73536 3.82715 11.7471V21.9717C3.82715 23.9834 4.85254 24.999 6.89356 24.999ZM6.91309 23.4268C5.95606 23.4268 5.39942 22.9092 5.39942 21.8936V11.835C5.39942 10.8193 5.95606 10.3018 6.91309 10.3018H10.0088C10.8877 10.3018 11.3662 10.1357 11.8545 9.58887L12.6162 8.7295C13.1728 8.1045 13.4658 7.94825 14.3251 7.94825H17.2451C18.1044 7.94825 18.3974 8.1045 18.9541 8.7295L19.7158 9.58887C20.2041 10.1357 20.6826 10.3018 21.5615 10.3018H24.7158C25.6826 10.3018 26.2392 10.8193 26.2392 11.835V21.8936C26.2392 22.9092 25.6826 23.4268 24.7158 23.4268H6.91309ZM15.8193 22.0205C18.7685 22.0205 21.1416 19.6572 21.1416 16.6787C21.1416 13.71 18.7783 11.3467 15.8193 11.3467C12.8603 11.3467 10.4873 13.71 10.4873 16.6787C10.4873 19.6572 12.8603 22.0205 15.8193 22.0205ZM15.8193 20.5362C13.7002 20.5362 11.9619 18.8272 11.9619 16.6787C11.9619 14.54 13.6904 12.8213 15.8193 12.8213C17.9482 12.8213 19.6669 14.54 19.6669 16.6787C19.6669 18.8272 17.9482 20.5362 15.8193 20.5362Z",
|
|
372
|
+
fill: "currentColor"
|
|
373
|
+
}
|
|
374
|
+
) });
|
|
375
|
+
}
|
|
376
|
+
function ImageIcon({ size = 32, color }) {
|
|
377
|
+
return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 32 32", fill: "none", style: { color }, children: [
|
|
378
|
+
/* @__PURE__ */ jsx(
|
|
379
|
+
"path",
|
|
380
|
+
{
|
|
381
|
+
d: "M7.30371 24.3056H23.6709C25.4385 24.3056 26.3272 23.3193 26.3272 21.4443L20.5264 15.9951C20.0967 15.5947 19.5791 15.3897 19.0518 15.3897C18.5147 15.3897 18.0362 15.5752 17.5869 15.9756L13.1729 19.9209L11.3662 18.29C10.9561 17.9189 10.5068 17.7334 10.0479 17.7334C9.60839 17.7334 9.18847 17.9091 8.78808 18.2802L5.06738 21.6396C5.12598 23.4072 5.84863 24.3056 7.30371 24.3056ZM7.37207 24.9892H24.2666C26.3174 24.9892 27.333 23.9834 27.333 21.9716V10.0381C27.333 8.02636 26.3174 7.01074 24.2666 7.01074H7.37207C5.33105 7.01074 4.30566 8.02636 4.30566 10.0381V21.9716C4.30566 23.9834 5.33105 24.9892 7.37207 24.9892ZM7.3916 23.4169C6.41504 23.4169 5.87793 22.8994 5.87793 21.8837V10.126C5.87793 9.11035 6.41504 8.58301 7.3916 8.58301H24.2471C25.2139 8.58301 25.7608 9.11035 25.7608 10.126V21.8837C25.7608 22.8994 25.2139 23.4169 24.2471 23.4169H7.3916Z",
|
|
382
|
+
fill: "currentColor"
|
|
383
|
+
}
|
|
384
|
+
),
|
|
385
|
+
/* @__PURE__ */ jsx(
|
|
386
|
+
"path",
|
|
387
|
+
{
|
|
388
|
+
d: "M11.5811 16.0928C12.8408 16.0928 13.876 15.0576 13.876 13.7881C13.876 12.5283 12.8408 11.4834 11.5811 11.4834C10.3115 11.4834 9.27637 12.5283 9.27637 13.7881C9.27637 15.0576 10.3115 16.0928 11.5811 16.0928Z",
|
|
389
|
+
fill: "currentColor"
|
|
390
|
+
}
|
|
391
|
+
)
|
|
392
|
+
] });
|
|
393
|
+
}
|
|
394
|
+
function CheckmarkIcon({ size = 32, color }) {
|
|
395
|
+
return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 32 32", fill: "none", style: { color }, children: [
|
|
396
|
+
/* @__PURE__ */ jsx(
|
|
397
|
+
"path",
|
|
398
|
+
{
|
|
399
|
+
d: "M15.8193 25.9561C21.3174 25.9561 25.7803 21.4932 25.7803 15.9951C25.7803 10.4971 21.3174 6.03418 15.8193 6.03418C10.3213 6.03418 5.8584 10.4971 5.8584 15.9951C5.8584 21.4932 10.3213 25.9561 15.8193 25.9561ZM15.8193 24.2959C11.2295 24.2959 7.51856 20.585 7.51856 15.9951C7.51856 11.4053 11.2295 7.69434 15.8193 7.69434C20.4092 7.69434 24.1201 11.4053 24.1201 15.9951C24.1201 20.585 20.4092 24.2959 15.8193 24.2959Z",
|
|
400
|
+
fill: "currentColor"
|
|
401
|
+
}
|
|
402
|
+
),
|
|
403
|
+
/* @__PURE__ */ jsx(
|
|
404
|
+
"path",
|
|
405
|
+
{
|
|
406
|
+
d: "M14.7451 20.6338C15.0674 20.6338 15.3408 20.4776 15.5361 20.1748L19.999 13.1533C20.1064 12.958 20.2334 12.7432 20.2334 12.5283C20.2334 12.0889 19.8428 11.8057 19.4326 11.8057C19.1885 11.8057 18.9443 11.9619 18.7588 12.2451L14.7061 18.749L12.7822 16.2588C12.5478 15.9463 12.333 15.8682 12.0596 15.8682C11.6396 15.8682 11.3076 16.21 11.3076 16.6397C11.3076 16.8545 11.3955 17.0596 11.5322 17.2451L13.915 20.1748C14.1592 20.4971 14.4228 20.6338 14.7451 20.6338Z",
|
|
407
|
+
fill: "currentColor"
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
] });
|
|
411
|
+
}
|
|
412
|
+
function CloseIcon({ size = 32, color }) {
|
|
413
|
+
return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 32 32", fill: "none", style: { color }, children: /* @__PURE__ */ jsx(
|
|
414
|
+
"path",
|
|
415
|
+
{
|
|
416
|
+
d: "M22.0693 8.52467L8.32911 22.2649C7.99708 22.5969 7.98732 23.1633 8.32911 23.4953C8.67091 23.8274 9.23732 23.8274 9.56935 23.4953L23.3096 9.75514C23.6416 9.42311 23.6514 8.8567 23.3096 8.52467C22.9678 8.18287 22.4111 8.17311 22.0693 8.52467ZM23.3096 22.2649L9.56935 8.52467C9.23732 8.18287 8.66115 8.17311 8.32911 8.52467C7.99708 8.86647 7.99708 9.42311 8.32911 9.75514L22.0693 23.4953C22.4014 23.8274 22.9775 23.8371 23.3096 23.4953C23.6416 23.1535 23.6416 22.5969 23.3096 22.2649Z",
|
|
417
|
+
fill: "currentColor"
|
|
418
|
+
}
|
|
419
|
+
) });
|
|
420
|
+
}
|
|
421
|
+
|
|
327
422
|
// src/overlay/color.ts
|
|
328
423
|
var gray = {
|
|
329
|
-
950: "
|
|
330
|
-
900: "
|
|
331
|
-
800: "
|
|
332
|
-
700: "
|
|
333
|
-
600: "
|
|
334
|
-
500: "
|
|
335
|
-
400: "
|
|
336
|
-
300: "
|
|
337
|
-
200: "
|
|
338
|
-
100: "
|
|
339
|
-
50: "
|
|
340
|
-
0: "
|
|
424
|
+
950: "oklch(0.162 0 0)",
|
|
425
|
+
900: "oklch(0.195 0 0)",
|
|
426
|
+
800: "oklch(0.254 0 0)",
|
|
427
|
+
700: "oklch(0.302 0 0)",
|
|
428
|
+
600: "oklch(0.348 0 0)",
|
|
429
|
+
500: "oklch(0.396 0 0)",
|
|
430
|
+
400: "oklch(0.459 0 0)",
|
|
431
|
+
300: "oklch(0.549 0 0)",
|
|
432
|
+
200: "oklch(0.649 0 0)",
|
|
433
|
+
100: "oklch(0.72 0 0)",
|
|
434
|
+
50: "oklch(0.863 0 0)",
|
|
435
|
+
0: "oklch(0.933 0 0)"
|
|
341
436
|
};
|
|
342
437
|
var bg = {
|
|
343
438
|
base: gray[900],
|
|
@@ -346,10 +441,15 @@ var bg = {
|
|
|
346
441
|
};
|
|
347
442
|
var fg = {
|
|
348
443
|
strong: gray[200],
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
444
|
+
// ~5.6:1 — headings, input values
|
|
445
|
+
default: "oklch(0.6 0 0)",
|
|
446
|
+
// ~4.6:1 — body text, interactive labels (AA)
|
|
447
|
+
sub: gray[300],
|
|
448
|
+
// ~3.8:1 — secondary labels, icons
|
|
449
|
+
muted: "oklch(0.5 0 0)",
|
|
450
|
+
// ~3:1 — inline labels, decorative
|
|
451
|
+
faint: gray[500]
|
|
452
|
+
// ~2:1 — non-essential hints only
|
|
353
453
|
};
|
|
354
454
|
var stroke = {
|
|
355
455
|
soft: "rgba(255, 255, 255, 0.08)",
|
|
@@ -387,17 +487,26 @@ var shadow = {
|
|
|
387
487
|
status: "0 4px 20px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.08)"
|
|
388
488
|
};
|
|
389
489
|
|
|
490
|
+
// src/overlay/ui/screenshots-panel.tsx
|
|
491
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState3 } from "react";
|
|
492
|
+
import { createPortal } from "react-dom";
|
|
493
|
+
import {
|
|
494
|
+
Trash2 as Trash22,
|
|
495
|
+
X
|
|
496
|
+
} from "lucide-react";
|
|
497
|
+
|
|
390
498
|
// src/overlay/ui/settings-panel.tsx
|
|
391
499
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
392
500
|
import {
|
|
501
|
+
AppWindow,
|
|
502
|
+
Check,
|
|
393
503
|
ChevronDown,
|
|
394
|
-
|
|
395
|
-
|
|
504
|
+
LayoutGrid,
|
|
505
|
+
Pipette,
|
|
396
506
|
Trash2,
|
|
397
|
-
Upload
|
|
398
|
-
X
|
|
507
|
+
Upload
|
|
399
508
|
} from "lucide-react";
|
|
400
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
509
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
401
510
|
function SettingsContent({
|
|
402
511
|
frameSettings,
|
|
403
512
|
onFrameSettingsChange,
|
|
@@ -405,90 +514,41 @@ function SettingsContent({
|
|
|
405
514
|
picking,
|
|
406
515
|
onPickFolder
|
|
407
516
|
}) {
|
|
408
|
-
return /* @__PURE__ */
|
|
409
|
-
/* @__PURE__ */
|
|
410
|
-
|
|
517
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
518
|
+
/* @__PURE__ */ jsx2(
|
|
519
|
+
BackgroundSetting,
|
|
411
520
|
{
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
ToggleSwitch,
|
|
415
|
-
{
|
|
416
|
-
enabled: frameSettings.enabled,
|
|
417
|
-
onChange: () => onFrameSettingsChange({ ...frameSettings, enabled: !frameSettings.enabled })
|
|
418
|
-
}
|
|
419
|
-
)
|
|
521
|
+
frameSettings,
|
|
522
|
+
onFrameSettingsChange
|
|
420
523
|
}
|
|
421
524
|
),
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
/* @__PURE__ */ jsx(
|
|
425
|
-
FrameSizeControl,
|
|
426
|
-
{
|
|
427
|
-
size: frameSettings.size,
|
|
428
|
-
onChange: (size) => onFrameSettingsChange({ ...frameSettings, size })
|
|
429
|
-
}
|
|
430
|
-
),
|
|
431
|
-
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
432
|
-
/* @__PURE__ */ jsx(
|
|
433
|
-
FrameBackgroundControl,
|
|
434
|
-
{
|
|
435
|
-
bgType: frameSettings.bgType,
|
|
436
|
-
bgColor: frameSettings.bgColor,
|
|
437
|
-
bgImage: frameSettings.bgImage,
|
|
438
|
-
frameSize: frameSettings.size,
|
|
439
|
-
onChange: (updates) => onFrameSettingsChange({ ...frameSettings, ...updates })
|
|
440
|
-
}
|
|
441
|
-
)
|
|
442
|
-
] }),
|
|
443
|
-
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
444
|
-
/* @__PURE__ */ jsx(
|
|
445
|
-
SettingsRow,
|
|
525
|
+
/* @__PURE__ */ jsx2(
|
|
526
|
+
FrameSizeControl,
|
|
446
527
|
{
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
ToggleSwitch,
|
|
450
|
-
{
|
|
451
|
-
enabled: frameSettings.browserChrome,
|
|
452
|
-
onChange: () => onFrameSettingsChange({ ...frameSettings, browserChrome: !frameSettings.browserChrome })
|
|
453
|
-
}
|
|
454
|
-
)
|
|
528
|
+
size: frameSettings.size,
|
|
529
|
+
onChange: (size) => onFrameSettingsChange({ ...frameSettings, size })
|
|
455
530
|
}
|
|
456
531
|
),
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
/* @__PURE__ */ jsx(
|
|
474
|
-
SegmentButton,
|
|
475
|
-
{
|
|
476
|
-
active: frameSettings.browserTheme === "dark",
|
|
477
|
-
onClick: () => onFrameSettingsChange({ ...frameSettings, browserTheme: "dark" }),
|
|
478
|
-
style: { borderRadius: "0 6px 6px 0" },
|
|
479
|
-
children: "Dark"
|
|
480
|
-
}
|
|
481
|
-
)
|
|
482
|
-
] })
|
|
483
|
-
}
|
|
484
|
-
)
|
|
485
|
-
] }),
|
|
486
|
-
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
487
|
-
saveDir !== void 0 && onPickFolder && /* @__PURE__ */ jsx(
|
|
532
|
+
/* @__PURE__ */ jsx2(SettingsDivider, {}),
|
|
533
|
+
/* @__PURE__ */ jsx2(
|
|
534
|
+
BrowserFrameSetting,
|
|
535
|
+
{
|
|
536
|
+
enabled: frameSettings.browserChrome,
|
|
537
|
+
theme: frameSettings.browserTheme,
|
|
538
|
+
padding: frameSettings.browserPadding ?? 20,
|
|
539
|
+
url: frameSettings.browserUrl ?? "localhost",
|
|
540
|
+
onToggle: () => onFrameSettingsChange({ ...frameSettings, browserChrome: !frameSettings.browserChrome }),
|
|
541
|
+
onSelect: (theme) => onFrameSettingsChange({ ...frameSettings, browserChrome: true, browserTheme: theme }),
|
|
542
|
+
onPaddingChange: (v) => onFrameSettingsChange({ ...frameSettings, browserPadding: v }),
|
|
543
|
+
onUrlChange: (v) => onFrameSettingsChange({ ...frameSettings, browserUrl: v })
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
/* @__PURE__ */ jsx2(SettingsDivider, {}),
|
|
547
|
+
saveDir !== void 0 && onPickFolder && /* @__PURE__ */ jsx2(
|
|
488
548
|
SettingsRow,
|
|
489
549
|
{
|
|
490
550
|
title: "Save Location",
|
|
491
|
-
description: /* @__PURE__ */
|
|
551
|
+
description: /* @__PURE__ */ jsx2(
|
|
492
552
|
"span",
|
|
493
553
|
{
|
|
494
554
|
style: {
|
|
@@ -501,7 +561,7 @@ function SettingsContent({
|
|
|
501
561
|
children: saveDir
|
|
502
562
|
}
|
|
503
563
|
),
|
|
504
|
-
control: /* @__PURE__ */
|
|
564
|
+
control: /* @__PURE__ */ jsx2(SmallButton, { onClick: onPickFolder, children: picking ? "..." : "Change" })
|
|
505
565
|
}
|
|
506
566
|
)
|
|
507
567
|
] });
|
|
@@ -511,20 +571,21 @@ function SettingsRow({
|
|
|
511
571
|
description,
|
|
512
572
|
control
|
|
513
573
|
}) {
|
|
514
|
-
return /* @__PURE__ */
|
|
515
|
-
/* @__PURE__ */
|
|
516
|
-
/* @__PURE__ */
|
|
517
|
-
description && /* @__PURE__ */
|
|
574
|
+
return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, padding: "14px 0" }, children: [
|
|
575
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 2, flex: 1, minWidth: 0 }, children: [
|
|
576
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: title }),
|
|
577
|
+
description && /* @__PURE__ */ jsx2("span", { style: { ...text.paragraph.xs, color: fg.sub }, children: description })
|
|
518
578
|
] }),
|
|
519
|
-
/* @__PURE__ */
|
|
579
|
+
/* @__PURE__ */ jsx2("div", { style: { flexShrink: 0 }, children: control })
|
|
520
580
|
] });
|
|
521
581
|
}
|
|
522
582
|
function SettingsDivider() {
|
|
523
|
-
return /* @__PURE__ */
|
|
583
|
+
return /* @__PURE__ */ jsx2(
|
|
524
584
|
"div",
|
|
525
585
|
{
|
|
526
586
|
style: {
|
|
527
|
-
borderBottom: `1px solid ${stroke.soft}
|
|
587
|
+
borderBottom: `1px solid ${stroke.soft}`,
|
|
588
|
+
margin: "0 -16px"
|
|
528
589
|
}
|
|
529
590
|
}
|
|
530
591
|
);
|
|
@@ -533,7 +594,7 @@ function ToggleSwitch({
|
|
|
533
594
|
enabled,
|
|
534
595
|
onChange
|
|
535
596
|
}) {
|
|
536
|
-
return /* @__PURE__ */
|
|
597
|
+
return /* @__PURE__ */ jsx2(
|
|
537
598
|
"button",
|
|
538
599
|
{
|
|
539
600
|
type: "button",
|
|
@@ -550,7 +611,7 @@ function ToggleSwitch({
|
|
|
550
611
|
flexShrink: 0,
|
|
551
612
|
transition: "background 0.12s ease"
|
|
552
613
|
},
|
|
553
|
-
children: /* @__PURE__ */
|
|
614
|
+
children: /* @__PURE__ */ jsx2(
|
|
554
615
|
"span",
|
|
555
616
|
{
|
|
556
617
|
style: {
|
|
@@ -573,13 +634,71 @@ function FrameSizeControl({
|
|
|
573
634
|
onChange
|
|
574
635
|
}) {
|
|
575
636
|
const [sizeOpen, setSizeOpen] = useState2(false);
|
|
637
|
+
const [editing, setEditing] = useState2(null);
|
|
638
|
+
const [text2, setText] = useState2("");
|
|
576
639
|
const currentPreset = FRAME_SIZE_PRESETS.find((p) => p.w === size.w && p.h === size.h);
|
|
577
640
|
const isCustom = !currentPreset;
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
641
|
+
const commitValue = (field, raw) => {
|
|
642
|
+
const n = parseInt(raw, 10);
|
|
643
|
+
if (!Number.isNaN(n) && n > 0) onChange({ ...size, [field]: n });
|
|
644
|
+
};
|
|
645
|
+
const inputStyle = {
|
|
646
|
+
flex: 1,
|
|
647
|
+
minWidth: 0,
|
|
648
|
+
border: "none",
|
|
649
|
+
background: "transparent",
|
|
650
|
+
color: fg.strong,
|
|
651
|
+
...text.label.xs,
|
|
652
|
+
fontFamily: "inherit",
|
|
653
|
+
textAlign: "left",
|
|
654
|
+
outline: "none",
|
|
655
|
+
padding: "0 2px 0 6px"
|
|
656
|
+
};
|
|
657
|
+
return /* @__PURE__ */ jsxs2("div", { style: { marginTop: 16, paddingBottom: 14 }, children: [
|
|
658
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: "Size" }),
|
|
659
|
+
/* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 6, marginTop: 8 }, children: ["w", "h"].map((field) => /* @__PURE__ */ jsxs2(
|
|
660
|
+
"div",
|
|
661
|
+
{
|
|
662
|
+
style: {
|
|
663
|
+
flex: 1,
|
|
664
|
+
minWidth: 0,
|
|
665
|
+
display: "flex",
|
|
666
|
+
alignItems: "center",
|
|
667
|
+
height: 30,
|
|
668
|
+
padding: "0 8px",
|
|
669
|
+
background: state.input,
|
|
670
|
+
borderRadius: 7
|
|
671
|
+
},
|
|
672
|
+
children: [
|
|
673
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.xs, color: fg.sub, flexShrink: 0, userSelect: "none" }, children: field.toUpperCase() }),
|
|
674
|
+
/* @__PURE__ */ jsx2(
|
|
675
|
+
"input",
|
|
676
|
+
{
|
|
677
|
+
type: "text",
|
|
678
|
+
value: editing === field ? text2 : String(size[field]),
|
|
679
|
+
onFocus: () => {
|
|
680
|
+
setEditing(field);
|
|
681
|
+
setText(String(size[field]));
|
|
682
|
+
},
|
|
683
|
+
onBlur: () => {
|
|
684
|
+
setEditing(null);
|
|
685
|
+
commitValue(field, text2);
|
|
686
|
+
},
|
|
687
|
+
onChange: (e) => setText(e.target.value),
|
|
688
|
+
onKeyDown: (e) => {
|
|
689
|
+
if (e.key === "Enter") e.target.blur();
|
|
690
|
+
},
|
|
691
|
+
style: inputStyle
|
|
692
|
+
}
|
|
693
|
+
)
|
|
694
|
+
]
|
|
695
|
+
},
|
|
696
|
+
field
|
|
697
|
+
)) }),
|
|
698
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, marginTop: 16 }, children: [
|
|
699
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: "Presets" }),
|
|
700
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
701
|
+
/* @__PURE__ */ jsxs2(
|
|
583
702
|
"button",
|
|
584
703
|
{
|
|
585
704
|
onClick: () => setSizeOpen((prev) => !prev),
|
|
@@ -587,12 +706,12 @@ function FrameSizeControl({
|
|
|
587
706
|
display: "flex",
|
|
588
707
|
alignItems: "center",
|
|
589
708
|
gap: 6,
|
|
590
|
-
height:
|
|
591
|
-
padding: "0
|
|
709
|
+
height: 28,
|
|
710
|
+
padding: "0 8px",
|
|
592
711
|
borderRadius: 7,
|
|
593
712
|
border: `1px solid ${stroke.default}`,
|
|
594
713
|
background: state.input,
|
|
595
|
-
color: fg.
|
|
714
|
+
color: fg.sub,
|
|
596
715
|
cursor: "pointer",
|
|
597
716
|
...text.label.xs,
|
|
598
717
|
fontFamily: "inherit",
|
|
@@ -600,11 +719,11 @@ function FrameSizeControl({
|
|
|
600
719
|
},
|
|
601
720
|
children: [
|
|
602
721
|
currentPreset ? currentPreset.label : "Custom",
|
|
603
|
-
/* @__PURE__ */
|
|
722
|
+
/* @__PURE__ */ jsx2(ChevronDown, { size: 12, strokeWidth: 2 })
|
|
604
723
|
]
|
|
605
724
|
}
|
|
606
725
|
),
|
|
607
|
-
sizeOpen && /* @__PURE__ */
|
|
726
|
+
sizeOpen && /* @__PURE__ */ jsx2(
|
|
608
727
|
"div",
|
|
609
728
|
{
|
|
610
729
|
style: {
|
|
@@ -619,7 +738,7 @@ function FrameSizeControl({
|
|
|
619
738
|
boxShadow: shadow.dropdown,
|
|
620
739
|
zIndex: 1
|
|
621
740
|
},
|
|
622
|
-
children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */
|
|
741
|
+
children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs2(
|
|
623
742
|
DropItem,
|
|
624
743
|
{
|
|
625
744
|
active: !isCustom && preset.w === size.w && preset.h === size.h,
|
|
@@ -628,8 +747,8 @@ function FrameSizeControl({
|
|
|
628
747
|
setSizeOpen(false);
|
|
629
748
|
},
|
|
630
749
|
children: [
|
|
631
|
-
/* @__PURE__ */
|
|
632
|
-
/* @__PURE__ */
|
|
750
|
+
/* @__PURE__ */ jsx2("span", { children: preset.label }),
|
|
751
|
+
/* @__PURE__ */ jsx2("span", { style: { marginLeft: 6, fontSize: 10, color: fg.muted }, children: preset.hint })
|
|
633
752
|
]
|
|
634
753
|
},
|
|
635
754
|
preset.label
|
|
@@ -637,39 +756,16 @@ function FrameSizeControl({
|
|
|
637
756
|
}
|
|
638
757
|
)
|
|
639
758
|
] })
|
|
640
|
-
] }),
|
|
641
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 10 }, children: [
|
|
642
|
-
/* @__PURE__ */ jsx(
|
|
643
|
-
NumInput,
|
|
644
|
-
{
|
|
645
|
-
value: size.w,
|
|
646
|
-
onChange: (v) => {
|
|
647
|
-
const n = parseInt(v, 10);
|
|
648
|
-
if (!Number.isNaN(n) && n > 0) onChange({ ...size, w: n });
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
),
|
|
652
|
-
/* @__PURE__ */ jsx(StaticText, { children: "x" }),
|
|
653
|
-
/* @__PURE__ */ jsx(
|
|
654
|
-
NumInput,
|
|
655
|
-
{
|
|
656
|
-
value: size.h,
|
|
657
|
-
onChange: (v) => {
|
|
658
|
-
const n = parseInt(v, 10);
|
|
659
|
-
if (!Number.isNaN(n) && n > 0) onChange({ ...size, h: n });
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
)
|
|
663
759
|
] })
|
|
664
760
|
] });
|
|
665
761
|
}
|
|
666
|
-
function
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
bgImage,
|
|
670
|
-
frameSize,
|
|
671
|
-
onChange
|
|
762
|
+
function BackgroundSetting({
|
|
763
|
+
frameSettings,
|
|
764
|
+
onFrameSettingsChange
|
|
672
765
|
}) {
|
|
766
|
+
const [tab, setTab] = useState2(
|
|
767
|
+
frameSettings.bgType === "image" ? "image" : frameSettings.bgType === "gradient" ? "gradient" : "solid"
|
|
768
|
+
);
|
|
673
769
|
const fileInputRef = useRef(null);
|
|
674
770
|
const handleFileSelect = (e) => {
|
|
675
771
|
const file = e.target.files?.[0];
|
|
@@ -678,52 +774,123 @@ function FrameBackgroundControl({
|
|
|
678
774
|
reader.onload = () => {
|
|
679
775
|
const dataUrl = reader.result;
|
|
680
776
|
if (dataUrl.length > 2 * 1024 * 1024) {
|
|
681
|
-
downscaleImage(dataUrl,
|
|
682
|
-
|
|
777
|
+
downscaleImage(dataUrl, frameSettings.size.w, frameSettings.size.h).then((scaled) => {
|
|
778
|
+
onFrameSettingsChange({ ...frameSettings, bgType: "image", bgImage: scaled });
|
|
683
779
|
});
|
|
684
780
|
} else {
|
|
685
|
-
|
|
781
|
+
onFrameSettingsChange({ ...frameSettings, bgType: "image", bgImage: dataUrl });
|
|
686
782
|
}
|
|
687
783
|
};
|
|
688
784
|
reader.readAsDataURL(file);
|
|
689
785
|
e.target.value = "";
|
|
690
786
|
};
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
onClick: () => onChange({ bgType: "image" }),
|
|
712
|
-
style: { borderRadius: "0 6px 6px 0" },
|
|
713
|
-
children: [
|
|
714
|
-
/* @__PURE__ */ jsx(ImageIcon, { size: 12, strokeWidth: 2 }),
|
|
715
|
-
"Image"
|
|
716
|
-
]
|
|
717
|
-
}
|
|
718
|
-
)
|
|
719
|
-
] })
|
|
787
|
+
const selectGradient = (g) => {
|
|
788
|
+
onFrameSettingsChange({ ...frameSettings, bgType: "gradient", bgGradient: g });
|
|
789
|
+
};
|
|
790
|
+
const selectColor = (c) => {
|
|
791
|
+
onFrameSettingsChange({ ...frameSettings, bgType: "color", bgColor: c });
|
|
792
|
+
};
|
|
793
|
+
const currentBg = frameSettings.bgType === "gradient" ? frameSettings.bgGradient : frameSettings.bgColor;
|
|
794
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
795
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }, children: [
|
|
796
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
797
|
+
/* @__PURE__ */ jsx2(LayoutGrid, { size: 16, strokeWidth: 1.6, color: fg.sub }),
|
|
798
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: "Background" })
|
|
799
|
+
] }),
|
|
800
|
+
/* @__PURE__ */ jsx2(
|
|
801
|
+
ToggleSwitch,
|
|
802
|
+
{
|
|
803
|
+
enabled: frameSettings.enabled,
|
|
804
|
+
onChange: () => onFrameSettingsChange({ ...frameSettings, enabled: !frameSettings.enabled })
|
|
805
|
+
}
|
|
806
|
+
)
|
|
720
807
|
] }),
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
808
|
+
/* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 2, marginTop: 12, background: state.subtle, borderRadius: 8, padding: 2 }, children: ["solid", "gradient", "image"].map((t) => /* @__PURE__ */ jsx2(
|
|
809
|
+
"button",
|
|
810
|
+
{
|
|
811
|
+
onClick: () => setTab(t),
|
|
812
|
+
style: {
|
|
813
|
+
flex: 1,
|
|
814
|
+
padding: "6px 0",
|
|
815
|
+
border: "none",
|
|
816
|
+
borderRadius: 6,
|
|
817
|
+
background: tab === t ? state.button : "transparent",
|
|
818
|
+
color: tab === t ? fg.strong : fg.default,
|
|
819
|
+
...text.label.xs,
|
|
820
|
+
fontFamily: "inherit",
|
|
821
|
+
cursor: "pointer",
|
|
822
|
+
transition: "background 0.12s ease, color 0.12s ease",
|
|
823
|
+
textTransform: "capitalize"
|
|
824
|
+
},
|
|
825
|
+
children: t
|
|
826
|
+
},
|
|
827
|
+
t
|
|
828
|
+
)) }),
|
|
829
|
+
tab === "gradient" && /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 8, marginTop: 12, paddingBottom: 10, flexWrap: "wrap" }, children: GRADIENT_PRESETS.map((g) => {
|
|
830
|
+
const selected = frameSettings.bgType === "gradient" && frameSettings.bgGradient === g;
|
|
831
|
+
return /* @__PURE__ */ jsx2(
|
|
832
|
+
PresetSwatch,
|
|
833
|
+
{
|
|
834
|
+
background: g,
|
|
835
|
+
selected,
|
|
836
|
+
onClick: () => selectGradient(g)
|
|
837
|
+
},
|
|
838
|
+
g
|
|
839
|
+
);
|
|
840
|
+
}) }),
|
|
841
|
+
tab === "solid" && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
842
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 8, marginTop: 12, paddingBottom: 10, flexWrap: "wrap" }, children: [
|
|
843
|
+
COLOR_PRESETS.map((c) => {
|
|
844
|
+
const selected = frameSettings.bgType === "color" && frameSettings.bgColor === c;
|
|
845
|
+
return /* @__PURE__ */ jsx2(
|
|
846
|
+
PresetSwatch,
|
|
847
|
+
{
|
|
848
|
+
background: c,
|
|
849
|
+
selected,
|
|
850
|
+
onClick: () => selectColor(c)
|
|
851
|
+
},
|
|
852
|
+
c
|
|
853
|
+
);
|
|
854
|
+
}),
|
|
855
|
+
(() => {
|
|
856
|
+
const customColor = frameSettings.bgColor;
|
|
857
|
+
const isCustom = !COLOR_PRESETS.includes(customColor.toUpperCase());
|
|
858
|
+
const bg2 = isCustom ? customColor : "transparent";
|
|
859
|
+
const iconColor = isCustom ? hexLuminance(customColor) > 0.4 ? "rgba(0,0,0,0.5)" : "rgba(255,255,255,0.7)" : fg.sub;
|
|
860
|
+
return /* @__PURE__ */ jsx2(
|
|
861
|
+
"button",
|
|
862
|
+
{
|
|
863
|
+
onClick: async () => {
|
|
864
|
+
if (!("EyeDropper" in window)) return;
|
|
865
|
+
try {
|
|
866
|
+
const result = await new window.EyeDropper().open();
|
|
867
|
+
selectColor(result.sRGBHex);
|
|
868
|
+
} catch {
|
|
869
|
+
}
|
|
870
|
+
},
|
|
871
|
+
style: {
|
|
872
|
+
width: 32,
|
|
873
|
+
height: 32,
|
|
874
|
+
borderRadius: "50%",
|
|
875
|
+
border: isCustom ? `1px solid ${stroke.soft}` : `1px dashed ${stroke.default}`,
|
|
876
|
+
outline: isCustom ? `2px solid ${accent.toggle}` : "none",
|
|
877
|
+
outlineOffset: 1,
|
|
878
|
+
background: bg2,
|
|
879
|
+
cursor: "pointer",
|
|
880
|
+
display: "flex",
|
|
881
|
+
alignItems: "center",
|
|
882
|
+
justifyContent: "center",
|
|
883
|
+
color: iconColor
|
|
884
|
+
},
|
|
885
|
+
children: /* @__PURE__ */ jsx2(Pipette, { size: 14, strokeWidth: 2 })
|
|
886
|
+
}
|
|
887
|
+
);
|
|
888
|
+
})()
|
|
889
|
+
] }),
|
|
890
|
+
/* @__PURE__ */ jsx2("div", { style: { paddingBottom: 4 }, children: /* @__PURE__ */ jsx2(ColorHexInput, { value: frameSettings.bgColor, onChange: selectColor }) })
|
|
724
891
|
] }),
|
|
725
|
-
|
|
726
|
-
/* @__PURE__ */
|
|
892
|
+
tab === "image" && /* @__PURE__ */ jsxs2("div", { style: { marginTop: 12 }, children: [
|
|
893
|
+
/* @__PURE__ */ jsx2(
|
|
727
894
|
"input",
|
|
728
895
|
{
|
|
729
896
|
ref: fileInputRef,
|
|
@@ -733,11 +900,11 @@ function FrameBackgroundControl({
|
|
|
733
900
|
style: { display: "none" }
|
|
734
901
|
}
|
|
735
902
|
),
|
|
736
|
-
bgImage ? /* @__PURE__ */
|
|
737
|
-
/* @__PURE__ */
|
|
903
|
+
frameSettings.bgImage ? /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
904
|
+
/* @__PURE__ */ jsx2(
|
|
738
905
|
"img",
|
|
739
906
|
{
|
|
740
|
-
src: bgImage,
|
|
907
|
+
src: frameSettings.bgImage,
|
|
741
908
|
alt: "",
|
|
742
909
|
style: {
|
|
743
910
|
width: 48,
|
|
@@ -748,224 +915,453 @@ function FrameBackgroundControl({
|
|
|
748
915
|
}
|
|
749
916
|
}
|
|
750
917
|
),
|
|
751
|
-
/* @__PURE__ */
|
|
752
|
-
/* @__PURE__ */
|
|
918
|
+
/* @__PURE__ */ jsxs2(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
|
|
919
|
+
/* @__PURE__ */ jsx2(Upload, { size: 11, strokeWidth: 2 }),
|
|
753
920
|
"Replace"
|
|
754
921
|
] }),
|
|
755
|
-
/* @__PURE__ */
|
|
756
|
-
] }) : /* @__PURE__ */
|
|
757
|
-
/* @__PURE__ */
|
|
922
|
+
/* @__PURE__ */ jsx2(SmallButton, { onClick: () => onFrameSettingsChange({ ...frameSettings, bgImage: null }), children: /* @__PURE__ */ jsx2(Trash2, { size: 11, strokeWidth: 2 }) })
|
|
923
|
+
] }) : /* @__PURE__ */ jsxs2(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
|
|
924
|
+
/* @__PURE__ */ jsx2(Upload, { size: 11, strokeWidth: 2 }),
|
|
758
925
|
"Upload image"
|
|
759
926
|
] })
|
|
927
|
+
] }),
|
|
928
|
+
/* @__PURE__ */ jsxs2("div", { style: { marginTop: 16 }, children: [
|
|
929
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: "Padding" }),
|
|
930
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 8 }, children: [
|
|
931
|
+
/* @__PURE__ */ jsx2(
|
|
932
|
+
SlimSlider,
|
|
933
|
+
{
|
|
934
|
+
min: 0,
|
|
935
|
+
max: 200,
|
|
936
|
+
step: 5,
|
|
937
|
+
value: frameSettings.padding,
|
|
938
|
+
onChange: (v) => onFrameSettingsChange({ ...frameSettings, padding: v })
|
|
939
|
+
}
|
|
940
|
+
),
|
|
941
|
+
/* @__PURE__ */ jsx2(
|
|
942
|
+
PaddingInput,
|
|
943
|
+
{
|
|
944
|
+
value: frameSettings.padding,
|
|
945
|
+
onChange: (n) => onFrameSettingsChange({ ...frameSettings, padding: n })
|
|
946
|
+
}
|
|
947
|
+
)
|
|
948
|
+
] })
|
|
760
949
|
] })
|
|
761
950
|
] });
|
|
762
951
|
}
|
|
763
|
-
function
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
952
|
+
function SlimSlider({
|
|
953
|
+
min,
|
|
954
|
+
max,
|
|
955
|
+
step,
|
|
956
|
+
value,
|
|
957
|
+
onChange
|
|
768
958
|
}) {
|
|
769
|
-
|
|
770
|
-
|
|
959
|
+
const trackRef = useRef(null);
|
|
960
|
+
const pct = (value - min) / (max - min) * 100;
|
|
961
|
+
const update = (clientX) => {
|
|
962
|
+
const rect = trackRef.current.getBoundingClientRect();
|
|
963
|
+
const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
|
964
|
+
const raw = min + ratio * (max - min);
|
|
965
|
+
const snapped = Math.round(raw / step) * step;
|
|
966
|
+
onChange(Math.max(min, Math.min(max, snapped)));
|
|
967
|
+
};
|
|
968
|
+
const onPointerDown = (e) => {
|
|
969
|
+
e.preventDefault();
|
|
970
|
+
e.target.setPointerCapture(e.pointerId);
|
|
971
|
+
update(e.clientX);
|
|
972
|
+
};
|
|
973
|
+
const onPointerMove = (e) => {
|
|
974
|
+
if (e.buttons === 0) return;
|
|
975
|
+
update(e.clientX);
|
|
976
|
+
};
|
|
977
|
+
return /* @__PURE__ */ jsx2(
|
|
978
|
+
"div",
|
|
771
979
|
{
|
|
772
|
-
|
|
980
|
+
ref: trackRef,
|
|
981
|
+
onPointerDown,
|
|
982
|
+
onPointerMove,
|
|
773
983
|
style: {
|
|
984
|
+
flex: 1,
|
|
985
|
+
minWidth: 0,
|
|
986
|
+
height: 20,
|
|
774
987
|
display: "flex",
|
|
775
988
|
alignItems: "center",
|
|
776
|
-
gap: 4,
|
|
777
|
-
height: 28,
|
|
778
|
-
padding: "0 10px",
|
|
779
|
-
border: `1px solid ${stroke.default}`,
|
|
780
|
-
background: active ? state.pressed : state.subtle,
|
|
781
|
-
color: active ? fg.strong : fg.sub,
|
|
782
989
|
cursor: "pointer",
|
|
783
|
-
|
|
784
|
-
fontFamily: "inherit",
|
|
785
|
-
transition: "background 0.12s ease, color 0.12s ease",
|
|
786
|
-
...style2
|
|
990
|
+
touchAction: "none"
|
|
787
991
|
},
|
|
788
|
-
children
|
|
992
|
+
children: /* @__PURE__ */ jsxs2("div", { style: { position: "relative", width: "100%", height: 3, borderRadius: 2, background: stroke.default }, children: [
|
|
993
|
+
/* @__PURE__ */ jsx2("div", { style: { position: "absolute", left: 0, top: 0, height: "100%", width: `${pct}%`, borderRadius: 2, background: fg.sub } }),
|
|
994
|
+
/* @__PURE__ */ jsx2(
|
|
995
|
+
"div",
|
|
996
|
+
{
|
|
997
|
+
style: {
|
|
998
|
+
position: "absolute",
|
|
999
|
+
top: "50%",
|
|
1000
|
+
left: `${pct}%`,
|
|
1001
|
+
width: 10,
|
|
1002
|
+
height: 10,
|
|
1003
|
+
borderRadius: "50%",
|
|
1004
|
+
background: fg.strong,
|
|
1005
|
+
transform: "translate(-50%, -50%)"
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
)
|
|
1009
|
+
] })
|
|
789
1010
|
}
|
|
790
1011
|
);
|
|
791
1012
|
}
|
|
792
|
-
function
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
}) {
|
|
796
|
-
const inputRef = useRef(null);
|
|
797
|
-
return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
|
|
798
|
-
/* @__PURE__ */ jsx(
|
|
799
|
-
"button",
|
|
800
|
-
{
|
|
801
|
-
onClick: () => inputRef.current?.click(),
|
|
802
|
-
style: {
|
|
803
|
-
width: 24,
|
|
804
|
-
height: 24,
|
|
805
|
-
borderRadius: 6,
|
|
806
|
-
border: `1px solid ${stroke.interactive}`,
|
|
807
|
-
background: color,
|
|
808
|
-
cursor: "pointer",
|
|
809
|
-
padding: 0
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
),
|
|
813
|
-
/* @__PURE__ */ jsx(
|
|
814
|
-
"input",
|
|
815
|
-
{
|
|
816
|
-
ref: inputRef,
|
|
817
|
-
type: "color",
|
|
818
|
-
value: color,
|
|
819
|
-
onChange: (e) => onChange(e.target.value),
|
|
820
|
-
style: {
|
|
821
|
-
position: "absolute",
|
|
822
|
-
top: 0,
|
|
823
|
-
left: 0,
|
|
824
|
-
width: 0,
|
|
825
|
-
height: 0,
|
|
826
|
-
opacity: 0,
|
|
827
|
-
pointerEvents: "none"
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
)
|
|
831
|
-
] });
|
|
832
|
-
}
|
|
833
|
-
function SmallButton({
|
|
834
|
-
children,
|
|
1013
|
+
function PresetSwatch({
|
|
1014
|
+
background,
|
|
1015
|
+
selected,
|
|
835
1016
|
onClick
|
|
836
1017
|
}) {
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
"button",
|
|
1018
|
+
return /* @__PURE__ */ jsx2(
|
|
1019
|
+
"div",
|
|
840
1020
|
{
|
|
841
1021
|
onClick,
|
|
842
|
-
onMouseEnter: () => setHovered(true),
|
|
843
|
-
onMouseLeave: () => setHovered(false),
|
|
844
1022
|
style: {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
borderRadius: 6,
|
|
850
|
-
border: `1px solid ${stroke.strong}`,
|
|
851
|
-
background: hovered ? state.hoverStrong : state.button,
|
|
852
|
-
color: fg.default,
|
|
853
|
-
...text.label.xs,
|
|
1023
|
+
width: 32,
|
|
1024
|
+
height: 32,
|
|
1025
|
+
borderRadius: "50%",
|
|
1026
|
+
background,
|
|
854
1027
|
cursor: "pointer",
|
|
855
|
-
|
|
856
|
-
|
|
1028
|
+
border: `1px solid ${stroke.soft}`,
|
|
1029
|
+
outline: selected ? `2px solid ${accent.toggle}` : "none",
|
|
1030
|
+
outlineOffset: 1,
|
|
1031
|
+
position: "relative",
|
|
1032
|
+
transition: "outline-color 0.12s ease",
|
|
1033
|
+
flexShrink: 0
|
|
857
1034
|
},
|
|
858
|
-
children
|
|
1035
|
+
children: selected && /* @__PURE__ */ jsx2(
|
|
1036
|
+
"div",
|
|
1037
|
+
{
|
|
1038
|
+
style: {
|
|
1039
|
+
position: "absolute",
|
|
1040
|
+
inset: 0,
|
|
1041
|
+
borderRadius: "50%",
|
|
1042
|
+
display: "flex",
|
|
1043
|
+
alignItems: "center",
|
|
1044
|
+
justifyContent: "center",
|
|
1045
|
+
background: "rgba(0,0,0,0.2)"
|
|
1046
|
+
},
|
|
1047
|
+
children: /* @__PURE__ */ jsx2(Check, { size: 16, strokeWidth: 3, color: "#fff" })
|
|
1048
|
+
}
|
|
1049
|
+
)
|
|
859
1050
|
}
|
|
860
1051
|
);
|
|
861
1052
|
}
|
|
862
|
-
function
|
|
863
|
-
|
|
864
|
-
|
|
1053
|
+
function hexLuminance(hex) {
|
|
1054
|
+
const n = parseInt(hex.replace("#", ""), 16);
|
|
1055
|
+
const r = (n >> 16 & 255) / 255;
|
|
1056
|
+
const g = (n >> 8 & 255) / 255;
|
|
1057
|
+
const b = (n & 255) / 255;
|
|
1058
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
1059
|
+
}
|
|
1060
|
+
function BrowserFrameSetting({
|
|
1061
|
+
enabled,
|
|
1062
|
+
theme,
|
|
1063
|
+
padding,
|
|
1064
|
+
url,
|
|
1065
|
+
onToggle,
|
|
1066
|
+
onSelect,
|
|
1067
|
+
onPaddingChange,
|
|
1068
|
+
onUrlChange
|
|
865
1069
|
}) {
|
|
866
|
-
const [
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1070
|
+
const trafficLights = /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 4 }, children: ["#FF5F57", "#FEBC2E", "#28C840"].map((c) => /* @__PURE__ */ jsx2("div", { style: { width: 5, height: 5, borderRadius: "50%", background: c } }, c)) });
|
|
1071
|
+
const themes = [
|
|
1072
|
+
{ value: "dark", label: "macOS Dark", titleBar: "#1C1C1C", urlBar: "#262626", border: "#333333" },
|
|
1073
|
+
{ value: "light", label: "macOS Light", titleBar: "#F5F5F5", urlBar: "#FFFFFF", border: "#EBEBEB" }
|
|
1074
|
+
];
|
|
1075
|
+
return /* @__PURE__ */ jsxs2("div", { style: { padding: "14px 0" }, children: [
|
|
1076
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }, children: [
|
|
1077
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
1078
|
+
/* @__PURE__ */ jsx2(AppWindow, { size: 16, strokeWidth: 1.6, color: fg.sub }),
|
|
1079
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: "Browser Frame" })
|
|
1080
|
+
] }),
|
|
1081
|
+
/* @__PURE__ */ jsx2(ToggleSwitch, { enabled, onChange: onToggle })
|
|
1082
|
+
] }),
|
|
1083
|
+
/* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 10, marginTop: 12 }, children: themes.map((t) => {
|
|
1084
|
+
const selected = enabled && theme === t.value;
|
|
1085
|
+
return /* @__PURE__ */ jsxs2(
|
|
1086
|
+
"div",
|
|
1087
|
+
{
|
|
1088
|
+
onClick: () => onSelect(t.value),
|
|
1089
|
+
style: {
|
|
1090
|
+
flex: 1,
|
|
1091
|
+
cursor: "pointer",
|
|
1092
|
+
borderRadius: 10,
|
|
1093
|
+
border: selected ? `2px solid ${accent.toggle}` : `1px solid ${stroke.soft}`,
|
|
1094
|
+
padding: selected ? 7 : 8,
|
|
1095
|
+
position: "relative",
|
|
1096
|
+
background: state.subtle,
|
|
1097
|
+
transition: "border-color 0.12s ease"
|
|
1098
|
+
},
|
|
1099
|
+
children: [
|
|
1100
|
+
/* @__PURE__ */ jsxs2(
|
|
1101
|
+
"div",
|
|
1102
|
+
{
|
|
1103
|
+
style: {
|
|
1104
|
+
background: t.titleBar,
|
|
1105
|
+
borderRadius: 6,
|
|
1106
|
+
overflow: "hidden",
|
|
1107
|
+
border: t.value === "light" ? `1px solid ${t.border}` : "none",
|
|
1108
|
+
display: "flex",
|
|
1109
|
+
alignItems: "center",
|
|
1110
|
+
gap: 6,
|
|
1111
|
+
padding: "6px 8px"
|
|
1112
|
+
},
|
|
1113
|
+
children: [
|
|
1114
|
+
trafficLights,
|
|
1115
|
+
/* @__PURE__ */ jsx2(
|
|
1116
|
+
"div",
|
|
1117
|
+
{
|
|
1118
|
+
style: {
|
|
1119
|
+
flex: 1,
|
|
1120
|
+
height: 8,
|
|
1121
|
+
background: t.urlBar,
|
|
1122
|
+
borderRadius: 2,
|
|
1123
|
+
...t.value === "light" ? { border: `1px solid ${t.border}` } : {}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
)
|
|
1127
|
+
]
|
|
1128
|
+
}
|
|
1129
|
+
),
|
|
1130
|
+
/* @__PURE__ */ jsx2("div", { style: { textAlign: "center", marginTop: 8, ...text.label.xs, color: fg.default }, children: t.label }),
|
|
1131
|
+
selected && /* @__PURE__ */ jsx2(
|
|
1132
|
+
"div",
|
|
1133
|
+
{
|
|
1134
|
+
style: {
|
|
1135
|
+
position: "absolute",
|
|
1136
|
+
top: -5,
|
|
1137
|
+
right: -5,
|
|
1138
|
+
width: 18,
|
|
1139
|
+
height: 18,
|
|
1140
|
+
borderRadius: "50%",
|
|
1141
|
+
background: accent.toggle,
|
|
1142
|
+
display: "flex",
|
|
1143
|
+
alignItems: "center",
|
|
1144
|
+
justifyContent: "center"
|
|
1145
|
+
},
|
|
1146
|
+
children: /* @__PURE__ */ jsx2(Check, { size: 10, strokeWidth: 3, color: "#fff" })
|
|
1147
|
+
}
|
|
1148
|
+
)
|
|
1149
|
+
]
|
|
1150
|
+
},
|
|
1151
|
+
t.value
|
|
1152
|
+
);
|
|
1153
|
+
}) }),
|
|
1154
|
+
/* @__PURE__ */ jsxs2("div", { style: { marginTop: 12 }, children: [
|
|
1155
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: "URL" }),
|
|
1156
|
+
/* @__PURE__ */ jsx2(
|
|
1157
|
+
"div",
|
|
1158
|
+
{
|
|
1159
|
+
style: {
|
|
1160
|
+
display: "flex",
|
|
1161
|
+
alignItems: "center",
|
|
1162
|
+
height: 30,
|
|
1163
|
+
padding: "0 8px",
|
|
1164
|
+
background: state.input,
|
|
1165
|
+
borderRadius: 7,
|
|
1166
|
+
marginTop: 8
|
|
1167
|
+
},
|
|
1168
|
+
children: /* @__PURE__ */ jsx2(
|
|
1169
|
+
"input",
|
|
1170
|
+
{
|
|
1171
|
+
type: "text",
|
|
1172
|
+
value: url,
|
|
1173
|
+
onChange: (e) => onUrlChange(e.target.value),
|
|
1174
|
+
placeholder: "localhost",
|
|
1175
|
+
style: {
|
|
1176
|
+
flex: 1,
|
|
1177
|
+
minWidth: 0,
|
|
1178
|
+
border: "none",
|
|
1179
|
+
background: "transparent",
|
|
1180
|
+
color: fg.strong,
|
|
1181
|
+
...text.label.xs,
|
|
1182
|
+
fontFamily: "inherit",
|
|
1183
|
+
outline: "none",
|
|
1184
|
+
padding: 0
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
)
|
|
890
1188
|
}
|
|
891
|
-
|
|
1189
|
+
)
|
|
1190
|
+
] }),
|
|
1191
|
+
/* @__PURE__ */ jsxs2("div", { style: { marginTop: 12 }, children: [
|
|
1192
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.sm, color: fg.strong }, children: "Padding" }),
|
|
1193
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 8 }, children: [
|
|
1194
|
+
/* @__PURE__ */ jsx2(
|
|
1195
|
+
SlimSlider,
|
|
1196
|
+
{
|
|
1197
|
+
min: 0,
|
|
1198
|
+
max: 200,
|
|
1199
|
+
step: 5,
|
|
1200
|
+
value: padding,
|
|
1201
|
+
onChange: onPaddingChange
|
|
1202
|
+
}
|
|
1203
|
+
),
|
|
1204
|
+
/* @__PURE__ */ jsx2(
|
|
1205
|
+
PaddingInput,
|
|
1206
|
+
{
|
|
1207
|
+
value: padding,
|
|
1208
|
+
onChange: onPaddingChange
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
] })
|
|
1212
|
+
] })
|
|
1213
|
+
] });
|
|
1214
|
+
}
|
|
1215
|
+
function SmallButton({
|
|
1216
|
+
children,
|
|
1217
|
+
onClick
|
|
1218
|
+
}) {
|
|
1219
|
+
const [hovered, setHovered] = useState2(false);
|
|
1220
|
+
return /* @__PURE__ */ jsx2(
|
|
1221
|
+
"button",
|
|
1222
|
+
{
|
|
1223
|
+
onClick,
|
|
1224
|
+
onMouseEnter: () => setHovered(true),
|
|
1225
|
+
onMouseLeave: () => setHovered(false),
|
|
892
1226
|
style: {
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
borderRadius:
|
|
898
|
-
|
|
1227
|
+
display: "flex",
|
|
1228
|
+
alignItems: "center",
|
|
1229
|
+
gap: 4,
|
|
1230
|
+
padding: "4px 10px",
|
|
1231
|
+
borderRadius: 6,
|
|
1232
|
+
border: `1px solid ${stroke.strong}`,
|
|
1233
|
+
background: hovered ? state.hoverStrong : state.button,
|
|
1234
|
+
color: fg.default,
|
|
899
1235
|
...text.label.xs,
|
|
1236
|
+
cursor: "pointer",
|
|
900
1237
|
fontFamily: "inherit",
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1238
|
+
transition: "background 0.12s ease"
|
|
1239
|
+
},
|
|
1240
|
+
children
|
|
904
1241
|
}
|
|
905
1242
|
);
|
|
906
1243
|
}
|
|
907
|
-
function
|
|
1244
|
+
function PaddingInput({
|
|
908
1245
|
value,
|
|
909
1246
|
onChange
|
|
910
1247
|
}) {
|
|
911
1248
|
const [editing, setEditing] = useState2(false);
|
|
912
|
-
const [text2, setText] = useState2(value);
|
|
1249
|
+
const [text2, setText] = useState2(String(value));
|
|
913
1250
|
useEffect(() => {
|
|
914
|
-
if (!editing)
|
|
915
|
-
setText(value);
|
|
916
|
-
}
|
|
1251
|
+
if (!editing) setText(String(value));
|
|
917
1252
|
}, [editing, value]);
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
if (/^#[0-9a-fA-F]{6}$/.test(hex)) {
|
|
921
|
-
onChange(hex);
|
|
922
|
-
}
|
|
923
|
-
};
|
|
924
|
-
return /* @__PURE__ */ jsx(
|
|
925
|
-
"input",
|
|
1253
|
+
return /* @__PURE__ */ jsxs2(
|
|
1254
|
+
"div",
|
|
926
1255
|
{
|
|
927
|
-
type: "text",
|
|
928
|
-
value: editing ? text2 : value,
|
|
929
|
-
onFocus: () => {
|
|
930
|
-
setEditing(true);
|
|
931
|
-
setText(value);
|
|
932
|
-
},
|
|
933
|
-
onBlur: () => {
|
|
934
|
-
setEditing(false);
|
|
935
|
-
commit(text2);
|
|
936
|
-
},
|
|
937
|
-
onChange: (e) => setText(e.target.value),
|
|
938
|
-
onKeyDown: (e) => {
|
|
939
|
-
if (e.key === "Enter") {
|
|
940
|
-
e.target.blur();
|
|
941
|
-
}
|
|
942
|
-
},
|
|
943
1256
|
style: {
|
|
944
|
-
|
|
945
|
-
|
|
1257
|
+
display: "flex",
|
|
1258
|
+
alignItems: "center",
|
|
1259
|
+
height: 30,
|
|
1260
|
+
padding: "0 8px",
|
|
946
1261
|
background: state.input,
|
|
947
|
-
border: `1px solid ${stroke.default}`,
|
|
948
1262
|
borderRadius: 7,
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1263
|
+
flexShrink: 0,
|
|
1264
|
+
width: 68
|
|
1265
|
+
},
|
|
1266
|
+
children: [
|
|
1267
|
+
/* @__PURE__ */ jsx2(
|
|
1268
|
+
"input",
|
|
1269
|
+
{
|
|
1270
|
+
type: "text",
|
|
1271
|
+
value: editing ? text2 : String(value),
|
|
1272
|
+
onFocus: () => {
|
|
1273
|
+
setEditing(true);
|
|
1274
|
+
setText(String(value));
|
|
1275
|
+
},
|
|
1276
|
+
onBlur: () => {
|
|
1277
|
+
setEditing(false);
|
|
1278
|
+
const n = parseInt(text2, 10);
|
|
1279
|
+
if (!Number.isNaN(n) && n >= 0 && n <= 200) onChange(n);
|
|
1280
|
+
},
|
|
1281
|
+
onChange: (e) => setText(e.target.value),
|
|
1282
|
+
onKeyDown: (e) => {
|
|
1283
|
+
if (e.key === "Enter") e.target.blur();
|
|
1284
|
+
},
|
|
1285
|
+
style: {
|
|
1286
|
+
flex: 1,
|
|
1287
|
+
minWidth: 0,
|
|
1288
|
+
border: "none",
|
|
1289
|
+
background: "transparent",
|
|
1290
|
+
color: fg.strong,
|
|
1291
|
+
...text.label.xs,
|
|
1292
|
+
fontFamily: "inherit",
|
|
1293
|
+
textAlign: "left",
|
|
1294
|
+
outline: "none",
|
|
1295
|
+
padding: 0
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
),
|
|
1299
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.xs, color: fg.sub, flexShrink: 0, userSelect: "none", marginLeft: 4 }, children: "px" })
|
|
1300
|
+
]
|
|
955
1301
|
}
|
|
956
1302
|
);
|
|
957
1303
|
}
|
|
958
|
-
function
|
|
959
|
-
|
|
960
|
-
|
|
1304
|
+
function ColorHexInput({
|
|
1305
|
+
value,
|
|
1306
|
+
onChange
|
|
1307
|
+
}) {
|
|
1308
|
+
const [editing, setEditing] = useState2(false);
|
|
1309
|
+
const [text2, setText] = useState2(value.replace("#", ""));
|
|
1310
|
+
useEffect(() => {
|
|
1311
|
+
if (!editing) setText(value.replace("#", ""));
|
|
1312
|
+
}, [editing, value]);
|
|
1313
|
+
const commit = (raw) => {
|
|
1314
|
+
const hex = raw.startsWith("#") ? raw : `#${raw}`;
|
|
1315
|
+
if (/^#[0-9a-fA-F]{6}$/.test(hex)) onChange(hex);
|
|
1316
|
+
};
|
|
1317
|
+
return /* @__PURE__ */ jsxs2(
|
|
1318
|
+
"div",
|
|
961
1319
|
{
|
|
962
1320
|
style: {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1321
|
+
flex: 1,
|
|
1322
|
+
minWidth: 0,
|
|
1323
|
+
display: "flex",
|
|
1324
|
+
alignItems: "center",
|
|
1325
|
+
height: 30,
|
|
1326
|
+
padding: "0 8px",
|
|
1327
|
+
background: state.input,
|
|
1328
|
+
borderRadius: 7,
|
|
1329
|
+
gap: 6
|
|
967
1330
|
},
|
|
968
|
-
children
|
|
1331
|
+
children: [
|
|
1332
|
+
/* @__PURE__ */ jsx2("span", { style: { ...text.label.xs, color: fg.sub, flexShrink: 0, userSelect: "none" }, children: "#" }),
|
|
1333
|
+
/* @__PURE__ */ jsx2(
|
|
1334
|
+
"input",
|
|
1335
|
+
{
|
|
1336
|
+
type: "text",
|
|
1337
|
+
value: editing ? text2 : value.replace("#", ""),
|
|
1338
|
+
onFocus: () => {
|
|
1339
|
+
setEditing(true);
|
|
1340
|
+
setText(value.replace("#", ""));
|
|
1341
|
+
},
|
|
1342
|
+
onBlur: () => {
|
|
1343
|
+
setEditing(false);
|
|
1344
|
+
commit(text2);
|
|
1345
|
+
},
|
|
1346
|
+
onChange: (e) => setText(e.target.value),
|
|
1347
|
+
onKeyDown: (e) => {
|
|
1348
|
+
if (e.key === "Enter") e.target.blur();
|
|
1349
|
+
},
|
|
1350
|
+
style: {
|
|
1351
|
+
flex: 1,
|
|
1352
|
+
minWidth: 0,
|
|
1353
|
+
border: "none",
|
|
1354
|
+
background: "transparent",
|
|
1355
|
+
color: fg.strong,
|
|
1356
|
+
...text.label.xs,
|
|
1357
|
+
fontFamily: "inherit",
|
|
1358
|
+
textAlign: "left",
|
|
1359
|
+
outline: "none",
|
|
1360
|
+
padding: 0
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
)
|
|
1364
|
+
]
|
|
969
1365
|
}
|
|
970
1366
|
);
|
|
971
1367
|
}
|
|
@@ -974,7 +1370,7 @@ function DropItem({
|
|
|
974
1370
|
onClick,
|
|
975
1371
|
active
|
|
976
1372
|
}) {
|
|
977
|
-
return /* @__PURE__ */
|
|
1373
|
+
return /* @__PURE__ */ jsx2(
|
|
978
1374
|
"button",
|
|
979
1375
|
{
|
|
980
1376
|
onClick,
|
|
@@ -1011,641 +1407,126 @@ async function downscaleImage(dataUrl, maxW, maxH) {
|
|
|
1011
1407
|
});
|
|
1012
1408
|
}
|
|
1013
1409
|
|
|
1014
|
-
// src/overlay/ui/
|
|
1015
|
-
import { Fragment as Fragment2, jsx as
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
return { x: vw - EDGE_MARGIN - w, y: vh - EDGE_MARGIN - h };
|
|
1050
|
-
case "bottom-left":
|
|
1051
|
-
return { x: EDGE_MARGIN, y: vh - EDGE_MARGIN - h };
|
|
1052
|
-
case "top-right":
|
|
1053
|
-
return { x: vw - EDGE_MARGIN - w, y: EDGE_MARGIN };
|
|
1054
|
-
case "top-left":
|
|
1055
|
-
return { x: EDGE_MARGIN, y: EDGE_MARGIN };
|
|
1056
|
-
}
|
|
1410
|
+
// src/overlay/ui/screenshots-panel.tsx
|
|
1411
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1412
|
+
function BrowserChromeBar({ theme, url = "localhost" }) {
|
|
1413
|
+
const colors = theme === "dark" ? { titleBar: "#1C1C1C", urlBar: "#262626", text: "#7B7B7B", border: "#333333" } : { titleBar: "#F5F5F5", urlBar: "#FFFFFF", text: "#999999", border: "#EBEBEB" };
|
|
1414
|
+
return /* @__PURE__ */ jsx3("div", { style: { background: colors.titleBar, flexShrink: 0, padding: "4px 6px" }, children: /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 6, height: 14 }, children: [
|
|
1415
|
+
/* @__PURE__ */ jsx3("div", { style: { display: "flex", gap: 5, flexShrink: 0 }, children: ["#FF5F57", "#FEBC2E", "#28C840"].map((c) => /* @__PURE__ */ jsx3("div", { style: { width: 6, height: 6, borderRadius: "50%", background: c } }, c)) }),
|
|
1416
|
+
/* @__PURE__ */ jsx3(
|
|
1417
|
+
"div",
|
|
1418
|
+
{
|
|
1419
|
+
style: {
|
|
1420
|
+
flex: 1,
|
|
1421
|
+
height: 14,
|
|
1422
|
+
background: colors.urlBar,
|
|
1423
|
+
borderRadius: 3,
|
|
1424
|
+
display: "flex",
|
|
1425
|
+
alignItems: "center",
|
|
1426
|
+
paddingLeft: 6,
|
|
1427
|
+
...theme === "light" ? { border: `1px solid ${colors.border}` } : {},
|
|
1428
|
+
boxSizing: "border-box"
|
|
1429
|
+
},
|
|
1430
|
+
children: /* @__PURE__ */ jsx3(
|
|
1431
|
+
"span",
|
|
1432
|
+
{
|
|
1433
|
+
style: {
|
|
1434
|
+
fontSize: 7,
|
|
1435
|
+
lineHeight: 1,
|
|
1436
|
+
color: colors.text,
|
|
1437
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
|
|
1438
|
+
},
|
|
1439
|
+
children: url
|
|
1440
|
+
}
|
|
1441
|
+
)
|
|
1442
|
+
}
|
|
1443
|
+
)
|
|
1444
|
+
] }) });
|
|
1057
1445
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
{ mode: "viewport", label: "Viewport", icon: Monitor },
|
|
1061
|
-
{ mode: "fullpage", label: "Full Page", icon: FileText }
|
|
1062
|
-
];
|
|
1063
|
-
function Toolbar({
|
|
1064
|
-
expanded,
|
|
1065
|
-
onToggle,
|
|
1066
|
-
phase,
|
|
1067
|
-
loading,
|
|
1068
|
-
selectedMode,
|
|
1069
|
-
onModeChange,
|
|
1070
|
-
onCapture,
|
|
1071
|
-
onCancel,
|
|
1446
|
+
function FramePreview({
|
|
1447
|
+
previewUrl,
|
|
1072
1448
|
frameSettings,
|
|
1073
|
-
|
|
1449
|
+
loading
|
|
1074
1450
|
}) {
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1077
|
-
const
|
|
1078
|
-
const
|
|
1079
|
-
const
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
return () => clearTimeout(timer);
|
|
1090
|
-
} else if (buttonsVisible) {
|
|
1091
|
-
setHistoryOpen(false);
|
|
1092
|
-
setAnimDone(false);
|
|
1093
|
-
setAnimIn(false);
|
|
1094
|
-
const timer = setTimeout(() => setButtonsVisible(false), 150);
|
|
1095
|
-
return () => clearTimeout(timer);
|
|
1096
|
-
}
|
|
1097
|
-
}, [expanded]);
|
|
1098
|
-
const [corner, setCorner] = useState3(() => {
|
|
1099
|
-
try {
|
|
1100
|
-
const stored = localStorage.getItem("ab-toolbar-corner");
|
|
1101
|
-
if (stored && ["bottom-right", "bottom-left", "top-right", "top-left"].includes(stored)) {
|
|
1102
|
-
return stored;
|
|
1103
|
-
}
|
|
1104
|
-
} catch {
|
|
1105
|
-
}
|
|
1106
|
-
return "bottom-right";
|
|
1107
|
-
});
|
|
1108
|
-
const [dragging, setDragging] = useState3(false);
|
|
1109
|
-
const [dragPos, setDragPos] = useState3(null);
|
|
1110
|
-
const [snapAnim, setSnapAnim] = useState3(null);
|
|
1111
|
-
const dragState = useRef2(null);
|
|
1112
|
-
const toolbarRef = useRef2(null);
|
|
1113
|
-
const [cameraHovered, setCameraHovered] = useState3(false);
|
|
1114
|
-
useEffect2(() => {
|
|
1115
|
-
if (!expanded) return;
|
|
1116
|
-
const onKey = (e) => {
|
|
1117
|
-
if (e.target?.tagName === "INPUT") {
|
|
1118
|
-
if (e.key === "Escape") {
|
|
1119
|
-
e.target.blur();
|
|
1120
|
-
}
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
if (e.key === "Escape") {
|
|
1124
|
-
if (historyOpen) {
|
|
1125
|
-
setHistoryOpen(false);
|
|
1126
|
-
return;
|
|
1127
|
-
}
|
|
1128
|
-
onCancel();
|
|
1129
|
-
} else if (e.key === "Enter") {
|
|
1130
|
-
onCapture(selectedMode);
|
|
1131
|
-
}
|
|
1132
|
-
};
|
|
1133
|
-
document.addEventListener("keydown", onKey);
|
|
1134
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
1135
|
-
}, [expanded, onCancel, onCapture, selectedMode, historyOpen]);
|
|
1136
|
-
const handleMouseDown = useCallback2(
|
|
1137
|
-
(e) => {
|
|
1138
|
-
e.preventDefault();
|
|
1139
|
-
const el = toolbarRef.current;
|
|
1140
|
-
if (!el) return;
|
|
1141
|
-
const rect = el.getBoundingClientRect();
|
|
1142
|
-
setDragging(true);
|
|
1143
|
-
setDragPos({ x: rect.left, y: rect.top });
|
|
1144
|
-
dragState.current = {
|
|
1145
|
-
dragging: true,
|
|
1146
|
-
startX: e.clientX,
|
|
1147
|
-
startY: e.clientY,
|
|
1148
|
-
origX: rect.left,
|
|
1149
|
-
origY: rect.top,
|
|
1150
|
-
distance: 0
|
|
1151
|
-
};
|
|
1152
|
-
},
|
|
1153
|
-
[]
|
|
1154
|
-
);
|
|
1155
|
-
useEffect2(() => {
|
|
1156
|
-
const handleMouseMove = (e) => {
|
|
1157
|
-
const ds = dragState.current;
|
|
1158
|
-
if (!ds || !ds.dragging) return;
|
|
1159
|
-
const dx = e.clientX - ds.startX;
|
|
1160
|
-
const dy = e.clientY - ds.startY;
|
|
1161
|
-
ds.distance = Math.sqrt(dx * dx + dy * dy);
|
|
1162
|
-
setDragPos({
|
|
1163
|
-
x: ds.origX + dx,
|
|
1164
|
-
y: ds.origY + dy
|
|
1165
|
-
});
|
|
1166
|
-
};
|
|
1167
|
-
const handleMouseUp = (e) => {
|
|
1168
|
-
const ds = dragState.current;
|
|
1169
|
-
if (!ds) return;
|
|
1170
|
-
if (ds.distance < 5) {
|
|
1171
|
-
onToggle();
|
|
1172
|
-
setDragging(false);
|
|
1173
|
-
setDragPos(null);
|
|
1174
|
-
dragState.current = null;
|
|
1175
|
-
} else {
|
|
1176
|
-
const el = toolbarRef.current;
|
|
1177
|
-
const w = el?.offsetWidth ?? CONTAINER_SIZE;
|
|
1178
|
-
const h = el?.offsetHeight ?? CONTAINER_SIZE;
|
|
1179
|
-
const currentX = ds.origX + (e.clientX - ds.startX);
|
|
1180
|
-
const currentY = ds.origY + (e.clientY - ds.startY);
|
|
1181
|
-
const centerX = currentX + w / 2;
|
|
1182
|
-
const centerY = currentY + h / 2;
|
|
1183
|
-
const newCorner = snapToCorner(centerX, centerY);
|
|
1184
|
-
setCorner(newCorner);
|
|
1185
|
-
try {
|
|
1186
|
-
localStorage.setItem("ab-toolbar-corner", newCorner);
|
|
1187
|
-
} catch {
|
|
1188
|
-
}
|
|
1189
|
-
const targetPos = getCornerPosition(newCorner, w, h);
|
|
1190
|
-
setDragging(false);
|
|
1191
|
-
setDragPos(null);
|
|
1192
|
-
setSnapAnim({ x: currentX, y: currentY, animate: false });
|
|
1193
|
-
dragState.current = null;
|
|
1194
|
-
requestAnimationFrame(() => {
|
|
1195
|
-
requestAnimationFrame(() => {
|
|
1196
|
-
setSnapAnim({ ...targetPos, animate: true });
|
|
1197
|
-
setTimeout(() => setSnapAnim(null), 300);
|
|
1198
|
-
});
|
|
1199
|
-
});
|
|
1451
|
+
const { enabled: frameEnabled, browserChrome, browserTheme, browserUrl, size, bgType, bgColor, bgGradient, bgImage, padding, browserPadding = 20 } = frameSettings;
|
|
1452
|
+
const aspectRatio = frameEnabled ? `${size.w} / ${size.h}` : "16 / 10";
|
|
1453
|
+
const outerBg = frameEnabled ? bgType === "image" && bgImage ? { backgroundImage: `url(${bgImage})`, backgroundSize: "cover", backgroundPosition: "center" } : bgType === "gradient" ? { background: bgGradient } : { background: bgColor } : { background: bg.elevated };
|
|
1454
|
+
const emptyState = /* @__PURE__ */ jsx3("span", { style: { ...text.paragraph.xs, color: fg.sub }, children: loading ? "Loading..." : "No screenshots yet" });
|
|
1455
|
+
const imageEl = previewUrl ? /* @__PURE__ */ jsx3(
|
|
1456
|
+
"img",
|
|
1457
|
+
{
|
|
1458
|
+
src: previewUrl,
|
|
1459
|
+
alt: "",
|
|
1460
|
+
style: {
|
|
1461
|
+
maxWidth: "100%",
|
|
1462
|
+
maxHeight: "100%",
|
|
1463
|
+
objectFit: "contain",
|
|
1464
|
+
display: "block"
|
|
1200
1465
|
}
|
|
1201
|
-
};
|
|
1202
|
-
window.addEventListener("mousemove", handleMouseMove);
|
|
1203
|
-
window.addEventListener("mouseup", handleMouseUp);
|
|
1204
|
-
return () => {
|
|
1205
|
-
window.removeEventListener("mousemove", handleMouseMove);
|
|
1206
|
-
window.removeEventListener("mouseup", handleMouseUp);
|
|
1207
|
-
};
|
|
1208
|
-
}, [onToggle]);
|
|
1209
|
-
const panelSide = isRightCorner(corner) ? "left" : "right";
|
|
1210
|
-
const tooltipSide = panelSide;
|
|
1211
|
-
const bottom = isBottomCorner(corner);
|
|
1212
|
-
const positionStyle = dragging && dragPos ? { left: dragPos.x, top: dragPos.y } : snapAnim ? {
|
|
1213
|
-
left: snapAnim.x,
|
|
1214
|
-
top: snapAnim.y,
|
|
1215
|
-
...snapAnim.animate && {
|
|
1216
|
-
transition: "left 0.3s cubic-bezier(0.23, 1, 0.32, 1), top 0.3s cubic-bezier(0.23, 1, 0.32, 1)"
|
|
1217
1466
|
}
|
|
1218
|
-
|
|
1219
|
-
const
|
|
1220
|
-
|
|
1221
|
-
const cameraButton = /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
1222
|
-
cameraTooltipLabel && cameraHovered && !dragging && /* @__PURE__ */ jsx2(
|
|
1223
|
-
"div",
|
|
1224
|
-
{
|
|
1225
|
-
style: {
|
|
1226
|
-
position: "absolute",
|
|
1227
|
-
...cameraTooltipStyle,
|
|
1228
|
-
background: bg.base,
|
|
1229
|
-
border: `1px solid ${stroke.default}`,
|
|
1230
|
-
borderRadius: 6,
|
|
1231
|
-
padding: "0 8px",
|
|
1232
|
-
height: 24,
|
|
1233
|
-
display: "flex",
|
|
1234
|
-
alignItems: "center",
|
|
1235
|
-
color: fg.strong,
|
|
1236
|
-
...text.label.xs,
|
|
1237
|
-
whiteSpace: "nowrap",
|
|
1238
|
-
boxShadow: shadow.tooltip,
|
|
1239
|
-
pointerEvents: "none"
|
|
1240
|
-
},
|
|
1241
|
-
children: cameraTooltipLabel
|
|
1242
|
-
}
|
|
1243
|
-
),
|
|
1244
|
-
/* @__PURE__ */ jsxs2(
|
|
1245
|
-
"div",
|
|
1246
|
-
{
|
|
1247
|
-
onMouseDown: handleMouseDown,
|
|
1248
|
-
onMouseEnter: () => setCameraHovered(true),
|
|
1249
|
-
onMouseLeave: () => setCameraHovered(false),
|
|
1250
|
-
style: {
|
|
1251
|
-
width: 32,
|
|
1252
|
-
height: 32,
|
|
1253
|
-
padding: 0,
|
|
1254
|
-
borderRadius: "50%",
|
|
1255
|
-
display: "flex",
|
|
1256
|
-
alignItems: "center",
|
|
1257
|
-
justifyContent: "center",
|
|
1258
|
-
cursor: dragging ? "grabbing" : "pointer",
|
|
1259
|
-
background: expanded && cameraHovered ? state.hoverStrong : "transparent",
|
|
1260
|
-
transition: "background 0.12s ease"
|
|
1261
|
-
},
|
|
1262
|
-
children: [
|
|
1263
|
-
/* @__PURE__ */ jsx2(
|
|
1264
|
-
"style",
|
|
1265
|
-
{
|
|
1266
|
-
dangerouslySetInnerHTML: {
|
|
1267
|
-
__html: `
|
|
1268
|
-
@keyframes ab-spin {
|
|
1269
|
-
0% { transform: rotate(0deg); }
|
|
1270
|
-
100% { transform: rotate(360deg); }
|
|
1271
|
-
}
|
|
1272
|
-
@keyframes ab-panel-in {
|
|
1273
|
-
from { opacity: 0; transform: translateY(4px); }
|
|
1274
|
-
to { opacity: 1; transform: translateY(0); }
|
|
1275
|
-
}
|
|
1276
|
-
`
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
),
|
|
1280
|
-
loading ? /* @__PURE__ */ jsx2(
|
|
1281
|
-
LoaderCircle,
|
|
1282
|
-
{
|
|
1283
|
-
size: 16,
|
|
1284
|
-
strokeWidth: 2,
|
|
1285
|
-
style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
|
|
1286
|
-
}
|
|
1287
|
-
) : phase === "ready" ? /* @__PURE__ */ jsx2(Check, { size: 16, strokeWidth: 2.6, color: accent.check }) : expanded ? /* @__PURE__ */ jsx2(
|
|
1288
|
-
X2,
|
|
1289
|
-
{
|
|
1290
|
-
size: 16,
|
|
1291
|
-
strokeWidth: 1.7,
|
|
1292
|
-
color: cameraHovered ? fg.strong : fg.sub
|
|
1293
|
-
}
|
|
1294
|
-
) : /* @__PURE__ */ jsx2(
|
|
1295
|
-
Camera,
|
|
1296
|
-
{
|
|
1297
|
-
size: 16,
|
|
1298
|
-
strokeWidth: 1.9,
|
|
1299
|
-
color: fg.sub
|
|
1300
|
-
}
|
|
1301
|
-
)
|
|
1302
|
-
]
|
|
1303
|
-
}
|
|
1304
|
-
)
|
|
1305
|
-
] });
|
|
1306
|
-
const toolbarButtons = buttonsVisible ? /* @__PURE__ */ jsx2(
|
|
1467
|
+
) : null;
|
|
1468
|
+
const padPct = frameEnabled ? `${(browserChrome ? browserPadding : padding) / size.h * 100}%` : void 0;
|
|
1469
|
+
return /* @__PURE__ */ jsx3(
|
|
1307
1470
|
"div",
|
|
1308
1471
|
{
|
|
1309
1472
|
style: {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1473
|
+
width: "100%",
|
|
1474
|
+
aspectRatio,
|
|
1475
|
+
borderRadius: 10,
|
|
1476
|
+
overflow: "hidden",
|
|
1477
|
+
border: `1px solid ${stroke.soft}`,
|
|
1478
|
+
marginBottom: 10,
|
|
1479
|
+
display: "flex",
|
|
1480
|
+
flexDirection: "column",
|
|
1481
|
+
...outerBg,
|
|
1482
|
+
...browserChrome && padPct ? { padding: padPct } : {}
|
|
1313
1483
|
},
|
|
1314
|
-
children: /* @__PURE__ */
|
|
1484
|
+
children: browserChrome ? /* @__PURE__ */ jsxs3("div", { style: { flex: 1, display: "flex", flexDirection: "column", borderRadius: 8, overflow: "hidden", minHeight: 0 }, children: [
|
|
1485
|
+
/* @__PURE__ */ jsx3(BrowserChromeBar, { theme: browserTheme, url: browserUrl }),
|
|
1486
|
+
/* @__PURE__ */ jsx3(
|
|
1487
|
+
"div",
|
|
1488
|
+
{
|
|
1489
|
+
style: {
|
|
1490
|
+
flex: 1,
|
|
1491
|
+
display: "flex",
|
|
1492
|
+
alignItems: "center",
|
|
1493
|
+
justifyContent: "center",
|
|
1494
|
+
minHeight: 0
|
|
1495
|
+
},
|
|
1496
|
+
children: imageEl || emptyState
|
|
1497
|
+
}
|
|
1498
|
+
)
|
|
1499
|
+
] }) : /* @__PURE__ */ jsx3(
|
|
1315
1500
|
"div",
|
|
1316
1501
|
{
|
|
1317
1502
|
style: {
|
|
1503
|
+
flex: 1,
|
|
1318
1504
|
display: "flex",
|
|
1319
|
-
flexDirection: "column",
|
|
1320
1505
|
alignItems: "center",
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
willChange: "transform, opacity"
|
|
1506
|
+
justifyContent: "center",
|
|
1507
|
+
minHeight: 0,
|
|
1508
|
+
...padPct ? { padding: padPct } : {}
|
|
1325
1509
|
},
|
|
1326
|
-
children:
|
|
1327
|
-
/* @__PURE__ */ jsx2("div", { style: { paddingBottom: 2 }, children: /* @__PURE__ */ jsx2(
|
|
1328
|
-
IconButton,
|
|
1329
|
-
{
|
|
1330
|
-
active: selectedMode === "component" && !historyOpen,
|
|
1331
|
-
tooltipSide,
|
|
1332
|
-
tooltip: "Component",
|
|
1333
|
-
onClick: () => {
|
|
1334
|
-
setHistoryOpen(false);
|
|
1335
|
-
onModeChange("component");
|
|
1336
|
-
},
|
|
1337
|
-
children: /* @__PURE__ */ jsx2(MousePointer2, { size: 16, strokeWidth: 1.7 })
|
|
1338
|
-
}
|
|
1339
|
-
) }),
|
|
1340
|
-
MODES.filter((m) => m.mode !== "component").map(({ mode, label, icon: ModeIcon }) => /* @__PURE__ */ jsx2(
|
|
1341
|
-
"div",
|
|
1342
|
-
{
|
|
1343
|
-
style: {
|
|
1344
|
-
maxHeight: modesExpanded ? 34 : 0,
|
|
1345
|
-
opacity: modesExpanded ? 1 : 0,
|
|
1346
|
-
transition: "max-height 200ms cubic-bezier(0.23, 1, 0.32, 1), opacity 150ms cubic-bezier(0.23, 1, 0.32, 1)"
|
|
1347
|
-
},
|
|
1348
|
-
children: /* @__PURE__ */ jsx2(
|
|
1349
|
-
IconButton,
|
|
1350
|
-
{
|
|
1351
|
-
active: selectedMode === mode && !historyOpen,
|
|
1352
|
-
tooltipSide,
|
|
1353
|
-
tooltip: label,
|
|
1354
|
-
onClick: () => {
|
|
1355
|
-
setHistoryOpen(false);
|
|
1356
|
-
onModeChange(mode);
|
|
1357
|
-
onCapture(mode);
|
|
1358
|
-
},
|
|
1359
|
-
children: /* @__PURE__ */ jsx2(ModeIcon, { size: 16, strokeWidth: 1.7 })
|
|
1360
|
-
}
|
|
1361
|
-
)
|
|
1362
|
-
},
|
|
1363
|
-
mode
|
|
1364
|
-
)),
|
|
1365
|
-
/* @__PURE__ */ jsx2(
|
|
1366
|
-
Separator,
|
|
1367
|
-
{
|
|
1368
|
-
vertical: false,
|
|
1369
|
-
onClick: () => setModesExpanded((p) => !p)
|
|
1370
|
-
}
|
|
1371
|
-
),
|
|
1372
|
-
/* @__PURE__ */ jsx2(
|
|
1373
|
-
HistoryButton,
|
|
1374
|
-
{
|
|
1375
|
-
open: historyOpen,
|
|
1376
|
-
onClick: () => {
|
|
1377
|
-
setHistoryOpen((prev) => !prev);
|
|
1378
|
-
},
|
|
1379
|
-
selectedMode,
|
|
1380
|
-
frameSettings,
|
|
1381
|
-
onFrameSettingsChange,
|
|
1382
|
-
tooltipSide
|
|
1383
|
-
}
|
|
1384
|
-
)
|
|
1385
|
-
]
|
|
1510
|
+
children: imageEl || emptyState
|
|
1386
1511
|
}
|
|
1387
1512
|
)
|
|
1388
1513
|
}
|
|
1389
|
-
) : null;
|
|
1390
|
-
return /* @__PURE__ */ jsx2(
|
|
1391
|
-
"div",
|
|
1392
|
-
{
|
|
1393
|
-
ref: toolbarRef,
|
|
1394
|
-
"data-afterbefore": "true",
|
|
1395
|
-
style: {
|
|
1396
|
-
position: "fixed",
|
|
1397
|
-
...positionStyle,
|
|
1398
|
-
zIndex: 2147483647,
|
|
1399
|
-
display: "flex",
|
|
1400
|
-
flexDirection: "column",
|
|
1401
|
-
alignItems: "center",
|
|
1402
|
-
background: bg.base,
|
|
1403
|
-
borderRadius: 999,
|
|
1404
|
-
padding: 6,
|
|
1405
|
-
boxShadow: shadow.toolbar,
|
|
1406
|
-
...fontBase,
|
|
1407
|
-
userSelect: "none"
|
|
1408
|
-
},
|
|
1409
|
-
children: bottom ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1410
|
-
toolbarButtons,
|
|
1411
|
-
cameraButton
|
|
1412
|
-
] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1413
|
-
cameraButton,
|
|
1414
|
-
toolbarButtons
|
|
1415
|
-
] })
|
|
1416
|
-
}
|
|
1417
|
-
);
|
|
1418
|
-
}
|
|
1419
|
-
function IconButton({
|
|
1420
|
-
children,
|
|
1421
|
-
active,
|
|
1422
|
-
tooltip,
|
|
1423
|
-
tooltipSide = "left",
|
|
1424
|
-
onClick
|
|
1425
|
-
}) {
|
|
1426
|
-
const [hovered, setHovered] = useState3(false);
|
|
1427
|
-
const tooltipStyle = tooltipSide === "left" ? {
|
|
1428
|
-
right: "calc(100% + 10px)",
|
|
1429
|
-
top: "50%",
|
|
1430
|
-
transform: "translateY(-50%)"
|
|
1431
|
-
} : {
|
|
1432
|
-
left: "calc(100% + 10px)",
|
|
1433
|
-
top: "50%",
|
|
1434
|
-
transform: "translateY(-50%)"
|
|
1435
|
-
};
|
|
1436
|
-
return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
1437
|
-
tooltip && hovered && /* @__PURE__ */ jsx2(
|
|
1438
|
-
"div",
|
|
1439
|
-
{
|
|
1440
|
-
style: {
|
|
1441
|
-
position: "absolute",
|
|
1442
|
-
...tooltipStyle,
|
|
1443
|
-
background: bg.base,
|
|
1444
|
-
border: `1px solid ${stroke.default}`,
|
|
1445
|
-
borderRadius: 6,
|
|
1446
|
-
padding: "0 8px",
|
|
1447
|
-
height: 24,
|
|
1448
|
-
display: "flex",
|
|
1449
|
-
alignItems: "center",
|
|
1450
|
-
color: fg.strong,
|
|
1451
|
-
...text.label.xs,
|
|
1452
|
-
whiteSpace: "nowrap",
|
|
1453
|
-
boxShadow: shadow.tooltip,
|
|
1454
|
-
pointerEvents: "none"
|
|
1455
|
-
},
|
|
1456
|
-
children: tooltip
|
|
1457
|
-
}
|
|
1458
|
-
),
|
|
1459
|
-
/* @__PURE__ */ jsx2(
|
|
1460
|
-
"button",
|
|
1461
|
-
{
|
|
1462
|
-
onClick,
|
|
1463
|
-
onMouseEnter: () => setHovered(true),
|
|
1464
|
-
onMouseLeave: () => setHovered(false),
|
|
1465
|
-
style: {
|
|
1466
|
-
width: 32,
|
|
1467
|
-
height: 32,
|
|
1468
|
-
borderRadius: "50%",
|
|
1469
|
-
border: "none",
|
|
1470
|
-
background: active || hovered ? state.hoverStrong : "transparent",
|
|
1471
|
-
display: "flex",
|
|
1472
|
-
alignItems: "center",
|
|
1473
|
-
justifyContent: "center",
|
|
1474
|
-
cursor: "pointer",
|
|
1475
|
-
padding: 0,
|
|
1476
|
-
color: active || hovered ? fg.strong : fg.sub,
|
|
1477
|
-
transition: "background 0.12s ease, color 0.12s ease"
|
|
1478
|
-
},
|
|
1479
|
-
children
|
|
1480
|
-
}
|
|
1481
|
-
)
|
|
1482
|
-
] });
|
|
1483
|
-
}
|
|
1484
|
-
function DropItem2({
|
|
1485
|
-
children,
|
|
1486
|
-
onClick,
|
|
1487
|
-
active,
|
|
1488
|
-
accent: accent2
|
|
1489
|
-
}) {
|
|
1490
|
-
return /* @__PURE__ */ jsx2(
|
|
1491
|
-
"button",
|
|
1492
|
-
{
|
|
1493
|
-
onClick,
|
|
1494
|
-
style: {
|
|
1495
|
-
display: "block",
|
|
1496
|
-
width: "100%",
|
|
1497
|
-
padding: "7px 12px",
|
|
1498
|
-
background: active ? state.active : "transparent",
|
|
1499
|
-
border: "none",
|
|
1500
|
-
color: accent2 ? accent.highlight : fg.strong,
|
|
1501
|
-
textAlign: "left",
|
|
1502
|
-
cursor: "pointer",
|
|
1503
|
-
...text.paragraph.sm,
|
|
1504
|
-
fontFamily: "inherit"
|
|
1505
|
-
},
|
|
1506
|
-
children
|
|
1507
|
-
}
|
|
1508
|
-
);
|
|
1509
|
-
}
|
|
1510
|
-
function Separator({
|
|
1511
|
-
vertical = true,
|
|
1512
|
-
onClick
|
|
1513
|
-
}) {
|
|
1514
|
-
return /* @__PURE__ */ jsx2(
|
|
1515
|
-
"div",
|
|
1516
|
-
{
|
|
1517
|
-
onClick,
|
|
1518
|
-
style: {
|
|
1519
|
-
position: "relative",
|
|
1520
|
-
width: vertical ? 1 : 24,
|
|
1521
|
-
height: vertical ? 18 : 1,
|
|
1522
|
-
background: stroke.strong,
|
|
1523
|
-
flexShrink: 0,
|
|
1524
|
-
margin: vertical ? "0 6px" : "6px 0",
|
|
1525
|
-
cursor: onClick ? "pointer" : void 0
|
|
1526
|
-
},
|
|
1527
|
-
children: onClick && /* @__PURE__ */ jsx2("div", { style: { position: "absolute", inset: vertical ? "0 -8px" : "-8px 0" } })
|
|
1528
|
-
}
|
|
1529
1514
|
);
|
|
1530
1515
|
}
|
|
1531
|
-
function
|
|
1532
|
-
const
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
...theme === "light" ? { border: `1px solid ${colors.border}` } : {}
|
|
1544
|
-
},
|
|
1545
|
-
children: /* @__PURE__ */ jsx2(
|
|
1546
|
-
"span",
|
|
1547
|
-
{
|
|
1548
|
-
style: {
|
|
1549
|
-
fontSize: 7,
|
|
1550
|
-
color: colors.text,
|
|
1551
|
-
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
|
|
1552
|
-
},
|
|
1553
|
-
children: "localhost"
|
|
1554
|
-
}
|
|
1555
|
-
)
|
|
1556
|
-
}
|
|
1557
|
-
) }),
|
|
1558
|
-
/* @__PURE__ */ jsx2("div", { style: { height: 1, background: colors.border } })
|
|
1559
|
-
] });
|
|
1560
|
-
}
|
|
1561
|
-
function FramePreview({
|
|
1562
|
-
previewUrl,
|
|
1563
|
-
frameSettings,
|
|
1564
|
-
loading,
|
|
1565
|
-
onClickLightbox
|
|
1566
|
-
}) {
|
|
1567
|
-
const { enabled: frameEnabled, browserChrome, browserTheme, size, bgType, bgColor, bgImage, padding } = frameSettings;
|
|
1568
|
-
const aspectRatio = frameEnabled ? `${size.w} / ${size.h}` : "16 / 10";
|
|
1569
|
-
const outerBg = frameEnabled ? bgType === "image" && bgImage ? { backgroundImage: `url(${bgImage})`, backgroundSize: "cover", backgroundPosition: "center" } : { background: bgColor } : { background: bg.elevated };
|
|
1570
|
-
const paddingPct = frameEnabled ? `${padding / size.w * 100}%` : void 0;
|
|
1571
|
-
const emptyState = /* @__PURE__ */ jsx2("span", { style: { ...text.paragraph.xs, color: fg.faint }, children: loading ? "Loading..." : "No screenshots yet" });
|
|
1572
|
-
const imageEl = previewUrl ? /* @__PURE__ */ jsx2(
|
|
1573
|
-
"img",
|
|
1574
|
-
{
|
|
1575
|
-
src: previewUrl,
|
|
1576
|
-
alt: "",
|
|
1577
|
-
style: {
|
|
1578
|
-
maxWidth: "100%",
|
|
1579
|
-
maxHeight: "100%",
|
|
1580
|
-
objectFit: "contain",
|
|
1581
|
-
display: "block"
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
) : null;
|
|
1585
|
-
return /* @__PURE__ */ jsx2(
|
|
1586
|
-
"div",
|
|
1587
|
-
{
|
|
1588
|
-
onClick: onClickLightbox,
|
|
1589
|
-
style: {
|
|
1590
|
-
width: "100%",
|
|
1591
|
-
aspectRatio,
|
|
1592
|
-
borderRadius: 10,
|
|
1593
|
-
overflow: "hidden",
|
|
1594
|
-
border: `1px solid ${stroke.soft}`,
|
|
1595
|
-
cursor: previewUrl ? "zoom-in" : "default",
|
|
1596
|
-
marginBottom: 10,
|
|
1597
|
-
display: "flex",
|
|
1598
|
-
flexDirection: "column",
|
|
1599
|
-
...outerBg
|
|
1600
|
-
},
|
|
1601
|
-
children: frameEnabled ? /* @__PURE__ */ jsxs2(
|
|
1602
|
-
"div",
|
|
1603
|
-
{
|
|
1604
|
-
style: {
|
|
1605
|
-
flex: 1,
|
|
1606
|
-
display: "flex",
|
|
1607
|
-
flexDirection: "column",
|
|
1608
|
-
padding: paddingPct,
|
|
1609
|
-
minHeight: 0
|
|
1610
|
-
},
|
|
1611
|
-
children: [
|
|
1612
|
-
browserChrome && /* @__PURE__ */ jsx2(BrowserChromeBar, { theme: browserTheme }),
|
|
1613
|
-
/* @__PURE__ */ jsx2(
|
|
1614
|
-
"div",
|
|
1615
|
-
{
|
|
1616
|
-
style: {
|
|
1617
|
-
flex: 1,
|
|
1618
|
-
display: "flex",
|
|
1619
|
-
alignItems: "center",
|
|
1620
|
-
justifyContent: "center",
|
|
1621
|
-
minHeight: 0,
|
|
1622
|
-
overflow: "hidden"
|
|
1623
|
-
},
|
|
1624
|
-
children: imageEl || emptyState
|
|
1625
|
-
}
|
|
1626
|
-
)
|
|
1627
|
-
]
|
|
1628
|
-
}
|
|
1629
|
-
) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1630
|
-
browserChrome && /* @__PURE__ */ jsx2(BrowserChromeBar, { theme: browserTheme }),
|
|
1631
|
-
/* @__PURE__ */ jsx2(
|
|
1632
|
-
"div",
|
|
1633
|
-
{
|
|
1634
|
-
style: {
|
|
1635
|
-
flex: 1,
|
|
1636
|
-
display: "flex",
|
|
1637
|
-
alignItems: "center",
|
|
1638
|
-
justifyContent: "center",
|
|
1639
|
-
minHeight: 0
|
|
1640
|
-
},
|
|
1641
|
-
children: imageEl || emptyState
|
|
1642
|
-
}
|
|
1643
|
-
)
|
|
1644
|
-
] })
|
|
1645
|
-
}
|
|
1646
|
-
);
|
|
1516
|
+
function formatTimestamp(filename) {
|
|
1517
|
+
const iso = filename.replace(/\.png$/, "").replace(/T(\d{2})-(\d{2})-(\d{2})-(\d+)Z$/, "T$1:$2:$3.$4Z");
|
|
1518
|
+
const date = new Date(iso);
|
|
1519
|
+
if (Number.isNaN(date.getTime())) return filename.replace(/\.png$/, "");
|
|
1520
|
+
const now = /* @__PURE__ */ new Date();
|
|
1521
|
+
const diffMs = now.getTime() - date.getTime();
|
|
1522
|
+
const diffMin = Math.floor(diffMs / 6e4);
|
|
1523
|
+
if (diffMin < 1) return "Just now";
|
|
1524
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
1525
|
+
const diffHr = Math.floor(diffMin / 60);
|
|
1526
|
+
if (diffHr < 24) return `${diffHr}h ago`;
|
|
1527
|
+
return date.toLocaleDateString(void 0, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
1647
1528
|
}
|
|
1648
|
-
function
|
|
1529
|
+
function ScreenshotsPanel({
|
|
1649
1530
|
open,
|
|
1650
1531
|
onClick,
|
|
1651
1532
|
selectedMode,
|
|
@@ -1654,7 +1535,6 @@ function HistoryButton({
|
|
|
1654
1535
|
tooltipSide
|
|
1655
1536
|
}) {
|
|
1656
1537
|
const [toast, setToast] = useState3(null);
|
|
1657
|
-
const [pushing, setPushing] = useState3(false);
|
|
1658
1538
|
const [saveDir, setSaveDir] = useState3(null);
|
|
1659
1539
|
const [picking, setPicking] = useState3(false);
|
|
1660
1540
|
const [repos, setRepos] = useState3([]);
|
|
@@ -1665,7 +1545,6 @@ function HistoryButton({
|
|
|
1665
1545
|
const [loading, setLoading] = useState3(false);
|
|
1666
1546
|
const [repoDropOpen, setRepoDropOpen] = useState3(false);
|
|
1667
1547
|
const [branchDropOpen, setBranchDropOpen] = useState3(false);
|
|
1668
|
-
const [lightboxSrc, setLightboxSrc] = useState3(null);
|
|
1669
1548
|
const [editingFile, setEditingFile] = useState3(null);
|
|
1670
1549
|
const [editValue, setEditValue] = useState3("");
|
|
1671
1550
|
const [selectedFile, setSelectedFile] = useState3(null);
|
|
@@ -1724,27 +1603,13 @@ function HistoryButton({
|
|
|
1724
1603
|
setToast({ message, type });
|
|
1725
1604
|
setTimeout(() => setToast(null), 3e3);
|
|
1726
1605
|
}, []);
|
|
1727
|
-
const
|
|
1606
|
+
const handleRename = async (oldName, newName) => {
|
|
1607
|
+
if (!newName.trim() || newName.trim() === oldName.replace(/\.png$/, "")) {
|
|
1608
|
+
setEditingFile(null);
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1728
1611
|
try {
|
|
1729
|
-
const
|
|
1730
|
-
const res = await fetch("/__afterbefore/open", {
|
|
1731
|
-
method: "POST",
|
|
1732
|
-
headers: body ? { "Content-Type": "application/json" } : void 0,
|
|
1733
|
-
body
|
|
1734
|
-
});
|
|
1735
|
-
if (!res.ok) throw new Error();
|
|
1736
|
-
showToast("Opened folder", "success");
|
|
1737
|
-
} catch {
|
|
1738
|
-
showToast("Could not open folder", "error");
|
|
1739
|
-
}
|
|
1740
|
-
};
|
|
1741
|
-
const handleRename = async (oldName, newName) => {
|
|
1742
|
-
if (!newName.trim() || newName.trim() === oldName.replace(/\.png$/, "")) {
|
|
1743
|
-
setEditingFile(null);
|
|
1744
|
-
return;
|
|
1745
|
-
}
|
|
1746
|
-
try {
|
|
1747
|
-
const res = await fetch("/__afterbefore/history/rename", {
|
|
1612
|
+
const res = await fetch("/__afterbefore/history/rename", {
|
|
1748
1613
|
method: "POST",
|
|
1749
1614
|
headers: { "Content-Type": "application/json" },
|
|
1750
1615
|
body: JSON.stringify({
|
|
@@ -1790,29 +1655,11 @@ function HistoryButton({
|
|
|
1790
1655
|
showToast("Delete failed", "error");
|
|
1791
1656
|
}
|
|
1792
1657
|
};
|
|
1793
|
-
const handlePush = async () => {
|
|
1794
|
-
setPushing(true);
|
|
1795
|
-
try {
|
|
1796
|
-
const res = await fetch("/__afterbefore/push", { method: "POST" });
|
|
1797
|
-
const data = await res.json();
|
|
1798
|
-
if (!res.ok) {
|
|
1799
|
-
showToast(data.error || "Push failed", "error");
|
|
1800
|
-
} else if (data.pr) {
|
|
1801
|
-
showToast(`Posted to PR #${data.pr}`, "success");
|
|
1802
|
-
} else {
|
|
1803
|
-
showToast("No PR found", "error");
|
|
1804
|
-
}
|
|
1805
|
-
} catch {
|
|
1806
|
-
showToast("Push failed", "error");
|
|
1807
|
-
} finally {
|
|
1808
|
-
setPushing(false);
|
|
1809
|
-
}
|
|
1810
|
-
};
|
|
1811
1658
|
const previewUrl = selectedFile ? `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(selectedFile)}` : null;
|
|
1812
|
-
return /* @__PURE__ */
|
|
1813
|
-
/* @__PURE__ */
|
|
1659
|
+
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1660
|
+
/* @__PURE__ */ jsx3(IconButton, { active: open, tooltipSide, tooltip: !open ? "Screenshots" : void 0, onClick, children: /* @__PURE__ */ jsx3(ImageIcon, { size: 20 }) }),
|
|
1814
1661
|
open && createPortal(
|
|
1815
|
-
/* @__PURE__ */
|
|
1662
|
+
/* @__PURE__ */ jsxs3(
|
|
1816
1663
|
"div",
|
|
1817
1664
|
{
|
|
1818
1665
|
"data-afterbefore": "true",
|
|
@@ -1828,13 +1675,26 @@ function HistoryButton({
|
|
|
1828
1675
|
...fontBase
|
|
1829
1676
|
},
|
|
1830
1677
|
children: [
|
|
1831
|
-
/* @__PURE__ */
|
|
1678
|
+
/* @__PURE__ */ jsx3(
|
|
1679
|
+
"style",
|
|
1680
|
+
{
|
|
1681
|
+
dangerouslySetInnerHTML: {
|
|
1682
|
+
__html: `
|
|
1683
|
+
@keyframes ab-panel-in {
|
|
1684
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
1685
|
+
to { opacity: 1; transform: translateY(0); }
|
|
1686
|
+
}
|
|
1687
|
+
`
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
),
|
|
1691
|
+
/* @__PURE__ */ jsxs3(
|
|
1832
1692
|
"div",
|
|
1833
1693
|
{
|
|
1834
1694
|
onClick: (e) => e.stopPropagation(),
|
|
1835
1695
|
style: {
|
|
1836
|
-
width:
|
|
1837
|
-
|
|
1696
|
+
width: 900,
|
|
1697
|
+
height: "70vh",
|
|
1838
1698
|
borderRadius: 14,
|
|
1839
1699
|
background: bg.base,
|
|
1840
1700
|
border: `1px solid ${stroke.default}`,
|
|
@@ -1845,17 +1705,18 @@ function HistoryButton({
|
|
|
1845
1705
|
animation: "ab-panel-in 150ms cubic-bezier(0.23, 1, 0.32, 1)"
|
|
1846
1706
|
},
|
|
1847
1707
|
children: [
|
|
1848
|
-
/* @__PURE__ */
|
|
1708
|
+
/* @__PURE__ */ jsxs3("div", { style: {
|
|
1849
1709
|
display: "flex",
|
|
1850
1710
|
alignItems: "center",
|
|
1851
1711
|
justifyContent: "space-between",
|
|
1852
|
-
padding: "16px 20px
|
|
1712
|
+
padding: "16px 20px",
|
|
1713
|
+
borderBottom: `1px solid ${stroke.soft}`
|
|
1853
1714
|
}, children: [
|
|
1854
|
-
/* @__PURE__ */
|
|
1855
|
-
/* @__PURE__ */
|
|
1856
|
-
/* @__PURE__ */
|
|
1715
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1716
|
+
/* @__PURE__ */ jsx3("div", { style: { ...text.label.sm, color: fg.strong }, children: "Screenshots" }),
|
|
1717
|
+
/* @__PURE__ */ jsx3("div", { style: { ...text.paragraph.xs, color: fg.sub, marginTop: 2 }, children: "Capture history & settings" })
|
|
1857
1718
|
] }),
|
|
1858
|
-
/* @__PURE__ */
|
|
1719
|
+
/* @__PURE__ */ jsx3(
|
|
1859
1720
|
"button",
|
|
1860
1721
|
{
|
|
1861
1722
|
onClick,
|
|
@@ -1869,222 +1730,249 @@ function HistoryButton({
|
|
|
1869
1730
|
alignItems: "center",
|
|
1870
1731
|
justifyContent: "center",
|
|
1871
1732
|
cursor: "pointer",
|
|
1872
|
-
color: fg.
|
|
1733
|
+
color: fg.sub,
|
|
1873
1734
|
padding: 0,
|
|
1874
1735
|
transition: "background 0.12s ease, color 0.12s ease"
|
|
1875
1736
|
},
|
|
1876
1737
|
onMouseEnter: (e) => {
|
|
1877
1738
|
e.currentTarget.style.background = state.hover;
|
|
1878
|
-
e.currentTarget.style.color = fg.
|
|
1739
|
+
e.currentTarget.style.color = fg.strong;
|
|
1879
1740
|
},
|
|
1880
1741
|
onMouseLeave: (e) => {
|
|
1881
1742
|
e.currentTarget.style.background = "transparent";
|
|
1882
|
-
e.currentTarget.style.color = fg.
|
|
1743
|
+
e.currentTarget.style.color = fg.sub;
|
|
1883
1744
|
},
|
|
1884
|
-
children: /* @__PURE__ */
|
|
1745
|
+
children: /* @__PURE__ */ jsx3(X, { size: 14, strokeWidth: 2 })
|
|
1885
1746
|
}
|
|
1886
1747
|
)
|
|
1887
1748
|
] }),
|
|
1888
|
-
/* @__PURE__ */
|
|
1889
|
-
/* @__PURE__ */
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
previewUrl,
|
|
1893
|
-
frameSettings,
|
|
1894
|
-
loading,
|
|
1895
|
-
onClickLightbox: () => {
|
|
1896
|
-
if (previewUrl) setLightboxSrc(previewUrl);
|
|
1897
|
-
}
|
|
1898
|
-
}
|
|
1899
|
-
),
|
|
1900
|
-
selectedFile && !loading && /* @__PURE__ */ jsxs2("div", { style: {
|
|
1901
|
-
display: "flex",
|
|
1902
|
-
alignItems: "center",
|
|
1903
|
-
gap: 8,
|
|
1904
|
-
marginBottom: 12
|
|
1905
|
-
}, children: [
|
|
1906
|
-
/* @__PURE__ */ jsx2("div", { style: { flex: 1, minWidth: 0 }, children: editingFile === selectedFile ? /* @__PURE__ */ jsx2(
|
|
1907
|
-
"input",
|
|
1749
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", flex: 1, overflow: "hidden", minHeight: 0 }, children: [
|
|
1750
|
+
/* @__PURE__ */ jsxs3("div", { style: { flex: 1, overflowY: "auto", padding: "16px 20px 20px", minHeight: 0 }, children: [
|
|
1751
|
+
/* @__PURE__ */ jsx3(
|
|
1752
|
+
FramePreview,
|
|
1908
1753
|
{
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
onKeyDown: (e) => {
|
|
1913
|
-
if (e.key === "Enter") handleRename(selectedFile, editValue);
|
|
1914
|
-
if (e.key === "Escape") setEditingFile(null);
|
|
1915
|
-
},
|
|
1916
|
-
onBlur: () => handleRename(selectedFile, editValue),
|
|
1917
|
-
style: {
|
|
1918
|
-
width: "100%",
|
|
1919
|
-
...text.label.xs,
|
|
1920
|
-
color: fg.strong,
|
|
1921
|
-
background: state.hover,
|
|
1922
|
-
border: `1px solid ${stroke.interactive}`,
|
|
1923
|
-
borderRadius: 4,
|
|
1924
|
-
padding: "2px 6px",
|
|
1925
|
-
outline: "none",
|
|
1926
|
-
fontFamily: "inherit"
|
|
1927
|
-
}
|
|
1754
|
+
previewUrl,
|
|
1755
|
+
frameSettings,
|
|
1756
|
+
loading
|
|
1928
1757
|
}
|
|
1929
|
-
)
|
|
1758
|
+
),
|
|
1759
|
+
selectedFile && !loading && /* @__PURE__ */ jsxs3("div", { style: {
|
|
1760
|
+
display: "flex",
|
|
1761
|
+
alignItems: "center",
|
|
1762
|
+
gap: 8,
|
|
1763
|
+
marginBottom: 12
|
|
1764
|
+
}, children: [
|
|
1765
|
+
/* @__PURE__ */ jsx3("div", { style: { flex: 1, minWidth: 0 }, children: editingFile === selectedFile ? /* @__PURE__ */ jsx3(
|
|
1766
|
+
"input",
|
|
1767
|
+
{
|
|
1768
|
+
autoFocus: true,
|
|
1769
|
+
value: editValue,
|
|
1770
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
1771
|
+
onKeyDown: (e) => {
|
|
1772
|
+
if (e.key === "Enter") handleRename(selectedFile, editValue);
|
|
1773
|
+
if (e.key === "Escape") setEditingFile(null);
|
|
1774
|
+
},
|
|
1775
|
+
onBlur: () => handleRename(selectedFile, editValue),
|
|
1776
|
+
style: {
|
|
1777
|
+
width: "100%",
|
|
1778
|
+
...text.label.xs,
|
|
1779
|
+
color: fg.strong,
|
|
1780
|
+
background: state.hover,
|
|
1781
|
+
border: `1px solid ${stroke.interactive}`,
|
|
1782
|
+
borderRadius: 4,
|
|
1783
|
+
padding: "2px 6px",
|
|
1784
|
+
outline: "none",
|
|
1785
|
+
fontFamily: "inherit"
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
) : /* @__PURE__ */ jsx3(
|
|
1789
|
+
"div",
|
|
1790
|
+
{
|
|
1791
|
+
onClick: () => {
|
|
1792
|
+
setEditingFile(selectedFile);
|
|
1793
|
+
setEditValue(selectedFile.replace(/\.png$/, ""));
|
|
1794
|
+
},
|
|
1795
|
+
style: {
|
|
1796
|
+
...text.label.xs,
|
|
1797
|
+
color: fg.strong,
|
|
1798
|
+
cursor: "pointer",
|
|
1799
|
+
overflow: "hidden",
|
|
1800
|
+
textOverflow: "ellipsis",
|
|
1801
|
+
whiteSpace: "nowrap"
|
|
1802
|
+
},
|
|
1803
|
+
title: "Click to rename",
|
|
1804
|
+
children: formatTimestamp(selectedFile)
|
|
1805
|
+
}
|
|
1806
|
+
) }),
|
|
1807
|
+
/* @__PURE__ */ jsx3(
|
|
1808
|
+
"button",
|
|
1809
|
+
{
|
|
1810
|
+
onClick: () => handleDelete(selectedFile),
|
|
1811
|
+
title: "Delete screenshot",
|
|
1812
|
+
style: {
|
|
1813
|
+
flexShrink: 0,
|
|
1814
|
+
width: 28,
|
|
1815
|
+
height: 28,
|
|
1816
|
+
borderRadius: 6,
|
|
1817
|
+
border: "none",
|
|
1818
|
+
background: "transparent",
|
|
1819
|
+
color: fg.muted,
|
|
1820
|
+
cursor: "pointer",
|
|
1821
|
+
display: "flex",
|
|
1822
|
+
alignItems: "center",
|
|
1823
|
+
justifyContent: "center",
|
|
1824
|
+
padding: 0
|
|
1825
|
+
},
|
|
1826
|
+
onMouseEnter: (e) => {
|
|
1827
|
+
e.currentTarget.style.color = feedback.error;
|
|
1828
|
+
e.currentTarget.style.background = feedback.errorBg;
|
|
1829
|
+
},
|
|
1830
|
+
onMouseLeave: (e) => {
|
|
1831
|
+
e.currentTarget.style.color = fg.muted;
|
|
1832
|
+
e.currentTarget.style.background = "transparent";
|
|
1833
|
+
},
|
|
1834
|
+
children: /* @__PURE__ */ jsx3(Trash22, { size: 14, strokeWidth: 1.8 })
|
|
1835
|
+
}
|
|
1836
|
+
)
|
|
1837
|
+
] }),
|
|
1838
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: 10, marginBottom: 10 }, children: [
|
|
1839
|
+
/* @__PURE__ */ jsx3("div", { style: { flex: 1, position: "relative" }, children: /* @__PURE__ */ jsx3(
|
|
1840
|
+
FilterDropdown,
|
|
1841
|
+
{
|
|
1842
|
+
label: "Project",
|
|
1843
|
+
value: selectedRepo,
|
|
1844
|
+
options: repos,
|
|
1845
|
+
isOpen: repoDropOpen,
|
|
1846
|
+
onToggle: () => {
|
|
1847
|
+
setRepoDropOpen((p) => !p);
|
|
1848
|
+
setBranchDropOpen(false);
|
|
1849
|
+
},
|
|
1850
|
+
onSelect: (repo) => {
|
|
1851
|
+
setSelectedRepo(repo);
|
|
1852
|
+
setSelectedBranch(null);
|
|
1853
|
+
setRepoDropOpen(false);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
) }),
|
|
1857
|
+
/* @__PURE__ */ jsx3("div", { style: { flex: 1, position: "relative" }, children: /* @__PURE__ */ jsx3(
|
|
1858
|
+
FilterDropdown,
|
|
1859
|
+
{
|
|
1860
|
+
label: "Branch",
|
|
1861
|
+
value: selectedBranch,
|
|
1862
|
+
options: branches,
|
|
1863
|
+
isOpen: branchDropOpen,
|
|
1864
|
+
onToggle: () => {
|
|
1865
|
+
setBranchDropOpen((p) => !p);
|
|
1866
|
+
setRepoDropOpen(false);
|
|
1867
|
+
},
|
|
1868
|
+
onSelect: (branch) => {
|
|
1869
|
+
setSelectedBranch(branch);
|
|
1870
|
+
setBranchDropOpen(false);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
) })
|
|
1874
|
+
] }),
|
|
1875
|
+
screenshots.length > 0 && /* @__PURE__ */ jsx3(
|
|
1930
1876
|
"div",
|
|
1931
1877
|
{
|
|
1932
|
-
onClick: () => {
|
|
1933
|
-
setEditingFile(selectedFile);
|
|
1934
|
-
setEditValue(selectedFile.replace(/\.png$/, ""));
|
|
1935
|
-
},
|
|
1936
|
-
style: {
|
|
1937
|
-
...text.label.xs,
|
|
1938
|
-
color: fg.strong,
|
|
1939
|
-
cursor: "pointer",
|
|
1940
|
-
overflow: "hidden",
|
|
1941
|
-
textOverflow: "ellipsis",
|
|
1942
|
-
whiteSpace: "nowrap"
|
|
1943
|
-
},
|
|
1944
|
-
title: "Click to rename",
|
|
1945
|
-
children: formatTimestamp(selectedFile)
|
|
1946
|
-
}
|
|
1947
|
-
) }),
|
|
1948
|
-
/* @__PURE__ */ jsx2(
|
|
1949
|
-
"button",
|
|
1950
|
-
{
|
|
1951
|
-
onClick: () => handleDelete(selectedFile),
|
|
1952
|
-
title: "Delete screenshot",
|
|
1953
1878
|
style: {
|
|
1954
|
-
flexShrink: 0,
|
|
1955
|
-
width: 28,
|
|
1956
|
-
height: 28,
|
|
1957
|
-
borderRadius: 6,
|
|
1958
|
-
border: "none",
|
|
1959
|
-
background: "transparent",
|
|
1960
|
-
color: fg.faint,
|
|
1961
|
-
cursor: "pointer",
|
|
1962
1879
|
display: "flex",
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
onMouseEnter: (e) => {
|
|
1968
|
-
e.currentTarget.style.color = feedback.error;
|
|
1969
|
-
e.currentTarget.style.background = feedback.errorBg;
|
|
1880
|
+
gap: 6,
|
|
1881
|
+
overflowX: "auto",
|
|
1882
|
+
paddingBottom: 4,
|
|
1883
|
+
marginBottom: 10
|
|
1970
1884
|
},
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1885
|
+
children: screenshots.map((shot) => {
|
|
1886
|
+
const thumbUrl = `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(shot.filename)}`;
|
|
1887
|
+
const isSelected = selectedFile === shot.filename;
|
|
1888
|
+
return /* @__PURE__ */ jsx3(
|
|
1889
|
+
"div",
|
|
1890
|
+
{
|
|
1891
|
+
onClick: () => setSelectedFile(shot.filename),
|
|
1892
|
+
style: {
|
|
1893
|
+
width: 64,
|
|
1894
|
+
height: 44,
|
|
1895
|
+
flexShrink: 0,
|
|
1896
|
+
borderRadius: 6,
|
|
1897
|
+
overflow: "hidden",
|
|
1898
|
+
cursor: "pointer",
|
|
1899
|
+
border: isSelected ? `2px solid ${accent.highlight}` : `1px solid ${stroke.soft}`,
|
|
1900
|
+
opacity: isSelected ? 1 : 0.7,
|
|
1901
|
+
transition: "opacity 0.12s ease, border-color 0.12s ease"
|
|
1902
|
+
},
|
|
1903
|
+
children: /* @__PURE__ */ jsx3(
|
|
1904
|
+
"img",
|
|
1905
|
+
{
|
|
1906
|
+
src: thumbUrl,
|
|
1907
|
+
alt: "",
|
|
1908
|
+
style: {
|
|
1909
|
+
width: "100%",
|
|
1910
|
+
height: "100%",
|
|
1911
|
+
objectFit: "cover",
|
|
1912
|
+
display: "block"
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
)
|
|
1916
|
+
},
|
|
1917
|
+
shot.filename
|
|
1918
|
+
);
|
|
1919
|
+
})
|
|
1976
1920
|
}
|
|
1977
1921
|
)
|
|
1978
1922
|
] }),
|
|
1979
|
-
/* @__PURE__ */
|
|
1980
|
-
|
|
1981
|
-
{
|
|
1982
|
-
|
|
1983
|
-
onFrameSettingsChange,
|
|
1984
|
-
saveDir: shortDir,
|
|
1985
|
-
picking,
|
|
1986
|
-
onPickFolder: handlePickFolder
|
|
1987
|
-
}
|
|
1988
|
-
) }),
|
|
1989
|
-
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 10, marginBottom: 10 }, children: [
|
|
1990
|
-
/* @__PURE__ */ jsx2("div", { style: { flex: 1, position: "relative" }, children: /* @__PURE__ */ jsx2(
|
|
1991
|
-
FilterDropdown,
|
|
1923
|
+
/* @__PURE__ */ jsx3("div", { style: { width: 1, flexShrink: 0, background: stroke.soft } }),
|
|
1924
|
+
/* @__PURE__ */ jsxs3("div", { style: { width: 300, flexShrink: 0, overflowY: "auto", padding: "16px 16px 12px", minHeight: 0, display: "flex", flexDirection: "column" }, children: [
|
|
1925
|
+
/* @__PURE__ */ jsx3("div", { style: { flex: 1 }, children: /* @__PURE__ */ jsx3(
|
|
1926
|
+
SettingsContent,
|
|
1992
1927
|
{
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
setRepoDropOpen((p) => !p);
|
|
1999
|
-
setBranchDropOpen(false);
|
|
2000
|
-
},
|
|
2001
|
-
onSelect: (repo) => {
|
|
2002
|
-
setSelectedRepo(repo);
|
|
2003
|
-
setSelectedBranch(null);
|
|
2004
|
-
setRepoDropOpen(false);
|
|
2005
|
-
}
|
|
1928
|
+
frameSettings,
|
|
1929
|
+
onFrameSettingsChange,
|
|
1930
|
+
saveDir: shortDir,
|
|
1931
|
+
picking,
|
|
1932
|
+
onPickFolder: handlePickFolder
|
|
2006
1933
|
}
|
|
2007
1934
|
) }),
|
|
2008
|
-
/* @__PURE__ */
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
1935
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 8, paddingTop: 12, paddingBottom: 2, marginTop: 12, borderTop: `1px solid ${stroke.soft}`, marginLeft: -16, marginRight: -16, paddingLeft: 16 }, children: [
|
|
1936
|
+
/* @__PURE__ */ jsx3("span", { style: { ...text.paragraph.xs, color: fg.muted }, children: "Paulius Kairevicius" }),
|
|
1937
|
+
/* @__PURE__ */ jsx3(
|
|
1938
|
+
"a",
|
|
1939
|
+
{
|
|
1940
|
+
href: "https://github.com/kairevicius",
|
|
1941
|
+
target: "_blank",
|
|
1942
|
+
rel: "noopener noreferrer",
|
|
1943
|
+
style: { color: fg.muted, display: "flex", transition: "color 0.12s" },
|
|
1944
|
+
onMouseEnter: (e) => {
|
|
1945
|
+
e.currentTarget.style.color = fg.strong;
|
|
1946
|
+
},
|
|
1947
|
+
onMouseLeave: (e) => {
|
|
1948
|
+
e.currentTarget.style.color = fg.muted;
|
|
1949
|
+
},
|
|
1950
|
+
children: /* @__PURE__ */ jsx3("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx3("path", { d: "M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" }) })
|
|
2022
1951
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
paddingBottom: 4,
|
|
2034
|
-
marginBottom: 10
|
|
2035
|
-
},
|
|
2036
|
-
children: screenshots.map((shot) => {
|
|
2037
|
-
const thumbUrl = `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(shot.filename)}`;
|
|
2038
|
-
const isSelected = selectedFile === shot.filename;
|
|
2039
|
-
return /* @__PURE__ */ jsx2(
|
|
2040
|
-
"div",
|
|
2041
|
-
{
|
|
2042
|
-
onClick: () => setSelectedFile(shot.filename),
|
|
2043
|
-
style: {
|
|
2044
|
-
width: 64,
|
|
2045
|
-
height: 44,
|
|
2046
|
-
flexShrink: 0,
|
|
2047
|
-
borderRadius: 6,
|
|
2048
|
-
overflow: "hidden",
|
|
2049
|
-
cursor: "pointer",
|
|
2050
|
-
border: isSelected ? `2px solid ${accent.highlight}` : `1px solid ${stroke.soft}`,
|
|
2051
|
-
opacity: isSelected ? 1 : 0.7,
|
|
2052
|
-
transition: "opacity 0.12s ease, border-color 0.12s ease"
|
|
2053
|
-
},
|
|
2054
|
-
children: /* @__PURE__ */ jsx2(
|
|
2055
|
-
"img",
|
|
2056
|
-
{
|
|
2057
|
-
src: thumbUrl,
|
|
2058
|
-
alt: "",
|
|
2059
|
-
style: {
|
|
2060
|
-
width: "100%",
|
|
2061
|
-
height: "100%",
|
|
2062
|
-
objectFit: "cover",
|
|
2063
|
-
display: "block"
|
|
2064
|
-
}
|
|
2065
|
-
}
|
|
2066
|
-
)
|
|
1952
|
+
),
|
|
1953
|
+
/* @__PURE__ */ jsx3(
|
|
1954
|
+
"a",
|
|
1955
|
+
{
|
|
1956
|
+
href: "https://x.com/kairevicius",
|
|
1957
|
+
target: "_blank",
|
|
1958
|
+
rel: "noopener noreferrer",
|
|
1959
|
+
style: { color: fg.muted, display: "flex", transition: "color 0.12s" },
|
|
1960
|
+
onMouseEnter: (e) => {
|
|
1961
|
+
e.currentTarget.style.color = fg.strong;
|
|
2067
1962
|
},
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
/* @__PURE__ */ jsxs2(ActionButton, { onClick: handleOpenFolder, children: [
|
|
2075
|
-
/* @__PURE__ */ jsx2(FolderOpen, { size: 13, strokeWidth: 1.8 }),
|
|
2076
|
-
"Open Folder"
|
|
2077
|
-
] }),
|
|
2078
|
-
/* @__PURE__ */ jsxs2(ActionButton, { onClick: handlePush, disabled: pushing, children: [
|
|
2079
|
-
/* @__PURE__ */ jsx2(ArrowUp, { size: 13, strokeWidth: 1.8 }),
|
|
2080
|
-
pushing ? "Pushing..." : "Push to PR"
|
|
1963
|
+
onMouseLeave: (e) => {
|
|
1964
|
+
e.currentTarget.style.color = fg.muted;
|
|
1965
|
+
},
|
|
1966
|
+
children: /* @__PURE__ */ jsx3("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx3("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) })
|
|
1967
|
+
}
|
|
1968
|
+
)
|
|
2081
1969
|
] })
|
|
2082
1970
|
] })
|
|
2083
1971
|
] })
|
|
2084
1972
|
]
|
|
2085
1973
|
}
|
|
2086
1974
|
),
|
|
2087
|
-
toast && /* @__PURE__ */
|
|
1975
|
+
toast && /* @__PURE__ */ jsx3(
|
|
2088
1976
|
"div",
|
|
2089
1977
|
{
|
|
2090
1978
|
onClick: (e) => e.stopPropagation(),
|
|
@@ -2108,72 +1996,568 @@ function HistoryButton({
|
|
|
2108
1996
|
}
|
|
2109
1997
|
),
|
|
2110
1998
|
document.body
|
|
1999
|
+
)
|
|
2000
|
+
] });
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
// src/overlay/ui/toolbar.tsx
|
|
2004
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2005
|
+
var TOOLTIP_DELAY = 500;
|
|
2006
|
+
var TOOLTIP_COOLDOWN = 300;
|
|
2007
|
+
var tooltipWarm = false;
|
|
2008
|
+
var tooltipCooldownTimer = null;
|
|
2009
|
+
function useTooltipDelay(hovered) {
|
|
2010
|
+
const [visible, setVisible] = useState4(false);
|
|
2011
|
+
const delayRef = useRef2(null);
|
|
2012
|
+
useEffect3(() => {
|
|
2013
|
+
if (!hovered) {
|
|
2014
|
+
setVisible(false);
|
|
2015
|
+
if (delayRef.current) {
|
|
2016
|
+
clearTimeout(delayRef.current);
|
|
2017
|
+
delayRef.current = null;
|
|
2018
|
+
}
|
|
2019
|
+
if (tooltipCooldownTimer) clearTimeout(tooltipCooldownTimer);
|
|
2020
|
+
tooltipCooldownTimer = setTimeout(() => {
|
|
2021
|
+
tooltipWarm = false;
|
|
2022
|
+
}, TOOLTIP_COOLDOWN);
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
if (tooltipCooldownTimer) {
|
|
2026
|
+
clearTimeout(tooltipCooldownTimer);
|
|
2027
|
+
tooltipCooldownTimer = null;
|
|
2028
|
+
}
|
|
2029
|
+
if (tooltipWarm) {
|
|
2030
|
+
setVisible(true);
|
|
2031
|
+
} else {
|
|
2032
|
+
delayRef.current = setTimeout(() => {
|
|
2033
|
+
tooltipWarm = true;
|
|
2034
|
+
setVisible(true);
|
|
2035
|
+
}, TOOLTIP_DELAY);
|
|
2036
|
+
}
|
|
2037
|
+
return () => {
|
|
2038
|
+
if (delayRef.current) {
|
|
2039
|
+
clearTimeout(delayRef.current);
|
|
2040
|
+
delayRef.current = null;
|
|
2041
|
+
}
|
|
2042
|
+
};
|
|
2043
|
+
}, [hovered]);
|
|
2044
|
+
return visible;
|
|
2045
|
+
}
|
|
2046
|
+
var EDGE_MARGIN = 24;
|
|
2047
|
+
var CONTAINER_SIZE = 38;
|
|
2048
|
+
function getCornerStyle(corner) {
|
|
2049
|
+
switch (corner) {
|
|
2050
|
+
case "bottom-right":
|
|
2051
|
+
return { bottom: EDGE_MARGIN, right: EDGE_MARGIN };
|
|
2052
|
+
case "bottom-left":
|
|
2053
|
+
return { bottom: EDGE_MARGIN, left: EDGE_MARGIN };
|
|
2054
|
+
case "top-right":
|
|
2055
|
+
return { top: EDGE_MARGIN, right: EDGE_MARGIN };
|
|
2056
|
+
case "top-left":
|
|
2057
|
+
return { top: EDGE_MARGIN, left: EDGE_MARGIN };
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
function isBottomCorner(corner) {
|
|
2061
|
+
return corner === "bottom-right" || corner === "bottom-left";
|
|
2062
|
+
}
|
|
2063
|
+
function isRightCorner(corner) {
|
|
2064
|
+
return corner === "bottom-right" || corner === "top-right";
|
|
2065
|
+
}
|
|
2066
|
+
function snapToCorner(x, y) {
|
|
2067
|
+
const cx = window.innerWidth / 2;
|
|
2068
|
+
const cy = window.innerHeight / 2;
|
|
2069
|
+
if (x < cx) {
|
|
2070
|
+
return y < cy ? "top-left" : "bottom-left";
|
|
2071
|
+
}
|
|
2072
|
+
return y < cy ? "top-right" : "bottom-right";
|
|
2073
|
+
}
|
|
2074
|
+
function getCornerPosition(corner, w, h) {
|
|
2075
|
+
const vw = window.innerWidth;
|
|
2076
|
+
const vh = window.innerHeight;
|
|
2077
|
+
switch (corner) {
|
|
2078
|
+
case "bottom-right":
|
|
2079
|
+
return { x: vw - EDGE_MARGIN - w, y: vh - EDGE_MARGIN - h };
|
|
2080
|
+
case "bottom-left":
|
|
2081
|
+
return { x: EDGE_MARGIN, y: vh - EDGE_MARGIN - h };
|
|
2082
|
+
case "top-right":
|
|
2083
|
+
return { x: vw - EDGE_MARGIN - w, y: EDGE_MARGIN };
|
|
2084
|
+
case "top-left":
|
|
2085
|
+
return { x: EDGE_MARGIN, y: EDGE_MARGIN };
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
var MODES = [
|
|
2089
|
+
{ mode: "component", label: "Component", icon: CameraIcon },
|
|
2090
|
+
{ mode: "viewport", label: "Viewport", icon: Monitor },
|
|
2091
|
+
{ mode: "fullpage", label: "Full Page", icon: FileText }
|
|
2092
|
+
];
|
|
2093
|
+
function Toolbar({
|
|
2094
|
+
expanded,
|
|
2095
|
+
onToggle,
|
|
2096
|
+
phase,
|
|
2097
|
+
loading,
|
|
2098
|
+
selectedMode,
|
|
2099
|
+
onModeChange,
|
|
2100
|
+
onCapture,
|
|
2101
|
+
onCancel,
|
|
2102
|
+
frameSettings,
|
|
2103
|
+
onFrameSettingsChange
|
|
2104
|
+
}) {
|
|
2105
|
+
const [historyOpen, setHistoryOpen] = useState4(false);
|
|
2106
|
+
const [modesExpanded, setModesExpanded] = useState4(false);
|
|
2107
|
+
const [buttonsVisible, setButtonsVisible] = useState4(expanded);
|
|
2108
|
+
const [animIn, setAnimIn] = useState4(expanded);
|
|
2109
|
+
const [animDone, setAnimDone] = useState4(expanded);
|
|
2110
|
+
useEffect3(() => {
|
|
2111
|
+
if (expanded) {
|
|
2112
|
+
setAnimDone(false);
|
|
2113
|
+
setButtonsVisible(true);
|
|
2114
|
+
setAnimIn(false);
|
|
2115
|
+
requestAnimationFrame(() => {
|
|
2116
|
+
requestAnimationFrame(() => setAnimIn(true));
|
|
2117
|
+
});
|
|
2118
|
+
const timer = setTimeout(() => setAnimDone(true), 250);
|
|
2119
|
+
return () => clearTimeout(timer);
|
|
2120
|
+
} else if (buttonsVisible) {
|
|
2121
|
+
setHistoryOpen(false);
|
|
2122
|
+
setAnimDone(false);
|
|
2123
|
+
setAnimIn(false);
|
|
2124
|
+
const timer = setTimeout(() => setButtonsVisible(false), 150);
|
|
2125
|
+
return () => clearTimeout(timer);
|
|
2126
|
+
}
|
|
2127
|
+
}, [expanded]);
|
|
2128
|
+
const [corner, setCorner] = useState4(() => {
|
|
2129
|
+
try {
|
|
2130
|
+
const stored = localStorage.getItem("ab-toolbar-corner");
|
|
2131
|
+
if (stored && ["bottom-right", "bottom-left", "top-right", "top-left"].includes(stored)) {
|
|
2132
|
+
return stored;
|
|
2133
|
+
}
|
|
2134
|
+
} catch {
|
|
2135
|
+
}
|
|
2136
|
+
return "bottom-right";
|
|
2137
|
+
});
|
|
2138
|
+
const [dragging, setDragging] = useState4(false);
|
|
2139
|
+
const [dragPos, setDragPos] = useState4(null);
|
|
2140
|
+
const [snapAnim, setSnapAnim] = useState4(null);
|
|
2141
|
+
const dragState = useRef2(null);
|
|
2142
|
+
const toolbarRef = useRef2(null);
|
|
2143
|
+
const [cameraHovered, setCameraHovered] = useState4(false);
|
|
2144
|
+
const cameraTooltipVisible = useTooltipDelay(cameraHovered && !!expanded);
|
|
2145
|
+
useEffect3(() => {
|
|
2146
|
+
if (!expanded) return;
|
|
2147
|
+
const onKey = (e) => {
|
|
2148
|
+
if (e.target?.tagName === "INPUT") {
|
|
2149
|
+
if (e.key === "Escape") {
|
|
2150
|
+
e.target.blur();
|
|
2151
|
+
}
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
if (e.key === "Escape") {
|
|
2155
|
+
if (historyOpen) {
|
|
2156
|
+
setHistoryOpen(false);
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
onCancel();
|
|
2160
|
+
} else if (e.key === "Enter") {
|
|
2161
|
+
onCapture(selectedMode);
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
document.addEventListener("keydown", onKey);
|
|
2165
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
2166
|
+
}, [expanded, onCancel, onCapture, selectedMode, historyOpen]);
|
|
2167
|
+
const handleMouseDown = useCallback3(
|
|
2168
|
+
(e) => {
|
|
2169
|
+
e.preventDefault();
|
|
2170
|
+
const el = toolbarRef.current;
|
|
2171
|
+
if (!el) return;
|
|
2172
|
+
const rect = el.getBoundingClientRect();
|
|
2173
|
+
setDragging(true);
|
|
2174
|
+
setDragPos({ x: rect.left, y: rect.top });
|
|
2175
|
+
dragState.current = {
|
|
2176
|
+
dragging: true,
|
|
2177
|
+
startX: e.clientX,
|
|
2178
|
+
startY: e.clientY,
|
|
2179
|
+
origX: rect.left,
|
|
2180
|
+
origY: rect.top,
|
|
2181
|
+
distance: 0
|
|
2182
|
+
};
|
|
2183
|
+
},
|
|
2184
|
+
[]
|
|
2185
|
+
);
|
|
2186
|
+
useEffect3(() => {
|
|
2187
|
+
const handleMouseMove = (e) => {
|
|
2188
|
+
const ds = dragState.current;
|
|
2189
|
+
if (!ds || !ds.dragging) return;
|
|
2190
|
+
const dx = e.clientX - ds.startX;
|
|
2191
|
+
const dy = e.clientY - ds.startY;
|
|
2192
|
+
ds.distance = Math.sqrt(dx * dx + dy * dy);
|
|
2193
|
+
setDragPos({
|
|
2194
|
+
x: ds.origX + dx,
|
|
2195
|
+
y: ds.origY + dy
|
|
2196
|
+
});
|
|
2197
|
+
};
|
|
2198
|
+
const handleMouseUp = (e) => {
|
|
2199
|
+
const ds = dragState.current;
|
|
2200
|
+
if (!ds) return;
|
|
2201
|
+
if (ds.distance < 5) {
|
|
2202
|
+
onToggle();
|
|
2203
|
+
setDragging(false);
|
|
2204
|
+
setDragPos(null);
|
|
2205
|
+
dragState.current = null;
|
|
2206
|
+
} else {
|
|
2207
|
+
const el = toolbarRef.current;
|
|
2208
|
+
const w = el?.offsetWidth ?? CONTAINER_SIZE;
|
|
2209
|
+
const h = el?.offsetHeight ?? CONTAINER_SIZE;
|
|
2210
|
+
const currentX = ds.origX + (e.clientX - ds.startX);
|
|
2211
|
+
const currentY = ds.origY + (e.clientY - ds.startY);
|
|
2212
|
+
const centerX = currentX + w / 2;
|
|
2213
|
+
const centerY = currentY + h / 2;
|
|
2214
|
+
const newCorner = snapToCorner(centerX, centerY);
|
|
2215
|
+
setCorner(newCorner);
|
|
2216
|
+
try {
|
|
2217
|
+
localStorage.setItem("ab-toolbar-corner", newCorner);
|
|
2218
|
+
} catch {
|
|
2219
|
+
}
|
|
2220
|
+
const targetPos = getCornerPosition(newCorner, w, h);
|
|
2221
|
+
setDragging(false);
|
|
2222
|
+
setDragPos(null);
|
|
2223
|
+
setSnapAnim({ x: currentX, y: currentY, animate: false });
|
|
2224
|
+
dragState.current = null;
|
|
2225
|
+
requestAnimationFrame(() => {
|
|
2226
|
+
requestAnimationFrame(() => {
|
|
2227
|
+
setSnapAnim({ ...targetPos, animate: true });
|
|
2228
|
+
setTimeout(() => setSnapAnim(null), 300);
|
|
2229
|
+
});
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
};
|
|
2233
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
2234
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
2235
|
+
return () => {
|
|
2236
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
2237
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
2238
|
+
};
|
|
2239
|
+
}, [onToggle]);
|
|
2240
|
+
const panelSide = isRightCorner(corner) ? "left" : "right";
|
|
2241
|
+
const tooltipSide = panelSide;
|
|
2242
|
+
const bottom = isBottomCorner(corner);
|
|
2243
|
+
const positionStyle = dragging && dragPos ? { left: dragPos.x, top: dragPos.y } : snapAnim ? {
|
|
2244
|
+
left: snapAnim.x,
|
|
2245
|
+
top: snapAnim.y,
|
|
2246
|
+
...snapAnim.animate && {
|
|
2247
|
+
transition: "left 0.3s cubic-bezier(0.23, 1, 0.32, 1), top 0.3s cubic-bezier(0.23, 1, 0.32, 1)"
|
|
2248
|
+
}
|
|
2249
|
+
} : getCornerStyle(corner);
|
|
2250
|
+
const cameraTooltipLabel = expanded ? "Close" : void 0;
|
|
2251
|
+
const cameraTooltipStyle = cameraTooltipLabel ? tooltipSide === "left" ? { right: "calc(100% + 10px)", top: "50%", transform: "translateY(-50%)" } : { left: "calc(100% + 10px)", top: "50%", transform: "translateY(-50%)" } : void 0;
|
|
2252
|
+
const cameraButton = /* @__PURE__ */ jsxs4("div", { style: { position: "relative" }, children: [
|
|
2253
|
+
cameraTooltipLabel && cameraTooltipVisible && !dragging && /* @__PURE__ */ jsx4(
|
|
2254
|
+
"div",
|
|
2255
|
+
{
|
|
2256
|
+
style: {
|
|
2257
|
+
position: "absolute",
|
|
2258
|
+
...cameraTooltipStyle,
|
|
2259
|
+
background: bg.base,
|
|
2260
|
+
border: `1px solid ${stroke.default}`,
|
|
2261
|
+
borderRadius: 6,
|
|
2262
|
+
padding: "0 8px",
|
|
2263
|
+
height: 24,
|
|
2264
|
+
display: "flex",
|
|
2265
|
+
alignItems: "center",
|
|
2266
|
+
color: fg.strong,
|
|
2267
|
+
...text.label.xs,
|
|
2268
|
+
whiteSpace: "nowrap",
|
|
2269
|
+
boxShadow: shadow.tooltip,
|
|
2270
|
+
pointerEvents: "none"
|
|
2271
|
+
},
|
|
2272
|
+
children: cameraTooltipLabel
|
|
2273
|
+
}
|
|
2111
2274
|
),
|
|
2112
|
-
|
|
2113
|
-
|
|
2275
|
+
/* @__PURE__ */ jsxs4(
|
|
2276
|
+
"div",
|
|
2277
|
+
{
|
|
2278
|
+
onMouseDown: handleMouseDown,
|
|
2279
|
+
onMouseEnter: () => setCameraHovered(true),
|
|
2280
|
+
onMouseLeave: () => setCameraHovered(false),
|
|
2281
|
+
style: {
|
|
2282
|
+
width: 32,
|
|
2283
|
+
height: 32,
|
|
2284
|
+
padding: 0,
|
|
2285
|
+
borderRadius: "50%",
|
|
2286
|
+
display: "flex",
|
|
2287
|
+
alignItems: "center",
|
|
2288
|
+
justifyContent: "center",
|
|
2289
|
+
cursor: dragging ? "grabbing" : "pointer",
|
|
2290
|
+
background: expanded && cameraHovered ? state.hoverStrong : "transparent",
|
|
2291
|
+
transition: "background 0.12s ease"
|
|
2292
|
+
},
|
|
2293
|
+
children: [
|
|
2294
|
+
/* @__PURE__ */ jsx4(
|
|
2295
|
+
"style",
|
|
2296
|
+
{
|
|
2297
|
+
dangerouslySetInnerHTML: {
|
|
2298
|
+
__html: `
|
|
2299
|
+
@keyframes ab-spin {
|
|
2300
|
+
0% { transform: rotate(0deg); }
|
|
2301
|
+
100% { transform: rotate(360deg); }
|
|
2302
|
+
}
|
|
2303
|
+
@keyframes ab-panel-in {
|
|
2304
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
2305
|
+
to { opacity: 1; transform: translateY(0); }
|
|
2306
|
+
}
|
|
2307
|
+
`
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
),
|
|
2311
|
+
loading ? /* @__PURE__ */ jsx4(
|
|
2312
|
+
LoaderCircle,
|
|
2313
|
+
{
|
|
2314
|
+
size: 16,
|
|
2315
|
+
strokeWidth: 2,
|
|
2316
|
+
style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
|
|
2317
|
+
}
|
|
2318
|
+
) : phase === "ready" ? /* @__PURE__ */ jsx4(CheckmarkIcon, { size: 20, color: fg.default }) : expanded ? /* @__PURE__ */ jsx4(
|
|
2319
|
+
CloseIcon,
|
|
2320
|
+
{
|
|
2321
|
+
size: 20,
|
|
2322
|
+
color: cameraHovered ? fg.strong : fg.default
|
|
2323
|
+
}
|
|
2324
|
+
) : /* @__PURE__ */ jsx4(
|
|
2325
|
+
CameraIcon,
|
|
2326
|
+
{
|
|
2327
|
+
size: 20,
|
|
2328
|
+
color: cameraHovered ? fg.strong : fg.default
|
|
2329
|
+
}
|
|
2330
|
+
)
|
|
2331
|
+
]
|
|
2332
|
+
}
|
|
2333
|
+
)
|
|
2334
|
+
] });
|
|
2335
|
+
const toolbarButtons = buttonsVisible ? /* @__PURE__ */ jsx4(
|
|
2336
|
+
"div",
|
|
2337
|
+
{
|
|
2338
|
+
style: {
|
|
2339
|
+
overflow: animDone ? "visible" : "hidden",
|
|
2340
|
+
maxHeight: animIn ? 195 : 0,
|
|
2341
|
+
transition: animIn ? "max-height 250ms cubic-bezier(0.23, 1, 0.32, 1)" : "max-height 150ms cubic-bezier(0.23, 1, 0.32, 1)"
|
|
2342
|
+
},
|
|
2343
|
+
children: /* @__PURE__ */ jsxs4(
|
|
2114
2344
|
"div",
|
|
2115
2345
|
{
|
|
2116
|
-
"data-afterbefore": "true",
|
|
2117
|
-
onClick: () => setLightboxSrc(null),
|
|
2118
|
-
onKeyDown: (e) => {
|
|
2119
|
-
if (e.key === "Escape") setLightboxSrc(null);
|
|
2120
|
-
},
|
|
2121
2346
|
style: {
|
|
2122
|
-
position: "fixed",
|
|
2123
|
-
inset: 0,
|
|
2124
|
-
zIndex: 2147483647,
|
|
2125
|
-
background: "rgba(0, 0, 0, 0.85)",
|
|
2126
2347
|
display: "flex",
|
|
2348
|
+
flexDirection: "column",
|
|
2127
2349
|
alignItems: "center",
|
|
2128
|
-
|
|
2129
|
-
|
|
2350
|
+
opacity: animIn ? 1 : 0,
|
|
2351
|
+
transform: animIn ? "translateY(0)" : `translateY(${bottom ? 6 : -6}px)`,
|
|
2352
|
+
transition: animIn ? "opacity 200ms cubic-bezier(0.23, 1, 0.32, 1), transform 200ms cubic-bezier(0.23, 1, 0.32, 1)" : "opacity 150ms cubic-bezier(0.23, 1, 0.32, 1), transform 150ms cubic-bezier(0.23, 1, 0.32, 1)",
|
|
2353
|
+
willChange: "transform, opacity"
|
|
2130
2354
|
},
|
|
2131
2355
|
children: [
|
|
2132
|
-
/* @__PURE__ */
|
|
2133
|
-
|
|
2356
|
+
/* @__PURE__ */ jsx4("div", { style: { paddingBottom: 2 }, children: /* @__PURE__ */ jsx4(
|
|
2357
|
+
IconButton,
|
|
2358
|
+
{
|
|
2359
|
+
active: selectedMode === "component" && !historyOpen,
|
|
2360
|
+
tooltipSide,
|
|
2361
|
+
tooltip: "Component",
|
|
2362
|
+
onClick: () => {
|
|
2363
|
+
setHistoryOpen(false);
|
|
2364
|
+
onModeChange("component");
|
|
2365
|
+
},
|
|
2366
|
+
children: /* @__PURE__ */ jsx4(CameraIcon, { size: 20 })
|
|
2367
|
+
}
|
|
2368
|
+
) }),
|
|
2369
|
+
MODES.filter((m) => m.mode !== "component").map(({ mode, label, icon: ModeIcon }) => /* @__PURE__ */ jsx4(
|
|
2370
|
+
"div",
|
|
2134
2371
|
{
|
|
2135
|
-
src: lightboxSrc,
|
|
2136
|
-
alt: "",
|
|
2137
|
-
onClick: (e) => e.stopPropagation(),
|
|
2138
2372
|
style: {
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2373
|
+
maxHeight: modesExpanded ? 34 : 0,
|
|
2374
|
+
opacity: modesExpanded ? 1 : 0,
|
|
2375
|
+
transition: "max-height 200ms cubic-bezier(0.23, 1, 0.32, 1), opacity 150ms cubic-bezier(0.23, 1, 0.32, 1)"
|
|
2376
|
+
},
|
|
2377
|
+
children: /* @__PURE__ */ jsx4(
|
|
2378
|
+
IconButton,
|
|
2379
|
+
{
|
|
2380
|
+
active: selectedMode === mode && !historyOpen,
|
|
2381
|
+
tooltipSide,
|
|
2382
|
+
tooltip: label,
|
|
2383
|
+
onClick: () => {
|
|
2384
|
+
setHistoryOpen(false);
|
|
2385
|
+
onModeChange(mode);
|
|
2386
|
+
onCapture(mode);
|
|
2387
|
+
},
|
|
2388
|
+
children: /* @__PURE__ */ jsx4(ModeIcon, { size: 16, strokeWidth: 1.7 })
|
|
2389
|
+
}
|
|
2390
|
+
)
|
|
2391
|
+
},
|
|
2392
|
+
mode
|
|
2393
|
+
)),
|
|
2394
|
+
/* @__PURE__ */ jsx4(
|
|
2395
|
+
Separator,
|
|
2396
|
+
{
|
|
2397
|
+
vertical: false,
|
|
2398
|
+
onClick: () => setModesExpanded((p) => !p)
|
|
2145
2399
|
}
|
|
2146
2400
|
),
|
|
2147
|
-
/* @__PURE__ */
|
|
2148
|
-
|
|
2401
|
+
/* @__PURE__ */ jsx4(
|
|
2402
|
+
ScreenshotsPanel,
|
|
2149
2403
|
{
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
top: 16,
|
|
2154
|
-
right: 16,
|
|
2155
|
-
width: 32,
|
|
2156
|
-
height: 32,
|
|
2157
|
-
borderRadius: "50%",
|
|
2158
|
-
border: "none",
|
|
2159
|
-
background: state.pressed,
|
|
2160
|
-
color: "white",
|
|
2161
|
-
cursor: "pointer",
|
|
2162
|
-
display: "flex",
|
|
2163
|
-
alignItems: "center",
|
|
2164
|
-
justifyContent: "center",
|
|
2165
|
-
padding: 0
|
|
2404
|
+
open: historyOpen,
|
|
2405
|
+
onClick: () => {
|
|
2406
|
+
setHistoryOpen((prev) => !prev);
|
|
2166
2407
|
},
|
|
2167
|
-
|
|
2408
|
+
selectedMode,
|
|
2409
|
+
frameSettings,
|
|
2410
|
+
onFrameSettingsChange,
|
|
2411
|
+
tooltipSide
|
|
2168
2412
|
}
|
|
2169
2413
|
)
|
|
2170
2414
|
]
|
|
2171
2415
|
}
|
|
2172
|
-
)
|
|
2173
|
-
|
|
2416
|
+
)
|
|
2417
|
+
}
|
|
2418
|
+
) : null;
|
|
2419
|
+
return /* @__PURE__ */ jsx4(
|
|
2420
|
+
"div",
|
|
2421
|
+
{
|
|
2422
|
+
ref: toolbarRef,
|
|
2423
|
+
"data-afterbefore": "true",
|
|
2424
|
+
style: {
|
|
2425
|
+
position: "fixed",
|
|
2426
|
+
...positionStyle,
|
|
2427
|
+
zIndex: 2147483647,
|
|
2428
|
+
display: "flex",
|
|
2429
|
+
flexDirection: "column",
|
|
2430
|
+
alignItems: "center",
|
|
2431
|
+
background: bg.base,
|
|
2432
|
+
borderRadius: 999,
|
|
2433
|
+
padding: 6,
|
|
2434
|
+
boxShadow: shadow.toolbar,
|
|
2435
|
+
...fontBase,
|
|
2436
|
+
userSelect: "none"
|
|
2437
|
+
},
|
|
2438
|
+
children: bottom ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
2439
|
+
toolbarButtons,
|
|
2440
|
+
cameraButton
|
|
2441
|
+
] }) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
2442
|
+
cameraButton,
|
|
2443
|
+
toolbarButtons
|
|
2444
|
+
] })
|
|
2445
|
+
}
|
|
2446
|
+
);
|
|
2447
|
+
}
|
|
2448
|
+
function IconButton({
|
|
2449
|
+
children,
|
|
2450
|
+
active,
|
|
2451
|
+
tooltip,
|
|
2452
|
+
tooltipSide = "left",
|
|
2453
|
+
onClick
|
|
2454
|
+
}) {
|
|
2455
|
+
const [hovered, setHovered] = useState4(false);
|
|
2456
|
+
const tooltipVisible = useTooltipDelay(hovered && !!tooltip);
|
|
2457
|
+
const tooltipStyle = tooltipSide === "left" ? {
|
|
2458
|
+
right: "calc(100% + 10px)",
|
|
2459
|
+
top: "50%",
|
|
2460
|
+
transform: "translateY(-50%)"
|
|
2461
|
+
} : {
|
|
2462
|
+
left: "calc(100% + 10px)",
|
|
2463
|
+
top: "50%",
|
|
2464
|
+
transform: "translateY(-50%)"
|
|
2465
|
+
};
|
|
2466
|
+
return /* @__PURE__ */ jsxs4("div", { style: { position: "relative" }, children: [
|
|
2467
|
+
tooltip && tooltipVisible && /* @__PURE__ */ jsx4(
|
|
2468
|
+
"div",
|
|
2469
|
+
{
|
|
2470
|
+
style: {
|
|
2471
|
+
position: "absolute",
|
|
2472
|
+
...tooltipStyle,
|
|
2473
|
+
background: bg.base,
|
|
2474
|
+
border: `1px solid ${stroke.default}`,
|
|
2475
|
+
borderRadius: 6,
|
|
2476
|
+
padding: "0 8px",
|
|
2477
|
+
height: 24,
|
|
2478
|
+
display: "flex",
|
|
2479
|
+
alignItems: "center",
|
|
2480
|
+
color: fg.strong,
|
|
2481
|
+
...text.label.xs,
|
|
2482
|
+
whiteSpace: "nowrap",
|
|
2483
|
+
boxShadow: shadow.tooltip,
|
|
2484
|
+
pointerEvents: "none"
|
|
2485
|
+
},
|
|
2486
|
+
children: tooltip
|
|
2487
|
+
}
|
|
2488
|
+
),
|
|
2489
|
+
/* @__PURE__ */ jsx4(
|
|
2490
|
+
"button",
|
|
2491
|
+
{
|
|
2492
|
+
onClick,
|
|
2493
|
+
onMouseEnter: () => setHovered(true),
|
|
2494
|
+
onMouseLeave: () => setHovered(false),
|
|
2495
|
+
style: {
|
|
2496
|
+
width: 32,
|
|
2497
|
+
height: 32,
|
|
2498
|
+
borderRadius: "50%",
|
|
2499
|
+
border: "none",
|
|
2500
|
+
background: active || hovered ? state.hoverStrong : "transparent",
|
|
2501
|
+
display: "flex",
|
|
2502
|
+
alignItems: "center",
|
|
2503
|
+
justifyContent: "center",
|
|
2504
|
+
cursor: "pointer",
|
|
2505
|
+
padding: 0,
|
|
2506
|
+
color: active || hovered ? fg.strong : fg.default,
|
|
2507
|
+
transition: "background 0.12s ease, color 0.12s ease"
|
|
2508
|
+
},
|
|
2509
|
+
children
|
|
2510
|
+
}
|
|
2174
2511
|
)
|
|
2175
2512
|
] });
|
|
2176
2513
|
}
|
|
2514
|
+
function DropItem2({
|
|
2515
|
+
children,
|
|
2516
|
+
onClick,
|
|
2517
|
+
active,
|
|
2518
|
+
accent: accent2
|
|
2519
|
+
}) {
|
|
2520
|
+
return /* @__PURE__ */ jsx4(
|
|
2521
|
+
"button",
|
|
2522
|
+
{
|
|
2523
|
+
onClick,
|
|
2524
|
+
style: {
|
|
2525
|
+
display: "block",
|
|
2526
|
+
width: "100%",
|
|
2527
|
+
padding: "7px 12px",
|
|
2528
|
+
background: active ? state.active : "transparent",
|
|
2529
|
+
border: "none",
|
|
2530
|
+
color: accent2 ? accent.highlight : fg.strong,
|
|
2531
|
+
textAlign: "left",
|
|
2532
|
+
cursor: "pointer",
|
|
2533
|
+
...text.paragraph.sm,
|
|
2534
|
+
fontFamily: "inherit"
|
|
2535
|
+
},
|
|
2536
|
+
children
|
|
2537
|
+
}
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
function Separator({
|
|
2541
|
+
vertical = true,
|
|
2542
|
+
onClick
|
|
2543
|
+
}) {
|
|
2544
|
+
return /* @__PURE__ */ jsx4(
|
|
2545
|
+
"div",
|
|
2546
|
+
{
|
|
2547
|
+
onClick,
|
|
2548
|
+
style: {
|
|
2549
|
+
position: "relative",
|
|
2550
|
+
width: vertical ? 1 : 24,
|
|
2551
|
+
height: vertical ? 18 : 1,
|
|
2552
|
+
background: stroke.strong,
|
|
2553
|
+
flexShrink: 0,
|
|
2554
|
+
margin: vertical ? "0 6px" : "6px 0",
|
|
2555
|
+
cursor: onClick ? "pointer" : void 0
|
|
2556
|
+
},
|
|
2557
|
+
children: onClick && /* @__PURE__ */ jsx4("div", { style: { position: "absolute", inset: vertical ? "0 -8px" : "-8px 0" } })
|
|
2558
|
+
}
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2177
2561
|
function FilterDropdown({
|
|
2178
2562
|
label,
|
|
2179
2563
|
value,
|
|
@@ -2182,20 +2566,20 @@ function FilterDropdown({
|
|
|
2182
2566
|
onToggle,
|
|
2183
2567
|
onSelect
|
|
2184
2568
|
}) {
|
|
2185
|
-
return /* @__PURE__ */
|
|
2186
|
-
/* @__PURE__ */
|
|
2569
|
+
return /* @__PURE__ */ jsxs4("div", { children: [
|
|
2570
|
+
/* @__PURE__ */ jsx4(
|
|
2187
2571
|
"div",
|
|
2188
2572
|
{
|
|
2189
2573
|
style: {
|
|
2190
2574
|
...text.subheading.xxs,
|
|
2191
|
-
color: fg.
|
|
2575
|
+
color: fg.sub,
|
|
2192
2576
|
marginBottom: 3
|
|
2193
2577
|
},
|
|
2194
2578
|
children: label
|
|
2195
2579
|
}
|
|
2196
2580
|
),
|
|
2197
|
-
/* @__PURE__ */
|
|
2198
|
-
/* @__PURE__ */
|
|
2581
|
+
/* @__PURE__ */ jsxs4("div", { style: { position: "relative" }, children: [
|
|
2582
|
+
/* @__PURE__ */ jsxs4(
|
|
2199
2583
|
"button",
|
|
2200
2584
|
{
|
|
2201
2585
|
onClick: onToggle,
|
|
@@ -2216,7 +2600,7 @@ function FilterDropdown({
|
|
|
2216
2600
|
fontFamily: "inherit"
|
|
2217
2601
|
},
|
|
2218
2602
|
children: [
|
|
2219
|
-
/* @__PURE__ */
|
|
2603
|
+
/* @__PURE__ */ jsx4(
|
|
2220
2604
|
"span",
|
|
2221
2605
|
{
|
|
2222
2606
|
style: {
|
|
@@ -2227,11 +2611,11 @@ function FilterDropdown({
|
|
|
2227
2611
|
children: value || "\u2014"
|
|
2228
2612
|
}
|
|
2229
2613
|
),
|
|
2230
|
-
/* @__PURE__ */
|
|
2614
|
+
/* @__PURE__ */ jsx4(ChevronDown2, { size: 12, strokeWidth: 2 })
|
|
2231
2615
|
]
|
|
2232
2616
|
}
|
|
2233
2617
|
),
|
|
2234
|
-
isOpen && options.length > 0 && /* @__PURE__ */
|
|
2618
|
+
isOpen && options.length > 0 && /* @__PURE__ */ jsx4(
|
|
2235
2619
|
"div",
|
|
2236
2620
|
{
|
|
2237
2621
|
style: {
|
|
@@ -2248,7 +2632,7 @@ function FilterDropdown({
|
|
|
2248
2632
|
boxShadow: shadow.dropdown,
|
|
2249
2633
|
zIndex: 1
|
|
2250
2634
|
},
|
|
2251
|
-
children: options.map((opt) => /* @__PURE__ */
|
|
2635
|
+
children: options.map((opt) => /* @__PURE__ */ jsx4(
|
|
2252
2636
|
DropItem2,
|
|
2253
2637
|
{
|
|
2254
2638
|
active: opt === value,
|
|
@@ -2262,61 +2646,15 @@ function FilterDropdown({
|
|
|
2262
2646
|
] })
|
|
2263
2647
|
] });
|
|
2264
2648
|
}
|
|
2265
|
-
function ActionButton({
|
|
2266
|
-
children,
|
|
2267
|
-
onClick,
|
|
2268
|
-
disabled
|
|
2269
|
-
}) {
|
|
2270
|
-
const [hovered, setHovered] = useState3(false);
|
|
2271
|
-
return /* @__PURE__ */ jsx2(
|
|
2272
|
-
"button",
|
|
2273
|
-
{
|
|
2274
|
-
onClick,
|
|
2275
|
-
disabled,
|
|
2276
|
-
onMouseEnter: () => setHovered(true),
|
|
2277
|
-
onMouseLeave: () => setHovered(false),
|
|
2278
|
-
style: {
|
|
2279
|
-
display: "flex",
|
|
2280
|
-
alignItems: "center",
|
|
2281
|
-
gap: 6,
|
|
2282
|
-
width: "100%",
|
|
2283
|
-
padding: "6px 8px",
|
|
2284
|
-
border: "none",
|
|
2285
|
-
background: hovered ? state.active : "transparent",
|
|
2286
|
-
color: fg.default,
|
|
2287
|
-
...text.label.xs,
|
|
2288
|
-
borderRadius: 6,
|
|
2289
|
-
cursor: disabled ? "wait" : "pointer",
|
|
2290
|
-
textAlign: "left",
|
|
2291
|
-
fontFamily: "inherit",
|
|
2292
|
-
transition: "background 0.1s ease"
|
|
2293
|
-
},
|
|
2294
|
-
children
|
|
2295
|
-
}
|
|
2296
|
-
);
|
|
2297
|
-
}
|
|
2298
|
-
function formatTimestamp(filename) {
|
|
2299
|
-
const iso = filename.replace(/\.png$/, "").replace(/T(\d{2})-(\d{2})-(\d{2})-(\d+)Z$/, "T$1:$2:$3.$4Z");
|
|
2300
|
-
const date = new Date(iso);
|
|
2301
|
-
if (Number.isNaN(date.getTime())) return filename.replace(/\.png$/, "");
|
|
2302
|
-
const now = /* @__PURE__ */ new Date();
|
|
2303
|
-
const diffMs = now.getTime() - date.getTime();
|
|
2304
|
-
const diffMin = Math.floor(diffMs / 6e4);
|
|
2305
|
-
if (diffMin < 1) return "Just now";
|
|
2306
|
-
if (diffMin < 60) return `${diffMin}m ago`;
|
|
2307
|
-
const diffHr = Math.floor(diffMin / 60);
|
|
2308
|
-
if (diffHr < 24) return `${diffHr}h ago`;
|
|
2309
|
-
return date.toLocaleDateString(void 0, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
2310
|
-
}
|
|
2311
2649
|
|
|
2312
2650
|
// src/overlay/ui/inspector.tsx
|
|
2313
|
-
import { useEffect as
|
|
2314
|
-
import { jsx as
|
|
2651
|
+
import { useEffect as useEffect4, useRef as useRef3, useCallback as useCallback4, useState as useState5 } from "react";
|
|
2652
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
2315
2653
|
function Inspector({ onSelect, onCancel }) {
|
|
2316
|
-
const [highlight, setHighlight] =
|
|
2654
|
+
const [highlight, setHighlight] = useState5(null);
|
|
2317
2655
|
const hoveredEl = useRef3(null);
|
|
2318
2656
|
const styleEl = useRef3(null);
|
|
2319
|
-
|
|
2657
|
+
useEffect4(() => {
|
|
2320
2658
|
const style2 = document.createElement("style");
|
|
2321
2659
|
style2.setAttribute("data-afterbefore", "true");
|
|
2322
2660
|
style2.textContent = [
|
|
@@ -2331,7 +2669,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
2331
2669
|
style2.remove();
|
|
2332
2670
|
};
|
|
2333
2671
|
}, []);
|
|
2334
|
-
const isOverlayElement =
|
|
2672
|
+
const isOverlayElement = useCallback4((el) => {
|
|
2335
2673
|
let node = el;
|
|
2336
2674
|
while (node) {
|
|
2337
2675
|
if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
|
|
@@ -2339,7 +2677,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
2339
2677
|
}
|
|
2340
2678
|
return false;
|
|
2341
2679
|
}, []);
|
|
2342
|
-
const handleMouseMove =
|
|
2680
|
+
const handleMouseMove = useCallback4(
|
|
2343
2681
|
(e) => {
|
|
2344
2682
|
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
2345
2683
|
if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {
|
|
@@ -2358,7 +2696,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
2358
2696
|
},
|
|
2359
2697
|
[isOverlayElement]
|
|
2360
2698
|
);
|
|
2361
|
-
const handleClick =
|
|
2699
|
+
const handleClick = useCallback4(
|
|
2362
2700
|
(e) => {
|
|
2363
2701
|
if (isOverlayElement(e.target)) return;
|
|
2364
2702
|
e.preventDefault();
|
|
@@ -2370,7 +2708,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
2370
2708
|
},
|
|
2371
2709
|
[onSelect, isOverlayElement]
|
|
2372
2710
|
);
|
|
2373
|
-
const handleKeyDown =
|
|
2711
|
+
const handleKeyDown = useCallback4(
|
|
2374
2712
|
(e) => {
|
|
2375
2713
|
if (e.key === "Escape") {
|
|
2376
2714
|
onCancel();
|
|
@@ -2378,7 +2716,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
2378
2716
|
},
|
|
2379
2717
|
[onCancel]
|
|
2380
2718
|
);
|
|
2381
|
-
|
|
2719
|
+
useEffect4(() => {
|
|
2382
2720
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
2383
2721
|
document.addEventListener("click", handleClick, true);
|
|
2384
2722
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -2388,7 +2726,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
2388
2726
|
document.removeEventListener("keydown", handleKeyDown);
|
|
2389
2727
|
};
|
|
2390
2728
|
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
2391
|
-
return /* @__PURE__ */
|
|
2729
|
+
return /* @__PURE__ */ jsx5("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: highlight && /* @__PURE__ */ jsx5(
|
|
2392
2730
|
"div",
|
|
2393
2731
|
{
|
|
2394
2732
|
style: {
|
|
@@ -2408,7 +2746,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
2408
2746
|
}
|
|
2409
2747
|
|
|
2410
2748
|
// src/overlay/index.tsx
|
|
2411
|
-
import { jsx as
|
|
2749
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2412
2750
|
async function saveCapture(mode, dataUrl) {
|
|
2413
2751
|
try {
|
|
2414
2752
|
const res = await fetch("/__afterbefore/save", {
|
|
@@ -2426,15 +2764,15 @@ async function saveCapture(mode, dataUrl) {
|
|
|
2426
2764
|
}
|
|
2427
2765
|
function AfterBefore() {
|
|
2428
2766
|
const { state: state2, captureComplete, reset } = useOverlayState();
|
|
2429
|
-
const [toolbarActive, setToolbarActive] =
|
|
2430
|
-
const [inspectorActive, setInspectorActive] =
|
|
2431
|
-
const [loading, setLoading] =
|
|
2432
|
-
const [selectedMode, setSelectedMode] =
|
|
2433
|
-
const [frameSettings, setFrameSettings] =
|
|
2434
|
-
|
|
2767
|
+
const [toolbarActive, setToolbarActive] = useState6(false);
|
|
2768
|
+
const [inspectorActive, setInspectorActive] = useState6(false);
|
|
2769
|
+
const [loading, setLoading] = useState6(false);
|
|
2770
|
+
const [selectedMode, setSelectedMode] = useState6("component");
|
|
2771
|
+
const [frameSettings, setFrameSettings] = useState6(DEFAULT_FRAME_SETTINGS);
|
|
2772
|
+
useEffect5(() => {
|
|
2435
2773
|
injectInterFont();
|
|
2436
2774
|
}, []);
|
|
2437
|
-
|
|
2775
|
+
useEffect5(() => {
|
|
2438
2776
|
try {
|
|
2439
2777
|
const stored = localStorage.getItem("ab-frame-settings");
|
|
2440
2778
|
if (stored) {
|
|
@@ -2449,7 +2787,7 @@ function AfterBefore() {
|
|
|
2449
2787
|
setFrameSettings(DEFAULT_FRAME_SETTINGS);
|
|
2450
2788
|
}
|
|
2451
2789
|
}, []);
|
|
2452
|
-
|
|
2790
|
+
useEffect5(() => {
|
|
2453
2791
|
if (state2.phase === "ready") {
|
|
2454
2792
|
const timer = setTimeout(() => {
|
|
2455
2793
|
reset();
|
|
@@ -2457,7 +2795,7 @@ function AfterBefore() {
|
|
|
2457
2795
|
return () => clearTimeout(timer);
|
|
2458
2796
|
}
|
|
2459
2797
|
}, [state2.phase, reset]);
|
|
2460
|
-
const handleToggle =
|
|
2798
|
+
const handleToggle = useCallback5(() => {
|
|
2461
2799
|
if (loading) return;
|
|
2462
2800
|
if (state2.phase === "ready") {
|
|
2463
2801
|
reset();
|
|
@@ -2475,7 +2813,7 @@ function AfterBefore() {
|
|
|
2475
2813
|
}
|
|
2476
2814
|
}
|
|
2477
2815
|
}, [state2.phase, loading, toolbarActive, inspectorActive, selectedMode, reset]);
|
|
2478
|
-
const performCapture =
|
|
2816
|
+
const performCapture = useCallback5(
|
|
2479
2817
|
async (mode, element) => {
|
|
2480
2818
|
setLoading(true);
|
|
2481
2819
|
try {
|
|
@@ -2494,7 +2832,7 @@ function AfterBefore() {
|
|
|
2494
2832
|
},
|
|
2495
2833
|
[captureComplete, frameSettings]
|
|
2496
2834
|
);
|
|
2497
|
-
const handleToolbarCapture =
|
|
2835
|
+
const handleToolbarCapture = useCallback5(
|
|
2498
2836
|
(mode) => {
|
|
2499
2837
|
if (mode === "viewport") {
|
|
2500
2838
|
setToolbarActive(false);
|
|
@@ -2508,11 +2846,11 @@ function AfterBefore() {
|
|
|
2508
2846
|
},
|
|
2509
2847
|
[performCapture]
|
|
2510
2848
|
);
|
|
2511
|
-
const handleToolbarCancel =
|
|
2849
|
+
const handleToolbarCancel = useCallback5(() => {
|
|
2512
2850
|
setToolbarActive(false);
|
|
2513
2851
|
setInspectorActive(false);
|
|
2514
2852
|
}, []);
|
|
2515
|
-
const handleComponentSelect =
|
|
2853
|
+
const handleComponentSelect = useCallback5(
|
|
2516
2854
|
(element) => {
|
|
2517
2855
|
setInspectorActive(false);
|
|
2518
2856
|
setToolbarActive(false);
|
|
@@ -2520,23 +2858,23 @@ function AfterBefore() {
|
|
|
2520
2858
|
},
|
|
2521
2859
|
[performCapture]
|
|
2522
2860
|
);
|
|
2523
|
-
const handleComponentCancel =
|
|
2861
|
+
const handleComponentCancel = useCallback5(() => {
|
|
2524
2862
|
setInspectorActive(false);
|
|
2525
2863
|
setToolbarActive(true);
|
|
2526
2864
|
}, []);
|
|
2527
|
-
const handleFrameSettingsChange =
|
|
2865
|
+
const handleFrameSettingsChange = useCallback5((next) => {
|
|
2528
2866
|
setFrameSettings(next);
|
|
2529
2867
|
try {
|
|
2530
2868
|
localStorage.setItem("ab-frame-settings", JSON.stringify(next));
|
|
2531
2869
|
} catch {
|
|
2532
2870
|
}
|
|
2533
2871
|
}, []);
|
|
2534
|
-
const handleModeChange =
|
|
2872
|
+
const handleModeChange = useCallback5((mode) => {
|
|
2535
2873
|
setSelectedMode(mode);
|
|
2536
2874
|
setInspectorActive(mode === "component");
|
|
2537
2875
|
}, []);
|
|
2538
|
-
return /* @__PURE__ */
|
|
2539
|
-
/* @__PURE__ */
|
|
2876
|
+
return /* @__PURE__ */ jsxs5("div", { "data-afterbefore": "true", children: [
|
|
2877
|
+
/* @__PURE__ */ jsx6(
|
|
2540
2878
|
Toolbar,
|
|
2541
2879
|
{
|
|
2542
2880
|
expanded: toolbarActive,
|
|
@@ -2551,7 +2889,7 @@ function AfterBefore() {
|
|
|
2551
2889
|
onFrameSettingsChange: handleFrameSettingsChange
|
|
2552
2890
|
}
|
|
2553
2891
|
),
|
|
2554
|
-
inspectorActive && /* @__PURE__ */
|
|
2892
|
+
inspectorActive && /* @__PURE__ */ jsx6(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel })
|
|
2555
2893
|
] });
|
|
2556
2894
|
}
|
|
2557
2895
|
export {
|