afterbefore 0.2.17 → 0.2.18

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.
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/overlay/index.tsx
4
- import { useState as useState4, useCallback as useCallback4, useEffect as useEffect3 } from "react";
4
+ import { useState as useState5, useCallback as useCallback4, useEffect as useEffect4 } from "react";
5
5
 
6
6
  // src/overlay/state.ts
7
7
  import { useState, useCallback } from "react";
@@ -178,477 +178,228 @@ function loadImage(src) {
178
178
  }
179
179
 
180
180
  // src/overlay/ui/toolbar.tsx
181
- import { useCallback as useCallback2, useEffect, useRef, useState as useState2 } from "react";
181
+ import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
182
182
  import {
183
183
  ArrowUp,
184
184
  Camera,
185
185
  Check,
186
- ChevronDown,
186
+ ChevronDown as ChevronDown2,
187
187
  Clock,
188
188
  Eye,
189
189
  FolderOpen,
190
- Frame,
191
- ImageIcon,
192
190
  LoaderCircle,
193
191
  Maximize,
194
192
  Monitor,
195
193
  MousePointer2,
196
- Palette,
197
194
  Settings,
195
+ Trash2 as Trash22,
196
+ X as X2
197
+ } from "lucide-react";
198
+
199
+ // src/overlay/ui/settings-panel.tsx
200
+ import { useEffect, useRef, useState as useState2 } from "react";
201
+ import {
202
+ ChevronDown,
203
+ ImageIcon,
204
+ Palette,
198
205
  Trash2,
199
206
  Upload,
200
207
  X
201
208
  } from "lucide-react";
202
209
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
203
- var EDGE_MARGIN = 24;
204
- var CONTAINER_SIZE = 38;
205
- function getCornerStyle(corner) {
206
- switch (corner) {
207
- case "bottom-right":
208
- return { bottom: EDGE_MARGIN, right: EDGE_MARGIN };
209
- case "bottom-left":
210
- return { bottom: EDGE_MARGIN, left: EDGE_MARGIN };
211
- case "top-right":
212
- return { top: EDGE_MARGIN, right: EDGE_MARGIN };
213
- case "top-left":
214
- return { top: EDGE_MARGIN, left: EDGE_MARGIN };
215
- }
216
- }
217
- function isBottomCorner(corner) {
218
- return corner === "bottom-right" || corner === "bottom-left";
219
- }
220
- function isRightCorner(corner) {
221
- return corner === "bottom-right" || corner === "top-right";
222
- }
223
- function snapToCorner(x, y) {
224
- const cx = window.innerWidth / 2;
225
- const cy = window.innerHeight / 2;
226
- if (x < cx) {
227
- return y < cy ? "top-left" : "bottom-left";
228
- }
229
- return y < cy ? "top-right" : "bottom-right";
230
- }
231
- var MODES = [
232
- { mode: "component", label: "Component", icon: MousePointer2 },
233
- { mode: "viewport", label: "Viewport", icon: Monitor },
234
- { mode: "fullpage", label: "Full Page", icon: Maximize }
235
- ];
236
- function Toolbar({
237
- expanded,
238
- onToggle,
239
- phase,
240
- loading,
210
+ function SettingsPanel({
211
+ style,
212
+ onClose,
241
213
  selectedMode,
242
- onModeChange,
243
- onCapture,
244
- onCancel,
245
214
  frameSettings,
246
215
  onFrameSettingsChange
247
216
  }) {
248
- const [settingsOpen, setSettingsOpen] = useState2(false);
249
- const [historyOpen, setHistoryOpen] = useState2(false);
250
- const [corner, setCorner] = useState2(() => {
217
+ const [saveDir, setSaveDir] = useState2(null);
218
+ const [picking, setPicking] = useState2(false);
219
+ useEffect(() => {
220
+ fetch("/__afterbefore/config").then((r) => r.json()).then((data) => setSaveDir(data.saveDir)).catch(() => {
221
+ });
222
+ }, []);
223
+ const handlePickFolder = async () => {
224
+ setPicking(true);
251
225
  try {
252
- const stored = localStorage.getItem("ab-toolbar-corner");
253
- if (stored && ["bottom-right", "bottom-left", "top-right", "top-left"].includes(stored)) {
254
- return stored;
226
+ const res = await fetch("/__afterbefore/pick-folder", { method: "POST" });
227
+ const data = await res.json();
228
+ if (data.folder) {
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);
255
235
  }
256
236
  } catch {
237
+ } finally {
238
+ setPicking(false);
257
239
  }
258
- return "bottom-right";
259
- });
260
- const [dragging, setDragging] = useState2(false);
261
- const [dragPos, setDragPos] = useState2(null);
262
- const dragState = useRef(null);
263
- const toolbarRef = useRef(null);
264
- const [cameraHovered, setCameraHovered] = useState2(false);
265
- useEffect(() => {
266
- if (!expanded) return;
267
- const onKey = (e) => {
268
- if (e.target?.tagName === "INPUT") {
269
- if (e.key === "Escape") {
270
- e.target.blur();
271
- }
272
- return;
273
- }
274
- if (e.key === "Escape") {
275
- if (settingsOpen) {
276
- setSettingsOpen(false);
277
- return;
278
- }
279
- onCancel();
280
- } else if (e.key === "Enter") {
281
- onCapture(selectedMode);
282
- }
283
- };
284
- document.addEventListener("keydown", onKey);
285
- return () => document.removeEventListener("keydown", onKey);
286
- }, [expanded, onCancel, onCapture, selectedMode, settingsOpen]);
287
- const handleMouseDown = useCallback2(
288
- (e) => {
289
- e.preventDefault();
290
- const el = toolbarRef.current;
291
- if (!el) return;
292
- const rect = el.getBoundingClientRect();
293
- setDragging(true);
294
- setDragPos({ x: rect.left, y: rect.top });
295
- dragState.current = {
296
- dragging: true,
297
- startX: e.clientX,
298
- startY: e.clientY,
299
- origX: rect.left,
300
- origY: rect.top,
301
- distance: 0
302
- };
303
- },
304
- []
305
- );
306
- useEffect(() => {
307
- const handleMouseMove = (e) => {
308
- const ds = dragState.current;
309
- if (!ds || !ds.dragging) return;
310
- const dx = e.clientX - ds.startX;
311
- const dy = e.clientY - ds.startY;
312
- ds.distance = Math.sqrt(dx * dx + dy * dy);
313
- setDragPos({
314
- x: ds.origX + dx,
315
- y: ds.origY + dy
316
- });
317
- };
318
- const handleMouseUp = (e) => {
319
- const ds = dragState.current;
320
- if (!ds) return;
321
- if (ds.distance < 5) {
322
- onToggle();
323
- } else {
324
- const el = toolbarRef.current;
325
- const w = el?.offsetWidth ?? CONTAINER_SIZE;
326
- const h = el?.offsetHeight ?? CONTAINER_SIZE;
327
- const centerX = ds.origX + (e.clientX - ds.startX) + w / 2;
328
- const centerY = ds.origY + (e.clientY - ds.startY) + h / 2;
329
- const newCorner = snapToCorner(centerX, centerY);
330
- setCorner(newCorner);
331
- try {
332
- localStorage.setItem("ab-toolbar-corner", newCorner);
333
- } catch {
334
- }
335
- }
336
- setDragging(false);
337
- setDragPos(null);
338
- dragState.current = null;
339
- };
340
- window.addEventListener("mousemove", handleMouseMove);
341
- window.addEventListener("mouseup", handleMouseUp);
342
- return () => {
343
- window.removeEventListener("mousemove", handleMouseMove);
344
- window.removeEventListener("mouseup", handleMouseUp);
345
- };
346
- }, [onToggle]);
347
- const panelSide = isRightCorner(corner) ? "left" : "right";
348
- const tooltipSide = panelSide;
349
- const bottom = isBottomCorner(corner);
350
- const positionStyle = dragging && dragPos ? { left: dragPos.x, top: dragPos.y } : getCornerStyle(corner);
351
- const cameraButton = /* @__PURE__ */ jsxs(
240
+ };
241
+ const shortDir = saveDir ? saveDir.replace(/^\/Users\/[^/]+/, "~") : "~/Desktop";
242
+ return /* @__PURE__ */ jsxs(
352
243
  "div",
353
244
  {
354
- onMouseDown: handleMouseDown,
355
- onMouseEnter: () => setCameraHovered(true),
356
- onMouseLeave: () => setCameraHovered(false),
357
245
  style: {
358
- width: 32,
359
- height: 32,
360
- borderRadius: "50%",
361
- display: "flex",
362
- alignItems: "center",
363
- justifyContent: "center",
364
- cursor: dragging ? "grabbing" : "pointer",
365
- background: cameraHovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
366
- transition: "background 0.12s ease"
246
+ minWidth: 300,
247
+ padding: "12px 16px",
248
+ borderRadius: 12,
249
+ background: "rgb(32, 32, 36)",
250
+ border: "1px solid rgba(255, 255, 255, 0.1)",
251
+ boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
252
+ ...style
367
253
  },
368
254
  children: [
369
- /* @__PURE__ */ jsx(
370
- "style",
371
- {
372
- dangerouslySetInnerHTML: {
373
- __html: `
374
- @keyframes ab-spin {
375
- 0% { transform: rotate(0deg); }
376
- 100% { transform: rotate(360deg); }
377
- }`
255
+ /* @__PURE__ */ jsx(SettingsHeader, { onClose }),
256
+ /* @__PURE__ */ jsx(SettingsDivider, {}),
257
+ selectedMode === "component" && /* @__PURE__ */ jsxs(Fragment, { children: [
258
+ /* @__PURE__ */ jsx(
259
+ SettingsRow,
260
+ {
261
+ title: "Frame",
262
+ description: "Wrap in a sized canvas with background",
263
+ control: /* @__PURE__ */ jsx(
264
+ ToggleSwitch,
265
+ {
266
+ enabled: frameSettings.enabled,
267
+ onChange: () => onFrameSettingsChange({ ...frameSettings, enabled: !frameSettings.enabled })
268
+ }
269
+ )
378
270
  }
379
- }
380
- ),
381
- loading ? /* @__PURE__ */ jsx(
382
- LoaderCircle,
383
- {
384
- size: 16,
385
- strokeWidth: 2,
386
- style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
387
- }
388
- ) : phase === "ready" ? /* @__PURE__ */ jsx(Check, { size: 16, strokeWidth: 2.6, color: "#4ade80" }) : /* @__PURE__ */ jsx(
389
- Camera,
271
+ ),
272
+ frameSettings.enabled && /* @__PURE__ */ jsxs(Fragment, { children: [
273
+ /* @__PURE__ */ jsx(SettingsDivider, {}),
274
+ /* @__PURE__ */ jsx(
275
+ FrameSizeControl,
276
+ {
277
+ size: frameSettings.size,
278
+ onChange: (size) => onFrameSettingsChange({ ...frameSettings, size })
279
+ }
280
+ ),
281
+ /* @__PURE__ */ jsx(SettingsDivider, {}),
282
+ /* @__PURE__ */ jsx(
283
+ FrameBackgroundControl,
284
+ {
285
+ bgType: frameSettings.bgType,
286
+ bgColor: frameSettings.bgColor,
287
+ bgImage: frameSettings.bgImage,
288
+ frameSize: frameSettings.size,
289
+ onChange: (updates) => onFrameSettingsChange({ ...frameSettings, ...updates })
290
+ }
291
+ )
292
+ ] }),
293
+ /* @__PURE__ */ jsx(SettingsDivider, {})
294
+ ] }),
295
+ /* @__PURE__ */ jsx(
296
+ SettingsRow,
390
297
  {
391
- size: 16,
392
- strokeWidth: 1.9,
393
- color: cameraHovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)"
298
+ title: "Save Location",
299
+ description: /* @__PURE__ */ jsx(
300
+ "span",
301
+ {
302
+ style: {
303
+ overflow: "hidden",
304
+ textOverflow: "ellipsis",
305
+ whiteSpace: "nowrap",
306
+ display: "block"
307
+ },
308
+ title: shortDir,
309
+ children: shortDir
310
+ }
311
+ ),
312
+ control: /* @__PURE__ */ jsx(SmallButton, { onClick: handlePickFolder, children: picking ? "..." : "Change" })
394
313
  }
395
314
  )
396
315
  ]
397
316
  }
398
317
  );
399
- const toolbarButtons = expanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
400
- /* @__PURE__ */ jsx(IconButton, { tooltipSide, tooltip: "Close", onClick: onCancel, children: /* @__PURE__ */ jsx(X, { size: 16, strokeWidth: 1.7 }) }),
401
- /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 2, padding: "4px 0" }, children: MODES.map(({ mode, label, icon: ModeIcon }) => /* @__PURE__ */ jsx(
402
- IconButton,
403
- {
404
- active: selectedMode === mode,
405
- tooltipSide,
406
- tooltip: label,
407
- onClick: () => {
408
- setSettingsOpen(false);
409
- setHistoryOpen(false);
410
- if (mode === "viewport" || mode === "fullpage") {
411
- onModeChange(mode);
412
- onCapture(mode);
413
- } else {
414
- onModeChange(mode);
415
- }
416
- },
417
- children: /* @__PURE__ */ jsx(ModeIcon, { size: 16, strokeWidth: 1.7 })
418
- },
419
- mode
420
- )) }),
421
- /* @__PURE__ */ jsx(Separator, { vertical: false }),
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" }),
422
323
  /* @__PURE__ */ jsx(
423
- SettingsButton,
324
+ "button",
424
325
  {
425
- open: settingsOpen,
426
- onClick: () => {
427
- setSettingsOpen((prev) => !prev);
428
- setHistoryOpen(false);
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"
429
342
  },
430
- selectedMode,
431
- frameSettings,
432
- onFrameSettingsChange,
433
- panelSide,
434
- tooltipSide
343
+ children: /* @__PURE__ */ jsx(X, { size: 14, strokeWidth: 2 })
435
344
  }
436
- ),
437
- /* @__PURE__ */ jsx(
438
- HistoryButton,
439
- {
440
- open: historyOpen,
441
- onClick: () => {
442
- setHistoryOpen((prev) => !prev);
443
- setSettingsOpen(false);
444
- },
445
- panelSide,
446
- tooltipSide
447
- }
448
- ),
449
- /* @__PURE__ */ jsx(Separator, { vertical: false })
450
- ] }) : null;
345
+ )
346
+ ] });
347
+ }
348
+ function SettingsRow({
349
+ title,
350
+ description,
351
+ control
352
+ }) {
353
+ return /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, padding: "14px 0" }, children: [
354
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 3, flex: 1, minWidth: 0 }, children: [
355
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "rgba(255, 255, 255, 0.92)" }, children: title }),
356
+ description && /* @__PURE__ */ jsx("span", { style: { fontSize: 11, color: "rgba(255, 255, 255, 0.42)", lineHeight: 1.3 }, children: description })
357
+ ] }),
358
+ /* @__PURE__ */ jsx("div", { style: { flexShrink: 0 }, children: control })
359
+ ] });
360
+ }
361
+ function SettingsDivider() {
362
+ return /* @__PURE__ */ jsx("div", { style: { height: 1, background: "rgba(255, 255, 255, 0.08)" } });
363
+ }
364
+ function ToggleSwitch({
365
+ enabled,
366
+ onChange
367
+ }) {
451
368
  return /* @__PURE__ */ jsx(
452
- "div",
369
+ "button",
453
370
  {
454
- ref: toolbarRef,
455
- "data-afterbefore": "true",
371
+ type: "button",
372
+ onClick: onChange,
456
373
  style: {
457
- position: "fixed",
458
- ...positionStyle,
459
- zIndex: 2147483647,
460
- display: "flex",
461
- flexDirection: "column",
462
- alignItems: "center",
463
- background: "rgb(32, 32, 36)",
374
+ width: 38,
375
+ height: 22,
464
376
  borderRadius: 999,
465
- padding: 6,
466
- boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
467
- fontFamily: "system-ui, -apple-system, sans-serif",
468
- userSelect: "none"
377
+ border: "none",
378
+ background: enabled ? "#38bdf8" : "rgba(255, 255, 255, 0.18)",
379
+ position: "relative",
380
+ cursor: "pointer",
381
+ padding: 0,
382
+ flexShrink: 0,
383
+ transition: "background 0.12s ease"
469
384
  },
470
- children: bottom ? /* @__PURE__ */ jsxs(Fragment, { children: [
471
- toolbarButtons,
472
- cameraButton
473
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
474
- cameraButton,
475
- toolbarButtons
476
- ] })
385
+ children: /* @__PURE__ */ jsx(
386
+ "span",
387
+ {
388
+ style: {
389
+ position: "absolute",
390
+ top: 2,
391
+ left: enabled ? 18 : 2,
392
+ width: 18,
393
+ height: 18,
394
+ borderRadius: "50%",
395
+ background: "#fff",
396
+ transition: "left 0.12s ease"
397
+ }
398
+ }
399
+ )
477
400
  }
478
401
  );
479
402
  }
