afterbefore 0.2.10 → 0.2.11

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,13 +1,80 @@
1
- // src/server/save.ts
2
- import { NextResponse } from "next/server";
3
- import { writeFile } from "fs/promises";
1
+ // src/server/config.ts
2
+ import { readFile, writeFile, mkdir } from "fs/promises";
4
3
  import { join } from "path";
5
4
  import { homedir } from "os";
5
+ import { NextResponse } from "next/server";
6
6
  import { execFile } from "child_process";
7
7
  import { promisify } from "util";
8
8
  var execFileAsync = promisify(execFile);
9
+ var CONFIG_DIR = join(process.cwd(), ".afterbefore");
10
+ var CONFIG_PATH = join(CONFIG_DIR, "config.json");
11
+ var DEFAULT_SAVE_DIR = join(homedir(), "Desktop");
12
+ async function readConfig() {
13
+ try {
14
+ const raw = await readFile(CONFIG_PATH, "utf-8");
15
+ const parsed = JSON.parse(raw);
16
+ return { saveDir: parsed.saveDir || DEFAULT_SAVE_DIR };
17
+ } catch {
18
+ return { saveDir: DEFAULT_SAVE_DIR };
19
+ }
20
+ }
21
+ async function writeConfig(config) {
22
+ await mkdir(CONFIG_DIR, { recursive: true });
23
+ await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n");
24
+ }
25
+ async function getSaveDir() {
26
+ const config = await readConfig();
27
+ return config.saveDir;
28
+ }
29
+ async function handleGetConfig() {
30
+ const config = await readConfig();
31
+ return NextResponse.json(config);
32
+ }
33
+ async function handleSetConfig(req) {
34
+ let body;
35
+ try {
36
+ body = await req.json();
37
+ } catch {
38
+ return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
39
+ }
40
+ if (typeof body.saveDir !== "string" || body.saveDir.trim() === "") {
41
+ return NextResponse.json({ error: "Invalid saveDir" }, { status: 400 });
42
+ }
43
+ const config = { saveDir: body.saveDir.trim() };
44
+ await writeConfig(config);
45
+ return NextResponse.json(config);
46
+ }
47
+ async function handlePickFolder() {
48
+ if (process.platform !== "darwin") {
49
+ return NextResponse.json(
50
+ { error: "Folder picker is only supported on macOS" },
51
+ { status: 501 }
52
+ );
53
+ }
54
+ try {
55
+ const { stdout } = await execFileAsync("osascript", [
56
+ "-e",
57
+ 'POSIX path of (choose folder with prompt "Select screenshot save location")'
58
+ ]);
59
+ const folder = stdout.trim().replace(/\/$/, "");
60
+ if (!folder) {
61
+ return NextResponse.json({ cancelled: true });
62
+ }
63
+ return NextResponse.json({ folder });
64
+ } catch {
65
+ return NextResponse.json({ cancelled: true });
66
+ }
67
+ }
68
+
69
+ // src/server/save.ts
70
+ import { NextResponse as NextResponse2 } from "next/server";
71
+ import { writeFile as writeFile2 } from "fs/promises";
72
+ import { join as join2 } from "path";
73
+ import { execFile as execFile2 } from "child_process";
74
+ import { promisify as promisify2 } from "util";
75
+ var execFileAsync2 = promisify2(execFile2);
9
76
  async function getBranch() {
10
- const { stdout } = await execFileAsync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
77
+ const { stdout } = await execFileAsync2("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
11
78
  cwd: process.cwd()
12
79
  });
13
80
  return stdout.trim();
