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.
- package/dist/{chunk-A73KCX5G.js → chunk-BFC2HVPX.js} +111 -43
- package/dist/chunk-BFC2HVPX.js.map +1 -0
- package/dist/overlay/index.js +102 -49
- package/dist/overlay/index.js.map +1 -1
- package/dist/server/middleware.js +14 -2
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/route.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-A73KCX5G.js.map +0 -1
|
@@ -1,13 +1,80 @@
|
|
|
1
|
-
// src/server/
|
|
2
|
-
import {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
119
|
+
const filepath = join2(saveDir, filename);
|
|
52
120
|
try {
|
|
53
|
-
await
|
|
121
|
+
await writeFile2(filepath, buffer);
|
|
54
122
|
} catch (err) {
|
|
55
|
-
return
|
|
123
|
+
return NextResponse2.json(
|
|
56
124
|
{ error: "Failed to write screenshot", detail: String(err) },
|
|
57
125
|
{ status: 500 }
|
|
58
126
|
);
|
|
59
127
|
}
|
|
60
|
-
return
|
|
128
|
+
return NextResponse2.json({ success: true, path: filepath });
|
|
61
129
|
}
|
|
62
130
|
|
|
63
131
|
// src/server/push.ts
|
|
64
|
-
import { NextResponse as
|
|
65
|
-
import { execFile as
|
|
66
|
-
import { access, mkdir, copyFile } from "fs/promises";
|
|
67
|
-
import { join as
|
|
68
|
-
import {
|
|
69
|
-
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
184
|
+
const desktop = await getSaveDir();
|
|
118
185
|
const branch = pr.headRefName;
|
|
119
|
-
const beforePath =
|
|
120
|
-
const afterPath =
|
|
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
|
|
197
|
+
return NextResponse3.json(
|
|
131
198
|
{ success: false, error: `Missing screenshots: ${missing.join(", ")}` },
|
|
132
199
|
{ status: 400 }
|
|
133
200
|
);
|
|
134
201
|
}
|
|
135
|
-
const repoDir =
|
|
136
|
-
const repoBefore =
|
|
137
|
-
const repoAfter =
|
|
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
|
|
206
|
+
await mkdir2(repoDir, { recursive: true });
|
|
140
207
|
await copyFile(beforePath, repoBefore);
|
|
141
208
|
await copyFile(afterPath, repoAfter);
|
|
142
209
|
} catch (err) {
|
|
143
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
211
|
-
import { execFile as
|
|
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 =
|
|
280
|
+
const desktop = await getSaveDir();
|
|
216
281
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "explorer" : "xdg-open";
|
|
217
|
-
|
|
218
|
-
return
|
|
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-
|
|
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 `|  |  |`,\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"]}
|
package/dist/overlay/index.js
CHANGED
|
@@ -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
|
|
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:
|
|
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("
|
|
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 & 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 & 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
|
-
|
|
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":"
|
|
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":[]}
|
package/dist/server/route.js
CHANGED
package/package.json
CHANGED
|
@@ -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 `|  |  |`,\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"]}
|