480
- function IconButton({
481
- children,
482
- active,
483
- tooltip,
484
- tooltipSide = "left",
485
- onClick
486
- }) {
487
- const [hovered, setHovered] = useState2(false);
488
- const tooltipStyle = tooltipSide === "left" ? {
489
- right: "calc(100% + 10px)",
490
- top: "50%",
491
- transform: "translateY(-50%)"
492
- } : {
493
- left: "calc(100% + 10px)",
494
- top: "50%",
495
- transform: "translateY(-50%)"
496
- };
497
- return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
498
- tooltip && hovered && /* @__PURE__ */ jsx(
499
- "div",
500
- {
501
- style: {
502
- position: "absolute",
503
- ...tooltipStyle,
504
- background: "rgb(32, 32, 36)",
505
- border: "1px solid rgba(255, 255, 255, 0.1)",
506
- borderRadius: 6,
507
- padding: "3px 8px",
508
- color: "rgba(255, 255, 255, 0.88)",
509
- fontSize: 11,
510
- whiteSpace: "nowrap",
511
- boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
512
- pointerEvents: "none"
513
- },
514
- children: tooltip
515
- }
516
- ),
517
- /* @__PURE__ */ jsx(
518
- "button",
519
- {
520
- onClick,
521
- onMouseEnter: () => setHovered(true),
522
- onMouseLeave: () => setHovered(false),
523
- style: {
524
- width: 32,
525
- height: 32,
526
- borderRadius: "50%",
527
- border: "none",
528
- background: active || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
529
- display: "flex",
530
- alignItems: "center",
531
- justifyContent: "center",
532
- cursor: "pointer",
533
- padding: 0,
534
- color: active || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
535
- transition: "background 0.12s ease, color 0.12s ease"
536
- },
537
- children
538
- }
539
- )
540
- ] });
541
- }
542
- function SettingsButton({
543
- open,
544
- onClick,
545
- selectedMode,
546
- frameSettings,
547
- onFrameSettingsChange,
548
- panelSide,
549
- tooltipSide
550
- }) {
551
- const [saveDir, setSaveDir] = useState2(null);
552
- const [picking, setPicking] = useState2(false);
553
- useEffect(() => {
554
- if (!open) return;
555
- fetch("/__afterbefore/config").then((r) => r.json()).then((data) => setSaveDir(data.saveDir)).catch(() => {
556
- });
557
- }, [open]);
558
- const handlePickFolder = async () => {
559
- setPicking(true);
560
- try {
561
- const res = await fetch("/__afterbefore/pick-folder", { method: "POST" });
562
- const data = await res.json();
563
- if (data.folder) {
564
- await fetch("/__afterbefore/config", {
565
- method: "POST",
566
- headers: { "Content-Type": "application/json" },
567
- body: JSON.stringify({ saveDir: data.folder })
568
- });
569
- setSaveDir(data.folder);
570
- }
571
- } catch {
572
- } finally {
573
- setPicking(false);
574
- }
575
- };
576
- const shortDir = saveDir ? saveDir.replace(/^\/Users\/[^/]+/, "~") : "~/Desktop";
577
- const panelStyle = panelSide === "left" ? { right: "calc(100% + 10px)", top: 0 } : { left: "calc(100% + 10px)", top: 0 };
578
- return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
579
- /* @__PURE__ */ jsx(IconButton, { active: open, tooltipSide, tooltip: !open ? "Settings" : void 0, onClick, children: /* @__PURE__ */ jsx(Settings, { size: 16, strokeWidth: 1.7 }) }),
580
- open && /* @__PURE__ */ jsxs(
581
- "div",
582
- {
583
- style: {
584
- position: "absolute",
585
- ...panelStyle,
586
- minWidth: 260,
587
- padding: "10px 12px",
588
- borderRadius: 12,
589
- background: "rgb(32, 32, 36)",
590
- border: "1px solid rgba(255, 255, 255, 0.1)",
591
- boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)"
592
- },
593
- children: [
594
- /* @__PURE__ */ jsx(
595
- "div",
596
- {
597
- style: {
598
- fontSize: 11,
599
- color: "rgba(255, 255, 255, 0.46)",
600
- letterSpacing: "0.03em",
601
- textTransform: "uppercase",
602
- marginBottom: 10
603
- },
604
- children: "Settings"
605
- }
606
- ),
607
- selectedMode === "component" && /* @__PURE__ */ jsxs(Fragment, { children: [
608
- /* @__PURE__ */ jsx(
609
- ToggleRow,
610
- {
611
- icon: /* @__PURE__ */ jsx(Frame, { size: 15, strokeWidth: 1.8 }),
612
- label: "Frame",
613
- hint: "Wrap component in a sized canvas with background",
614
- enabled: frameSettings.enabled,
615
- onChange: () => onFrameSettingsChange({ ...frameSettings, enabled: !frameSettings.enabled })
616
- }
617
- ),
618
- frameSettings.enabled && /* @__PURE__ */ jsxs("div", { style: { marginTop: 8, display: "flex", flexDirection: "column", gap: 10 }, children: [
619
- /* @__PURE__ */ jsx(
620
- FrameSizeControl,
621
- {
622
- size: frameSettings.size,
623
- onChange: (size) => onFrameSettingsChange({ ...frameSettings, size })
624
- }
625
- ),
626
- /* @__PURE__ */ jsx(
627
- FrameBackgroundControl,
628
- {
629
- bgType: frameSettings.bgType,
630
- bgColor: frameSettings.bgColor,
631
- bgImage: frameSettings.bgImage,
632
- frameSize: frameSettings.size,
633
- onChange: (updates) => onFrameSettingsChange({ ...frameSettings, ...updates })
634
- }
635
- )
636
- ] })
637
- ] }),
638
- selectedMode === "component" && /* @__PURE__ */ jsx("div", { style: { height: 1, background: "rgba(255,255,255,0.08)", margin: "8px 0" } }),
639
- /* @__PURE__ */ jsx(
640
- SaveLocationRow,
641
- {
642
- dir: shortDir,
643
- picking,
644
- onPick: handlePickFolder
645
- }
646
- )
647
- ]
648
- }
649
- )
650
- ] });
651
- }
652
403
  function FrameSizeControl({
653
404
  size,
654
405
  onChange
@@ -656,9 +407,73 @@ function FrameSizeControl({
656
407
  const [sizeOpen, setSizeOpen] = useState2(false);
657
408
  const currentPreset = FRAME_SIZE_PRESETS.find((p) => p.w === size.w && p.h === size.h);
658
409
  const isCustom = !currentPreset;
659
- return /* @__PURE__ */ jsxs("div", { children: [
660
- /* @__PURE__ */ jsx(SettingsLabel, { children: "Size" }),
661
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 4 }, children: [
410
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "14px 0" }, children: [
411
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }, children: [
412
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 3 }, children: [
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
+ ] }),
416
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", flexShrink: 0 }, children: [
417
+ /* @__PURE__ */ jsxs(
418
+ "button",
419
+ {
420
+ onClick: () => setSizeOpen((prev) => !prev),
421
+ style: {
422
+ display: "flex",
423
+ alignItems: "center",
424
+ gap: 6,
425
+ height: 30,
426
+ padding: "0 10px",
427
+ borderRadius: 7,
428
+ border: "1px solid rgba(255,255,255,0.1)",
429
+ background: "rgba(255,255,255,0.07)",
430
+ color: "rgba(255,255,255,0.88)",
431
+ cursor: "pointer",
432
+ fontSize: 12,
433
+ fontFamily: "inherit",
434
+ whiteSpace: "nowrap"
435
+ },
436
+ children: [
437
+ currentPreset ? currentPreset.label : "Custom",
438
+ /* @__PURE__ */ jsx(ChevronDown, { size: 12, strokeWidth: 2 })
439
+ ]
440
+ }
441
+ ),
442
+ sizeOpen && /* @__PURE__ */ jsx(
443
+ "div",
444
+ {
445
+ style: {
446
+ position: "absolute",
447
+ bottom: "calc(100% + 4px)",
448
+ right: 0,
449
+ minWidth: 180,
450
+ background: "rgb(32, 32, 36)",
451
+ border: "1px solid rgba(255, 255, 255, 0.1)",
452
+ borderRadius: 8,
453
+ padding: "4px 0",
454
+ boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
455
+ zIndex: 1
456
+ },
457
+ children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs(
458
+ DropItem,
459
+ {
460
+ active: !isCustom && preset.w === size.w && preset.h === size.h,
461
+ onClick: () => {
462
+ onChange({ w: preset.w, h: preset.h });
463
+ setSizeOpen(false);
464
+ },
465
+ children: [
466
+ /* @__PURE__ */ jsx("span", { children: preset.label }),
467
+ /* @__PURE__ */ jsx("span", { style: { marginLeft: 6, fontSize: 10, color: "rgba(255,255,255,0.34)" }, children: preset.hint })
468
+ ]
469
+ },
470
+ preset.label
471
+ ))
472
+ }
473
+ )
474
+ ] })
475
+ ] }),
476
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 10 }, children: [
662
477
  /* @__PURE__ */ jsx(
663
478
  NumInput,
664
479
  {
@@ -680,66 +495,6 @@ function FrameSizeControl({
680
495
  }
681
496
  }
682
497
  )
683
- ] }),
684
- /* @__PURE__ */ jsxs("div", { style: { position: "relative", marginTop: 6 }, children: [
685
- /* @__PURE__ */ jsxs(
686
- "button",
687
- {
688
- onClick: () => setSizeOpen((prev) => !prev),
689
- style: {
690
- display: "flex",
691
- alignItems: "center",
692
- justifyContent: "space-between",
693
- gap: 6,
694
- width: "100%",
695
- height: 30,
696
- padding: "0 8px",
697
- borderRadius: 7,
698
- border: "1px solid rgba(255,255,255,0.1)",
699
- background: "rgba(255,255,255,0.07)",
700
- color: "rgba(255,255,255,0.88)",
701
- cursor: "pointer",
702
- fontSize: 12,
703
- fontFamily: "inherit"
704
- },
705
- children: [
706
- currentPreset ? currentPreset.label : "Custom",
707
- /* @__PURE__ */ jsx(ChevronDown, { size: 12, strokeWidth: 2 })
708
- ]
709
- }
710
- ),
711
- sizeOpen && /* @__PURE__ */ jsx(
712
- "div",
713
- {
714
- style: {
715
- position: "absolute",
716
- bottom: "calc(100% + 4px)",
717
- left: 0,
718
- right: 0,
719
- background: "rgb(32, 32, 36)",
720
- border: "1px solid rgba(255, 255, 255, 0.1)",
721
- borderRadius: 8,
722
- padding: "4px 0",
723
- boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
724
- zIndex: 1
725
- },
726
- children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs(
727
- DropItem,
728
- {
729
- active: !isCustom && preset.w === size.w && preset.h === size.h,
730
- onClick: () => {
731
- onChange({ w: preset.w, h: preset.h });
732
- setSizeOpen(false);
733
- },
734
- children: [
735
- /* @__PURE__ */ jsx("span", { children: preset.label }),
736
- /* @__PURE__ */ jsx("span", { style: { marginLeft: 6, fontSize: 10, color: "rgba(255,255,255,0.34)" }, children: preset.hint })
737
- ]
738
- },
739
- preset.label
740
- ))
741
- }
742
- )
743
498
  ] })
