afterbefore 0.2.15 → 0.2.17

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 useState5, useCallback as useCallback5, useRef as useRef4, useEffect as useEffect4 } from "react";
4
+ import { useState as useState4, useCallback as useCallback4, useEffect as useEffect3 } from "react";
5
5
 
6
6
  // src/overlay/state.ts
7
7
  import { useState, useCallback } from "react";
@@ -34,10 +34,10 @@ var DEFAULT_FRAME_SETTINGS = {
34
34
  padding: 40
35
35
  };
36
36
  var FRAME_SIZE_PRESETS = [
37
- { label: "1920 x 1080", w: 1920, h: 1080 },
38
- { label: "1080 x 1080", w: 1080, h: 1080 },
39
- { label: "1200 x 630", w: 1200, h: 630 },
40
- { label: "1080 x 1920", w: 1080, h: 1920 }
37
+ { label: "1920 x 1080", hint: "Desktop / HD", w: 1920, h: 1080 },
38
+ { label: "1080 x 1080", hint: "Social square", w: 1080, h: 1080 },
39
+ { label: "1200 x 630", hint: "Open Graph / link preview", w: 1200, h: 630 },
40
+ { label: "1080 x 1920", hint: "Story / portrait", w: 1080, h: 1920 }
41
41
  ];
42
42
  var DEV_UI_SELECTORS = [
43
43
  // Afterbefore overlay
@@ -177,48 +177,131 @@ function loadImage(src) {
177
177
  });
178
178
  }
179
179
 
180
- // src/overlay/ui/icon.tsx
181
- import { useRef, useCallback as useCallback2, useEffect, useState as useState2 } from "react";
182
- import { Camera, Check, LoaderCircle } from "lucide-react";
183
- import { jsx, jsxs } from "react/jsx-runtime";
184
- var CONTAINER_SIZE = 38;
185
- var ICON_SIZE = CONTAINER_SIZE;
180
+ // src/overlay/ui/toolbar.tsx
181
+ import { useCallback as useCallback2, useEffect, useRef, useState as useState2 } from "react";
182
+ import {
183
+ ArrowUp,
184
+ Camera,
185
+ Check,
186
+ ChevronDown,
187
+ Clock,
188
+ Eye,
189
+ FolderOpen,
190
+ Frame,
191
+ ImageIcon,
192
+ LoaderCircle,
193
+ Maximize,
194
+ Monitor,
195
+ MousePointer2,
196
+ Palette,
197
+ Settings,
198
+ Trash2,
199
+ Upload,
200
+ X
201
+ } from "lucide-react";
202
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
186
203
  var EDGE_MARGIN = 24;
187
- function Icon({ phase, onClick, loading, onPositionChange }) {
188
- const ref = useRef(null);
189
- const [pos, setPos] = useState2({ x: -1, y: -1 });
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,
241
+ selectedMode,
242
+ onModeChange,
243
+ onCapture,
244
+ onCancel,
245
+ frameSettings,
246
+ onFrameSettingsChange
247
+ }) {
248
+ const [settingsOpen, setSettingsOpen] = useState2(false);
249
+ const [historyOpen, setHistoryOpen] = useState2(false);
250
+ const [corner, setCorner] = useState2(() => {
251
+ 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;
255
+ }
256
+ } catch {
257
+ }
258
+ return "bottom-right";
259
+ });
190
260
  const [dragging, setDragging] = useState2(false);
261
+ const [dragPos, setDragPos] = useState2(null);
191
262
  const dragState = useRef(null);
263
+ const toolbarRef = useRef(null);
264
+ const [cameraHovered, setCameraHovered] = useState2(false);
192
265
  useEffect(() => {
193
- setPos((prev) => {
194
- if (prev.x === -1 || prev.y === -1) {
195
- return {
196
- x: window.innerWidth - ICON_SIZE - EDGE_MARGIN,
197
- y: window.innerHeight - ICON_SIZE - EDGE_MARGIN
198
- };
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;
199
273
  }
200
- return prev;
201
- });
202
- }, []);
203
- useEffect(() => {
204
- if (pos.x !== -1 && pos.y !== -1) {
205
- onPositionChange?.({ x: pos.x, y: pos.y });
206
- }
207
- }, [pos, onPositionChange]);
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]);
208
287
  const handleMouseDown = useCallback2(
209
288
  (e) => {
210
289
  e.preventDefault();
290
+ const el = toolbarRef.current;
291
+ if (!el) return;
292
+ const rect = el.getBoundingClientRect();
211
293
  setDragging(true);
294
+ setDragPos({ x: rect.left, y: rect.top });
212
295
  dragState.current = {
213
296
  dragging: true,
214
297
  startX: e.clientX,
215
298
  startY: e.clientY,
216
- origX: pos.x,
217
- origY: pos.y,
299
+ origX: rect.left,
300
+ origY: rect.top,
218
301
  distance: 0
219
302
  };
220
303
  },
221
- [pos]
304
+ []
222
305
  );
223
306
  useEffect(() => {
224
307
  const handleMouseMove = (e) => {
@@ -227,23 +310,31 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
227
310
  const dx = e.clientX - ds.startX;
228
311
  const dy = e.clientY - ds.startY;
229
312
  ds.distance = Math.sqrt(dx * dx + dy * dy);
230
- const newX = Math.max(
231
- 0,
232
- Math.min(window.innerWidth - ICON_SIZE, ds.origX + dx)
233
- );
234
- const newY = Math.max(
235
- 0,
236
- Math.min(window.innerHeight - ICON_SIZE, ds.origY + dy)
237
- );
238
- setPos({ x: newX, y: newY });
313
+ setDragPos({
314
+ x: ds.origX + dx,
315
+ y: ds.origY + dy
316
+ });
239
317
  };
240
- const handleMouseUp = () => {
318
+ const handleMouseUp = (e) => {
241
319
  const ds = dragState.current;
242
320
  if (!ds) return;
243
321
  if (ds.distance < 5) {
244
- onClick();
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
+ }
245
335
  }
246
336
  setDragging(false);
337
+ setDragPos(null);
247
338
  dragState.current = null;
248
339
  };
249
340
  window.addEventListener("mousemove", handleMouseMove);
@@ -252,39 +343,27 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
252
343
  window.removeEventListener("mousemove", handleMouseMove);
253
344
  window.removeEventListener("mouseup", handleMouseUp);
254
345
  };
255
- }, [onClick]);
256
- if (pos.x === -1 || pos.y === -1) return null;
257
- return /* @__PURE__ */ jsxs(
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(
258
352
  "div",
259
353
  {
260
- ref,
261
- "data-afterbefore": "true",
262
354
  onMouseDown: handleMouseDown,
355
+ onMouseEnter: () => setCameraHovered(true),
356
+ onMouseLeave: () => setCameraHovered(false),
263
357
  style: {
264
- position: "fixed",
265
- left: pos.x,
266
- top: pos.y,
267
- width: CONTAINER_SIZE,
268
- height: CONTAINER_SIZE,
358
+ width: 32,
359
+ height: 32,
269
360
  borderRadius: "50%",
270
- background: "rgba(32, 32, 36, 0.92)",
271
- backdropFilter: "blur(20px)",
272
- WebkitBackdropFilter: "blur(20px)",
273
- border: "none",
274
361
  display: "flex",
275
362
  alignItems: "center",
276
363
  justifyContent: "center",
277
364
  cursor: dragging ? "grabbing" : "pointer",
278
- zIndex: 2147483647,
279
- boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
280
- transition: "background 0.15s",
281
- userSelect: "none"
282
- },
283
- onMouseEnter: (e) => {
284
- e.currentTarget.style.background = "rgba(32, 32, 36, 0.98)";
285
- },
286
- onMouseLeave: (e) => {
287
- e.currentTarget.style.background = "rgba(32, 32, 36, 0.92)";
365
+ background: cameraHovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
366
+ transition: "background 0.12s ease"
288
367
  },
289
368
  children: [
290
369
  /* @__PURE__ */ jsx(
@@ -306,218 +385,136 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
306
385
  strokeWidth: 2,
307
386
  style: { animation: "ab-spin 0.8s linear infinite", color: "white" }
308
387
  }
309
- ) : phase === "ready" ? /* @__PURE__ */ jsx(Check, { size: 16, strokeWidth: 2.6, color: "#4ade80" }) : /* @__PURE__ */ jsx(Camera, { size: 16, strokeWidth: 1.9, color: "white" })
388
+ ) : phase === "ready" ? /* @__PURE__ */ jsx(Check, { size: 16, strokeWidth: 2.6, color: "#4ade80" }) : /* @__PURE__ */ jsx(
389
+ Camera,
390
+ {
391
+ size: 16,
392
+ strokeWidth: 1.9,
393
+ color: cameraHovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)"
394
+ }
395
+ )
310
396
  ]