@@ -20,26 +87,26 @@ async function handleSave(req) {
20
87
  try {
21
88
  body = await req.json();
22
89
  } catch {
23
- return NextResponse.json(
90
+ return NextResponse2.json(
24
91
  { error: "Invalid JSON body" },
25
92
  { status: 400 }
26
93
  );
27
94
  }
28
95
  const { type, mode, image } = body;
29
96
  if (!VALID_TYPES.includes(type)) {
30
- return NextResponse.json(
97
+ return NextResponse2.json(
31
98
  { error: `Invalid type: must be "before" or "after"` },
32
99
  { status: 400 }
33
100
  );
34
101
  }
35
102
  if (!VALID_MODES.includes(mode)) {
36
- return NextResponse.json(
103
+ return NextResponse2.json(
37
104
  { error: `Invalid mode: must be "fullpage", "viewport", or "area"` },
38
105
  { status: 400 }
39
106
  );
40
107
  }
41
108
  if (typeof image !== "string" || !image.startsWith(DATA_URL_PREFIX)) {
42
- return NextResponse.json(
109
+ return NextResponse2.json(
43
110
  { error: "Invalid image: must be a data:image/png;base64 data URL" },
44
111
  { status: 400 }
45
112
  );
@@ -47,29 +114,29 @@ async function handleSave(req) {
47
114
  const base64 = image.slice(DATA_URL_PREFIX.length);
48
115
  const buffer = Buffer.from(base64, "base64");
49
116
  const branch = await getBranch();
117
+ const saveDir = await getSaveDir();
50
118
  const filename = `${branch}-${type}.png`;
51
- const filepath = join(homedir(), "Desktop", filename);
119
+ const filepath = join2(saveDir, filename);
52
120
  try {
53
- await writeFile(filepath, buffer);
121
+ await writeFile2(filepath, buffer);
54
122
  } catch (err) {
55
- return NextResponse.json(
123
+ return NextResponse2.json(
56
124
  { error: "Failed to write screenshot", detail: String(err) },
57
125
  { status: 500 }
58
126
  );
59
127
  }
60
- return NextResponse.json({ success: true, path: `~/Desktop/${filename}` });
128
+ return NextResponse2.json({ success: true, path: filepath });
61
129
  }
62
130
 
63
131
  // src/server/push.ts
64
- import { NextResponse as NextResponse2 } from "next/server";
65
- import { execFile as execFile2 } from "child_process";
66
- import { access, mkdir, copyFile } from "fs/promises";
67
- import { join as join2 } from "path";
68
- import { homedir as homedir2 } from "os";
69
- import { promisify as promisify2 } from "util";
70
- var execFileAsync2 = promisify2(execFile2);
132
+ import { NextResponse as NextResponse3 } from "next/server";
133
+ import { execFile as execFile3 } from "child_process";
134
+ import { access, mkdir as mkdir2, copyFile } from "fs/promises";
135
+ import { join as join3 } from "path";
136
+ import { promisify as promisify3 } from "util";
137
+ var execFileAsync3 = promisify3(execFile3);
71
138
  async function run(cmd, args) {
72
- return execFileAsync2(cmd, args, { cwd: process.cwd() });
139
+ return execFileAsync3(cmd, args, { cwd: process.cwd() });
73
140
  }
74
141
  async function ghAvailable() {
75
142
  try {
@@ -102,22 +169,22 @@ async function fileExists(path) {
102
169
  }
103
170
  async function handlePush(req) {
104
171
  if (!await ghAvailable()) {
105
- return NextResponse2.json(
172
+ return NextResponse3.json(
106
173
  { success: false, error: "GitHub CLI (gh) is not installed or not in PATH" },
107
174
  { status: 500 }
108
175
  );
109
176
  }
110
177
  const pr = await getPrInfo();
111
178
  if (!pr) {
112
- return NextResponse2.json(
179
+ return NextResponse3.json(
113
180
  { success: false, error: "No PR found for current branch" },
114
181
  { status: 404 }
115
182
  );
116
183
  }
117
- const desktop = join2(homedir2(), "Desktop");
184
+ const desktop = await getSaveDir();
118
185
  const branch = pr.headRefName;
119
- const beforePath = join2(desktop, `${branch}-before.png`);
120
- const afterPath = join2(desktop, `${branch}-after.png`);
186
+ const beforePath = join3(desktop, `${branch}-before.png`);
187
+ const afterPath = join3(desktop, `${branch}-after.png`);
121
188
  const [hasBefore, hasAfter] = await Promise.all([
122
189
  fileExists(beforePath),
123
190
  fileExists(afterPath)
@@ -127,20 +194,20 @@ async function handlePush(req) {
127
194
  !hasBefore && `${branch}-before.png`,
128
195
  !hasAfter && `${branch}-after.png`
129
196
  ].filter(Boolean);
130
- return NextResponse2.json(
197
+ return NextResponse3.json(
131
198
  { success: false, error: `Missing screenshots: ${missing.join(", ")}` },
132
199
  { status: 400 }
133
200
  );
134
201
  }
135
- const repoDir = join2(process.cwd(), ".afterbefore");
136
- const repoBefore = join2(repoDir, `${branch}-before.png`);
137
- const repoAfter = join2(repoDir, `${branch}-after.png`);
202
+ const repoDir = join3(process.cwd(), ".afterbefore");
203
+ const repoBefore = join3(repoDir, `${branch}-before.png`);
204
+ const repoAfter = join3(repoDir, `${branch}-after.png`);
138
205
  try {
139
- await mkdir(repoDir, { recursive: true });
206
+ await mkdir2(repoDir, { recursive: true });
140
207
  await copyFile(beforePath, repoBefore);
141
208
  await copyFile(afterPath, repoAfter);
142
209
  } catch (err) {
143
- return NextResponse2.json(
210
+ return NextResponse3.json(
144
211
  { success: false, error: "Failed to copy screenshots into repo", detail: String(err) },
145
212
  { status: 500 }
146
213
  );
@@ -155,7 +222,7 @@ async function handlePush(req) {
155
222
  } catch (err) {
156
223
  const msg = String(err);
157
224
  if (!msg.includes("nothing to commit")) {
158
- return NextResponse2.json(
225
+ return NextResponse3.json(
159
226
  { success: false, error: "Failed to commit screenshots", detail: msg },
160
227
  { status: 500 }
161
228
  );
@@ -164,7 +231,7 @@ async function handlePush(req) {
164
231
  try {
165
232
  await run("git", ["push"]);
166
233
  } catch (err) {
167
- return NextResponse2.json(
234
+ return NextResponse3.json(
168
235
  { success: false, error: "Failed to push to remote", detail: String(err) },
169
236
  { status: 500 }
170
237
  );
@@ -193,12 +260,12 @@ async function handlePush(req) {
193
260
  ]);
194
261
  commentUrl = stdout.trim() || void 0;
195
262
  } catch (err) {
196
- return NextResponse2.json(
263
+ return NextResponse3.json(
197
264
  { success: false, error: "Failed to post PR comment", detail: String(err) },
198
265
  { status: 500 }
199
266
  );
200
267
  }
201
- return NextResponse2.json({
268
+ return NextResponse3.json({
202
269
  success: true,
203
270
  prNumber: pr.number,
204
271
  prUrl: pr.url,
@@ -207,20 +274,21 @@ async function handlePush(req) {
207
274
  }
208
275
 
209
276
  // src/server/open.ts
210
- import { NextResponse as NextResponse3 } from "next/server";
211
- import { execFile as execFile3 } from "child_process";
212
- import { join as join3 } from "path";
213
- import { homedir as homedir3 } from "os";
277
+ import { NextResponse as NextResponse4 } from "next/server";
278
+ import { execFile as execFile4 } from "child_process";
214
279
  async function handleOpen(_req) {
215
- const desktop = join3(homedir3(), "Desktop");
280
+ const desktop = await getSaveDir();
216
281
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "explorer" : "xdg-open";
217
- execFile3(cmd, [desktop]);
218
- return NextResponse3.json({ success: true });
282
+ execFile4(cmd, [desktop]);
283
+ return NextResponse4.json({ success: true });
219
284
  }
220
285
 
221
286
  export {
287
+ handleGetConfig,
288
+ handleSetConfig,
289
+ handlePickFolder,
222
290
  handleSave,
223
291
  handlePush,
224
292
  handleOpen
225
293
  };
226
- //# sourceMappingURL=chunk-A73KCX5G.js.map
294
+ //# sourceMappingURL=chunk-BFC2HVPX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/config.ts","../src/server/save.ts","../src/server/push.ts","../src/server/open.ts"],"sourcesContent":["import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\ninterface Config {\n saveDir: string;\n}\n\nconst CONFIG_DIR = join(process.cwd(), \".afterbefore\");\nconst CONFIG_PATH = join(CONFIG_DIR, \"config.json\");\nconst DEFAULT_SAVE_DIR = join(homedir(), \"Desktop\");\n\nasync function readConfig(): Promise<Config> {\n try {\n const raw = await readFile(CONFIG_PATH, \"utf-8\");\n const parsed = JSON.parse(raw);\n return { saveDir: parsed.saveDir || DEFAULT_SAVE_DIR };\n } catch {\n return { saveDir: DEFAULT_SAVE_DIR };\n }\n}\n\nasync function writeConfig(config: Config): Promise<void> {\n await mkdir(CONFIG_DIR, { recursive: true });\n await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + \"\\n\");\n}\n\nexport async function getSaveDir(): Promise<string> {\n const config = await readConfig();\n return config.saveDir;\n}\n\nexport async function handleGetConfig(): Promise<NextResponse> {\n const config = await readConfig();\n return NextResponse.json(config);\n}\n\nexport async function handleSetConfig(req: NextRequest): Promise<NextResponse> {\n let body: Partial<Config>;\n try {\n body = await req.json();\n } catch {\n return NextResponse.json({ error: \"Invalid JSON\" }, { status: 400 });\n }\n\n if (typeof body.saveDir !== \"string\" || body.saveDir.trim() === \"\") {\n return NextResponse.json({ error: \"Invalid saveDir\" }, { status: 400 });\n }\n\n const config: Config = { saveDir: body.saveDir.trim() };\n await writeConfig(config);\n return NextResponse.json(config);\n}\n\nexport async function handlePickFolder(): Promise<NextResponse> {\n if (process.platform !== \"darwin\") {\n return NextResponse.json(\n { error: \"Folder picker is only supported on macOS\" },\n { status: 501 },\n );\n }\n\n try {\n const { stdout } = await execFileAsync(\"osascript\", [\n \"-e\",\n 'POSIX path of (choose folder with prompt \"Select screenshot save location\")',\n ]);\n const folder = stdout.trim().replace(/\\/$/, \"\");\n if (!folder) {\n return NextResponse.json({ cancelled: true });\n }\n return NextResponse.json({ folder });\n } catch {\n // User cancelled the dialog\n return NextResponse.json({ cancelled: true });\n }\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { getSaveDir } from \"./config\";\n\nconst execFileAsync = promisify(execFile);\n\nasync function getBranch(): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], {\n cwd: process.cwd(),\n });\n return stdout.trim();\n}\n\nconst VALID_TYPES = [\"before\", \"after\"] as const;\ntype ScreenshotType = (typeof VALID_TYPES)[number];\n\nconst VALID_MODES = [\"fullpage\", \"viewport\", \"area\", \"component\"] as const;\n\nconst DATA_URL_PREFIX = \"data:image/png;base64,\";\n\ninterface SaveRequestBody {\n type: ScreenshotType;\n mode: string;\n image: string;\n}\n\nexport async function handleSave(req: NextRequest): Promise<NextResponse> {\n let body: SaveRequestBody;\n try {\n body = await req.json();\n } catch {\n return NextResponse.json(\n { error: \"Invalid JSON body\" },\n { status: 400 },\n );\n }\n\n const { type, mode, image } = body;\n\n if (!VALID_TYPES.includes(type as ScreenshotType)) {\n return NextResponse.json(\n { error: `Invalid type: must be \"before\" or \"after\"` },\n { status: 400 },\n );\n }\n\n if (!VALID_MODES.includes(mode as (typeof VALID_MODES)[number])) {\n return NextResponse.json(\n { error: `Invalid mode: must be \"fullpage\", \"viewport\", or \"area\"` },\n { status: 400 },\n );\n }\n\n if (typeof image !== \"string\" || !image.startsWith(DATA_URL_PREFIX)) {\n return NextResponse.json(\n { error: \"Invalid image: must be a data:image/png;base64 data URL\" },\n { status: 400 },\n );\n }\n\n const base64 = image.slice(DATA_URL_PREFIX.length);\n const buffer = Buffer.from(base64, \"base64\");\n\n const branch = await getBranch();\n const saveDir = await getSaveDir();\n const filename = `${branch}-${type}.png`;\n const filepath = join(saveDir, filename);\n\n try {\n await writeFile(filepath, buffer);\n } catch (err) {\n return NextResponse.json(\n { error: \"Failed to write screenshot\", detail: String(err) },\n { status: 500 },\n );\n }\n\n return NextResponse.json({ success: true, path: filepath });\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { access, mkdir, copyFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { getSaveDir } from \"./config\";\n\nconst execFileAsync = promisify(execFile);\n\ninterface PrInfo {\n number: number;\n url: string;\n headRepository: { owner: { login: string }; name: string };\n headRefName: string;\n}\n\nasync function run(\n cmd: string,\n args: string[],\n): Promise<{ stdout: string; stderr: string }> {\n return execFileAsync(cmd, args, { cwd: process.cwd() });\n}\n\nasync function ghAvailable(): Promise<boolean> {\n try {\n await run(\"gh\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function getPrInfo(): Promise<PrInfo | null> {\n try {\n const { stdout } = await run(\"gh\", [\n \"pr\",\n \"view\",\n \"--json\",\n \"number,url,headRepository,headRefName\",\n ]);\n return JSON.parse(stdout) as PrInfo;\n } catch {\n return null;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function handlePush(req: NextRequest): Promise<NextResponse> {\n // 1. Check gh CLI availability\n if (!(await ghAvailable())) {\n return NextResponse.json(\n { success: false, error: \"GitHub CLI (gh) is not installed or not in PATH\" },\n { status: 500 },\n );\n }\n\n // 2. Check for active PR\n const pr = await getPrInfo();\n if (!pr) {\n return NextResponse.json(\n { success: false, error: \"No PR found for current branch\" },\n { status: 404 },\n );\n }\n\n // 3. Check that screenshot files exist in save directory\n const desktop = await getSaveDir();\n const branch = pr.headRefName;\n const beforePath = join(desktop, `${branch}-before.png`);\n const afterPath = join(desktop, `${branch}-after.png`);\n\n const [hasBefore, hasAfter] = await Promise.all([\n fileExists(beforePath),\n fileExists(afterPath),\n ]);\n\n if (!hasBefore || !hasAfter) {\n const missing = [\n !hasBefore && `${branch}-before.png`,\n !hasAfter && `${branch}-after.png`,\n ].filter(Boolean);\n return NextResponse.json(\n { success: false, error: `Missing screenshots: ${missing.join(\", \")}` },\n { status: 400 },\n );\n }\n\n // 4. Copy from Desktop into repo, stage, commit, and push\n const repoDir = join(process.cwd(), \".afterbefore\");\n const repoBefore = join(repoDir, `${branch}-before.png`);\n const repoAfter = join(repoDir, `${branch}-after.png`);\n\n try {\n await mkdir(repoDir, { recursive: true });\n await copyFile(beforePath, repoBefore);\n await copyFile(afterPath, repoAfter);\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to copy screenshots into repo\", detail: String(err) },\n { status: 500 },\n );\n }\n\n try {\n await run(\"git\", [\"add\", repoBefore, repoAfter]);\n await run(\"git\", [\n \"commit\",\n \"-m\",\n \"chore: add before/after screenshots\",\n ]);\n } catch (err) {\n // Commit may fail if files are already committed with no changes.\n // That's fine -- we still want to push and comment.\n const msg = String(err);\n if (!msg.includes(\"nothing to commit\")) {\n return NextResponse.json(\n { success: false, error: \"Failed to commit screenshots\", detail: msg },\n { status: 500 },\n );\n }\n }\n\n try {\n await run(\"git\", [\"push\"]);\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to push to remote\", detail: String(err) },\n { status: 500 },\n );\n }\n\n // 5. Build raw GitHub URLs for the images\n const owner = pr.headRepository.owner.login;\n const repo = pr.headRepository.name;\n const rawBase = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;\n\n const beforeUrl = `${rawBase}/.afterbefore/${branch}-before.png`;\n const afterUrl = `${rawBase}/.afterbefore/${branch}-after.png`;\n\n // Cache-bust with timestamp so GitHub doesn't serve stale images\n const ts = Date.now();\n const commentBody = [\n \"## Before / After\",\n \"\",\n \"| Before | After |\",\n \"|--------|-------|\",\n `| ![before](${beforeUrl}?t=${ts}) | ![after](${afterUrl}?t=${ts}) |`,\n ].join(\"\\n\");\n\n // 6. Post PR comment\n let commentUrl: string | undefined;\n try {\n const { stdout } = await run(\"gh\", [\n \"pr\",\n \"comment\",\n String(pr.number),\n \"--body\",\n commentBody,\n ]);\n // gh pr comment prints the comment URL to stdout\n commentUrl = stdout.trim() || undefined;\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to post PR comment\", detail: String(err) },\n { status: 500 },\n );\n }\n\n return NextResponse.json({\n success: true,\n prNumber: pr.number,\n prUrl: pr.url,\n commentUrl,\n });\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { getSaveDir } from \"./config\";\n\nexport async function handleOpen(_req: NextRequest): Promise<NextResponse> {\n const desktop = await getSaveDir();\n\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"explorer\"\n : \"xdg-open\";\n\n execFile(cmd, [desktop]);\n\n return NextResponse.json({ success: true });\n}\n"],"mappings":"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","names":["NextResponse","writeFile","join","execFile","promisify","execFileAsync","promisify","execFile","NextResponse","join","writeFile","NextResponse","execFile","mkdir","join","promisify","execFileAsync","promisify","execFile","NextResponse","join","mkdir","NextResponse","execFile","execFile","NextResponse"]}
@@ -480,10 +480,10 @@ function CapturePreview({ mode, onClick }) {
480
480
  // src/overlay/ui/toolbar.tsx
481
481
  import { useEffect as useEffect4, useState as useState5 } from "react";
482
482
  import {
483
- Camera as Camera2,
484
483
  ChevronDown,
485
484
  Crop,
486
485
  FileText,
486
+ FolderOpen,
487
487
  Frame,
488
488
  Magnet,
489
489
  Monitor,
@@ -898,10 +898,10 @@ function Selector({
898
898
  // src/overlay/ui/toolbar.tsx
899
899
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
900
900
  var MODES = [
901
+ { mode: "component", label: "Capture Component", icon: MousePointer2 },
901
902
  { mode: "area", label: "Capture Selected Area", icon: Crop },
902
903
  { mode: "viewport", label: "Capture Viewport", icon: Monitor },
903
- { mode: "fullpage", label: "Capture Full Page", icon: FileText },
904
- { mode: "component", label: "Capture Component", icon: MousePointer2 }
904
+ { mode: "fullpage", label: "Capture Full Page", icon: FileText }
905
905
  ];
906
906
  function Toolbar({
907
907
  selectedMode,
@@ -1013,13 +1013,6 @@ function Toolbar({
1013
1013
  frameOnBlackEnabled,
1014
1014
  onFrameOnBlackChange
1015
1015
  }
1016
- ),
1017
- !showAreaControls && /* @__PURE__ */ jsx4(
1018
- CaptureButton,
1019
- {
1020
- label: "Capture",
1021
- onClick: () => onCapture(selectedMode)
1022
- }
1023
1016
  )
1024
1017
  ] }),
1025
1018
  activeAreaRect && /* @__PURE__ */ jsxs3(Fragment2, { children: [
@@ -1202,7 +1195,32 @@ function SettingsButton({
1202
1195
  onFrameOnBlackChange
1203
1196
  }) {
1204
1197
  const [hovered, setHovered] = useState5(false);
1205
- const settingsHeader = selectedMode === "component" ? "Component Settings" : selectedMode === "area" ? "Area Settings" : "Settings";
1198
+ const [saveDir, setSaveDir] = useState5(null);
1199
+ const [picking, setPicking] = useState5(false);
1200
+ useEffect4(() => {
1201
+ if (!open) return;
1202
+ fetch("/__afterbefore/config").then((r) => r.json()).then((data) => setSaveDir(data.saveDir)).catch(() => {
1203
+ });
1204
+ }, [open]);
1205
+ const handlePickFolder = async () => {
1206
+ setPicking(true);
1207
+ try {
1208
+ const res = await fetch("/__afterbefore/pick-folder", { method: "POST" });
1209
+ const data = await res.json();
1210
+ if (data.folder) {
1211
+ await fetch("/__afterbefore/config", {
1212
+ method: "POST",
1213
+ headers: { "Content-Type": "application/json" },
1214
+ body: JSON.stringify({ saveDir: data.folder })
1215
+ });
1216
+ setSaveDir(data.folder);
1217
+ }
1218
+ } catch {
1219
+ } finally {
1220
+ setPicking(false);
1221
+ }
1222
+ };
1223
+ const shortDir = saveDir ? saveDir.replace(/^\/Users\/[^/]+/, "~") : "~/Desktop";
1206
1224
  return /* @__PURE__ */ jsxs3("div", { style: { position: "relative", marginRight: 6 }, children: [
1207
1225
  /* @__PURE__ */ jsx4(
1208
1226
  "button",
@@ -1245,7 +1263,7 @@ function SettingsButton({
1245
1263
  textTransform: "uppercase",
1246
1264
  marginBottom: 10
1247
1265
  },
1248
- children: settingsHeader
1266
+ children: "Settings"
1249
1267
  }
1250
1268
  ),
1251
1269
  selectedMode === "area" && /* @__PURE__ */ jsx4(
@@ -1265,12 +1283,79 @@ function SettingsButton({
1265
1283
  enabled: frameOnBlackEnabled,
1266
1284
  onChange: () => onFrameOnBlackChange(!frameOnBlackEnabled)
1267
1285
  }
1286
+ ),
1287
+ (selectedMode === "area" || selectedMode === "component") && /* @__PURE__ */ jsx4("div", { style: { height: 1, background: "rgba(255,255,255,0.08)", margin: "8px 0" } }),
1288
+ /* @__PURE__ */ jsx4(
1289
+ SaveLocationRow,
1290
+ {
1291
+ dir: shortDir,
1292
+ picking,
1293
+ onPick: handlePickFolder
1294
+ }
1268
1295
  )
1269
1296
  ]
1270
1297
  }
1271
1298
  )
1272
1299
  ] });
1273
1300
  }
1301
+ function SaveLocationRow({
1302
+ dir,
1303
+ picking,
1304
+ onPick
1305
+ }) {
1306
+ const [btnHovered, setBtnHovered] = useState5(false);
1307
+ return /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: /* @__PURE__ */ jsxs3(
1308
+ "div",
1309
+ {
1310
+ style: {
1311
+ display: "flex",
1312
+ alignItems: "center",
1313
+ gap: 8,
1314
+ color: "rgba(255, 255, 255, 0.88)",
1315
+ fontSize: 13
1316
+ },
1317
+ children: [
1318
+ /* @__PURE__ */ jsx4(FolderOpen, { size: 15, strokeWidth: 1.8, style: { flexShrink: 0 } }),
1319
+ /* @__PURE__ */ jsx4(
1320
+ "span",
1321
+ {
1322
+ style: {
1323
+ overflow: "hidden",
1324
+ textOverflow: "ellipsis",
1325
+ whiteSpace: "nowrap",
1326
+ flex: 1,
1327
+ minWidth: 0
1328
+ },
1329
+ title: dir,
1330
+ children: dir
1331
+ }
1332
+ ),
1333
+ /* @__PURE__ */ jsx4(
1334
+ "button",
1335
+ {
1336
+ onClick: onPick,
1337
+ disabled: picking,
1338
+ onMouseEnter: () => setBtnHovered(true),
1339
+ onMouseLeave: () => setBtnHovered(false),
1340
+ style: {
1341
+ padding: "3px 8px",
1342
+ borderRadius: 6,
1343
+ border: "1px solid rgba(255,255,255,0.12)",
1344
+ background: btnHovered ? "rgba(255,255,255,0.12)" : "rgba(255,255,255,0.06)",
1345
+ color: "rgba(255,255,255,0.78)",
1346
+ fontSize: 11,
1347
+ cursor: picking ? "wait" : "pointer",
1348
+ flexShrink: 0,
1349
+ fontFamily: "inherit",
1350
+ transition: "background 0.12s ease"
1351
+ },
1352
+ children: picking ? "..." : "Change"
1353
+ }
1354
+ )
1355
+ ]
1356
+ }
1357
+ ) });
1358
+ }
1274
1359
  function ToggleRow({
1275
1360
  icon,
1276
1361
  label,
@@ -1343,42 +1428,6 @@ function ToggleRow({
1343
1428
  }
1344
1429
  );
1345
1430
  }
1346
- function CaptureButton({
1347
- label,
1348
- onClick
1349
- }) {
1350
- const [hovered, setHovered] = useState5(false);
1351
- return /* @__PURE__ */ jsxs3(
1352
- "button",
1353
- {
1354
- onClick,
1355
- onMouseEnter: () => setHovered(true),
1356
- onMouseLeave: () => setHovered(false),
1357
- style: {
1358
- padding: "0 18px",
1359
- height: 40,
1360
- borderRadius: 12,
1361
- border: "none",
1362
- background: hovered ? "#2f7bf8" : "#3b82f6",
1363
- color: "white",
1364
- fontSize: 13,
1365
- fontWeight: 600,
1366
- fontFamily: "inherit",
1367
- cursor: "pointer",
1368
- whiteSpace: "nowrap",
1369
- transition: "background 0.12s ease",
1370
- flexShrink: 0,
1371
- display: "flex",
1372
- alignItems: "center",
1373
- gap: 8
1374
- },
1375
- children: [
1376
- /* @__PURE__ */ jsx4(Camera2, { size: 16, strokeWidth: 1.9 }),
1377
- label
1378
- ]
1379
- }
1380
- );
1381
- }
1382
1431
  function ControlGroup({
1383
1432
  label,
1384
1433
  children
@@ -2077,7 +2126,7 @@ function AfterBefore() {
2077
2126
  const [selectorActive, setSelectorActive] = useState8(false);
2078
2127
  const [inspectorActive, setInspectorActive] = useState8(false);
2079
2128
  const [loading, setLoading] = useState8(false);
2080
- const [selectedMode, setSelectedMode] = useState8("area");
2129
+ const [selectedMode, setSelectedMode] = useState8("component");
2081
2130
  const [magnetEnabled, setMagnetEnabled] = useState8(true);
2082
2131
  const [areaRect, setAreaRect] = useState8(null);
2083
2132
  const [areaAspect, setAreaAspect] = useState8(DEFAULT_AREA_ASPECT);
@@ -2235,6 +2284,10 @@ function AfterBefore() {
2235
2284
  setSelectorActive(true);
2236
2285
  setAreaRect(createInitialAreaRect());
2237
2286
  setAreaAspect(DEFAULT_AREA_ASPECT);
2287
+ } else if (mode === "component") {
2288
+ setSelectorActive(false);
2289
+ setToolbarActive(false);
2290
+ setInspectorActive(true);
2238
2291
  } else {
2239
2292
  setSelectorActive(false);
2240
2293
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/overlay/index.tsx","../../src/overlay/state.ts","../../src/overlay/capture.ts","../../src/overlay/ui/icon.tsx","../../src/overlay/ui/preview.tsx","../../src/overlay/ui/toolbar.tsx","../../src/overlay/ui/selector.tsx","../../src/overlay/ui/inspector.tsx","../../src/overlay/ui/status.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useState, useCallback, useRef, useEffect } from \"react\";\nimport { useOverlayState } from \"./state\";\nimport type { CaptureMode } from \"./state\";\nimport { capture } from \"./capture\";\nimport { Icon } from \"./ui/icon\";\nimport { CapturePreview } from \"./ui/preview\";\nimport { Toolbar } from \"./ui/toolbar\";\nimport {\n Selector,\n type AreaAspectLabel,\n type AreaRect,\n DEFAULT_AREA_ASPECT,\n createInitialAreaRect,\n} from \"./ui/selector\";\nimport { Inspector } from \"./ui/inspector\";\nimport { Status } from \"./ui/status\";\n\nasync function saveCapture(\n type: \"before\" | \"after\",\n mode: CaptureMode,\n dataUrl: string,\n) {\n try {\n const res = await fetch(\"/__afterbefore/save\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ type, mode, image: dataUrl }),\n });\n if (!res.ok) throw new Error(\"Save failed\");\n } catch {\n // Fallback: browser download (no branch info available client-side)\n const link = document.createElement(\"a\");\n link.download = `${type}.png`;\n link.href = dataUrl;\n link.click();\n }\n}\n\nexport function AfterBefore() {\n const { state, captureComplete, reset } = useOverlayState();\n const [statusOpen, setStatusOpen] = useState(false);\n const [toolbarActive, setToolbarActive] = useState(false);\n const [selectorActive, setSelectorActive] = useState(false);\n const [inspectorActive, setInspectorActive] = useState(false);\n const [loading, setLoading] = useState(false);\n const [selectedMode, setSelectedMode] = useState<CaptureMode>(\"area\");\n const [magnetEnabled, setMagnetEnabled] = useState(true);\n const [areaRect, setAreaRect] = useState<AreaRect | null>(null);\n const [areaAspect, setAreaAspect] = useState<AreaAspectLabel>(DEFAULT_AREA_ASPECT);\n const [areaPresets, setAreaPresets] = useState<{ label: string; rect: AreaRect }[]>([]);\n const [frameOnBlackEnabled, setFrameOnBlackEnabled] = useState(false);\n const iconPos = useRef<{ x: number; y: number }>({ x: 24, y: 0 });\n\n useEffect(() => {\n try {\n setMagnetEnabled(localStorage.getItem(\"ab-magnet\") !== \"false\");\n } catch {\n setMagnetEnabled(true);\n }\n\n try {\n const savedPresets = localStorage.getItem(\"ab-area-presets\");\n setAreaPresets(savedPresets ? JSON.parse(savedPresets) : []);\n } catch {\n setAreaPresets([]);\n }\n\n try {\n setFrameOnBlackEnabled(localStorage.getItem(\"ab-frame-black\") === \"true\");\n } catch {\n setFrameOnBlackEnabled(false);\n }\n }, []);\n\n useEffect(() => {\n if (state.phase === \"ready\") {\n const timer = setTimeout(() => {\n reset();\n setStatusOpen(false);\n }, 1500);\n return () => clearTimeout(timer);\n }\n }, [state.phase, reset]);\n\n const handlePositionChange = useCallback(\n (pos: { x: number; y: number }) => {\n iconPos.current = pos;\n },\n [],\n );\n\n const handleIconClick = useCallback(() => {\n if (loading) return;\n\n if (state.phase === \"ready\") {\n setStatusOpen((prev: boolean) => !prev);\n } else if (toolbarActive || inspectorActive) {\n setToolbarActive(false);\n setSelectorActive(false);\n setInspectorActive(false);\n setStatusOpen(false);\n } else {\n setStatusOpen(false);\n if (selectedMode === \"component\") {\n setInspectorActive(true);\n } else {\n setToolbarActive(true);\n setInspectorActive(false);\n if (selectedMode === \"area\") {\n setSelectorActive(true);\n setAreaRect(createInitialAreaRect());\n setAreaAspect(DEFAULT_AREA_ASPECT);\n }\n }\n }\n }, [state.phase, loading, toolbarActive, inspectorActive, selectedMode]);\n\n const performCapture = useCallback(\n async (\n mode: CaptureMode,\n area?: { x: number; y: number; width: number; height: number },\n element?: HTMLElement,\n ) => {\n setLoading(true);\n try {\n const dataUrl = await capture({ mode, area, element, frameOnBlack: frameOnBlackEnabled });\n const type = state.phase === \"idle\" ? \"before\" : \"after\";\n await saveCapture(type, mode, dataUrl);\n captureComplete({\n dataUrl,\n mode,\n timestamp: Date.now(),\n });\n } catch (err) {\n console.error(\"[afterbefore] Capture failed:\", err);\n } finally {\n setLoading(false);\n }\n },\n [state.phase, captureComplete, frameOnBlackEnabled],\n );\n\n const handleToolbarCapture = useCallback(\n (mode: CaptureMode) => {\n if (mode === \"area\") {\n if (areaRect) {\n setSelectorActive(false);\n setToolbarActive(false);\n performCapture(\"area\", {\n x: Math.round(areaRect.x),\n y: Math.round(areaRect.y),\n width: Math.round(areaRect.w),\n height: Math.round(areaRect.h),\n });\n }\n return;\n } else if (mode === \"viewport\") {\n setToolbarActive(false);\n performCapture(\"viewport\");\n } else if (mode === \"fullpage\") {\n setToolbarActive(false);\n performCapture(\"fullpage\");\n } else if (mode === \"component\") {\n setToolbarActive(false);\n setInspectorActive(true);\n }\n },\n [areaRect, performCapture],\n );\n\n const handleToolbarCancel = useCallback(() => {\n setToolbarActive(false);\n setSelectorActive(false);\n }, []);\n\n const handleComponentSelect = useCallback(\n (element: HTMLElement) => {\n setInspectorActive(false);\n performCapture(\"component\", undefined, element);\n },\n [performCapture],\n );\n\n const handleComponentCancel = useCallback(() => {\n setInspectorActive(false);\n setToolbarActive(true);\n }, []);\n\n const handleAreaSelect = useCallback(\n (area: { x: number; y: number; width: number; height: number }) => {\n setSelectorActive(false);\n setToolbarActive(false);\n performCapture(\"area\", area);\n },\n [performCapture],\n );\n\n const handleAreaCancel = useCallback(() => {\n setSelectorActive(false);\n setToolbarActive(true);\n }, []);\n\n const handleMagnetChange = useCallback((enabled: boolean) => {\n setMagnetEnabled(enabled);\n try {\n localStorage.setItem(\"ab-magnet\", String(enabled));\n } catch {\n // noop\n }\n }, []);\n\n const handleFrameOnBlackChange = useCallback((enabled: boolean) => {\n setFrameOnBlackEnabled(enabled);\n try {\n localStorage.setItem(\"ab-frame-black\", String(enabled));\n } catch {\n // noop\n }\n }, []);\n\n const handleModeChange = useCallback((mode: CaptureMode) => {\n setSelectedMode(mode);\n if (mode === \"area\") {\n setSelectorActive(true);\n setAreaRect(createInitialAreaRect());\n setAreaAspect(DEFAULT_AREA_ASPECT);\n } else {\n setSelectorActive(false);\n }\n }, []);\n\n const handleAreaRectChange = useCallback((nextRect: AreaRect | null) => {\n setAreaRect(nextRect);\n }, []);\n\n const handleAreaSizeChange = useCallback(\n (field: \"w\" | \"h\", value: string) => {\n const nextValue = parseInt(value, 10);\n if (Number.isNaN(nextValue) || nextValue < 20 || !areaRect) {\n return;\n }\n\n const aspectRatio =\n areaAspect === \"Free\"\n ? 0\n : ({ \"16:9\": 16 / 9, \"4:3\": 4 / 3, \"1:1\": 1, \"3:2\": 3 / 2, \"21:9\": 21 / 9 } as const)[areaAspect];\n\n if (field === \"w\") {\n setAreaRect({\n ...areaRect,\n w: nextValue,\n h: aspectRatio > 0 ? nextValue / aspectRatio : areaRect.h,\n });\n } else {\n setAreaRect({\n ...areaRect,\n h: nextValue,\n w: aspectRatio > 0 ? nextValue * aspectRatio : areaRect.w,\n });\n }\n },\n [areaAspect, areaRect],\n );\n\n const handleAreaPositionChange = useCallback(\n (field: \"x\" | \"y\", value: string) => {\n const nextValue = parseInt(value, 10);\n if (Number.isNaN(nextValue) || !areaRect) {\n return;\n }\n\n setAreaRect({ ...areaRect, [field]: nextValue });\n },\n [areaRect],\n );\n\n const handleAreaAspectChange = useCallback(\n (nextAspect: AreaAspectLabel) => {\n setAreaAspect(nextAspect);\n if (!areaRect || nextAspect === \"Free\") {\n return;\n }\n\n const aspectRatio = ({ \"16:9\": 16 / 9, \"4:3\": 4 / 3, \"1:1\": 1, \"3:2\": 3 / 2, \"21:9\": 21 / 9 } as const)[nextAspect];\n setAreaRect({ ...areaRect, h: areaRect.w / aspectRatio });\n },\n [areaRect],\n );\n\n const handleAreaSavePreset = useCallback(() => {\n if (!areaRect) {\n return;\n }\n\n const label = `${Math.round(areaRect.w)}x${Math.round(areaRect.h)}`;\n const nextPresets = [\n ...areaPresets.filter((preset) => preset.label !== label),\n { label, rect: { ...areaRect } },\n ];\n\n setAreaPresets(nextPresets);\n try {\n localStorage.setItem(\"ab-area-presets\", JSON.stringify(nextPresets));\n } catch {\n // noop\n }\n }, [areaPresets, areaRect]);\n\n const handleAreaLoadPreset = useCallback((preset: { label: string; rect: AreaRect }) => {\n setAreaRect({ ...preset.rect });\n }, []);\n\n const handleReset = useCallback(() => {\n reset();\n setStatusOpen(false);\n }, [reset]);\n\n const handleStatusClose = useCallback(() => {\n setStatusOpen(false);\n }, []);\n\n return (\n <div data-afterbefore=\"true\">\n <Icon\n phase={state.phase}\n onClick={handleIconClick}\n loading={loading}\n onPositionChange={handlePositionChange}\n />\n\n {toolbarActive && !selectorActive && !inspectorActive && !loading && (\n <CapturePreview\n mode={selectedMode}\n onClick={() => handleToolbarCapture(selectedMode)}\n />\n )}\n\n {toolbarActive && !inspectorActive && (\n <Toolbar\n selectedMode={selectedMode}\n onModeChange={handleModeChange}\n onCapture={handleToolbarCapture}\n onCancel={handleToolbarCancel}\n magnetEnabled={magnetEnabled}\n onMagnetChange={handleMagnetChange}\n areaSelectionActive={selectorActive}\n areaRect={areaRect}\n areaAspect={areaAspect}\n areaPresets={areaPresets}\n onAreaSizeChange={handleAreaSizeChange}\n onAreaPositionChange={handleAreaPositionChange}\n onAreaAspectChange={handleAreaAspectChange}\n onAreaSavePreset={handleAreaSavePreset}\n onAreaLoadPreset={handleAreaLoadPreset}\n frameOnBlackEnabled={frameOnBlackEnabled}\n onFrameOnBlackChange={handleFrameOnBlackChange}\n />\n )}\n\n {selectorActive && (\n <Selector\n rect={areaRect}\n aspect={areaAspect}\n onRectChange={handleAreaRectChange}\n onSelect={handleAreaSelect}\n onCancel={handleAreaCancel}\n magnetEnabled={magnetEnabled}\n />\n )}\n\n {inspectorActive && (\n <Inspector onSelect={handleComponentSelect} onCancel={handleComponentCancel} />\n )}\n\n {statusOpen && state.phase === \"ready\" && (\n <Status\n onReset={handleReset}\n position={iconPos.current}\n onClose={handleStatusClose}\n />\n )}\n </div>\n );\n}\n","import { useState, useCallback } from \"react\";\n\nexport type CaptureMode = \"viewport\" | \"fullpage\" | \"area\" | \"component\";\n\nexport type OverlayPhase = \"idle\" | \"captured-before\" | \"ready\";\n\nexport interface CaptureResult {\n dataUrl: string;\n mode: CaptureMode;\n timestamp: number;\n}\n\nexport interface OverlayState {\n phase: OverlayPhase;\n before: CaptureResult | null;\n after: CaptureResult | null;\n}\n\nconst initialState: OverlayState = {\n phase: \"idle\",\n before: null,\n after: null,\n};\n\nexport function useOverlayState() {\n const [state, setState] = useState<OverlayState>(initialState);\n\n const captureComplete = useCallback(\n (result: CaptureResult) => {\n setState((prev) => {\n if (prev.phase === \"idle\") {\n return { ...prev, phase: \"captured-before\", before: result };\n }\n if (prev.phase === \"captured-before\") {\n return { ...prev, phase: \"ready\", after: result };\n }\n return prev;\n });\n },\n [],\n );\n\n const reset = useCallback(() => {\n setState(initialState);\n }, []);\n\n return { state, captureComplete, reset };\n}\n","import { snapdom } from \"@zumer/snapdom\";\nimport type { CaptureMode } from \"./state\";\n\ninterface CaptureOptions {\n mode: CaptureMode;\n area?: { x: number; y: number; width: number; height: number };\n element?: HTMLElement;\n frameOnBlack?: boolean;\n}\n\n/** Selectors for dev tool UI that should be excluded from capture */\nconst DEV_UI_SELECTORS = [\n // Afterbefore overlay\n \"[data-afterbefore]\",\n // Next.js dev indicators\n \"[data-nextjs-toast]\",\n \"[data-nextjs-dev-overlay]\",\n \"[data-nextjs-dialog]\",\n \"[data-nextjs-dialog-backdrop]\",\n \"[data-next-badge]\",\n \"[data-next-mark]\",\n];\n\nconst SNAPDOM_BASE = {\n exclude: DEV_UI_SELECTORS,\n excludeMode: \"remove\" as const,\n};\n\nasync function toPngDataUrl(\n el: Element,\n opts?: Record<string, unknown>,\n): Promise<string> {\n const result = await snapdom(el, { ...SNAPDOM_BASE, ...opts });\n const img = await result.toPng();\n return img.src;\n}\n\nexport async function capture(options: CaptureOptions): Promise<string> {\n const { mode, area, element } = options;\n\n if (mode === \"viewport\") {\n return captureViewport();\n }\n if (mode === \"fullpage\") {\n return captureFullPage();\n }\n if (mode === \"area\" && area) {\n return captureArea(area);\n }\n if (mode === \"component\" && element) {\n return captureComponent(element, options.frameOnBlack);\n }\n throw new Error(`Invalid capture mode: ${mode}`);\n}\n\nasync function captureViewport(): Promise<string> {\n const dpr = window.devicePixelRatio || 1;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const scrollY = window.scrollY;\n\n // snapdom renders the full element content, so capture full page and crop to viewport\n const fullDataUrl = await captureFullPage();\n const img = await loadImage(fullDataUrl);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = vw * dpr;\n canvas.height = vh * dpr;\n\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(\n img,\n 0,\n scrollY * dpr,\n vw * dpr,\n vh * dpr,\n 0,\n 0,\n vw * dpr,\n vh * dpr,\n );\n\n return canvas.toDataURL(\"image/png\");\n}\n\nasync function captureFullPage(): Promise<string> {\n const scrollY = window.scrollY;\n const body = document.body;\n const html = document.documentElement;\n\n const fullHeight = Math.max(\n body.scrollHeight,\n body.offsetHeight,\n html.clientHeight,\n html.scrollHeight,\n html.offsetHeight,\n );\n\n const prevOverflow = html.style.overflow;\n const prevHeight = html.style.height;\n html.style.overflow = \"visible\";\n html.style.height = `${fullHeight}px`;\n\n try {\n return await toPngDataUrl(document.documentElement, {\n width: window.innerWidth,\n height: fullHeight,\n });\n } finally {\n html.style.overflow = prevOverflow;\n html.style.height = prevHeight;\n window.scrollTo(0, scrollY);\n }\n}\n\nasync function captureArea(area: {\n x: number;\n y: number;\n width: number;\n height: number;\n}): Promise<string> {\n const fullDataUrl = await captureViewport();\n\n const img = await loadImage(fullDataUrl);\n const dpr = window.devicePixelRatio || 1;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = area.width * dpr;\n canvas.height = area.height * dpr;\n\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(\n img,\n area.x * dpr,\n area.y * dpr,\n area.width * dpr,\n area.height * dpr,\n 0,\n 0,\n area.width * dpr,\n area.height * dpr,\n );\n\n return canvas.toDataURL(\"image/png\");\n}\n\nasync function captureComponent(\n element: HTMLElement,\n frameOnBlack?: boolean,\n): Promise<string> {\n const dataUrl = await toPngDataUrl(element);\n\n if (!frameOnBlack) {\n return dataUrl;\n }\n\n const img = await loadImage(dataUrl);\n const dpr = window.devicePixelRatio || 1;\n\n const FRAME_W = 1920;\n const FRAME_H = 1080;\n\n // Component dimensions in CSS pixels\n const compW = img.width / dpr;\n const compH = img.height / dpr;\n\n // Scale down if component exceeds frame (with padding)\n const padding = 40;\n const maxW = FRAME_W - padding * 2;\n const maxH = FRAME_H - padding * 2;\n const scale = Math.min(1, maxW / compW, maxH / compH);\n\n const drawW = compW * scale * dpr;\n const drawH = compH * scale * dpr;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = FRAME_W * dpr;\n canvas.height = FRAME_H * dpr;\n\n const ctx = canvas.getContext(\"2d\")!;\n ctx.fillStyle = \"#000000\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n // Center the component\n const dx = (canvas.width - drawW) / 2;\n const dy = (canvas.height - drawH) / 2;\n ctx.drawImage(img, dx, dy, drawW, drawH);\n\n return canvas.toDataURL(\"image/png\");\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = src;\n });\n}\n","\"use client\";\n\nimport React, { useRef, useCallback, useEffect, useState } from \"react\";\nimport { Camera, Check, LoaderCircle } from \"lucide-react\";\nimport type { OverlayPhase } from \"../state\";\n\ninterface IconProps {\n phase: OverlayPhase;\n onClick: () => void;\n loading?: boolean;\n onPositionChange?: (pos: { x: number; y: number }) => void;\n}\n\nconst ICON_SIZE = 40;\nconst EDGE_MARGIN = 24;\n\nexport function Icon({ phase, onClick, loading, onPositionChange }: IconProps) {\n const ref = useRef<HTMLDivElement>(null);\n const [pos, setPos] = useState({ x: EDGE_MARGIN, y: -1 });\n const dragState = useRef<{\n dragging: boolean;\n startX: number;\n startY: number;\n origX: number;\n origY: number;\n distance: number;\n } | null>(null);\n\n // Initialize y position on mount (need window.innerHeight)\n useEffect(() => {\n setPos((prev) => {\n if (prev.y === -1) {\n const y = window.innerHeight - ICON_SIZE - EDGE_MARGIN;\n return { x: prev.x, y };\n }\n return prev;\n });\n }, []);\n\n // Report position changes upstream\n useEffect(() => {\n if (pos.y !== -1) {\n onPositionChange?.({ x: pos.x, y: pos.y });\n }\n }, [pos, onPositionChange]);\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n dragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n origX: pos.x,\n origY: pos.y,\n distance: 0,\n };\n },\n [pos],\n );\n\n useEffect(() => {\n const handleMouseMove = (e: MouseEvent) => {\n const ds = dragState.current;\n if (!ds || !ds.dragging) return;\n\n const dx = e.clientX - ds.startX;\n const dy = e.clientY - ds.startY;\n ds.distance = Math.sqrt(dx * dx + dy * dy);\n\n const newX = Math.max(\n 0,\n Math.min(window.innerWidth - ICON_SIZE, ds.origX + dx),\n );\n const newY = Math.max(\n 0,\n Math.min(window.innerHeight - ICON_SIZE, ds.origY + dy),\n );\n setPos({ x: newX, y: newY });\n };\n\n const handleMouseUp = () => {\n const ds = dragState.current;\n if (!ds) return;\n\n if (ds.distance < 5) {\n onClick();\n }\n dragState.current = null;\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [onClick]);\n\n // Don't render until y is initialized\n if (pos.y === -1) return null;\n\n return (\n <div\n ref={ref}\n data-afterbefore=\"true\"\n onMouseDown={handleMouseDown}\n style={{\n position: \"fixed\",\n left: pos.x,\n top: pos.y,\n width: ICON_SIZE,\n height: ICON_SIZE,\n borderRadius: \"50%\",\n background: \"rgba(30, 30, 30, 0.85)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"grab\",\n zIndex: 2147483647,\n boxShadow: \"0 2px 8px rgba(0,0,0,0.3)\",\n transition: \"background 0.15s\",\n userSelect: \"none\",\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLDivElement).style.background =\n \"rgba(30, 30, 30, 0.95)\";\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLDivElement).style.background =\n \"rgba(30, 30, 30, 0.85)\";\n }}\n >\n <style\n dangerouslySetInnerHTML={{\n __html: `\n@keyframes ab-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.08); opacity: 0.85; }\n}\n@keyframes ab-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}`,\n }}\n />\n\n {loading ? (\n <LoaderCircle\n size={20}\n strokeWidth={2}\n style={{ animation: \"ab-spin 0.8s linear infinite\", color: \"white\" }}\n />\n ) : phase === \"ready\" ? (\n <Check size={20} strokeWidth={2.6} color=\"#4ade80\" />\n ) : (\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n animation:\n phase === \"captured-before\"\n ? \"ab-pulse 2s ease-in-out infinite\"\n : \"none\",\n }}\n >\n <Camera size={20} strokeWidth={1.9} color=\"white\" />\n\n {/* Badge for captured-before */}\n {phase === \"captured-before\" && (\n <div\n style={{\n position: \"absolute\",\n top: -6,\n right: -8,\n width: 14,\n height: 14,\n borderRadius: \"50%\",\n background: \"#3b82f6\",\n color: \"white\",\n fontSize: \"9px\",\n fontWeight: 700,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n lineHeight: 1,\n fontFamily: \"system-ui, sans-serif\",\n }}\n >\n 1\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport type { CaptureMode } from \"../state\";\n\ninterface CapturePreviewProps {\n mode: CaptureMode;\n onClick?: () => void;\n}\n\ninterface PreviewRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst DEFAULT_ASPECT_RATIO = 16 / 9;\n\nfunction getAreaPreviewRect(): PreviewRect {\n const safeWidth = Math.max(320, window.innerWidth - 120);\n const safeHeight = Math.max(180, window.innerHeight - 220);\n const width = Math.min(window.innerWidth * 0.72, safeHeight * DEFAULT_ASPECT_RATIO, safeWidth);\n const height = width / DEFAULT_ASPECT_RATIO;\n\n return {\n x: (window.innerWidth - width) / 2,\n y: Math.max(40, (window.innerHeight - height) / 2 - 20),\n width,\n height,\n };\n}\n\nconst CAMERA_CURSOR = `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z'/%3E%3Ccircle cx='12' cy='13' r='3'/%3E%3C/svg%3E\") 16 16, pointer`;\n\nexport function CapturePreview({ mode, onClick }: CapturePreviewProps) {\n const [areaRect, setAreaRect] = useState<PreviewRect | null>(null);\n\n useEffect(() => {\n if (mode !== \"area\") {\n return;\n }\n\n const syncRect = () => {\n setAreaRect(getAreaPreviewRect());\n };\n\n syncRect();\n window.addEventListener(\"resize\", syncRect);\n return () => window.removeEventListener(\"resize\", syncRect);\n }, [mode]);\n\n if (mode === \"area\" && areaRect) {\n return (\n <div\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483645,\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n left: areaRect.x,\n top: areaRect.y,\n width: areaRect.width,\n height: areaRect.height,\n background: \"rgba(125, 211, 252, 0.16)\",\n border: \"1.5px solid rgba(125, 211, 252, 0.95)\",\n boxShadow: \"0 0 0 1px rgba(191, 219, 254, 0.4), 0 0 32px rgba(56, 189, 248, 0.18)\",\n borderRadius: 14,\n }}\n />\n </div>\n );\n }\n\n if (mode === \"viewport\" || mode === \"fullpage\") {\n return (\n <div\n data-afterbefore=\"true\"\n onClick={onClick}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483645,\n cursor: CAMERA_CURSOR,\n background: \"rgba(125, 211, 252, 0.15)\",\n boxShadow: \"inset 0 0 0 1.5px rgba(125, 211, 252, 0.9)\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n top: 36,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n padding: \"8px 14px\",\n borderRadius: 999,\n background: \"rgba(125, 211, 252, 0.16)\",\n border: \"1px solid rgba(125, 211, 252, 0.42)\",\n color: \"rgba(224, 242, 254, 0.96)\",\n fontSize: 12,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n boxShadow: \"0 10px 30px rgba(14, 116, 144, 0.18)\",\n pointerEvents: \"none\",\n }}\n >\n {mode === \"fullpage\" ? \"Click to capture full page\" : \"Click to capture viewport\"}\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483645,\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n top: 36,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n padding: \"8px 14px\",\n borderRadius: 999,\n background: \"rgba(125, 211, 252, 0.16)\",\n border: \"1px solid rgba(125, 211, 252, 0.42)\",\n color: \"rgba(224, 242, 254, 0.96)\",\n fontSize: 12,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n boxShadow: \"0 10px 30px rgba(14, 116, 144, 0.18)\",\n }}\n >\n Click Capture, then hover an element to preview it\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport {\n Camera,\n ChevronDown,\n Crop,\n FileText,\n Frame,\n Magnet,\n Monitor,\n MousePointer2,\n Save,\n Settings2,\n X,\n} from \"lucide-react\";\nimport type { CaptureMode } from \"../state\";\nimport {\n AREA_ASPECT_RATIOS,\n type AreaAspectLabel,\n type AreaRect,\n} from \"./selector\";\n\ninterface ToolbarProps {\n selectedMode: CaptureMode;\n onModeChange: (mode: CaptureMode) => void;\n onCapture: (mode: CaptureMode) => void;\n onCancel: () => void;\n magnetEnabled: boolean;\n onMagnetChange: (enabled: boolean) => void;\n areaSelectionActive: boolean;\n areaRect: AreaRect | null;\n areaAspect: AreaAspectLabel;\n areaPresets: { label: string; rect: AreaRect }[];\n onAreaSizeChange: (field: \"w\" | \"h\", value: string) => void;\n onAreaPositionChange: (field: \"x\" | \"y\", value: string) => void;\n onAreaAspectChange: (aspect: AreaAspectLabel) => void;\n onAreaSavePreset: () => void;\n onAreaLoadPreset: (preset: { label: string; rect: AreaRect }) => void;\n frameOnBlackEnabled: boolean;\n onFrameOnBlackChange: (enabled: boolean) => void;\n}\n\nconst MODES: { mode: CaptureMode; label: string; icon: React.ComponentType<{ size?: number; strokeWidth?: number }> }[] = [\n { mode: \"area\", label: \"Capture Selected Area\", icon: Crop },\n { mode: \"viewport\", label: \"Capture Viewport\", icon: Monitor },\n { mode: \"fullpage\", label: \"Capture Full Page\", icon: FileText },\n { mode: \"component\", label: \"Capture Component\", icon: MousePointer2 },\n];\n\nexport function Toolbar({\n selectedMode,\n onModeChange,\n onCapture,\n onCancel,\n magnetEnabled,\n onMagnetChange,\n areaSelectionActive,\n areaRect,\n areaAspect,\n areaPresets,\n onAreaSizeChange,\n onAreaPositionChange,\n onAreaAspectChange,\n onAreaSavePreset,\n onAreaLoadPreset,\n frameOnBlackEnabled,\n onFrameOnBlackChange,\n}: ToolbarProps) {\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [aspectOpen, setAspectOpen] = useState(false);\n const [savedOpen, setSavedOpen] = useState(false);\n\n const showAreaControls = selectedMode === \"area\" && areaSelectionActive && areaRect !== null;\n const activeAreaRect = showAreaControls ? areaRect : null;\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if ((e.target as HTMLElement)?.tagName === \"INPUT\") {\n if (e.key === \"Escape\") {\n (e.target as HTMLElement).blur();\n }\n return;\n }\n\n if (e.key === \"Escape\") {\n if (settingsOpen) {\n setSettingsOpen(false);\n return;\n }\n if (aspectOpen) {\n setAspectOpen(false);\n return;\n }\n if (savedOpen) {\n setSavedOpen(false);\n return;\n }\n onCancel();\n } else if (e.key === \"Enter\") {\n onCapture(selectedMode);\n }\n };\n\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [aspectOpen, onCancel, onCapture, savedOpen, selectedMode, settingsOpen]);\n\n return (\n <div\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n bottom: 48,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n flexWrap: \"wrap\",\n justifyContent: \"center\",\n maxWidth: \"min(calc(100vw - 32px), 1120px)\",\n background: \"rgba(32, 32, 36, 0.92)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 18,\n padding: \"6px 10px\",\n boxShadow: \"0 8px 32px rgba(0, 0, 0, 0.4)\",\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 0 }}>\n <CloseButton onClick={onCancel} />\n\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 2, padding: \"0 4px\" }}>\n {MODES.map(({ mode, label, icon: Icon }) => (\n <ModeButton\n key={mode}\n label={label}\n selected={selectedMode === mode}\n onClick={() => {\n setSettingsOpen(false);\n onModeChange(mode);\n }}\n >\n <Icon size={18} strokeWidth={1.7} />\n </ModeButton>\n ))}\n </div>\n\n <Separator />\n\n <SettingsButton\n open={settingsOpen}\n onClick={() => {\n setAspectOpen(false);\n setSavedOpen(false);\n setSettingsOpen((prev) => !prev);\n }}\n selectedMode={selectedMode}\n magnetEnabled={magnetEnabled}\n onMagnetChange={onMagnetChange}\n frameOnBlackEnabled={frameOnBlackEnabled}\n onFrameOnBlackChange={onFrameOnBlackChange}\n />\n\n {!showAreaControls && (\n <CaptureButton\n label=\"Capture\"\n onClick={() => onCapture(selectedMode)}\n />\n )}\n </div>\n\n {activeAreaRect && (\n <>\n <Separator vertical={false} />\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n flexWrap: \"wrap\",\n justifyContent: \"center\",\n }}\n >\n <ControlGroup label=\"Size\">\n <NumInput value={Math.round(activeAreaRect.w)} onChange={(value) => onAreaSizeChange(\"w\", value)} />\n <StaticText>x</StaticText>\n <NumInput value={Math.round(activeAreaRect.h)} onChange={(value) => onAreaSizeChange(\"h\", value)} />\n </ControlGroup>\n\n <ControlGroup label=\"Position\">\n <NumInput value={Math.round(activeAreaRect.x)} onChange={(value) => onAreaPositionChange(\"x\", value)} />\n <StaticText>x</StaticText>\n <NumInput value={Math.round(activeAreaRect.y)} onChange={(value) => onAreaPositionChange(\"y\", value)} />\n </ControlGroup>\n\n <div style={{ position: \"relative\" }}>\n <DropButton\n active={areaAspect !== \"Free\"}\n onClick={() => {\n setSavedOpen(false);\n setAspectOpen((prev) => !prev);\n }}\n >\n {areaAspect}\n <ChevronDown size={14} strokeWidth={1.8} />\n </DropButton>\n\n {aspectOpen && (\n <DropMenu>\n {AREA_ASPECT_RATIOS.map((item) => (\n <DropItem\n key={item.label}\n active={item.label === areaAspect}\n onClick={() => {\n onAreaAspectChange(item.label);\n setAspectOpen(false);\n }}\n >\n {item.label}\n </DropItem>\n ))}\n </DropMenu>\n )}\n </div>\n\n <div style={{ position: \"relative\" }}>\n <DropButton\n onClick={() => {\n setAspectOpen(false);\n setSavedOpen((prev) => !prev);\n }}\n >\n <Save size={14} strokeWidth={1.8} />\n Saved\n <ChevronDown size={14} strokeWidth={1.8} />\n </DropButton>\n\n {savedOpen && (\n <DropMenu>\n <DropItem accent onClick={onAreaSavePreset}>\n Save current\n </DropItem>\n {areaPresets.length > 0 && <MenuDivider />}\n {areaPresets.map((preset) => (\n <DropItem\n key={preset.label}\n onClick={() => {\n onAreaLoadPreset(preset);\n setSavedOpen(false);\n }}\n >\n {preset.label}\n </DropItem>\n ))}\n {areaPresets.length === 0 && (\n <div\n style={{\n padding: \"6px 12px\",\n color: \"rgba(255,255,255,0.3)\",\n fontSize: 12,\n }}\n >\n No saved areas\n </div>\n )}\n </DropMenu>\n )}\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nfunction CloseButton({ onClick }: { onClick: () => void }) {\n const [hovered, setHovered] = useState(false);\n\n return (\n <button\n onClick={onClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n style={circleButtonStyle(hovered, true)}\n >\n <X size={18} strokeWidth={1.9} />\n </button>\n );\n}\n\nfunction ModeButton({\n children,\n label,\n selected,\n onClick,\n}: {\n children: React.ReactNode;\n label: string;\n selected: boolean;\n onClick: () => void;\n}) {\n const [hovered, setHovered] = useState(false);\n\n return (\n <div style={{ position: \"relative\" }}>\n {hovered && (\n <div\n style={{\n position: \"absolute\",\n left: \"50%\",\n bottom: \"calc(100% + 10px)\",\n transform: \"translateX(-50%)\",\n background: \"rgba(32, 32, 36, 0.96)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 8,\n padding: \"5px 10px\",\n color: \"rgba(255, 255, 255, 0.88)\",\n fontSize: 12,\n whiteSpace: \"nowrap\",\n boxShadow: \"0 8px 28px rgba(0, 0, 0, 0.28)\",\n pointerEvents: \"none\",\n }}\n >\n {label}\n </div>\n )}\n\n <button\n onClick={onClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n style={{\n width: 42,\n height: 40,\n borderRadius: 12,\n border: \"none\",\n background: selected\n ? \"rgba(255, 255, 255, 0.15)\"\n : hovered\n ? \"rgba(255, 255, 255, 0.08)\"\n : \"transparent\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n padding: 0,\n color: selected\n ? \"rgba(255, 255, 255, 0.96)\"\n : \"rgba(255, 255, 255, 0.52)\",\n transition: \"background 0.12s ease, color 0.12s ease\",\n }}\n >\n {children}\n </button>\n </div>\n );\n}\n\nfunction SettingsButton({\n open,\n onClick,\n selectedMode,\n magnetEnabled,\n onMagnetChange,\n frameOnBlackEnabled,\n onFrameOnBlackChange,\n}: {\n open: boolean;\n onClick: () => void;\n selectedMode: CaptureMode;\n magnetEnabled: boolean;\n onMagnetChange: (enabled: boolean) => void;\n frameOnBlackEnabled: boolean;\n onFrameOnBlackChange: (enabled: boolean) => void;\n}) {\n const [hovered, setHovered] = useState(false);\n\n const settingsHeader =\n selectedMode === \"component\"\n ? \"Component Settings\"\n : selectedMode === \"area\"\n ? \"Area Settings\"\n : \"Settings\";\n\n return (\n <div style={{ position: \"relative\", marginRight: 6 }}>\n <button\n onClick={onClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n style={{\n ...circleButtonStyle(open || hovered, false),\n color: \"rgba(255, 255, 255, 0.58)\",\n }}\n >\n <Settings2 size={18} strokeWidth={1.7} />\n </button>\n\n {open && (\n <div\n style={{\n position: \"absolute\",\n left: \"50%\",\n bottom: \"calc(100% + 12px)\",\n transform: \"translateX(-50%)\",\n minWidth: 210,\n padding: \"10px 12px\",\n borderRadius: 12,\n background: \"rgba(32, 32, 36, 0.96)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n boxShadow: \"0 14px 36px rgba(0, 0, 0, 0.32)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n }}\n >\n <div\n style={{\n fontSize: 11,\n color: \"rgba(255, 255, 255, 0.46)\",\n letterSpacing: \"0.03em\",\n textTransform: \"uppercase\",\n marginBottom: 10,\n }}\n >\n {settingsHeader}\n </div>\n\n {selectedMode === \"area\" && (\n <ToggleRow\n icon={<Magnet size={15} strokeWidth={1.8} />}\n label=\"Magnet snap\"\n enabled={magnetEnabled}\n onChange={() => onMagnetChange(!magnetEnabled)}\n />\n )}\n\n {selectedMode === \"component\" && (\n <ToggleRow\n icon={<Frame size={15} strokeWidth={1.8} />}\n label=\"1920 x 1080 frame\"\n enabled={frameOnBlackEnabled}\n onChange={() => onFrameOnBlackChange(!frameOnBlackEnabled)}\n />\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction ToggleRow({\n icon,\n label,\n enabled,\n onChange,\n}: {\n icon: React.ReactNode;\n label: string;\n enabled: boolean;\n onChange: () => void;\n}) {\n return (\n <label\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 12,\n cursor: \"pointer\",\n }}\n >\n <span\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n color: \"rgba(255, 255, 255, 0.88)\",\n fontSize: 13,\n whiteSpace: \"nowrap\",\n }}\n >\n {icon}\n {label}\n </span>\n\n <button\n type=\"button\"\n onClick={onChange}\n style={{\n width: 38,\n height: 22,\n borderRadius: 999,\n border: \"none\",\n background: enabled ? \"#38bdf8\" : \"rgba(255, 255, 255, 0.18)\",\n position: \"relative\",\n cursor: \"pointer\",\n padding: 0,\n flexShrink: 0,\n transition: \"background 0.12s ease\",\n }}\n >\n <span\n style={{\n position: \"absolute\",\n top: 2,\n left: enabled ? 18 : 2,\n width: 18,\n height: 18,\n borderRadius: \"50%\",\n background: \"#fff\",\n transition: \"left 0.12s ease\",\n }}\n />\n </button>\n </label>\n );\n}\n\nfunction CaptureButton({\n label,\n onClick,\n}: {\n label: string;\n onClick: () => void;\n}) {\n const [hovered, setHovered] = useState(false);\n\n return (\n <button\n onClick={onClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n style={{\n padding: \"0 18px\",\n height: 40,\n borderRadius: 12,\n border: \"none\",\n background: hovered ? \"#2f7bf8\" : \"#3b82f6\",\n color: \"white\",\n fontSize: 13,\n fontWeight: 600,\n fontFamily: \"inherit\",\n cursor: \"pointer\",\n whiteSpace: \"nowrap\",\n transition: \"background 0.12s ease\",\n flexShrink: 0,\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n }}\n >\n <Camera size={16} strokeWidth={1.9} />\n {label}\n </button>\n );\n}\n\nfunction ControlGroup({\n label,\n children,\n}: {\n label: string;\n children: React.ReactNode;\n}) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"0 4px\",\n }}\n >\n <span\n style={{\n fontSize: 11,\n color: \"rgba(255, 255, 255, 0.42)\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.03em\",\n }}\n >\n {label}\n </span>\n {children}\n </div>\n );\n}\n\nfunction NumInput({\n value,\n onChange,\n}: {\n value: number;\n onChange: (value: string) => void;\n}) {\n const [editing, setEditing] = useState(false);\n const [text, setText] = useState(String(value));\n\n useEffect(() => {\n if (!editing) {\n setText(String(value));\n }\n }, [editing, value]);\n\n return (\n <input\n type=\"text\"\n value={editing ? text : String(value)}\n onFocus={() => {\n setEditing(true);\n setText(String(value));\n }}\n onBlur={() => {\n setEditing(false);\n onChange(text);\n }}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n (e.target as HTMLElement).blur();\n }\n }}\n style={{\n width: 54,\n padding: \"4px 6px\",\n background: \"rgba(255, 255, 255, 0.07)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 7,\n color: \"rgba(255, 255, 255, 0.9)\",\n fontSize: 12,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n textAlign: \"center\",\n outline: \"none\",\n }}\n />\n );\n}\n\nfunction StaticText({ children }: { children: React.ReactNode }) {\n return (\n <span\n style={{\n fontSize: 11,\n color: \"rgba(255,255,255,0.35)\",\n minWidth: 8,\n textAlign: \"center\",\n }}\n >\n {children}\n </span>\n );\n}\n\nfunction DropButton({\n children,\n onClick,\n active,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n active?: boolean;\n}) {\n return (\n <button\n onClick={onClick}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n height: 34,\n padding: \"0 10px\",\n borderRadius: 10,\n border: \"1px solid rgba(255,255,255,0.08)\",\n background: \"rgba(255,255,255,0.04)\",\n color: active ? \"rgba(125, 211, 252, 0.96)\" : \"rgba(255,255,255,0.78)\",\n cursor: \"pointer\",\n fontSize: 12,\n fontFamily: \"inherit\",\n }}\n >\n {children}\n </button>\n );\n}\n\nfunction DropMenu({ children }: { children: React.ReactNode }) {\n return (\n <div\n style={{\n position: \"absolute\",\n bottom: \"calc(100% + 8px)\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n minWidth: 120,\n background: \"rgba(32, 32, 36, 0.96)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 10,\n padding: \"4px 0\",\n boxShadow: \"0 10px 30px rgba(0, 0, 0, 0.3)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n }}\n >\n {children}\n </div>\n );\n}\n\nfunction DropItem({\n children,\n onClick,\n active,\n accent,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n active?: boolean;\n accent?: boolean;\n}) {\n return (\n <button\n onClick={onClick}\n style={{\n display: \"block\",\n width: \"100%\",\n padding: \"7px 12px\",\n background: active ? \"rgba(255, 255, 255, 0.08)\" : \"transparent\",\n border: \"none\",\n color: accent\n ? \"rgba(125, 211, 252, 0.96)\"\n : \"rgba(255, 255, 255, 0.86)\",\n textAlign: \"left\",\n cursor: \"pointer\",\n fontSize: 13,\n fontFamily: \"inherit\",\n }}\n >\n {children}\n </button>\n );\n}\n\nfunction MenuDivider() {\n return (\n <div\n style={{\n height: 1,\n background: \"rgba(255,255,255,0.08)\",\n margin: \"4px 0\",\n }}\n />\n );\n}\n\nfunction Separator({ vertical = true }: { vertical?: boolean }) {\n return (\n <div\n style={{\n width: vertical ? 1 : 24,\n height: vertical ? 24 : 1,\n background: \"rgba(255,255,255,0.12)\",\n flexShrink: 0,\n }}\n />\n );\n}\n\nfunction circleButtonStyle(active: boolean, round: boolean) {\n return {\n width: 40,\n height: 40,\n borderRadius: round ? \"50%\" : 12,\n border: \"none\",\n background: active ? \"rgba(255, 255, 255, 0.12)\" : \"transparent\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n padding: 0,\n transition: \"background 0.12s ease, color 0.12s ease\",\n marginRight: round ? 6 : 0,\n } as const;\n}\n","\"use client\";\n\nimport React, { useRef, useCallback, useEffect, useMemo, useState } from \"react\";\n\ninterface SelectorProps {\n rect: AreaRect | null;\n aspect: AreaAspectLabel;\n magnetEnabled: boolean;\n onRectChange: (rect: AreaRect | null) => void;\n onSelect: (area: {\n x: number;\n y: number;\n width: number;\n height: number;\n }) => void;\n onCancel: () => void;\n}\n\ntype Corner = \"tl\" | \"tr\" | \"bl\" | \"br\";\ntype DragMode = \"none\" | \"drawing\" | \"moving\" | \"resizing\";\n\nexport interface AreaRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport type AreaAspectLabel = \"Free\" | \"16:9\" | \"4:3\" | \"1:1\" | \"3:2\" | \"21:9\";\n\nexport const DEFAULT_AREA_ASPECT: AreaAspectLabel = \"16:9\";\n\nexport const AREA_ASPECT_RATIOS: { label: AreaAspectLabel; value: number }[] = [\n { label: \"Free\", value: 0 },\n { label: \"16:9\", value: 16 / 9 },\n { label: \"4:3\", value: 4 / 3 },\n { label: \"1:1\", value: 1 },\n { label: \"3:2\", value: 3 / 2 },\n { label: \"21:9\", value: 21 / 9 },\n];\n\nconst HANDLE_R = 6;\nconst HANDLE_HIT = 16;\nconst MIN_SIZE = 20;\nconst SNAP_THRESHOLD = 8;\n\nconst CAMERA_CURSOR = `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='%23e0f2fe' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7h3l1.5-2h7L17 7h3a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2Z'/%3E%3Ccircle cx='12' cy='13' r='4'/%3E%3C/svg%3E\") 12 12, crosshair`;\n\nexport function createInitialAreaRect(): AreaRect {\n const safeWidth = Math.max(320, window.innerWidth - 96);\n const safeHeight = Math.max(180, window.innerHeight - 220);\n const w = Math.min(window.innerWidth * 0.72, safeHeight * (16 / 9), safeWidth);\n const h = w / (16 / 9);\n\n return {\n x: (window.innerWidth - w) / 2,\n y: Math.max(40, (window.innerHeight - h) / 2 - 20),\n w,\n h,\n };\n}\n\nfunction getAspectRatio(label: AreaAspectLabel): number {\n return AREA_ASPECT_RATIOS.find((item) => item.label === label)?.value ?? 0;\n}\n\nexport function Selector({\n rect,\n aspect,\n magnetEnabled,\n onRectChange,\n onSelect,\n onCancel,\n}: SelectorProps) {\n const [snappedX, setSnappedX] = useState(false);\n const [cursor, setCursor] = useState(\"crosshair\");\n const mode = useRef<DragMode>(\"none\");\n const start = useRef({ x: 0, y: 0 });\n const snapRef = useRef<AreaRect>({ x: 0, y: 0, w: 0, h: 0 });\n const corner = useRef<Corner>(\"br\");\n const ratio = useMemo(() => getAspectRatio(aspect), [aspect]);\n\n const applySnap = useCallback(\n (nextRect: AreaRect): AreaRect => {\n if (!magnetEnabled) {\n setSnappedX(false);\n return nextRect;\n }\n\n const centerX = nextRect.x + nextRect.w / 2;\n const viewportCenterX = window.innerWidth / 2;\n\n if (Math.abs(centerX - viewportCenterX) < SNAP_THRESHOLD) {\n setSnappedX(true);\n return { ...nextRect, x: viewportCenterX - nextRect.w / 2 };\n }\n\n setSnappedX(false);\n return nextRect;\n },\n [magnetEnabled],\n );\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n onCancel();\n }\n };\n\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [onCancel]);\n\n const hitCorner = useCallback((mx: number, my: number, currentRect: AreaRect): Corner | null => {\n const corners: [Corner, number, number][] = [\n [\"tl\", currentRect.x, currentRect.y],\n [\"tr\", currentRect.x + currentRect.w, currentRect.y],\n [\"bl\", currentRect.x, currentRect.y + currentRect.h],\n [\"br\", currentRect.x + currentRect.w, currentRect.y + currentRect.h],\n ];\n\n for (const [hitCorner, cx, cy] of corners) {\n if (Math.abs(mx - cx) <= HANDLE_HIT && Math.abs(my - cy) <= HANDLE_HIT) {\n return hitCorner;\n }\n }\n\n return null;\n }, []);\n\n const hitInside = useCallback(\n (mx: number, my: number, currentRect: AreaRect) =>\n mx >= currentRect.x &&\n mx <= currentRect.x + currentRect.w &&\n my >= currentRect.y &&\n my <= currentRect.y + currentRect.h,\n [],\n );\n\n const onDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const mx = e.clientX;\n const my = e.clientY;\n\n if (rect) {\n const activeCorner = hitCorner(mx, my, rect);\n if (activeCorner) {\n mode.current = \"resizing\";\n corner.current = activeCorner;\n start.current = { x: mx, y: my };\n snapRef.current = { ...rect };\n return;\n }\n\n if (hitInside(mx, my, rect)) {\n mode.current = \"moving\";\n start.current = { x: mx, y: my };\n snapRef.current = { ...rect };\n return;\n }\n }\n\n mode.current = \"drawing\";\n start.current = { x: mx, y: my };\n onRectChange({ x: mx, y: my, w: 0, h: 0 });\n },\n [hitCorner, hitInside, onRectChange, rect],\n );\n\n const onMove = useCallback(\n (e: React.MouseEvent) => {\n const mx = e.clientX;\n const my = e.clientY;\n\n if (mode.current === \"none\") {\n if (rect) {\n const activeCorner = hitCorner(mx, my, rect);\n if (activeCorner) {\n setCursor(\n activeCorner === \"tl\" || activeCorner === \"br\"\n ? \"nwse-resize\"\n : \"nesw-resize\",\n );\n } else if (hitInside(mx, my, rect)) {\n setCursor(CAMERA_CURSOR);\n } else {\n setCursor(\"crosshair\");\n }\n } else {\n setCursor(\"crosshair\");\n }\n return;\n }\n\n if (mode.current === \"drawing\") {\n const sx = start.current.x;\n const sy = start.current.y;\n let x = Math.min(sx, mx);\n let y = Math.min(sy, my);\n let w = Math.abs(mx - sx);\n let h = Math.abs(my - sy);\n\n if (ratio > 0) {\n h = w / ratio;\n if (my < sy) {\n y = sy - h;\n }\n }\n\n onRectChange(applySnap({ x, y, w, h }));\n return;\n }\n\n if (mode.current === \"moving\") {\n const dx = mx - start.current.x;\n const dy = my - start.current.y;\n onRectChange(\n applySnap({\n ...snapRef.current,\n x: snapRef.current.x + dx,\n y: snapRef.current.y + dy,\n }),\n );\n return;\n }\n\n if (mode.current === \"resizing\") {\n const original = snapRef.current;\n const nextRect = { ...original };\n\n if (corner.current === \"br\") {\n nextRect.w = Math.max(MIN_SIZE, mx - original.x);\n nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);\n } else if (corner.current === \"bl\") {\n nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);\n nextRect.x = original.x + original.w - nextRect.w;\n nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);\n } else if (corner.current === \"tr\") {\n nextRect.w = Math.max(MIN_SIZE, mx - original.x);\n nextRect.h =\n ratio > 0\n ? nextRect.w / ratio\n : Math.max(MIN_SIZE, original.y + original.h - my);\n nextRect.y = original.y + original.h - nextRect.h;\n } else {\n nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);\n nextRect.h =\n ratio > 0\n ? nextRect.w / ratio\n : Math.max(MIN_SIZE, original.y + original.h - my);\n nextRect.x = original.x + original.w - nextRect.w;\n nextRect.y = original.y + original.h - nextRect.h;\n }\n\n onRectChange(applySnap(nextRect));\n }\n },\n [applySnap, hitCorner, hitInside, onRectChange, ratio, rect],\n );\n\n const onUp = useCallback(\n (e: React.MouseEvent) => {\n const previousMode = mode.current;\n\n if (previousMode === \"drawing\" && rect) {\n if (rect.w < MIN_SIZE || rect.h < MIN_SIZE) {\n onRectChange(null);\n }\n }\n\n if (previousMode === \"moving\" && rect) {\n const dx = Math.abs(e.clientX - start.current.x);\n const dy = Math.abs(e.clientY - start.current.y);\n if (dx < 3 && dy < 3) {\n onSelect({\n x: Math.round(rect.x),\n y: Math.round(rect.y),\n width: Math.round(rect.w),\n height: Math.round(rect.h),\n });\n }\n }\n\n mode.current = \"none\";\n },\n [onRectChange, onSelect, rect],\n );\n\n const hasRect = rect && rect.w > 0 && rect.h > 0;\n\n return (\n <div\n data-afterbefore=\"true\"\n onMouseDown={onDown}\n onMouseMove={onMove}\n onMouseUp={onUp}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483646,\n cursor,\n }}\n >\n {snappedX && (\n <div\n style={{\n position: \"absolute\",\n left: \"50%\",\n top: 0,\n bottom: 0,\n width: 0,\n borderLeft: \"1px solid rgba(56, 189, 248, 0.55)\",\n pointerEvents: \"none\",\n zIndex: 2,\n }}\n />\n )}\n\n {hasRect ? (\n <>\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: 0,\n width: \"100%\",\n height: rect.y,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: rect.y,\n width: rect.x,\n height: rect.h,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: rect.x + rect.w,\n top: rect.y,\n width: `calc(100% - ${rect.x + rect.w}px)`,\n height: rect.h,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: rect.y + rect.h,\n width: \"100%\",\n height: `calc(100% - ${rect.y + rect.h}px)`,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y,\n width: rect.w,\n height: rect.h,\n background: \"rgba(125, 211, 252, 0.08)\",\n pointerEvents: \"none\",\n borderRadius: 12,\n }}\n />\n\n <div\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y,\n width: rect.w,\n height: rect.h,\n border: \"1.5px dashed rgba(255, 255, 255, 0.45)\",\n borderRadius: 12,\n pointerEvents: \"none\",\n boxShadow: \"0 0 0 1px rgba(125, 211, 252, 0.38)\",\n }}\n />\n\n {[1, 2].map((line) => (\n <React.Fragment key={line}>\n <div\n style={{\n position: \"absolute\",\n left: rect.x + (rect.w * line) / 3,\n top: rect.y,\n width: 0,\n height: rect.h,\n borderLeft: \"1px dashed rgba(255, 255, 255, 0.18)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y + (rect.h * line) / 3,\n width: rect.w,\n height: 0,\n borderTop: \"1px dashed rgba(255, 255, 255, 0.18)\",\n pointerEvents: \"none\",\n }}\n />\n </React.Fragment>\n ))}\n\n {(\n [\n [rect.x, rect.y],\n [rect.x + rect.w, rect.y],\n [rect.x, rect.y + rect.h],\n [rect.x + rect.w, rect.y + rect.h],\n ] as [number, number][]\n ).map(([cx, cy], index) => (\n <div\n key={index}\n style={{\n position: \"absolute\",\n left: cx - HANDLE_R,\n top: cy - HANDLE_R,\n width: HANDLE_R * 2,\n height: HANDLE_R * 2,\n borderRadius: \"50%\",\n border: \"2px solid rgba(255, 255, 255, 0.8)\",\n background: \"rgba(0, 0, 0, 0.25)\",\n pointerEvents: \"none\",\n }}\n />\n ))}\n </>\n ) : (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useEffect, useRef, useCallback, useState } from \"react\";\n\ninterface InspectorProps {\n onSelect: (element: HTMLElement) => void;\n onCancel: () => void;\n}\n\nexport function Inspector({ onSelect, onCancel }: InspectorProps) {\n const [highlight, setHighlight] = useState<{\n x: number;\n y: number;\n width: number;\n height: number;\n tag: string;\n } | null>(null);\n const hoveredEl = useRef<HTMLElement | null>(null);\n const styleEl = useRef<HTMLStyleElement | null>(null);\n\n // Inject global crosshair cursor style\n useEffect(() => {\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-afterbefore\", \"true\");\n style.textContent = \"*, *::before, *::after { cursor: crosshair !important; }\";\n document.head.appendChild(style);\n styleEl.current = style;\n return () => {\n style.remove();\n };\n }, []);\n\n const isOverlayElement = useCallback((el: Element | null): boolean => {\n let node = el;\n while (node) {\n if (node instanceof HTMLElement && node.dataset.afterbefore) return true;\n node = node.parentElement;\n }\n return false;\n }, []);\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => {\n const el = document.elementFromPoint(e.clientX, e.clientY);\n if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {\n setHighlight(null);\n hoveredEl.current = null;\n return;\n }\n hoveredEl.current = el;\n const rect = el.getBoundingClientRect();\n setHighlight({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n tag: el.tagName.toLowerCase() + (el.className && typeof el.className === \"string\" ? `.${el.className.split(\" \")[0]}` : \"\"),\n });\n },\n [isOverlayElement],\n );\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n if (hoveredEl.current) {\n onSelect(hoveredEl.current);\n }\n },\n [onSelect],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n onCancel();\n }\n },\n [onCancel],\n );\n\n useEffect(() => {\n document.addEventListener(\"mousemove\", handleMouseMove, true);\n document.addEventListener(\"click\", handleClick, true);\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n document.removeEventListener(\"mousemove\", handleMouseMove, true);\n document.removeEventListener(\"click\", handleClick, true);\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [handleMouseMove, handleClick, handleKeyDown]);\n\n return (\n <div data-afterbefore=\"true\" style={{ position: \"fixed\", inset: 0, zIndex: 2147483646, pointerEvents: \"none\" }}>\n {highlight && (\n <>\n {/* Highlight overlay */}\n <div\n style={{\n position: \"fixed\",\n left: highlight.x,\n top: highlight.y,\n width: highlight.width,\n height: highlight.height,\n background: \"rgba(59, 130, 246, 0.15)\",\n border: \"2px solid rgba(59, 130, 246, 0.7)\",\n borderRadius: 2,\n pointerEvents: \"none\",\n }}\n />\n {/* Tag label */}\n <div\n style={{\n position: \"fixed\",\n left: highlight.x,\n top: Math.max(0, highlight.y - 24),\n background: \"rgba(59, 130, 246, 0.9)\",\n color: \"#fff\",\n fontSize: 11,\n fontFamily: \"system-ui, -apple-system, monospace\",\n padding: \"2px 6px\",\n borderRadius: 3,\n pointerEvents: \"none\",\n whiteSpace: \"nowrap\",\n lineHeight: \"18px\",\n }}\n >\n {highlight.tag}\n </div>\n </>\n )}\n\n {/* Instruction hint */}\n {!highlight && (\n <div\n style={{\n position: \"fixed\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n color: \"rgba(255, 255, 255, 0.7)\",\n fontSize: 14,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n pointerEvents: \"none\",\n textShadow: \"0 1px 4px rgba(0, 0, 0, 0.5)\",\n background: \"rgba(0, 0, 0, 0.5)\",\n padding: \"8px 16px\",\n borderRadius: 8,\n }}\n >\n Hover to inspect · Click to capture · Esc to cancel\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect, useCallback } from \"react\";\n\ninterface StatusProps {\n onReset: () => void;\n position: { x: number; y: number };\n onClose: () => void;\n}\n\ninterface Toast {\n message: string;\n type: \"success\" | \"error\";\n}\n\nconst PANEL_WIDTH = 220;\n\nexport function Status({ onReset, position, onClose }: StatusProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n const [toast, setToast] = useState<Toast | null>(null);\n const [pushing, setPushing] = useState(false);\n\n const showToast = useCallback((message: string, type: Toast[\"type\"]) => {\n setToast({ message, type });\n setTimeout(() => setToast(null), 3000);\n }, []);\n\n // Click outside to close\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (panelRef.current && !panelRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [onClose]);\n\n // Escape to close\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [onClose]);\n\n const handleOpenFolder = async () => {\n try {\n const res = await fetch(\"/__afterbefore/open\", { method: \"POST\" });\n if (!res.ok) throw new Error();\n showToast(\"Opened folder\", \"success\");\n } catch {\n showToast(\"Could not open folder\", \"error\");\n }\n };\n\n const handleCopyMarkdown = async () => {\n try {\n const res = await fetch(\"/__afterbefore/markdown\");\n if (!res.ok) throw new Error();\n const { markdown } = await res.json();\n await navigator.clipboard.writeText(markdown);\n showToast(\"Copied!\", \"success\");\n } catch {\n showToast(\"Copy failed\", \"error\");\n }\n };\n\n const handlePush = async () => {\n setPushing(true);\n try {\n const res = await fetch(\"/__afterbefore/push\", { method: \"POST\" });\n const data = await res.json();\n if (!res.ok) {\n showToast(data.error || \"Push failed\", \"error\");\n } else if (data.pr) {\n showToast(`Posted to PR #${data.pr}`, \"success\");\n } else {\n showToast(\"No PR found\", \"error\");\n }\n } catch {\n showToast(\"Push failed\", \"error\");\n } finally {\n setPushing(false);\n }\n };\n\n const handleReset = () => {\n onReset();\n onClose();\n };\n\n const panelLeft = Math.max(\n 8,\n Math.min(position.x - PANEL_WIDTH / 2 + 20, window.innerWidth - PANEL_WIDTH - 8),\n );\n const panelBottom = window.innerHeight - position.y + 8;\n\n const buttonStyle: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n padding: \"7px 10px\",\n border: \"none\",\n background: \"transparent\",\n color: \"rgba(255,255,255,0.9)\",\n fontSize: 13,\n borderRadius: 6,\n cursor: \"pointer\",\n textAlign: \"left\" as const,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n transition: \"background 0.1s\",\n };\n\n const onEnter = (e: React.MouseEvent) => {\n (e.currentTarget as HTMLButtonElement).style.background =\n \"rgba(255,255,255,0.1)\";\n };\n const onLeave = (e: React.MouseEvent) => {\n (e.currentTarget as HTMLButtonElement).style.background = \"transparent\";\n };\n\n return (\n <div\n ref={panelRef}\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n left: panelLeft,\n bottom: panelBottom,\n width: PANEL_WIDTH,\n background: \"rgba(24, 24, 27, 0.95)\",\n borderRadius: 10,\n boxShadow:\n \"0 4px 20px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.08)\",\n zIndex: 2147483647,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n backdropFilter: \"blur(12px)\",\n overflow: \"hidden\",\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"10px 12px 6px\",\n fontSize: 12,\n fontWeight: 600,\n color: \"rgba(255,255,255,0.5)\",\n letterSpacing: \"0.02em\",\n }}\n >\n Before &amp; After captured\n </div>\n\n {/* Actions */}\n <div style={{ padding: \"0 4px 4px\" }}>\n <button\n style={buttonStyle}\n onClick={handleOpenFolder}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <FolderIcon />\n Open Folder\n </button>\n <button\n style={buttonStyle}\n onClick={handleCopyMarkdown}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <CopyIcon />\n Copy Markdown\n </button>\n <button\n style={buttonStyle}\n onClick={handlePush}\n disabled={pushing}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <PushIcon />\n {pushing ? \"Pushing...\" : \"Push to PR\"}\n </button>\n\n {/* Separator */}\n <div\n style={{\n height: 1,\n background: \"rgba(255,255,255,0.08)\",\n margin: \"4px 6px\",\n }}\n />\n\n <button\n style={{ ...buttonStyle, color: \"rgba(255,255,255,0.5)\" }}\n onClick={handleReset}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <ResetIcon />\n Reset\n </button>\n </div>\n\n {/* Toast */}\n {toast && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"100%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n marginBottom: 8,\n padding: \"6px 12px\",\n borderRadius: 6,\n fontSize: 12,\n fontWeight: 500,\n whiteSpace: \"nowrap\",\n color: \"white\",\n background:\n toast.type === \"success\"\n ? \"rgba(34, 197, 94, 0.9)\"\n : \"rgba(239, 68, 68, 0.9)\",\n boxShadow: \"0 2px 8px rgba(0,0,0,0.3)\",\n }}\n >\n {toast.message}\n </div>\n )}\n </div>\n );\n}\n\nfunction FolderIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.5)\" }}\n >\n <path\n d=\"M1.5 3A1.5 1.5 0 013 1.5h2.38a1 1 0 01.72.3L7 2.72a1 1 0 00.72.3H11A1.5 1.5 0 0112.5 4.5v6A1.5 1.5 0 0111 12H3A1.5 1.5 0 011.5 10.5V3z\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n />\n </svg>\n );\n}\n\nfunction CopyIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.5)\" }}\n >\n <rect\n x=\"4\"\n y=\"4\"\n width=\"8.5\"\n height=\"8.5\"\n rx=\"1.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n />\n <path\n d=\"M10 4V2.5A1.5 1.5 0 008.5 1h-6A1.5 1.5 0 001 2.5v6A1.5 1.5 0 002.5 10H4\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n />\n </svg>\n );\n}\n\nfunction PushIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.5)\" }}\n >\n <path\n d=\"M7 11V3m0 0L4 6m3-3l3 3\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nfunction ResetIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.4)\" }}\n >\n <path\n d=\"M2.5 7a4.5 4.5 0 118 2.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M2.5 3v4h4\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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","names":["useState","useCallback","useRef","useEffect","useCallback","useState","useEffect","useState","jsx","useEffect","useState","Camera","React","useRef","useCallback","useEffect","useState","jsx","jsxs","CAMERA_CURSOR","hitCorner","Fragment","jsx","jsxs","useState","useEffect","Icon","Camera","useEffect","useRef","useCallback","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","jsx","jsxs","jsx","jsxs","useState","useRef","useEffect","useCallback"]}
1
+ {"version":3,"sources":["../../src/overlay/index.tsx","../../src/overlay/state.ts","../../src/overlay/capture.ts","../../src/overlay/ui/icon.tsx","../../src/overlay/ui/preview.tsx","../../src/overlay/ui/toolbar.tsx","../../src/overlay/ui/selector.tsx","../../src/overlay/ui/inspector.tsx","../../src/overlay/ui/status.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useState, useCallback, useRef, useEffect } from \"react\";\nimport { useOverlayState } from \"./state\";\nimport type { CaptureMode } from \"./state\";\nimport { capture } from \"./capture\";\nimport { Icon } from \"./ui/icon\";\nimport { CapturePreview } from \"./ui/preview\";\nimport { Toolbar } from \"./ui/toolbar\";\nimport {\n Selector,\n type AreaAspectLabel,\n type AreaRect,\n DEFAULT_AREA_ASPECT,\n createInitialAreaRect,\n} from \"./ui/selector\";\nimport { Inspector } from \"./ui/inspector\";\nimport { Status } from \"./ui/status\";\n\nasync function saveCapture(\n type: \"before\" | \"after\",\n mode: CaptureMode,\n dataUrl: string,\n) {\n try {\n const res = await fetch(\"/__afterbefore/save\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ type, mode, image: dataUrl }),\n });\n if (!res.ok) throw new Error(\"Save failed\");\n } catch {\n // Fallback: browser download (no branch info available client-side)\n const link = document.createElement(\"a\");\n link.download = `${type}.png`;\n link.href = dataUrl;\n link.click();\n }\n}\n\nexport function AfterBefore() {\n const { state, captureComplete, reset } = useOverlayState();\n const [statusOpen, setStatusOpen] = useState(false);\n const [toolbarActive, setToolbarActive] = useState(false);\n const [selectorActive, setSelectorActive] = useState(false);\n const [inspectorActive, setInspectorActive] = useState(false);\n const [loading, setLoading] = useState(false);\n const [selectedMode, setSelectedMode] = useState<CaptureMode>(\"component\");\n const [magnetEnabled, setMagnetEnabled] = useState(true);\n const [areaRect, setAreaRect] = useState<AreaRect | null>(null);\n const [areaAspect, setAreaAspect] = useState<AreaAspectLabel>(DEFAULT_AREA_ASPECT);\n const [areaPresets, setAreaPresets] = useState<{ label: string; rect: AreaRect }[]>([]);\n const [frameOnBlackEnabled, setFrameOnBlackEnabled] = useState(false);\n const iconPos = useRef<{ x: number; y: number }>({ x: 24, y: 0 });\n\n useEffect(() => {\n try {\n setMagnetEnabled(localStorage.getItem(\"ab-magnet\") !== \"false\");\n } catch {\n setMagnetEnabled(true);\n }\n\n try {\n const savedPresets = localStorage.getItem(\"ab-area-presets\");\n setAreaPresets(savedPresets ? JSON.parse(savedPresets) : []);\n } catch {\n setAreaPresets([]);\n }\n\n try {\n setFrameOnBlackEnabled(localStorage.getItem(\"ab-frame-black\") === \"true\");\n } catch {\n setFrameOnBlackEnabled(false);\n }\n }, []);\n\n useEffect(() => {\n if (state.phase === \"ready\") {\n const timer = setTimeout(() => {\n reset();\n setStatusOpen(false);\n }, 1500);\n return () => clearTimeout(timer);\n }\n }, [state.phase, reset]);\n\n const handlePositionChange = useCallback(\n (pos: { x: number; y: number }) => {\n iconPos.current = pos;\n },\n [],\n );\n\n const handleIconClick = useCallback(() => {\n if (loading) return;\n\n if (state.phase === \"ready\") {\n setStatusOpen((prev: boolean) => !prev);\n } else if (toolbarActive || inspectorActive) {\n setToolbarActive(false);\n setSelectorActive(false);\n setInspectorActive(false);\n setStatusOpen(false);\n } else {\n setStatusOpen(false);\n if (selectedMode === \"component\") {\n setInspectorActive(true);\n } else {\n setToolbarActive(true);\n setInspectorActive(false);\n if (selectedMode === \"area\") {\n setSelectorActive(true);\n setAreaRect(createInitialAreaRect());\n setAreaAspect(DEFAULT_AREA_ASPECT);\n }\n }\n }\n }, [state.phase, loading, toolbarActive, inspectorActive, selectedMode]);\n\n const performCapture = useCallback(\n async (\n mode: CaptureMode,\n area?: { x: number; y: number; width: number; height: number },\n element?: HTMLElement,\n ) => {\n setLoading(true);\n try {\n const dataUrl = await capture({ mode, area, element, frameOnBlack: frameOnBlackEnabled });\n const type = state.phase === \"idle\" ? \"before\" : \"after\";\n await saveCapture(type, mode, dataUrl);\n captureComplete({\n dataUrl,\n mode,\n timestamp: Date.now(),\n });\n } catch (err) {\n console.error(\"[afterbefore] Capture failed:\", err);\n } finally {\n setLoading(false);\n }\n },\n [state.phase, captureComplete, frameOnBlackEnabled],\n );\n\n const handleToolbarCapture = useCallback(\n (mode: CaptureMode) => {\n if (mode === \"area\") {\n if (areaRect) {\n setSelectorActive(false);\n setToolbarActive(false);\n performCapture(\"area\", {\n x: Math.round(areaRect.x),\n y: Math.round(areaRect.y),\n width: Math.round(areaRect.w),\n height: Math.round(areaRect.h),\n });\n }\n return;\n } else if (mode === \"viewport\") {\n setToolbarActive(false);\n performCapture(\"viewport\");\n } else if (mode === \"fullpage\") {\n setToolbarActive(false);\n performCapture(\"fullpage\");\n } else if (mode === \"component\") {\n setToolbarActive(false);\n setInspectorActive(true);\n }\n },\n [areaRect, performCapture],\n );\n\n const handleToolbarCancel = useCallback(() => {\n setToolbarActive(false);\n setSelectorActive(false);\n }, []);\n\n const handleComponentSelect = useCallback(\n (element: HTMLElement) => {\n setInspectorActive(false);\n performCapture(\"component\", undefined, element);\n },\n [performCapture],\n );\n\n const handleComponentCancel = useCallback(() => {\n setInspectorActive(false);\n setToolbarActive(true);\n }, []);\n\n const handleAreaSelect = useCallback(\n (area: { x: number; y: number; width: number; height: number }) => {\n setSelectorActive(false);\n setToolbarActive(false);\n performCapture(\"area\", area);\n },\n [performCapture],\n );\n\n const handleAreaCancel = useCallback(() => {\n setSelectorActive(false);\n setToolbarActive(true);\n }, []);\n\n const handleMagnetChange = useCallback((enabled: boolean) => {\n setMagnetEnabled(enabled);\n try {\n localStorage.setItem(\"ab-magnet\", String(enabled));\n } catch {\n // noop\n }\n }, []);\n\n const handleFrameOnBlackChange = useCallback((enabled: boolean) => {\n setFrameOnBlackEnabled(enabled);\n try {\n localStorage.setItem(\"ab-frame-black\", String(enabled));\n } catch {\n // noop\n }\n }, []);\n\n const handleModeChange = useCallback((mode: CaptureMode) => {\n setSelectedMode(mode);\n if (mode === \"area\") {\n setSelectorActive(true);\n setAreaRect(createInitialAreaRect());\n setAreaAspect(DEFAULT_AREA_ASPECT);\n } else if (mode === \"component\") {\n setSelectorActive(false);\n setToolbarActive(false);\n setInspectorActive(true);\n } else {\n setSelectorActive(false);\n }\n }, []);\n\n const handleAreaRectChange = useCallback((nextRect: AreaRect | null) => {\n setAreaRect(nextRect);\n }, []);\n\n const handleAreaSizeChange = useCallback(\n (field: \"w\" | \"h\", value: string) => {\n const nextValue = parseInt(value, 10);\n if (Number.isNaN(nextValue) || nextValue < 20 || !areaRect) {\n return;\n }\n\n const aspectRatio =\n areaAspect === \"Free\"\n ? 0\n : ({ \"16:9\": 16 / 9, \"4:3\": 4 / 3, \"1:1\": 1, \"3:2\": 3 / 2, \"21:9\": 21 / 9 } as const)[areaAspect];\n\n if (field === \"w\") {\n setAreaRect({\n ...areaRect,\n w: nextValue,\n h: aspectRatio > 0 ? nextValue / aspectRatio : areaRect.h,\n });\n } else {\n setAreaRect({\n ...areaRect,\n h: nextValue,\n w: aspectRatio > 0 ? nextValue * aspectRatio : areaRect.w,\n });\n }\n },\n [areaAspect, areaRect],\n );\n\n const handleAreaPositionChange = useCallback(\n (field: \"x\" | \"y\", value: string) => {\n const nextValue = parseInt(value, 10);\n if (Number.isNaN(nextValue) || !areaRect) {\n return;\n }\n\n setAreaRect({ ...areaRect, [field]: nextValue });\n },\n [areaRect],\n );\n\n const handleAreaAspectChange = useCallback(\n (nextAspect: AreaAspectLabel) => {\n setAreaAspect(nextAspect);\n if (!areaRect || nextAspect === \"Free\") {\n return;\n }\n\n const aspectRatio = ({ \"16:9\": 16 / 9, \"4:3\": 4 / 3, \"1:1\": 1, \"3:2\": 3 / 2, \"21:9\": 21 / 9 } as const)[nextAspect];\n setAreaRect({ ...areaRect, h: areaRect.w / aspectRatio });\n },\n [areaRect],\n );\n\n const handleAreaSavePreset = useCallback(() => {\n if (!areaRect) {\n return;\n }\n\n const label = `${Math.round(areaRect.w)}x${Math.round(areaRect.h)}`;\n const nextPresets = [\n ...areaPresets.filter((preset) => preset.label !== label),\n { label, rect: { ...areaRect } },\n ];\n\n setAreaPresets(nextPresets);\n try {\n localStorage.setItem(\"ab-area-presets\", JSON.stringify(nextPresets));\n } catch {\n // noop\n }\n }, [areaPresets, areaRect]);\n\n const handleAreaLoadPreset = useCallback((preset: { label: string; rect: AreaRect }) => {\n setAreaRect({ ...preset.rect });\n }, []);\n\n const handleReset = useCallback(() => {\n reset();\n setStatusOpen(false);\n }, [reset]);\n\n const handleStatusClose = useCallback(() => {\n setStatusOpen(false);\n }, []);\n\n return (\n <div data-afterbefore=\"true\">\n <Icon\n phase={state.phase}\n onClick={handleIconClick}\n loading={loading}\n onPositionChange={handlePositionChange}\n />\n\n {toolbarActive && !selectorActive && !inspectorActive && !loading && (\n <CapturePreview\n mode={selectedMode}\n onClick={() => handleToolbarCapture(selectedMode)}\n />\n )}\n\n {toolbarActive && !inspectorActive && (\n <Toolbar\n selectedMode={selectedMode}\n onModeChange={handleModeChange}\n onCapture={handleToolbarCapture}\n onCancel={handleToolbarCancel}\n magnetEnabled={magnetEnabled}\n onMagnetChange={handleMagnetChange}\n areaSelectionActive={selectorActive}\n areaRect={areaRect}\n areaAspect={areaAspect}\n areaPresets={areaPresets}\n onAreaSizeChange={handleAreaSizeChange}\n onAreaPositionChange={handleAreaPositionChange}\n onAreaAspectChange={handleAreaAspectChange}\n onAreaSavePreset={handleAreaSavePreset}\n onAreaLoadPreset={handleAreaLoadPreset}\n frameOnBlackEnabled={frameOnBlackEnabled}\n onFrameOnBlackChange={handleFrameOnBlackChange}\n />\n )}\n\n {selectorActive && (\n <Selector\n rect={areaRect}\n aspect={areaAspect}\n onRectChange={handleAreaRectChange}\n onSelect={handleAreaSelect}\n onCancel={handleAreaCancel}\n magnetEnabled={magnetEnabled}\n />\n )}\n\n {inspectorActive && (\n <Inspector onSelect={handleComponentSelect} onCancel={handleComponentCancel} />\n )}\n\n {statusOpen && state.phase === \"ready\" && (\n <Status\n onReset={handleReset}\n position={iconPos.current}\n onClose={handleStatusClose}\n />\n )}\n </div>\n );\n}\n","import { useState, useCallback } from \"react\";\n\nexport type CaptureMode = \"viewport\" | \"fullpage\" | \"area\" | \"component\";\n\nexport type OverlayPhase = \"idle\" | \"captured-before\" | \"ready\";\n\nexport interface CaptureResult {\n dataUrl: string;\n mode: CaptureMode;\n timestamp: number;\n}\n\nexport interface OverlayState {\n phase: OverlayPhase;\n before: CaptureResult | null;\n after: CaptureResult | null;\n}\n\nconst initialState: OverlayState = {\n phase: \"idle\",\n before: null,\n after: null,\n};\n\nexport function useOverlayState() {\n const [state, setState] = useState<OverlayState>(initialState);\n\n const captureComplete = useCallback(\n (result: CaptureResult) => {\n setState((prev) => {\n if (prev.phase === \"idle\") {\n return { ...prev, phase: \"captured-before\", before: result };\n }\n if (prev.phase === \"captured-before\") {\n return { ...prev, phase: \"ready\", after: result };\n }\n return prev;\n });\n },\n [],\n );\n\n const reset = useCallback(() => {\n setState(initialState);\n }, []);\n\n return { state, captureComplete, reset };\n}\n","import { snapdom } from \"@zumer/snapdom\";\nimport type { CaptureMode } from \"./state\";\n\ninterface CaptureOptions {\n mode: CaptureMode;\n area?: { x: number; y: number; width: number; height: number };\n element?: HTMLElement;\n frameOnBlack?: boolean;\n}\n\n/** Selectors for dev tool UI that should be excluded from capture */\nconst DEV_UI_SELECTORS = [\n // Afterbefore overlay\n \"[data-afterbefore]\",\n // Next.js dev indicators\n \"[data-nextjs-toast]\",\n \"[data-nextjs-dev-overlay]\",\n \"[data-nextjs-dialog]\",\n \"[data-nextjs-dialog-backdrop]\",\n \"[data-next-badge]\",\n \"[data-next-mark]\",\n];\n\nconst SNAPDOM_BASE = {\n exclude: DEV_UI_SELECTORS,\n excludeMode: \"remove\" as const,\n};\n\nasync function toPngDataUrl(\n el: Element,\n opts?: Record<string, unknown>,\n): Promise<string> {\n const result = await snapdom(el, { ...SNAPDOM_BASE, ...opts });\n const img = await result.toPng();\n return img.src;\n}\n\nexport async function capture(options: CaptureOptions): Promise<string> {\n const { mode, area, element } = options;\n\n if (mode === \"viewport\") {\n return captureViewport();\n }\n if (mode === \"fullpage\") {\n return captureFullPage();\n }\n if (mode === \"area\" && area) {\n return captureArea(area);\n }\n if (mode === \"component\" && element) {\n return captureComponent(element, options.frameOnBlack);\n }\n throw new Error(`Invalid capture mode: ${mode}`);\n}\n\nasync function captureViewport(): Promise<string> {\n const dpr = window.devicePixelRatio || 1;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const scrollY = window.scrollY;\n\n // snapdom renders the full element content, so capture full page and crop to viewport\n const fullDataUrl = await captureFullPage();\n const img = await loadImage(fullDataUrl);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = vw * dpr;\n canvas.height = vh * dpr;\n\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(\n img,\n 0,\n scrollY * dpr,\n vw * dpr,\n vh * dpr,\n 0,\n 0,\n vw * dpr,\n vh * dpr,\n );\n\n return canvas.toDataURL(\"image/png\");\n}\n\nasync function captureFullPage(): Promise<string> {\n const scrollY = window.scrollY;\n const body = document.body;\n const html = document.documentElement;\n\n const fullHeight = Math.max(\n body.scrollHeight,\n body.offsetHeight,\n html.clientHeight,\n html.scrollHeight,\n html.offsetHeight,\n );\n\n const prevOverflow = html.style.overflow;\n const prevHeight = html.style.height;\n html.style.overflow = \"visible\";\n html.style.height = `${fullHeight}px`;\n\n try {\n return await toPngDataUrl(document.documentElement, {\n width: window.innerWidth,\n height: fullHeight,\n });\n } finally {\n html.style.overflow = prevOverflow;\n html.style.height = prevHeight;\n window.scrollTo(0, scrollY);\n }\n}\n\nasync function captureArea(area: {\n x: number;\n y: number;\n width: number;\n height: number;\n}): Promise<string> {\n const fullDataUrl = await captureViewport();\n\n const img = await loadImage(fullDataUrl);\n const dpr = window.devicePixelRatio || 1;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = area.width * dpr;\n canvas.height = area.height * dpr;\n\n const ctx = canvas.getContext(\"2d\")!;\n ctx.drawImage(\n img,\n area.x * dpr,\n area.y * dpr,\n area.width * dpr,\n area.height * dpr,\n 0,\n 0,\n area.width * dpr,\n area.height * dpr,\n );\n\n return canvas.toDataURL(\"image/png\");\n}\n\nasync function captureComponent(\n element: HTMLElement,\n frameOnBlack?: boolean,\n): Promise<string> {\n const dataUrl = await toPngDataUrl(element);\n\n if (!frameOnBlack) {\n return dataUrl;\n }\n\n const img = await loadImage(dataUrl);\n const dpr = window.devicePixelRatio || 1;\n\n const FRAME_W = 1920;\n const FRAME_H = 1080;\n\n // Component dimensions in CSS pixels\n const compW = img.width / dpr;\n const compH = img.height / dpr;\n\n // Scale down if component exceeds frame (with padding)\n const padding = 40;\n const maxW = FRAME_W - padding * 2;\n const maxH = FRAME_H - padding * 2;\n const scale = Math.min(1, maxW / compW, maxH / compH);\n\n const drawW = compW * scale * dpr;\n const drawH = compH * scale * dpr;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = FRAME_W * dpr;\n canvas.height = FRAME_H * dpr;\n\n const ctx = canvas.getContext(\"2d\")!;\n ctx.fillStyle = \"#000000\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n // Center the component\n const dx = (canvas.width - drawW) / 2;\n const dy = (canvas.height - drawH) / 2;\n ctx.drawImage(img, dx, dy, drawW, drawH);\n\n return canvas.toDataURL(\"image/png\");\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = src;\n });\n}\n","\"use client\";\n\nimport React, { useRef, useCallback, useEffect, useState } from \"react\";\nimport { Camera, Check, LoaderCircle } from \"lucide-react\";\nimport type { OverlayPhase } from \"../state\";\n\ninterface IconProps {\n phase: OverlayPhase;\n onClick: () => void;\n loading?: boolean;\n onPositionChange?: (pos: { x: number; y: number }) => void;\n}\n\nconst ICON_SIZE = 40;\nconst EDGE_MARGIN = 24;\n\nexport function Icon({ phase, onClick, loading, onPositionChange }: IconProps) {\n const ref = useRef<HTMLDivElement>(null);\n const [pos, setPos] = useState({ x: EDGE_MARGIN, y: -1 });\n const dragState = useRef<{\n dragging: boolean;\n startX: number;\n startY: number;\n origX: number;\n origY: number;\n distance: number;\n } | null>(null);\n\n // Initialize y position on mount (need window.innerHeight)\n useEffect(() => {\n setPos((prev) => {\n if (prev.y === -1) {\n const y = window.innerHeight - ICON_SIZE - EDGE_MARGIN;\n return { x: prev.x, y };\n }\n return prev;\n });\n }, []);\n\n // Report position changes upstream\n useEffect(() => {\n if (pos.y !== -1) {\n onPositionChange?.({ x: pos.x, y: pos.y });\n }\n }, [pos, onPositionChange]);\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n dragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n origX: pos.x,\n origY: pos.y,\n distance: 0,\n };\n },\n [pos],\n );\n\n useEffect(() => {\n const handleMouseMove = (e: MouseEvent) => {\n const ds = dragState.current;\n if (!ds || !ds.dragging) return;\n\n const dx = e.clientX - ds.startX;\n const dy = e.clientY - ds.startY;\n ds.distance = Math.sqrt(dx * dx + dy * dy);\n\n const newX = Math.max(\n 0,\n Math.min(window.innerWidth - ICON_SIZE, ds.origX + dx),\n );\n const newY = Math.max(\n 0,\n Math.min(window.innerHeight - ICON_SIZE, ds.origY + dy),\n );\n setPos({ x: newX, y: newY });\n };\n\n const handleMouseUp = () => {\n const ds = dragState.current;\n if (!ds) return;\n\n if (ds.distance < 5) {\n onClick();\n }\n dragState.current = null;\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n window.addEventListener(\"mouseup\", handleMouseUp);\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"mouseup\", handleMouseUp);\n };\n }, [onClick]);\n\n // Don't render until y is initialized\n if (pos.y === -1) return null;\n\n return (\n <div\n ref={ref}\n data-afterbefore=\"true\"\n onMouseDown={handleMouseDown}\n style={{\n position: \"fixed\",\n left: pos.x,\n top: pos.y,\n width: ICON_SIZE,\n height: ICON_SIZE,\n borderRadius: \"50%\",\n background: \"rgba(30, 30, 30, 0.85)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"grab\",\n zIndex: 2147483647,\n boxShadow: \"0 2px 8px rgba(0,0,0,0.3)\",\n transition: \"background 0.15s\",\n userSelect: \"none\",\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLDivElement).style.background =\n \"rgba(30, 30, 30, 0.95)\";\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLDivElement).style.background =\n \"rgba(30, 30, 30, 0.85)\";\n }}\n >\n <style\n dangerouslySetInnerHTML={{\n __html: `\n@keyframes ab-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.08); opacity: 0.85; }\n}\n@keyframes ab-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}`,\n }}\n />\n\n {loading ? (\n <LoaderCircle\n size={20}\n strokeWidth={2}\n style={{ animation: \"ab-spin 0.8s linear infinite\", color: \"white\" }}\n />\n ) : phase === \"ready\" ? (\n <Check size={20} strokeWidth={2.6} color=\"#4ade80\" />\n ) : (\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n animation:\n phase === \"captured-before\"\n ? \"ab-pulse 2s ease-in-out infinite\"\n : \"none\",\n }}\n >\n <Camera size={20} strokeWidth={1.9} color=\"white\" />\n\n {/* Badge for captured-before */}\n {phase === \"captured-before\" && (\n <div\n style={{\n position: \"absolute\",\n top: -6,\n right: -8,\n width: 14,\n height: 14,\n borderRadius: \"50%\",\n background: \"#3b82f6\",\n color: \"white\",\n fontSize: \"9px\",\n fontWeight: 700,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n lineHeight: 1,\n fontFamily: \"system-ui, sans-serif\",\n }}\n >\n 1\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport type { CaptureMode } from \"../state\";\n\ninterface CapturePreviewProps {\n mode: CaptureMode;\n onClick?: () => void;\n}\n\ninterface PreviewRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst DEFAULT_ASPECT_RATIO = 16 / 9;\n\nfunction getAreaPreviewRect(): PreviewRect {\n const safeWidth = Math.max(320, window.innerWidth - 120);\n const safeHeight = Math.max(180, window.innerHeight - 220);\n const width = Math.min(window.innerWidth * 0.72, safeHeight * DEFAULT_ASPECT_RATIO, safeWidth);\n const height = width / DEFAULT_ASPECT_RATIO;\n\n return {\n x: (window.innerWidth - width) / 2,\n y: Math.max(40, (window.innerHeight - height) / 2 - 20),\n width,\n height,\n };\n}\n\nconst CAMERA_CURSOR = `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z'/%3E%3Ccircle cx='12' cy='13' r='3'/%3E%3C/svg%3E\") 16 16, pointer`;\n\nexport function CapturePreview({ mode, onClick }: CapturePreviewProps) {\n const [areaRect, setAreaRect] = useState<PreviewRect | null>(null);\n\n useEffect(() => {\n if (mode !== \"area\") {\n return;\n }\n\n const syncRect = () => {\n setAreaRect(getAreaPreviewRect());\n };\n\n syncRect();\n window.addEventListener(\"resize\", syncRect);\n return () => window.removeEventListener(\"resize\", syncRect);\n }, [mode]);\n\n if (mode === \"area\" && areaRect) {\n return (\n <div\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483645,\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n left: areaRect.x,\n top: areaRect.y,\n width: areaRect.width,\n height: areaRect.height,\n background: \"rgba(125, 211, 252, 0.16)\",\n border: \"1.5px solid rgba(125, 211, 252, 0.95)\",\n boxShadow: \"0 0 0 1px rgba(191, 219, 254, 0.4), 0 0 32px rgba(56, 189, 248, 0.18)\",\n borderRadius: 14,\n }}\n />\n </div>\n );\n }\n\n if (mode === \"viewport\" || mode === \"fullpage\") {\n return (\n <div\n data-afterbefore=\"true\"\n onClick={onClick}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483645,\n cursor: CAMERA_CURSOR,\n background: \"rgba(125, 211, 252, 0.15)\",\n boxShadow: \"inset 0 0 0 1.5px rgba(125, 211, 252, 0.9)\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n top: 36,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n padding: \"8px 14px\",\n borderRadius: 999,\n background: \"rgba(125, 211, 252, 0.16)\",\n border: \"1px solid rgba(125, 211, 252, 0.42)\",\n color: \"rgba(224, 242, 254, 0.96)\",\n fontSize: 12,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n boxShadow: \"0 10px 30px rgba(14, 116, 144, 0.18)\",\n pointerEvents: \"none\",\n }}\n >\n {mode === \"fullpage\" ? \"Click to capture full page\" : \"Click to capture viewport\"}\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483645,\n pointerEvents: \"none\",\n }}\n >\n <div\n style={{\n position: \"absolute\",\n top: 36,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n padding: \"8px 14px\",\n borderRadius: 999,\n background: \"rgba(125, 211, 252, 0.16)\",\n border: \"1px solid rgba(125, 211, 252, 0.42)\",\n color: \"rgba(224, 242, 254, 0.96)\",\n fontSize: 12,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n boxShadow: \"0 10px 30px rgba(14, 116, 144, 0.18)\",\n }}\n >\n Click Capture, then hover an element to preview it\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport {\n ChevronDown,\n Crop,\n FileText,\n FolderOpen,\n Frame,\n Magnet,\n Monitor,\n MousePointer2,\n Save,\n Settings2,\n X,\n} from \"lucide-react\";\nimport type { CaptureMode } from \"../state\";\nimport {\n AREA_ASPECT_RATIOS,\n type AreaAspectLabel,\n type AreaRect,\n} from \"./selector\";\n\ninterface ToolbarProps {\n selectedMode: CaptureMode;\n onModeChange: (mode: CaptureMode) => void;\n onCapture: (mode: CaptureMode) => void;\n onCancel: () => void;\n magnetEnabled: boolean;\n onMagnetChange: (enabled: boolean) => void;\n areaSelectionActive: boolean;\n areaRect: AreaRect | null;\n areaAspect: AreaAspectLabel;\n areaPresets: { label: string; rect: AreaRect }[];\n onAreaSizeChange: (field: \"w\" | \"h\", value: string) => void;\n onAreaPositionChange: (field: \"x\" | \"y\", value: string) => void;\n onAreaAspectChange: (aspect: AreaAspectLabel) => void;\n onAreaSavePreset: () => void;\n onAreaLoadPreset: (preset: { label: string; rect: AreaRect }) => void;\n frameOnBlackEnabled: boolean;\n onFrameOnBlackChange: (enabled: boolean) => void;\n}\n\nconst MODES: { mode: CaptureMode; label: string; icon: React.ComponentType<{ size?: number; strokeWidth?: number }> }[] = [\n { mode: \"component\", label: \"Capture Component\", icon: MousePointer2 },\n { mode: \"area\", label: \"Capture Selected Area\", icon: Crop },\n { mode: \"viewport\", label: \"Capture Viewport\", icon: Monitor },\n { mode: \"fullpage\", label: \"Capture Full Page\", icon: FileText },\n];\n\nexport function Toolbar({\n selectedMode,\n onModeChange,\n onCapture,\n onCancel,\n magnetEnabled,\n onMagnetChange,\n areaSelectionActive,\n areaRect,\n areaAspect,\n areaPresets,\n onAreaSizeChange,\n onAreaPositionChange,\n onAreaAspectChange,\n onAreaSavePreset,\n onAreaLoadPreset,\n frameOnBlackEnabled,\n onFrameOnBlackChange,\n}: ToolbarProps) {\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [aspectOpen, setAspectOpen] = useState(false);\n const [savedOpen, setSavedOpen] = useState(false);\n\n const showAreaControls = selectedMode === \"area\" && areaSelectionActive && areaRect !== null;\n const activeAreaRect = showAreaControls ? areaRect : null;\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if ((e.target as HTMLElement)?.tagName === \"INPUT\") {\n if (e.key === \"Escape\") {\n (e.target as HTMLElement).blur();\n }\n return;\n }\n\n if (e.key === \"Escape\") {\n if (settingsOpen) {\n setSettingsOpen(false);\n return;\n }\n if (aspectOpen) {\n setAspectOpen(false);\n return;\n }\n if (savedOpen) {\n setSavedOpen(false);\n return;\n }\n onCancel();\n } else if (e.key === \"Enter\") {\n onCapture(selectedMode);\n }\n };\n\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [aspectOpen, onCancel, onCapture, savedOpen, selectedMode, settingsOpen]);\n\n return (\n <div\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n bottom: 48,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n gap: 10,\n flexWrap: \"wrap\",\n justifyContent: \"center\",\n maxWidth: \"min(calc(100vw - 32px), 1120px)\",\n background: \"rgba(32, 32, 36, 0.92)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 18,\n padding: \"6px 10px\",\n boxShadow: \"0 8px 32px rgba(0, 0, 0, 0.4)\",\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 0 }}>\n <CloseButton onClick={onCancel} />\n\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 2, padding: \"0 4px\" }}>\n {MODES.map(({ mode, label, icon: Icon }) => (\n <ModeButton\n key={mode}\n label={label}\n selected={selectedMode === mode}\n onClick={() => {\n setSettingsOpen(false);\n onModeChange(mode);\n }}\n >\n <Icon size={18} strokeWidth={1.7} />\n </ModeButton>\n ))}\n </div>\n\n <Separator />\n\n <SettingsButton\n open={settingsOpen}\n onClick={() => {\n setAspectOpen(false);\n setSavedOpen(false);\n setSettingsOpen((prev) => !prev);\n }}\n selectedMode={selectedMode}\n magnetEnabled={magnetEnabled}\n onMagnetChange={onMagnetChange}\n frameOnBlackEnabled={frameOnBlackEnabled}\n onFrameOnBlackChange={onFrameOnBlackChange}\n />\n\n </div>\n\n {activeAreaRect && (\n <>\n <Separator vertical={false} />\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n flexWrap: \"wrap\",\n justifyContent: \"center\",\n }}\n >\n <ControlGroup label=\"Size\">\n <NumInput value={Math.round(activeAreaRect.w)} onChange={(value) => onAreaSizeChange(\"w\", value)} />\n <StaticText>x</StaticText>\n <NumInput value={Math.round(activeAreaRect.h)} onChange={(value) => onAreaSizeChange(\"h\", value)} />\n </ControlGroup>\n\n <ControlGroup label=\"Position\">\n <NumInput value={Math.round(activeAreaRect.x)} onChange={(value) => onAreaPositionChange(\"x\", value)} />\n <StaticText>x</StaticText>\n <NumInput value={Math.round(activeAreaRect.y)} onChange={(value) => onAreaPositionChange(\"y\", value)} />\n </ControlGroup>\n\n <div style={{ position: \"relative\" }}>\n <DropButton\n active={areaAspect !== \"Free\"}\n onClick={() => {\n setSavedOpen(false);\n setAspectOpen((prev) => !prev);\n }}\n >\n {areaAspect}\n <ChevronDown size={14} strokeWidth={1.8} />\n </DropButton>\n\n {aspectOpen && (\n <DropMenu>\n {AREA_ASPECT_RATIOS.map((item) => (\n <DropItem\n key={item.label}\n active={item.label === areaAspect}\n onClick={() => {\n onAreaAspectChange(item.label);\n setAspectOpen(false);\n }}\n >\n {item.label}\n </DropItem>\n ))}\n </DropMenu>\n )}\n </div>\n\n <div style={{ position: \"relative\" }}>\n <DropButton\n onClick={() => {\n setAspectOpen(false);\n setSavedOpen((prev) => !prev);\n }}\n >\n <Save size={14} strokeWidth={1.8} />\n Saved\n <ChevronDown size={14} strokeWidth={1.8} />\n </DropButton>\n\n {savedOpen && (\n <DropMenu>\n <DropItem accent onClick={onAreaSavePreset}>\n Save current\n </DropItem>\n {areaPresets.length > 0 && <MenuDivider />}\n {areaPresets.map((preset) => (\n <DropItem\n key={preset.label}\n onClick={() => {\n onAreaLoadPreset(preset);\n setSavedOpen(false);\n }}\n >\n {preset.label}\n </DropItem>\n ))}\n {areaPresets.length === 0 && (\n <div\n style={{\n padding: \"6px 12px\",\n color: \"rgba(255,255,255,0.3)\",\n fontSize: 12,\n }}\n >\n No saved areas\n </div>\n )}\n </DropMenu>\n )}\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nfunction CloseButton({ onClick }: { onClick: () => void }) {\n const [hovered, setHovered] = useState(false);\n\n return (\n <button\n onClick={onClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n style={circleButtonStyle(hovered, true)}\n >\n <X size={18} strokeWidth={1.9} />\n </button>\n );\n}\n\nfunction ModeButton({\n children,\n label,\n selected,\n onClick,\n}: {\n children: React.ReactNode;\n label: string;\n selected: boolean;\n onClick: () => void;\n}) {\n const [hovered, setHovered] = useState(false);\n\n return (\n <div style={{ position: \"relative\" }}>\n {hovered && (\n <div\n style={{\n position: \"absolute\",\n left: \"50%\",\n bottom: \"calc(100% + 10px)\",\n transform: \"translateX(-50%)\",\n background: \"rgba(32, 32, 36, 0.96)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 8,\n padding: \"5px 10px\",\n color: \"rgba(255, 255, 255, 0.88)\",\n fontSize: 12,\n whiteSpace: \"nowrap\",\n boxShadow: \"0 8px 28px rgba(0, 0, 0, 0.28)\",\n pointerEvents: \"none\",\n }}\n >\n {label}\n </div>\n )}\n\n <button\n onClick={onClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n style={{\n width: 42,\n height: 40,\n borderRadius: 12,\n border: \"none\",\n background: selected\n ? \"rgba(255, 255, 255, 0.15)\"\n : hovered\n ? \"rgba(255, 255, 255, 0.08)\"\n : \"transparent\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n padding: 0,\n color: selected\n ? \"rgba(255, 255, 255, 0.96)\"\n : \"rgba(255, 255, 255, 0.52)\",\n transition: \"background 0.12s ease, color 0.12s ease\",\n }}\n >\n {children}\n </button>\n </div>\n );\n}\n\nfunction SettingsButton({\n open,\n onClick,\n selectedMode,\n magnetEnabled,\n onMagnetChange,\n frameOnBlackEnabled,\n onFrameOnBlackChange,\n}: {\n open: boolean;\n onClick: () => void;\n selectedMode: CaptureMode;\n magnetEnabled: boolean;\n onMagnetChange: (enabled: boolean) => void;\n frameOnBlackEnabled: boolean;\n onFrameOnBlackChange: (enabled: boolean) => void;\n}) {\n const [hovered, setHovered] = useState(false);\n const [saveDir, setSaveDir] = useState<string | null>(null);\n const [picking, setPicking] = useState(false);\n\n useEffect(() => {\n if (!open) return;\n fetch(\"/__afterbefore/config\")\n .then((r) => r.json())\n .then((data) => setSaveDir(data.saveDir))\n .catch(() => {});\n }, [open]);\n\n const handlePickFolder = async () => {\n setPicking(true);\n try {\n const res = await fetch(\"/__afterbefore/pick-folder\", { method: \"POST\" });\n const data = await res.json();\n if (data.folder) {\n await fetch(\"/__afterbefore/config\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ saveDir: data.folder }),\n });\n setSaveDir(data.folder);\n }\n } catch {\n // noop\n } finally {\n setPicking(false);\n }\n };\n\n const shortDir = saveDir\n ? saveDir.replace(/^\\/Users\\/[^/]+/, \"~\")\n : \"~/Desktop\";\n\n return (\n <div style={{ position: \"relative\", marginRight: 6 }}>\n <button\n onClick={onClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n style={{\n ...circleButtonStyle(open || hovered, false),\n color: \"rgba(255, 255, 255, 0.58)\",\n }}\n >\n <Settings2 size={18} strokeWidth={1.7} />\n </button>\n\n {open && (\n <div\n style={{\n position: \"absolute\",\n left: \"50%\",\n bottom: \"calc(100% + 12px)\",\n transform: \"translateX(-50%)\",\n minWidth: 210,\n padding: \"10px 12px\",\n borderRadius: 12,\n background: \"rgba(32, 32, 36, 0.96)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n boxShadow: \"0 14px 36px rgba(0, 0, 0, 0.32)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n }}\n >\n <div\n style={{\n fontSize: 11,\n color: \"rgba(255, 255, 255, 0.46)\",\n letterSpacing: \"0.03em\",\n textTransform: \"uppercase\",\n marginBottom: 10,\n }}\n >\n Settings\n </div>\n\n {selectedMode === \"area\" && (\n <ToggleRow\n icon={<Magnet size={15} strokeWidth={1.8} />}\n label=\"Magnet snap\"\n enabled={magnetEnabled}\n onChange={() => onMagnetChange(!magnetEnabled)}\n />\n )}\n\n {selectedMode === \"component\" && (\n <ToggleRow\n icon={<Frame size={15} strokeWidth={1.8} />}\n label=\"1920 x 1080 frame\"\n enabled={frameOnBlackEnabled}\n onChange={() => onFrameOnBlackChange(!frameOnBlackEnabled)}\n />\n )}\n\n {(selectedMode === \"area\" || selectedMode === \"component\") && (\n <div style={{ height: 1, background: \"rgba(255,255,255,0.08)\", margin: \"8px 0\" }} />\n )}\n\n <SaveLocationRow\n dir={shortDir}\n picking={picking}\n onPick={handlePickFolder}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction SaveLocationRow({\n dir,\n picking,\n onPick,\n}: {\n dir: string;\n picking: boolean;\n onPick: () => void;\n}) {\n const [btnHovered, setBtnHovered] = useState(false);\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 6 }}>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n color: \"rgba(255, 255, 255, 0.88)\",\n fontSize: 13,\n }}\n >\n <FolderOpen size={15} strokeWidth={1.8} style={{ flexShrink: 0 }} />\n <span\n style={{\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n flex: 1,\n minWidth: 0,\n }}\n title={dir}\n >\n {dir}\n </span>\n <button\n onClick={onPick}\n disabled={picking}\n onMouseEnter={() => setBtnHovered(true)}\n onMouseLeave={() => setBtnHovered(false)}\n style={{\n padding: \"3px 8px\",\n borderRadius: 6,\n border: \"1px solid rgba(255,255,255,0.12)\",\n background: btnHovered ? \"rgba(255,255,255,0.12)\" : \"rgba(255,255,255,0.06)\",\n color: \"rgba(255,255,255,0.78)\",\n fontSize: 11,\n cursor: picking ? \"wait\" : \"pointer\",\n flexShrink: 0,\n fontFamily: \"inherit\",\n transition: \"background 0.12s ease\",\n }}\n >\n {picking ? \"...\" : \"Change\"}\n </button>\n </div>\n </div>\n );\n}\n\nfunction ToggleRow({\n icon,\n label,\n enabled,\n onChange,\n}: {\n icon: React.ReactNode;\n label: string;\n enabled: boolean;\n onChange: () => void;\n}) {\n return (\n <label\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 12,\n cursor: \"pointer\",\n }}\n >\n <span\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n color: \"rgba(255, 255, 255, 0.88)\",\n fontSize: 13,\n whiteSpace: \"nowrap\",\n }}\n >\n {icon}\n {label}\n </span>\n\n <button\n type=\"button\"\n onClick={onChange}\n style={{\n width: 38,\n height: 22,\n borderRadius: 999,\n border: \"none\",\n background: enabled ? \"#38bdf8\" : \"rgba(255, 255, 255, 0.18)\",\n position: \"relative\",\n cursor: \"pointer\",\n padding: 0,\n flexShrink: 0,\n transition: \"background 0.12s ease\",\n }}\n >\n <span\n style={{\n position: \"absolute\",\n top: 2,\n left: enabled ? 18 : 2,\n width: 18,\n height: 18,\n borderRadius: \"50%\",\n background: \"#fff\",\n transition: \"left 0.12s ease\",\n }}\n />\n </button>\n </label>\n );\n}\n\nfunction ControlGroup({\n label,\n children,\n}: {\n label: string;\n children: React.ReactNode;\n}) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"0 4px\",\n }}\n >\n <span\n style={{\n fontSize: 11,\n color: \"rgba(255, 255, 255, 0.42)\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.03em\",\n }}\n >\n {label}\n </span>\n {children}\n </div>\n );\n}\n\nfunction NumInput({\n value,\n onChange,\n}: {\n value: number;\n onChange: (value: string) => void;\n}) {\n const [editing, setEditing] = useState(false);\n const [text, setText] = useState(String(value));\n\n useEffect(() => {\n if (!editing) {\n setText(String(value));\n }\n }, [editing, value]);\n\n return (\n <input\n type=\"text\"\n value={editing ? text : String(value)}\n onFocus={() => {\n setEditing(true);\n setText(String(value));\n }}\n onBlur={() => {\n setEditing(false);\n onChange(text);\n }}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n (e.target as HTMLElement).blur();\n }\n }}\n style={{\n width: 54,\n padding: \"4px 6px\",\n background: \"rgba(255, 255, 255, 0.07)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 7,\n color: \"rgba(255, 255, 255, 0.9)\",\n fontSize: 12,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n textAlign: \"center\",\n outline: \"none\",\n }}\n />\n );\n}\n\nfunction StaticText({ children }: { children: React.ReactNode }) {\n return (\n <span\n style={{\n fontSize: 11,\n color: \"rgba(255,255,255,0.35)\",\n minWidth: 8,\n textAlign: \"center\",\n }}\n >\n {children}\n </span>\n );\n}\n\nfunction DropButton({\n children,\n onClick,\n active,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n active?: boolean;\n}) {\n return (\n <button\n onClick={onClick}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n height: 34,\n padding: \"0 10px\",\n borderRadius: 10,\n border: \"1px solid rgba(255,255,255,0.08)\",\n background: \"rgba(255,255,255,0.04)\",\n color: active ? \"rgba(125, 211, 252, 0.96)\" : \"rgba(255,255,255,0.78)\",\n cursor: \"pointer\",\n fontSize: 12,\n fontFamily: \"inherit\",\n }}\n >\n {children}\n </button>\n );\n}\n\nfunction DropMenu({ children }: { children: React.ReactNode }) {\n return (\n <div\n style={{\n position: \"absolute\",\n bottom: \"calc(100% + 8px)\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n minWidth: 120,\n background: \"rgba(32, 32, 36, 0.96)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 10,\n padding: \"4px 0\",\n boxShadow: \"0 10px 30px rgba(0, 0, 0, 0.3)\",\n backdropFilter: \"blur(20px)\",\n WebkitBackdropFilter: \"blur(20px)\",\n }}\n >\n {children}\n </div>\n );\n}\n\nfunction DropItem({\n children,\n onClick,\n active,\n accent,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n active?: boolean;\n accent?: boolean;\n}) {\n return (\n <button\n onClick={onClick}\n style={{\n display: \"block\",\n width: \"100%\",\n padding: \"7px 12px\",\n background: active ? \"rgba(255, 255, 255, 0.08)\" : \"transparent\",\n border: \"none\",\n color: accent\n ? \"rgba(125, 211, 252, 0.96)\"\n : \"rgba(255, 255, 255, 0.86)\",\n textAlign: \"left\",\n cursor: \"pointer\",\n fontSize: 13,\n fontFamily: \"inherit\",\n }}\n >\n {children}\n </button>\n );\n}\n\nfunction MenuDivider() {\n return (\n <div\n style={{\n height: 1,\n background: \"rgba(255,255,255,0.08)\",\n margin: \"4px 0\",\n }}\n />\n );\n}\n\nfunction Separator({ vertical = true }: { vertical?: boolean }) {\n return (\n <div\n style={{\n width: vertical ? 1 : 24,\n height: vertical ? 24 : 1,\n background: \"rgba(255,255,255,0.12)\",\n flexShrink: 0,\n }}\n />\n );\n}\n\nfunction circleButtonStyle(active: boolean, round: boolean) {\n return {\n width: 40,\n height: 40,\n borderRadius: round ? \"50%\" : 12,\n border: \"none\",\n background: active ? \"rgba(255, 255, 255, 0.12)\" : \"transparent\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n padding: 0,\n transition: \"background 0.12s ease, color 0.12s ease\",\n marginRight: round ? 6 : 0,\n } as const;\n}\n","\"use client\";\n\nimport React, { useRef, useCallback, useEffect, useMemo, useState } from \"react\";\n\ninterface SelectorProps {\n rect: AreaRect | null;\n aspect: AreaAspectLabel;\n magnetEnabled: boolean;\n onRectChange: (rect: AreaRect | null) => void;\n onSelect: (area: {\n x: number;\n y: number;\n width: number;\n height: number;\n }) => void;\n onCancel: () => void;\n}\n\ntype Corner = \"tl\" | \"tr\" | \"bl\" | \"br\";\ntype DragMode = \"none\" | \"drawing\" | \"moving\" | \"resizing\";\n\nexport interface AreaRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport type AreaAspectLabel = \"Free\" | \"16:9\" | \"4:3\" | \"1:1\" | \"3:2\" | \"21:9\";\n\nexport const DEFAULT_AREA_ASPECT: AreaAspectLabel = \"16:9\";\n\nexport const AREA_ASPECT_RATIOS: { label: AreaAspectLabel; value: number }[] = [\n { label: \"Free\", value: 0 },\n { label: \"16:9\", value: 16 / 9 },\n { label: \"4:3\", value: 4 / 3 },\n { label: \"1:1\", value: 1 },\n { label: \"3:2\", value: 3 / 2 },\n { label: \"21:9\", value: 21 / 9 },\n];\n\nconst HANDLE_R = 6;\nconst HANDLE_HIT = 16;\nconst MIN_SIZE = 20;\nconst SNAP_THRESHOLD = 8;\n\nconst CAMERA_CURSOR = `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='%23e0f2fe' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7h3l1.5-2h7L17 7h3a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2Z'/%3E%3Ccircle cx='12' cy='13' r='4'/%3E%3C/svg%3E\") 12 12, crosshair`;\n\nexport function createInitialAreaRect(): AreaRect {\n const safeWidth = Math.max(320, window.innerWidth - 96);\n const safeHeight = Math.max(180, window.innerHeight - 220);\n const w = Math.min(window.innerWidth * 0.72, safeHeight * (16 / 9), safeWidth);\n const h = w / (16 / 9);\n\n return {\n x: (window.innerWidth - w) / 2,\n y: Math.max(40, (window.innerHeight - h) / 2 - 20),\n w,\n h,\n };\n}\n\nfunction getAspectRatio(label: AreaAspectLabel): number {\n return AREA_ASPECT_RATIOS.find((item) => item.label === label)?.value ?? 0;\n}\n\nexport function Selector({\n rect,\n aspect,\n magnetEnabled,\n onRectChange,\n onSelect,\n onCancel,\n}: SelectorProps) {\n const [snappedX, setSnappedX] = useState(false);\n const [cursor, setCursor] = useState(\"crosshair\");\n const mode = useRef<DragMode>(\"none\");\n const start = useRef({ x: 0, y: 0 });\n const snapRef = useRef<AreaRect>({ x: 0, y: 0, w: 0, h: 0 });\n const corner = useRef<Corner>(\"br\");\n const ratio = useMemo(() => getAspectRatio(aspect), [aspect]);\n\n const applySnap = useCallback(\n (nextRect: AreaRect): AreaRect => {\n if (!magnetEnabled) {\n setSnappedX(false);\n return nextRect;\n }\n\n const centerX = nextRect.x + nextRect.w / 2;\n const viewportCenterX = window.innerWidth / 2;\n\n if (Math.abs(centerX - viewportCenterX) < SNAP_THRESHOLD) {\n setSnappedX(true);\n return { ...nextRect, x: viewportCenterX - nextRect.w / 2 };\n }\n\n setSnappedX(false);\n return nextRect;\n },\n [magnetEnabled],\n );\n\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n onCancel();\n }\n };\n\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [onCancel]);\n\n const hitCorner = useCallback((mx: number, my: number, currentRect: AreaRect): Corner | null => {\n const corners: [Corner, number, number][] = [\n [\"tl\", currentRect.x, currentRect.y],\n [\"tr\", currentRect.x + currentRect.w, currentRect.y],\n [\"bl\", currentRect.x, currentRect.y + currentRect.h],\n [\"br\", currentRect.x + currentRect.w, currentRect.y + currentRect.h],\n ];\n\n for (const [hitCorner, cx, cy] of corners) {\n if (Math.abs(mx - cx) <= HANDLE_HIT && Math.abs(my - cy) <= HANDLE_HIT) {\n return hitCorner;\n }\n }\n\n return null;\n }, []);\n\n const hitInside = useCallback(\n (mx: number, my: number, currentRect: AreaRect) =>\n mx >= currentRect.x &&\n mx <= currentRect.x + currentRect.w &&\n my >= currentRect.y &&\n my <= currentRect.y + currentRect.h,\n [],\n );\n\n const onDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n const mx = e.clientX;\n const my = e.clientY;\n\n if (rect) {\n const activeCorner = hitCorner(mx, my, rect);\n if (activeCorner) {\n mode.current = \"resizing\";\n corner.current = activeCorner;\n start.current = { x: mx, y: my };\n snapRef.current = { ...rect };\n return;\n }\n\n if (hitInside(mx, my, rect)) {\n mode.current = \"moving\";\n start.current = { x: mx, y: my };\n snapRef.current = { ...rect };\n return;\n }\n }\n\n mode.current = \"drawing\";\n start.current = { x: mx, y: my };\n onRectChange({ x: mx, y: my, w: 0, h: 0 });\n },\n [hitCorner, hitInside, onRectChange, rect],\n );\n\n const onMove = useCallback(\n (e: React.MouseEvent) => {\n const mx = e.clientX;\n const my = e.clientY;\n\n if (mode.current === \"none\") {\n if (rect) {\n const activeCorner = hitCorner(mx, my, rect);\n if (activeCorner) {\n setCursor(\n activeCorner === \"tl\" || activeCorner === \"br\"\n ? \"nwse-resize\"\n : \"nesw-resize\",\n );\n } else if (hitInside(mx, my, rect)) {\n setCursor(CAMERA_CURSOR);\n } else {\n setCursor(\"crosshair\");\n }\n } else {\n setCursor(\"crosshair\");\n }\n return;\n }\n\n if (mode.current === \"drawing\") {\n const sx = start.current.x;\n const sy = start.current.y;\n let x = Math.min(sx, mx);\n let y = Math.min(sy, my);\n let w = Math.abs(mx - sx);\n let h = Math.abs(my - sy);\n\n if (ratio > 0) {\n h = w / ratio;\n if (my < sy) {\n y = sy - h;\n }\n }\n\n onRectChange(applySnap({ x, y, w, h }));\n return;\n }\n\n if (mode.current === \"moving\") {\n const dx = mx - start.current.x;\n const dy = my - start.current.y;\n onRectChange(\n applySnap({\n ...snapRef.current,\n x: snapRef.current.x + dx,\n y: snapRef.current.y + dy,\n }),\n );\n return;\n }\n\n if (mode.current === \"resizing\") {\n const original = snapRef.current;\n const nextRect = { ...original };\n\n if (corner.current === \"br\") {\n nextRect.w = Math.max(MIN_SIZE, mx - original.x);\n nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);\n } else if (corner.current === \"bl\") {\n nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);\n nextRect.x = original.x + original.w - nextRect.w;\n nextRect.h = ratio > 0 ? nextRect.w / ratio : Math.max(MIN_SIZE, my - original.y);\n } else if (corner.current === \"tr\") {\n nextRect.w = Math.max(MIN_SIZE, mx - original.x);\n nextRect.h =\n ratio > 0\n ? nextRect.w / ratio\n : Math.max(MIN_SIZE, original.y + original.h - my);\n nextRect.y = original.y + original.h - nextRect.h;\n } else {\n nextRect.w = Math.max(MIN_SIZE, original.x + original.w - mx);\n nextRect.h =\n ratio > 0\n ? nextRect.w / ratio\n : Math.max(MIN_SIZE, original.y + original.h - my);\n nextRect.x = original.x + original.w - nextRect.w;\n nextRect.y = original.y + original.h - nextRect.h;\n }\n\n onRectChange(applySnap(nextRect));\n }\n },\n [applySnap, hitCorner, hitInside, onRectChange, ratio, rect],\n );\n\n const onUp = useCallback(\n (e: React.MouseEvent) => {\n const previousMode = mode.current;\n\n if (previousMode === \"drawing\" && rect) {\n if (rect.w < MIN_SIZE || rect.h < MIN_SIZE) {\n onRectChange(null);\n }\n }\n\n if (previousMode === \"moving\" && rect) {\n const dx = Math.abs(e.clientX - start.current.x);\n const dy = Math.abs(e.clientY - start.current.y);\n if (dx < 3 && dy < 3) {\n onSelect({\n x: Math.round(rect.x),\n y: Math.round(rect.y),\n width: Math.round(rect.w),\n height: Math.round(rect.h),\n });\n }\n }\n\n mode.current = \"none\";\n },\n [onRectChange, onSelect, rect],\n );\n\n const hasRect = rect && rect.w > 0 && rect.h > 0;\n\n return (\n <div\n data-afterbefore=\"true\"\n onMouseDown={onDown}\n onMouseMove={onMove}\n onMouseUp={onUp}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483646,\n cursor,\n }}\n >\n {snappedX && (\n <div\n style={{\n position: \"absolute\",\n left: \"50%\",\n top: 0,\n bottom: 0,\n width: 0,\n borderLeft: \"1px solid rgba(56, 189, 248, 0.55)\",\n pointerEvents: \"none\",\n zIndex: 2,\n }}\n />\n )}\n\n {hasRect ? (\n <>\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: 0,\n width: \"100%\",\n height: rect.y,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: rect.y,\n width: rect.x,\n height: rect.h,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: rect.x + rect.w,\n top: rect.y,\n width: `calc(100% - ${rect.x + rect.w}px)`,\n height: rect.h,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: rect.y + rect.h,\n width: \"100%\",\n height: `calc(100% - ${rect.y + rect.h}px)`,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y,\n width: rect.w,\n height: rect.h,\n background: \"rgba(125, 211, 252, 0.08)\",\n pointerEvents: \"none\",\n borderRadius: 12,\n }}\n />\n\n <div\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y,\n width: rect.w,\n height: rect.h,\n border: \"1.5px dashed rgba(255, 255, 255, 0.45)\",\n borderRadius: 12,\n pointerEvents: \"none\",\n boxShadow: \"0 0 0 1px rgba(125, 211, 252, 0.38)\",\n }}\n />\n\n {[1, 2].map((line) => (\n <React.Fragment key={line}>\n <div\n style={{\n position: \"absolute\",\n left: rect.x + (rect.w * line) / 3,\n top: rect.y,\n width: 0,\n height: rect.h,\n borderLeft: \"1px dashed rgba(255, 255, 255, 0.18)\",\n pointerEvents: \"none\",\n }}\n />\n <div\n style={{\n position: \"absolute\",\n left: rect.x,\n top: rect.y + (rect.h * line) / 3,\n width: rect.w,\n height: 0,\n borderTop: \"1px dashed rgba(255, 255, 255, 0.18)\",\n pointerEvents: \"none\",\n }}\n />\n </React.Fragment>\n ))}\n\n {(\n [\n [rect.x, rect.y],\n [rect.x + rect.w, rect.y],\n [rect.x, rect.y + rect.h],\n [rect.x + rect.w, rect.y + rect.h],\n ] as [number, number][]\n ).map(([cx, cy], index) => (\n <div\n key={index}\n style={{\n position: \"absolute\",\n left: cx - HANDLE_R,\n top: cy - HANDLE_R,\n width: HANDLE_R * 2,\n height: HANDLE_R * 2,\n borderRadius: \"50%\",\n border: \"2px solid rgba(255, 255, 255, 0.8)\",\n background: \"rgba(0, 0, 0, 0.25)\",\n pointerEvents: \"none\",\n }}\n />\n ))}\n </>\n ) : (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: \"rgba(0, 0, 0, 0.5)\",\n pointerEvents: \"none\",\n }}\n />\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useEffect, useRef, useCallback, useState } from \"react\";\n\ninterface InspectorProps {\n onSelect: (element: HTMLElement) => void;\n onCancel: () => void;\n}\n\nexport function Inspector({ onSelect, onCancel }: InspectorProps) {\n const [highlight, setHighlight] = useState<{\n x: number;\n y: number;\n width: number;\n height: number;\n tag: string;\n } | null>(null);\n const hoveredEl = useRef<HTMLElement | null>(null);\n const styleEl = useRef<HTMLStyleElement | null>(null);\n\n // Inject global crosshair cursor style\n useEffect(() => {\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-afterbefore\", \"true\");\n style.textContent = \"*, *::before, *::after { cursor: crosshair !important; }\";\n document.head.appendChild(style);\n styleEl.current = style;\n return () => {\n style.remove();\n };\n }, []);\n\n const isOverlayElement = useCallback((el: Element | null): boolean => {\n let node = el;\n while (node) {\n if (node instanceof HTMLElement && node.dataset.afterbefore) return true;\n node = node.parentElement;\n }\n return false;\n }, []);\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => {\n const el = document.elementFromPoint(e.clientX, e.clientY);\n if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {\n setHighlight(null);\n hoveredEl.current = null;\n return;\n }\n hoveredEl.current = el;\n const rect = el.getBoundingClientRect();\n setHighlight({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n tag: el.tagName.toLowerCase() + (el.className && typeof el.className === \"string\" ? `.${el.className.split(\" \")[0]}` : \"\"),\n });\n },\n [isOverlayElement],\n );\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n if (hoveredEl.current) {\n onSelect(hoveredEl.current);\n }\n },\n [onSelect],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n onCancel();\n }\n },\n [onCancel],\n );\n\n useEffect(() => {\n document.addEventListener(\"mousemove\", handleMouseMove, true);\n document.addEventListener(\"click\", handleClick, true);\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n document.removeEventListener(\"mousemove\", handleMouseMove, true);\n document.removeEventListener(\"click\", handleClick, true);\n document.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [handleMouseMove, handleClick, handleKeyDown]);\n\n return (\n <div data-afterbefore=\"true\" style={{ position: \"fixed\", inset: 0, zIndex: 2147483646, pointerEvents: \"none\" }}>\n {highlight && (\n <>\n {/* Highlight overlay */}\n <div\n style={{\n position: \"fixed\",\n left: highlight.x,\n top: highlight.y,\n width: highlight.width,\n height: highlight.height,\n background: \"rgba(59, 130, 246, 0.15)\",\n border: \"2px solid rgba(59, 130, 246, 0.7)\",\n borderRadius: 2,\n pointerEvents: \"none\",\n }}\n />\n {/* Tag label */}\n <div\n style={{\n position: \"fixed\",\n left: highlight.x,\n top: Math.max(0, highlight.y - 24),\n background: \"rgba(59, 130, 246, 0.9)\",\n color: \"#fff\",\n fontSize: 11,\n fontFamily: \"system-ui, -apple-system, monospace\",\n padding: \"2px 6px\",\n borderRadius: 3,\n pointerEvents: \"none\",\n whiteSpace: \"nowrap\",\n lineHeight: \"18px\",\n }}\n >\n {highlight.tag}\n </div>\n </>\n )}\n\n {/* Instruction hint */}\n {!highlight && (\n <div\n style={{\n position: \"fixed\",\n top: \"50%\",\n left: \"50%\",\n transform: \"translate(-50%, -50%)\",\n color: \"rgba(255, 255, 255, 0.7)\",\n fontSize: 14,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n pointerEvents: \"none\",\n textShadow: \"0 1px 4px rgba(0, 0, 0, 0.5)\",\n background: \"rgba(0, 0, 0, 0.5)\",\n padding: \"8px 16px\",\n borderRadius: 8,\n }}\n >\n Hover to inspect · Click to capture · Esc to cancel\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect, useCallback } from \"react\";\n\ninterface StatusProps {\n onReset: () => void;\n position: { x: number; y: number };\n onClose: () => void;\n}\n\ninterface Toast {\n message: string;\n type: \"success\" | \"error\";\n}\n\nconst PANEL_WIDTH = 220;\n\nexport function Status({ onReset, position, onClose }: StatusProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n const [toast, setToast] = useState<Toast | null>(null);\n const [pushing, setPushing] = useState(false);\n\n const showToast = useCallback((message: string, type: Toast[\"type\"]) => {\n setToast({ message, type });\n setTimeout(() => setToast(null), 3000);\n }, []);\n\n // Click outside to close\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (panelRef.current && !panelRef.current.contains(e.target as Node)) {\n onClose();\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [onClose]);\n\n // Escape to close\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [onClose]);\n\n const handleOpenFolder = async () => {\n try {\n const res = await fetch(\"/__afterbefore/open\", { method: \"POST\" });\n if (!res.ok) throw new Error();\n showToast(\"Opened folder\", \"success\");\n } catch {\n showToast(\"Could not open folder\", \"error\");\n }\n };\n\n const handleCopyMarkdown = async () => {\n try {\n const res = await fetch(\"/__afterbefore/markdown\");\n if (!res.ok) throw new Error();\n const { markdown } = await res.json();\n await navigator.clipboard.writeText(markdown);\n showToast(\"Copied!\", \"success\");\n } catch {\n showToast(\"Copy failed\", \"error\");\n }\n };\n\n const handlePush = async () => {\n setPushing(true);\n try {\n const res = await fetch(\"/__afterbefore/push\", { method: \"POST\" });\n const data = await res.json();\n if (!res.ok) {\n showToast(data.error || \"Push failed\", \"error\");\n } else if (data.pr) {\n showToast(`Posted to PR #${data.pr}`, \"success\");\n } else {\n showToast(\"No PR found\", \"error\");\n }\n } catch {\n showToast(\"Push failed\", \"error\");\n } finally {\n setPushing(false);\n }\n };\n\n const handleReset = () => {\n onReset();\n onClose();\n };\n\n const panelLeft = Math.max(\n 8,\n Math.min(position.x - PANEL_WIDTH / 2 + 20, window.innerWidth - PANEL_WIDTH - 8),\n );\n const panelBottom = window.innerHeight - position.y + 8;\n\n const buttonStyle: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n padding: \"7px 10px\",\n border: \"none\",\n background: \"transparent\",\n color: \"rgba(255,255,255,0.9)\",\n fontSize: 13,\n borderRadius: 6,\n cursor: \"pointer\",\n textAlign: \"left\" as const,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n transition: \"background 0.1s\",\n };\n\n const onEnter = (e: React.MouseEvent) => {\n (e.currentTarget as HTMLButtonElement).style.background =\n \"rgba(255,255,255,0.1)\";\n };\n const onLeave = (e: React.MouseEvent) => {\n (e.currentTarget as HTMLButtonElement).style.background = \"transparent\";\n };\n\n return (\n <div\n ref={panelRef}\n data-afterbefore=\"true\"\n style={{\n position: \"fixed\",\n left: panelLeft,\n bottom: panelBottom,\n width: PANEL_WIDTH,\n background: \"rgba(24, 24, 27, 0.95)\",\n borderRadius: 10,\n boxShadow:\n \"0 4px 20px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.08)\",\n zIndex: 2147483647,\n fontFamily: \"system-ui, -apple-system, sans-serif\",\n backdropFilter: \"blur(12px)\",\n overflow: \"hidden\",\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: \"10px 12px 6px\",\n fontSize: 12,\n fontWeight: 600,\n color: \"rgba(255,255,255,0.5)\",\n letterSpacing: \"0.02em\",\n }}\n >\n Before &amp; After captured\n </div>\n\n {/* Actions */}\n <div style={{ padding: \"0 4px 4px\" }}>\n <button\n style={buttonStyle}\n onClick={handleOpenFolder}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <FolderIcon />\n Open Folder\n </button>\n <button\n style={buttonStyle}\n onClick={handleCopyMarkdown}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <CopyIcon />\n Copy Markdown\n </button>\n <button\n style={buttonStyle}\n onClick={handlePush}\n disabled={pushing}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <PushIcon />\n {pushing ? \"Pushing...\" : \"Push to PR\"}\n </button>\n\n {/* Separator */}\n <div\n style={{\n height: 1,\n background: \"rgba(255,255,255,0.08)\",\n margin: \"4px 6px\",\n }}\n />\n\n <button\n style={{ ...buttonStyle, color: \"rgba(255,255,255,0.5)\" }}\n onClick={handleReset}\n onMouseEnter={onEnter}\n onMouseLeave={onLeave}\n >\n <ResetIcon />\n Reset\n </button>\n </div>\n\n {/* Toast */}\n {toast && (\n <div\n style={{\n position: \"absolute\",\n bottom: \"100%\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n marginBottom: 8,\n padding: \"6px 12px\",\n borderRadius: 6,\n fontSize: 12,\n fontWeight: 500,\n whiteSpace: \"nowrap\",\n color: \"white\",\n background:\n toast.type === \"success\"\n ? \"rgba(34, 197, 94, 0.9)\"\n : \"rgba(239, 68, 68, 0.9)\",\n boxShadow: \"0 2px 8px rgba(0,0,0,0.3)\",\n }}\n >\n {toast.message}\n </div>\n )}\n </div>\n );\n}\n\nfunction FolderIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.5)\" }}\n >\n <path\n d=\"M1.5 3A1.5 1.5 0 013 1.5h2.38a1 1 0 01.72.3L7 2.72a1 1 0 00.72.3H11A1.5 1.5 0 0112.5 4.5v6A1.5 1.5 0 0111 12H3A1.5 1.5 0 011.5 10.5V3z\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n />\n </svg>\n );\n}\n\nfunction CopyIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.5)\" }}\n >\n <rect\n x=\"4\"\n y=\"4\"\n width=\"8.5\"\n height=\"8.5\"\n rx=\"1.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n />\n <path\n d=\"M10 4V2.5A1.5 1.5 0 008.5 1h-6A1.5 1.5 0 001 2.5v6A1.5 1.5 0 002.5 10H4\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n />\n </svg>\n );\n}\n\nfunction PushIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.5)\" }}\n >\n <path\n d=\"M7 11V3m0 0L4 6m3-3l3 3\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nfunction ResetIcon() {\n return (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n style={{ color: \"rgba(255,255,255,0.4)\" }}\n >\n <path\n d=\"M2.5 7a4.5 4.5 0 118 2.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M2.5 3v4h4\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n"],"mappings":"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","names":["useState","useCallback","useRef","useEffect","useCallback","useState","useEffect","useState","jsx","useEffect","useState","React","useRef","useCallback","useEffect","useState","jsx","jsxs","CAMERA_CURSOR","hitCorner","Fragment","jsx","jsxs","useState","useEffect","Icon","useEffect","useRef","useCallback","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","jsx","jsxs","jsx","jsxs","useState","useRef","useEffect","useCallback"]}
@@ -1,8 +1,11 @@
1
1
  import {
2
+ handleGetConfig,
2
3
  handleOpen,
4
+ handlePickFolder,
3
5
  handlePush,
4
- handleSave
5
- } from "../chunk-A73KCX5G.js";
6
+ handleSave,
7
+ handleSetConfig
8
+ } from "../chunk-BFC2HVPX.js";
6
9
 
7
10
  // src/server/middleware.ts
8
11
  import { NextResponse } from "next/server";
@@ -17,6 +20,15 @@ async function handleAfterBefore(req) {
17
20
  if (pathname === "/__afterbefore/open" && req.method === "POST") {
18
21
  return handleOpen(req);
19
22
  }
23
+ if (pathname === "/__afterbefore/config" && req.method === "GET") {
24
+ return handleGetConfig();
25
+ }
26
+ if (pathname === "/__afterbefore/config" && req.method === "POST") {
27
+ return handleSetConfig(req);
28
+ }
29
+ if (pathname === "/__afterbefore/pick-folder" && req.method === "POST") {
30
+ return handlePickFolder();
31
+ }
20
32
  return NextResponse.json({ error: "Not found" }, { status: 404 });
21
33
  }
22
34
  var config = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/middleware.ts"],"sourcesContent":["import { NextRequest, NextResponse } from \"next/server\";\nimport { handleSave } from \"./save\";\nimport { handlePush } from \"./push\";\nimport { handleOpen } from \"./open\";\n\nexport async function handleAfterBefore(\n req: NextRequest,\n): Promise<NextResponse> {\n const { pathname } = req.nextUrl;\n\n if (pathname === \"/__afterbefore/save\" && req.method === \"POST\") {\n return handleSave(req);\n }\n if (pathname === \"/__afterbefore/push\" && req.method === \"POST\") {\n return handlePush(req);\n }\n if (pathname === \"/__afterbefore/open\" && req.method === \"POST\") {\n return handleOpen(req);\n }\n\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n}\n\nexport const config = {\n matcher: \"/__afterbefore/:path*\",\n};\n"],"mappings":";;;;;;;AAAA,SAAsB,oBAAoB;AAK1C,eAAsB,kBACpB,KACuB;AACvB,QAAM,EAAE,SAAS,IAAI,IAAI;AAEzB,MAAI,aAAa,yBAAyB,IAAI,WAAW,QAAQ;AAC/D,WAAO,WAAW,GAAG;AAAA,EACvB;AACA,MAAI,aAAa,yBAAyB,IAAI,WAAW,QAAQ;AAC/D,WAAO,WAAW,GAAG;AAAA,EACvB;AACA,MAAI,aAAa,yBAAyB,IAAI,WAAW,QAAQ;AAC/D,WAAO,WAAW,GAAG;AAAA,EACvB;AAEA,SAAO,aAAa,KAAK,EAAE,OAAO,YAAY,GAAG,EAAE,QAAQ,IAAI,CAAC;AAClE;AAEO,IAAM,SAAS;AAAA,EACpB,SAAS;AACX;","names":[]}
1
+ {"version":3,"sources":["../../src/server/middleware.ts"],"sourcesContent":["import { NextRequest, NextResponse } from \"next/server\";\nimport { handleSave } from \"./save\";\nimport { handlePush } from \"./push\";\nimport { handleOpen } from \"./open\";\nimport { handleGetConfig, handleSetConfig, handlePickFolder } from \"./config\";\n\nexport async function handleAfterBefore(\n req: NextRequest,\n): Promise<NextResponse> {\n const { pathname } = req.nextUrl;\n\n if (pathname === \"/__afterbefore/save\" && req.method === \"POST\") {\n return handleSave(req);\n }\n if (pathname === \"/__afterbefore/push\" && req.method === \"POST\") {\n return handlePush(req);\n }\n if (pathname === \"/__afterbefore/open\" && req.method === \"POST\") {\n return handleOpen(req);\n }\n if (pathname === \"/__afterbefore/config\" && req.method === \"GET\") {\n return handleGetConfig();\n }\n if (pathname === \"/__afterbefore/config\" && req.method === \"POST\") {\n return handleSetConfig(req);\n }\n if (pathname === \"/__afterbefore/pick-folder\" && req.method === \"POST\") {\n return handlePickFolder();\n }\n\n return NextResponse.json({ error: \"Not found\" }, { status: 404 });\n}\n\nexport const config = {\n matcher: \"/__afterbefore/:path*\",\n};\n"],"mappings":";;;;;;;;;;AAAA,SAAsB,oBAAoB;AAM1C,eAAsB,kBACpB,KACuB;AACvB,QAAM,EAAE,SAAS,IAAI,IAAI;AAEzB,MAAI,aAAa,yBAAyB,IAAI,WAAW,QAAQ;AAC/D,WAAO,WAAW,GAAG;AAAA,EACvB;AACA,MAAI,aAAa,yBAAyB,IAAI,WAAW,QAAQ;AAC/D,WAAO,WAAW,GAAG;AAAA,EACvB;AACA,MAAI,aAAa,yBAAyB,IAAI,WAAW,QAAQ;AAC/D,WAAO,WAAW,GAAG;AAAA,EACvB;AACA,MAAI,aAAa,2BAA2B,IAAI,WAAW,OAAO;AAChE,WAAO,gBAAgB;AAAA,EACzB;AACA,MAAI,aAAa,2BAA2B,IAAI,WAAW,QAAQ;AACjE,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AACA,MAAI,aAAa,gCAAgC,IAAI,WAAW,QAAQ;AACtE,WAAO,iBAAiB;AAAA,EAC1B;AAEA,SAAO,aAAa,KAAK,EAAE,OAAO,YAAY,GAAG,EAAE,QAAQ,IAAI,CAAC;AAClE;AAEO,IAAM,SAAS;AAAA,EACpB,SAAS;AACX;","names":[]}
@@ -2,7 +2,7 @@ import {
2
2
  handleOpen,
3
3
  handlePush,
4
4
  handleSave
5
- } from "../chunk-A73KCX5G.js";
5
+ } from "../chunk-BFC2HVPX.js";
6
6
 
7
7
  // src/server/route.ts
8
8
  import { NextResponse } from "next/server";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "afterbefore",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Before/after screenshot overlay for Next.js development",
5
5
  "type": "module",
6
6
  "main": "./dist/overlay/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/save.ts","../src/server/push.ts","../src/server/open.ts"],"sourcesContent":["import { NextRequest, NextResponse } from \"next/server\";\nimport { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nasync function getBranch(): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], {\n cwd: process.cwd(),\n });\n return stdout.trim();\n}\n\nconst VALID_TYPES = [\"before\", \"after\"] as const;\ntype ScreenshotType = (typeof VALID_TYPES)[number];\n\nconst VALID_MODES = [\"fullpage\", \"viewport\", \"area\", \"component\"] as const;\n\nconst DATA_URL_PREFIX = \"data:image/png;base64,\";\n\ninterface SaveRequestBody {\n type: ScreenshotType;\n mode: string;\n image: string;\n}\n\nexport async function handleSave(req: NextRequest): Promise<NextResponse> {\n let body: SaveRequestBody;\n try {\n body = await req.json();\n } catch {\n return NextResponse.json(\n { error: \"Invalid JSON body\" },\n { status: 400 },\n );\n }\n\n const { type, mode, image } = body;\n\n if (!VALID_TYPES.includes(type as ScreenshotType)) {\n return NextResponse.json(\n { error: `Invalid type: must be \"before\" or \"after\"` },\n { status: 400 },\n );\n }\n\n if (!VALID_MODES.includes(mode as (typeof VALID_MODES)[number])) {\n return NextResponse.json(\n { error: `Invalid mode: must be \"fullpage\", \"viewport\", or \"area\"` },\n { status: 400 },\n );\n }\n\n if (typeof image !== \"string\" || !image.startsWith(DATA_URL_PREFIX)) {\n return NextResponse.json(\n { error: \"Invalid image: must be a data:image/png;base64 data URL\" },\n { status: 400 },\n );\n }\n\n const base64 = image.slice(DATA_URL_PREFIX.length);\n const buffer = Buffer.from(base64, \"base64\");\n\n const branch = await getBranch();\n const filename = `${branch}-${type}.png`;\n const filepath = join(homedir(), \"Desktop\", filename);\n\n try {\n await writeFile(filepath, buffer);\n } catch (err) {\n return NextResponse.json(\n { error: \"Failed to write screenshot\", detail: String(err) },\n { status: 500 },\n );\n }\n\n return NextResponse.json({ success: true, path: `~/Desktop/${filename}` });\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { access, mkdir, copyFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\ninterface PrInfo {\n number: number;\n url: string;\n headRepository: { owner: { login: string }; name: string };\n headRefName: string;\n}\n\nasync function run(\n cmd: string,\n args: string[],\n): Promise<{ stdout: string; stderr: string }> {\n return execFileAsync(cmd, args, { cwd: process.cwd() });\n}\n\nasync function ghAvailable(): Promise<boolean> {\n try {\n await run(\"gh\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function getPrInfo(): Promise<PrInfo | null> {\n try {\n const { stdout } = await run(\"gh\", [\n \"pr\",\n \"view\",\n \"--json\",\n \"number,url,headRepository,headRefName\",\n ]);\n return JSON.parse(stdout) as PrInfo;\n } catch {\n return null;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function handlePush(req: NextRequest): Promise<NextResponse> {\n // 1. Check gh CLI availability\n if (!(await ghAvailable())) {\n return NextResponse.json(\n { success: false, error: \"GitHub CLI (gh) is not installed or not in PATH\" },\n { status: 500 },\n );\n }\n\n // 2. Check for active PR\n const pr = await getPrInfo();\n if (!pr) {\n return NextResponse.json(\n { success: false, error: \"No PR found for current branch\" },\n { status: 404 },\n );\n }\n\n // 3. Check that screenshot files exist on Desktop\n const desktop = join(homedir(), \"Desktop\");\n const branch = pr.headRefName;\n const beforePath = join(desktop, `${branch}-before.png`);\n const afterPath = join(desktop, `${branch}-after.png`);\n\n const [hasBefore, hasAfter] = await Promise.all([\n fileExists(beforePath),\n fileExists(afterPath),\n ]);\n\n if (!hasBefore || !hasAfter) {\n const missing = [\n !hasBefore && `${branch}-before.png`,\n !hasAfter && `${branch}-after.png`,\n ].filter(Boolean);\n return NextResponse.json(\n { success: false, error: `Missing screenshots: ${missing.join(\", \")}` },\n { status: 400 },\n );\n }\n\n // 4. Copy from Desktop into repo, stage, commit, and push\n const repoDir = join(process.cwd(), \".afterbefore\");\n const repoBefore = join(repoDir, `${branch}-before.png`);\n const repoAfter = join(repoDir, `${branch}-after.png`);\n\n try {\n await mkdir(repoDir, { recursive: true });\n await copyFile(beforePath, repoBefore);\n await copyFile(afterPath, repoAfter);\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to copy screenshots into repo\", detail: String(err) },\n { status: 500 },\n );\n }\n\n try {\n await run(\"git\", [\"add\", repoBefore, repoAfter]);\n await run(\"git\", [\n \"commit\",\n \"-m\",\n \"chore: add before/after screenshots\",\n ]);\n } catch (err) {\n // Commit may fail if files are already committed with no changes.\n // That's fine -- we still want to push and comment.\n const msg = String(err);\n if (!msg.includes(\"nothing to commit\")) {\n return NextResponse.json(\n { success: false, error: \"Failed to commit screenshots\", detail: msg },\n { status: 500 },\n );\n }\n }\n\n try {\n await run(\"git\", [\"push\"]);\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to push to remote\", detail: String(err) },\n { status: 500 },\n );\n }\n\n // 5. Build raw GitHub URLs for the images\n const owner = pr.headRepository.owner.login;\n const repo = pr.headRepository.name;\n const rawBase = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;\n\n const beforeUrl = `${rawBase}/.afterbefore/${branch}-before.png`;\n const afterUrl = `${rawBase}/.afterbefore/${branch}-after.png`;\n\n // Cache-bust with timestamp so GitHub doesn't serve stale images\n const ts = Date.now();\n const commentBody = [\n \"## Before / After\",\n \"\",\n \"| Before | After |\",\n \"|--------|-------|\",\n `| ![before](${beforeUrl}?t=${ts}) | ![after](${afterUrl}?t=${ts}) |`,\n ].join(\"\\n\");\n\n // 6. Post PR comment\n let commentUrl: string | undefined;\n try {\n const { stdout } = await run(\"gh\", [\n \"pr\",\n \"comment\",\n String(pr.number),\n \"--body\",\n commentBody,\n ]);\n // gh pr comment prints the comment URL to stdout\n commentUrl = stdout.trim() || undefined;\n } catch (err) {\n return NextResponse.json(\n { success: false, error: \"Failed to post PR comment\", detail: String(err) },\n { status: 500 },\n );\n }\n\n return NextResponse.json({\n success: true,\n prNumber: pr.number,\n prUrl: pr.url,\n commentUrl,\n });\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { execFile } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport async function handleOpen(_req: NextRequest): Promise<NextResponse> {\n const desktop = join(homedir(), \"Desktop\");\n\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"explorer\"\n : \"xdg-open\";\n\n execFile(cmd, [desktop]);\n\n return NextResponse.json({ success: true });\n}\n"],"mappings":"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","names":["NextResponse","execFile","join","homedir","promisify","execFileAsync","NextResponse","execFile","join","homedir"]}