744
499
  ] });
745
500
  }
@@ -768,39 +523,44 @@ function FrameBackgroundControl({
768
523
  reader.readAsDataURL(file);
769
524
  e.target.value = "";
770
525
  };
771
- return /* @__PURE__ */ jsxs("div", { children: [
772
- /* @__PURE__ */ jsx(SettingsLabel, { children: "Background" }),
773
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 2, marginTop: 4 }, children: [
774
- /* @__PURE__ */ jsxs(
775
- SegmentButton,
776
- {
777
- active: bgType === "color",
778
- onClick: () => onChange({ bgType: "color" }),
779
- style: { borderRadius: "6px 0 0 6px" },
780
- children: [
781
- /* @__PURE__ */ jsx(Palette, { size: 12, strokeWidth: 2 }),
782
- "Color"
783
- ]
784
- }
785
- ),
786
- /* @__PURE__ */ jsxs(
787
- SegmentButton,
788
- {
789
- active: bgType === "image",
790
- onClick: () => onChange({ bgType: "image" }),
791
- style: { borderRadius: "0 6px 6px 0" },
792
- children: [
793
- /* @__PURE__ */ jsx(ImageIcon, { size: 12, strokeWidth: 2 }),
794
- "Image"
795
- ]
796
- }
797
- )
798
- ] }),
799
- bgType === "color" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 }, children: [
800
- /* @__PURE__ */ jsx(ColorSwatch, { color: bgColor, onChange: (c) => onChange({ bgColor: c }) }),
526
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "14px 0" }, children: [
527
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16 }, children: [
528
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 3 }, children: [
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
+ ] }),
532
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 2, flexShrink: 0 }, children: [
533
+ /* @__PURE__ */ jsxs(
534
+ SegmentButton,
535
+ {
536
+ active: bgType === "color",
537
+ onClick: () => onChange({ bgType: "color" }),
538
+ style: { borderRadius: "6px 0 0 6px" },
539
+ children: [
540
+ /* @__PURE__ */ jsx(Palette, { size: 12, strokeWidth: 2 }),
541
+ "Color"
542
+ ]
543
+ }
544
+ ),
545
+ /* @__PURE__ */ jsxs(
546
+ SegmentButton,
547
+ {
548
+ active: bgType === "image",
549
+ onClick: () => onChange({ bgType: "image" }),
550
+ style: { borderRadius: "0 6px 6px 0" },
551
+ children: [
552
+ /* @__PURE__ */ jsx(ImageIcon, { size: 12, strokeWidth: 2 }),
553
+ "Image"
554
+ ]
555
+ }
556
+ )
557
+ ] })
558
+ ] }),
559
+ bgType === "color" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 10 }, children: [
560
+ /* @__PURE__ */ jsx(ColorSwatch, { color: bgColor, onChange: (c) => onChange({ bgColor: c }) }),
801
561
  /* @__PURE__ */ jsx(HexInput, { value: bgColor, onChange: (c) => onChange({ bgColor: c }) })
802
562
  ] }),