311
397
  }
312
398
  );
313
- }
314
-
315
- // src/overlay/ui/preview.tsx
316
- import { jsx as jsx2 } from "react/jsx-runtime";
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`;
318
- function CapturePreview({ mode, onClick }) {
319
- if (mode === "viewport" || mode === "fullpage") {
320
- return /* @__PURE__ */ jsx2(
321
- "div",
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,
322
403
  {
323
- "data-afterbefore": "true",
324
- onClick,
325
- style: {
326
- position: "fixed",
327
- inset: 0,
328
- zIndex: 2147483645,
329
- cursor: CAMERA_CURSOR,
330
- background: "rgba(59, 130, 246, 0.15)"
331
- }
332
- }
333
- );
334
- }
335
- return null;
336
- }
337
-
338
- // src/overlay/ui/toolbar.tsx
339
- import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
340
- import {
341
- ArrowUp,
342
- ChevronDown,
343
- Clock,
344
- Copy,
345
- Maximize,
346
- FolderOpen,
347
- Frame,
348
- ImageIcon,
349
- Monitor,
350
- MousePointer2,
351
- Palette,
352
- Settings,
353
- Trash2,
354
- Upload,
355
- X
356
- } from "lucide-react";
357
- import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
358
- var MODES = [
359
- { mode: "component", label: "Capture Component", icon: MousePointer2 },
360
- { mode: "viewport", label: "Capture Viewport", icon: Monitor },
361
- { mode: "fullpage", label: "Capture Full Page", icon: Maximize }
362
- ];
363
- function Toolbar({
364
- selectedMode,
365
- onModeChange,
366
- onCapture,
367
- onCancel,
368
- frameSettings,
369
- onFrameSettingsChange
370
- }) {
371
- const [settingsOpen, setSettingsOpen] = useState3(false);
372
- const [historyOpen, setHistoryOpen] = useState3(false);
373
- useEffect2(() => {
374
- const onKey = (e) => {
375
- if (e.target?.tagName === "INPUT") {
376
- if (e.key === "Escape") {
377
- e.target.blur();
378
- }
379
- return;
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 }),
422
+ /* @__PURE__ */ jsx(
423
+ SettingsButton,
424
+ {
425
+ open: settingsOpen,
426
+ onClick: () => {
427
+ setSettingsOpen((prev) => !prev);
428
+ setHistoryOpen(false);
429
+ },
430
+ selectedMode,
431
+ frameSettings,
432
+ onFrameSettingsChange,
433
+ panelSide,
434
+ tooltipSide
380
435
  }
381
- if (e.key === "Escape") {
382
- if (settingsOpen) {
436
+ ),
437
+ /* @__PURE__ */ jsx(
438
+ HistoryButton,
439
+ {
440
+ open: historyOpen,
441
+ onClick: () => {
442
+ setHistoryOpen((prev) => !prev);
383
443
  setSettingsOpen(false);
384
- return;
385
- }
386
- onCancel();
387
- } else if (e.key === "Enter") {
388
- onCapture(selectedMode);
444
+ },
445
+ panelSide,
446
+ tooltipSide
389
447
  }
390
- };
391
- document.addEventListener("keydown", onKey);
392
- return () => document.removeEventListener("keydown", onKey);
393
- }, [onCancel, onCapture, selectedMode, settingsOpen]);
394
- return /* @__PURE__ */ jsx3(
448
+ ),
449
+ /* @__PURE__ */ jsx(Separator, { vertical: false })
450
+ ] }) : null;
451
+ return /* @__PURE__ */ jsx(
395
452
  "div",
396
453
  {
454
+ ref: toolbarRef,
397
455
  "data-afterbefore": "true",
398
456
  style: {
399
457
  position: "fixed",
400
- bottom: 48,
401
- left: "50%",
402
- transform: "translateX(-50%)",
458
+ ...positionStyle,
403
459
  zIndex: 2147483647,
404
460
  display: "flex",
461
+ flexDirection: "column",
405
462
  alignItems: "center",
406
- gap: 10,
407
- flexWrap: "wrap",
408
- justifyContent: "center",
409
- maxWidth: "min(calc(100vw - 32px), 1120px)",
410
- background: "rgba(32, 32, 36, 0.92)",
411
- backdropFilter: "blur(20px)",
412
- WebkitBackdropFilter: "blur(20px)",
413
- border: "none",
463
+ background: "rgb(32, 32, 36)",
414
464
  borderRadius: 999,
415
465
  padding: 6,
416
466
  boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
417
- fontFamily: "system-ui, -apple-system, sans-serif"
467
+ fontFamily: "system-ui, -apple-system, sans-serif",
468
+ userSelect: "none"
418
469
  },
419
- children: /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 0 }, children: [
420
- /* @__PURE__ */ jsx3(CloseButton, { onClick: onCancel }),
421
- /* @__PURE__ */ jsx3("div", { style: { display: "flex", alignItems: "center", gap: 2, padding: "0 4px" }, children: MODES.map(({ mode, label, icon: Icon2 }) => /* @__PURE__ */ jsx3(
422
- ModeButton,
423
- {
424
- label,
425
- selected: selectedMode === mode,
426
- onClick: () => {
427
- setSettingsOpen(false);
428
- setHistoryOpen(false);
429
- onModeChange(mode);
430
- },
431
- children: /* @__PURE__ */ jsx3(Icon2, { size: 16, strokeWidth: 1.7 })
432
- },
433
- mode
434
- )) }),
435
- /* @__PURE__ */ jsx3(Separator, {}),
436
- /* @__PURE__ */ jsx3(
437
- SettingsButton,
438
- {
439
- open: settingsOpen,
440
- onClick: () => {
441
- setSettingsOpen((prev) => !prev);
442
- setHistoryOpen(false);
443
- },
444
- selectedMode,
445
- frameSettings,
446
- onFrameSettingsChange
447
- }
448
- ),
449
- /* @__PURE__ */ jsx3(
450
- HistoryButton,
451
- {
452
- open: historyOpen,
453
- onClick: () => {
454
- setHistoryOpen((prev) => !prev);
455
- setSettingsOpen(false);
456
- }
457
- }
458
- )
470
+ children: bottom ? /* @__PURE__ */ jsxs(Fragment, { children: [
471
+ toolbarButtons,
472
+ cameraButton
473
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
474
+ cameraButton,
475
+ toolbarButtons
459
476
  ] })
460
477
  }
461
478
  );
462
479
  }
463
- function CloseButton({ onClick }) {
464
- const [hovered, setHovered] = useState3(false);
465
- return /* @__PURE__ */ jsx3(
466
- "button",
467
- {
468
- onClick,
469
- onMouseEnter: () => setHovered(true),
470
- onMouseLeave: () => setHovered(false),
471
- style: {
472
- width: 32,
473
- height: 32,
474
- borderRadius: "50%",
475
- border: "none",
476
- background: hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
477
- display: "flex",
478
- alignItems: "center",
479
- justifyContent: "center",
480
- cursor: "pointer",
481
- padding: 0,
482
- color: hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
483
- transition: "background 0.12s ease, color 0.12s ease"
484
- },
485
- children: /* @__PURE__ */ jsx3(X, { size: 16, strokeWidth: 1.7 })
486
- }
487
- );
488
- }
489
- function ModeButton({
480
+ function IconButton({
490
481
  children,
491
- label,
492
- selected,
482
+ active,
483
+ tooltip,
484
+ tooltipSide = "left",
493
485
  onClick
494
486
  }) {
495
- const [hovered, setHovered] = useState3(false);
496
- return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
497
- hovered && /* @__PURE__ */ jsx3(
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(
498
499
  "div",
499
500
  {
500
501
  style: {
501
502
  position: "absolute",
502
- left: "50%",
503
- bottom: "calc(100% + 10px)",
504
- transform: "translateX(-50%)",
505
- background: "rgba(32, 32, 36, 0.96)",
506
- backdropFilter: "blur(20px)",
507
- WebkitBackdropFilter: "blur(20px)",
503
+ ...tooltipStyle,
504
+ background: "rgb(32, 32, 36)",
508
505
  border: "1px solid rgba(255, 255, 255, 0.1)",
509
- borderRadius: 8,
510
- padding: "5px 10px",
506
+ borderRadius: 6,
507
+ padding: "3px 8px",
511
508
  color: "rgba(255, 255, 255, 0.88)",
512
- fontSize: 12,
509
+ fontSize: 11,
513
510
  whiteSpace: "nowrap",
514
511
  boxShadow: "0 8px 28px rgba(0, 0, 0, 0.28)",
515
512
  pointerEvents: "none"
516
513
  },
517
- children: label
514
+ children: tooltip
518
515
  }
519
516
  ),
520
- /* @__PURE__ */ jsx3(
517
+ /* @__PURE__ */ jsx(
521
518
  "button",
522
519
  {
523
520
  onClick,
@@ -528,13 +525,13 @@ function ModeButton({
528
525
  height: 32,
529
526
  borderRadius: "50%",
530
527
  border: "none",
531
- background: selected || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
528
+ background: active || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
532
529
  display: "flex",
533
530
  alignItems: "center",
534
531
  justifyContent: "center",
535
532
  cursor: "pointer",
536
533
  padding: 0,
537
- color: selected || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
534
+ color: active || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
538
535
  transition: "background 0.12s ease, color 0.12s ease"
539
536
  },
540
537
  children
@@ -547,12 +544,13 @@ function SettingsButton({
547
544
  onClick,
548
545
  selectedMode,
549
546
  frameSettings,
550
- onFrameSettingsChange
547
+ onFrameSettingsChange,
548
+ panelSide,
549
+ tooltipSide
551
550
  }) {
552
- const [hovered, setHovered] = useState3(false);
553
- const [saveDir, setSaveDir] = useState3(null);
554
- const [picking, setPicking] = useState3(false);
555
- useEffect2(() => {
551
+ const [saveDir, setSaveDir] = useState2(null);
552
+ const [picking, setPicking] = useState2(false);
553
+ useEffect(() => {
556
554
  if (!open) return;
557
555
  fetch("/__afterbefore/config").then((r) => r.json()).then((data) => setSaveDir(data.saveDir)).catch(() => {
558
556
  });
@@ -576,49 +574,24 @@ function SettingsButton({
576
574
  }
577
575
  };
578
576
  const shortDir = saveDir ? saveDir.replace(/^\/Users\/[^/]+/, "~") : "~/Desktop";
579
- return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
580
- /* @__PURE__ */ jsx3(
581
- "button",
582
- {
583
- onClick,
584
- onMouseEnter: () => setHovered(true),
585
- onMouseLeave: () => setHovered(false),
586
- style: {
587
- width: 32,
588
- height: 32,
589
- borderRadius: "50%",
590
- border: "none",
591
- background: open || hovered ? "rgba(255, 255, 255, 0.12)" : "transparent",
592
- display: "flex",
593
- alignItems: "center",
594
- justifyContent: "center",
595
- cursor: "pointer",
596
- padding: 0,
597
- color: open || hovered ? "rgba(255, 255, 255, 0.96)" : "rgba(255, 255, 255, 0.52)",
598
- transition: "background 0.12s ease, color 0.12s ease"
599
- },
600
- children: /* @__PURE__ */ jsx3(Settings, { size: 16, strokeWidth: 1.7 })
601
- }
602
- ),
603
- open && /* @__PURE__ */ jsxs2(
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(
604
581
  "div",
605
582
  {
606
583
  style: {
607
584
  position: "absolute",
608
- left: "50%",
609
- bottom: "calc(100% + 12px)",
610
- transform: "translateX(-50%)",
585
+ ...panelStyle,
611
586
  minWidth: 260,
612
587
  padding: "10px 12px",
613
588
  borderRadius: 12,
614
- background: "rgba(32, 32, 36, 0.96)",
589
+ background: "rgb(32, 32, 36)",
615
590
  border: "1px solid rgba(255, 255, 255, 0.1)",
616
- boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)",
617
- backdropFilter: "blur(20px)",
618
- WebkitBackdropFilter: "blur(20px)"
591
+ boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)"
619
592
  },
620
593
  children: [
621
- /* @__PURE__ */ jsx3(
594
+ /* @__PURE__ */ jsx(
622
595
  "div",
623
596
  {
624
597
  style: {
@@ -631,25 +604,26 @@ function SettingsButton({
631
604
  children: "Settings"
632
605
  }
633
606
  ),
634
- selectedMode === "component" && /* @__PURE__ */ jsxs2(Fragment, { children: [
635
- /* @__PURE__ */ jsx3(
607
+ selectedMode === "component" && /* @__PURE__ */ jsxs(Fragment, { children: [
608
+ /* @__PURE__ */ jsx(
636
609
  ToggleRow,
637
610
  {
638
- icon: /* @__PURE__ */ jsx3(Frame, { size: 15, strokeWidth: 1.8 }),
611
+ icon: /* @__PURE__ */ jsx(Frame, { size: 15, strokeWidth: 1.8 }),
639
612
  label: "Frame",
613
+ hint: "Wrap component in a sized canvas with background",
640
614
  enabled: frameSettings.enabled,
641
615
  onChange: () => onFrameSettingsChange({ ...frameSettings, enabled: !frameSettings.enabled })
642
616
  }
643
617
  ),
644
- frameSettings.enabled && /* @__PURE__ */ jsxs2("div", { style: { marginTop: 8, display: "flex", flexDirection: "column", gap: 10 }, children: [
645
- /* @__PURE__ */ jsx3(
618
+ frameSettings.enabled && /* @__PURE__ */ jsxs("div", { style: { marginTop: 8, display: "flex", flexDirection: "column", gap: 10 }, children: [
619
+ /* @__PURE__ */ jsx(
646
620
  FrameSizeControl,
647
621
  {
648
622
  size: frameSettings.size,
649
623
  onChange: (size) => onFrameSettingsChange({ ...frameSettings, size })
650
624
  }
651
625
  ),
652
- /* @__PURE__ */ jsx3(
626
+ /* @__PURE__ */ jsx(
653
627
  FrameBackgroundControl,
654
628
  {
655
629
  bgType: frameSettings.bgType,
@@ -661,8 +635,8 @@ function SettingsButton({
661
635
  )
662
636
  ] })
663
637
  ] }),
664
- selectedMode === "component" && /* @__PURE__ */ jsx3("div", { style: { height: 1, background: "rgba(255,255,255,0.08)", margin: "8px 0" } }),
665
- /* @__PURE__ */ jsx3(
638
+ selectedMode === "component" && /* @__PURE__ */ jsx("div", { style: { height: 1, background: "rgba(255,255,255,0.08)", margin: "8px 0" } }),
639
+ /* @__PURE__ */ jsx(
666
640
  SaveLocationRow,
667
641
  {
668
642
  dir: shortDir,
@@ -679,13 +653,13 @@ function FrameSizeControl({
679
653
  size,
680
654
  onChange
681
655
  }) {
682
- const [sizeOpen, setSizeOpen] = useState3(false);
656
+ const [sizeOpen, setSizeOpen] = useState2(false);
683
657
  const currentPreset = FRAME_SIZE_PRESETS.find((p) => p.w === size.w && p.h === size.h);
684
658
  const isCustom = !currentPreset;
685
- return /* @__PURE__ */ jsxs2("div", { children: [
686
- /* @__PURE__ */ jsx3(SettingsLabel, { children: "Size" }),
687
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 4, marginTop: 4 }, children: [
688
- /* @__PURE__ */ jsx3(
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: [
662
+ /* @__PURE__ */ jsx(
689
663
  NumInput,
690
664
  {
691
665
  value: size.w,
@@ -695,8 +669,8 @@ function FrameSizeControl({
695
669
  }
696
670
  }
697
671
  ),
698
- /* @__PURE__ */ jsx3(StaticText, { children: "x" }),
699
- /* @__PURE__ */ jsx3(
672
+ /* @__PURE__ */ jsx(StaticText, { children: "x" }),
673
+ /* @__PURE__ */ jsx(
700
674
  NumInput,
701
675
  {
702
676
  value: size.h,
@@ -707,8 +681,8 @@ function FrameSizeControl({
707
681
  }
708
682
  )
709
683
  ] }),
710
- /* @__PURE__ */ jsxs2("div", { style: { position: "relative", marginTop: 6 }, children: [
711
- /* @__PURE__ */ jsxs2(
684
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", marginTop: 6 }, children: [
685
+ /* @__PURE__ */ jsxs(
712
686
  "button",
713
687
  {
714
688
  onClick: () => setSizeOpen((prev) => !prev),
@@ -730,11 +704,11 @@ function FrameSizeControl({
730
704
  },
731
705
  children: [
732
706
  currentPreset ? currentPreset.label : "Custom",
733
- /* @__PURE__ */ jsx3(ChevronDown, { size: 12, strokeWidth: 2 })
707
+ /* @__PURE__ */ jsx(ChevronDown, { size: 12, strokeWidth: 2 })
734
708
  ]
735
709
  }
736
710
  ),
737
- sizeOpen && /* @__PURE__ */ jsx3(
711
+ sizeOpen && /* @__PURE__ */ jsx(
738
712
  "div",
739
713
  {
740
714
  style: {
@@ -742,16 +716,14 @@ function FrameSizeControl({
742
716
  bottom: "calc(100% + 4px)",
743
717
  left: 0,
744
718
  right: 0,
745
- background: "rgba(32, 32, 36, 0.96)",
719
+ background: "rgb(32, 32, 36)",
746
720
  border: "1px solid rgba(255, 255, 255, 0.1)",
747
721
  borderRadius: 8,
748
722
  padding: "4px 0",
749
723
  boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
750
- backdropFilter: "blur(20px)",
751
- WebkitBackdropFilter: "blur(20px)",
752
724
  zIndex: 1
753
725
  },
754
- children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsx3(
726
+ children: FRAME_SIZE_PRESETS.map((preset) => /* @__PURE__ */ jsxs(
755
727
  DropItem,
756
728
  {
757
729
  active: !isCustom && preset.w === size.w && preset.h === size.h,
@@ -759,7 +731,10 @@ function FrameSizeControl({
759
731
  onChange({ w: preset.w, h: preset.h });
760
732
  setSizeOpen(false);
761
733
  },
762
- children: preset.label
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
+ ]
763
738
  },
764
739
  preset.label
765
740
  ))
@@ -775,7 +750,7 @@ function FrameBackgroundControl({
775
750
  frameSize,
776
751
  onChange
777
752
  }) {
778
- const fileInputRef = useRef2(null);
753
+ const fileInputRef = useRef(null);
779
754
  const handleFileSelect = (e) => {
780
755
  const file = e.target.files?.[0];
781
756
  if (!file) return;
@@ -793,40 +768,40 @@ function FrameBackgroundControl({
793
768
  reader.readAsDataURL(file);
794
769
  e.target.value = "";
795
770
  };
796
- return /* @__PURE__ */ jsxs2("div", { children: [
797
- /* @__PURE__ */ jsx3(SettingsLabel, { children: "Background" }),
798
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 2, marginTop: 4 }, children: [
799
- /* @__PURE__ */ jsxs2(
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(
800
775
  SegmentButton,
801
776
  {
802
777
  active: bgType === "color",
803
778
  onClick: () => onChange({ bgType: "color" }),
804
779
  style: { borderRadius: "6px 0 0 6px" },
805
780
  children: [
806
- /* @__PURE__ */ jsx3(Palette, { size: 12, strokeWidth: 2 }),
781
+ /* @__PURE__ */ jsx(Palette, { size: 12, strokeWidth: 2 }),
807
782
  "Color"
808
783
  ]
809
784
  }
810
785
  ),
811
- /* @__PURE__ */ jsxs2(
786
+ /* @__PURE__ */ jsxs(
812
787
  SegmentButton,
813
788
  {
814
789
  active: bgType === "image",
815
790
  onClick: () => onChange({ bgType: "image" }),
816
791
  style: { borderRadius: "0 6px 6px 0" },
817
792
  children: [
818
- /* @__PURE__ */ jsx3(ImageIcon, { size: 12, strokeWidth: 2 }),
793
+ /* @__PURE__ */ jsx(ImageIcon, { size: 12, strokeWidth: 2 }),
819
794
  "Image"
820
795
  ]
821
796
  }
822
797
  )
823
798
  ] }),
824
- bgType === "color" && /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 }, children: [
825
- /* @__PURE__ */ jsx3(ColorSwatch, { color: bgColor, onChange: (c) => onChange({ bgColor: c }) }),
826
- /* @__PURE__ */ jsx3(HexInput, { value: bgColor, onChange: (c) => onChange({ bgColor: c }) })
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 }) }),
801
+ /* @__PURE__ */ jsx(HexInput, { value: bgColor, onChange: (c) => onChange({ bgColor: c }) })
827
802
  ] }),
828
- bgType === "image" && /* @__PURE__ */ jsxs2("div", { style: { marginTop: 6 }, children: [
829
- /* @__PURE__ */ jsx3(
803
+ bgType === "image" && /* @__PURE__ */ jsxs("div", { style: { marginTop: 6 }, children: [
804
+ /* @__PURE__ */ jsx(
830
805
  "input",
831
806
  {
832
807
  ref: fileInputRef,
@@ -836,8 +811,8 @@ function FrameBackgroundControl({
836
811
  style: { display: "none" }
837
812
  }
838
813
  ),
839
- bgImage ? /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
840
- /* @__PURE__ */ jsx3(
814
+ bgImage ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
815
+ /* @__PURE__ */ jsx(
841
816
  "img",
842
817
  {
843
818
  src: bgImage,
@@ -851,20 +826,20 @@ function FrameBackgroundControl({
851
826
  }
852
827
  }
853
828
  ),
854
- /* @__PURE__ */ jsxs2(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
855
- /* @__PURE__ */ jsx3(Upload, { size: 11, strokeWidth: 2 }),
829
+ /* @__PURE__ */ jsxs(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
830
+ /* @__PURE__ */ jsx(Upload, { size: 11, strokeWidth: 2 }),
856
831
  "Replace"
857
832
  ] }),
858
- /* @__PURE__ */ jsx3(SmallButton, { onClick: () => onChange({ bgImage: null }), children: /* @__PURE__ */ jsx3(Trash2, { size: 11, strokeWidth: 2 }) })
859
- ] }) : /* @__PURE__ */ jsxs2(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
860
- /* @__PURE__ */ jsx3(Upload, { size: 11, strokeWidth: 2 }),
833
+ /* @__PURE__ */ jsx(SmallButton, { onClick: () => onChange({ bgImage: null }), children: /* @__PURE__ */ jsx(Trash2, { size: 11, strokeWidth: 2 }) })
834
+ ] }) : /* @__PURE__ */ jsxs(SmallButton, { onClick: () => fileInputRef.current?.click(), children: [
835
+ /* @__PURE__ */ jsx(Upload, { size: 11, strokeWidth: 2 }),
861
836
  "Upload image"
862
837
  ] })
863
838
  ] })
864
839
  ] });
865
840
  }
866
841
  function SettingsLabel({ children }) {
867
- return /* @__PURE__ */ jsx3(
842
+ return /* @__PURE__ */ jsx(
868
843
  "div",
869
844
  {
870
845
  style: {
@@ -882,7 +857,7 @@ function SegmentButton({
882
857
  onClick,
883
858
  style
884
859
  }) {
885
- return /* @__PURE__ */ jsx3(
860
+ return /* @__PURE__ */ jsx(
886
861
  "button",
887
862
  {
888
863
  onClick,
@@ -909,9 +884,9 @@ function ColorSwatch({
909
884
  color,
910
885
  onChange
911
886
  }) {
912
- const inputRef = useRef2(null);
913
- return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
914
- /* @__PURE__ */ jsx3(
887
+ const inputRef = useRef(null);
888
+ return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
889
+ /* @__PURE__ */ jsx(
915
890
  "button",
916
891
  {
917
892
  onClick: () => inputRef.current?.click(),
@@ -926,7 +901,7 @@ function ColorSwatch({
926
901
  }
927
902
  }
928
903
  ),
929
- /* @__PURE__ */ jsx3(
904
+ /* @__PURE__ */ jsx(
930
905
  "input",
931
906
  {
932
907
  ref: inputRef,
@@ -950,8 +925,8 @@ function SmallButton({
950
925
  children,
951
926
  onClick
952
927
  }) {
953
- const [hovered, setHovered] = useState3(false);
954
- return /* @__PURE__ */ jsx3(
928
+ const [hovered, setHovered] = useState2(false);
929
+ return /* @__PURE__ */ jsx(
955
930
  "button",
956
931
  {
957
932
  onClick,
@@ -996,8 +971,8 @@ function SaveLocationRow({
996
971
  picking,
997
972
  onPick
998
973
  }) {
999
- const [btnHovered, setBtnHovered] = useState3(false);
1000
- return /* @__PURE__ */ jsx3("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: /* @__PURE__ */ jsxs2(
974
+ const [btnHovered, setBtnHovered] = useState2(false);
975
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: /* @__PURE__ */ jsxs(
1001
976
  "div",
1002
977
  {
1003
978
  style: {
@@ -1008,8 +983,8 @@ function SaveLocationRow({
1008
983
  fontSize: 13
1009
984
  },
1010
985
  children: [
1011
- /* @__PURE__ */ jsx3(FolderOpen, { size: 15, strokeWidth: 1.8, style: { flexShrink: 0 } }),
1012
- /* @__PURE__ */ jsx3(
986
+ /* @__PURE__ */ jsx(FolderOpen, { size: 15, strokeWidth: 1.8, style: { flexShrink: 0 } }),
987
+ /* @__PURE__ */ jsx(
1013
988
  "span",
1014
989
  {
1015
990
  style: {
@@ -1023,7 +998,7 @@ function SaveLocationRow({
1023
998
  children: dir
1024
999
  }
1025
1000
  ),
1026
- /* @__PURE__ */ jsx3(
1001
+ /* @__PURE__ */ jsx(
1027
1002
  "button",
1028
1003
  {
1029
1004
  onClick: onPick,
@@ -1052,10 +1027,11 @@ function SaveLocationRow({
1052
1027
  function ToggleRow({
1053
1028
  icon,
1054
1029
  label,
1030
+ hint,
1055
1031
  enabled,
1056
1032
  onChange
1057
1033
  }) {
1058
- return /* @__PURE__ */ jsxs2(
1034
+ return /* @__PURE__ */ jsxs(
1059
1035
  "label",
1060
1036
  {
1061
1037
  style: {
@@ -1066,24 +1042,37 @@ function ToggleRow({
1066
1042
  cursor: "pointer"
1067
1043
  },
1068
1044
  children: [
1069
- /* @__PURE__ */ jsxs2(
1070
- "span",
1071
- {
1072
- style: {
1073
- display: "flex",
1074
- alignItems: "center",
1075
- gap: 8,
1076
- color: "rgba(255, 255, 255, 0.88)",
1077
- fontSize: 13,
1078
- whiteSpace: "nowrap"
1079
- },
1080
- children: [
1081
- icon,
1082
- label
1083
- ]
1084
- }
1085
- ),
1086
- /* @__PURE__ */ jsx3(
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(
1087
1076
  "button",
1088
1077
  {
1089
1078
  type: "button",
@@ -1100,7 +1089,7 @@ function ToggleRow({
1100
1089
  flexShrink: 0,
1101
1090
  transition: "background 0.12s ease"
1102
1091
  },
1103
- children: /* @__PURE__ */ jsx3(
1092
+ children: /* @__PURE__ */ jsx(
1104
1093
  "span",
1105
1094
  {
1106
1095
  style: {
@@ -1125,14 +1114,14 @@ function NumInput({
1125
1114
  value,
1126
1115
  onChange
1127
1116
  }) {
1128
- const [editing, setEditing] = useState3(false);
1129
- const [text, setText] = useState3(String(value));
1130
- useEffect2(() => {
1117
+ const [editing, setEditing] = useState2(false);
1118
+ const [text, setText] = useState2(String(value));
1119
+ useEffect(() => {
1131
1120
  if (!editing) {
1132
1121
  setText(String(value));
1133
1122
  }
1134
1123
  }, [editing, value]);
1135
- return /* @__PURE__ */ jsx3(
1124
+ return /* @__PURE__ */ jsx(
1136
1125
  "input",
1137
1126
  {
1138
1127
  type: "text",
@@ -1170,9 +1159,9 @@ function HexInput({
1170
1159
  value,
1171
1160
  onChange
1172
1161
  }) {
1173
- const [editing, setEditing] = useState3(false);
1174
- const [text, setText] = useState3(value);
1175
- useEffect2(() => {
1162
+ const [editing, setEditing] = useState2(false);
1163
+ const [text, setText] = useState2(value);
1164
+ useEffect(() => {
1176
1165
  if (!editing) {
1177
1166
  setText(value);
1178
1167
  }
@@ -1183,7 +1172,7 @@ function HexInput({
1183
1172
  onChange(hex);
1184
1173
  }
1185
1174
  };
1186
- return /* @__PURE__ */ jsx3(
1175
+ return /* @__PURE__ */ jsx(
1187
1176
  "input",
1188
1177
  {
1189
1178
  type: "text",
@@ -1218,7 +1207,7 @@ function HexInput({
1218
1207
  );
1219
1208
  }
1220
1209
  function StaticText({ children }) {
1221
- return /* @__PURE__ */ jsx3(
1210
+ return /* @__PURE__ */ jsx(
1222
1211
  "span",
1223
1212
  {
1224
1213
  style: {
@@ -1237,7 +1226,7 @@ function DropItem({
1237
1226
  active,
1238
1227
  accent
1239
1228
  }) {
1240
- return /* @__PURE__ */ jsx3(
1229
+ return /* @__PURE__ */ jsx(
1241
1230
  "button",
1242
1231
  {
1243
1232
  onClick,
@@ -1258,7 +1247,7 @@ function DropItem({
1258
1247
  );
1259
1248
  }
1260
1249
  function Separator({ vertical = true }) {
1261
- return /* @__PURE__ */ jsx3(
1250
+ return /* @__PURE__ */ jsx(
1262
1251
  "div",
1263
1252
  {
1264
1253
  style: {
@@ -1273,20 +1262,25 @@ function Separator({ vertical = true }) {
1273
1262
  }
1274
1263
  function HistoryButton({
1275
1264
  open,
1276
- onClick
1265
+ onClick,
1266
+ panelSide,
1267
+ tooltipSide
1277
1268
  }) {
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(() => {
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(() => {
1290
1284
  if (!open) {
1291
1285
  setRepoDropOpen(false);
1292
1286
  setBranchDropOpen(false);
@@ -1305,28 +1299,69 @@ function HistoryButton({
1305
1299
  }).catch(() => {
1306
1300
  }).finally(() => setLoading(false));
1307
1301
  }, [open, selectedRepo, selectedBranch]);
1308
- const showToast = useCallback3((message, type) => {
1302
+ const showToast = useCallback2((message, type) => {
1309
1303
  setToast({ message, type });
1310
1304
  setTimeout(() => setToast(null), 3e3);
1311
1305
  }, []);
1312
1306
  const handleOpenFolder = async () => {
1313
1307
  try {
1314
- const res = await fetch("/__afterbefore/open", { method: "POST" });
1308
+ const body = selectedRepo && selectedBranch ? JSON.stringify({ repo: selectedRepo, branch: selectedBranch }) : void 0;
1309
+ const res = await fetch("/__afterbefore/open", {
1310
+ method: "POST",
1311
+ headers: body ? { "Content-Type": "application/json" } : void 0,
1312
+ body
1313
+ });
1315
1314
  if (!res.ok) throw new Error();
1316
1315
  showToast("Opened folder", "success");
1317
1316
  } catch {
1318
1317
  showToast("Could not open folder", "error");
1319
1318
  }
1320
1319
  };
1321
- const handleCopyMarkdown = async () => {
1320
+ const handleRename = async (oldName, newName) => {
1321
+ if (!newName.trim() || newName.trim() === oldName.replace(/\.png$/, "")) {
1322
+ setEditingFile(null);
1323
+ return;
1324
+ }
1325
+ try {
1326
+ const res = await fetch("/__afterbefore/history/rename", {
1327
+ method: "POST",
1328
+ headers: { "Content-Type": "application/json" },
1329
+ body: JSON.stringify({
1330
+ repo: selectedRepo,
1331
+ branch: selectedBranch,
1332
+ oldName,
1333
+ newName: newName.trim()
1334
+ })
1335
+ });
1336
+ if (!res.ok) throw new Error();
1337
+ const data = await res.json();
1338
+ setScreenshots(
1339
+ (prev) => prev.map(
1340
+ (s) => s.filename === oldName ? { ...s, filename: data.filename, timestamp: data.filename.replace(/\.png$/, "") } : s
1341
+ )
1342
+ );
1343
+ showToast("Renamed", "success");
1344
+ } catch {
1345
+ showToast("Rename failed", "error");
1346
+ }
1347
+ setEditingFile(null);
1348
+ };
1349
+ const handleDelete = async (filename) => {
1322
1350
  try {
1323
- const res = await fetch("/__afterbefore/markdown");
1351
+ const res = await fetch("/__afterbefore/history/delete", {
1352
+ method: "POST",
1353
+ headers: { "Content-Type": "application/json" },
1354
+ body: JSON.stringify({
1355
+ repo: selectedRepo,
1356
+ branch: selectedBranch,
1357
+ file: filename
1358
+ })
1359
+ });
1324
1360
  if (!res.ok) throw new Error();
1325
- const { markdown } = await res.json();
1326
- await navigator.clipboard.writeText(markdown);
1327
- showToast("Copied!", "success");
1361
+ setScreenshots((prev) => prev.filter((s) => s.filename !== filename));
1362
+ showToast("Deleted", "success");
1328
1363
  } catch {
1329
- showToast("Copy failed", "error");
1364
+ showToast("Delete failed", "error");
1330
1365
  }
1331
1366
  };
1332
1367
  const handlePush = async () => {
@@ -1347,73 +1382,25 @@ function HistoryButton({
1347
1382
  setPushing(false);
1348
1383
  }
1349
1384
  };
1350
- return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1351
- hovered && !open && /* @__PURE__ */ jsx3(
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(
1352
1389
  "div",
1353
1390
  {
1354
1391
  style: {
1355
1392
  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%)",
1393
+ ...panelStyle,
1405
1394
  minWidth: 300,
1406
1395
  maxWidth: 360,
1407
1396
  padding: "10px 12px",
1408
1397
  borderRadius: 12,
1409
- background: "rgba(32, 32, 36, 0.96)",
1398
+ background: "rgb(32, 32, 36)",
1410
1399
  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)"
1400
+ boxShadow: "0 14px 36px rgba(0, 0, 0, 0.32)"
1414
1401
  },
1415
1402
  children: [
1416
- /* @__PURE__ */ jsx3(
1403
+ /* @__PURE__ */ jsx(
1417
1404
  "div",
1418
1405
  {
1419
1406
  style: {
@@ -1426,8 +1413,8 @@ function HistoryButton({
1426
1413
  children: "Screenshots"
1427
1414
  }
1428
1415
  ),
1429
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginBottom: 10 }, children: [
1430
- /* @__PURE__ */ jsx3(
1416
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginBottom: 10 }, children: [
1417
+ /* @__PURE__ */ jsx(
1431
1418
  FilterDropdown,
1432
1419
  {
1433
1420
  label: "Project",
@@ -1445,7 +1432,7 @@ function HistoryButton({
1445
1432
  }
1446
1433
  }
1447
1434
  ),
1448
- /* @__PURE__ */ jsx3(
1435
+ /* @__PURE__ */ jsx(
1449
1436
  FilterDropdown,
1450
1437
  {
1451
1438
  label: "Branch",
@@ -1463,7 +1450,7 @@ function HistoryButton({
1463
1450
  }
1464
1451
  )
1465
1452
  ] }),
1466
- loading ? /* @__PURE__ */ jsx3(
1453
+ loading ? /* @__PURE__ */ jsx(
1467
1454
  "div",
1468
1455
  {
1469
1456
  style: {
@@ -1474,7 +1461,7 @@ function HistoryButton({
1474
1461
  },
1475
1462
  children: "Loading..."
1476
1463
  }
1477
- ) : screenshots.length === 0 ? /* @__PURE__ */ jsx3(
1464
+ ) : screenshots.length === 0 ? /* @__PURE__ */ jsx(
1478
1465
  "div",
1479
1466
  {
1480
1467
  style: {
@@ -1485,8 +1472,8 @@ function HistoryButton({
1485
1472
  },
1486
1473
  children: "No screenshots yet"
1487
1474
  }
1488
- ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
1489
- /* @__PURE__ */ jsx3(
1475
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1476
+ /* @__PURE__ */ jsx(
1490
1477
  "div",
1491
1478
  {
1492
1479
  style: {
@@ -1496,48 +1483,150 @@ function HistoryButton({
1496
1483
  flexDirection: "column",
1497
1484
  gap: 8
1498
1485
  },
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)"
1486
+ children: screenshots.map((shot) => {
1487
+ const imgUrl = `/__afterbefore/history/image?repo=${encodeURIComponent(selectedRepo || "")}&branch=${encodeURIComponent(selectedBranch || "")}&file=${encodeURIComponent(shot.filename)}`;
1488
+ const isEditing = editingFile === shot.filename;
1489
+ return /* @__PURE__ */ jsxs(
1490
+ "div",
1491
+ {
1492
+ style: {
1493
+ display: "flex",
1494
+ gap: 10,
1495
+ alignItems: "center"
1496
+ },
1497
+ children: [
1498
+ /* @__PURE__ */ jsxs(
1499
+ "div",
1500
+ {
1501
+ style: {
1502
+ position: "relative",
1503
+ width: 56,
1504
+ height: 36,
1505
+ flexShrink: 0,
1506
+ borderRadius: 4,
1507
+ overflow: "hidden",
1508
+ cursor: "pointer"
1509
+ },
1510
+ onMouseEnter: () => setHoveredThumb(shot.filename),
1511
+ onMouseLeave: () => setHoveredThumb(null),
1512
+ onClick: () => setLightboxSrc(imgUrl),
1513
+ children: [
1514
+ /* @__PURE__ */ jsx(
1515
+ "img",
1516
+ {
1517
+ src: imgUrl,
1518
+ alt: "",
1519
+ style: {
1520
+ width: 56,
1521
+ height: 36,
1522
+ objectFit: "cover",
1523
+ border: "1px solid rgba(255, 255, 255, 0.1)",
1524
+ borderRadius: 4,
1525
+ background: "rgba(255, 255, 255, 0.05)",
1526
+ display: "block"
1527
+ }
1528
+ }
1529
+ ),
1530
+ /* @__PURE__ */ jsx(
1531
+ "div",
1532
+ {
1533
+ style: {
1534
+ position: "absolute",
1535
+ inset: 0,
1536
+ background: "rgba(0, 0, 0, 0.55)",
1537
+ display: "flex",
1538
+ alignItems: "center",
1539
+ justifyContent: "center",
1540
+ borderRadius: 4,
1541
+ opacity: hoveredThumb === shot.filename ? 1 : 0,
1542
+ transition: "opacity 0.15s ease"
1543
+ },
1544
+ children: /* @__PURE__ */ jsx(Eye, { size: 16, strokeWidth: 1.8, color: "rgba(255, 255, 255, 0.9)" })
1545
+ }
1546
+ )
1547
+ ]
1521
1548
  }
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
- ))
1549
+ ),
1550
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minWidth: 0 }, children: isEditing ? /* @__PURE__ */ jsx(
1551
+ "input",
1552
+ {
1553
+ autoFocus: true,
1554
+ value: editValue,
1555
+ onChange: (e) => setEditValue(e.target.value),
1556
+ onKeyDown: (e) => {
1557
+ if (e.key === "Enter") handleRename(shot.filename, editValue);
1558
+ if (e.key === "Escape") setEditingFile(null);
1559
+ },
1560
+ onBlur: () => handleRename(shot.filename, editValue),
1561
+ style: {
1562
+ width: "100%",
1563
+ fontSize: 12,
1564
+ color: "rgba(255, 255, 255, 0.88)",
1565
+ background: "rgba(255, 255, 255, 0.1)",
1566
+ border: "1px solid rgba(255, 255, 255, 0.2)",
1567
+ borderRadius: 4,
1568
+ padding: "2px 6px",
1569
+ outline: "none",
1570
+ fontFamily: "inherit"
1571
+ }
1572
+ }
1573
+ ) : /* @__PURE__ */ jsx(
1574
+ "div",
1575
+ {
1576
+ onClick: () => {
1577
+ setEditingFile(shot.filename);
1578
+ setEditValue(shot.filename.replace(/\.png$/, ""));
1579
+ },
1580
+ style: {
1581
+ fontSize: 12,
1582
+ color: "rgba(255, 255, 255, 0.88)",
1583
+ cursor: "pointer",
1584
+ overflow: "hidden",
1585
+ textOverflow: "ellipsis",
1586
+ whiteSpace: "nowrap"
1587
+ },
1588
+ title: "Click to rename",
1589
+ children: formatTimestamp(shot.filename)
1590
+ }
1591
+ ) }),
1592
+ /* @__PURE__ */ jsx(
1593
+ "button",
1594
+ {
1595
+ onClick: () => handleDelete(shot.filename),
1596
+ title: "Delete screenshot",
1597
+ style: {
1598
+ flexShrink: 0,
1599
+ width: 24,
1600
+ height: 24,
1601
+ borderRadius: 4,
1602
+ border: "none",
1603
+ background: "transparent",
1604
+ color: "rgba(255, 255, 255, 0.35)",
1605
+ cursor: "pointer",
1606
+ display: "flex",
1607
+ alignItems: "center",
1608
+ justifyContent: "center",
1609
+ padding: 0
1610
+ },
1611
+ onMouseEnter: (e) => {
1612
+ e.currentTarget.style.color = "rgba(239, 68, 68, 0.9)";
1613
+ e.currentTarget.style.background = "rgba(239, 68, 68, 0.1)";
1614
+ },
1615
+ onMouseLeave: (e) => {
1616
+ e.currentTarget.style.color = "rgba(255, 255, 255, 0.35)";
1617
+ e.currentTarget.style.background = "transparent";
1618
+ },
1619
+ children: /* @__PURE__ */ jsx(Trash2, { size: 13, strokeWidth: 1.8 })
1620
+ }
1621
+ )
1622
+ ]
1623
+ },
1624
+ shot.filename
1625
+ );
1626
+ })
1538
1627
  }
1539
1628
  ),
1540
- /* @__PURE__ */ jsx3(
1629
+ /* @__PURE__ */ jsx(
1541
1630
  "div",
1542
1631
  {
1543
1632
  style: {
@@ -1547,22 +1636,18 @@ function HistoryButton({
1547
1636
  }
1548
1637
  }
1549
1638
  ),
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 }),
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 }),
1553
1642
  "Open Folder"
1554
1643
  ] }),
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 }),
1644
+ /* @__PURE__ */ jsxs(ActionButton, { onClick: handlePush, disabled: pushing, children: [
1645
+ /* @__PURE__ */ jsx(ArrowUp, { size: 13, strokeWidth: 1.8 }),
1561
1646
  pushing ? "Pushing..." : "Push to PR"
1562
1647
  ] })
1563
1648
  ] })
1564
1649
  ] }),
1565
- toast && /* @__PURE__ */ jsx3(
1650
+ toast && /* @__PURE__ */ jsx(
1566
1651
  "div",
1567
1652
  {
1568
1653
  style: {
@@ -1585,6 +1670,66 @@ function HistoryButton({
1585
1670
  )
1586
1671
  ]
1587
1672
  }
1673
+ ),
1674
+ lightboxSrc && /* @__PURE__ */ jsxs(
1675
+ "div",
1676
+ {
1677
+ onClick: () => setLightboxSrc(null),
1678
+ onKeyDown: (e) => {
1679
+ if (e.key === "Escape") setLightboxSrc(null);
1680
+ },
1681
+ style: {
1682
+ position: "fixed",
1683
+ inset: 0,
1684
+ bottom: 100,
1685
+ zIndex: 2147483646,
1686
+ background: "rgba(0, 0, 0, 0.85)",
1687
+ display: "flex",
1688
+ alignItems: "center",
1689
+ justifyContent: "center",
1690
+ cursor: "zoom-out"
1691
+ },
1692
+ children: [
1693
+ /* @__PURE__ */ jsx(
1694
+ "img",
1695
+ {
1696
+ src: lightboxSrc,
1697
+ alt: "",
1698
+ onClick: (e) => e.stopPropagation(),
1699
+ style: {
1700
+ maxWidth: "90vw",
1701
+ maxHeight: "calc(100% - 32px)",
1702
+ borderRadius: 8,
1703
+ boxShadow: "0 20px 60px rgba(0, 0, 0, 0.5)",
1704
+ cursor: "default"
1705
+ }
1706
+ }
1707
+ ),
1708
+ /* @__PURE__ */ jsx(
1709
+ "button",
1710
+ {
1711
+ onClick: () => setLightboxSrc(null),
1712
+ style: {
1713
+ position: "absolute",
1714
+ top: 16,
1715
+ right: 16,
1716
+ width: 32,
1717
+ height: 32,
1718
+ borderRadius: "50%",
1719
+ border: "none",
1720
+ background: "rgba(255, 255, 255, 0.15)",
1721
+ color: "white",
1722
+ cursor: "pointer",
1723
+ display: "flex",
1724
+ alignItems: "center",
1725
+ justifyContent: "center",
1726
+ padding: 0
1727
+ },
1728
+ children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2 })
1729
+ }
1730
+ )
1731
+ ]
1732
+ }
1588
1733
  )
1589
1734
  ] });
1590
1735
  }
@@ -1596,8 +1741,8 @@ function FilterDropdown({
1596
1741
  onToggle,
1597
1742
  onSelect
1598
1743
  }) {
1599
- return /* @__PURE__ */ jsxs2("div", { children: [
1600
- /* @__PURE__ */ jsx3(
1744
+ return /* @__PURE__ */ jsxs("div", { children: [
1745
+ /* @__PURE__ */ jsx(
1601
1746
  "div",
1602
1747
  {
1603
1748
  style: {
@@ -1609,8 +1754,8 @@ function FilterDropdown({
1609
1754
  children: label
1610
1755
  }
1611
1756
  ),
1612
- /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1613
- /* @__PURE__ */ jsxs2(
1757
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
1758
+ /* @__PURE__ */ jsxs(
1614
1759
  "button",
1615
1760
  {
1616
1761
  onClick: onToggle,
@@ -1631,7 +1776,7 @@ function FilterDropdown({
1631
1776
  fontFamily: "inherit"
1632
1777
  },
1633
1778
  children: [
1634
- /* @__PURE__ */ jsx3(
1779
+ /* @__PURE__ */ jsx(
1635
1780
  "span",
1636
1781
  {
1637
1782
  style: {
@@ -1642,11 +1787,11 @@ function FilterDropdown({
1642
1787
  children: value || "\u2014"
1643
1788
  }
1644
1789
  ),
1645
- /* @__PURE__ */ jsx3(ChevronDown, { size: 12, strokeWidth: 2 })
1790
+ /* @__PURE__ */ jsx(ChevronDown, { size: 12, strokeWidth: 2 })
1646
1791
  ]
1647
1792
  }
1648
1793
  ),
1649
- isOpen && options.length > 0 && /* @__PURE__ */ jsx3(
1794
+ isOpen && options.length > 0 && /* @__PURE__ */ jsx(
1650
1795
  "div",
1651
1796
  {
1652
1797
  style: {
@@ -1656,16 +1801,14 @@ function FilterDropdown({
1656
1801
  right: 0,
1657
1802
  maxHeight: 160,
1658
1803
  overflowY: "auto",
1659
- background: "rgba(32, 32, 36, 0.96)",
1804
+ background: "rgb(32, 32, 36)",
1660
1805
  border: "1px solid rgba(255, 255, 255, 0.1)",
1661
1806
  borderRadius: 8,
1662
1807
  padding: "4px 0",
1663
1808
  boxShadow: "0 10px 30px rgba(0, 0, 0, 0.3)",
1664
- backdropFilter: "blur(20px)",
1665
- WebkitBackdropFilter: "blur(20px)",
1666
1809
  zIndex: 1
1667
1810
  },
1668
- children: options.map((opt) => /* @__PURE__ */ jsx3(
1811
+ children: options.map((opt) => /* @__PURE__ */ jsx(
1669
1812
  DropItem,
1670
1813
  {
1671
1814
  active: opt === value,
@@ -1684,8 +1827,8 @@ function ActionButton({
1684
1827
  onClick,
1685
1828
  disabled
1686
1829
  }) {
1687
- const [hovered, setHovered] = useState3(false);
1688
- return /* @__PURE__ */ jsx3(
1830
+ const [hovered, setHovered] = useState2(false);
1831
+ return /* @__PURE__ */ jsx(
1689
1832
  "button",
1690
1833
  {
1691
1834
  onClick,
@@ -1727,23 +1870,28 @@ function formatTimestamp(filename) {
1727
1870
  }
1728
1871
 
1729
1872
  // 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";
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";
1732
1875
  function Inspector({ onSelect, onCancel }) {
1733
- const [highlight, setHighlight] = useState4(null);
1734
- const hoveredEl = useRef3(null);
1735
- const styleEl = useRef3(null);
1736
- useEffect3(() => {
1876
+ const [highlight, setHighlight] = useState3(null);
1877
+ const hoveredEl = useRef2(null);
1878
+ const styleEl = useRef2(null);
1879
+ useEffect2(() => {
1737
1880
  const style = document.createElement("style");
1738
1881
  style.setAttribute("data-afterbefore", "true");
1739
- style.textContent = ":not([data-afterbefore]):not([data-afterbefore] *) { cursor: crosshair !important; }";
1882
+ style.textContent = [
1883
+ "* { cursor: crosshair !important; }",
1884
+ "[data-afterbefore], [data-afterbefore] * { cursor: auto !important; }",
1885
+ "[data-afterbefore] button, [data-afterbefore] label, [data-afterbefore] a { cursor: pointer !important; }",
1886
+ "[data-afterbefore] input, [data-afterbefore] textarea { cursor: text !important; }"
1887
+ ].join("\n");
1740
1888
  document.head.appendChild(style);
1741
1889
  styleEl.current = style;
1742
1890
  return () => {
1743
1891
  style.remove();
1744
1892
  };
1745
1893
  }, []);
1746
- const isOverlayElement = useCallback4((el) => {
1894
+ const isOverlayElement = useCallback3((el) => {
1747
1895
  let node = el;
1748
1896
  while (node) {
1749
1897
  if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
@@ -1751,7 +1899,7 @@ function Inspector({ onSelect, onCancel }) {
1751
1899
  }
1752
1900
  return false;
1753
1901
  }, []);
1754
- const handleMouseMove = useCallback4(
1902
+ const handleMouseMove = useCallback3(
1755
1903
  (e) => {
1756
1904
  const el = document.elementFromPoint(e.clientX, e.clientY);
1757
1905
  if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {
@@ -1765,13 +1913,12 @@ function Inspector({ onSelect, onCancel }) {
1765
1913
  x: rect.x,
1766
1914
  y: rect.y,
1767
1915
  width: rect.width,
1768
- height: rect.height,
1769
- tag: el.tagName.toLowerCase() + (el.className && typeof el.className === "string" ? `.${el.className.split(" ")[0]}` : "")
1916
+ height: rect.height
1770
1917
  });
1771
1918
  },
1772
1919
  [isOverlayElement]
1773
1920
  );
1774
- const handleClick = useCallback4(
1921
+ const handleClick = useCallback3(
1775
1922
  (e) => {
1776
1923
  if (isOverlayElement(e.target)) return;
1777
1924
  e.preventDefault();
@@ -1783,7 +1930,7 @@ function Inspector({ onSelect, onCancel }) {
1783
1930
  },
1784
1931
  [onSelect, isOverlayElement]
1785
1932
  );
1786
- const handleKeyDown = useCallback4(
1933
+ const handleKeyDown = useCallback3(
1787
1934
  (e) => {
1788
1935
  if (e.key === "Escape") {
1789
1936
  onCancel();
@@ -1791,7 +1938,7 @@ function Inspector({ onSelect, onCancel }) {
1791
1938
  },
1792
1939
  [onCancel]
1793
1940
  );
1794
- useEffect3(() => {
1941
+ useEffect2(() => {
1795
1942
  document.addEventListener("mousemove", handleMouseMove, true);
1796
1943
  document.addEventListener("click", handleClick, true);
1797
1944
  document.addEventListener("keydown", handleKeyDown);
@@ -1801,48 +1948,27 @@ function Inspector({ onSelect, onCancel }) {
1801
1948
  document.removeEventListener("keydown", handleKeyDown);
1802
1949
  };
1803
1950
  }, [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
1951
+ return /* @__PURE__ */ jsx2("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: highlight && /* @__PURE__ */ jsx2(
1952
+ "div",
1953
+ {
1954
+ style: {
1955
+ position: "fixed",
1956
+ left: highlight.x,
1957
+ top: highlight.y,
1958
+ width: highlight.width,
1959
+ height: highlight.height,
1960
+ background: "transparent",
1961
+ border: "1px solid #fff",
1962
+ borderRadius: 2,
1963
+ boxShadow: "0 0 0 9999px rgba(0, 0, 0, 0.5)",
1964
+ pointerEvents: "none"
1839
1965
  }
1840
- )
1841
- ] }) });
1966
+ }
1967
+ ) });
1842
1968
  }
1843
1969
 
1844
1970
  // src/overlay/index.tsx
1845
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1971
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1846
1972
  async function saveCapture(mode, dataUrl) {
1847
1973
  try {
1848
1974
  const res = await fetch("/__afterbefore/save", {
@@ -1860,13 +1986,12 @@ async function saveCapture(mode, dataUrl) {
1860
1986
  }
1861
1987
  function AfterBefore() {
1862
1988
  const { state, captureComplete, reset } = useOverlayState();
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(() => {
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(() => {
1870
1995
  try {
1871
1996
  const stored = localStorage.getItem("ab-frame-settings");
1872
1997
  if (stored) {
@@ -1881,7 +2006,7 @@ function AfterBefore() {
1881
2006
  setFrameSettings(DEFAULT_FRAME_SETTINGS);
1882
2007
  }
1883
2008
  }, []);
1884
- useEffect4(() => {
2009
+ useEffect3(() => {
1885
2010
  if (state.phase === "ready") {
1886
2011
  const timer = setTimeout(() => {
1887
2012
  reset();
@@ -1889,13 +2014,7 @@ function AfterBefore() {
1889
2014
  return () => clearTimeout(timer);
1890
2015
  }
1891
2016
  }, [state.phase, reset]);
1892
- const handlePositionChange = useCallback5(
1893
- (pos) => {
1894
- iconPos.current = pos;
1895
- },
1896
- []
1897
- );
1898
- const handleIconClick = useCallback5(() => {
2017
+ const handleToggle = useCallback4(() => {
1899
2018
  if (loading) return;
1900
2019
  if (state.phase === "ready") {
1901
2020
  reset();
@@ -1913,7 +2032,7 @@ function AfterBefore() {
1913
2032
  }
1914
2033
  }
1915
2034
  }, [state.phase, loading, toolbarActive, inspectorActive, selectedMode, reset]);
1916
- const performCapture = useCallback5(
2035
+ const performCapture = useCallback4(
1917
2036
  async (mode, element) => {
1918
2037
  setLoading(true);
1919
2038
  try {
@@ -1932,7 +2051,7 @@ function AfterBefore() {
1932
2051
  },
1933
2052
  [captureComplete, frameSettings]
1934
2053
  );
1935
- const handleToolbarCapture = useCallback5(
2054
+ const handleToolbarCapture = useCallback4(
1936
2055
  (mode) => {
1937
2056
  if (mode === "viewport") {
1938
2057
  setToolbarActive(false);
@@ -1946,10 +2065,11 @@ function AfterBefore() {
1946
2065
  },
1947
2066
  [performCapture]
1948
2067
  );
1949
- const handleToolbarCancel = useCallback5(() => {
2068
+ const handleToolbarCancel = useCallback4(() => {
1950
2069
  setToolbarActive(false);
2070
+ setInspectorActive(false);
1951
2071
  }, []);
1952
- const handleComponentSelect = useCallback5(
2072
+ const handleComponentSelect = useCallback4(
1953
2073
  (element) => {
1954
2074
  setInspectorActive(false);
1955
2075
  setToolbarActive(false);
@@ -1957,41 +2077,29 @@ function AfterBefore() {
1957
2077
  },
1958
2078
  [performCapture]
1959
2079
  );
1960
- const handleComponentCancel = useCallback5(() => {
2080
+ const handleComponentCancel = useCallback4(() => {
1961
2081
  setInspectorActive(false);
1962
2082
  setToolbarActive(true);
1963
2083
  }, []);
1964
- const handleFrameSettingsChange = useCallback5((next) => {
2084
+ const handleFrameSettingsChange = useCallback4((next) => {
1965
2085
  setFrameSettings(next);
1966
2086
  try {
1967
2087
  localStorage.setItem("ab-frame-settings", JSON.stringify(next));
1968
2088
  } catch {
1969
2089
  }
1970
2090
  }, []);
1971
- const handleModeChange = useCallback5((mode) => {
2091
+ const handleModeChange = useCallback4((mode) => {
1972
2092
  setSelectedMode(mode);
1973
2093
  setInspectorActive(mode === "component");
1974
2094
  }, []);
1975
- return /* @__PURE__ */ jsxs4("div", { "data-afterbefore": "true", children: [
1976
- /* @__PURE__ */ jsx5(
1977
- Icon,
2095
+ return /* @__PURE__ */ jsxs2("div", { "data-afterbefore": "true", children: [
2096
+ /* @__PURE__ */ jsx3(
2097
+ Toolbar,
1978
2098
  {
2099
+ expanded: toolbarActive,
2100
+ onToggle: handleToggle,
1979
2101
  phase: state.phase,
1980
- onClick: handleIconClick,
1981
2102
  loading,
1982
- onPositionChange: handlePositionChange
1983
- }
1984
- ),
1985
- toolbarActive && !inspectorActive && !loading && /* @__PURE__ */ jsx5(
1986
- CapturePreview,
1987
- {
1988
- mode: selectedMode,
1989
- onClick: () => handleToolbarCapture(selectedMode)
1990
- }
1991
- ),
1992
- toolbarActive && /* @__PURE__ */ jsx5(
1993
- Toolbar,
1994
- {
1995
2103
  selectedMode,
1996
2104
  onModeChange: handleModeChange,
1997
2105
  onCapture: handleToolbarCapture,
@@ -2000,7 +2108,7 @@ function AfterBefore() {
2000
2108
  onFrameSettingsChange: handleFrameSettingsChange
2001
2109
  }
2002
2110
  ),
2003
- inspectorActive && /* @__PURE__ */ jsx5(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel })
2111
+ inspectorActive && /* @__PURE__ */ jsx3(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel })
2004
2112
  ] });
2005
2113
  }
2006
2114
  export {