afterbefore 0.2.13 → 0.2.15
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/README.md +41 -30
- package/dist/{chunk-N33DB2F6.js → chunk-XSDO6N5Q.js} +146 -7
- package/dist/chunk-XSDO6N5Q.js.map +1 -0
- package/dist/overlay/index.js +648 -476
- package/dist/overlay/index.js.map +1 -1
- package/dist/server/middleware.js +9 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/route.d.ts +6 -2
- package/dist/server/route.js +13 -3
- package/dist/server/route.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-N33DB2F6.js.map +0 -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 useState5, useCallback as useCallback5, useRef as useRef4, useEffect as useEffect4 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/overlay/state.ts
|
|
7
7
|
import { useState, useCallback } from "react";
|
|
@@ -181,11 +181,13 @@ function loadImage(src) {
|
|
|
181
181
|
import { useRef, useCallback as useCallback2, useEffect, useState as useState2 } from "react";
|
|
182
182
|
import { Camera, Check, LoaderCircle } from "lucide-react";
|
|
183
183
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
184
|
-
var
|
|
184
|
+
var CONTAINER_SIZE = 38;
|
|
185
|
+
var ICON_SIZE = CONTAINER_SIZE;
|
|
185
186
|
var EDGE_MARGIN = 24;
|
|
186
187
|
function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
187
188
|
const ref = useRef(null);
|
|
188
189
|
const [pos, setPos] = useState2({ x: -1, y: -1 });
|
|
190
|
+
const [dragging, setDragging] = useState2(false);
|
|
189
191
|
const dragState = useRef(null);
|
|
190
192
|
useEffect(() => {
|
|
191
193
|
setPos((prev) => {
|
|
@@ -206,6 +208,7 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
206
208
|
const handleMouseDown = useCallback2(
|
|
207
209
|
(e) => {
|
|
208
210
|
e.preventDefault();
|
|
211
|
+
setDragging(true);
|
|
209
212
|
dragState.current = {
|
|
210
213
|
dragging: true,
|
|
211
214
|
startX: e.clientX,
|
|
@@ -240,6 +243,7 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
240
243
|
if (ds.distance < 5) {
|
|
241
244
|
onClick();
|
|
242
245
|
}
|
|
246
|
+
setDragging(false);
|
|
243
247
|
dragState.current = null;
|
|
244
248
|
};
|
|
245
249
|
window.addEventListener("mousemove", handleMouseMove);
|
|
@@ -260,17 +264,17 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
260
264
|
position: "fixed",
|
|
261
265
|
left: pos.x,
|
|
262
266
|
top: pos.y,
|
|
263
|
-
width:
|
|
264
|
-
height:
|
|
267
|
+
width: CONTAINER_SIZE,
|
|
268
|
+
height: CONTAINER_SIZE,
|
|
265
269
|
borderRadius: "50%",
|
|
266
270
|
background: "rgba(32, 32, 36, 0.92)",
|
|
267
271
|
backdropFilter: "blur(20px)",
|
|
268
272
|
WebkitBackdropFilter: "blur(20px)",
|
|
269
|
-
border: "
|
|
273
|
+
border: "none",
|
|
270
274
|
display: "flex",
|
|
271
275
|
alignItems: "center",
|
|
272
276
|
justifyContent: "center",
|
|
273
|
-
cursor: "
|
|
277
|
+
cursor: dragging ? "grabbing" : "pointer",
|
|
274
278
|
zIndex: 2147483647,
|
|
275
279
|
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
276
280
|
transition: "background 0.15s",
|
|
@@ -310,7 +314,7 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
310
314
|
|
|
311
315
|
// src/overlay/ui/preview.tsx
|
|
312
316
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
313
|
-
var CAMERA_CURSOR = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0
|
|
317
|
+
var CAMERA_CURSOR = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cpath d='M6 12h4l2-3h8l2 3h4a3 3 0 0 1 3 3v9a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3v-9a3 3 0 0 1 3-3z' fill='black' fill-opacity='0.25' transform='translate(0,1)'/%3E%3Cpath d='M6 12h4l2-3h8l2 3h4a3 3 0 0 1 3 3v9a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3v-9a3 3 0 0 1 3-3z' fill='white'/%3E%3Ccircle cx='16' cy='19' r='4.5' fill='none' stroke='%23555' stroke-width='1.5'/%3E%3Ccircle cx='16' cy='19' r='1.5' fill='%23999'/%3E%3C/svg%3E") 16 16, pointer`;
|
|
314
318
|
function CapturePreview({ mode, onClick }) {
|
|
315
319
|
if (mode === "viewport" || mode === "fullpage") {
|
|
316
320
|
return /* @__PURE__ */ jsx2(
|
|
@@ -323,8 +327,7 @@ function CapturePreview({ mode, onClick }) {
|
|
|
323
327
|
inset: 0,
|
|
324
328
|
zIndex: 2147483645,
|
|
325
329
|
cursor: CAMERA_CURSOR,
|
|
326
|
-
background: "rgba(59, 130, 246, 0.15)"
|
|
327
|
-
boxShadow: "inset 0 0 0 2px rgba(59, 130, 246, 0.7)"
|
|
330
|
+
background: "rgba(59, 130, 246, 0.15)"
|
|
328
331
|
}
|
|
329
332
|
}
|
|
330
333
|
);
|
|
@@ -333,9 +336,12 @@ function CapturePreview({ mode, onClick }) {
|
|
|
333
336
|
}
|
|
334
337
|
|
|
335
338
|
// src/overlay/ui/toolbar.tsx
|
|
336
|
-
import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
339
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
337
340
|
import {
|
|
341
|
+
ArrowUp,
|
|
338
342
|
ChevronDown,
|
|
343
|
+
Clock,
|
|
344
|
+
Copy,
|
|
339
345
|
Maximize,
|
|
340
346
|
FolderOpen,
|
|
341
347
|
Frame,
|
|
@@ -363,6 +369,7 @@ function Toolbar({
|
|
|
363
369
|
onFrameSettingsChange
|
|
364
370
|
}) {
|
|
365
371
|
const [settingsOpen, setSettingsOpen] = useState3(false);
|
|
372
|
+
const [historyOpen, setHistoryOpen] = useState3(false);
|
|
366
373
|
useEffect2(() => {
|
|
367
374
|
const onKey = (e) => {
|
|
368
375
|
if (e.target?.tagName === "INPUT") {
|
|
@@ -403,7 +410,7 @@ function Toolbar({
|
|
|
403
410
|
background: "rgba(32, 32, 36, 0.92)",
|
|
404
411
|
backdropFilter: "blur(20px)",
|
|
405
412
|
WebkitBackdropFilter: "blur(20px)",
|
|
406
|
-
border: "
|
|
413
|
+
border: "none",
|
|
407
414
|
borderRadius: 999,
|
|
408
415
|
padding: 6,
|
|
409
416
|
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
|
@@ -418,6 +425,7 @@ function Toolbar({
|
|
|
418
425
|
selected: selectedMode === mode,
|
|
419
426
|
onClick: () => {
|
|
420
427
|
setSettingsOpen(false);
|
|
428
|
+
setHistoryOpen(false);
|
|
421
429
|
onModeChange(mode);
|
|
422
430
|
},
|
|
423
431
|
children: /* @__PURE__ */ jsx3(Icon2, { size: 16, strokeWidth: 1.7 })
|
|
@@ -429,11 +437,24 @@ function Toolbar({
|
|
|
429
437
|
SettingsButton,
|
|
430
438
|
{
|
|
431
439
|
open: settingsOpen,
|
|
432
|
-
onClick: () =>
|
|
440
|
+
onClick: () => {
|
|
441
|
+
setSettingsOpen((prev) => !prev);
|
|
442
|
+
setHistoryOpen(false);
|
|
443
|
+
},
|
|
433
444
|
selectedMode,
|
|
434
445
|
frameSettings,
|
|
435
446
|
onFrameSettingsChange
|
|
436
447
|
}
|
|
448
|
+
),
|
|
449
|
+
/* @__PURE__ */ jsx3(
|
|
450
|
+
HistoryButton,
|
|
451
|
+
{
|
|
452
|
+
open: historyOpen,
|
|
453
|
+
onClick: () => {
|
|
454
|
+
setHistoryOpen((prev) => !prev);
|
|
455
|
+
setSettingsOpen(false);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
437
458
|
)
|
|
438
459
|
] })
|
|
439
460
|
}
|
|
@@ -450,7 +471,7 @@ function CloseButton({ onClick }) {
|
|
|
450
471
|
style: {
|
|
451
472
|
width: 32,
|
|
452
473
|
height: 32,
|
|
453
|
-
borderRadius:
|
|
474
|
+
borderRadius: "50%",
|
|
454
475
|
border: "none",
|
|
455
476
|
background: hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
456
477
|
display: "flex",
|
|
@@ -505,7 +526,7 @@ function ModeButton({
|
|
|
505
526
|
style: {
|
|
506
527
|
width: 32,
|
|
507
528
|
height: 32,
|
|
508
|
-
borderRadius:
|
|
529
|
+
borderRadius: "50%",
|
|
509
530
|
border: "none",
|
|
510
531
|
background: selected || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
511
532
|
display: "flex",
|
|
@@ -663,7 +684,30 @@ function FrameSizeControl({
|
|
|
663
684
|
const isCustom = !currentPreset;
|
|
664
685
|
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
665
686
|
/* @__PURE__ */ jsx3(SettingsLabel, { children: "Size" }),
|
|
666
|
-
/* @__PURE__ */
|
|
687
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 4 }, children: [
|
|
688
|
+
/* @__PURE__ */ jsx3(
|
|
689
|
+
NumInput,
|
|
690
|
+
{
|
|
691
|
+
value: size.w,
|
|
692
|
+
onChange: (v) => {
|
|
693
|
+
const n = parseInt(v, 10);
|
|
694
|
+
if (!Number.isNaN(n) && n > 0) onChange({ ...size, w: n });
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
),
|
|
698
|
+
/* @__PURE__ */ jsx3(StaticText, { children: "x" }),
|
|
699
|
+
/* @__PURE__ */ jsx3(
|
|
700
|
+
NumInput,
|
|
701
|
+
{
|
|
702
|
+
value: size.h,
|
|
703
|
+
onChange: (v) => {
|
|
704
|
+
const n = parseInt(v, 10);
|
|
705
|
+
if (!Number.isNaN(n) && n > 0) onChange({ ...size, h: n });
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
)
|
|
709
|
+
] }),
|
|
710
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative", marginTop: 6 }, children: [
|
|
667
711
|
/* @__PURE__ */ jsxs2(
|
|
668
712
|
"button",
|
|
669
713
|
{
|
|
@@ -690,7 +734,7 @@ function FrameSizeControl({
|
|
|
690
734
|
]
|
|
691
735
|
}
|
|
692
736
|
),
|
|
693
|
-
sizeOpen && /* @__PURE__ */
|
|
737
|
+
sizeOpen && /* @__PURE__ */ jsx3(
|
|
694
738
|
"div",
|
|
695
739
|
{
|
|
696
740
|
style: {
|
|
@@ -707,44 +751,18 @@ function FrameSizeControl({
|
|
|
707
751
|
WebkitBackdropFilter: "blur(20px)",
|
|
708
752
|
zIndex: 1
|
|
709
753
|
},
|
|
710
|
-
children:
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
setSizeOpen(false);
|
|
718
|
-
},
|
|
719
|
-
children: preset.label
|
|
754
|
+
children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsx3(
|
|
755
|
+
DropItem,
|
|
756
|
+
{
|
|
757
|
+
active: !isCustom && preset.w === size.w && preset.h === size.h,
|
|
758
|
+
onClick: () => {
|
|
759
|
+
onChange({ w: preset.w, h: preset.h });
|
|
760
|
+
setSizeOpen(false);
|
|
720
761
|
},
|
|
721
|
-
preset.label
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
}
|
|
726
|
-
)
|
|
727
|
-
] }) }),
|
|
728
|
-
isCustom && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 6 }, children: [
|
|
729
|
-
/* @__PURE__ */ jsx3(
|
|
730
|
-
NumInput,
|
|
731
|
-
{
|
|
732
|
-
value: size.w,
|
|
733
|
-
onChange: (v) => {
|
|
734
|
-
const n = parseInt(v, 10);
|
|
735
|
-
if (!Number.isNaN(n) && n > 0) onChange({ ...size, w: n });
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
),
|
|
739
|
-
/* @__PURE__ */ jsx3(StaticText, { children: "x" }),
|
|
740
|
-
/* @__PURE__ */ jsx3(
|
|
741
|
-
NumInput,
|
|
742
|
-
{
|
|
743
|
-
value: size.h,
|
|
744
|
-
onChange: (v) => {
|
|
745
|
-
const n = parseInt(v, 10);
|
|
746
|
-
if (!Number.isNaN(n) && n > 0) onChange({ ...size, h: n });
|
|
747
|
-
}
|
|
762
|
+
children: preset.label
|
|
763
|
+
},
|
|
764
|
+
preset.label
|
|
765
|
+
))
|
|
748
766
|
}
|
|
749
767
|
)
|
|
750
768
|
] })
|
|
@@ -805,7 +823,7 @@ function FrameBackgroundControl({
|
|
|
805
823
|
] }),
|
|
806
824
|
bgType === "color" && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 }, children: [
|
|
807
825
|
/* @__PURE__ */ jsx3(ColorSwatch, { color: bgColor, onChange: (c) => onChange({ bgColor: c }) }),
|
|
808
|
-
/* @__PURE__ */ jsx3(
|
|
826
|
+
/* @__PURE__ */ jsx3(HexInput, { value: bgColor, onChange: (c) => onChange({ bgColor: c }) })
|
|
809
827
|
] }),
|
|
810
828
|
bgType === "image" && /* @__PURE__ */ jsxs2("div", { style: { marginTop: 6 }, children: [
|
|
811
829
|
/* @__PURE__ */ jsx3(
|
|
@@ -1148,6 +1166,57 @@ function NumInput({
|
|
|
1148
1166
|
}
|
|
1149
1167
|
);
|
|
1150
1168
|
}
|
|
1169
|
+
function HexInput({
|
|
1170
|
+
value,
|
|
1171
|
+
onChange
|
|
1172
|
+
}) {
|
|
1173
|
+
const [editing, setEditing] = useState3(false);
|
|
1174
|
+
const [text, setText] = useState3(value);
|
|
1175
|
+
useEffect2(() => {
|
|
1176
|
+
if (!editing) {
|
|
1177
|
+
setText(value);
|
|
1178
|
+
}
|
|
1179
|
+
}, [editing, value]);
|
|
1180
|
+
const commit = (raw) => {
|
|
1181
|
+
const hex = raw.startsWith("#") ? raw : `#${raw}`;
|
|
1182
|
+
if (/^#[0-9a-fA-F]{6}$/.test(hex)) {
|
|
1183
|
+
onChange(hex);
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
return /* @__PURE__ */ jsx3(
|
|
1187
|
+
"input",
|
|
1188
|
+
{
|
|
1189
|
+
type: "text",
|
|
1190
|
+
value: editing ? text : value,
|
|
1191
|
+
onFocus: () => {
|
|
1192
|
+
setEditing(true);
|
|
1193
|
+
setText(value);
|
|
1194
|
+
},
|
|
1195
|
+
onBlur: () => {
|
|
1196
|
+
setEditing(false);
|
|
1197
|
+
commit(text);
|
|
1198
|
+
},
|
|
1199
|
+
onChange: (e) => setText(e.target.value),
|
|
1200
|
+
onKeyDown: (e) => {
|
|
1201
|
+
if (e.key === "Enter") {
|
|
1202
|
+
e.target.blur();
|
|
1203
|
+
}
|
|
1204
|
+
},
|
|
1205
|
+
style: {
|
|
1206
|
+
width: 72,
|
|
1207
|
+
padding: "4px 6px",
|
|
1208
|
+
background: "rgba(255, 255, 255, 0.07)",
|
|
1209
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1210
|
+
borderRadius: 7,
|
|
1211
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
1212
|
+
fontSize: 12,
|
|
1213
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
1214
|
+
textAlign: "left",
|
|
1215
|
+
outline: "none"
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
);
|
|
1219
|
+
}
|
|
1151
1220
|
function StaticText({ children }) {
|
|
1152
1221
|
return /* @__PURE__ */ jsx3(
|
|
1153
1222
|
"span",
|
|
@@ -1202,150 +1271,44 @@ function Separator({ vertical = true }) {
|
|
|
1202
1271
|
}
|
|
1203
1272
|
);
|
|
1204
1273
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
const [
|
|
1211
|
-
const
|
|
1212
|
-
const
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
while (node) {
|
|
1226
|
-
if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
|
|
1227
|
-
node = node.parentElement;
|
|
1274
|
+
function HistoryButton({
|
|
1275
|
+
open,
|
|
1276
|
+
onClick
|
|
1277
|
+
}) {
|
|
1278
|
+
const [hovered, setHovered] = useState3(false);
|
|
1279
|
+
const [toast, setToast] = useState3(null);
|
|
1280
|
+
const [pushing, setPushing] = useState3(false);
|
|
1281
|
+
const [repos, setRepos] = useState3([]);
|
|
1282
|
+
const [branches, setBranches] = useState3([]);
|
|
1283
|
+
const [screenshots, setScreenshots] = useState3([]);
|
|
1284
|
+
const [selectedRepo, setSelectedRepo] = useState3(null);
|
|
1285
|
+
const [selectedBranch, setSelectedBranch] = useState3(null);
|
|
1286
|
+
const [loading, setLoading] = useState3(false);
|
|
1287
|
+
const [repoDropOpen, setRepoDropOpen] = useState3(false);
|
|
1288
|
+
const [branchDropOpen, setBranchDropOpen] = useState3(false);
|
|
1289
|
+
useEffect2(() => {
|
|
1290
|
+
if (!open) {
|
|
1291
|
+
setRepoDropOpen(false);
|
|
1292
|
+
setBranchDropOpen(false);
|
|
1293
|
+
return;
|
|
1228
1294
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
(
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
y: rect.y,
|
|
1244
|
-
width: rect.width,
|
|
1245
|
-
height: rect.height,
|
|
1246
|
-
tag: el.tagName.toLowerCase() + (el.className && typeof el.className === "string" ? `.${el.className.split(" ")[0]}` : "")
|
|
1247
|
-
});
|
|
1248
|
-
},
|
|
1249
|
-
[isOverlayElement]
|
|
1250
|
-
);
|
|
1251
|
-
const handleClick = useCallback3(
|
|
1252
|
-
(e) => {
|
|
1253
|
-
if (isOverlayElement(e.target)) return;
|
|
1254
|
-
e.preventDefault();
|
|
1255
|
-
e.stopPropagation();
|
|
1256
|
-
e.stopImmediatePropagation();
|
|
1257
|
-
if (hoveredEl.current) {
|
|
1258
|
-
onSelect(hoveredEl.current);
|
|
1259
|
-
}
|
|
1260
|
-
},
|
|
1261
|
-
[onSelect, isOverlayElement]
|
|
1262
|
-
);
|
|
1263
|
-
const handleKeyDown = useCallback3(
|
|
1264
|
-
(e) => {
|
|
1265
|
-
if (e.key === "Escape") {
|
|
1266
|
-
onCancel();
|
|
1267
|
-
}
|
|
1268
|
-
},
|
|
1269
|
-
[onCancel]
|
|
1270
|
-
);
|
|
1271
|
-
useEffect3(() => {
|
|
1272
|
-
document.addEventListener("mousemove", handleMouseMove, true);
|
|
1273
|
-
document.addEventListener("click", handleClick, true);
|
|
1274
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
1275
|
-
return () => {
|
|
1276
|
-
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
1277
|
-
document.removeEventListener("click", handleClick, true);
|
|
1278
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
1279
|
-
};
|
|
1280
|
-
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
1281
|
-
return /* @__PURE__ */ jsx4("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: highlight && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1282
|
-
/* @__PURE__ */ jsx4(
|
|
1283
|
-
"div",
|
|
1284
|
-
{
|
|
1285
|
-
style: {
|
|
1286
|
-
position: "fixed",
|
|
1287
|
-
left: highlight.x,
|
|
1288
|
-
top: highlight.y,
|
|
1289
|
-
width: highlight.width,
|
|
1290
|
-
height: highlight.height,
|
|
1291
|
-
background: "rgba(59, 130, 246, 0.15)",
|
|
1292
|
-
border: "2px solid rgba(59, 130, 246, 0.7)",
|
|
1293
|
-
borderRadius: 2,
|
|
1294
|
-
pointerEvents: "none"
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
),
|
|
1298
|
-
/* @__PURE__ */ jsx4(
|
|
1299
|
-
"div",
|
|
1300
|
-
{
|
|
1301
|
-
style: {
|
|
1302
|
-
position: "fixed",
|
|
1303
|
-
left: highlight.x,
|
|
1304
|
-
top: Math.max(0, highlight.y - 24),
|
|
1305
|
-
background: "rgba(59, 130, 246, 0.9)",
|
|
1306
|
-
color: "#fff",
|
|
1307
|
-
fontSize: 11,
|
|
1308
|
-
fontFamily: "system-ui, -apple-system, monospace",
|
|
1309
|
-
padding: "2px 6px",
|
|
1310
|
-
borderRadius: 3,
|
|
1311
|
-
pointerEvents: "none",
|
|
1312
|
-
whiteSpace: "nowrap",
|
|
1313
|
-
lineHeight: "18px"
|
|
1314
|
-
},
|
|
1315
|
-
children: highlight.tag
|
|
1316
|
-
}
|
|
1317
|
-
)
|
|
1318
|
-
] }) });
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
// src/overlay/ui/status.tsx
|
|
1322
|
-
import { useState as useState5, useRef as useRef4, useEffect as useEffect4, useCallback as useCallback4 } from "react";
|
|
1323
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1324
|
-
var PANEL_WIDTH = 220;
|
|
1325
|
-
function Status({ onReset, position, onClose }) {
|
|
1326
|
-
const panelRef = useRef4(null);
|
|
1327
|
-
const [toast, setToast] = useState5(null);
|
|
1328
|
-
const [pushing, setPushing] = useState5(false);
|
|
1329
|
-
const showToast = useCallback4((message, type) => {
|
|
1295
|
+
setLoading(true);
|
|
1296
|
+
const params = new URLSearchParams();
|
|
1297
|
+
if (selectedRepo) params.set("repo", selectedRepo);
|
|
1298
|
+
if (selectedBranch) params.set("branch", selectedBranch);
|
|
1299
|
+
fetch(`/__afterbefore/history?${params}`).then((r) => r.json()).then((data) => {
|
|
1300
|
+
setRepos(data.repos || []);
|
|
1301
|
+
setBranches(data.branches || []);
|
|
1302
|
+
setScreenshots(data.screenshots || []);
|
|
1303
|
+
if (!selectedRepo && data.currentRepo) setSelectedRepo(data.currentRepo);
|
|
1304
|
+
if (!selectedBranch && data.currentBranch) setSelectedBranch(data.currentBranch);
|
|
1305
|
+
}).catch(() => {
|
|
1306
|
+
}).finally(() => setLoading(false));
|
|
1307
|
+
}, [open, selectedRepo, selectedBranch]);
|
|
1308
|
+
const showToast = useCallback3((message, type) => {
|
|
1330
1309
|
setToast({ message, type });
|
|
1331
1310
|
setTimeout(() => setToast(null), 3e3);
|
|
1332
1311
|
}, []);
|
|
1333
|
-
useEffect4(() => {
|
|
1334
|
-
const handler = (e) => {
|
|
1335
|
-
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
1336
|
-
onClose();
|
|
1337
|
-
}
|
|
1338
|
-
};
|
|
1339
|
-
document.addEventListener("mousedown", handler);
|
|
1340
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
1341
|
-
}, [onClose]);
|
|
1342
|
-
useEffect4(() => {
|
|
1343
|
-
const handler = (e) => {
|
|
1344
|
-
if (e.key === "Escape") onClose();
|
|
1345
|
-
};
|
|
1346
|
-
document.addEventListener("keydown", handler);
|
|
1347
|
-
return () => document.removeEventListener("keydown", handler);
|
|
1348
|
-
}, [onClose]);
|
|
1349
1312
|
const handleOpenFolder = async () => {
|
|
1350
1313
|
try {
|
|
1351
1314
|
const res = await fetch("/__afterbefore/open", { method: "POST" });
|
|
@@ -1384,273 +1347,502 @@ function Status({ onReset, position, onClose }) {
|
|
|
1384
1347
|
setPushing(false);
|
|
1385
1348
|
}
|
|
1386
1349
|
};
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
"
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
style: buttonStyle,
|
|
1455
|
-
onClick: handleOpenFolder,
|
|
1456
|
-
onMouseEnter: onEnter,
|
|
1457
|
-
onMouseLeave: onLeave,
|
|
1458
|
-
children: [
|
|
1459
|
-
/* @__PURE__ */ jsx5(FolderIcon, {}),
|
|
1460
|
-
"Open Folder"
|
|
1461
|
-
]
|
|
1462
|
-
}
|
|
1463
|
-
),
|
|
1464
|
-
/* @__PURE__ */ jsxs4(
|
|
1465
|
-
"button",
|
|
1466
|
-
{
|
|
1467
|
-
style: buttonStyle,
|
|
1468
|
-
onClick: handleCopyMarkdown,
|
|
1469
|
-
onMouseEnter: onEnter,
|
|
1470
|
-
onMouseLeave: onLeave,
|
|
1471
|
-
children: [
|
|
1472
|
-
/* @__PURE__ */ jsx5(CopyIcon, {}),
|
|
1473
|
-
"Copy Markdown"
|
|
1474
|
-
]
|
|
1475
|
-
}
|
|
1476
|
-
),
|
|
1477
|
-
/* @__PURE__ */ jsxs4(
|
|
1478
|
-
"button",
|
|
1479
|
-
{
|
|
1480
|
-
style: buttonStyle,
|
|
1481
|
-
onClick: handlePush,
|
|
1482
|
-
disabled: pushing,
|
|
1483
|
-
onMouseEnter: onEnter,
|
|
1484
|
-
onMouseLeave: onLeave,
|
|
1485
|
-
children: [
|
|
1486
|
-
/* @__PURE__ */ jsx5(PushIcon, {}),
|
|
1487
|
-
pushing ? "Pushing..." : "Push to PR"
|
|
1488
|
-
]
|
|
1489
|
-
}
|
|
1490
|
-
),
|
|
1491
|
-
/* @__PURE__ */ jsx5(
|
|
1350
|
+
return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
1351
|
+
hovered && !open && /* @__PURE__ */ jsx3(
|
|
1352
|
+
"div",
|
|
1353
|
+
{
|
|
1354
|
+
style: {
|
|
1355
|
+
position: "absolute",
|
|
1356
|
+
left: "50%",
|
|
1357
|
+
bottom: "calc(100% + 10px)",
|
|
1358
|
+
transform: "translateX(-50%)",
|
|
1359
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1360
|
+
backdropFilter: "blur(20px)",
|
|
1361
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
1362
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1363
|
+
borderRadius: 8,
|
|
1364
|
+
padding: "5px 10px",
|
|
1365
|
+
color: "rgba(255, 255, 255, 0.88)",
|
|
1366
|
+
fontSize: 12,
|
|
1367
|
+
whiteSpace: "nowrap",
|
|
1368
|
+
boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
|
|
1369
|
+
pointerEvents: "none"
|
|
1370
|
+
},
|
|
1371
|
+
children: "Screenshots"
|
|
1372
|
+
}
|
|
1373
|
+
),
|
|
1374
|
+
/* @__PURE__ */ jsx3(
|
|
1375
|
+
"button",
|
|
1376
|
+
{
|
|
1377
|
+
onClick,
|
|
1378
|
+
onMouseEnter: () => setHovered(true),
|
|
1379
|
+
onMouseLeave: () => setHovered(false),
|
|
1380
|
+
style: {
|
|
1381
|
+
width: 32,
|
|
1382
|
+
height: 32,
|
|
1383
|
+
borderRadius: "50%",
|
|
1384
|
+
border: "none",
|
|
1385
|
+
background: open || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
|
|
1386
|
+
display: "flex",
|
|
1387
|
+
alignItems: "center",
|
|
1388
|
+
justifyContent: "center",
|
|
1389
|
+
cursor: "pointer",
|
|
1390
|
+
padding: 0,
|
|
1391
|
+
color: open || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
|
|
1392
|
+
transition: "background 0.12s ease, color 0.12s ease"
|
|
1393
|
+
},
|
|
1394
|
+
children: /* @__PURE__ */ jsx3(Clock, { size: 16, strokeWidth: 1.7 })
|
|
1395
|
+
}
|
|
1396
|
+
),
|
|
1397
|
+
open && /* @__PURE__ */ jsxs2(
|
|
1398
|
+
"div",
|
|
1399
|
+
{
|
|
1400
|
+
style: {
|
|
1401
|
+
position: "absolute",
|
|
1402
|
+
left: "50%",
|
|
1403
|
+
bottom: "calc(100% + 12px)",
|
|
1404
|
+
transform: "translateX(-50%)",
|
|
1405
|
+
minWidth: 300,
|
|
1406
|
+
maxWidth: 360,
|
|
1407
|
+
padding: "10px 12px",
|
|
1408
|
+
borderRadius: 12,
|
|
1409
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1410
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1411
|
+
boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
|
|
1412
|
+
backdropFilter: "blur(20px)",
|
|
1413
|
+
WebkitBackdropFilter: "blur(20px)"
|
|
1414
|
+
},
|
|
1415
|
+
children: [
|
|
1416
|
+
/* @__PURE__ */ jsx3(
|
|
1492
1417
|
"div",
|
|
1493
1418
|
{
|
|
1494
1419
|
style: {
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1420
|
+
fontSize: 11,
|
|
1421
|
+
color: "rgba(255, 255, 255, 0.46)",
|
|
1422
|
+
letterSpacing: "0.03em",
|
|
1423
|
+
textTransform: "uppercase",
|
|
1424
|
+
marginBottom: 10
|
|
1425
|
+
},
|
|
1426
|
+
children: "Screenshots"
|
|
1499
1427
|
}
|
|
1500
1428
|
),
|
|
1501
|
-
/* @__PURE__ */
|
|
1502
|
-
|
|
1429
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginBottom: 10 }, children: [
|
|
1430
|
+
/* @__PURE__ */ jsx3(
|
|
1431
|
+
FilterDropdown,
|
|
1432
|
+
{
|
|
1433
|
+
label: "Project",
|
|
1434
|
+
value: selectedRepo,
|
|
1435
|
+
options: repos,
|
|
1436
|
+
isOpen: repoDropOpen,
|
|
1437
|
+
onToggle: () => {
|
|
1438
|
+
setRepoDropOpen((p) => !p);
|
|
1439
|
+
setBranchDropOpen(false);
|
|
1440
|
+
},
|
|
1441
|
+
onSelect: (repo) => {
|
|
1442
|
+
setSelectedRepo(repo);
|
|
1443
|
+
setSelectedBranch(null);
|
|
1444
|
+
setRepoDropOpen(false);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
),
|
|
1448
|
+
/* @__PURE__ */ jsx3(
|
|
1449
|
+
FilterDropdown,
|
|
1450
|
+
{
|
|
1451
|
+
label: "Branch",
|
|
1452
|
+
value: selectedBranch,
|
|
1453
|
+
options: branches,
|
|
1454
|
+
isOpen: branchDropOpen,
|
|
1455
|
+
onToggle: () => {
|
|
1456
|
+
setBranchDropOpen((p) => !p);
|
|
1457
|
+
setRepoDropOpen(false);
|
|
1458
|
+
},
|
|
1459
|
+
onSelect: (branch) => {
|
|
1460
|
+
setSelectedBranch(branch);
|
|
1461
|
+
setBranchDropOpen(false);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
)
|
|
1465
|
+
] }),
|
|
1466
|
+
loading ? /* @__PURE__ */ jsx3(
|
|
1467
|
+
"div",
|
|
1468
|
+
{
|
|
1469
|
+
style: {
|
|
1470
|
+
padding: "12px 0",
|
|
1471
|
+
textAlign: "center",
|
|
1472
|
+
fontSize: 12,
|
|
1473
|
+
color: "rgba(255, 255, 255, 0.35)"
|
|
1474
|
+
},
|
|
1475
|
+
children: "Loading..."
|
|
1476
|
+
}
|
|
1477
|
+
) : screenshots.length === 0 ? /* @__PURE__ */ jsx3(
|
|
1478
|
+
"div",
|
|
1503
1479
|
{
|
|
1504
|
-
style: {
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1480
|
+
style: {
|
|
1481
|
+
padding: "12px 0",
|
|
1482
|
+
textAlign: "center",
|
|
1483
|
+
fontSize: 12,
|
|
1484
|
+
color: "rgba(255, 255, 255, 0.35)"
|
|
1485
|
+
},
|
|
1486
|
+
children: "No screenshots yet"
|
|
1487
|
+
}
|
|
1488
|
+
) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1489
|
+
/* @__PURE__ */ jsx3(
|
|
1490
|
+
"div",
|
|
1491
|
+
{
|
|
1492
|
+
style: {
|
|
1493
|
+
maxHeight: 240,
|
|
1494
|
+
overflowY: "auto",
|
|
1495
|
+
display: "flex",
|
|
1496
|
+
flexDirection: "column",
|
|
1497
|
+
gap: 8
|
|
1498
|
+
},
|
|
1499
|
+
children: screenshots.map((shot) => /* @__PURE__ */ jsxs2(
|
|
1500
|
+
"div",
|
|
1501
|
+
{
|
|
1502
|
+
style: {
|
|
1503
|
+
display: "flex",
|
|
1504
|
+
gap: 10,
|
|
1505
|
+
alignItems: "center"
|
|
1506
|
+
},
|
|
1507
|
+
children: [
|
|
1508
|
+
/* @__PURE__ */ jsx3(
|
|
1509
|
+
"img",
|
|
1510
|
+
{
|
|
1511
|
+
src: `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(shot.filename)}`,
|
|
1512
|
+
alt: "",
|
|
1513
|
+
style: {
|
|
1514
|
+
width: 56,
|
|
1515
|
+
height: 36,
|
|
1516
|
+
borderRadius: 4,
|
|
1517
|
+
objectFit: "cover",
|
|
1518
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1519
|
+
flexShrink: 0,
|
|
1520
|
+
background: "rgba(255, 255, 255, 0.05)"
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
),
|
|
1524
|
+
/* @__PURE__ */ jsx3("div", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx3(
|
|
1525
|
+
"div",
|
|
1526
|
+
{
|
|
1527
|
+
style: {
|
|
1528
|
+
fontSize: 12,
|
|
1529
|
+
color: "rgba(255, 255, 255, 0.88)"
|
|
1530
|
+
},
|
|
1531
|
+
children: formatTimestamp(shot.filename)
|
|
1532
|
+
}
|
|
1533
|
+
) })
|
|
1534
|
+
]
|
|
1535
|
+
},
|
|
1536
|
+
shot.filename
|
|
1537
|
+
))
|
|
1538
|
+
}
|
|
1539
|
+
),
|
|
1540
|
+
/* @__PURE__ */ jsx3(
|
|
1541
|
+
"div",
|
|
1542
|
+
{
|
|
1543
|
+
style: {
|
|
1544
|
+
height: 1,
|
|
1545
|
+
background: "rgba(255, 255, 255, 0.08)",
|
|
1546
|
+
margin: "8px 0"
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
),
|
|
1550
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
1551
|
+
/* @__PURE__ */ jsxs2(ActionButton, { onClick: handleOpenFolder, children: [
|
|
1552
|
+
/* @__PURE__ */ jsx3(FolderOpen, { size: 13, strokeWidth: 1.8 }),
|
|
1553
|
+
"Open Folder"
|
|
1554
|
+
] }),
|
|
1555
|
+
/* @__PURE__ */ jsxs2(ActionButton, { onClick: handleCopyMarkdown, children: [
|
|
1556
|
+
/* @__PURE__ */ jsx3(Copy, { size: 13, strokeWidth: 1.8 }),
|
|
1557
|
+
"Copy Markdown"
|
|
1558
|
+
] }),
|
|
1559
|
+
/* @__PURE__ */ jsxs2(ActionButton, { onClick: handlePush, disabled: pushing, children: [
|
|
1560
|
+
/* @__PURE__ */ jsx3(ArrowUp, { size: 13, strokeWidth: 1.8 }),
|
|
1561
|
+
pushing ? "Pushing..." : "Push to PR"
|
|
1562
|
+
] })
|
|
1563
|
+
] })
|
|
1564
|
+
] }),
|
|
1565
|
+
toast && /* @__PURE__ */ jsx3(
|
|
1566
|
+
"div",
|
|
1567
|
+
{
|
|
1568
|
+
style: {
|
|
1569
|
+
position: "absolute",
|
|
1570
|
+
bottom: "100%",
|
|
1571
|
+
left: "50%",
|
|
1572
|
+
transform: "translateX(-50%)",
|
|
1573
|
+
marginBottom: 8,
|
|
1574
|
+
padding: "6px 12px",
|
|
1575
|
+
borderRadius: 6,
|
|
1576
|
+
fontSize: 12,
|
|
1577
|
+
fontWeight: 500,
|
|
1578
|
+
whiteSpace: "nowrap",
|
|
1579
|
+
color: "white",
|
|
1580
|
+
background: toast.type === "success" ? "rgba(34, 197, 94, 0.9)" : "rgba(239, 68, 68, 0.9)",
|
|
1581
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.3)"
|
|
1582
|
+
},
|
|
1583
|
+
children: toast.message
|
|
1512
1584
|
}
|
|
1513
1585
|
)
|
|
1514
|
-
]
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
style: {
|
|
1519
|
-
position: "absolute",
|
|
1520
|
-
bottom: "100%",
|
|
1521
|
-
left: "50%",
|
|
1522
|
-
transform: "translateX(-50%)",
|
|
1523
|
-
marginBottom: 8,
|
|
1524
|
-
padding: "6px 12px",
|
|
1525
|
-
borderRadius: 6,
|
|
1526
|
-
fontSize: 12,
|
|
1527
|
-
fontWeight: 500,
|
|
1528
|
-
whiteSpace: "nowrap",
|
|
1529
|
-
color: "white",
|
|
1530
|
-
background: toast.type === "success" ? "rgba(34, 197, 94, 0.9)" : "rgba(239, 68, 68, 0.9)",
|
|
1531
|
-
boxShadow: "0 2px 8px rgba(0,0,0,0.3)"
|
|
1532
|
-
},
|
|
1533
|
-
children: toast.message
|
|
1534
|
-
}
|
|
1535
|
-
)
|
|
1536
|
-
]
|
|
1537
|
-
}
|
|
1538
|
-
);
|
|
1586
|
+
]
|
|
1587
|
+
}
|
|
1588
|
+
)
|
|
1589
|
+
] });
|
|
1539
1590
|
}
|
|
1540
|
-
function
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1591
|
+
function FilterDropdown({
|
|
1592
|
+
label,
|
|
1593
|
+
value,
|
|
1594
|
+
options,
|
|
1595
|
+
isOpen,
|
|
1596
|
+
onToggle,
|
|
1597
|
+
onSelect
|
|
1598
|
+
}) {
|
|
1599
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
1600
|
+
/* @__PURE__ */ jsx3(
|
|
1601
|
+
"div",
|
|
1602
|
+
{
|
|
1603
|
+
style: {
|
|
1604
|
+
fontSize: 11,
|
|
1605
|
+
color: "rgba(255, 255, 255, 0.42)",
|
|
1606
|
+
letterSpacing: "0.02em",
|
|
1607
|
+
marginBottom: 3
|
|
1608
|
+
},
|
|
1609
|
+
children: label
|
|
1610
|
+
}
|
|
1611
|
+
),
|
|
1612
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
1613
|
+
/* @__PURE__ */ jsxs2(
|
|
1614
|
+
"button",
|
|
1550
1615
|
{
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1616
|
+
onClick: onToggle,
|
|
1617
|
+
style: {
|
|
1618
|
+
display: "flex",
|
|
1619
|
+
alignItems: "center",
|
|
1620
|
+
justifyContent: "space-between",
|
|
1621
|
+
gap: 6,
|
|
1622
|
+
width: "100%",
|
|
1623
|
+
height: 30,
|
|
1624
|
+
padding: "0 8px",
|
|
1625
|
+
borderRadius: 7,
|
|
1626
|
+
border: "1px solid rgba(255,255,255,0.1)",
|
|
1627
|
+
background: "rgba(255,255,255,0.07)",
|
|
1628
|
+
color: "rgba(255,255,255,0.88)",
|
|
1629
|
+
cursor: "pointer",
|
|
1630
|
+
fontSize: 12,
|
|
1631
|
+
fontFamily: "inherit"
|
|
1632
|
+
},
|
|
1633
|
+
children: [
|
|
1634
|
+
/* @__PURE__ */ jsx3(
|
|
1635
|
+
"span",
|
|
1636
|
+
{
|
|
1637
|
+
style: {
|
|
1638
|
+
overflow: "hidden",
|
|
1639
|
+
textOverflow: "ellipsis",
|
|
1640
|
+
whiteSpace: "nowrap"
|
|
1641
|
+
},
|
|
1642
|
+
children: value || "\u2014"
|
|
1643
|
+
}
|
|
1644
|
+
),
|
|
1645
|
+
/* @__PURE__ */ jsx3(ChevronDown, { size: 12, strokeWidth: 2 })
|
|
1646
|
+
]
|
|
1647
|
+
}
|
|
1648
|
+
),
|
|
1649
|
+
isOpen && options.length > 0 && /* @__PURE__ */ jsx3(
|
|
1650
|
+
"div",
|
|
1651
|
+
{
|
|
1652
|
+
style: {
|
|
1653
|
+
position: "absolute",
|
|
1654
|
+
bottom: "calc(100% + 4px)",
|
|
1655
|
+
left: 0,
|
|
1656
|
+
right: 0,
|
|
1657
|
+
maxHeight: 160,
|
|
1658
|
+
overflowY: "auto",
|
|
1659
|
+
background: "rgba(32, 32, 36, 0.96)",
|
|
1660
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1661
|
+
borderRadius: 8,
|
|
1662
|
+
padding: "4px 0",
|
|
1663
|
+
boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
|
|
1664
|
+
backdropFilter: "blur(20px)",
|
|
1665
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
1666
|
+
zIndex: 1
|
|
1667
|
+
},
|
|
1668
|
+
children: options.map((opt) => /* @__PURE__ */ jsx3(
|
|
1669
|
+
DropItem,
|
|
1670
|
+
{
|
|
1671
|
+
active: opt === value,
|
|
1672
|
+
onClick: () => onSelect(opt),
|
|
1673
|
+
children: opt
|
|
1674
|
+
},
|
|
1675
|
+
opt
|
|
1676
|
+
))
|
|
1555
1677
|
}
|
|
1556
1678
|
)
|
|
1557
|
-
}
|
|
1558
|
-
);
|
|
1679
|
+
] })
|
|
1680
|
+
] });
|
|
1559
1681
|
}
|
|
1560
|
-
function
|
|
1561
|
-
|
|
1562
|
-
|
|
1682
|
+
function ActionButton({
|
|
1683
|
+
children,
|
|
1684
|
+
onClick,
|
|
1685
|
+
disabled
|
|
1686
|
+
}) {
|
|
1687
|
+
const [hovered, setHovered] = useState3(false);
|
|
1688
|
+
return /* @__PURE__ */ jsx3(
|
|
1689
|
+
"button",
|
|
1563
1690
|
{
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
d: "M10 4V2.5A1.5 1.5 0 008.5 1h-6A1.5 1.5 0 001 2.5v6A1.5 1.5 0 002.5 10H4",
|
|
1586
|
-
fill: "none",
|
|
1587
|
-
stroke: "currentColor",
|
|
1588
|
-
strokeWidth: "1.3"
|
|
1589
|
-
}
|
|
1590
|
-
)
|
|
1591
|
-
]
|
|
1691
|
+
onClick,
|
|
1692
|
+
disabled,
|
|
1693
|
+
onMouseEnter: () => setHovered(true),
|
|
1694
|
+
onMouseLeave: () => setHovered(false),
|
|
1695
|
+
style: {
|
|
1696
|
+
display: "flex",
|
|
1697
|
+
alignItems: "center",
|
|
1698
|
+
gap: 6,
|
|
1699
|
+
width: "100%",
|
|
1700
|
+
padding: "6px 8px",
|
|
1701
|
+
border: "none",
|
|
1702
|
+
background: hovered ? "rgba(255, 255, 255, 0.08)" : "transparent",
|
|
1703
|
+
color: "rgba(255, 255, 255, 0.78)",
|
|
1704
|
+
fontSize: 12,
|
|
1705
|
+
borderRadius: 6,
|
|
1706
|
+
cursor: disabled ? "wait" : "pointer",
|
|
1707
|
+
textAlign: "left",
|
|
1708
|
+
fontFamily: "inherit",
|
|
1709
|
+
transition: "background 0.1s ease"
|
|
1710
|
+
},
|
|
1711
|
+
children
|
|
1592
1712
|
}
|
|
1593
1713
|
);
|
|
1594
1714
|
}
|
|
1595
|
-
function
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
fill: "none",
|
|
1608
|
-
stroke: "currentColor",
|
|
1609
|
-
strokeWidth: "1.3",
|
|
1610
|
-
strokeLinecap: "round",
|
|
1611
|
-
strokeLinejoin: "round"
|
|
1612
|
-
}
|
|
1613
|
-
)
|
|
1614
|
-
}
|
|
1615
|
-
);
|
|
1715
|
+
function formatTimestamp(filename) {
|
|
1716
|
+
const iso = filename.replace(/\.png$/, "").replace(/T(\d{2})-(\d{2})-(\d{2})-(\d+)Z$/, "T$1:$2:$3.$4Z");
|
|
1717
|
+
const date = new Date(iso);
|
|
1718
|
+
if (Number.isNaN(date.getTime())) return filename.replace(/\.png$/, "");
|
|
1719
|
+
const now = /* @__PURE__ */ new Date();
|
|
1720
|
+
const diffMs = now.getTime() - date.getTime();
|
|
1721
|
+
const diffMin = Math.floor(diffMs / 6e4);
|
|
1722
|
+
if (diffMin < 1) return "Just now";
|
|
1723
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
1724
|
+
const diffHr = Math.floor(diffMin / 60);
|
|
1725
|
+
if (diffHr < 24) return `${diffHr}h ago`;
|
|
1726
|
+
return date.toLocaleDateString(void 0, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
1616
1727
|
}
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
fill: "none",
|
|
1641
|
-
stroke: "currentColor",
|
|
1642
|
-
strokeWidth: "1.3",
|
|
1643
|
-
strokeLinecap: "round",
|
|
1644
|
-
strokeLinejoin: "round"
|
|
1645
|
-
}
|
|
1646
|
-
)
|
|
1647
|
-
]
|
|
1728
|
+
|
|
1729
|
+
// src/overlay/ui/inspector.tsx
|
|
1730
|
+
import { useEffect as useEffect3, useRef as useRef3, useCallback as useCallback4, useState as useState4 } from "react";
|
|
1731
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1732
|
+
function Inspector({ onSelect, onCancel }) {
|
|
1733
|
+
const [highlight, setHighlight] = useState4(null);
|
|
1734
|
+
const hoveredEl = useRef3(null);
|
|
1735
|
+
const styleEl = useRef3(null);
|
|
1736
|
+
useEffect3(() => {
|
|
1737
|
+
const style = document.createElement("style");
|
|
1738
|
+
style.setAttribute("data-afterbefore", "true");
|
|
1739
|
+
style.textContent = ":not([data-afterbefore]):not([data-afterbefore] *) { cursor: crosshair !important; }";
|
|
1740
|
+
document.head.appendChild(style);
|
|
1741
|
+
styleEl.current = style;
|
|
1742
|
+
return () => {
|
|
1743
|
+
style.remove();
|
|
1744
|
+
};
|
|
1745
|
+
}, []);
|
|
1746
|
+
const isOverlayElement = useCallback4((el) => {
|
|
1747
|
+
let node = el;
|
|
1748
|
+
while (node) {
|
|
1749
|
+
if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
|
|
1750
|
+
node = node.parentElement;
|
|
1648
1751
|
}
|
|
1752
|
+
return false;
|
|
1753
|
+
}, []);
|
|
1754
|
+
const handleMouseMove = useCallback4(
|
|
1755
|
+
(e) => {
|
|
1756
|
+
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
1757
|
+
if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {
|
|
1758
|
+
setHighlight(null);
|
|
1759
|
+
hoveredEl.current = null;
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
hoveredEl.current = el;
|
|
1763
|
+
const rect = el.getBoundingClientRect();
|
|
1764
|
+
setHighlight({
|
|
1765
|
+
x: rect.x,
|
|
1766
|
+
y: rect.y,
|
|
1767
|
+
width: rect.width,
|
|
1768
|
+
height: rect.height,
|
|
1769
|
+
tag: el.tagName.toLowerCase() + (el.className && typeof el.className === "string" ? `.${el.className.split(" ")[0]}` : "")
|
|
1770
|
+
});
|
|
1771
|
+
},
|
|
1772
|
+
[isOverlayElement]
|
|
1773
|
+
);
|
|
1774
|
+
const handleClick = useCallback4(
|
|
1775
|
+
(e) => {
|
|
1776
|
+
if (isOverlayElement(e.target)) return;
|
|
1777
|
+
e.preventDefault();
|
|
1778
|
+
e.stopPropagation();
|
|
1779
|
+
e.stopImmediatePropagation();
|
|
1780
|
+
if (hoveredEl.current) {
|
|
1781
|
+
onSelect(hoveredEl.current);
|
|
1782
|
+
}
|
|
1783
|
+
},
|
|
1784
|
+
[onSelect, isOverlayElement]
|
|
1649
1785
|
);
|
|
1786
|
+
const handleKeyDown = useCallback4(
|
|
1787
|
+
(e) => {
|
|
1788
|
+
if (e.key === "Escape") {
|
|
1789
|
+
onCancel();
|
|
1790
|
+
}
|
|
1791
|
+
},
|
|
1792
|
+
[onCancel]
|
|
1793
|
+
);
|
|
1794
|
+
useEffect3(() => {
|
|
1795
|
+
document.addEventListener("mousemove", handleMouseMove, true);
|
|
1796
|
+
document.addEventListener("click", handleClick, true);
|
|
1797
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1798
|
+
return () => {
|
|
1799
|
+
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
1800
|
+
document.removeEventListener("click", handleClick, true);
|
|
1801
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
1802
|
+
};
|
|
1803
|
+
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
1804
|
+
return /* @__PURE__ */ jsx4("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: highlight && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1805
|
+
/* @__PURE__ */ jsx4(
|
|
1806
|
+
"div",
|
|
1807
|
+
{
|
|
1808
|
+
style: {
|
|
1809
|
+
position: "fixed",
|
|
1810
|
+
left: highlight.x,
|
|
1811
|
+
top: highlight.y,
|
|
1812
|
+
width: highlight.width,
|
|
1813
|
+
height: highlight.height,
|
|
1814
|
+
background: "rgba(59, 130, 246, 0.15)",
|
|
1815
|
+
border: "2px solid rgba(59, 130, 246, 0.7)",
|
|
1816
|
+
borderRadius: 2,
|
|
1817
|
+
pointerEvents: "none"
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
),
|
|
1821
|
+
/* @__PURE__ */ jsx4(
|
|
1822
|
+
"div",
|
|
1823
|
+
{
|
|
1824
|
+
style: {
|
|
1825
|
+
position: "fixed",
|
|
1826
|
+
left: highlight.x,
|
|
1827
|
+
top: Math.max(0, highlight.y - 24),
|
|
1828
|
+
background: "rgba(59, 130, 246, 0.9)",
|
|
1829
|
+
color: "#fff",
|
|
1830
|
+
fontSize: 11,
|
|
1831
|
+
fontFamily: "system-ui, -apple-system, monospace",
|
|
1832
|
+
padding: "2px 6px",
|
|
1833
|
+
borderRadius: 3,
|
|
1834
|
+
pointerEvents: "none",
|
|
1835
|
+
whiteSpace: "nowrap",
|
|
1836
|
+
lineHeight: "18px"
|
|
1837
|
+
},
|
|
1838
|
+
children: highlight.tag
|
|
1839
|
+
}
|
|
1840
|
+
)
|
|
1841
|
+
] }) });
|
|
1650
1842
|
}
|
|
1651
1843
|
|
|
1652
1844
|
// src/overlay/index.tsx
|
|
1653
|
-
import { jsx as
|
|
1845
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1654
1846
|
async function saveCapture(mode, dataUrl) {
|
|
1655
1847
|
try {
|
|
1656
1848
|
const res = await fetch("/__afterbefore/save", {
|
|
@@ -1668,14 +1860,13 @@ async function saveCapture(mode, dataUrl) {
|
|
|
1668
1860
|
}
|
|
1669
1861
|
function AfterBefore() {
|
|
1670
1862
|
const { state, captureComplete, reset } = useOverlayState();
|
|
1671
|
-
const [
|
|
1672
|
-
const [
|
|
1673
|
-
const [
|
|
1674
|
-
const [
|
|
1675
|
-
const [
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
useEffect5(() => {
|
|
1863
|
+
const [toolbarActive, setToolbarActive] = useState5(false);
|
|
1864
|
+
const [inspectorActive, setInspectorActive] = useState5(false);
|
|
1865
|
+
const [loading, setLoading] = useState5(false);
|
|
1866
|
+
const [selectedMode, setSelectedMode] = useState5("component");
|
|
1867
|
+
const [frameSettings, setFrameSettings] = useState5(DEFAULT_FRAME_SETTINGS);
|
|
1868
|
+
const iconPos = useRef4({ x: 24, y: 0 });
|
|
1869
|
+
useEffect4(() => {
|
|
1679
1870
|
try {
|
|
1680
1871
|
const stored = localStorage.getItem("ab-frame-settings");
|
|
1681
1872
|
if (stored) {
|
|
@@ -1690,11 +1881,10 @@ function AfterBefore() {
|
|
|
1690
1881
|
setFrameSettings(DEFAULT_FRAME_SETTINGS);
|
|
1691
1882
|
}
|
|
1692
1883
|
}, []);
|
|
1693
|
-
|
|
1884
|
+
useEffect4(() => {
|
|
1694
1885
|
if (state.phase === "ready") {
|
|
1695
1886
|
const timer = setTimeout(() => {
|
|
1696
1887
|
reset();
|
|
1697
|
-
setStatusOpen(false);
|
|
1698
1888
|
}, 1500);
|
|
1699
1889
|
return () => clearTimeout(timer);
|
|
1700
1890
|
}
|
|
@@ -1708,13 +1898,12 @@ function AfterBefore() {
|
|
|
1708
1898
|
const handleIconClick = useCallback5(() => {
|
|
1709
1899
|
if (loading) return;
|
|
1710
1900
|
if (state.phase === "ready") {
|
|
1711
|
-
|
|
1712
|
-
}
|
|
1901
|
+
reset();
|
|
1902
|
+
}
|
|
1903
|
+
if (toolbarActive || inspectorActive) {
|
|
1713
1904
|
setToolbarActive(false);
|
|
1714
1905
|
setInspectorActive(false);
|
|
1715
|
-
setStatusOpen(false);
|
|
1716
1906
|
} else {
|
|
1717
|
-
setStatusOpen(false);
|
|
1718
1907
|
if (selectedMode === "component") {
|
|
1719
1908
|
setToolbarActive(true);
|
|
1720
1909
|
setInspectorActive(true);
|
|
@@ -1723,7 +1912,7 @@ function AfterBefore() {
|
|
|
1723
1912
|
setInspectorActive(false);
|
|
1724
1913
|
}
|
|
1725
1914
|
}
|
|
1726
|
-
}, [state.phase, loading, toolbarActive, inspectorActive, selectedMode]);
|
|
1915
|
+
}, [state.phase, loading, toolbarActive, inspectorActive, selectedMode, reset]);
|
|
1727
1916
|
const performCapture = useCallback5(
|
|
1728
1917
|
async (mode, element) => {
|
|
1729
1918
|
setLoading(true);
|
|
@@ -1781,19 +1970,10 @@ function AfterBefore() {
|
|
|
1781
1970
|
}, []);
|
|
1782
1971
|
const handleModeChange = useCallback5((mode) => {
|
|
1783
1972
|
setSelectedMode(mode);
|
|
1784
|
-
|
|
1785
|
-
setInspectorActive(true);
|
|
1786
|
-
}
|
|
1787
|
-
}, []);
|
|
1788
|
-
const handleReset = useCallback5(() => {
|
|
1789
|
-
reset();
|
|
1790
|
-
setStatusOpen(false);
|
|
1791
|
-
}, [reset]);
|
|
1792
|
-
const handleStatusClose = useCallback5(() => {
|
|
1793
|
-
setStatusOpen(false);
|
|
1973
|
+
setInspectorActive(mode === "component");
|
|
1794
1974
|
}, []);
|
|
1795
|
-
return /* @__PURE__ */
|
|
1796
|
-
/* @__PURE__ */
|
|
1975
|
+
return /* @__PURE__ */ jsxs4("div", { "data-afterbefore": "true", children: [
|
|
1976
|
+
/* @__PURE__ */ jsx5(
|
|
1797
1977
|
Icon,
|
|
1798
1978
|
{
|
|
1799
1979
|
phase: state.phase,
|
|
@@ -1802,14 +1982,14 @@ function AfterBefore() {
|
|
|
1802
1982
|
onPositionChange: handlePositionChange
|
|
1803
1983
|
}
|
|
1804
1984
|
),
|
|
1805
|
-
toolbarActive && !inspectorActive && !loading && /* @__PURE__ */
|
|
1985
|
+
toolbarActive && !inspectorActive && !loading && /* @__PURE__ */ jsx5(
|
|
1806
1986
|
CapturePreview,
|
|
1807
1987
|
{
|
|
1808
1988
|
mode: selectedMode,
|
|
1809
1989
|
onClick: () => handleToolbarCapture(selectedMode)
|
|
1810
1990
|
}
|
|
1811
1991
|
),
|
|
1812
|
-
toolbarActive && /* @__PURE__ */
|
|
1992
|
+
toolbarActive && /* @__PURE__ */ jsx5(
|
|
1813
1993
|
Toolbar,
|
|
1814
1994
|
{
|
|
1815
1995
|
selectedMode,
|
|
@@ -1820,15 +2000,7 @@ function AfterBefore() {
|
|
|
1820
2000
|
onFrameSettingsChange: handleFrameSettingsChange
|
|
1821
2001
|
}
|
|
1822
2002
|
),
|
|
1823
|
-
inspectorActive && /* @__PURE__ */
|
|
1824
|
-
statusOpen && state.phase === "ready" && /* @__PURE__ */ jsx6(
|
|
1825
|
-
Status,
|
|
1826
|
-
{
|
|
1827
|
-
onReset: handleReset,
|
|
1828
|
-
position: iconPos.current,
|
|
1829
|
-
onClose: handleStatusClose
|
|
1830
|
-
}
|
|
1831
|
-
)
|
|
2003
|
+
inspectorActive && /* @__PURE__ */ jsx5(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel })
|
|
1832
2004
|
] });
|
|
1833
2005
|
}
|
|
1834
2006
|
export {
|