803
- bgType === "image" && /* @__PURE__ */ jsxs("div", { style: { marginTop: 6 }, children: [
563
+ bgType === "image" && /* @__PURE__ */ jsxs("div", { style: { marginTop: 10 }, children: [
804
564
  /* @__PURE__ */ jsx(
805
565
  "input",
806
566
  {
@@ -838,19 +598,6 @@ function FrameBackgroundControl({
838
598
  ] })
839
599
  ] });
840
600
  }
841
- function SettingsLabel({ children }) {
842
- return /* @__PURE__ */ jsx(
843
- "div",
844
- {
845
- style: {
846
- fontSize: 11,
847
- color: "rgba(255, 255, 255, 0.42)",
848
- letterSpacing: "0.02em"
849
- },
850
- children
851
- }
852
- );
853
- }
854
601
  function SegmentButton({
855
602
  children,
856
603
  active,
@@ -950,6 +697,141 @@ function SmallButton({
950
697
  }
951
698
  );
952
699
  }
700
+ function NumInput({
701
+ value,
702
+ onChange
703
+ }) {
704
+ const [editing, setEditing] = useState2(false);
705
+ const [text, setText] = useState2(String(value));
706
+ useEffect(() => {
707
+ if (!editing) {
708
+ setText(String(value));
709
+ }
710
+ }, [editing, value]);
711
+ return /* @__PURE__ */ jsx(
712
+ "input",
713
+ {
714
+ type: "text",
715
+ value: editing ? text : String(value),
716
+ onFocus: () => {
717
+ setEditing(true);
718
+ setText(String(value));
719
+ },
720
+ onBlur: () => {
721
+ setEditing(false);
722
+ onChange(text);
723
+ },
724
+ onChange: (e) => setText(e.target.value),
725
+ onKeyDown: (e) => {
726
+ if (e.key === "Enter") {
727
+ e.target.blur();
728
+ }
729
+ },
730
+ style: {
731
+ width: 54,
732
+ padding: "4px 6px",
733
+ background: "rgba(255, 255, 255, 0.07)",
734
+ border: "1px solid rgba(255, 255, 255, 0.1)",
735
+ borderRadius: 7,
736
+ color: "rgba(255, 255, 255, 0.9)",
737
+ fontSize: 12,
738
+ fontFamily: "system-ui, -apple-system, sans-serif",
739
+ textAlign: "center",
740
+ outline: "none"
741
+ }
742
+ }
743
+ );
744
+ }
745
+ function HexInput({
746
+ value,
747
+ onChange
748
+ }) {
749
+ const [editing, setEditing] = useState2(false);
750
+ const [text, setText] = useState2(value);
751
+ useEffect(() => {
752
+ if (!editing) {
753
+ setText(value);
754
+ }
755
+ }, [editing, value]);
756
+ const commit = (raw) => {
757
+ const hex = raw.startsWith("#") ? raw : `#${raw}`;
758
+ if (/^#[0-9a-fA-F]{6}$/.test(hex)) {
759
+ onChange(hex);
760
+ }
761
+ };
762
+ return /* @__PURE__ */ jsx(
763
+ "input",
764
+ {
765
+ type: "text",
766
+ value: editing ? text : value,
767
+ onFocus: () => {
768
+ setEditing(true);
769
+ setText(value);
770
+ },
771
+ onBlur: () => {
772
+ setEditing(false);
773
+ commit(text);
774
+ },
775
+ onChange: (e) => setText(e.target.value),
776
+ onKeyDown: (e) => {
777
+ if (e.key === "Enter") {
778
+ e.target.blur();
779
+ }
780
+ },
781
+ style: {
782
+ width: 72,
783
+ padding: "4px 6px",
784
+ background: "rgba(255, 255, 255, 0.07)",
785
+ border: "1px solid rgba(255, 255, 255, 0.1)",
786
+ borderRadius: 7,
787
+ color: "rgba(255, 255, 255, 0.9)",
788
+ fontSize: 12,
789
+ fontFamily: "system-ui, -apple-system, sans-serif",
790
+ textAlign: "left",
791
+ outline: "none"
792
+ }
793
+ }
794
+ );
795
+ }
796
+ function StaticText({ children }) {
797
+ return /* @__PURE__ */ jsx(
798
+ "span",
799
+ {
800
+ style: {
801
+ fontSize: 11,
802
+ color: "rgba(255,255,255,0.35)",
803
+ minWidth: 8,
804
+ textAlign: "center"
805
+ },
806
+ children
807
+ }
808
+ );
809
+ }
810
+ function DropItem({
811
+ children,
812
+ onClick,
813
+ active
814
+ }) {
815
+ return /* @__PURE__ */ jsx(
816
+ "button",
817
+ {
818
+ onClick,
819
+ style: {
820
+ display: "block",
821
+ width: "100%",
822
+ padding: "7px 12px",
823
+ background: active ? "rgba(255, 255, 255, 0.08)" : "transparent",
824
+ border: "none",
825
+ color: "rgba(255, 255, 255, 0.86)",
826
+ textAlign: "left",
827
+ cursor: "pointer",
828
+ fontSize: 13,
829
+ fontFamily: "inherit"
830
+ },
831
+ children
832
+ }
833
+ );
834
+ }
953
835
  async function downscaleImage(dataUrl, maxW, maxH) {
954
836
  return new Promise((resolve) => {
955
837
  const img = new Image();
@@ -966,267 +848,413 @@ async function downscaleImage(dataUrl, maxW, maxH) {
966
848
  img.src = dataUrl;
967
849
  });
968
850
  }
969
- function SaveLocationRow({
970
- dir,
971
- picking,
972
- onPick
973
- }) {
974
- const [btnHovered, setBtnHovered] = useState2(false);
975
- return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: /* @__PURE__ */ jsxs(
976
- "div",
977
- {
978
- style: {
979
- display: "flex",
980
- alignItems: "center",
981
- gap: 8,
982
- color: "rgba(255, 255, 255, 0.88)",
983
- fontSize: 13
984
- },
985
- children: [
986
- /* @__PURE__ */ jsx(FolderOpen, { size: 15, strokeWidth: 1.8, style: { flexShrink: 0 } }),
987
- /* @__PURE__ */ jsx(
988
- "span",
989
- {
990
- style: {
991
- overflow: "hidden",
992
- textOverflow: "ellipsis",
993
- whiteSpace: "nowrap",
994
- flex: 1,
995
- minWidth: 0
996
- },
997
- title: dir,
998
- children: dir
999
- }
1000
- ),
1001
- /* @__PURE__ */ jsx(
1002
- "button",
1003
- {
1004
- onClick: onPick,
1005
- disabled: picking,
1006
- onMouseEnter: () => setBtnHovered(true),
1007
- onMouseLeave: () => setBtnHovered(false),
1008
- style: {
1009
- padding: "3px 8px",
1010
- borderRadius: 6,
1011
- border: "1px solid rgba(255,255,255,0.12)",
1012
- background: btnHovered ? "rgba(255,255,255,0.12)" : "rgba(255,255,255,0.06)",
1013
- color: "rgba(255,255,255,0.78)",
1014
- fontSize: 11,
1015
- cursor: picking ? "wait" : "pointer",
1016
- flexShrink: 0,
1017
- fontFamily: "inherit",
1018
- transition: "background 0.12s ease"
1019
- },
1020
- children: picking ? "..." : "Change"
1021
- }
1022
- )
1023
- ]
1024
- }
1025
- ) });
851
+
852
+ // src/overlay/ui/toolbar.tsx
853
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
854
+ var EDGE_MARGIN = 24;
855
+ var CONTAINER_SIZE = 38;
856
+ function getCornerStyle(corner) {
857
+ switch (corner) {
858
+ case "bottom-right":
859
+ return { bottom: EDGE_MARGIN, right: EDGE_MARGIN };
860
+ case "bottom-left":
861
+ return { bottom: EDGE_MARGIN, left: EDGE_MARGIN };
862
+ case "top-right":
863
+ return { top: EDGE_MARGIN, right: EDGE_MARGIN };
864
+ case "top-left":
865
+ return { top: EDGE_MARGIN, left: EDGE_MARGIN };
866
+ }
1026
867
  }
1027
- function ToggleRow({
1028
- icon,
1029
- label,
1030
- hint,
1031
- enabled,
1032
- onChange
868
+ function isBottomCorner(corner) {
869
+ return corner === "bottom-right" || corner === "bottom-left";
870
+ }
871
+ function isRightCorner(corner) {
872
+ return corner === "bottom-right" || corner === "top-right";
873
+ }
874
+ function snapToCorner(x, y) {
875
+ const cx = window.innerWidth / 2;
876
+ const cy = window.innerHeight / 2;
877
+ if (x < cx) {
878
+ return y < cy ? "top-left" : "bottom-left";
879
+ }
880
+ return y < cy ? "top-right" : "bottom-right";
881
+ }
882
+ var MODES = [
883
+ { mode: "component", label: "Component", icon: MousePointer2 },
884
+ { mode: "viewport", label: "Viewport", icon: Monitor },
885
+ { mode: "fullpage", label: "Full Page", icon: Maximize }
886
+ ];
887
+ function Toolbar({
888
+ expanded,
889
+ onToggle,
890
+ phase,
891
+ loading,
892
+ selectedMode,
893
+ onModeChange,
894
+ onCapture,
895
+ onCancel,
896
+ frameSettings,
897
+ onFrameSettingsChange
1033
898
  }) {
1034
- return /* @__PURE__ */ jsxs(
1035
- "label",
899
+ const [settingsOpen, setSettingsOpen] = useState3(false);
900
+ const [historyOpen, setHistoryOpen] = useState3(false);
901
+ const [corner, setCorner] = useState3(() => {
902
+ try {
903
+ const stored = localStorage.getItem("ab-toolbar-corner");
904
+ if (stored && ["bottom-right", "bottom-left", "top-right", "top-left"].includes(stored)) {
905
+ return stored;
906
+ }
907
+ } catch {
908
+ }
909
+ return "bottom-right";
910
+ });
911
+ const [dragging, setDragging] = useState3(false);
912
+ const [dragPos, setDragPos] = useState3(null);
913
+ const dragState = useRef2(null);
914
+ const toolbarRef = useRef2(null);
915
+ const [cameraHovered, setCameraHovered] = useState3(false);
916
+ useEffect2(() => {
917
+ if (!expanded) return;
918
+ const onKey = (e) => {
919
+ if (e.target?.tagName === "INPUT") {
920
+ if (e.key === "Escape") {
921
+ e.target.blur();
922
+ }
923
+ return;
924
+ }
925
+ if (e.key === "Escape") {
926
+ if (settingsOpen) {
927
+ setSettingsOpen(false);
928
+ return;
929
+ }
930
+ onCancel();
931
+ } else if (e.key === "Enter") {
932
+ onCapture(selectedMode);
933
+ }
934
+ };
935
+ document.addEventListener("keydown", onKey);
936
+ return () => document.removeEventListener("keydown", onKey);
937
+ }, [expanded, onCancel, onCapture, selectedMode, settingsOpen]);
938
+ const handleMouseDown = useCallback2(
939
+ (e) => {
940
+ e.preventDefault();
941
+ const el = toolbarRef.current;
942
+ if (!el) return;
943
+ const rect = el.getBoundingClientRect();
944
+ setDragging(true);
945
+ setDragPos({ x: rect.left, y: rect.top });
946
+ dragState.current = {
947
+ dragging: true,
948
+ startX: e.clientX,
949
+ startY: e.clientY,
950
+ origX: rect.left,
951
+ origY: rect.top,
952
+ distance: 0
953
+ };
954
+ },
955
+ []
956
+ );
957
+ useEffect2(() => {
958
+ const handleMouseMove = (e) => {
959
+ const ds = dragState.current;
960
+ if (!ds || !ds.dragging) return;
961
+ const dx = e.clientX - ds.startX;
962
+ const dy = e.clientY - ds.startY;
963
+ ds.distance = Math.sqrt(dx * dx + dy * dy);
964
+ setDragPos({
965
+ x: ds.origX + dx,
966
+ y: ds.origY + dy
967
+ });
968
+ };
969
+ const handleMouseUp = (e) => {
970
+ const ds = dragState.current;
971
+ if (!ds) return;
972
+ if (ds.distance < 5) {
973
+ onToggle();
974
+ } else {
975
+ const el = toolbarRef.current;
976
+ const w = el?.offsetWidth ?? CONTAINER_SIZE;
977
+ const h = el?.offsetHeight ?? CONTAINER_SIZE;
978
+ const centerX = ds.origX + (e.clientX - ds.startX) + w / 2;
979
+ const centerY = ds.origY + (e.clientY - ds.startY) + h / 2;
980
+ const newCorner = snapToCorner(centerX, centerY);
981
+ setCorner(newCorner);
982
+ try {
983
+ localStorage.setItem("ab-toolbar-corner", newCorner);
984
+ } catch {
985
+ }
986
+ }
987
+ setDragging(false);
988
+ setDragPos(null);
989
+ dragState.current = null;
990
+ };
991
+ window.addEventListener("mousemove", handleMouseMove);
992
+ window.addEventListener("mouseup", handleMouseUp);
993
+ return () => {
994
+ window.removeEventListener("mousemove", handleMouseMove);
995
+ window.removeEventListener("mouseup", handleMouseUp);
996
+ };
997
+ }, [onToggle]);
998
+ const panelSide = isRightCorner(corner) ? "left" : "right";
999
+ const tooltipSide = panelSide;
1000
+ const bottom = isBottomCorner(corner);
1001
+ const positionStyle = dragging && dragPos ? { left: dragPos.x, top: dragPos.y } : getCornerStyle(corner);
1002
+ const cameraTooltipLabel = expanded ? "Close" : void 0;
1003
+ 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
+ const cameraButton = /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1005
+ cameraTooltipLabel && cameraHovered && !dragging && /* @__PURE__ */ jsx2(
1006
+ "div",
1007
+ {
1008
+ style: {
1009
+ position: "absolute",
1010
+ ...cameraTooltipStyle,
1011
+ background: "rgb(32, 32, 36)",
1012
+ border: "1px solid rgba(255, 255, 255, 0.1)",
1013
+ borderRadius: 6,
1014
+ padding: "3px 8px",
1015
+ color: "rgba(255, 255, 255, 0.88)",
1016
+ fontSize: 11,
1017
+ whiteSpace: "nowrap",
1018
+ boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
1019
+ pointerEvents: "none"
1020
+ },
1021
+ children: cameraTooltipLabel
1022
+ }
1023
+ ),
1024
+ /* @__PURE__ */ jsxs2(
1025
+ "div",
1026
+ {
1027
+ onMouseDown: handleMouseDown,
1028
+ onMouseEnter: () => setCameraHovered(true),
1029
+ onMouseLeave: () => setCameraHovered(false),
1030
+ style: {
1031
+ width: 36,
1032
+ height: 36,
1033
+ padding: 2,
1034
+ borderRadius: "50%",
1035
+ display: "flex",
1036
+ alignItems: "center",
1037
+ justifyContent: "center",
1038
+ cursor: dragging ? "grabbing" : "pointer",
1039
+ background: expanded && cameraHovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
1040
+ transition: "background 0.12s ease"
1041
+ },
1042
+ children: [
1043
+ /* @__PURE__ */ jsx2(
1044
+ "style",
1045
+ {
1046
+ dangerouslySetInnerHTML: {
1047
+ __html: `
1048
+ @keyframes ab-spin {
1049
+ 0% { transform: rotate(0deg); }
1050
+ 100% { transform: rotate(360deg); }
1051
+ }`
1052
+ }
1053
+ }
1054
+ ),
1055
+ loading ? /* @__PURE__ */ jsx2(
1056
+ LoaderCircle,
1057
+ {
1058
+ size: 16,
1059
+ strokeWidth: 2,
1060
+ style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
1061
+ }
1062
+ ) : phase === "ready" ? /* @__PURE__ */ jsx2(Check, { size: 16, strokeWidth: 2.6, color: "#4ade80" }) : expanded ? /* @__PURE__ */ jsx2(
1063
+ X2,
1064
+ {
1065
+ size: 16,
1066
+ strokeWidth: 1.7,
1067
+ color: cameraHovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)"
1068
+ }
1069
+ ) : /* @__PURE__ */ jsx2(
1070
+ Camera,
1071
+ {
1072
+ size: 16,
1073
+ strokeWidth: 1.9,
1074
+ color: "rgba(255, 255, 255, 0.52)"
1075
+ }
1076
+ )
1077
+ ]
1078
+ }
1079
+ )
1080
+ ] });
1081
+ const toolbarButtons = expanded ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1082
+ /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 2, padding: "4px 0" }, children: MODES.map(({ mode, label, icon: ModeIcon }) => /* @__PURE__ */ jsx2(
1083
+ IconButton,
1084
+ {
1085
+ active: selectedMode === mode,
1086
+ tooltipSide,
1087
+ tooltip: label,
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 })
1099
+ },
1100
+ mode
1101
+ )) }),
1102
+ /* @__PURE__ */ jsx2(Separator, { vertical: false }),
1103
+ /* @__PURE__ */ jsx2(
1104
+ SettingsButton,
1105
+ {
1106
+ open: settingsOpen,
1107
+ onClick: () => {
1108
+ setSettingsOpen((prev) => !prev);
1109
+ setHistoryOpen(false);
1110
+ },
1111
+ selectedMode,
1112
+ frameSettings,
1113
+ onFrameSettingsChange,
1114
+ panelSide,
1115
+ tooltipSide,
1116
+ bottom
1117
+ }
1118
+ ),
1119
+ /* @__PURE__ */ jsx2(
1120
+ HistoryButton,
1121
+ {
1122
+ open: historyOpen,
1123
+ onClick: () => {
1124
+ setHistoryOpen((prev) => !prev);
1125
+ setSettingsOpen(false);
1126
+ },
1127
+ panelSide,
1128
+ tooltipSide,
1129
+ bottom
1130
+ }
1131
+ ),
1132
+ /* @__PURE__ */ jsx2(Separator, { vertical: false })
1133
+ ] }) : null;
1134
+ return /* @__PURE__ */ jsx2(
1135
+ "div",
1036
1136
  {
1137
+ ref: toolbarRef,
1138
+ "data-afterbefore": "true",
1037
1139
  style: {
1140
+ position: "fixed",
1141
+ ...positionStyle,
1142
+ zIndex: 2147483647,
1038
1143
  display: "flex",
1144
+ flexDirection: "column",
1039
1145
  alignItems: "center",
1040
- justifyContent: "space-between",
1041
- gap: 12,
1042
- cursor: "pointer"
1146
+ background: "rgb(32, 32, 36)",
1147
+ borderRadius: 999,
1148
+ padding: 6,
1149
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
1150
+ fontFamily: "system-ui, -apple-system, sans-serif",
1151
+ userSelect: "none"
1043
1152
  },
1044
- children: [
1045
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
1046
- /* @__PURE__ */ jsxs(
1047
- "span",
1048
- {
1049
- style: {
1050
- display: "flex",
1051
- alignItems: "center",
1052
- gap: 8,
1053
- color: "rgba(255, 255, 255, 0.88)",
1054
- fontSize: 13,
1055
- whiteSpace: "nowrap"
1056
- },
1057
- children: [
1058
- icon,
1059
- label
1060
- ]
1061
- }
1062
- ),
1063
- hint && /* @__PURE__ */ jsx(
1064
- "span",
1065
- {
1066
- style: {
1067
- fontSize: 10,
1068
- color: "rgba(255, 255, 255, 0.36)",
1069
- paddingLeft: 23
1070
- },
1071
- children: hint
1072
- }
1073
- )
1074
- ] }),
1075
- /* @__PURE__ */ jsx(
1076
- "button",
1077
- {
1078
- type: "button",
1079
- onClick: onChange,
1080
- style: {
1081
- width: 38,
1082
- height: 22,
1083
- borderRadius: 999,
1084
- border: "none",
1085
- background: enabled ? "#38bdf8" : "rgba(255, 255, 255, 0.18)",
1086
- position: "relative",
1087
- cursor: "pointer",
1088
- padding: 0,
1089
- flexShrink: 0,
1090
- transition: "background 0.12s ease"
1091
- },
1092
- children: /* @__PURE__ */ jsx(
1093
- "span",
1094
- {
1095
- style: {
1096
- position: "absolute",
1097
- top: 2,
1098
- left: enabled ? 18 : 2,
1099
- width: 18,
1100
- height: 18,
1101
- borderRadius: "50%",
1102
- background: "#fff",
1103
- transition: "left 0.12s ease"
1104
- }
1105
- }
1106
- )
1107
- }
1108
- )
1109
- ]
1153
+ children: bottom ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1154
+ toolbarButtons,
1155
+ cameraButton
1156
+ ] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
1157
+ cameraButton,
1158
+ toolbarButtons
1159
+ ] })
1110
1160
  }
