afterbefore 0.2.20 → 0.2.22
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 +931 -625
- package/dist/overlay/index.js.map +1 -1
- package/package.json +1 -1
package/dist/overlay/index.js
CHANGED
|
@@ -10,7 +10,7 @@ var initialState = {
|
|
|
10
10
|
lastCapture: null
|
|
11
11
|
};
|
|
12
12
|
function useOverlayState() {
|
|
13
|
-
const [
|
|
13
|
+
const [state2, setState] = useState(initialState);
|
|
14
14
|
const captureComplete = useCallback(
|
|
15
15
|
(result) => {
|
|
16
16
|
setState({ phase: "ready", lastCapture: result });
|
|
@@ -20,7 +20,7 @@ function useOverlayState() {
|
|
|
20
20
|
const reset = useCallback(() => {
|
|
21
21
|
setState(initialState);
|
|
22
22
|
}, []);
|
|
23
|
-
return { state, captureComplete, reset };
|
|
23
|
+
return { state: state2, captureComplete, reset };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// src/overlay/capture.ts
|
|
@@ -31,7 +31,9 @@ var DEFAULT_FRAME_SETTINGS = {
|
|
|
31
31
|
bgType: "color",
|
|
32
32
|
bgColor: "#000000",
|
|
33
33
|
bgImage: null,
|
|
34
|
-
padding: 40
|
|
34
|
+
padding: 40,
|
|
35
|
+
browserChrome: false,
|
|
36
|
+
browserTheme: "dark"
|
|
35
37
|
};
|
|
36
38
|
var FRAME_SIZE_PRESETS = [
|
|
37
39
|
{ label: "1920 x 1080", hint: "Desktop / HD", w: 1920, h: 1080 },
|
|
@@ -62,7 +64,7 @@ async function toPngDataUrl(el, opts) {
|
|
|
62
64
|
async function capture(options) {
|
|
63
65
|
const { mode, element } = options;
|
|
64
66
|
if (mode === "viewport") {
|
|
65
|
-
return captureViewport();
|
|
67
|
+
return captureViewport(options.frameSettings);
|
|
66
68
|
}
|
|
67
69
|
if (mode === "fullpage") {
|
|
68
70
|
return captureFullPage();
|
|
@@ -72,19 +74,19 @@ async function capture(options) {
|
|
|
72
74
|
}
|
|
73
75
|
throw new Error(`Invalid capture mode: ${mode}`);
|
|
74
76
|
}
|
|
75
|
-
async function captureViewport() {
|
|
77
|
+
async function captureViewport(frameSettings) {
|
|
76
78
|
const dpr = window.devicePixelRatio || 1;
|
|
77
79
|
const vw = window.innerWidth;
|
|
78
80
|
const vh = window.innerHeight;
|
|
79
81
|
const scrollY = window.scrollY;
|
|
80
82
|
const fullDataUrl = await captureFullPage();
|
|
81
|
-
const
|
|
83
|
+
const fullImg = await loadImage(fullDataUrl);
|
|
82
84
|
const canvas = document.createElement("canvas");
|
|
83
85
|
canvas.width = vw * dpr;
|
|
84
86
|
canvas.height = vh * dpr;
|
|
85
87
|
const ctx = canvas.getContext("2d");
|
|
86
88
|
ctx.drawImage(
|
|
87
|
-
|
|
89
|
+
fullImg,
|
|
88
90
|
0,
|
|
89
91
|
scrollY * dpr,
|
|
90
92
|
vw * dpr,
|
|
@@ -94,8 +96,77 @@ async function captureViewport() {
|
|
|
94
96
|
vw * dpr,
|
|
95
97
|
vh * dpr
|
|
96
98
|
);
|
|
99
|
+
const viewportDataUrl = canvas.toDataURL("image/png");
|
|
100
|
+
if (!frameSettings?.browserChrome) {
|
|
101
|
+
return viewportDataUrl;
|
|
102
|
+
}
|
|
103
|
+
const viewportImg = await loadImage(viewportDataUrl);
|
|
104
|
+
return drawBrowserChrome(viewportImg, frameSettings.browserTheme, dpr);
|
|
105
|
+
}
|
|
106
|
+
function drawBrowserChrome(img, theme, dpr) {
|
|
107
|
+
const TITLE_BAR_H = 40;
|
|
108
|
+
const URL_BAR_H = 28;
|
|
109
|
+
const URL_BAR_MARGIN_TOP = 6;
|
|
110
|
+
const URL_BAR_MARGIN_BOTTOM = 6;
|
|
111
|
+
const CHROME_H = TITLE_BAR_H + URL_BAR_H + URL_BAR_MARGIN_TOP + URL_BAR_MARGIN_BOTTOM;
|
|
112
|
+
const imgW = img.width;
|
|
113
|
+
const imgH = img.height;
|
|
114
|
+
const canvas = document.createElement("canvas");
|
|
115
|
+
canvas.width = imgW;
|
|
116
|
+
canvas.height = imgH + CHROME_H * dpr;
|
|
117
|
+
const ctx = canvas.getContext("2d");
|
|
118
|
+
const colors = theme === "dark" ? { titleBar: "#1C1C1C", urlBar: "#262626", text: "#7B7B7B", border: "#333333" } : { titleBar: "#F5F5F5", urlBar: "#FFFFFF", text: "#999999", border: "#EBEBEB" };
|
|
119
|
+
ctx.fillStyle = colors.titleBar;
|
|
120
|
+
ctx.fillRect(0, 0, canvas.width, CHROME_H * dpr);
|
|
121
|
+
ctx.fillStyle = colors.border;
|
|
122
|
+
ctx.fillRect(0, (CHROME_H - 1) * dpr, canvas.width, dpr);
|
|
123
|
+
const dotY = TITLE_BAR_H / 2 * dpr;
|
|
124
|
+
const dotR = 6 * dpr;
|
|
125
|
+
const dotStartX = 18 * dpr;
|
|
126
|
+
const dotGap = 20 * dpr;
|
|
127
|
+
const dotColors = ["#FF5F57", "#FEBC2E", "#28C840"];
|
|
128
|
+
for (let i = 0; i < 3; i++) {
|
|
129
|
+
ctx.beginPath();
|
|
130
|
+
ctx.arc(dotStartX + i * dotGap, dotY, dotR, 0, Math.PI * 2);
|
|
131
|
+
ctx.fillStyle = dotColors[i];
|
|
132
|
+
ctx.fill();
|
|
133
|
+
}
|
|
134
|
+
const urlBarY = (TITLE_BAR_H + URL_BAR_MARGIN_TOP) * dpr;
|
|
135
|
+
const urlBarPadX = 80 * dpr;
|
|
136
|
+
const urlBarX = urlBarPadX;
|
|
137
|
+
const urlBarW = canvas.width - urlBarPadX * 2;
|
|
138
|
+
const urlBarH = URL_BAR_H * dpr;
|
|
139
|
+
const urlBarR = 6 * dpr;
|
|
140
|
+
ctx.fillStyle = colors.urlBar;
|
|
141
|
+
roundRect(ctx, urlBarX, urlBarY, urlBarW, urlBarH, urlBarR);
|
|
142
|
+
ctx.fill();
|
|
143
|
+
if (theme === "light") {
|
|
144
|
+
ctx.strokeStyle = colors.border;
|
|
145
|
+
ctx.lineWidth = dpr;
|
|
146
|
+
roundRect(ctx, urlBarX, urlBarY, urlBarW, urlBarH, urlBarR);
|
|
147
|
+
ctx.stroke();
|
|
148
|
+
}
|
|
149
|
+
ctx.fillStyle = colors.text;
|
|
150
|
+
ctx.font = `${11 * dpr}px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`;
|
|
151
|
+
ctx.textAlign = "center";
|
|
152
|
+
ctx.textBaseline = "middle";
|
|
153
|
+
ctx.fillText("localhost", canvas.width / 2, urlBarY + urlBarH / 2);
|
|
154
|
+
ctx.drawImage(img, 0, CHROME_H * dpr);
|
|
97
155
|
return canvas.toDataURL("image/png");
|
|
98
156
|
}
|
|
157
|
+
function roundRect(ctx, x, y, w, h, r) {
|
|
158
|
+
ctx.beginPath();
|
|
159
|
+
ctx.moveTo(x + r, y);
|
|
160
|
+
ctx.lineTo(x + w - r, y);
|
|
161
|
+
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
|
|
162
|
+
ctx.lineTo(x + w, y + h - r);
|
|
163
|
+
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
|
|
164
|
+
ctx.lineTo(x + r, y + h);
|
|
165
|
+
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
|
|
166
|
+
ctx.lineTo(x, y + r);
|
|
167
|
+
ctx.quadraticCurveTo(x, y, x + r, y);
|
|
168
|
+
ctx.closePath();
|
|
169
|
+
}
|
|
99
170
|
async function captureFullPage() {
|
|
100
171
|
const scrollY = window.scrollY;
|
|
101
172
|
const body = document.body;
|
|
@@ -177,8 +248,67 @@ function loadImage(src) {
|
|
|
177
248
|
});
|
|
178
249
|
}
|
|
179
250
|
|
|
251
|
+
// src/overlay/font.ts
|
|
252
|
+
var FONT_FAMILY = "'Inter var', 'Inter', system-ui, -apple-system, sans-serif";
|
|
253
|
+
var FONT_FEATURE_SETTINGS = "'ss11' 1, 'calt' 1";
|
|
254
|
+
var fontBase = {
|
|
255
|
+
fontFamily: FONT_FAMILY,
|
|
256
|
+
fontFeatureSettings: FONT_FEATURE_SETTINGS
|
|
257
|
+
};
|
|
258
|
+
function style(fontSize, lineHeight, fontWeight, letterSpacing, extra) {
|
|
259
|
+
return { fontSize, lineHeight: `${lineHeight}px`, fontWeight, letterSpacing, ...extra };
|
|
260
|
+
}
|
|
261
|
+
var text = {
|
|
262
|
+
// --- Title (Medium 500) ---
|
|
263
|
+
title: {
|
|
264
|
+
h1: style(56, 64, 500, "-0.01em"),
|
|
265
|
+
h2: style(48, 56, 500, "-0.01em"),
|
|
266
|
+
h3: style(40, 48, 500, "-0.01em"),
|
|
267
|
+
h4: style(32, 40, 500, "-0.005em"),
|
|
268
|
+
h5: style(24, 32, 500, "0em"),
|
|
269
|
+
h6: style(20, 28, 500, "0em")
|
|
270
|
+
},
|
|
271
|
+
// --- Label (Medium 500) ---
|
|
272
|
+
label: {
|
|
273
|
+
xl: style(24, 32, 500, "-0.015em"),
|
|
274
|
+
lg: style(18, 24, 500, "-0.015em"),
|
|
275
|
+
md: style(16, 24, 500, "-0.011em"),
|
|
276
|
+
sm: style(14, 20, 500, "-0.006em"),
|
|
277
|
+
xs: style(12, 16, 500, "0em")
|
|
278
|
+
},
|
|
279
|
+
// --- Paragraph (Regular 400) ---
|
|
280
|
+
paragraph: {
|
|
281
|
+
xl: style(24, 32, 400, "-0.015em"),
|
|
282
|
+
lg: style(18, 24, 400, "-0.015em"),
|
|
283
|
+
md: style(16, 24, 400, "-0.011em"),
|
|
284
|
+
sm: style(14, 20, 400, "-0.006em"),
|
|
285
|
+
xs: style(12, 16, 400, "0em")
|
|
286
|
+
},
|
|
287
|
+
// --- Subheading (Medium 500, uppercase) ---
|
|
288
|
+
subheading: {
|
|
289
|
+
md: style(16, 24, 500, "0.06em", { textTransform: "uppercase" }),
|
|
290
|
+
sm: style(14, 20, 500, "0.06em", { textTransform: "uppercase" }),
|
|
291
|
+
xs: style(12, 16, 500, "0.04em", { textTransform: "uppercase" }),
|
|
292
|
+
xxs: style(11, 12, 500, "0.02em", { textTransform: "uppercase" })
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
var INTER_CSS_ID = "afterbefore-inter-font";
|
|
296
|
+
function injectInterFont() {
|
|
297
|
+
if (document.getElementById(INTER_CSS_ID)) return;
|
|
298
|
+
const preconnect = document.createElement("link");
|
|
299
|
+
preconnect.rel = "preconnect";
|
|
300
|
+
preconnect.href = "https://rsms.me/";
|
|
301
|
+
document.head.appendChild(preconnect);
|
|
302
|
+
const stylesheet = document.createElement("link");
|
|
303
|
+
stylesheet.id = INTER_CSS_ID;
|
|
304
|
+
stylesheet.rel = "stylesheet";
|
|
305
|
+
stylesheet.href = "https://rsms.me/inter/inter.css";
|
|
306
|
+
document.head.appendChild(stylesheet);
|
|
307
|
+
}
|
|
308
|
+
|
|
180
309
|
// src/overlay/ui/toolbar.tsx
|
|
181
310
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
311
|
+
import { createPortal } from "react-dom";
|
|
182
312
|
import {
|
|
183
313
|
ArrowUp,
|
|
184
314
|
Camera,
|
|
@@ -191,11 +321,73 @@ import {
|
|
|
191
321
|
FileText,
|
|
192
322
|
Monitor,
|
|
193
323
|
MousePointer2,
|
|
194
|
-
Settings,
|
|
195
324
|
Trash2 as Trash22,
|
|
196
325
|
X as X2
|
|
197
326
|
} from "lucide-react";
|
|
198
327
|
|
|
328
|
+
// src/overlay/color.ts
|
|
329
|
+
var gray = {
|
|
330
|
+
950: "#171717",
|
|
331
|
+
900: "#1C1C1C",
|
|
332
|
+
800: "#262626",
|
|
333
|
+
700: "#333333",
|
|
334
|
+
600: "#5C5C5C",
|
|
335
|
+
500: "#7B7B7B",
|
|
336
|
+
400: "#A3A3A3",
|
|
337
|
+
300: "#D1D1D1",
|
|
338
|
+
200: "#EBEBEB",
|
|
339
|
+
100: "#F5F5F5",
|
|
340
|
+
50: "#F7F7F7",
|
|
341
|
+
0: "#FFFFFF"
|
|
342
|
+
};
|
|
343
|
+
var bg = {
|
|
344
|
+
base: gray[900],
|
|
345
|
+
elevated: gray[950],
|
|
346
|
+
dropdown: gray[900]
|
|
347
|
+
};
|
|
348
|
+
var fg = {
|
|
349
|
+
strong: gray[200],
|
|
350
|
+
default: gray[300],
|
|
351
|
+
sub: gray[500],
|
|
352
|
+
muted: gray[600],
|
|
353
|
+
faint: gray[600]
|
|
354
|
+
};
|
|
355
|
+
var stroke = {
|
|
356
|
+
soft: "rgba(255, 255, 255, 0.08)",
|
|
357
|
+
default: "rgba(255, 255, 255, 0.1)",
|
|
358
|
+
strong: "rgba(255, 255, 255, 0.12)",
|
|
359
|
+
interactive: "rgba(255, 255, 255, 0.18)"
|
|
360
|
+
};
|
|
361
|
+
var state = {
|
|
362
|
+
subtle: "rgba(255, 255, 255, 0.04)",
|
|
363
|
+
button: "rgba(255, 255, 255, 0.06)",
|
|
364
|
+
input: "rgba(255, 255, 255, 0.07)",
|
|
365
|
+
active: "rgba(255, 255, 255, 0.08)",
|
|
366
|
+
hover: "rgba(255, 255, 255, 0.1)",
|
|
367
|
+
hoverStrong: "rgba(255, 255, 255, 0.12)",
|
|
368
|
+
pressed: "rgba(255, 255, 255, 0.14)"
|
|
369
|
+
};
|
|
370
|
+
var accent = {
|
|
371
|
+
primary: "#335CFF",
|
|
372
|
+
toggle: "#38bdf8",
|
|
373
|
+
check: "#4ade80",
|
|
374
|
+
highlight: "rgba(125, 211, 252, 0.96)"
|
|
375
|
+
};
|
|
376
|
+
var feedback = {
|
|
377
|
+
success: "rgba(34, 197, 94, 0.9)",
|
|
378
|
+
error: "rgba(239, 68, 68, 0.9)",
|
|
379
|
+
errorText: "rgba(239, 68, 68, 0.9)",
|
|
380
|
+
errorBg: "rgba(239, 68, 68, 0.1)"
|
|
381
|
+
};
|
|
382
|
+
var shadow = {
|
|
383
|
+
toolbar: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
384
|
+
panel: "0 14px 36px rgba(0, 0, 0, 0.32)",
|
|
385
|
+
dropdown: "0 10px 30px rgba(0, 0, 0, 0.3)",
|
|
386
|
+
tooltip: "0 8px 28px rgba(0, 0, 0, 0.28)",
|
|
387
|
+
toast: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
388
|
+
status: "0 4px 20px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.08)"
|
|
389
|
+
};
|
|
390
|
+
|
|
199
391
|
// src/overlay/ui/settings-panel.tsx
|
|
200
392
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
201
393
|
import {
|
|
@@ -207,140 +399,110 @@ import {
|
|
|
207
399
|
X
|
|
208
400
|
} from "lucide-react";
|
|
209
401
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
210
|
-
function
|
|
211
|
-
style,
|
|
212
|
-
onClose,
|
|
213
|
-
selectedMode,
|
|
402
|
+
function SettingsContent({
|
|
214
403
|
frameSettings,
|
|
215
|
-
onFrameSettingsChange
|
|
404
|
+
onFrameSettingsChange,
|
|
405
|
+
saveDir,
|
|
406
|
+
picking,
|
|
407
|
+
onPickFolder
|
|
216
408
|
}) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
await fetch("/__afterbefore/config", {
|
|
230
|
-
method: "POST",
|
|
231
|
-
headers: { "Content-Type": "application/json" },
|
|
232
|
-
body: JSON.stringify({ saveDir: data.folder })
|
|
233
|
-
});
|
|
234
|
-
setSaveDir(data.folder);
|
|
409
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
410
|
+
/* @__PURE__ */ jsx(
|
|
411
|
+
SettingsRow,
|
|
412
|
+
{
|
|
413
|
+
title: "Frame",
|
|
414
|
+
control: /* @__PURE__ */ jsx(
|
|
415
|
+
ToggleSwitch,
|
|
416
|
+
{
|
|
417
|
+
enabled: frameSettings.enabled,
|
|
418
|
+
onChange: () => onFrameSettingsChange({ ...frameSettings, enabled: !frameSettings.enabled })
|
|
419
|
+
}
|
|
420
|
+
)
|
|
235
421
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
422
|
+
),
|
|
423
|
+
frameSettings.enabled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
424
|
+
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
425
|
+
/* @__PURE__ */ jsx(
|
|
426
|
+
FrameSizeControl,
|
|
427
|
+
{
|
|
428
|
+
size: frameSettings.size,
|
|
429
|
+
onChange: (size) => onFrameSettingsChange({ ...frameSettings, size })
|
|
430
|
+
}
|
|
431
|
+
),
|
|
432
|
+
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
433
|
+
/* @__PURE__ */ jsx(
|
|
434
|
+
FrameBackgroundControl,
|
|
435
|
+
{
|
|
436
|
+
bgType: frameSettings.bgType,
|
|
437
|
+
bgColor: frameSettings.bgColor,
|
|
438
|
+
bgImage: frameSettings.bgImage,
|
|
439
|
+
frameSize: frameSettings.size,
|
|
440
|
+
onChange: (updates) => onFrameSettingsChange({ ...frameSettings, ...updates })
|
|
441
|
+
}
|
|
442
|
+
)
|
|
443
|
+
] }),
|
|
444
|
+
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
445
|
+
/* @__PURE__ */ jsx(
|
|
446
|
+
SettingsRow,
|
|
447
|
+
{
|
|
448
|
+
title: "Browser Chrome",
|
|
449
|
+
control: /* @__PURE__ */ jsx(
|
|
450
|
+
ToggleSwitch,
|
|
451
|
+
{
|
|
452
|
+
enabled: frameSettings.browserChrome,
|
|
453
|
+
onChange: () => onFrameSettingsChange({ ...frameSettings, browserChrome: !frameSettings.browserChrome })
|
|
454
|
+
}
|
|
455
|
+
)
|
|
456
|
+
}
|
|
457
|
+
),
|
|
458
|
+
frameSettings.browserChrome && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
459
|
+
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
460
|
+
/* @__PURE__ */ jsx(
|
|
461
|
+
SettingsRow,
|
|
462
|
+
{
|
|
463
|
+
title: "Theme",
|
|
464
|
+
control: /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 2, flexShrink: 0 }, children: [
|
|
274
465
|
/* @__PURE__ */ jsx(
|
|
275
|
-
|
|
466
|
+
SegmentButton,
|
|
276
467
|
{
|
|
277
|
-
|
|
278
|
-
|
|
468
|
+
active: frameSettings.browserTheme === "light",
|
|
469
|
+
onClick: () => onFrameSettingsChange({ ...frameSettings, browserTheme: "light" }),
|
|
470
|
+
style: { borderRadius: "6px 0 0 6px" },
|
|
471
|
+
children: "Light"
|
|
279
472
|
}
|
|
280
473
|
),
|
|
281
|
-
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
282
474
|
/* @__PURE__ */ jsx(
|
|
283
|
-
|
|
475
|
+
SegmentButton,
|
|
284
476
|
{
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
onChange: (updates) => onFrameSettingsChange({ ...frameSettings, ...updates })
|
|
477
|
+
active: frameSettings.browserTheme === "dark",
|
|
478
|
+
onClick: () => onFrameSettingsChange({ ...frameSettings, browserTheme: "dark" }),
|
|
479
|
+
style: { borderRadius: "0 6px 6px 0" },
|
|
480
|
+
children: "Dark"
|
|
290
481
|
}
|
|
291
482
|
)
|
|
292
|
-
] })
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
483
|
+
] })
|
|
484
|
+
}
|
|
485
|
+
)
|
|
486
|
+
] }),
|
|
487
|
+
/* @__PURE__ */ jsx(SettingsDivider, {}),
|
|
488
|
+
saveDir !== void 0 && onPickFolder && /* @__PURE__ */ jsx(
|
|
489
|
+
SettingsRow,
|
|
490
|
+
{
|
|
491
|
+
title: "Save Location",
|
|
492
|
+
description: /* @__PURE__ */ jsx(
|
|
493
|
+
"span",
|
|
297
494
|
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
"
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
display: "block"
|
|
307
|
-
},
|
|
308
|
-
title: shortDir,
|
|
309
|
-
children: shortDir
|
|
310
|
-
}
|
|
311
|
-
),
|
|
312
|
-
control: /* @__PURE__ */ jsx(SmallButton, { onClick: handlePickFolder, children: picking ? "..." : "Change" })
|
|
495
|
+
style: {
|
|
496
|
+
overflow: "hidden",
|
|
497
|
+
textOverflow: "ellipsis",
|
|
498
|
+
whiteSpace: "nowrap",
|
|
499
|
+
display: "block"
|
|
500
|
+
},
|
|
501
|
+
title: saveDir,
|
|
502
|
+
children: saveDir
|
|
313
503
|
}
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
function SettingsHeader({ onClose }) {
|
|
320
|
-
const [hovered, setHovered] = useState2(false);
|
|
321
|
-
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", paddingBottom: 8 }, children: [
|
|
322
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: 14, fontWeight: 600, color: "rgba(255, 255, 255, 0.92)" }, children: "Settings" }),
|
|
323
|
-
/* @__PURE__ */ jsx(
|
|
324
|
-
"button",
|
|
325
|
-
{
|
|
326
|
-
onClick: onClose,
|
|
327
|
-
onMouseEnter: () => setHovered(true),
|
|
328
|
-
onMouseLeave: () => setHovered(false),
|
|
329
|
-
style: {
|
|
330
|
-
width: 24,
|
|
331
|
-
height: 24,
|
|
332
|
-
borderRadius: 6,
|
|
333
|
-
border: "none",
|
|
334
|
-
background: hovered ? "rgba(255, 255, 255, 0.1)" : "transparent",
|
|
335
|
-
display: "flex",
|
|
336
|
-
alignItems: "center",
|
|
337
|
-
justifyContent: "center",
|
|
338
|
-
cursor: "pointer",
|
|
339
|
-
color: hovered ? "rgba(255, 255, 255, 0.8)" : "rgba(255, 255, 255, 0.46)",
|
|
340
|
-
padding: 0,
|
|
341
|
-
transition: "background 0.12s ease, color 0.12s ease"
|
|
342
|
-
},
|
|
343
|
-
children: /* @__PURE__ */ jsx(X, { size: 14, strokeWidth: 2 })
|
|
504
|
+
),
|
|
505
|
+
control: /* @__PURE__ */ jsx(SmallButton, { onClick: onPickFolder, children: picking ? "..." : "Change" })
|
|
344
506
|
}
|
|
345
507
|
)
|
|
346
508
|
] });
|
|
@@ -350,16 +512,23 @@ function SettingsRow({
|
|
|
350
512
|
description,
|
|
351
513
|
control
|
|
352
514
|
}) {
|
|
353
|
-
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, padding: "
|
|
354
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap:
|
|
355
|
-
/* @__PURE__ */ jsx("span", { style: {
|
|
356
|
-
description && /* @__PURE__ */ jsx("span", { style: {
|
|
515
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, padding: "10px 0" }, children: [
|
|
516
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2, flex: 1, minWidth: 0 }, children: [
|
|
517
|
+
/* @__PURE__ */ jsx("span", { style: { ...text.label.sm, color: fg.strong }, children: title }),
|
|
518
|
+
description && /* @__PURE__ */ jsx("span", { style: { ...text.paragraph.xs, color: fg.muted }, children: description })
|
|
357
519
|
] }),
|
|
358
520
|
/* @__PURE__ */ jsx("div", { style: { flexShrink: 0 }, children: control })
|
|
359
521
|
] });
|
|
360
522
|
}
|
|
361
523
|
function SettingsDivider() {
|
|
362
|
-
return /* @__PURE__ */ jsx(
|
|
524
|
+
return /* @__PURE__ */ jsx(
|
|
525
|
+
"div",
|
|
526
|
+
{
|
|
527
|
+
style: {
|
|
528
|
+
borderBottom: `1px solid ${stroke.soft}`
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
);
|
|
363
532
|
}
|
|
364
533
|
function ToggleSwitch({
|
|
365
534
|
enabled,
|
|
@@ -375,7 +544,7 @@ function ToggleSwitch({
|
|
|
375
544
|
height: 22,
|
|
376
545
|
borderRadius: 999,
|
|
377
546
|
border: "none",
|
|
378
|
-
background: enabled ?
|
|
547
|
+
background: enabled ? accent.toggle : stroke.interactive,
|
|
379
548
|
position: "relative",
|
|
380
549
|
cursor: "pointer",
|
|
381
550
|
padding: 0,
|
|
@@ -407,12 +576,9 @@ function FrameSizeControl({
|
|
|
407
576
|
const [sizeOpen, setSizeOpen] = useState2(false);
|
|
408
577
|
const currentPreset = FRAME_SIZE_PRESETS.find((p) => p.w === size.w && p.h === size.h);
|
|
409
578
|
const isCustom = !currentPreset;
|
|
410
|
-
return /* @__PURE__ */ jsxs("div", { style: { padding: "
|
|
579
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "10px 0" }, children: [
|
|
411
580
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }, children: [
|
|
412
|
-
/* @__PURE__ */
|
|
413
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "rgba(255, 255, 255, 0.92)" }, children: "Size" }),
|
|
414
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: 11, color: "rgba(255, 255, 255, 0.42)", lineHeight: 1.3 }, children: "Set the frame dimensions" })
|
|
415
|
-
] }),
|
|
581
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("span", { style: { ...text.label.sm, color: fg.strong }, children: "Size" }) }),
|
|
416
582
|
/* @__PURE__ */ jsxs("div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
417
583
|
/* @__PURE__ */ jsxs(
|
|
418
584
|
"button",
|
|
@@ -425,11 +591,11 @@ function FrameSizeControl({
|
|
|
425
591
|
height: 30,
|
|
426
592
|
padding: "0 10px",
|
|
427
593
|
borderRadius: 7,
|
|
428
|
-
border:
|
|
429
|
-
background:
|
|
430
|
-
color:
|
|
594
|
+
border: `1px solid ${stroke.default}`,
|
|
595
|
+
background: state.input,
|
|
596
|
+
color: fg.strong,
|
|
431
597
|
cursor: "pointer",
|
|
432
|
-
|
|
598
|
+
...text.label.xs,
|
|
433
599
|
fontFamily: "inherit",
|
|
434
600
|
whiteSpace: "nowrap"
|
|
435
601
|
},
|
|
@@ -447,11 +613,11 @@ function FrameSizeControl({
|
|
|
447
613
|
bottom: "calc(100% + 4px)",
|
|
448
614
|
right: 0,
|
|
449
615
|
minWidth: 180,
|
|
450
|
-
background:
|
|
451
|
-
border:
|
|
616
|
+
background: bg.base,
|
|
617
|
+
border: `1px solid ${stroke.default}`,
|
|
452
618
|
borderRadius: 8,
|
|
453
619
|
padding: "4px 0",
|
|
454
|
-
boxShadow:
|
|
620
|
+
boxShadow: shadow.dropdown,
|
|
455
621
|
zIndex: 1
|
|
456
622
|
},
|
|
457
623
|
children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs(
|
|
@@ -464,7 +630,7 @@ function FrameSizeControl({
|
|
|
464
630
|
},
|
|
465
631
|
children: [
|
|
466
632
|
/* @__PURE__ */ jsx("span", { children: preset.label }),
|
|
467
|
-
/* @__PURE__ */ jsx("span", { style: { marginLeft: 6, fontSize: 10, color:
|
|
633
|
+
/* @__PURE__ */ jsx("span", { style: { marginLeft: 6, fontSize: 10, color: fg.faint }, children: preset.hint })
|
|
468
634
|
]
|
|
469
635
|
},
|
|
470
636
|
preset.label
|
|
@@ -523,12 +689,9 @@ function FrameBackgroundControl({
|
|
|
523
689
|
reader.readAsDataURL(file);
|
|
524
690
|
e.target.value = "";
|
|
525
691
|
};
|
|
526
|
-
return /* @__PURE__ */ jsxs("div", { style: { padding: "
|
|
692
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "10px 0" }, children: [
|
|
527
693
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }, children: [
|
|
528
|
-
/* @__PURE__ */
|
|
529
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "rgba(255, 255, 255, 0.92)" }, children: "Background" }),
|
|
530
|
-
/* @__PURE__ */ jsx("span", { style: { fontSize: 11, color: "rgba(255, 255, 255, 0.42)", lineHeight: 1.3 }, children: "Frame background color or image" })
|
|
531
|
-
] }),
|
|
694
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("span", { style: { ...text.label.sm, color: fg.strong }, children: "Background" }) }),
|
|
532
695
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 2, flexShrink: 0 }, children: [
|
|
533
696
|
/* @__PURE__ */ jsxs(
|
|
534
697
|
SegmentButton,
|
|
@@ -582,7 +745,7 @@ function FrameBackgroundControl({
|
|
|
582
745
|
height: 28,
|
|
583
746
|
borderRadius: 4,
|
|
584
747
|
objectFit: "cover",
|
|
585
|
-
border:
|
|
748
|
+
border: `1px solid ${stroke.strong}`
|
|
586
749
|
}
|
|
587
750
|
}
|
|
588
751
|
),
|
|
@@ -602,7 +765,7 @@ function SegmentButton({
|
|
|
602
765
|
children,
|
|
603
766
|
active,
|
|
604
767
|
onClick,
|
|
605
|
-
style
|
|
768
|
+
style: style2
|
|
606
769
|
}) {
|
|
607
770
|
return /* @__PURE__ */ jsx(
|
|
608
771
|
"button",
|
|
@@ -612,16 +775,16 @@ function SegmentButton({
|
|
|
612
775
|
display: "flex",
|
|
613
776
|
alignItems: "center",
|
|
614
777
|
gap: 4,
|
|
615
|
-
height:
|
|
778
|
+
height: 28,
|
|
616
779
|
padding: "0 10px",
|
|
617
|
-
border:
|
|
618
|
-
background: active ?
|
|
619
|
-
color: active ?
|
|
780
|
+
border: `1px solid ${stroke.default}`,
|
|
781
|
+
background: active ? state.pressed : state.subtle,
|
|
782
|
+
color: active ? fg.strong : fg.sub,
|
|
620
783
|
cursor: "pointer",
|
|
621
|
-
|
|
784
|
+
...text.label.xs,
|
|
622
785
|
fontFamily: "inherit",
|
|
623
786
|
transition: "background 0.12s ease, color 0.12s ease",
|
|
624
|
-
...
|
|
787
|
+
...style2
|
|
625
788
|
},
|
|
626
789
|
children
|
|
627
790
|
}
|
|
@@ -641,7 +804,7 @@ function ColorSwatch({
|
|
|
641
804
|
width: 24,
|
|
642
805
|
height: 24,
|
|
643
806
|
borderRadius: 6,
|
|
644
|
-
border:
|
|
807
|
+
border: `1px solid ${stroke.interactive}`,
|
|
645
808
|
background: color,
|
|
646
809
|
cursor: "pointer",
|
|
647
810
|
padding: 0
|
|
@@ -683,12 +846,12 @@ function SmallButton({
|
|
|
683
846
|
display: "flex",
|
|
684
847
|
alignItems: "center",
|
|
685
848
|
gap: 4,
|
|
686
|
-
padding: "
|
|
849
|
+
padding: "4px 10px",
|
|
687
850
|
borderRadius: 6,
|
|
688
|
-
border:
|
|
689
|
-
background: hovered ?
|
|
690
|
-
color:
|
|
691
|
-
|
|
851
|
+
border: `1px solid ${stroke.strong}`,
|
|
852
|
+
background: hovered ? state.hoverStrong : state.button,
|
|
853
|
+
color: fg.default,
|
|
854
|
+
...text.label.xs,
|
|
692
855
|
cursor: "pointer",
|
|
693
856
|
fontFamily: "inherit",
|
|
694
857
|
transition: "background 0.12s ease"
|
|
@@ -702,7 +865,7 @@ function NumInput({
|
|
|
702
865
|
onChange
|
|
703
866
|
}) {
|
|
704
867
|
const [editing, setEditing] = useState2(false);
|
|
705
|
-
const [
|
|
868
|
+
const [text2, setText] = useState2(String(value));
|
|
706
869
|
useEffect(() => {
|
|
707
870
|
if (!editing) {
|
|
708
871
|
setText(String(value));
|
|
@@ -712,14 +875,14 @@ function NumInput({
|
|
|
712
875
|
"input",
|
|
713
876
|
{
|
|
714
877
|
type: "text",
|
|
715
|
-
value: editing ?
|
|
878
|
+
value: editing ? text2 : String(value),
|
|
716
879
|
onFocus: () => {
|
|
717
880
|
setEditing(true);
|
|
718
881
|
setText(String(value));
|
|
719
882
|
},
|
|
720
883
|
onBlur: () => {
|
|
721
884
|
setEditing(false);
|
|
722
|
-
onChange(
|
|
885
|
+
onChange(text2);
|
|
723
886
|
},
|
|
724
887
|
onChange: (e) => setText(e.target.value),
|
|
725
888
|
onKeyDown: (e) => {
|
|
@@ -730,12 +893,12 @@ function NumInput({
|
|
|
730
893
|
style: {
|
|
731
894
|
width: 54,
|
|
732
895
|
padding: "4px 6px",
|
|
733
|
-
background:
|
|
734
|
-
border:
|
|
896
|
+
background: state.input,
|
|
897
|
+
border: `1px solid ${stroke.default}`,
|
|
735
898
|
borderRadius: 7,
|
|
736
|
-
color:
|
|
737
|
-
|
|
738
|
-
fontFamily: "
|
|
899
|
+
color: fg.strong,
|
|
900
|
+
...text.label.xs,
|
|
901
|
+
fontFamily: "inherit",
|
|
739
902
|
textAlign: "center",
|
|
740
903
|
outline: "none"
|
|
741
904
|
}
|
|
@@ -747,7 +910,7 @@ function HexInput({
|
|
|
747
910
|
onChange
|
|
748
911
|
}) {
|
|
749
912
|
const [editing, setEditing] = useState2(false);
|
|
750
|
-
const [
|
|
913
|
+
const [text2, setText] = useState2(value);
|
|
751
914
|
useEffect(() => {
|
|
752
915
|
if (!editing) {
|
|
753
916
|
setText(value);
|
|
@@ -763,14 +926,14 @@ function HexInput({
|
|
|
763
926
|
"input",
|
|
764
927
|
{
|
|
765
928
|
type: "text",
|
|
766
|
-
value: editing ?
|
|
929
|
+
value: editing ? text2 : value,
|
|
767
930
|
onFocus: () => {
|
|
768
931
|
setEditing(true);
|
|
769
932
|
setText(value);
|
|
770
933
|
},
|
|
771
934
|
onBlur: () => {
|
|
772
935
|
setEditing(false);
|
|
773
|
-
commit(
|
|
936
|
+
commit(text2);
|
|
774
937
|
},
|
|
775
938
|
onChange: (e) => setText(e.target.value),
|
|
776
939
|
onKeyDown: (e) => {
|
|
@@ -781,12 +944,12 @@ function HexInput({
|
|
|
781
944
|
style: {
|
|
782
945
|
width: 72,
|
|
783
946
|
padding: "4px 6px",
|
|
784
|
-
background:
|
|
785
|
-
border:
|
|
947
|
+
background: state.input,
|
|
948
|
+
border: `1px solid ${stroke.default}`,
|
|
786
949
|
borderRadius: 7,
|
|
787
|
-
color:
|
|
788
|
-
|
|
789
|
-
fontFamily: "
|
|
950
|
+
color: fg.strong,
|
|
951
|
+
...text.label.xs,
|
|
952
|
+
fontFamily: "inherit",
|
|
790
953
|
textAlign: "left",
|
|
791
954
|
outline: "none"
|
|
792
955
|
}
|
|
@@ -799,7 +962,7 @@ function StaticText({ children }) {
|
|
|
799
962
|
{
|
|
800
963
|
style: {
|
|
801
964
|
fontSize: 11,
|
|
802
|
-
color:
|
|
965
|
+
color: fg.faint,
|
|
803
966
|
minWidth: 8,
|
|
804
967
|
textAlign: "center"
|
|
805
968
|
},
|
|
@@ -820,12 +983,12 @@ function DropItem({
|
|
|
820
983
|
display: "block",
|
|
821
984
|
width: "100%",
|
|
822
985
|
padding: "7px 12px",
|
|
823
|
-
background: active ?
|
|
986
|
+
background: active ? state.active : "transparent",
|
|
824
987
|
border: "none",
|
|
825
|
-
color:
|
|
988
|
+
color: fg.strong,
|
|
826
989
|
textAlign: "left",
|
|
827
990
|
cursor: "pointer",
|
|
828
|
-
|
|
991
|
+
...text.paragraph.sm,
|
|
829
992
|
fontFamily: "inherit"
|
|
830
993
|
},
|
|
831
994
|
children
|
|
@@ -879,6 +1042,20 @@ function snapToCorner(x, y) {
|
|
|
879
1042
|
}
|
|
880
1043
|
return y < cy ? "top-right" : "bottom-right";
|
|
881
1044
|
}
|
|
1045
|
+
function getCornerPosition(corner, w, h) {
|
|
1046
|
+
const vw = window.innerWidth;
|
|
1047
|
+
const vh = window.innerHeight;
|
|
1048
|
+
switch (corner) {
|
|
1049
|
+
case "bottom-right":
|
|
1050
|
+
return { x: vw - EDGE_MARGIN - w, y: vh - EDGE_MARGIN - h };
|
|
1051
|
+
case "bottom-left":
|
|
1052
|
+
return { x: EDGE_MARGIN, y: vh - EDGE_MARGIN - h };
|
|
1053
|
+
case "top-right":
|
|
1054
|
+
return { x: vw - EDGE_MARGIN - w, y: EDGE_MARGIN };
|
|
1055
|
+
case "top-left":
|
|
1056
|
+
return { x: EDGE_MARGIN, y: EDGE_MARGIN };
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
882
1059
|
var MODES = [
|
|
883
1060
|
{ mode: "component", label: "Component", icon: MousePointer2 },
|
|
884
1061
|
{ mode: "viewport", label: "Viewport", icon: Monitor },
|
|
@@ -896,8 +1073,29 @@ function Toolbar({
|
|
|
896
1073
|
frameSettings,
|
|
897
1074
|
onFrameSettingsChange
|
|
898
1075
|
}) {
|
|
899
|
-
const [settingsOpen, setSettingsOpen] = useState3(false);
|
|
900
1076
|
const [historyOpen, setHistoryOpen] = useState3(false);
|
|
1077
|
+
const [modesExpanded, setModesExpanded] = useState3(true);
|
|
1078
|
+
const [buttonsVisible, setButtonsVisible] = useState3(expanded);
|
|
1079
|
+
const [animIn, setAnimIn] = useState3(expanded);
|
|
1080
|
+
const [animDone, setAnimDone] = useState3(expanded);
|
|
1081
|
+
useEffect2(() => {
|
|
1082
|
+
if (expanded) {
|
|
1083
|
+
setAnimDone(false);
|
|
1084
|
+
setButtonsVisible(true);
|
|
1085
|
+
setAnimIn(false);
|
|
1086
|
+
requestAnimationFrame(() => {
|
|
1087
|
+
requestAnimationFrame(() => setAnimIn(true));
|
|
1088
|
+
});
|
|
1089
|
+
const timer = setTimeout(() => setAnimDone(true), 250);
|
|
1090
|
+
return () => clearTimeout(timer);
|
|
1091
|
+
} else if (buttonsVisible) {
|
|
1092
|
+
setHistoryOpen(false);
|
|
1093
|
+
setAnimDone(false);
|
|
1094
|
+
setAnimIn(false);
|
|
1095
|
+
const timer = setTimeout(() => setButtonsVisible(false), 150);
|
|
1096
|
+
return () => clearTimeout(timer);
|
|
1097
|
+
}
|
|
1098
|
+
}, [expanded]);
|
|
901
1099
|
const [corner, setCorner] = useState3(() => {
|
|
902
1100
|
try {
|
|
903
1101
|
const stored = localStorage.getItem("ab-toolbar-corner");
|
|
@@ -910,6 +1108,7 @@ function Toolbar({
|
|
|
910
1108
|
});
|
|
911
1109
|
const [dragging, setDragging] = useState3(false);
|
|
912
1110
|
const [dragPos, setDragPos] = useState3(null);
|
|
1111
|
+
const [snapAnim, setSnapAnim] = useState3(null);
|
|
913
1112
|
const dragState = useRef2(null);
|
|
914
1113
|
const toolbarRef = useRef2(null);
|
|
915
1114
|
const [cameraHovered, setCameraHovered] = useState3(false);
|
|
@@ -923,8 +1122,8 @@ function Toolbar({
|
|
|
923
1122
|
return;
|
|
924
1123
|
}
|
|
925
1124
|
if (e.key === "Escape") {
|
|
926
|
-
if (
|
|
927
|
-
|
|
1125
|
+
if (historyOpen) {
|
|
1126
|
+
setHistoryOpen(false);
|
|
928
1127
|
return;
|
|
929
1128
|
}
|
|
930
1129
|
onCancel();
|
|
@@ -934,7 +1133,7 @@ function Toolbar({
|
|
|
934
1133
|
};
|
|
935
1134
|
document.addEventListener("keydown", onKey);
|
|
936
1135
|
return () => document.removeEventListener("keydown", onKey);
|
|
937
|
-
}, [expanded, onCancel, onCapture, selectedMode,
|
|
1136
|
+
}, [expanded, onCancel, onCapture, selectedMode, historyOpen]);
|
|
938
1137
|
const handleMouseDown = useCallback2(
|
|
939
1138
|
(e) => {
|
|
940
1139
|
e.preventDefault();
|
|
@@ -971,22 +1170,35 @@ function Toolbar({
|
|
|
971
1170
|
if (!ds) return;
|
|
972
1171
|
if (ds.distance < 5) {
|
|
973
1172
|
onToggle();
|
|
1173
|
+
setDragging(false);
|
|
1174
|
+
setDragPos(null);
|
|
1175
|
+
dragState.current = null;
|
|
974
1176
|
} else {
|
|
975
1177
|
const el = toolbarRef.current;
|
|
976
1178
|
const w = el?.offsetWidth ?? CONTAINER_SIZE;
|
|
977
1179
|
const h = el?.offsetHeight ?? CONTAINER_SIZE;
|
|
978
|
-
const
|
|
979
|
-
const
|
|
1180
|
+
const currentX = ds.origX + (e.clientX - ds.startX);
|
|
1181
|
+
const currentY = ds.origY + (e.clientY - ds.startY);
|
|
1182
|
+
const centerX = currentX + w / 2;
|
|
1183
|
+
const centerY = currentY + h / 2;
|
|
980
1184
|
const newCorner = snapToCorner(centerX, centerY);
|
|
981
1185
|
setCorner(newCorner);
|
|
982
1186
|
try {
|
|
983
1187
|
localStorage.setItem("ab-toolbar-corner", newCorner);
|
|
984
1188
|
} catch {
|
|
985
1189
|
}
|
|
1190
|
+
const targetPos = getCornerPosition(newCorner, w, h);
|
|
1191
|
+
setDragging(false);
|
|
1192
|
+
setDragPos(null);
|
|
1193
|
+
setSnapAnim({ x: currentX, y: currentY, animate: false });
|
|
1194
|
+
dragState.current = null;
|
|
1195
|
+
requestAnimationFrame(() => {
|
|
1196
|
+
requestAnimationFrame(() => {
|
|
1197
|
+
setSnapAnim({ ...targetPos, animate: true });
|
|
1198
|
+
setTimeout(() => setSnapAnim(null), 300);
|
|
1199
|
+
});
|
|
1200
|
+
});
|
|
986
1201
|
}
|
|
987
|
-
setDragging(false);
|
|
988
|
-
setDragPos(null);
|
|
989
|
-
dragState.current = null;
|
|
990
1202
|
};
|
|
991
1203
|
window.addEventListener("mousemove", handleMouseMove);
|
|
992
1204
|
window.addEventListener("mouseup", handleMouseUp);
|
|
@@ -998,7 +1210,13 @@ function Toolbar({
|
|
|
998
1210
|
const panelSide = isRightCorner(corner) ? "left" : "right";
|
|
999
1211
|
const tooltipSide = panelSide;
|
|
1000
1212
|
const bottom = isBottomCorner(corner);
|
|
1001
|
-
const positionStyle = dragging && dragPos ? { left: dragPos.x, top: dragPos.y } :
|
|
1213
|
+
const positionStyle = dragging && dragPos ? { left: dragPos.x, top: dragPos.y } : snapAnim ? {
|
|
1214
|
+
left: snapAnim.x,
|
|
1215
|
+
top: snapAnim.y,
|
|
1216
|
+
...snapAnim.animate && {
|
|
1217
|
+
transition: "left 0.3s cubic-bezier(0.23, 1, 0.32, 1), top 0.3s cubic-bezier(0.23, 1, 0.32, 1)"
|
|
1218
|
+
}
|
|
1219
|
+
} : getCornerStyle(corner);
|
|
1002
1220
|
const cameraTooltipLabel = expanded ? "Close" : void 0;
|
|
1003
1221
|
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;
|
|
1004
1222
|
const cameraButton = /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
@@ -1008,14 +1226,17 @@ function Toolbar({
|
|
|
1008
1226
|
style: {
|
|
1009
1227
|
position: "absolute",
|
|
1010
1228
|
...cameraTooltipStyle,
|
|
1011
|
-
background:
|
|
1012
|
-
border:
|
|
1229
|
+
background: bg.base,
|
|
1230
|
+
border: `1px solid ${stroke.default}`,
|
|
1013
1231
|
borderRadius: 6,
|
|
1014
|
-
padding: "
|
|
1015
|
-
|
|
1016
|
-
|
|
1232
|
+
padding: "0 8px",
|
|
1233
|
+
height: 24,
|
|
1234
|
+
display: "flex",
|
|
1235
|
+
alignItems: "center",
|
|
1236
|
+
color: fg.strong,
|
|
1237
|
+
...text.label.xs,
|
|
1017
1238
|
whiteSpace: "nowrap",
|
|
1018
|
-
boxShadow:
|
|
1239
|
+
boxShadow: shadow.tooltip,
|
|
1019
1240
|
pointerEvents: "none"
|
|
1020
1241
|
},
|
|
1021
1242
|
children: cameraTooltipLabel
|
|
@@ -1036,7 +1257,7 @@ function Toolbar({
|
|
|
1036
1257
|
alignItems: "center",
|
|
1037
1258
|
justifyContent: "center",
|
|
1038
1259
|
cursor: dragging ? "grabbing" : "pointer",
|
|
1039
|
-
background: expanded && cameraHovered ?
|
|
1260
|
+
background: expanded && cameraHovered ? state.hoverStrong : "transparent",
|
|
1040
1261
|
transition: "background 0.12s ease"
|
|
1041
1262
|
},
|
|
1042
1263
|
children: [
|
|
@@ -1048,7 +1269,12 @@ function Toolbar({
|
|
|
1048
1269
|
@keyframes ab-spin {
|
|
1049
1270
|
0% { transform: rotate(0deg); }
|
|
1050
1271
|
100% { transform: rotate(360deg); }
|
|
1051
|
-
}
|
|
1272
|
+
}
|
|
1273
|
+
@keyframes ab-panel-in {
|
|
1274
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
1275
|
+
to { opacity: 1; transform: translateY(0); }
|
|
1276
|
+
}
|
|
1277
|
+
`
|
|
1052
1278
|
}
|
|
1053
1279
|
}
|
|
1054
1280
|
),
|
|
@@ -1059,78 +1285,111 @@ function Toolbar({
|
|
|
1059
1285
|
strokeWidth: 2,
|
|
1060
1286
|
style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
|
|
1061
1287
|
}
|
|
1062
|
-
) : phase === "ready" ? /* @__PURE__ */ jsx2(Check, { size: 16, strokeWidth: 2.6, color:
|
|
1288
|
+
) : phase === "ready" ? /* @__PURE__ */ jsx2(Check, { size: 16, strokeWidth: 2.6, color: accent.check }) : expanded ? /* @__PURE__ */ jsx2(
|
|
1063
1289
|
X2,
|
|
1064
1290
|
{
|
|
1065
1291
|
size: 16,
|
|
1066
1292
|
strokeWidth: 1.7,
|
|
1067
|
-
color: cameraHovered ?
|
|
1293
|
+
color: cameraHovered ? fg.strong : fg.sub
|
|
1068
1294
|
}
|
|
1069
1295
|
) : /* @__PURE__ */ jsx2(
|
|
1070
1296
|
Camera,
|
|
1071
1297
|
{
|
|
1072
1298
|
size: 16,
|
|
1073
1299
|
strokeWidth: 1.9,
|
|
1074
|
-
color:
|
|
1300
|
+
color: fg.sub
|
|
1075
1301
|
}
|
|
1076
1302
|
)
|
|
1077
1303
|
]
|
|
1078
1304
|
}
|
|
1079
1305
|
)
|
|
1080
1306
|
] });
|
|
1081
|
-
const toolbarButtons =
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
{
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
onClick: () => {
|
|
1089
|
-
setSettingsOpen(false);
|
|
1090
|
-
setHistoryOpen(false);
|
|
1091
|
-
if (mode === "viewport" || mode === "fullpage") {
|
|
1092
|
-
onModeChange(mode);
|
|
1093
|
-
onCapture(mode);
|
|
1094
|
-
} else {
|
|
1095
|
-
onModeChange(mode);
|
|
1096
|
-
}
|
|
1097
|
-
},
|
|
1098
|
-
children: /* @__PURE__ */ jsx2(ModeIcon, { size: 16, strokeWidth: 1.7 })
|
|
1307
|
+
const toolbarButtons = buttonsVisible ? /* @__PURE__ */ jsx2(
|
|
1308
|
+
"div",
|
|
1309
|
+
{
|
|
1310
|
+
style: {
|
|
1311
|
+
overflow: animDone ? "visible" : "hidden",
|
|
1312
|
+
maxHeight: animIn ? 195 : 0,
|
|
1313
|
+
transition: animIn ? "max-height 250ms cubic-bezier(0.23, 1, 0.32, 1)" : "max-height 150ms cubic-bezier(0.23, 1, 0.32, 1)"
|
|
1099
1314
|
},
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1315
|
+
children: /* @__PURE__ */ jsxs2(
|
|
1316
|
+
"div",
|
|
1317
|
+
{
|
|
1318
|
+
style: {
|
|
1319
|
+
display: "flex",
|
|
1320
|
+
flexDirection: "column",
|
|
1321
|
+
alignItems: "center",
|
|
1322
|
+
opacity: animIn ? 1 : 0,
|
|
1323
|
+
transform: animIn ? "translateY(0)" : `translateY(${bottom ? 6 : -6}px)`,
|
|
1324
|
+
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)",
|
|
1325
|
+
willChange: "transform, opacity"
|
|
1326
|
+
},
|
|
1327
|
+
children: [
|
|
1328
|
+
/* @__PURE__ */ jsx2("div", { style: { paddingBottom: 2 }, children: /* @__PURE__ */ jsx2(
|
|
1329
|
+
IconButton,
|
|
1330
|
+
{
|
|
1331
|
+
active: selectedMode === "component" && !historyOpen,
|
|
1332
|
+
tooltipSide,
|
|
1333
|
+
tooltip: "Component",
|
|
1334
|
+
onClick: () => {
|
|
1335
|
+
setHistoryOpen(false);
|
|
1336
|
+
onModeChange("component");
|
|
1337
|
+
},
|
|
1338
|
+
children: /* @__PURE__ */ jsx2(MousePointer2, { size: 16, strokeWidth: 1.7 })
|
|
1339
|
+
}
|
|
1340
|
+
) }),
|
|
1341
|
+
MODES.filter((m) => m.mode !== "component").map(({ mode, label, icon: ModeIcon }) => /* @__PURE__ */ jsx2(
|
|
1342
|
+
"div",
|
|
1343
|
+
{
|
|
1344
|
+
style: {
|
|
1345
|
+
maxHeight: modesExpanded ? 34 : 0,
|
|
1346
|
+
opacity: modesExpanded ? 1 : 0,
|
|
1347
|
+
transition: "max-height 200ms cubic-bezier(0.23, 1, 0.32, 1), opacity 150ms cubic-bezier(0.23, 1, 0.32, 1)"
|
|
1348
|
+
},
|
|
1349
|
+
children: /* @__PURE__ */ jsx2(
|
|
1350
|
+
IconButton,
|
|
1351
|
+
{
|
|
1352
|
+
active: selectedMode === mode && !historyOpen,
|
|
1353
|
+
tooltipSide,
|
|
1354
|
+
tooltip: label,
|
|
1355
|
+
onClick: () => {
|
|
1356
|
+
setHistoryOpen(false);
|
|
1357
|
+
onModeChange(mode);
|
|
1358
|
+
onCapture(mode);
|
|
1359
|
+
},
|
|
1360
|
+
children: /* @__PURE__ */ jsx2(ModeIcon, { size: 16, strokeWidth: 1.7 })
|
|
1361
|
+
}
|
|
1362
|
+
)
|
|
1363
|
+
},
|
|
1364
|
+
mode
|
|
1365
|
+
)),
|
|
1366
|
+
/* @__PURE__ */ jsx2(
|
|
1367
|
+
Separator,
|
|
1368
|
+
{
|
|
1369
|
+
vertical: false,
|
|
1370
|
+
onClick: () => setModesExpanded((p) => !p)
|
|
1371
|
+
}
|
|
1372
|
+
),
|
|
1373
|
+
/* @__PURE__ */ jsx2(
|
|
1374
|
+
HistoryButton,
|
|
1375
|
+
{
|
|
1376
|
+
open: historyOpen,
|
|
1377
|
+
onClick: () => {
|
|
1378
|
+
setHistoryOpen((prev) => !prev);
|
|
1379
|
+
},
|
|
1380
|
+
selectedMode,
|
|
1381
|
+
frameSettings,
|
|
1382
|
+
onFrameSettingsChange,
|
|
1383
|
+
panelSide,
|
|
1384
|
+
tooltipSide,
|
|
1385
|
+
bottom
|
|
1386
|
+
}
|
|
1387
|
+
)
|
|
1388
|
+
]
|
|
1389
|
+
}
|
|
1390
|
+
)
|
|
1391
|
+
}
|
|
1392
|
+
) : null;
|
|
1134
1393
|
return /* @__PURE__ */ jsx2(
|
|
1135
1394
|
"div",
|
|
1136
1395
|
{
|
|
@@ -1143,11 +1402,11 @@ function Toolbar({
|
|
|
1143
1402
|
display: "flex",
|
|
1144
1403
|
flexDirection: "column",
|
|
1145
1404
|
alignItems: "center",
|
|
1146
|
-
background:
|
|
1405
|
+
background: bg.base,
|
|
1147
1406
|
borderRadius: 999,
|
|
1148
1407
|
padding: 6,
|
|
1149
|
-
boxShadow:
|
|
1150
|
-
|
|
1408
|
+
boxShadow: shadow.toolbar,
|
|
1409
|
+
...fontBase,
|
|
1151
1410
|
userSelect: "none"
|
|
1152
1411
|
},
|
|
1153
1412
|
children: bottom ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
@@ -1184,14 +1443,17 @@ function IconButton({
|
|
|
1184
1443
|
style: {
|
|
1185
1444
|
position: "absolute",
|
|
1186
1445
|
...tooltipStyle,
|
|
1187
|
-
background:
|
|
1188
|
-
border:
|
|
1446
|
+
background: bg.base,
|
|
1447
|
+
border: `1px solid ${stroke.default}`,
|
|
1189
1448
|
borderRadius: 6,
|
|
1190
|
-
padding: "
|
|
1191
|
-
|
|
1192
|
-
|
|
1449
|
+
padding: "0 8px",
|
|
1450
|
+
height: 24,
|
|
1451
|
+
display: "flex",
|
|
1452
|
+
alignItems: "center",
|
|
1453
|
+
color: fg.strong,
|
|
1454
|
+
...text.label.xs,
|
|
1193
1455
|
whiteSpace: "nowrap",
|
|
1194
|
-
boxShadow:
|
|
1456
|
+
boxShadow: shadow.tooltip,
|
|
1195
1457
|
pointerEvents: "none"
|
|
1196
1458
|
},
|
|
1197
1459
|
children: tooltip
|
|
@@ -1208,13 +1470,13 @@ function IconButton({
|
|
|
1208
1470
|
height: 32,
|
|
1209
1471
|
borderRadius: "50%",
|
|
1210
1472
|
border: "none",
|
|
1211
|
-
background: active || hovered ?
|
|
1473
|
+
background: active || hovered ? state.hoverStrong : "transparent",
|
|
1212
1474
|
display: "flex",
|
|
1213
1475
|
alignItems: "center",
|
|
1214
1476
|
justifyContent: "center",
|
|
1215
1477
|
cursor: "pointer",
|
|
1216
1478
|
padding: 0,
|
|
1217
|
-
color: active || hovered ?
|
|
1479
|
+
color: active || hovered ? fg.strong : fg.sub,
|
|
1218
1480
|
transition: "background 0.12s ease, color 0.12s ease"
|
|
1219
1481
|
},
|
|
1220
1482
|
children
|
|
@@ -1222,37 +1484,11 @@ function IconButton({
|
|
|
1222
1484
|
)
|
|
1223
1485
|
] });
|
|
1224
1486
|
}
|
|
1225
|
-
function SettingsButton({
|
|
1226
|
-
open,
|
|
1227
|
-
onClick,
|
|
1228
|
-
selectedMode,
|
|
1229
|
-
frameSettings,
|
|
1230
|
-
onFrameSettingsChange,
|
|
1231
|
-
panelSide,
|
|
1232
|
-
tooltipSide,
|
|
1233
|
-
bottom
|
|
1234
|
-
}) {
|
|
1235
|
-
const verticalAlign = bottom ? { bottom: 0 } : { top: 0 };
|
|
1236
|
-
const panelStyle = panelSide === "left" ? { right: "calc(100% + 10px)", ...verticalAlign } : { left: "calc(100% + 10px)", ...verticalAlign };
|
|
1237
|
-
return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
1238
|
-
/* @__PURE__ */ jsx2(IconButton, { active: open, tooltipSide, tooltip: !open ? "Settings" : void 0, onClick, children: /* @__PURE__ */ jsx2(Settings, { size: 16, strokeWidth: 1.7 }) }),
|
|
1239
|
-
open && /* @__PURE__ */ jsx2(
|
|
1240
|
-
SettingsPanel,
|
|
1241
|
-
{
|
|
1242
|
-
style: { position: "absolute", ...panelStyle },
|
|
1243
|
-
onClose: onClick,
|
|
1244
|
-
selectedMode,
|
|
1245
|
-
frameSettings,
|
|
1246
|
-
onFrameSettingsChange
|
|
1247
|
-
}
|
|
1248
|
-
)
|
|
1249
|
-
] });
|
|
1250
|
-
}
|
|
1251
1487
|
function DropItem2({
|
|
1252
1488
|
children,
|
|
1253
1489
|
onClick,
|
|
1254
1490
|
active,
|
|
1255
|
-
accent
|
|
1491
|
+
accent: accent2
|
|
1256
1492
|
}) {
|
|
1257
1493
|
return /* @__PURE__ */ jsx2(
|
|
1258
1494
|
"button",
|
|
@@ -1262,41 +1498,79 @@ function DropItem2({
|
|
|
1262
1498
|
display: "block",
|
|
1263
1499
|
width: "100%",
|
|
1264
1500
|
padding: "7px 12px",
|
|
1265
|
-
background: active ?
|
|
1501
|
+
background: active ? state.active : "transparent",
|
|
1266
1502
|
border: "none",
|
|
1267
|
-
color:
|
|
1503
|
+
color: accent2 ? accent.highlight : fg.strong,
|
|
1268
1504
|
textAlign: "left",
|
|
1269
1505
|
cursor: "pointer",
|
|
1270
|
-
|
|
1506
|
+
...text.paragraph.sm,
|
|
1271
1507
|
fontFamily: "inherit"
|
|
1272
1508
|
},
|
|
1273
1509
|
children
|
|
1274
1510
|
}
|
|
1275
1511
|
);
|
|
1276
1512
|
}
|
|
1277
|
-
function Separator({
|
|
1513
|
+
function Separator({
|
|
1514
|
+
vertical = true,
|
|
1515
|
+
onClick
|
|
1516
|
+
}) {
|
|
1278
1517
|
return /* @__PURE__ */ jsx2(
|
|
1279
1518
|
"div",
|
|
1280
1519
|
{
|
|
1520
|
+
onClick,
|
|
1281
1521
|
style: {
|
|
1522
|
+
position: "relative",
|
|
1282
1523
|
width: vertical ? 1 : 24,
|
|
1283
1524
|
height: vertical ? 18 : 1,
|
|
1284
|
-
background:
|
|
1525
|
+
background: stroke.strong,
|
|
1285
1526
|
flexShrink: 0,
|
|
1286
|
-
margin: vertical ? "0 6px" : "6px 0"
|
|
1287
|
-
|
|
1527
|
+
margin: vertical ? "0 6px" : "6px 0",
|
|
1528
|
+
cursor: onClick ? "pointer" : void 0
|
|
1529
|
+
},
|
|
1530
|
+
children: onClick && /* @__PURE__ */ jsx2("div", { style: { position: "absolute", inset: vertical ? "0 -8px" : "-8px 0" } })
|
|
1531
|
+
}
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1534
|
+
function PanelTab({
|
|
1535
|
+
children,
|
|
1536
|
+
active,
|
|
1537
|
+
onClick
|
|
1538
|
+
}) {
|
|
1539
|
+
return /* @__PURE__ */ jsx2(
|
|
1540
|
+
"button",
|
|
1541
|
+
{
|
|
1542
|
+
onClick,
|
|
1543
|
+
style: {
|
|
1544
|
+
flex: 1,
|
|
1545
|
+
padding: "6px 0",
|
|
1546
|
+
border: "none",
|
|
1547
|
+
borderBottom: `2px solid ${active ? fg.strong : "transparent"}`,
|
|
1548
|
+
background: "transparent",
|
|
1549
|
+
color: active ? fg.strong : fg.muted,
|
|
1550
|
+
...text.label.xs,
|
|
1551
|
+
fontFamily: "inherit",
|
|
1552
|
+
cursor: "pointer",
|
|
1553
|
+
transition: "color 0.12s ease, border-color 0.12s ease"
|
|
1554
|
+
},
|
|
1555
|
+
children
|
|
1288
1556
|
}
|
|
1289
1557
|
);
|
|
1290
1558
|
}
|
|
1291
1559
|
function HistoryButton({
|
|
1292
1560
|
open,
|
|
1293
1561
|
onClick,
|
|
1562
|
+
selectedMode,
|
|
1563
|
+
frameSettings,
|
|
1564
|
+
onFrameSettingsChange,
|
|
1294
1565
|
panelSide,
|
|
1295
1566
|
tooltipSide,
|
|
1296
1567
|
bottom
|
|
1297
1568
|
}) {
|
|
1569
|
+
const [activeTab, setActiveTab] = useState3("screenshots");
|
|
1298
1570
|
const [toast, setToast] = useState3(null);
|
|
1299
1571
|
const [pushing, setPushing] = useState3(false);
|
|
1572
|
+
const [saveDir, setSaveDir] = useState3(null);
|
|
1573
|
+
const [picking, setPicking] = useState3(false);
|
|
1300
1574
|
const [repos, setRepos] = useState3([]);
|
|
1301
1575
|
const [branches, setBranches] = useState3([]);
|
|
1302
1576
|
const [screenshots, setScreenshots] = useState3([]);
|
|
@@ -1309,6 +1583,30 @@ function HistoryButton({
|
|
|
1309
1583
|
const [editingFile, setEditingFile] = useState3(null);
|
|
1310
1584
|
const [editValue, setEditValue] = useState3("");
|
|
1311
1585
|
const [hoveredThumb, setHoveredThumb] = useState3(null);
|
|
1586
|
+
useEffect2(() => {
|
|
1587
|
+
if (!open) return;
|
|
1588
|
+
fetch("/__afterbefore/config").then((r) => r.json()).then((data) => setSaveDir(data.saveDir)).catch(() => {
|
|
1589
|
+
});
|
|
1590
|
+
}, [open]);
|
|
1591
|
+
const handlePickFolder = async () => {
|
|
1592
|
+
setPicking(true);
|
|
1593
|
+
try {
|
|
1594
|
+
const res = await fetch("/__afterbefore/pick-folder", { method: "POST" });
|
|
1595
|
+
const data = await res.json();
|
|
1596
|
+
if (data.folder) {
|
|
1597
|
+
await fetch("/__afterbefore/config", {
|
|
1598
|
+
method: "POST",
|
|
1599
|
+
headers: { "Content-Type": "application/json" },
|
|
1600
|
+
body: JSON.stringify({ saveDir: data.folder })
|
|
1601
|
+
});
|
|
1602
|
+
setSaveDir(data.folder);
|
|
1603
|
+
}
|
|
1604
|
+
} catch {
|
|
1605
|
+
} finally {
|
|
1606
|
+
setPicking(false);
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
const shortDir = saveDir ? saveDir.replace(/^\/Users\/[^/]+/, "~") : "~/Desktop";
|
|
1312
1610
|
useEffect2(() => {
|
|
1313
1611
|
if (!open) {
|
|
1314
1612
|
setRepoDropOpen(false);
|
|
@@ -1425,255 +1723,259 @@ function HistoryButton({
|
|
|
1425
1723
|
maxWidth: 360,
|
|
1426
1724
|
padding: "10px 12px",
|
|
1427
1725
|
borderRadius: 12,
|
|
1428
|
-
background:
|
|
1429
|
-
border:
|
|
1430
|
-
boxShadow:
|
|
1726
|
+
background: bg.base,
|
|
1727
|
+
border: `1px solid ${stroke.default}`,
|
|
1728
|
+
boxShadow: shadow.panel,
|
|
1729
|
+
animation: "ab-panel-in 150ms cubic-bezier(0.23, 1, 0.32, 1)"
|
|
1431
1730
|
},
|
|
1432
1731
|
children: [
|
|
1433
|
-
/* @__PURE__ */
|
|
1434
|
-
"
|
|
1732
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 2, marginBottom: 10 }, children: [
|
|
1733
|
+
/* @__PURE__ */ jsx2(PanelTab, { active: activeTab === "screenshots", onClick: () => setActiveTab("screenshots"), children: "Screenshots" }),
|
|
1734
|
+
/* @__PURE__ */ jsx2(PanelTab, { active: activeTab === "settings", onClick: () => setActiveTab("settings"), children: "Settings" })
|
|
1735
|
+
] }),
|
|
1736
|
+
activeTab === "settings" && /* @__PURE__ */ jsx2(
|
|
1737
|
+
SettingsContent,
|
|
1435
1738
|
{
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
marginBottom: 10
|
|
1442
|
-
},
|
|
1443
|
-
children: "Screenshots"
|
|
1739
|
+
frameSettings,
|
|
1740
|
+
onFrameSettingsChange,
|
|
1741
|
+
saveDir: shortDir,
|
|
1742
|
+
picking,
|
|
1743
|
+
onPickFolder: handlePickFolder
|
|
1444
1744
|
}
|
|
1445
1745
|
),
|
|
1446
|
-
/* @__PURE__ */ jsxs2(
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1746
|
+
activeTab === "screenshots" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1747
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginBottom: 10 }, children: [
|
|
1748
|
+
/* @__PURE__ */ jsx2(
|
|
1749
|
+
FilterDropdown,
|
|
1750
|
+
{
|
|
1751
|
+
label: "Project",
|
|
1752
|
+
value: selectedRepo,
|
|
1753
|
+
options: repos,
|
|
1754
|
+
isOpen: repoDropOpen,
|
|
1755
|
+
onToggle: () => {
|
|
1756
|
+
setRepoDropOpen((p) => !p);
|
|
1757
|
+
setBranchDropOpen(false);
|
|
1758
|
+
},
|
|
1759
|
+
onSelect: (repo) => {
|
|
1760
|
+
setSelectedRepo(repo);
|
|
1761
|
+
setSelectedBranch(null);
|
|
1762
|
+
setRepoDropOpen(false);
|
|
1763
|
+
}
|
|
1462
1764
|
}
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1765
|
+
),
|
|
1766
|
+
/* @__PURE__ */ jsx2(
|
|
1767
|
+
FilterDropdown,
|
|
1768
|
+
{
|
|
1769
|
+
label: "Branch",
|
|
1770
|
+
value: selectedBranch,
|
|
1771
|
+
options: branches,
|
|
1772
|
+
isOpen: branchDropOpen,
|
|
1773
|
+
onToggle: () => {
|
|
1774
|
+
setBranchDropOpen((p) => !p);
|
|
1775
|
+
setRepoDropOpen(false);
|
|
1776
|
+
},
|
|
1777
|
+
onSelect: (branch) => {
|
|
1778
|
+
setSelectedBranch(branch);
|
|
1779
|
+
setBranchDropOpen(false);
|
|
1780
|
+
}
|
|
1479
1781
|
}
|
|
1480
|
-
|
|
1481
|
-
)
|
|
1482
|
-
|
|
1483
|
-
loading ? /* @__PURE__ */ jsx2(
|
|
1484
|
-
"div",
|
|
1485
|
-
{
|
|
1486
|
-
style: {
|
|
1487
|
-
padding: "12px 0",
|
|
1488
|
-
textAlign: "center",
|
|
1489
|
-
fontSize: 12,
|
|
1490
|
-
color: "rgba(255, 255, 255, 0.35)"
|
|
1491
|
-
},
|
|
1492
|
-
children: "Loading..."
|
|
1493
|
-
}
|
|
1494
|
-
) : screenshots.length === 0 ? /* @__PURE__ */ jsx2(
|
|
1495
|
-
"div",
|
|
1496
|
-
{
|
|
1497
|
-
style: {
|
|
1498
|
-
padding: "12px 0",
|
|
1499
|
-
textAlign: "center",
|
|
1500
|
-
fontSize: 12,
|
|
1501
|
-
color: "rgba(255, 255, 255, 0.35)"
|
|
1502
|
-
},
|
|
1503
|
-
children: "No screenshots yet"
|
|
1504
|
-
}
|
|
1505
|
-
) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1506
|
-
/* @__PURE__ */ jsx2(
|
|
1782
|
+
)
|
|
1783
|
+
] }),
|
|
1784
|
+
loading ? /* @__PURE__ */ jsx2(
|
|
1507
1785
|
"div",
|
|
1508
1786
|
{
|
|
1509
1787
|
style: {
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
gap: 8
|
|
1788
|
+
padding: "12px 0",
|
|
1789
|
+
textAlign: "center",
|
|
1790
|
+
...text.paragraph.xs,
|
|
1791
|
+
color: fg.faint
|
|
1515
1792
|
},
|
|
1516
|
-
children:
|
|
1517
|
-
const imgUrl = `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(shot.filename)}`;
|
|
1518
|
-
const isEditing = editingFile === shot.filename;
|
|
1519
|
-
return /* @__PURE__ */ jsxs2(
|
|
1520
|
-
"div",
|
|
1521
|
-
{
|
|
1522
|
-
style: {
|
|
1523
|
-
display: "flex",
|
|
1524
|
-
gap: 10,
|
|
1525
|
-
alignItems: "center"
|
|
1526
|
-
},
|
|
1527
|
-
children: [
|
|
1528
|
-
/* @__PURE__ */ jsxs2(
|
|
1529
|
-
"div",
|
|
1530
|
-
{
|
|
1531
|
-
style: {
|
|
1532
|
-
position: "relative",
|
|
1533
|
-
width: 56,
|
|
1534
|
-
height: 36,
|
|
1535
|
-
flexShrink: 0,
|
|
1536
|
-
borderRadius: 4,
|
|
1537
|
-
overflow: "hidden",
|
|
1538
|
-
cursor: "pointer"
|
|
1539
|
-
},
|
|
1540
|
-
onMouseEnter: () => setHoveredThumb(shot.filename),
|
|
1541
|
-
onMouseLeave: () => setHoveredThumb(null),
|
|
1542
|
-
onClick: () => setLightboxSrc(imgUrl),
|
|
1543
|
-
children: [
|
|
1544
|
-
/* @__PURE__ */ jsx2(
|
|
1545
|
-
"img",
|
|
1546
|
-
{
|
|
1547
|
-
src: imgUrl,
|
|
1548
|
-
alt: "",
|
|
1549
|
-
style: {
|
|
1550
|
-
width: 56,
|
|
1551
|
-
height: 36,
|
|
1552
|
-
objectFit: "cover",
|
|
1553
|
-
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1554
|
-
borderRadius: 4,
|
|
1555
|
-
background: "rgba(255, 255, 255, 0.05)",
|
|
1556
|
-
display: "block"
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
),
|
|
1560
|
-
/* @__PURE__ */ jsx2(
|
|
1561
|
-
"div",
|
|
1562
|
-
{
|
|
1563
|
-
style: {
|
|
1564
|
-
position: "absolute",
|
|
1565
|
-
inset: 0,
|
|
1566
|
-
background: "rgba(0, 0, 0, 0.55)",
|
|
1567
|
-
display: "flex",
|
|
1568
|
-
alignItems: "center",
|
|
1569
|
-
justifyContent: "center",
|
|
1570
|
-
borderRadius: 4,
|
|
1571
|
-
opacity: hoveredThumb === shot.filename ? 1 : 0,
|
|
1572
|
-
transition: "opacity 0.15s ease"
|
|
1573
|
-
},
|
|
1574
|
-
children: /* @__PURE__ */ jsx2(Eye, { size: 16, strokeWidth: 1.8, color: "rgba(255, 255, 255, 0.9)" })
|
|
1575
|
-
}
|
|
1576
|
-
)
|
|
1577
|
-
]
|
|
1578
|
-
}
|
|
1579
|
-
),
|
|
1580
|
-
/* @__PURE__ */ jsx2("div", { style: { flex: 1, minWidth: 0 }, children: isEditing ? /* @__PURE__ */ jsx2(
|
|
1581
|
-
"input",
|
|
1582
|
-
{
|
|
1583
|
-
autoFocus: true,
|
|
1584
|
-
value: editValue,
|
|
1585
|
-
onChange: (e) => setEditValue(e.target.value),
|
|
1586
|
-
onKeyDown: (e) => {
|
|
1587
|
-
if (e.key === "Enter") handleRename(shot.filename, editValue);
|
|
1588
|
-
if (e.key === "Escape") setEditingFile(null);
|
|
1589
|
-
},
|
|
1590
|
-
onBlur: () => handleRename(shot.filename, editValue),
|
|
1591
|
-
style: {
|
|
1592
|
-
width: "100%",
|
|
1593
|
-
fontSize: 12,
|
|
1594
|
-
color: "rgba(255, 255, 255, 0.88)",
|
|
1595
|
-
background: "rgba(255, 255, 255, 0.1)",
|
|
1596
|
-
border: "1px solid rgba(255, 255, 255, 0.2)",
|
|
1597
|
-
borderRadius: 4,
|
|
1598
|
-
padding: "2px 6px",
|
|
1599
|
-
outline: "none",
|
|
1600
|
-
fontFamily: "inherit"
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
) : /* @__PURE__ */ jsx2(
|
|
1604
|
-
"div",
|
|
1605
|
-
{
|
|
1606
|
-
onClick: () => {
|
|
1607
|
-
setEditingFile(shot.filename);
|
|
1608
|
-
setEditValue(shot.filename.replace(/\.png$/, ""));
|
|
1609
|
-
},
|
|
1610
|
-
style: {
|
|
1611
|
-
fontSize: 12,
|
|
1612
|
-
color: "rgba(255, 255, 255, 0.88)",
|
|
1613
|
-
cursor: "pointer",
|
|
1614
|
-
overflow: "hidden",
|
|
1615
|
-
textOverflow: "ellipsis",
|
|
1616
|
-
whiteSpace: "nowrap"
|
|
1617
|
-
},
|
|
1618
|
-
title: "Click to rename",
|
|
1619
|
-
children: formatTimestamp(shot.filename)
|
|
1620
|
-
}
|
|
1621
|
-
) }),
|
|
1622
|
-
/* @__PURE__ */ jsx2(
|
|
1623
|
-
"button",
|
|
1624
|
-
{
|
|
1625
|
-
onClick: () => handleDelete(shot.filename),
|
|
1626
|
-
title: "Delete screenshot",
|
|
1627
|
-
style: {
|
|
1628
|
-
flexShrink: 0,
|
|
1629
|
-
width: 24,
|
|
1630
|
-
height: 24,
|
|
1631
|
-
borderRadius: 4,
|
|
1632
|
-
border: "none",
|
|
1633
|
-
background: "transparent",
|
|
1634
|
-
color: "rgba(255, 255, 255, 0.35)",
|
|
1635
|
-
cursor: "pointer",
|
|
1636
|
-
display: "flex",
|
|
1637
|
-
alignItems: "center",
|
|
1638
|
-
justifyContent: "center",
|
|
1639
|
-
padding: 0
|
|
1640
|
-
},
|
|
1641
|
-
onMouseEnter: (e) => {
|
|
1642
|
-
e.currentTarget.style.color = "rgba(239, 68, 68, 0.9)";
|
|
1643
|
-
e.currentTarget.style.background = "rgba(239, 68, 68, 0.1)";
|
|
1644
|
-
},
|
|
1645
|
-
onMouseLeave: (e) => {
|
|
1646
|
-
e.currentTarget.style.color = "rgba(255, 255, 255, 0.35)";
|
|
1647
|
-
e.currentTarget.style.background = "transparent";
|
|
1648
|
-
},
|
|
1649
|
-
children: /* @__PURE__ */ jsx2(Trash22, { size: 13, strokeWidth: 1.8 })
|
|
1650
|
-
}
|
|
1651
|
-
)
|
|
1652
|
-
]
|
|
1653
|
-
},
|
|
1654
|
-
shot.filename
|
|
1655
|
-
);
|
|
1656
|
-
})
|
|
1793
|
+
children: "Loading..."
|
|
1657
1794
|
}
|
|
1658
|
-
)
|
|
1659
|
-
/* @__PURE__ */ jsx2(
|
|
1795
|
+
) : screenshots.length === 0 ? /* @__PURE__ */ jsx2(
|
|
1660
1796
|
"div",
|
|
1661
1797
|
{
|
|
1662
1798
|
style: {
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1799
|
+
padding: "12px 0",
|
|
1800
|
+
textAlign: "center",
|
|
1801
|
+
...text.paragraph.xs,
|
|
1802
|
+
color: fg.faint
|
|
1803
|
+
},
|
|
1804
|
+
children: "No screenshots yet"
|
|
1667
1805
|
}
|
|
1668
|
-
),
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1806
|
+
) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1807
|
+
/* @__PURE__ */ jsx2(
|
|
1808
|
+
"div",
|
|
1809
|
+
{
|
|
1810
|
+
style: {
|
|
1811
|
+
maxHeight: 240,
|
|
1812
|
+
overflowY: "auto",
|
|
1813
|
+
display: "flex",
|
|
1814
|
+
flexDirection: "column",
|
|
1815
|
+
gap: 8
|
|
1816
|
+
},
|
|
1817
|
+
children: screenshots.map((shot) => {
|
|
1818
|
+
const imgUrl = `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(shot.filename)}`;
|
|
1819
|
+
const isEditing = editingFile === shot.filename;
|
|
1820
|
+
return /* @__PURE__ */ jsxs2(
|
|
1821
|
+
"div",
|
|
1822
|
+
{
|
|
1823
|
+
style: {
|
|
1824
|
+
display: "flex",
|
|
1825
|
+
gap: 10,
|
|
1826
|
+
alignItems: "center"
|
|
1827
|
+
},
|
|
1828
|
+
children: [
|
|
1829
|
+
/* @__PURE__ */ jsxs2(
|
|
1830
|
+
"div",
|
|
1831
|
+
{
|
|
1832
|
+
style: {
|
|
1833
|
+
position: "relative",
|
|
1834
|
+
width: 56,
|
|
1835
|
+
height: 36,
|
|
1836
|
+
flexShrink: 0,
|
|
1837
|
+
borderRadius: 4,
|
|
1838
|
+
overflow: "hidden",
|
|
1839
|
+
cursor: "pointer"
|
|
1840
|
+
},
|
|
1841
|
+
onMouseEnter: () => setHoveredThumb(shot.filename),
|
|
1842
|
+
onMouseLeave: () => setHoveredThumb(null),
|
|
1843
|
+
onClick: () => setLightboxSrc(imgUrl),
|
|
1844
|
+
children: [
|
|
1845
|
+
/* @__PURE__ */ jsx2(
|
|
1846
|
+
"img",
|
|
1847
|
+
{
|
|
1848
|
+
src: imgUrl,
|
|
1849
|
+
alt: "",
|
|
1850
|
+
style: {
|
|
1851
|
+
width: 56,
|
|
1852
|
+
height: 36,
|
|
1853
|
+
objectFit: "cover",
|
|
1854
|
+
border: `1px solid ${stroke.default}`,
|
|
1855
|
+
borderRadius: 4,
|
|
1856
|
+
background: state.subtle,
|
|
1857
|
+
display: "block"
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
),
|
|
1861
|
+
/* @__PURE__ */ jsx2(
|
|
1862
|
+
"div",
|
|
1863
|
+
{
|
|
1864
|
+
style: {
|
|
1865
|
+
position: "absolute",
|
|
1866
|
+
inset: 0,
|
|
1867
|
+
background: "rgba(0, 0, 0, 0.55)",
|
|
1868
|
+
display: "flex",
|
|
1869
|
+
alignItems: "center",
|
|
1870
|
+
justifyContent: "center",
|
|
1871
|
+
borderRadius: 4,
|
|
1872
|
+
opacity: hoveredThumb === shot.filename ? 1 : 0,
|
|
1873
|
+
transition: "opacity 0.15s ease"
|
|
1874
|
+
},
|
|
1875
|
+
children: /* @__PURE__ */ jsx2(Eye, { size: 16, strokeWidth: 1.8, color: fg.strong })
|
|
1876
|
+
}
|
|
1877
|
+
)
|
|
1878
|
+
]
|
|
1879
|
+
}
|
|
1880
|
+
),
|
|
1881
|
+
/* @__PURE__ */ jsx2("div", { style: { flex: 1, minWidth: 0 }, children: isEditing ? /* @__PURE__ */ jsx2(
|
|
1882
|
+
"input",
|
|
1883
|
+
{
|
|
1884
|
+
autoFocus: true,
|
|
1885
|
+
value: editValue,
|
|
1886
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
1887
|
+
onKeyDown: (e) => {
|
|
1888
|
+
if (e.key === "Enter") handleRename(shot.filename, editValue);
|
|
1889
|
+
if (e.key === "Escape") setEditingFile(null);
|
|
1890
|
+
},
|
|
1891
|
+
onBlur: () => handleRename(shot.filename, editValue),
|
|
1892
|
+
style: {
|
|
1893
|
+
width: "100%",
|
|
1894
|
+
...text.label.xs,
|
|
1895
|
+
color: fg.strong,
|
|
1896
|
+
background: state.hover,
|
|
1897
|
+
border: `1px solid ${stroke.interactive}`,
|
|
1898
|
+
borderRadius: 4,
|
|
1899
|
+
padding: "2px 6px",
|
|
1900
|
+
outline: "none",
|
|
1901
|
+
fontFamily: "inherit"
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
) : /* @__PURE__ */ jsx2(
|
|
1905
|
+
"div",
|
|
1906
|
+
{
|
|
1907
|
+
onClick: () => {
|
|
1908
|
+
setEditingFile(shot.filename);
|
|
1909
|
+
setEditValue(shot.filename.replace(/\.png$/, ""));
|
|
1910
|
+
},
|
|
1911
|
+
style: {
|
|
1912
|
+
...text.label.xs,
|
|
1913
|
+
color: fg.strong,
|
|
1914
|
+
cursor: "pointer",
|
|
1915
|
+
overflow: "hidden",
|
|
1916
|
+
textOverflow: "ellipsis",
|
|
1917
|
+
whiteSpace: "nowrap"
|
|
1918
|
+
},
|
|
1919
|
+
title: "Click to rename",
|
|
1920
|
+
children: formatTimestamp(shot.filename)
|
|
1921
|
+
}
|
|
1922
|
+
) }),
|
|
1923
|
+
/* @__PURE__ */ jsx2(
|
|
1924
|
+
"button",
|
|
1925
|
+
{
|
|
1926
|
+
onClick: () => handleDelete(shot.filename),
|
|
1927
|
+
title: "Delete screenshot",
|
|
1928
|
+
style: {
|
|
1929
|
+
flexShrink: 0,
|
|
1930
|
+
width: 24,
|
|
1931
|
+
height: 24,
|
|
1932
|
+
borderRadius: 4,
|
|
1933
|
+
border: "none",
|
|
1934
|
+
background: "transparent",
|
|
1935
|
+
color: fg.faint,
|
|
1936
|
+
cursor: "pointer",
|
|
1937
|
+
display: "flex",
|
|
1938
|
+
alignItems: "center",
|
|
1939
|
+
justifyContent: "center",
|
|
1940
|
+
padding: 0
|
|
1941
|
+
},
|
|
1942
|
+
onMouseEnter: (e) => {
|
|
1943
|
+
e.currentTarget.style.color = feedback.error;
|
|
1944
|
+
e.currentTarget.style.background = feedback.errorBg;
|
|
1945
|
+
},
|
|
1946
|
+
onMouseLeave: (e) => {
|
|
1947
|
+
e.currentTarget.style.color = fg.faint;
|
|
1948
|
+
e.currentTarget.style.background = "transparent";
|
|
1949
|
+
},
|
|
1950
|
+
children: /* @__PURE__ */ jsx2(Trash22, { size: 13, strokeWidth: 1.8 })
|
|
1951
|
+
}
|
|
1952
|
+
)
|
|
1953
|
+
]
|
|
1954
|
+
},
|
|
1955
|
+
shot.filename
|
|
1956
|
+
);
|
|
1957
|
+
})
|
|
1958
|
+
}
|
|
1959
|
+
),
|
|
1960
|
+
/* @__PURE__ */ jsx2(
|
|
1961
|
+
"div",
|
|
1962
|
+
{
|
|
1963
|
+
style: {
|
|
1964
|
+
height: 1,
|
|
1965
|
+
background: state.active,
|
|
1966
|
+
margin: "8px 0"
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
),
|
|
1970
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
1971
|
+
/* @__PURE__ */ jsxs2(ActionButton, { onClick: handleOpenFolder, children: [
|
|
1972
|
+
/* @__PURE__ */ jsx2(FolderOpen, { size: 13, strokeWidth: 1.8 }),
|
|
1973
|
+
"Open Folder"
|
|
1974
|
+
] }),
|
|
1975
|
+
/* @__PURE__ */ jsxs2(ActionButton, { onClick: handlePush, disabled: pushing, children: [
|
|
1976
|
+
/* @__PURE__ */ jsx2(ArrowUp, { size: 13, strokeWidth: 1.8 }),
|
|
1977
|
+
pushing ? "Pushing..." : "Push to PR"
|
|
1978
|
+
] })
|
|
1677
1979
|
] })
|
|
1678
1980
|
] })
|
|
1679
1981
|
] }),
|
|
@@ -1688,12 +1990,11 @@ function HistoryButton({
|
|
|
1688
1990
|
marginBottom: 8,
|
|
1689
1991
|
padding: "6px 12px",
|
|
1690
1992
|
borderRadius: 6,
|
|
1691
|
-
|
|
1692
|
-
fontWeight: 500,
|
|
1993
|
+
...text.label.xs,
|
|
1693
1994
|
whiteSpace: "nowrap",
|
|
1694
1995
|
color: "white",
|
|
1695
|
-
background: toast.type === "success" ?
|
|
1696
|
-
boxShadow:
|
|
1996
|
+
background: toast.type === "success" ? feedback.success : feedback.error,
|
|
1997
|
+
boxShadow: shadow.toast
|
|
1697
1998
|
},
|
|
1698
1999
|
children: toast.message
|
|
1699
2000
|
}
|
|
@@ -1701,65 +2002,68 @@ function HistoryButton({
|
|
|
1701
2002
|
]
|
|
1702
2003
|
}
|
|
1703
2004
|
),
|
|
1704
|
-
lightboxSrc &&
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
2005
|
+
lightboxSrc && createPortal(
|
|
2006
|
+
/* @__PURE__ */ jsxs2(
|
|
2007
|
+
"div",
|
|
2008
|
+
{
|
|
2009
|
+
"data-afterbefore": "true",
|
|
2010
|
+
onClick: () => setLightboxSrc(null),
|
|
2011
|
+
onKeyDown: (e) => {
|
|
2012
|
+
if (e.key === "Escape") setLightboxSrc(null);
|
|
2013
|
+
},
|
|
2014
|
+
style: {
|
|
2015
|
+
position: "fixed",
|
|
2016
|
+
inset: 0,
|
|
2017
|
+
zIndex: 2147483647,
|
|
2018
|
+
background: "rgba(0, 0, 0, 0.85)",
|
|
2019
|
+
display: "flex",
|
|
2020
|
+
alignItems: "center",
|
|
2021
|
+
justifyContent: "center",
|
|
2022
|
+
cursor: "zoom-out"
|
|
2023
|
+
},
|
|
2024
|
+
children: [
|
|
2025
|
+
/* @__PURE__ */ jsx2(
|
|
2026
|
+
"img",
|
|
2027
|
+
{
|
|
2028
|
+
src: lightboxSrc,
|
|
2029
|
+
alt: "",
|
|
2030
|
+
onClick: (e) => e.stopPropagation(),
|
|
2031
|
+
style: {
|
|
2032
|
+
maxWidth: "90vw",
|
|
2033
|
+
maxHeight: "calc(100vh - 64px)",
|
|
2034
|
+
borderRadius: 8,
|
|
2035
|
+
boxShadow: "0 20px 60px rgba(0, 0, 0, 0.5)",
|
|
2036
|
+
cursor: "default"
|
|
2037
|
+
}
|
|
1735
2038
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
2039
|
+
),
|
|
2040
|
+
/* @__PURE__ */ jsx2(
|
|
2041
|
+
"button",
|
|
2042
|
+
{
|
|
2043
|
+
onClick: () => setLightboxSrc(null),
|
|
2044
|
+
style: {
|
|
2045
|
+
position: "absolute",
|
|
2046
|
+
top: 16,
|
|
2047
|
+
right: 16,
|
|
2048
|
+
width: 32,
|
|
2049
|
+
height: 32,
|
|
2050
|
+
borderRadius: "50%",
|
|
2051
|
+
border: "none",
|
|
2052
|
+
background: state.pressed,
|
|
2053
|
+
color: "white",
|
|
2054
|
+
cursor: "pointer",
|
|
2055
|
+
display: "flex",
|
|
2056
|
+
alignItems: "center",
|
|
2057
|
+
justifyContent: "center",
|
|
2058
|
+
padding: 0
|
|
2059
|
+
},
|
|
2060
|
+
children: /* @__PURE__ */ jsx2(X2, { size: 18, strokeWidth: 2 })
|
|
2061
|
+
}
|
|
2062
|
+
)
|
|
2063
|
+
]
|
|
2064
|
+
}
|
|
2065
|
+
),
|
|
2066
|
+
document.body
|
|
1763
2067
|
)
|
|
1764
2068
|
] });
|
|
1765
2069
|
}
|
|
@@ -1776,9 +2080,8 @@ function FilterDropdown({
|
|
|
1776
2080
|
"div",
|
|
1777
2081
|
{
|
|
1778
2082
|
style: {
|
|
1779
|
-
|
|
1780
|
-
color:
|
|
1781
|
-
letterSpacing: "0.02em",
|
|
2083
|
+
...text.subheading.xxs,
|
|
2084
|
+
color: fg.muted,
|
|
1782
2085
|
marginBottom: 3
|
|
1783
2086
|
},
|
|
1784
2087
|
children: label
|
|
@@ -1798,11 +2101,11 @@ function FilterDropdown({
|
|
|
1798
2101
|
height: 30,
|
|
1799
2102
|
padding: "0 8px",
|
|
1800
2103
|
borderRadius: 7,
|
|
1801
|
-
border:
|
|
1802
|
-
background:
|
|
1803
|
-
color:
|
|
2104
|
+
border: `1px solid ${stroke.default}`,
|
|
2105
|
+
background: state.input,
|
|
2106
|
+
color: fg.strong,
|
|
1804
2107
|
cursor: "pointer",
|
|
1805
|
-
|
|
2108
|
+
...text.label.xs,
|
|
1806
2109
|
fontFamily: "inherit"
|
|
1807
2110
|
},
|
|
1808
2111
|
children: [
|
|
@@ -1831,11 +2134,11 @@ function FilterDropdown({
|
|
|
1831
2134
|
right: 0,
|
|
1832
2135
|
maxHeight: 160,
|
|
1833
2136
|
overflowY: "auto",
|
|
1834
|
-
background:
|
|
1835
|
-
border:
|
|
2137
|
+
background: bg.base,
|
|
2138
|
+
border: `1px solid ${stroke.default}`,
|
|
1836
2139
|
borderRadius: 8,
|
|
1837
2140
|
padding: "4px 0",
|
|
1838
|
-
boxShadow:
|
|
2141
|
+
boxShadow: shadow.dropdown,
|
|
1839
2142
|
zIndex: 1
|
|
1840
2143
|
},
|
|
1841
2144
|
children: options.map((opt) => /* @__PURE__ */ jsx2(
|
|
@@ -1872,9 +2175,9 @@ function ActionButton({
|
|
|
1872
2175
|
width: "100%",
|
|
1873
2176
|
padding: "6px 8px",
|
|
1874
2177
|
border: "none",
|
|
1875
|
-
background: hovered ?
|
|
1876
|
-
color:
|
|
1877
|
-
|
|
2178
|
+
background: hovered ? state.active : "transparent",
|
|
2179
|
+
color: fg.default,
|
|
2180
|
+
...text.label.xs,
|
|
1878
2181
|
borderRadius: 6,
|
|
1879
2182
|
cursor: disabled ? "wait" : "pointer",
|
|
1880
2183
|
textAlign: "left",
|
|
@@ -1907,18 +2210,18 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1907
2210
|
const hoveredEl = useRef3(null);
|
|
1908
2211
|
const styleEl = useRef3(null);
|
|
1909
2212
|
useEffect3(() => {
|
|
1910
|
-
const
|
|
1911
|
-
|
|
1912
|
-
|
|
2213
|
+
const style2 = document.createElement("style");
|
|
2214
|
+
style2.setAttribute("data-afterbefore", "true");
|
|
2215
|
+
style2.textContent = [
|
|
1913
2216
|
"* { cursor: crosshair !important; }",
|
|
1914
2217
|
"[data-afterbefore], [data-afterbefore] * { cursor: auto !important; }",
|
|
1915
2218
|
"[data-afterbefore] button, [data-afterbefore] label, [data-afterbefore] a { cursor: pointer !important; }",
|
|
1916
2219
|
"[data-afterbefore] input, [data-afterbefore] textarea { cursor: text !important; }"
|
|
1917
2220
|
].join("\n");
|
|
1918
|
-
document.head.appendChild(
|
|
1919
|
-
styleEl.current =
|
|
2221
|
+
document.head.appendChild(style2);
|
|
2222
|
+
styleEl.current = style2;
|
|
1920
2223
|
return () => {
|
|
1921
|
-
|
|
2224
|
+
style2.remove();
|
|
1922
2225
|
};
|
|
1923
2226
|
}, []);
|
|
1924
2227
|
const isOverlayElement = useCallback3((el) => {
|
|
@@ -2015,12 +2318,15 @@ async function saveCapture(mode, dataUrl) {
|
|
|
2015
2318
|
}
|
|
2016
2319
|
}
|
|
2017
2320
|
function AfterBefore() {
|
|
2018
|
-
const { state, captureComplete, reset } = useOverlayState();
|
|
2321
|
+
const { state: state2, captureComplete, reset } = useOverlayState();
|
|
2019
2322
|
const [toolbarActive, setToolbarActive] = useState5(false);
|
|
2020
2323
|
const [inspectorActive, setInspectorActive] = useState5(false);
|
|
2021
2324
|
const [loading, setLoading] = useState5(false);
|
|
2022
2325
|
const [selectedMode, setSelectedMode] = useState5("component");
|
|
2023
2326
|
const [frameSettings, setFrameSettings] = useState5(DEFAULT_FRAME_SETTINGS);
|
|
2327
|
+
useEffect4(() => {
|
|
2328
|
+
injectInterFont();
|
|
2329
|
+
}, []);
|
|
2024
2330
|
useEffect4(() => {
|
|
2025
2331
|
try {
|
|
2026
2332
|
const stored = localStorage.getItem("ab-frame-settings");
|
|
@@ -2037,16 +2343,16 @@ function AfterBefore() {
|
|
|
2037
2343
|
}
|
|
2038
2344
|
}, []);
|
|
2039
2345
|
useEffect4(() => {
|
|
2040
|
-
if (
|
|
2346
|
+
if (state2.phase === "ready") {
|
|
2041
2347
|
const timer = setTimeout(() => {
|
|
2042
2348
|
reset();
|
|
2043
2349
|
}, 1500);
|
|
2044
2350
|
return () => clearTimeout(timer);
|
|
2045
2351
|
}
|
|
2046
|
-
}, [
|
|
2352
|
+
}, [state2.phase, reset]);
|
|
2047
2353
|
const handleToggle = useCallback4(() => {
|
|
2048
2354
|
if (loading) return;
|
|
2049
|
-
if (
|
|
2355
|
+
if (state2.phase === "ready") {
|
|
2050
2356
|
reset();
|
|
2051
2357
|
}
|
|
2052
2358
|
if (toolbarActive || inspectorActive) {
|
|
@@ -2061,7 +2367,7 @@ function AfterBefore() {
|
|
|
2061
2367
|
setInspectorActive(false);
|
|
2062
2368
|
}
|
|
2063
2369
|
}
|
|
2064
|
-
}, [
|
|
2370
|
+
}, [state2.phase, loading, toolbarActive, inspectorActive, selectedMode, reset]);
|
|
2065
2371
|
const performCapture = useCallback4(
|
|
2066
2372
|
async (mode, element) => {
|
|
2067
2373
|
setLoading(true);
|
|
@@ -2128,7 +2434,7 @@ function AfterBefore() {
|
|
|
2128
2434
|
{
|
|
2129
2435
|
expanded: toolbarActive,
|
|
2130
2436
|
onToggle: handleToggle,
|
|
2131
|
-
phase:
|
|
2437
|
+
phase: state2.phase,
|
|
2132
2438
|
loading,
|
|
2133
2439
|
selectedMode,
|
|
2134
2440
|
onModeChange: handleModeChange,
|