1111
1161
  );
1112
1162
  }
1113
- function NumInput({
1114
- value,
1115
- onChange
1163
+ function IconButton({
1164
+ children,
1165
+ active,
1166
+ tooltip,
1167
+ tooltipSide = "left",
1168
+ onClick
1116
1169
  }) {
1117
- const [editing, setEditing] = useState2(false);
1118
- const [text, setText] = useState2(String(value));
1119
- useEffect(() => {
1120
- if (!editing) {
1121
- setText(String(value));
1122
- }
1123
- }, [editing, value]);
1124
- return /* @__PURE__ */ jsx(
1125
- "input",
1126
- {
1127
- type: "text",
1128
- value: editing ? text : String(value),
1129
- onFocus: () => {
1130
- setEditing(true);
1131
- setText(String(value));
1132
- },
1133
- onBlur: () => {
1134
- setEditing(false);
1135
- onChange(text);
1136
- },
1137
- onChange: (e) => setText(e.target.value),
1138
- onKeyDown: (e) => {
1139
- if (e.key === "Enter") {
1140
- e.target.blur();
1141
- }
1142
- },
1143
- style: {
1144
- width: 54,
1145
- padding: "4px 6px",
1146
- background: "rgba(255, 255, 255, 0.07)",
1147
- border: "1px solid rgba(255, 255, 255, 0.1)",
1148
- borderRadius: 7,
1149
- color: "rgba(255, 255, 255, 0.9)",
1150
- fontSize: 12,
1151
- fontFamily: "system-ui, -apple-system, sans-serif",
1152
- textAlign: "center",
1153
- outline: "none"
1170
+ const [hovered, setHovered] = useState3(false);
1171
+ const tooltipStyle = tooltipSide === "left" ? {
1172
+ right: "calc(100% + 10px)",
1173
+ top: "50%",
1174
+ transform: "translateY(-50%)"
1175
+ } : {
1176
+ left: "calc(100% + 10px)",
1177
+ top: "50%",
1178
+ transform: "translateY(-50%)"
1179
+ };
1180
+ return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1181
+ tooltip && hovered && /* @__PURE__ */ jsx2(
1182
+ "div",
1183
+ {
1184
+ style: {
1185
+ position: "absolute",
1186
+ ...tooltipStyle,
1187
+ background: "rgb(32, 32, 36)",
1188
+ border: "1px solid rgba(255, 255, 255, 0.1)",
1189
+ borderRadius: 6,
1190
+ padding: "3px 8px",
1191
+ color: "rgba(255, 255, 255, 0.88)",
1192
+ fontSize: 11,
1193
+ whiteSpace: "nowrap",
1194
+ boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
1195
+ pointerEvents: "none"
1196
+ },
1197
+ children: tooltip
1154
1198
  }
1155
- }
1156
- );
1199
+ ),
1200
+ /* @__PURE__ */ jsx2(
1201
+ "button",
1202
+ {
1203
+ onClick,
1204
+ onMouseEnter: () => setHovered(true),
1205
+ onMouseLeave: () => setHovered(false),
1206
+ style: {
1207
+ width: 32,
1208
+ height: 32,
1209
+ borderRadius: "50%",
1210
+ border: "none",
1211
+ background: active || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
1212
+ display: "flex",
1213
+ alignItems: "center",
1214
+ justifyContent: "center",
1215
+ cursor: "pointer",
1216
+ padding: 0,
1217
+ color: active || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
1218
+ transition: "background 0.12s ease, color 0.12s ease"
1219
+ },
1220
+ children
1221
+ }
1222
+ )
1223
+ ] });
1157
1224
  }
1158
- function HexInput({
1159
- value,
1160
- onChange
1225
+ function SettingsButton({
1226
+ open,
1227
+ onClick,
1228
+ selectedMode,
1229
+ frameSettings,
1230
+ onFrameSettingsChange,
1231
+ panelSide,
1232
+ tooltipSide,
1233
+ bottom
1161
1234
  }) {
1162
- const [editing, setEditing] = useState2(false);
1163
- const [text, setText] = useState2(value);
1164
- useEffect(() => {
1165
- if (!editing) {
1166
- setText(value);
1167
- }
1168
- }, [editing, value]);
1169
- const commit = (raw) => {
1170
- const hex = raw.startsWith("#") ? raw : `#${raw}`;
1171
- if (/^#[0-9a-fA-F]{6}$/.test(hex)) {
1172
- onChange(hex);
1173
- }
1174
- };
1175
- return /* @__PURE__ */ jsx(
1176
- "input",
1177
- {
1178
- type: "text",
1179
- value: editing ? text : value,
1180
- onFocus: () => {
1181
- setEditing(true);
1182
- setText(value);
1183
- },
1184
- onBlur: () => {
1185
- setEditing(false);
1186
- commit(text);
1187
- },
1188
- onChange: (e) => setText(e.target.value),
1189
- onKeyDown: (e) => {
1190
- if (e.key === "Enter") {
1191
- e.target.blur();
1192
- }
1193
- },
1194
- style: {
1195
- width: 72,
1196
- padding: "4px 6px",
1197
- background: "rgba(255, 255, 255, 0.07)",
1198
- border: "1px solid rgba(255, 255, 255, 0.1)",
1199
- borderRadius: 7,
1200
- color: "rgba(255, 255, 255, 0.9)",
1201
- fontSize: 12,
1202
- fontFamily: "system-ui, -apple-system, sans-serif",
1203
- textAlign: "left",
1204
- outline: "none"
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
1205
1247
  }
1206
- }
1207
- );
1208
- }
1209
- function StaticText({ children }) {
1210
- return /* @__PURE__ */ jsx(
1211
- "span",
1212
- {
1213
- style: {
1214
- fontSize: 11,
1215
- color: "rgba(255,255,255,0.35)",
1216
- minWidth: 8,
1217
- textAlign: "center"
1218
- },
1219
- children
1220
- }
1221
- );
1248
+ )
1249
+ ] });
1222
1250
  }
1223
- function DropItem({
1251
+ function DropItem2({
1224
1252
  children,
1225
1253
  onClick,
1226
1254
  active,
1227
1255
  accent
1228
1256
  }) {
1229
- return /* @__PURE__ */ jsx(
1257
+ return /* @__PURE__ */ jsx2(
1230
1258
  "button",
1231
1259
  {
1232
1260
  onClick,
@@ -1247,7 +1275,7 @@ function DropItem({
1247
1275
  );
1248
1276
  }
1249
1277
  function Separator({ vertical = true }) {
1250
- return /* @__PURE__ */ jsx(
1278
+ return /* @__PURE__ */ jsx2(
1251
1279
  "div",
1252
1280
  {
1253
1281
  style: {
@@ -1264,23 +1292,24 @@ function HistoryButton({
1264
1292
  open,
1265
1293
  onClick,
1266
1294
  panelSide,
1267
- tooltipSide
1295
+ tooltipSide,
1296
+ bottom
1268
1297
  }) {
1269
- const [toast, setToast] = useState2(null);
1270
- const [pushing, setPushing] = useState2(false);
1271
- const [repos, setRepos] = useState2([]);
1272
- const [branches, setBranches] = useState2([]);
1273
- const [screenshots, setScreenshots] = useState2([]);
1274
- const [selectedRepo, setSelectedRepo] = useState2(null);
1275
- const [selectedBranch, setSelectedBranch] = useState2(null);
1276
- const [loading, setLoading] = useState2(false);
1277
- const [repoDropOpen, setRepoDropOpen] = useState2(false);
1278
- const [branchDropOpen, setBranchDropOpen] = useState2(false);
1279
- const [lightboxSrc, setLightboxSrc] = useState2(null);
1280
- const [editingFile, setEditingFile] = useState2(null);
1281
- const [editValue, setEditValue] = useState2("");
1282
- const [hoveredThumb, setHoveredThumb] = useState2(null);
1283
- useEffect(() => {
1298
+ const [toast, setToast] = useState3(null);
1299
+ const [pushing, setPushing] = useState3(false);
1300
+ const [repos, setRepos] = useState3([]);
1301
+ const [branches, setBranches] = useState3([]);
1302
+ const [screenshots, setScreenshots] = useState3([]);
1303
+ const [selectedRepo, setSelectedRepo] = useState3(null);
1304
+ const [selectedBranch, setSelectedBranch] = useState3(null);
1305
+ const [loading, setLoading] = useState3(false);
1306
+ const [repoDropOpen, setRepoDropOpen] = useState3(false);
1307
+ const [branchDropOpen, setBranchDropOpen] = useState3(false);
1308
+ const [lightboxSrc, setLightboxSrc] = useState3(null);
1309
+ const [editingFile, setEditingFile] = useState3(null);
1310
+ const [editValue, setEditValue] = useState3("");
1311
+ const [hoveredThumb, setHoveredThumb] = useState3(null);
1312
+ useEffect2(() => {
1284
1313
  if (!open) {
1285
1314
  setRepoDropOpen(false);
1286
1315
  setBranchDropOpen(false);
@@ -1382,10 +1411,11 @@ function HistoryButton({
1382
1411
  setPushing(false);
1383
1412
  }
1384
1413
  };
1385
- const panelStyle = panelSide === "left" ? { right: "calc(100% + 10px)", top: 0 } : { left: "calc(100% + 10px)", top: 0 };
1386
- return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
1387
- /* @__PURE__ */ jsx(IconButton, { active: open, tooltipSide, tooltip: !open ? "Screenshots" : void 0, onClick, children: /* @__PURE__ */ jsx(Clock, { size: 16, strokeWidth: 1.7 }) }),
1388
- open && /* @__PURE__ */ jsxs(
1414
+ const verticalAlign = bottom ? { bottom: 0 } : { top: 0 };
1415
+ const panelStyle = panelSide === "left" ? { right: "calc(100% + 10px)", ...verticalAlign } : { left: "calc(100% + 10px)", ...verticalAlign };
1416
+ return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1417
+ /* @__PURE__ */ jsx2(IconButton, { active: open, tooltipSide, tooltip: !open ? "Screenshots" : void 0, onClick, children: /* @__PURE__ */ jsx2(Clock, { size: 16, strokeWidth: 1.7 }) }),
1418
+ open && /* @__PURE__ */ jsxs2(
1389
1419
  "div",
1390
1420
  {
1391
1421
  style: {
@@ -1400,7 +1430,7 @@ function HistoryButton({
1400
1430
  boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)"
1401
1431
  },
1402
1432
  children: [
1403
- /* @__PURE__ */ jsx(
1433
+ /* @__PURE__ */ jsx2(
1404
1434
  "div",
1405
1435
  {
1406
1436
  style: {
@@ -1413,8 +1443,8 @@ function HistoryButton({
1413
1443
  children: "Screenshots"
1414
1444
  }
1415
1445
  ),
1416
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginBottom: 10 }, children: [
1417
- /* @__PURE__ */ jsx(
1446
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginBottom: 10 }, children: [
1447
+ /* @__PURE__ */ jsx2(
1418
1448
  FilterDropdown,
1419
1449
  {
1420
1450
  label: "Project",
@@ -1432,7 +1462,7 @@ function HistoryButton({
1432
1462
  }
1433
1463
  }
1434
1464
  ),
1435
- /* @__PURE__ */ jsx(
1465
+ /* @__PURE__ */ jsx2(
1436
1466
  FilterDropdown,
1437
1467
  {
1438
1468
  label: "Branch",
@@ -1450,7 +1480,7 @@ function HistoryButton({
1450
1480
  }
1451
1481
  )
1452
1482
  ] }),
1453
- loading ? /* @__PURE__ */ jsx(
1483
+ loading ? /* @__PURE__ */ jsx2(
1454
1484
  "div",
1455
1485
  {
1456
1486
  style: {
@@ -1461,7 +1491,7 @@ function HistoryButton({
1461
1491
  },
1462
1492
  children: "Loading..."
1463
1493
  }
1464
- ) : screenshots.length === 0 ? /* @__PURE__ */ jsx(
1494
+ ) : screenshots.length === 0 ? /* @__PURE__ */ jsx2(
1465
1495
  "div",
1466
1496
  {
1467
1497
  style: {
@@ -1472,8 +1502,8 @@ function HistoryButton({
1472
1502
  },
1473
1503
  children: "No screenshots yet"
1474
1504
  }
1475
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1476
- /* @__PURE__ */ jsx(
1505
+ ) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
1506
+ /* @__PURE__ */ jsx2(
1477
1507
  "div",
1478
1508
  {
1479
1509
  style: {
@@ -1486,7 +1516,7 @@ function HistoryButton({
1486
1516
  children: screenshots.map((shot) => {
1487
1517
  const imgUrl = `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(shot.filename)}`;
1488
1518
  const isEditing = editingFile === shot.filename;
1489
- return /* @__PURE__ */ jsxs(
1519
+ return /* @__PURE__ */ jsxs2(
1490
1520
  "div",
1491
1521
  {
1492
1522
  style: {
@@ -1495,7 +1525,7 @@ function HistoryButton({
1495
1525
  alignItems: "center"
1496
1526
  },
1497
1527
  children: [
1498
- /* @__PURE__ */ jsxs(
1528
+ /* @__PURE__ */ jsxs2(
1499
1529
  "div",
1500
1530
  {
1501
1531
  style: {
@@ -1511,7 +1541,7 @@ function HistoryButton({
1511
1541
  onMouseLeave: () => setHoveredThumb(null),
1512
1542
  onClick: () => setLightboxSrc(imgUrl),
1513
1543
  children: [
1514
- /* @__PURE__ */ jsx(
1544
+ /* @__PURE__ */ jsx2(
1515
1545
  "img",
1516
1546
  {
1517
1547
  src: imgUrl,
@@ -1527,7 +1557,7 @@ function HistoryButton({
1527
1557
  }
1528
1558
  }
1529
1559
  ),
1530
- /* @__PURE__ */ jsx(
1560
+ /* @__PURE__ */ jsx2(
1531
1561
  "div",
1532
1562
  {
1533
1563
  style: {
@@ -1541,13 +1571,13 @@ function HistoryButton({
1541
1571
  opacity: hoveredThumb === shot.filename ? 1 : 0,
1542
1572
  transition: "opacity 0.15s ease"
1543
1573
  },
1544
- children: /* @__PURE__ */ jsx(Eye, { size: 16, strokeWidth: 1.8, color: "rgba(255, 255, 255, 0.9)" })
1574
+ children: /* @__PURE__ */ jsx2(Eye, { size: 16, strokeWidth: 1.8, color: "rgba(255, 255, 255, 0.9)" })
1545
1575
  }
1546
1576
  )
1547
1577
  ]
1548
1578
  }
1549
1579
  ),
1550
- /* @__PURE__ */ jsx("div", { style: { flex: 1, minWidth: 0 }, children: isEditing ? /* @__PURE__ */ jsx(
1580
+ /* @__PURE__ */ jsx2("div", { style: { flex: 1, minWidth: 0 }, children: isEditing ? /* @__PURE__ */ jsx2(
1551
1581
  "input",
1552
1582
  {
1553
1583
  autoFocus: true,
@@ -1570,7 +1600,7 @@ function HistoryButton({
1570
1600
  fontFamily: "inherit"
1571
1601
  }
1572
1602
  }
1573
- ) : /* @__PURE__ */ jsx(
1603
+ ) : /* @__PURE__ */ jsx2(
1574
1604
  "div",
1575
1605
  {
1576
1606
  onClick: () => {
@@ -1589,7 +1619,7 @@ function HistoryButton({
1589
1619
  children: formatTimestamp(shot.filename)
1590
1620
  }
1591
1621
  ) }),
1592
- /* @__PURE__ */ jsx(
1622
+ /* @__PURE__ */ jsx2(
1593
1623
  "button",
1594
1624
  {
1595
1625
  onClick: () => handleDelete(shot.filename),
@@ -1616,7 +1646,7 @@ function HistoryButton({
1616
1646
  e.currentTarget.style.color = "rgba(255, 255, 255, 0.35)";
1617
1647
  e.currentTarget.style.background = "transparent";
1618
1648
  },
1619
- children: /* @__PURE__ */ jsx(Trash2, { size: 13, strokeWidth: 1.8 })
1649
+ children: /* @__PURE__ */ jsx2(Trash22, { size: 13, strokeWidth: 1.8 })
1620
1650
  }
1621
1651
  )
1622
1652
  ]
@@ -1626,7 +1656,7 @@ function HistoryButton({
1626
1656
  })
1627
1657
  }
1628
1658
  ),
1629
- /* @__PURE__ */ jsx(
1659
+ /* @__PURE__ */ jsx2(
1630
1660
  "div",
1631
1661
  {
1632
1662
  style: {
@@ -1636,18 +1666,18 @@ function HistoryButton({
1636
1666
  }
1637
1667
  }
1638
1668
  ),
1639
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
1640
- /* @__PURE__ */ jsxs(ActionButton, { onClick: handleOpenFolder, children: [
1641
- /* @__PURE__ */ jsx(FolderOpen, { size: 13, strokeWidth: 1.8 }),
1669
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
1670
+ /* @__PURE__ */ jsxs2(ActionButton, { onClick: handleOpenFolder, children: [
1671
+ /* @__PURE__ */ jsx2(FolderOpen, { size: 13, strokeWidth: 1.8 }),
1642
1672
  "Open Folder"
1643
1673
  ] }),
1644
- /* @__PURE__ */ jsxs(ActionButton, { onClick: handlePush, disabled: pushing, children: [
1645
- /* @__PURE__ */ jsx(ArrowUp, { size: 13, strokeWidth: 1.8 }),
1674
+ /* @__PURE__ */ jsxs2(ActionButton, { onClick: handlePush, disabled: pushing, children: [
1675
+ /* @__PURE__ */ jsx2(ArrowUp, { size: 13, strokeWidth: 1.8 }),
1646
1676
  pushing ? "Pushing..." : "Push to PR"
1647
1677
  ] })
1648
1678
  ] })
1649
1679
  ] }),
1650
- toast && /* @__PURE__ */ jsx(
1680
+ toast && /* @__PURE__ */ jsx2(
1651
1681
  "div",
1652
1682
  {
1653
1683
  style: {
@@ -1671,7 +1701,7 @@ function HistoryButton({
1671
1701
  ]
1672
1702
  }
1673
1703
  ),
1674
- lightboxSrc && /* @__PURE__ */ jsxs(
1704
+ lightboxSrc && /* @__PURE__ */ jsxs2(
1675
1705
  "div",
1676
1706
  {
1677
1707
  onClick: () => setLightboxSrc(null),
@@ -1690,7 +1720,7 @@ function HistoryButton({
1690
1720
  cursor: "zoom-out"
1691
1721
  },
1692
1722
  children: [
1693
- /* @__PURE__ */ jsx(
1723
+ /* @__PURE__ */ jsx2(
1694
1724
  "img",
1695
1725
  {
1696
1726
  src: lightboxSrc,
@@ -1705,7 +1735,7 @@ function HistoryButton({
1705
1735
  }
1706
1736
  }
1707
1737
  ),
1708
- /* @__PURE__ */ jsx(
1738
+ /* @__PURE__ */ jsx2(
1709
1739
  "button",
1710
1740
  {
1711
1741
  onClick: () => setLightboxSrc(null),
@@ -1725,7 +1755,7 @@ function HistoryButton({
1725
1755
  justifyContent: "center",
1726
1756
  padding: 0
1727
1757
  },
1728
- children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2 })
1758
+ children: /* @__PURE__ */ jsx2(X2, { size: 18, strokeWidth: 2 })
1729
1759
  }
1730
1760
  )
1731
1761
  ]
@@ -1741,8 +1771,8 @@ function FilterDropdown({
1741
1771
  onToggle,
1742
1772
  onSelect
1743
1773
  }) {
1744
- return /* @__PURE__ */ jsxs("div", { children: [
1745
- /* @__PURE__ */ jsx(
1774
+ return /* @__PURE__ */ jsxs2("div", { children: [
1775
+ /* @__PURE__ */ jsx2(
1746
1776
  "div",
1747
1777
  {
1748
1778
  style: {
@@ -1754,8 +1784,8 @@ function FilterDropdown({
1754
1784
  children: label
1755
1785
  }
1756
1786
  ),
1757
- /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
1758
- /* @__PURE__ */ jsxs(
1787
+ /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1788
+ /* @__PURE__ */ jsxs2(
1759
1789
  "button",
1760
1790
  {
1761
1791
  onClick: onToggle,
@@ -1776,7 +1806,7 @@ function FilterDropdown({
1776
1806
  fontFamily: "inherit"
1777
1807
  },
1778
1808
  children: [
1779
- /* @__PURE__ */ jsx(
1809
+ /* @__PURE__ */ jsx2(
1780
1810
  "span",
1781
1811
  {
1782
1812
  style: {
@@ -1787,11 +1817,11 @@ function FilterDropdown({
1787
1817
  children: value || "\u2014"
1788
1818
  }
1789
1819
  ),
1790
- /* @__PURE__ */ jsx(ChevronDown, { size: 12, strokeWidth: 2 })
1820
+ /* @__PURE__ */ jsx2(ChevronDown2, { size: 12, strokeWidth: 2 })
1791
1821
  ]
1792
1822
  }
1793
1823
  ),
1794
- isOpen && options.length > 0 && /* @__PURE__ */ jsx(
1824
+ isOpen && options.length > 0 && /* @__PURE__ */ jsx2(
1795
1825
  "div",
1796
1826
  {
1797
1827
  style: {
@@ -1808,8 +1838,8 @@ function FilterDropdown({
1808
1838
  boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
1809
1839
  zIndex: 1
1810
1840
  },
1811
- children: options.map((opt) => /* @__PURE__ */ jsx(
1812
- DropItem,
1841
+ children: options.map((opt) => /* @__PURE__ */ jsx2(
1842
+ DropItem2,
1813
1843
  {
1814
1844
  active: opt === value,
1815
1845
  onClick: () => onSelect(opt),
@@ -1827,8 +1857,8 @@ function ActionButton({
1827
1857
  onClick,
1828
1858
  disabled
1829
1859
  }) {
1830
- const [hovered, setHovered] = useState2(false);
1831
- return /* @__PURE__ */ jsx(
1860
+ const [hovered, setHovered] = useState3(false);
1861
+ return /* @__PURE__ */ jsx2(
1832
1862
  "button",
1833
1863
  {
1834
1864
  onClick,
@@ -1870,13 +1900,13 @@ function formatTimestamp(filename) {
1870
1900
  }
1871
1901
 
1872
1902
  // src/overlay/ui/inspector.tsx
1873
- import { useEffect as useEffect2, useRef as useRef2, useCallback as useCallback3, useState as useState3 } from "react";
1874
- import { jsx as jsx2 } from "react/jsx-runtime";
1903
+ import { useEffect as useEffect3, useRef as useRef3, useCallback as useCallback3, useState as useState4 } from "react";
1904
+ import { jsx as jsx3 } from "react/jsx-runtime";
1875
1905
  function Inspector({ onSelect, onCancel }) {
1876
- const [highlight, setHighlight] = useState3(null);
1877
- const hoveredEl = useRef2(null);
1878
- const styleEl = useRef2(null);
1879
- useEffect2(() => {
1906
+ const [highlight, setHighlight] = useState4(null);
1907
+ const hoveredEl = useRef3(null);
1908
+ const styleEl = useRef3(null);
1909
+ useEffect3(() => {
1880
1910
  const style = document.createElement("style");
1881
1911
  style.setAttribute("data-afterbefore", "true");
1882
1912
  style.textContent = [
@@ -1938,7 +1968,7 @@ function Inspector({ onSelect, onCancel }) {
1938
1968
  },
1939
1969
  [onCancel]
1940
1970
  );
1941
- useEffect2(() => {
1971
+ useEffect3(() => {
1942
1972
  document.addEventListener("mousemove", handleMouseMove, true);
1943
1973
  document.addEventListener("click", handleClick, true);
1944
1974
  document.addEventListener("keydown", handleKeyDown);
@@ -1948,7 +1978,7 @@ function Inspector({ onSelect, onCancel }) {
1948
1978
  document.removeEventListener("keydown", handleKeyDown);
1949
1979
  };
1950
1980
  }, [handleMouseMove, handleClick, handleKeyDown]);
1951
- return /* @__PURE__ */ jsx2("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: highlight && /* @__PURE__ */ jsx2(
1981
+ return /* @__PURE__ */ jsx3("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: highlight && /* @__PURE__ */ jsx3(
1952
1982
  "div",
1953
1983
  {
1954
1984
  style: {
@@ -1968,7 +1998,7 @@ function Inspector({ onSelect, onCancel }) {
1968
1998
  }
1969
1999
 
1970
2000
  // src/overlay/index.tsx
1971
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2001
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1972
2002
  async function saveCapture(mode, dataUrl) {
1973
2003
  try {
1974
2004
  const res = await fetch("/__afterbefore/save", {
@@ -1986,12 +2016,12 @@ async function saveCapture(mode, dataUrl) {
1986
2016
  }
1987
2017
  function AfterBefore() {
1988
2018
  const { state, captureComplete, reset } = useOverlayState();
1989
- const [toolbarActive, setToolbarActive] = useState4(false);
1990
- const [inspectorActive, setInspectorActive] = useState4(false);
1991
- const [loading, setLoading] = useState4(false);
1992
- const [selectedMode, setSelectedMode] = useState4("component");
1993
- const [frameSettings, setFrameSettings] = useState4(DEFAULT_FRAME_SETTINGS);
1994
- useEffect3(() => {
2019
+ const [toolbarActive, setToolbarActive] = useState5(false);
2020
+ const [inspectorActive, setInspectorActive] = useState5(false);
2021
+ const [loading, setLoading] = useState5(false);
2022
+ const [selectedMode, setSelectedMode] = useState5("component");
2023
+ const [frameSettings, setFrameSettings] = useState5(DEFAULT_FRAME_SETTINGS);
2024
+ useEffect4(() => {
1995
2025
  try {
1996
2026
  const stored = localStorage.getItem("ab-frame-settings");
1997
2027
  if (stored) {
@@ -2006,7 +2036,7 @@ function AfterBefore() {
2006
2036
  setFrameSettings(DEFAULT_FRAME_SETTINGS);
2007
2037
  }
2008
2038
  }, []);
2009
- useEffect3(() => {
2039
+ useEffect4(() => {
2010
2040
  if (state.phase === "ready") {
2011
2041
  const timer = setTimeout(() => {
2012
2042
  reset();
@@ -2092,8 +2122,8 @@ function AfterBefore() {
2092
2122
  setSelectedMode(mode);
2093
2123
  setInspectorActive(mode === "component");
2094
2124
  }, []);
2095
- return /* @__PURE__ */ jsxs2("div", { "data-afterbefore": "true", children: [
2096
- /* @__PURE__ */ jsx3(
2125
+ return /* @__PURE__ */ jsxs3("div", { "data-afterbefore": "true", children: [
2126
+ /* @__PURE__ */ jsx4(
2097
2127
  Toolbar,
2098
2128
  {
2099
2129
  expanded: toolbarActive,
@@ -2108,7 +2138,7 @@ function AfterBefore() {
2108
2138
  onFrameSettingsChange: handleFrameSettingsChange
2109
2139
  }
2110
2140
  ),
2111
- inspectorActive && /* @__PURE__ */ jsx3(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel })
2141
+ inspectorActive && /* @__PURE__ */ jsx4(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel })
2112
2142
  ] });
2113
2143
  }
2114
2144
  export {