paintress 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/README.zh-CN.md +3 -2
- package/dist/cli.js +183 -15
- package/dist/index.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/{render-YpsrjGNy.js → render-CzpO1cOe.js} +21 -2
- package/dist/{server-19PJh0Vn.js → server-vPylVJZf.js} +64 -17
- package/package.json +1 -1
- package/skills/paintress/SKILL.md +2 -2
- package/ui/dist/assets/index-Dyrrkh92.css +1 -0
- package/ui/dist/assets/index-kPX0SDa0.js +8 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-BEKlFXv9.css +0 -1
- package/ui/dist/assets/index-om6XE6pt.js +0 -7
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ paintress move <file> <id> <parent> [--index n] reparent a node
|
|
|
56
56
|
paintress batch <file> '<ops-json>' several operations at once
|
|
57
57
|
paintress validate <file> check against the format spec
|
|
58
58
|
paintress render <file> <out.html> write the canvas as HTML
|
|
59
|
-
paintress shot <file> <out.png> [--scale n]
|
|
59
|
+
paintress shot <file> <out.png> [--scale n] [--board id|name] render to PNG (one board or the whole canvas)
|
|
60
60
|
|
|
61
61
|
paintress web [--port n] [--idle ms] [--daemon] start the viewer
|
|
62
62
|
paintress ping | status | stop viewer control
|
|
@@ -78,6 +78,10 @@ paintress watch demo ./demo
|
|
|
78
78
|
|
|
79
79
|
Canvas navigation: wheel zooms at the pointer, space / middle button / empty area drags to pan, `Ctrl/Cmd+0` returns to 100%, `Shift+1` fits the window. Files with more than one board get a board strip. Edits made through the CLI or MCP are highlighted in the viewer, and clicks assign short ids that the agent can read back with `paintress_marks`.
|
|
80
80
|
|
|
81
|
+
Project rows have an **×** on hover that unbinds the project (design files are untouched; an agent re-registers on its next start), and **Stop server** in the sidebar footer shuts the viewer process down — both ask for confirmation first.
|
|
82
|
+
|
|
83
|
+
When npm has a newer release than the running one, the version badge in the header grows a second line in rust red; clicking it opens the upgrade prompt (one copyable sentence) and the GitHub link. The check is client-optional on the daemon side: if npm is unreachable, the badge simply stays as it is.
|
|
84
|
+
|
|
81
85
|
The toolbar's right side has two viewer-only controls. **Canvas background** switches Light / Gray / Dark for the design surface without touching the rest of the UI (click a stop or drag the knob). **Language** switches the interface between 中文 and EN; on first load it follows the browser, and anything that is not Chinese gets English. Both are per-browser and remembered locally. Registering a project, or dropping a new `.ptr` / `.pen` into a watched directory, updates every open viewer without a reload.
|
|
82
86
|
|
|
83
87
|
## MCP clients
|
|
@@ -112,18 +116,19 @@ paintress mcp-config cursor # print the exact snippet instead of editing files
|
|
|
112
116
|
|
|
113
117
|
## Release (maintainers)
|
|
114
118
|
|
|
115
|
-
Publishing is tag-driven: a `v*` tag makes `.github/workflows/publish.yml` build,
|
|
119
|
+
Publishing is tag-driven: a `v*` tag makes `.github/workflows/publish.yml` first check that **ci passed for the same commit**, then build, verify the package contents and run `npm publish --provenance` through OIDC trusted publishing. Tests run once, in `ci.yml`; publishing does not re-run them. Do not publish from a laptop.
|
|
116
120
|
|
|
117
121
|
```bash
|
|
118
122
|
pnpm release patch # 0.3.1 → 0.3.2
|
|
119
123
|
pnpm release minor # 0.3.1 → 0.4.0
|
|
120
124
|
pnpm release major # 0.3.1 → 1.0.0
|
|
121
125
|
pnpm release patch --dry-run # print the plan only
|
|
126
|
+
pnpm release --retag # after a failed release: move the unpublished tag and re-publish
|
|
122
127
|
```
|
|
123
128
|
|
|
124
129
|
The script refuses to run on a dirty worktree or a non-default branch, verifies the tag is free, runs typecheck (server + ui), the test suite, the build and the package-contents check, then commits `chore(release): vX.Y.Z`, tags it, pushes branch + tag, and finally waits until the version is actually on npm (a green run that published nothing is reported as a failure, not a success).
|
|
125
130
|
|
|
126
|
-
`--prepare-only` stops after the local commit and tag; `--no-wait` returns right after the push; `--local` publishes from this machine as an emergency path and skips the CI checks.
|
|
131
|
+
`--prepare-only` stops after the local commit and tag; `--no-wait` returns right after the push; `--local` publishes from this machine as an emergency path and skips the CI checks. `--retag` is the recovery path after a failed release: once it confirms the version is not on npm yet, it moves the existing tag to the current commit and re-publishes under the same version number; an already published version is refused.
|
|
127
132
|
|
|
128
133
|
## License
|
|
129
134
|
|
package/README.zh-CN.md
CHANGED
|
@@ -112,18 +112,19 @@ paintress mcp-config cursor # 只打印片段,不改文件
|
|
|
112
112
|
|
|
113
113
|
## 发版(维护者)
|
|
114
114
|
|
|
115
|
-
发布由 tag 驱动:`v*` tag 会让 `.github/workflows/publish.yml`
|
|
115
|
+
发布由 tag 驱动:`v*` tag 会让 `.github/workflows/publish.yml` 先校验**同一提交的 ci 已通过**,再构建、自检包内容并通过 OIDC trusted publishing 执行 `npm publish --provenance`。测试只在 `ci.yml` 跑一次,发布不重跑。不要在笔记本上直接发布。
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
118
|
pnpm release patch # 0.3.1 → 0.3.2
|
|
119
119
|
pnpm release minor # 0.3.1 → 0.4.0
|
|
120
120
|
pnpm release major # 0.3.1 → 1.0.0
|
|
121
121
|
pnpm release patch --dry-run # 只打印计划
|
|
122
|
+
pnpm release --retag # 发版失败后:把未发布的 tag 移到当前提交重发
|
|
122
123
|
```
|
|
123
124
|
|
|
124
125
|
脚本会拒绝在脏工作区或非默认分支上发版,确认 tag 未被占用,跑类型检查(服务端 + ui)、测试、构建与包内容自检,然后提交 `chore(release): vX.Y.Z`、打 tag、推分支与 tag,最后等到版本真的出现在 npm 上才算完(CI 绿了但什么都没发出去,会如实报成失败)。
|
|
125
126
|
|
|
126
|
-
`--prepare-only` 停在本地提交与 tag;`--no-wait` 推完就返回;`--local` 本机直接发布,是应急路径,会跳过 CI
|
|
127
|
+
`--prepare-only` 停在本地提交与 tag;`--no-wait` 推完就返回;`--local` 本机直接发布,是应急路径,会跳过 CI 的检查。`--retag` 是发版失败后的恢复路径:确认该版本还没上 npm 后,把已有 tag 移到当前提交重发(版本号不变);已发布的版本会被拒绝。
|
|
127
128
|
|
|
128
129
|
## 许可
|
|
129
130
|
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as isDaemonRunning, c as pidPath, d as sanitizeProjectName, f as socketPath, i as attachPersistent, l as resolveProjectDir, m as encodeLine, n as runStdioServer, o as sendRequest, p as LineDecoder, r as TOOLS, s as lockPath, u as safeJoin } from "./server-
|
|
3
|
-
import {
|
|
2
|
+
import { a as isDaemonRunning, c as pidPath, d as sanitizeProjectName, f as socketPath, i as attachPersistent, l as resolveProjectDir, m as encodeLine, n as runStdioServer, o as sendRequest, p as LineDecoder, r as TOOLS, s as lockPath, u as safeJoin } from "./server-vPylVJZf.js";
|
|
3
|
+
import { T as loadDoc, qt as VERSION, t as renderDocument } from "./render-CzpO1cOe.js";
|
|
4
4
|
import "./index.js";
|
|
5
5
|
import { chmodSync, closeSync, copyFileSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { homedir } from "node:os";
|
|
@@ -21,7 +21,7 @@ const DESIGN_EXT = /* @__PURE__ */ new Set([".ptr", ".pen"]);
|
|
|
21
21
|
var Registry = class {
|
|
22
22
|
projects = /* @__PURE__ */ new Map();
|
|
23
23
|
/** 注册(或复用)项目目录;同名不同目录视为冲突。depth 默认 3、上限 6 */
|
|
24
|
-
watch(projectNameRaw, dir, depth) {
|
|
24
|
+
watch(projectNameRaw, dir, depth, opts = {}) {
|
|
25
25
|
const name = sanitizeProjectName(projectNameRaw);
|
|
26
26
|
const { root, rootReal } = resolveProjectDir(dir);
|
|
27
27
|
const wanted = clampDepth(depth);
|
|
@@ -30,6 +30,7 @@ var Registry = class {
|
|
|
30
30
|
if (existing.rootReal !== rootReal) throw new Error(`项目名 "${name}" 已被 ${existing.root} 占用,请换一个名字(--name)`);
|
|
31
31
|
if (depth !== void 0) existing.depth = wanted;
|
|
32
32
|
existing.lastAccess = Date.now();
|
|
33
|
+
if (opts.owner === "manual") existing.owner = "manual";
|
|
33
34
|
return existing;
|
|
34
35
|
}
|
|
35
36
|
const entry = {
|
|
@@ -39,6 +40,7 @@ var Registry = class {
|
|
|
39
40
|
depth: wanted,
|
|
40
41
|
agents: /* @__PURE__ */ new Set(),
|
|
41
42
|
browsers: /* @__PURE__ */ new Set(),
|
|
43
|
+
owner: opts.owner ?? "manual",
|
|
42
44
|
lastAccess: Date.now(),
|
|
43
45
|
createdAt: Date.now()
|
|
44
46
|
};
|
|
@@ -339,6 +341,57 @@ var WatchManager = class {
|
|
|
339
341
|
await Promise.all([...this.designs.values()].map((d) => d.close()));
|
|
340
342
|
}
|
|
341
343
|
};
|
|
344
|
+
// src/web/update-check.ts
|
|
345
|
+
const OK_TTL_MS = 216e5;
|
|
346
|
+
const FAIL_TTL_MS = 6e5;
|
|
347
|
+
const TIMEOUT_MS = 3e3;
|
|
348
|
+
const REGISTRY_URL = "https://registry.npmjs.org/paintress/latest";
|
|
349
|
+
/** 当前缓存是否已经过期(没有缓存也算过期) */
|
|
350
|
+
function shouldRefresh(state, now = Date.now()) {
|
|
351
|
+
if (state === null) return true;
|
|
352
|
+
const ttl = state.version === null ? FAIL_TTL_MS : OK_TTL_MS;
|
|
353
|
+
return now - state.checkedAt >= ttl;
|
|
354
|
+
}
|
|
355
|
+
/** 查一次 npm;任何失败(离线 / 超时 / 404 / 坏 JSON)都返回 null,不抛 */
|
|
356
|
+
async function fetchLatestVersion(fetchImpl = fetch, timeoutMs = TIMEOUT_MS) {
|
|
357
|
+
try {
|
|
358
|
+
const res = await fetchImpl(REGISTRY_URL, { signal: AbortSignal.timeout(timeoutMs) });
|
|
359
|
+
if (!res.ok) return null;
|
|
360
|
+
const body = await res.json();
|
|
361
|
+
return typeof body.version === "string" && body.version !== "" ? body.version : null;
|
|
362
|
+
} catch {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
var VersionChecker = class {
|
|
367
|
+
fetcher;
|
|
368
|
+
state = null;
|
|
369
|
+
inFlight = null;
|
|
370
|
+
constructor(fetcher = () => fetchLatestVersion()) {
|
|
371
|
+
this.fetcher = fetcher;
|
|
372
|
+
}
|
|
373
|
+
/** 已完成探测的最新版号(没查到为 null) */
|
|
374
|
+
get latest() {
|
|
375
|
+
return this.state?.version ?? null;
|
|
376
|
+
}
|
|
377
|
+
/** 读当前值并在后台刷新(不阻塞调用方) */
|
|
378
|
+
peek() {
|
|
379
|
+
if (shouldRefresh(this.state) && this.inFlight === null) {
|
|
380
|
+
const task = this.refresh().finally(() => {
|
|
381
|
+
this.inFlight = null;
|
|
382
|
+
});
|
|
383
|
+
this.inFlight = task;
|
|
384
|
+
}
|
|
385
|
+
return this.latest;
|
|
386
|
+
}
|
|
387
|
+
async refresh() {
|
|
388
|
+
const version = await this.fetcher();
|
|
389
|
+
this.state = {
|
|
390
|
+
version,
|
|
391
|
+
checkedAt: Date.now()
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
};
|
|
342
395
|
// src/web/daemon.ts
|
|
343
396
|
const DEFAULT_PORT = 3316;
|
|
344
397
|
const MIME = {
|
|
@@ -442,12 +495,21 @@ function layout(title, body) {
|
|
|
442
495
|
function esc(s) {
|
|
443
496
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
444
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* 破坏性写接口的 CSRF 门槛:要求自定义头 `x-paintress: 1`。
|
|
500
|
+
* 跨站 fetch 带自定义头会触发 CORS 预检,而 daemon 从不应答预检 —— 跳站页面发不出该请求。
|
|
501
|
+
* 不做 Origin 白名单:手机经隧道/反代访问时 Origin 是本机看不到的域名,白名单会误伤正常使用。
|
|
502
|
+
*/
|
|
503
|
+
function isTrustedWrite(req) {
|
|
504
|
+
return req.headers["x-paintress"] === "1";
|
|
505
|
+
}
|
|
445
506
|
async function startDaemon(opts = {}) {
|
|
446
507
|
const releaseLock = acquireLock();
|
|
447
508
|
const registry = new Registry();
|
|
448
509
|
const marks = new MarksStore();
|
|
449
510
|
const changes = new ChangesStore();
|
|
450
511
|
const watchers = new WatchManager();
|
|
512
|
+
const versions = new VersionChecker();
|
|
451
513
|
const startedAt = Date.now();
|
|
452
514
|
const idleTimeoutMs = opts.idleTimeoutMs ?? 6e4;
|
|
453
515
|
const idleCheckMs = opts.idleCheckMs ?? 15e3;
|
|
@@ -458,6 +520,10 @@ async function startDaemon(opts = {}) {
|
|
|
458
520
|
* 项目列表变化时推 `projects` 事件,避免用户按 F5 才看到新项目。
|
|
459
521
|
*/
|
|
460
522
|
const registryClients = /* @__PURE__ */ new Set();
|
|
523
|
+
/** 控制面长连接:shutdown 时必须主动结束,否则 server.close() 会一直等 agent attach */
|
|
524
|
+
const controlClients = /* @__PURE__ */ new Set();
|
|
525
|
+
/** 将被关闭的长连接数:agent attach + 设计稿 SSE + 项目列表 SSE */
|
|
526
|
+
const connectionCount = () => registryClients.size + registry.all().reduce((n, p) => n + p.agents.size + p.browsers.size, 0);
|
|
461
527
|
const notifyRegistry = () => {
|
|
462
528
|
const payload = JSON.stringify({
|
|
463
529
|
projects: registry.all().length,
|
|
@@ -483,15 +549,59 @@ async function startDaemon(opts = {}) {
|
|
|
483
549
|
}, 150);
|
|
484
550
|
registryTimer.unref?.();
|
|
485
551
|
};
|
|
552
|
+
/**
|
|
553
|
+
* agent 自动注册的项目退场:连接归零且无浏览器在看的宽限期后 unwatch。
|
|
554
|
+
* - 宽限期跨过 agent 崩溃重启的窗口(新进程会重新 watch/attach,定时器随即撤销)
|
|
555
|
+
* - 浏览器 SSE 开着时永不退场
|
|
556
|
+
* - 人手动 watch 的项目(owner=manual)不参与自动退场
|
|
557
|
+
*/
|
|
558
|
+
const autoDetachMs = opts.autoDetachMs ?? 45e3;
|
|
559
|
+
const autoDetachTimers = /* @__PURE__ */ new Map();
|
|
560
|
+
function cancelAutoDetach(name) {
|
|
561
|
+
const timer = autoDetachTimers.get(name);
|
|
562
|
+
if (timer === void 0) return;
|
|
563
|
+
clearTimeout(timer);
|
|
564
|
+
autoDetachTimers.delete(name);
|
|
565
|
+
}
|
|
566
|
+
/** 移除项目并释放目录监听(与 unwatch 同一套收尾),返回是否真的移除了 */
|
|
567
|
+
function detachProject(entry, reason) {
|
|
568
|
+
cancelAutoDetach(entry.name);
|
|
569
|
+
if (!registry.remove(entry.name)) return false;
|
|
570
|
+
if (!registry.all().some((p) => p.rootReal === entry.rootReal)) watchers.unwatchDesigns(entry.rootReal);
|
|
571
|
+
if (!opts.quiet) process.stderr.write(`paintress web: 解绑项目 ${entry.name}(${reason})\n`);
|
|
572
|
+
notifyRegistry();
|
|
573
|
+
return true;
|
|
574
|
+
}
|
|
575
|
+
function maybeScheduleAutoDetach(name) {
|
|
576
|
+
if (closing) return;
|
|
577
|
+
const entry = registry.get(name);
|
|
578
|
+
if (entry === void 0 || entry.owner !== "agent" || !registry.isIdle(entry)) {
|
|
579
|
+
cancelAutoDetach(name);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (autoDetachTimers.has(name)) return;
|
|
583
|
+
const timer = setTimeout(() => {
|
|
584
|
+
autoDetachTimers.delete(name);
|
|
585
|
+
const current = registry.get(name);
|
|
586
|
+
if (current === void 0 || current.owner !== "agent" || !registry.isIdle(current)) return;
|
|
587
|
+
detachProject(current, "agent 已退出");
|
|
588
|
+
}, autoDetachMs);
|
|
589
|
+
timer.unref?.();
|
|
590
|
+
autoDetachTimers.set(name, timer);
|
|
591
|
+
}
|
|
486
592
|
/** 控制面:一个连接可同时作为 agent 存活信号 */
|
|
487
593
|
const handleClient = (socket) => {
|
|
594
|
+
controlClients.add(socket);
|
|
595
|
+
socket.on("close", () => controlClients.delete(socket));
|
|
488
596
|
const decoder = new LineDecoder();
|
|
489
597
|
let attachToken = null;
|
|
490
598
|
const cleanup = () => {
|
|
491
599
|
if (!attachToken) return;
|
|
492
|
-
const
|
|
600
|
+
const gone = attachToken.project;
|
|
601
|
+
const entry = registry.get(gone);
|
|
493
602
|
if (entry) entry.agents.delete(attachToken.token);
|
|
494
603
|
attachToken = null;
|
|
604
|
+
maybeScheduleAutoDetach(gone);
|
|
495
605
|
};
|
|
496
606
|
socket.on("close", cleanup);
|
|
497
607
|
socket.on("error", cleanup);
|
|
@@ -531,7 +641,8 @@ async function startDaemon(opts = {}) {
|
|
|
531
641
|
});
|
|
532
642
|
break;
|
|
533
643
|
case "watch": {
|
|
534
|
-
const entry = registry.watch(req.project, req.dir, req.depth);
|
|
644
|
+
const entry = registry.watch(req.project, req.dir, req.depth, req.owner === "agent" ? { owner: "agent" } : {});
|
|
645
|
+
cancelAutoDetach(entry.name);
|
|
535
646
|
watchers.watchDesigns(entry.rootReal, entry.depth, scheduleRegistryNotify);
|
|
536
647
|
reply({
|
|
537
648
|
ok: true,
|
|
@@ -543,20 +654,17 @@ async function startDaemon(opts = {}) {
|
|
|
543
654
|
}
|
|
544
655
|
case "unwatch": {
|
|
545
656
|
const before = registry.get(req.project);
|
|
546
|
-
const removed =
|
|
657
|
+
const removed = before === void 0 ? false : detachProject(before, "unwatch");
|
|
547
658
|
reply({
|
|
548
659
|
ok: true,
|
|
549
660
|
unwatched: removed
|
|
550
661
|
});
|
|
551
|
-
if (removed) {
|
|
552
|
-
if (before && !registry.all().some((p) => p.rootReal === before.rootReal)) watchers.unwatchDesigns(before.rootReal);
|
|
553
|
-
notifyRegistry();
|
|
554
|
-
}
|
|
555
662
|
break;
|
|
556
663
|
}
|
|
557
664
|
case "attach": {
|
|
558
665
|
const entry = registry.get(req.project);
|
|
559
666
|
if (!entry) throw new Error(`项目未注册:${req.project}`);
|
|
667
|
+
cancelAutoDetach(req.project);
|
|
560
668
|
const token = Symbol(`agent:${req.project}`);
|
|
561
669
|
entry.agents.add(token);
|
|
562
670
|
attachToken = {
|
|
@@ -669,10 +777,38 @@ async function startDaemon(opts = {}) {
|
|
|
669
777
|
pid: process.pid,
|
|
670
778
|
uptimeMs: Date.now() - startedAt,
|
|
671
779
|
version: VERSION,
|
|
780
|
+
latest: opts.updateCheck === true ? versions.peek() : null,
|
|
781
|
+
connections: connectionCount(),
|
|
672
782
|
projects: registry.all().map((p) => registry.info(p))
|
|
673
783
|
});
|
|
674
784
|
return;
|
|
675
785
|
}
|
|
786
|
+
if (segments[1] === "version" && segments.length === 2) {
|
|
787
|
+
sendJson(200, {
|
|
788
|
+
ok: true,
|
|
789
|
+
pid: process.pid,
|
|
790
|
+
version: VERSION,
|
|
791
|
+
latest: opts.updateCheck === true ? versions.peek() : null,
|
|
792
|
+
connections: connectionCount()
|
|
793
|
+
});
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
if (segments[1] === "projects" && segments.length === 3 && req.method === "DELETE") {
|
|
797
|
+
if (!isTrustedWrite(req)) {
|
|
798
|
+
sendJson(403, {
|
|
799
|
+
ok: false,
|
|
800
|
+
error: "缺少 x-paintress 头"
|
|
801
|
+
});
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const name = decodeURIComponent(segments[2] ?? "");
|
|
805
|
+
const entry = registry.get(name);
|
|
806
|
+
sendJson(200, {
|
|
807
|
+
ok: true,
|
|
808
|
+
unwatched: entry === void 0 ? false : detachProject(entry, "web 界面解绑")
|
|
809
|
+
});
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
676
812
|
if (segments[1] === "projects" && segments[3] === "files") {
|
|
677
813
|
const name = decodeURIComponent(segments[2] ?? "");
|
|
678
814
|
const entry = registry.get(name);
|
|
@@ -692,6 +828,24 @@ async function startDaemon(opts = {}) {
|
|
|
692
828
|
});
|
|
693
829
|
return;
|
|
694
830
|
}
|
|
831
|
+
if (segments[1] === "shutdown" && req.method === "POST") {
|
|
832
|
+
if (!isTrustedWrite(req)) {
|
|
833
|
+
sendJson(403, {
|
|
834
|
+
ok: false,
|
|
835
|
+
error: "缺少 x-paintress 头"
|
|
836
|
+
});
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
res.once("finish", () => {
|
|
840
|
+
setTimeout(() => void shutdown("web 界面关闭"), 0).unref?.();
|
|
841
|
+
});
|
|
842
|
+
sendJson(200, {
|
|
843
|
+
ok: true,
|
|
844
|
+
shutdown: true,
|
|
845
|
+
connections: connectionCount()
|
|
846
|
+
});
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
695
849
|
if (segments[1] === "changes") {
|
|
696
850
|
const qProject = url.searchParams.get("project") ?? "";
|
|
697
851
|
const qFile = url.searchParams.get("path") ?? "";
|
|
@@ -808,6 +962,7 @@ async function startDaemon(opts = {}) {
|
|
|
808
962
|
res.write(": connected\n\n");
|
|
809
963
|
const token = Symbol("browser");
|
|
810
964
|
entry.browsers.add(token);
|
|
965
|
+
cancelAutoDetach(entry.name);
|
|
811
966
|
const release = watchers.acquire(abs, () => {
|
|
812
967
|
res.write(`event: change\ndata: ${JSON.stringify({
|
|
813
968
|
path: relPath,
|
|
@@ -819,6 +974,7 @@ async function startDaemon(opts = {}) {
|
|
|
819
974
|
clearInterval(keepAlive);
|
|
820
975
|
release();
|
|
821
976
|
entry.browsers.delete(token);
|
|
977
|
+
maybeScheduleAutoDetach(entry.name);
|
|
822
978
|
};
|
|
823
979
|
req.on("close", done);
|
|
824
980
|
return;
|
|
@@ -957,13 +1113,19 @@ async function startDaemon(opts = {}) {
|
|
|
957
1113
|
if (!opts.quiet) process.stderr.write(`paintress web: 退出(${reason})\n`);
|
|
958
1114
|
clearInterval(idleTimer);
|
|
959
1115
|
if (registryTimer !== null) clearTimeout(registryTimer);
|
|
1116
|
+
for (const timer of autoDetachTimers.values()) clearTimeout(timer);
|
|
1117
|
+
autoDetachTimers.clear();
|
|
960
1118
|
for (const client of registryClients) try {
|
|
961
1119
|
client.end();
|
|
962
1120
|
} catch {}
|
|
963
1121
|
registryClients.clear();
|
|
1122
|
+
for (const client of controlClients) client.end();
|
|
1123
|
+
controlClients.clear();
|
|
964
1124
|
await watchers.closeAll();
|
|
965
1125
|
await new Promise((resolve) => sockServer.close(() => resolve()));
|
|
966
|
-
|
|
1126
|
+
const httpClosed = new Promise((resolve) => httpServer.close(() => resolve()));
|
|
1127
|
+
httpServer.closeAllConnections();
|
|
1128
|
+
await httpClosed;
|
|
967
1129
|
releaseLock();
|
|
968
1130
|
}
|
|
969
1131
|
return {
|
|
@@ -1281,7 +1443,8 @@ const FLAG_KEYS = /* @__PURE__ */ new Set([
|
|
|
1281
1443
|
"layout",
|
|
1282
1444
|
"padding",
|
|
1283
1445
|
"gap",
|
|
1284
|
-
"force"
|
|
1446
|
+
"force",
|
|
1447
|
+
"board"
|
|
1285
1448
|
]);
|
|
1286
1449
|
const BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
1287
1450
|
"regex",
|
|
@@ -1538,7 +1701,8 @@ async function main(argv) {
|
|
|
1538
1701
|
}
|
|
1539
1702
|
const handle = await startDaemon({
|
|
1540
1703
|
...port !== void 0 ? { port } : {},
|
|
1541
|
-
...idle !== void 0 ? { idleTimeoutMs: idle } : {}
|
|
1704
|
+
...idle !== void 0 ? { idleTimeoutMs: idle } : {},
|
|
1705
|
+
updateCheck: true
|
|
1542
1706
|
});
|
|
1543
1707
|
console.log(JSON.stringify({
|
|
1544
1708
|
ok: true,
|
|
@@ -1646,14 +1810,18 @@ async function main(argv) {
|
|
|
1646
1810
|
out: a1
|
|
1647
1811
|
});
|
|
1648
1812
|
break;
|
|
1649
|
-
case "shot":
|
|
1813
|
+
case "shot": {
|
|
1650
1814
|
if (!a1) throw new Error("缺少 <out.png> 参数");
|
|
1815
|
+
if (flags["board"] === true) throw new Error("--board 需要画板 id 或 name");
|
|
1816
|
+
const board = flagStr(flags, "board");
|
|
1651
1817
|
out = await call("paintress_screenshot", {
|
|
1652
1818
|
path: file,
|
|
1653
1819
|
out: a1,
|
|
1654
|
-
...flagNum(flags, "scale") !== void 0 ? { scale: flagNum(flags, "scale") } : {}
|
|
1820
|
+
...flagNum(flags, "scale") !== void 0 ? { scale: flagNum(flags, "scale") } : {},
|
|
1821
|
+
...board !== void 0 ? { board } : {}
|
|
1655
1822
|
});
|
|
1656
1823
|
break;
|
|
1824
|
+
}
|
|
1657
1825
|
default:
|
|
1658
1826
|
console.error(`未知子命令:${cmd}`);
|
|
1659
1827
|
return 2;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { It as Affine, it as BackgroundBlurEffect, bt as BlendMode, at as BlurEffect, Lt as BoolOrVar, z as BrowserSchema, Rt as Color, zt as ColorOrVar, Bt as CornerRadius, xt as CrossAxis, j as DocumentObjectSchema, M as DocumentSchema, ot as EffectEntry, st as Effects, B as EllipseSchema, w as FileChangedError, ct as FillEntry, St as FillRule, lt as Fills, V as FrameSchema, ut as GradientFill, Ct as GradientType, dt as GraphicsBlock, H as GroupSchema, U as IconFontSchema, wt as IconLibrary, W as IconSchema, ft as ImageFill, Tt as ImageFit, G as KNOWN_NODE_TYPES, K as LayoutBlock, Et as LayoutDir, Dt as MainAxis, pt as MeshGradientFill, q as NodeBase, J as NodeSchema, Y as NoteSchema, Vt as NumOrVar, N as PEN_DOC_VERSION, P as PTR_SPEC_VERSION, Ht as Padding, X as PathSchema, Z as PolygonSchema, Ot as PositionMode, F as PtrDocumentSchema, Q as RectangleSchema, $ as RefSchema, et as ScriptSchema, mt as ShaderEffect, ht as ShaderFill, gt as ShadowEffect, kt as ShadowKind, Ut as Sizing, _t as SolidFill, Wt as StringOrVar, At as StrokeAlign, vt as StrokeBlock, jt as StrokeCap, Mt as StrokeJoin, yt as StrokeWidth, Nt as TextAlign, Pt as TextAlignVertical, Ft as TextGrowth, tt as TextSchema, nt as UnknownNodeSchema, Gt as VARIABLE_NAME, I as VariableDef, Kt as VariableRef, L as XPaintress, R as X_PAINTRESS_KEY, g as batch, n as boardBoxes, _ as buildIndex, k as collectIds, c as commonToCss, r as computeCanvas, l as cornerRadiusToCss, u as effectsToCss, i as escapeAttr, a as escapeHtml, m as expandRefs, d as fillsToCss, A as genId, v as get, s as getLucideIcon, y as insert, T as loadDoc, h as makeVarResolver, b as move, x as query, S as remove, t as renderDocument, o as renderTree, E as saveDoc, rt as schemaForType, D as serializeDoc, f as strokeToCss, p as textToCss, C as update, O as validateDoc } from "./render-CzpO1cOe.js";
|
package/dist/mcp/server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as createMcpServer, n as runStdioServer } from "../server-
|
|
1
|
+
export { t as createMcpServer, n as runStdioServer } from "../server-vPylVJZf.js";
|
|
@@ -1606,6 +1606,23 @@ function computeCanvas(nodes, vars) {
|
|
|
1606
1606
|
height: Math.max(1, Math.ceil(maxH))
|
|
1607
1607
|
};
|
|
1608
1608
|
}
|
|
1609
|
+
function boardBoxes(nodes, vars) {
|
|
1610
|
+
const out = [];
|
|
1611
|
+
for (const n of nodes) {
|
|
1612
|
+
if (!isRecord(n)) continue;
|
|
1613
|
+
const box = nodeBox(n, vars);
|
|
1614
|
+
const name = typeof n["name"] === "string" && n["name"] !== "" ? n["name"] : void 0;
|
|
1615
|
+
out.push({
|
|
1616
|
+
id: typeof n["id"] === "string" ? n["id"] : "",
|
|
1617
|
+
...name !== void 0 ? { name } : {},
|
|
1618
|
+
x: box.x,
|
|
1619
|
+
y: box.y,
|
|
1620
|
+
w: box.w,
|
|
1621
|
+
h: box.h
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
return out;
|
|
1625
|
+
}
|
|
1609
1626
|
/** 渲染整棵(已展开的)树:顶层节点在画布上绝对定位,并带画布元数据 */
|
|
1610
1627
|
function renderTree(nodes, vars, warnings) {
|
|
1611
1628
|
return nodes.filter(isRecord).map((n) => renderNode(n, "none", vars, warnings, boardAttrs(n, vars))).join("");
|
|
@@ -1621,6 +1638,7 @@ function renderDocument(doc, opts = {}) {
|
|
|
1621
1638
|
const vars = makeVarResolver(doc, warnings);
|
|
1622
1639
|
const expanded = expandRefs(doc, warnings);
|
|
1623
1640
|
const canvas = computeCanvas(expanded, vars);
|
|
1641
|
+
const boards = boardBoxes(expanded, vars);
|
|
1624
1642
|
const title = opts.title ?? "paintress render";
|
|
1625
1643
|
const body = renderTree(expanded, vars, warnings);
|
|
1626
1644
|
return {
|
|
@@ -1645,7 +1663,8 @@ function renderDocument(doc, opts = {}) {
|
|
|
1645
1663
|
""
|
|
1646
1664
|
].join("\n"),
|
|
1647
1665
|
warnings,
|
|
1648
|
-
canvas
|
|
1666
|
+
canvas,
|
|
1667
|
+
boards
|
|
1649
1668
|
};
|
|
1650
1669
|
}
|
|
1651
|
-
export {
|
|
1670
|
+
export { RefSchema as $, genId as A, StrokeAlign as At, EllipseSchema as B, CornerRadius as Bt, update as C, GradientType as Ct, serializeDoc as D, MainAxis as Dt, saveDoc as E, LayoutDir as Et, PtrDocumentSchema as F, TextGrowth as Ft, KNOWN_NODE_TYPES as G, VARIABLE_NAME as Gt, GroupSchema as H, Padding as Ht, VariableDef as I, Affine as It, NodeSchema as J, LayoutBlock as K, VariableRef as Kt, XPaintress as L, BoolOrVar as Lt, DocumentSchema as M, StrokeJoin as Mt, PEN_DOC_VERSION as N, TextAlign as Nt, validateDoc as O, PositionMode as Ot, PTR_SPEC_VERSION as P, TextAlignVertical as Pt, RectangleSchema as Q, X_PAINTRESS_KEY as R, Color as Rt, remove as S, FillRule as St, loadDoc as T, ImageFit as Tt, IconFontSchema as U, Sizing as Ut, FrameSchema as V, NumOrVar as Vt, IconSchema as W, StringOrVar as Wt, PathSchema as X, NoteSchema as Y, PolygonSchema as Z, buildIndex as _, SolidFill as _t, escapeHtml as a, BlurEffect as at, move as b, BlendMode as bt, commonToCss as c, FillEntry as ct, fillsToCss as d, GraphicsBlock as dt, ScriptSchema as et, strokeToCss as f, ImageFill as ft, batch as g, ShadowEffect as gt, makeVarResolver as h, ShaderFill as ht, escapeAttr as i, BackgroundBlurEffect as it, DocumentObjectSchema as j, StrokeCap as jt, collectIds as k, ShadowKind as kt, cornerRadiusToCss as l, Fills as lt, expandRefs as m, ShaderEffect as mt, boardBoxes as n, UnknownNodeSchema as nt, renderTree as o, EffectEntry as ot, textToCss as p, MeshGradientFill as pt, NodeBase as q, VERSION as qt, computeCanvas as r, schemaForType as rt, getLucideIcon as s, Effects as st, renderDocument as t, TextSchema as tt, effectsToCss as u, GradientFill as ut, get as v, StrokeBlock as vt, FileChangedError as w, IconLibrary as wt, query as x, CrossAxis as xt, insert as y, StrokeWidth as yt, BrowserSchema as z, ColorOrVar as zt };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as genId, C as update, E as saveDoc, M as DocumentSchema, N as PEN_DOC_VERSION, O as validateDoc, S as remove, T as loadDoc, b as move, g as batch, k as collectIds, qt as VERSION, t as renderDocument, v as get, x as query, y as insert } from "./render-CzpO1cOe.js";
|
|
2
2
|
import { existsSync, mkdirSync, mkdtempSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { homedir, tmpdir } from "node:os";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -66,12 +66,51 @@ function findBrowser() {
|
|
|
66
66
|
}
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
function boardLabel(b) {
|
|
70
|
+
return b.name !== void 0 && b.name !== "" ? `${b.name}(id=${b.id})` : b.id;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 画板选择子:id 精确 → name 精确 → name/id 模糊(不区分大小写)。
|
|
74
|
+
* 模糊命中多个时报歧义并列出候选,不猜——猜错会让 AI 以为看到了另一页。
|
|
75
|
+
*/
|
|
76
|
+
function selectBoard(boards, query) {
|
|
77
|
+
if (boards.length === 0) throw new Error("设计稿没有画板(顶层节点为空),无法按画板截图");
|
|
78
|
+
const q = query.trim();
|
|
79
|
+
if (q === "") throw new Error("board 参数不能为空");
|
|
80
|
+
const byId = boards.filter((b) => b.id === q);
|
|
81
|
+
if (byId.length === 1) return byId[0];
|
|
82
|
+
const byName = boards.filter((b) => b.name === q);
|
|
83
|
+
if (byName.length === 1) return byName[0];
|
|
84
|
+
const lower = q.toLowerCase();
|
|
85
|
+
const fuzzy = boards.filter((b) => b.id.toLowerCase().includes(lower) || (b.name ?? "").toLowerCase().includes(lower));
|
|
86
|
+
if (fuzzy.length === 1) return fuzzy[0];
|
|
87
|
+
const all = boards.map(boardLabel).join("、");
|
|
88
|
+
if (fuzzy.length === 0) throw new Error(`没有匹配「${q}」的画板;可选:${all}`);
|
|
89
|
+
throw new Error(`「${q}」命中 ${fuzzy.length} 个画板,请写更精确的名字或 id:${fuzzy.map(boardLabel).join("、")}`);
|
|
90
|
+
}
|
|
91
|
+
/** 渲染并截图整张画布;指定 board 时只裁该画板(走同一套渲染与浏览器) */
|
|
70
92
|
async function screenshotPen(penPath, outPng, opts = {}) {
|
|
71
93
|
const browserPath = findBrowser();
|
|
72
94
|
if (!browserPath) throw new Error("未找到可用浏览器:安装 Chromium/Chrome,或设置 PTR_BROWSER 指向可执行文件");
|
|
73
95
|
const loaded = loadDoc(penPath);
|
|
74
96
|
const rendered = renderDocument(loaded.doc);
|
|
97
|
+
const target = opts.board !== void 0 ? selectBoard(rendered.boards, opts.board) : void 0;
|
|
98
|
+
if (target !== void 0 && (target.w <= 0 || target.h <= 0)) throw new Error(`画板 ${boardLabel(target)} 尺寸为 0(${target.w}×${target.h}),无法截图`);
|
|
99
|
+
const viewport = {
|
|
100
|
+
width: Math.max(rendered.canvas.width, target !== void 0 ? Math.ceil(target.x + target.w) : 0),
|
|
101
|
+
height: Math.max(rendered.canvas.height, target !== void 0 ? Math.ceil(target.y + target.h) : 0)
|
|
102
|
+
};
|
|
103
|
+
const clip = target !== void 0 ? {
|
|
104
|
+
x: target.x,
|
|
105
|
+
y: target.y,
|
|
106
|
+
width: Math.ceil(target.w),
|
|
107
|
+
height: Math.ceil(target.h)
|
|
108
|
+
} : {
|
|
109
|
+
x: 0,
|
|
110
|
+
y: 0,
|
|
111
|
+
width: rendered.canvas.width,
|
|
112
|
+
height: rendered.canvas.height
|
|
113
|
+
};
|
|
75
114
|
const tmpDir = mkdtempSync(join(tmpdir(), "paintress-shot-"));
|
|
76
115
|
const htmlPath = join(tmpDir, "page.html");
|
|
77
116
|
writeFileSync(htmlPath, rendered.html, "utf8");
|
|
@@ -82,22 +121,14 @@ async function screenshotPen(penPath, outPng, opts = {}) {
|
|
|
82
121
|
});
|
|
83
122
|
try {
|
|
84
123
|
const page = await browser.newPage({
|
|
85
|
-
viewport
|
|
86
|
-
width: rendered.canvas.width,
|
|
87
|
-
height: rendered.canvas.height
|
|
88
|
-
},
|
|
124
|
+
viewport,
|
|
89
125
|
deviceScaleFactor: opts.scale ?? 2
|
|
90
126
|
});
|
|
91
127
|
await page.goto(`file://${htmlPath}`);
|
|
92
128
|
await page.waitForTimeout(opts.settleMs ?? 120);
|
|
93
129
|
await page.screenshot({
|
|
94
130
|
path: outPng,
|
|
95
|
-
clip
|
|
96
|
-
x: 0,
|
|
97
|
-
y: 0,
|
|
98
|
-
width: rendered.canvas.width,
|
|
99
|
-
height: rendered.canvas.height
|
|
100
|
-
}
|
|
131
|
+
clip
|
|
101
132
|
});
|
|
102
133
|
} finally {
|
|
103
134
|
await browser.close();
|
|
@@ -109,12 +140,21 @@ async function screenshotPen(penPath, outPng, opts = {}) {
|
|
|
109
140
|
});
|
|
110
141
|
}
|
|
111
142
|
if (statSync(outPng).size === 0) throw new Error("截图产物为空文件");
|
|
112
|
-
|
|
143
|
+
const result = {
|
|
113
144
|
out: outPng,
|
|
114
145
|
canvas: rendered.canvas,
|
|
115
146
|
warnings: rendered.warnings,
|
|
116
147
|
browser: browserPath
|
|
117
148
|
};
|
|
149
|
+
if (target !== void 0) result.board = {
|
|
150
|
+
id: target.id,
|
|
151
|
+
...target.name !== void 0 ? { name: target.name } : {},
|
|
152
|
+
x: target.x,
|
|
153
|
+
y: target.y,
|
|
154
|
+
width: target.w,
|
|
155
|
+
height: target.h
|
|
156
|
+
};
|
|
157
|
+
return result;
|
|
118
158
|
}
|
|
119
159
|
// src/web/protocol.ts
|
|
120
160
|
function encodeLine(msg) {
|
|
@@ -638,19 +678,25 @@ const TOOLS = {
|
|
|
638
678
|
}
|
|
639
679
|
},
|
|
640
680
|
paintress_screenshot: {
|
|
641
|
-
description: "渲染并截图为 PNG(默认 2x);需要本机 Chromium/Chrome 或 PTR_BROWSER
|
|
681
|
+
description: "渲染并截图为 PNG(默认 2x);需要本机 Chromium/Chrome 或 PTR_BROWSER 指向的可执行文件。指定 board 时只截该画板(顶层 frame,即“一页”),而不是整张画布",
|
|
642
682
|
inputSchema: {
|
|
643
683
|
path: z.string(),
|
|
644
684
|
out: z.string().describe("输出 .png 路径"),
|
|
645
|
-
scale: z.number().int().min(1).max(4).optional().describe("像素倍率,默认 2")
|
|
685
|
+
scale: z.number().int().min(1).max(4).optional().describe("像素倍率,默认 2"),
|
|
686
|
+
board: z.string().optional().describe("只截某个画板:id 或 name;模糊命中多个时会报错并列出候选")
|
|
646
687
|
},
|
|
647
688
|
run: async (a) => {
|
|
648
689
|
if (!findBrowser()) throw new Error("未找到可用浏览器:安装 Chromium/Chrome,或设置 PTR_BROWSER");
|
|
649
|
-
const
|
|
690
|
+
const board = typeof a["board"] === "string" ? a["board"] : "";
|
|
691
|
+
const res = await screenshotPen(reqStr(a, "path"), reqStr(a, "out"), {
|
|
692
|
+
...typeof a["scale"] === "number" ? { scale: a["scale"] } : {},
|
|
693
|
+
...board !== "" ? { board } : {}
|
|
694
|
+
});
|
|
650
695
|
return {
|
|
651
696
|
ok: true,
|
|
652
697
|
out: res.out,
|
|
653
698
|
canvas: res.canvas,
|
|
699
|
+
...res.board !== void 0 ? { board: res.board } : {},
|
|
654
700
|
browser: res.browser,
|
|
655
701
|
warnings: res.warnings
|
|
656
702
|
};
|
|
@@ -717,7 +763,8 @@ async function autoRegister(cwd = process.cwd()) {
|
|
|
717
763
|
const watched = await sendRequest({
|
|
718
764
|
kind: "watch",
|
|
719
765
|
project,
|
|
720
|
-
dir: cwd
|
|
766
|
+
dir: cwd,
|
|
767
|
+
owner: "agent"
|
|
721
768
|
}, 8e3);
|
|
722
769
|
if (!watched.ok) throw new Error(watched.error);
|
|
723
770
|
return {
|
package/package.json
CHANGED
|
@@ -37,7 +37,7 @@ If either prints something, **do not install again**. Use the existing binary. `
|
|
|
37
37
|
| `paintress_batch` | several operations in one call |
|
|
38
38
|
| `paintress_validate` | check the document against the format spec |
|
|
39
39
|
| `paintress_render` | write the canvas as a standalone HTML file |
|
|
40
|
-
| `paintress_screenshot` | render to PNG (headless Chromium) |
|
|
40
|
+
| `paintress_screenshot` | render to PNG (headless Chromium); pass `board` (id or name) to capture one board instead of the whole canvas |
|
|
41
41
|
| `paintress_marks` | read the user's click markers (`#1 → node id`) |
|
|
42
42
|
|
|
43
43
|
## Working rules
|
|
@@ -47,7 +47,7 @@ If either prints something, **do not install again**. Use the existing binary. `
|
|
|
47
47
|
3. **`#N` means a marker.** When the user writes `#1`, call `paintress_marks` and map `#1` to a real node id. Markers are per viewer session.
|
|
48
48
|
4. **Top-level nodes are boards.** Use `paintress_doc_info` to list them before guessing what "the second screen" means.
|
|
49
49
|
5. **After a batch, validate.** `paintress_validate` catches structural mistakes before the user opens the file.
|
|
50
|
-
6. **Screenshots are for you.** `paintress_screenshot` is how you look at the design; the HTML viewer is for the human.
|
|
50
|
+
6. **Screenshots are for you.** `paintress_screenshot` is how you look at the design; the HTML viewer is for the human. When a document has several boards, pass `board` to get just that page — an ambiguous name errors out and lists the candidates rather than guessing.
|
|
51
51
|
|
|
52
52
|
## Node fields worth knowing
|
|
53
53
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--bg:#f6f1ea;--panel:#fffcf8;--border:#e6ded2;--text:#1f2a37;--muted:#7a7166;--accent:#205080;--accent-soft:#20508014;--gold:#908030;--gold-soft:#90803073;--radius:8px}*{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:100%}body{color:var(--text);background:var(--bg);-webkit-font-smoothing:antialiased;font:14px/1.55 system-ui,-apple-system,Segoe UI,Noto Sans SC,sans-serif}.app{grid-template-columns:280px 1fr;height:100%;display:grid}.sidebar{background:var(--panel);border-right:1px solid var(--border);flex-direction:column;min-height:0;display:flex}.sidebar-head{border-bottom:1px solid var(--border);align-items:center;gap:8px;padding:16px 16px 12px;display:flex}.sidebar-head h1{letter-spacing:-.01em;color:var(--accent);font-size:15px;font-weight:650}.badge{color:var(--muted);background:var(--bg);border-radius:999px;padding:1px 6px;font-size:11px}.badge-stack{font:inherit;cursor:pointer;border:1px solid #0000;flex-direction:column;align-items:flex-start;gap:1px;font-size:11px;line-height:1.2;display:inline-flex}.badge-stack:hover{border-color:#b4402a59}.badge-new{color:#b4402a;font-weight:700}.prompt{background:var(--bg);border:1px solid var(--border);font:inherit;white-space:pre-wrap;word-break:break-word;-webkit-user-select:all;user-select:all;border-radius:6px;margin:10px 0 8px;padding:8px 10px;font-size:12px;line-height:1.6}a.ghost{text-decoration:none;display:inline-block}.section{min-height:0;padding:12px 8px 4px;overflow-y:auto}.section.files{border-top:1px solid var(--border);flex:1;padding-top:12px}.section h2{text-transform:uppercase;letter-spacing:.06em;color:var(--muted);justify-content:space-between;gap:8px;padding:0 8px 8px;font-size:11px;font-weight:600;display:flex}.hint{color:var(--muted);text-transform:none;letter-spacing:0;font-size:11px;font-weight:400}.list{list-style:none}.item{text-align:left;cursor:pointer;width:100%;font:inherit;color:inherit;background:0 0;border:0;border-radius:6px;flex-direction:column;gap:1px;padding:7px 8px;display:flex}.item:hover{background:var(--bg)}.item.active{background:var(--accent-soft);color:var(--accent)}.item-name{text-overflow:ellipsis;white-space:nowrap;font-size:13px;overflow:hidden}.item-meta{color:var(--muted);font-size:11px}.item.active .item-meta{color:var(--accent);opacity:.75}.empty{color:var(--muted);padding:4px 8px 12px;font-size:12px;line-height:1.7}.empty code{background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:1px 5px;font-size:11px}.sidebar-foot{border-top:1px solid var(--border);color:var(--muted);flex-wrap:wrap;align-items:center;gap:8px;padding:10px 16px;font-size:12px;display:flex}.toggle{cursor:pointer;align-items:center;gap:5px;display:inline-flex}.ghost{background:var(--bg);border:1px solid var(--border);font:inherit;color:var(--text);cursor:pointer;border-radius:6px;padding:3px 9px;font-size:12px}.ghost:hover{border-color:var(--accent);color:var(--accent)}.stage{background:var(--canvas-bg,var(--bg));flex-direction:column;min-width:0;min-height:0;display:flex}.toolbar{border-bottom:1px solid var(--border);background:var(--panel);justify-content:space-between;align-items:center;gap:12px;padding:8px 14px;display:flex}.toolbar code{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.preview{border:1px solid var(--border);background:var(--canvas-bg,#fff);border-radius:10px;flex:1;width:calc(100% - 24px);min-height:0;margin:12px;box-shadow:0 1px 2px #1f2a370d,0 8px 24px #1f2a370d}.stage[data-canvas-bg=dark] .preview{border-color:#ffffff1f;box-shadow:0 1px 2px #00000059,0 10px 30px #00000052}.placeholder{color:var(--muted);flex:1;place-items:center;display:grid}.error{border-radius:var(--radius);color:#b91c1c;white-space:pre-wrap;background:#fef2f2;border:1px solid #fecaca;margin:12px;padding:10px 12px;font-size:12px}.section.marks{border-top:1px solid var(--border);flex:0 auto;max-height:34vh}.mark-no{background:var(--accent-soft);min-width:20px;color:var(--accent);font-variant-numeric:tabular-nums;border-radius:4px;margin-right:4px;padding:0 4px;font-size:11px;display:inline-block}.item.active .mark-no{background:#fff}.ghost.tiny{text-transform:none;letter-spacing:0;padding:1px 6px;font-size:11px}.crumbs{flex-wrap:wrap;align-items:center;gap:3px;min-width:0;display:flex;overflow:hidden}.crumbs code{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.crumb{font:inherit;color:var(--muted);cursor:pointer;text-overflow:ellipsis;white-space:nowrap;background:0 0;border:0;border-radius:4px;max-width:220px;padding:2px 5px;font-size:12px;overflow:hidden}.crumb:hover{background:var(--bg);color:var(--text)}.crumb.active{color:var(--accent);background:var(--accent-soft)}.sep{color:var(--border);font-size:11px}.brand-mark{flex:none;width:auto;height:32px}.canvas-bg{-webkit-user-select:none;user-select:none;flex:none;align-items:center;gap:8px;display:inline-flex}.canvas-bg-label{letter-spacing:.04em;text-transform:uppercase;color:var(--muted);text-align:right;min-width:34px;font-size:11px;font-weight:500}.canvas-bg-track{width:84px;height:calc(var(--thumb) + var(--pad) * 2);cursor:pointer;touch-action:none;background:linear-gradient(#e7e0d5,#f3eee6 60%,#f7f2ea);border-radius:999px;position:relative;box-shadow:inset 0 1px 2px #1f2a373d,inset 0 -1px #ffffffe6,inset 0 0 0 1px #1f2a3712,0 1px #fff}.canvas-bg-track:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.canvas-bg-thumb{top:var(--pad);left:var(--pad);width:var(--thumb);height:var(--thumb);transform:translateX(calc(var(--pos) * var(--step)));background:linear-gradient(#fff,#f1ebe1);border-radius:50%;justify-content:center;align-items:center;transition:transform .17s cubic-bezier(.22,.61,.36,1);display:flex;position:absolute;box-shadow:0 1px 2px #1f2a374d,0 0 0 1px #1f2a3714,inset 0 1px #fff}.canvas-bg-track.dragging .canvas-bg-thumb{transition:none}.canvas-bg-dot{background:var(--dot,#fff);border-radius:50%;width:11px;height:11px;transition:background .17s;box-shadow:0 0 0 1px #1f2a3742,0 1px 1px #1f2a371f}.lang-switch{background:linear-gradient(#ece6dc,#f6f1e9);border-radius:999px;flex:none;align-items:center;gap:2px;margin-left:4px;padding:2px;display:inline-flex;box-shadow:inset 0 1px 2px #1f2a3729,inset 0 0 0 1px #1f2a370d}.lang-opt{font:inherit;color:var(--muted);cursor:pointer;background:0 0;border:0;border-radius:999px;padding:2px 7px;font-size:11px;line-height:16px}.lang-opt:hover{color:var(--text)}.lang-opt.active{color:var(--accent);background:linear-gradient(#fffdf9,#f3ede4);font-weight:600;box-shadow:0 1px 2px #1f2a372e,inset 0 1px #fff}.tool-sep{background:var(--border);flex:none;width:1px;height:18px;margin:0 2px}.tools{flex:none;align-items:center;gap:6px;display:flex}.zoom{font-variant-numeric:tabular-nums;text-align:right;min-width:40px}.boardbar{border-bottom:1px solid var(--border);background:var(--panel);align-items:center;gap:6px;padding:6px 14px;display:flex;overflow-x:auto}.board{background:var(--bg);border:1px solid var(--border);font:inherit;color:var(--text);cursor:pointer;border-radius:6px;flex:none;align-items:baseline;gap:6px;padding:3px 9px;font-size:12px;display:inline-flex}.board:hover{border-color:var(--accent);color:var(--accent)}.board.active{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}.board-size{color:var(--muted);font-variant-numeric:tabular-nums;font-size:10px}.board.active .board-size{color:var(--accent);opacity:.75}.row{align-items:center;display:flex;position:relative}.row .item{flex:1;min-width:0}.row-action{background:var(--panel);width:20px;height:20px;color:var(--muted);font:inherit;cursor:pointer;opacity:0;border:1px solid #0000;border-radius:5px;place-items:center;padding:0;font-size:13px;line-height:1;transition:opacity .12s;display:grid;position:absolute;top:50%;right:4px;transform:translateY(-50%)}.row:hover .row-action,.row-action:focus-visible{opacity:1}.row-action:hover{color:#a33;border-color:#aa333359}@media (hover:none){.row-action{opacity:1}}.modal-backdrop{z-index:50;background:#1f2a3747;place-items:center;display:grid;position:fixed;inset:0}.modal{background:var(--panel);border:1px solid var(--border);border-radius:10px;width:min(380px,100vw - 32px);padding:16px 18px 14px;box-shadow:0 12px 40px #1f2a372e}.modal h3{color:var(--accent);margin-bottom:6px;font-size:14px;font-weight:650}.modal-body{color:var(--muted);font-size:12.5px;line-height:1.65}.modal-actions{justify-content:flex-end;gap:8px;margin-top:14px;display:flex}.ghost.danger{color:#a33}.ghost.danger:hover,.ghost.danger:focus-visible{color:#a33;background:#aa33330f;border-color:#a33}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return t(this.context.count)},getNextContextId(){return t(this.context.count++)}};function t(t){let n=String(t),r=n.length-1;return e.context.id+(r?String.fromCharCode(96+r):``)+n}function n(t){e.context=t}var r=(e,t)=>e===t,i=Symbol(`solid-track`),a={equals:r},o=null,s=oe,c=1,l=2,u={owned:null,cleanups:null,context:null,owner:null},d=null,f=null,p=null,m=null,h=null,g=0;function _(e,t){let n=p,r=d,i=e.length===0,a=t===void 0?r:t,o=i?u:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(v(o));d=o,p=null;try{return j(s,!0)}finally{p=n,d=r}}function v(e){return()=>C(()=>F(e))}function y(e,t){t=t?Object.assign({},a,t):a;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[O.bind(n),e=>(typeof e==`function`&&(e=f&&f.running&&f.sources.has(n)?e(n.tValue):e(n.value)),re(n,e))]}function b(e,t,n){k(ae(e,t,!1,c))}function x(e,t,n){s=se;let r=ae(e,t,!1,c),i=ne&&D(ne);i&&(r.suspense=i),n&&n.render||(r.user=!0),h?h.push(r):k(r)}function S(e,t,n){n=n?Object.assign({},a,n):a;let r=ae(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,k(r),O.bind(r)}function C(e){if(p===null)return e();let t=p;p=null;try{return e()}finally{p=t}}function w(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=C(()=>t(o,i,n));return i=o,s}}function T(e){x(()=>C(e))}function E(e){return d===null||(d.cleanups===null?d.cleanups=[e]:d.cleanups.push(e)),e}var[ee,te]=y(!1);function D(e){let t;return d&&d.context&&(t=d.context[e.id])!==void 0?t:e.defaultValue}var ne;function O(){let e=f&&f.running;if(this.sources&&(e?this.tState:this.state)){if((e?this.tState:this.state)===c)k(this);else{let e=m;m=null,j(()=>N(this),!1),m=e}}if(p){let e=this.observers;if(!e||e[e.length-1]!==p){let t=e?e.length:0;p.sources?(p.sources.push(this),p.sourceSlots.push(t)):(p.sources=[this],p.sourceSlots=[t]),e?(e.push(p),this.observerSlots.push(p.sources.length-1)):(this.observers=[p],this.observerSlots=[p.sources.length-1])}}return e&&f.sources.has(this)?this.tValue:this.value}function re(e,t,n){let r=f&&f.running&&f.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(f){let r=f.running;(r||!n&&f.sources.has(e))&&(f.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&j(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=f&&f.running;r&&f.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?m.push(n):h.push(n),n.observers&&P(n)),r?n.tState=c:n.state=c)}if(m.length>1e6)throw m=[],Error()},!1)}return t}function k(e){if(!e.fn)return;F(e);let t=g;ie(e,f&&f.running&&f.sources.has(e)?e.tValue:e.value,t),f&&!f.running&&f.sources.has(e)&&queueMicrotask(()=>{j(()=>{f&&(f.running=!0),p=d=e,ie(e,e.tValue,t),p=d=null},!1)})}function ie(e,t,n){let r,i=d,a=p;p=d=e;try{r=e.fn(t)}catch(t){return e.pure&&(f&&f.running?(e.tState=c,e.tOwned&&e.tOwned.forEach(F),e.tOwned=void 0):(e.state=c,e.owned&&e.owned.forEach(F),e.owned=null)),e.updatedAt=n+1,I(t)}finally{p=a,d=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?re(e,r,!0):f&&f.running&&e.pure?(f.sources.has(e)||(e.value=r),f.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function ae(e,t,n,r=c,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:d,context:d?d.context:null,pure:n};return f&&f.running&&(a.state=0,a.tState=r),d===null||d!==u&&(f&&f.running&&d.pure?d.tOwned?d.tOwned.push(a):d.tOwned=[a]:d.owned?d.owned.push(a):d.owned=[a]),a}function A(e){let t=f&&f.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===l)return N(e);if(e.suspense&&C(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<g);){if(t&&f.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(f.disposed.has(t))return}if((t?e.tState:e.state)===c)k(e);else if((t?e.tState:e.state)===l){let t=m;m=null,j(()=>N(e,n[0]),!1),m=t}}}function j(e,t){if(m)return e();let n=!1;t||(m=[]),h?n=!0:h=[],g++;try{let t=e();return M(n),t}catch(e){n||(h=null),m=null,I(e)}}function M(e){if(m&&=(oe(m),null),e)return;let t;if(f){if(!f.promises.size&&!f.queue.size){let e=f.sources,n=f.disposed;h.push.apply(h,f.effects),t=f.resolve;for(let e of h)`tState`in e&&(e.state=e.tState),delete e.tState;f=null,j(()=>{for(let e of n)F(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)F(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}te(!1)},!1)}else if(f.running){f.running=!1,f.effects.push.apply(f.effects,h),h=null,te(!0);return}}let n=h;h=null,n.length&&j(()=>s(n),!1),t&&t()}function oe(e){for(let t=0;t<e.length;t++)A(e[t])}function se(t){let r,i=0;for(r=0;r<t.length;r++){let e=t[r];e.user?t[i++]=e:A(e)}if(e.context){if(e.count){e.effects||=[],e.effects.push(...t.slice(0,i));return}n()}for(e.effects&&(e.done||!e.count)&&(t=[...e.effects,...t],i+=e.effects.length,delete e.effects),r=0;r<i;r++)A(t[r])}function N(e,t){let n=f&&f.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===c?i!==t&&(!i.updatedAt||i.updatedAt<g)&&A(i):e===l&&N(i,t)}}}function P(e){let t=f&&f.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=l:r.state=l,r.pure?m.push(r):h.push(r),r.observers&&P(r))}}function F(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)F(e.tOwned[t]);delete e.tOwned}if(f&&f.running&&e.pure)ce(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)F(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}f&&f.running?e.tState=0:e.state=0}function ce(e,t){if(t||(e.tState=0,f.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)ce(e.owned[t])}function le(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function ue(e,t,n){try{for(let n of t)n(e)}catch(e){I(e,n&&n.owner||null)}}function I(e,t=d){let n=o&&t&&t.context&&t.context[o],r=le(e);if(!n)throw r;h?h.push({fn(){ue(r,n,t)},state:c}):ue(r,n,t)}var L=Symbol(`fallback`);function de(e){for(let t=0;t<e.length;t++)e[t]()}function R(e,t,n={}){let r=[],a=[],o=[],s=0,c=t.length>1?[]:null;return E(()=>de(o)),()=>{let l=e()||[],u=l.length,d,f;return l[i],C(()=>{let e,t,i,m,h,g,v,y,b;if(u===0)s!==0&&(de(o),o=[],r=[],a=[],s=0,c&&=[]),n.fallback&&(r=[L],a[0]=_(e=>(o[0]=e,n.fallback())),s=1);else if(s===0){for(a=Array(u),f=0;f<u;f++)r[f]=l[f],a[f]=_(p);s=u}else{for(i=Array(u),m=Array(u),c&&(h=Array(u)),g=0,v=Math.min(s,u);g<v&&r[g]===l[g];g++);for(v=s-1,y=u-1;v>=g&&y>=g&&r[v]===l[y];v--,y--)i[y]=a[v],m[y]=o[v],c&&(h[y]=c[v]);for(e=new Map,t=Array(y+1),f=y;f>=g;f--)b=l[f],d=e.get(b),t[f]=d===void 0?-1:d,e.set(b,f);for(d=g;d<=v;d++)b=r[d],f=e.get(b),f!==void 0&&f!==-1?(i[f]=a[d],m[f]=o[d],c&&(h[f]=c[d]),f=t[f],e.set(b,f)):o[d]();for(f=g;f<u;f++)f in i?(a[f]=i[f],o[f]=m[f],c&&(c[f]=h[f],c[f](f))):a[f]=_(p);a=a.slice(0,s=u),r=l.slice(0)}return a});function p(e){if(o[f]=e,c){let[e,n]=y(f);return c[f]=n,t(l[f],e)}return t(l[f])}}}function z(e,t){return C(()=>e(t||{}))}var B=e=>`Stale read from <${e}>.`;function fe(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return S(R(()=>e.each,e.children,t||void 0))}function V(e){let t=e.keyed,n=S(()=>e.when,void 0,void 0),r=t?n:S(n,void 0,{equals:(e,t)=>!e==!t});return S(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?C(()=>a(t?i:()=>{if(!C(r))throw B(`Show`);return n()})):a}return e.fallback},void 0,void 0)}var pe=e=>S(()=>e());function me(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;)if(t[o]===n[s])o++,s++;else{for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)l&&l.has(t[o])||t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null){if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&(d=l.get(t[c]))!=null&&d===r+u;)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++}else t[o++].remove()}}}var H=`_$DX_DELEGATE`;function he(e,t,n,r={}){let i;return _(r=>{i=r,t===document?e():q(t,e(),!n&&t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function U(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>C(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function W(e,t=window.document){let n=t[H]||(t[H]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,ve))}}function G(e,t,n){_e(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function K(e,t,n){n==null?e.style.removeProperty(t):e.style.setProperty(t,n)}function ge(e,t,n){return C(()=>e(t,n))}function q(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return J(e,t,r,n);b(r=>J(e,t(),r,n),r)}function _e(t){return!!e.context&&!e.done&&(!t||t.isConnected)}function ve(t){if(e.registry&&e.events&&e.events.find(([e,n])=>n===t))return;let n=t.target,r=`$$${t.type}`,i=t.target,a=t.currentTarget,o=e=>Object.defineProperty(t,"target",{configurable:!0,value:e}),s=()=>{let e=n[r];if(e&&!n.disabled){let i=n[`${r}Data`];if(i===void 0?e.call(n,t):e.call(n,i,t),t.cancelBubble)return}return n.host&&typeof n.host!=`string`&&!n.host._$host&&n.contains(t.target)&&o(n.host),!0},c=()=>{for(;s()&&(n=n._$host||n.parentNode||n.host););};Object.defineProperty(t,"currentTarget",{configurable:!0,get(){return n||document}}),e.registry&&!e.done&&(e.done=_$HY.done=!0);try{if(t.composedPath){let e=t.composedPath();o(e[0]);for(let t=0;t<e.length-2&&(n=e[t],s());t++){if(n._$host){n=n._$host,c();break}if(n.parentNode===a)break}}else c();o(i)}finally{t=n=null}}function J(e,t,n,r,i){let a=_e(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=Y(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=Y(e,n,r)}else if(o===`function`)return b(()=>{let i=t();for(;typeof i==`function`;)i=i();n=J(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(ye(o,t,n,i))return b(()=>n=J(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=Y(e,n,r),s)return n}else c?n.length===0?be(e,o,r):me(e,n,o):(n&&Y(e),be(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=Y(e,n,r,t);Y(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function ye(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(o!=null&&o!==!0&&o!==!1){if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=ye(e,o,s)||i;else if(c===`function`){if(r){for(;typeof o==`function`;)o=o();i=ye(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0}else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}}return i}function be(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function Y(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}async function X(e){let t=await fetch(e,{headers:{accept:`application/json`}});if(!t.ok){let e=await t.text().catch(()=>``);throw Error(`HTTP ${t.status}${e?`: ${e.slice(0,200)}`:``}`)}return await t.json()}function xe(){return X(`/api/projects`)}function Se(){return X(`/api/version`)}function Ce(e){return X(`/api/projects/${encodeURIComponent(e)}/files`)}function we(e,t){return`/render/${encodeURIComponent(e)}/${t.split(`/`).map(encodeURIComponent).join(`/`)}?embed=1`}function Te(e,t){return`/events?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`}function Ee(){return`/events`}function De(e){return X(`/api/marks?project=${encodeURIComponent(e)}`)}async function Oe(e){let t=await fetch(`/api/marks`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e)});if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.json();if(!n.ok)throw Error(n.error??`添加标记失败`);return n.mark}async function ke(e){let t=await fetch(`/api/marks?project=${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok)throw Error(`HTTP ${t.status}`);return(await t.json()).cleared}var Ae={"x-paintress":`1`};async function je(e){let t=await fetch(`/api/projects/${encodeURIComponent(e)}`,{method:`DELETE`,headers:Ae}),n=await t.json();if(!t.ok||!n.ok)throw Error(n.error??`HTTP ${t.status}`);return n.unwatched===!0}async function Me(){let e=await fetch(`/api/shutdown`,{method:`POST`,headers:Ae}),t=await e.json();if(!e.ok||!t.ok)throw Error(t.error??`HTTP ${e.status}`);return t.connections??0}function Ne(e,t){return X(`/api/changes?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`)}var Z=U(`<div class=modal-actions>`),Pe=U(`<div class=modal-backdrop><div class=modal role=dialog aria-modal=true><h3>`),Fe=U(`<p class=modal-body>`),Ie=U(`<button class=ghost>`),Le=U(`<button class="ghost danger">`);function Re(e){x(()=>{e.open&&queueMicrotask(()=>{(e.initialFocus?.()??document.querySelector(`.modal-actions button`))?.focus()})});let t=t=>{t.key===`Escape`&&(t.preventDefault(),e.onClose())};return z(V,{get when(){return e.open},get children(){var n=Pe(),r=n.firstChild,i=r.firstChild;return n.$$mousedown=t=>{t.target===t.currentTarget&&e.onClose()},r.$$keydown=t,q(i,()=>e.title),q(r,()=>e.children,null),q(r,z(V,{get when(){return e.actions},get children(){var t=Z();return q(t,()=>e.actions),t}}),null),b(()=>G(r,`aria-label`,e.title)),n}})}function ze(e){let t;return z(Re,{get open(){return e.open},get title(){return e.title},get onClose(){return e.onCancel},initialFocus:()=>t,get actions(){return[(()=>{var t=Ie();return t.$$click=()=>e.onCancel(),q(t,()=>e.cancelLabel),t})(),(()=>{var n=Le();return n.$$click=()=>e.onConfirm(),ge(e=>{t=e},n),q(n,()=>e.confirmLabel),n})()]},get children(){var t=Fe();return q(t,()=>e.body),t}})}W([`mousedown`,`keydown`,`click`]);function Be(e){let t=e.trim().replace(/^v/i,``),n=t.indexOf(`-`);return{nums:(n>=0?t.slice(0,n):t).split(`.`).map(e=>{let t=Number.parseInt(e,10);return Number.isFinite(t)?t:0}),prerelease:n>=0}}function Ve(e,t){let n=Be(e),r=Be(t),i=Math.max(n.nums.length,r.nums.length);for(let e=0;e<i;e+=1){let t=n.nums[e]??0,i=r.nums[e]??0;if(t!==i)return t>i?1:-1}return n.prerelease===r.prerelease?0:n.prerelease?-1:1}function He(e,t){return Ve(e,t)>0}var Ue=.1,We=.02;function Ge(e,t){return t===0||Math.abs(e)>=Math.abs(t)?null:t>0?-1:1}function Q(e,t=Ue){return Math.min(4,Math.max(t,e))}function Ke(e,t,n,r,i=Ue){let a=Q(e.z*t,i);if(a===e.z)return e;let o=a/e.z;return{z:a,tx:n-(n-e.tx)*o,ty:r-(r-e.ty)*o}}function qe(e,t,n,r=Ue){return Ke(e,Q(t,r)/e.z,n.width/2,n.height/2,r)}function Je(e,t,n=24){let r=Math.max(1,e.w),i=Math.max(1,e.h),a=Math.max(1,t.width-n*2),o=Math.max(1,t.height-n*2),s=Q(Math.min(a/r,o/i),We);return{z:s,tx:(t.width-r*s)/2-e.x*s,ty:(t.height-i*s)/2-e.y*s}}function Ye(e,t,n){return{z:e.z,tx:e.tx+t,ty:e.ty+n}}function Xe(e){return`translate(${e.tx}px, ${e.ty}px) scale(${e.z})`}function Ze(e){if(e===null||e===``)return null;let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=`object`||!t)return null;let{z:n,tx:r,ty:i}=t;return typeof n!=`number`||typeof r!=`number`||typeof i!=`number`||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(i)||n<=0?null:{z:Q(n,We),tx:r,ty:i}}var Qe=3,$e=.0015;function et({doc:e,onChange:t,onLevelStep:n}){let r=e.querySelector(`.ptr-canvas`);if(r===null)return null;let i=r;i.style.transformOrigin=`0 0`;let a={z:1,tx:0,ty:0},o=!1,s=!1,c=!1,l=null,u=()=>({width:e.documentElement.clientWidth||1,height:e.documentElement.clientHeight||1});function d(){i.style.transform=Xe(a),t?.(a)}function f(e){a=e,d()}function p(){i.style.transition=``}function m(e){i.style.transition=`transform 180ms ease-out`,f(e),setTimeout(p,220)}function h(t){e.documentElement.style.cursor=t}function g(e){if(e.preventDefault(),e.altKey&&n!==void 0){let t=Ge(e.deltaX,e.deltaY);t!==null&&n(t,{x:e.clientX,y:e.clientY});return}p();let t=1;e.deltaMode===1?t=16:e.deltaMode===2&&(t=u().height);let r=a.z<.1?We:Ue;f(Ke(a,Math.exp(-e.deltaY*t*$e),e.clientX,e.clientY,r))}function _(t){return t.button===1?!0:t.button===0?o?!0:t.target===i||t.target===e.body||t.target===e.documentElement:!1}function v(e){_(e)&&(e.preventDefault(),l={lastX:e.clientX,lastY:e.clientY,startX:e.clientX,startY:e.clientY},s=!1)}function y(t){if(!l)return;if(!s){if(Math.hypot(t.clientX-l.startX,t.clientY-l.startY)<Qe)return;s=!0,p(),e.body.style.userSelect=`none`,h(`grabbing`)}let n=t.clientX-l.lastX,r=t.clientY-l.lastY;l.lastX=t.clientX,l.lastY=t.clientY,f(Ye(a,n,r))}function b(){l&&(l=null,s&&(s=!1,c=!0,e.body.style.userSelect=``,h(o?`grab`:``)))}function x(e){o!==e&&(o=e,s||h(e?`grab`:``))}function S(e){if(e.key===` `&&!e.metaKey&&!e.ctrlKey&&!e.altKey){let t=e.target,n=t?.tagName??``;if(n===`INPUT`||n===`TEXTAREA`||t?.isContentEditable===!0)return;x(!0),e.preventDefault()}else T(e)&&e.preventDefault()}function C(e){e.key===` `&&x(!1)}function w(){x(!1),b()}function T(e){return(e.ctrlKey||e.metaKey)&&(e.key===`0`||e.key===`)`||e.code===`Digit0`||e.code===`Numpad0`)?(f(qe(a,1,u())),!0):e.shiftKey&&!e.ctrlKey&&!e.metaKey&&(e.key===`!`||e.code===`Digit1`)?(E(),!0):!1}function E(){f(Je({x:0,y:0,w:i.offsetWidth,h:i.offsetHeight},u()))}function ee(e){let t=u();m({z:a.z,tx:t.width/2-(e.x+e.w/2)*a.z,ty:t.height/2-(e.y+e.h/2)*a.z})}return e.addEventListener(`wheel`,g,{passive:!1}),e.addEventListener(`mousedown`,v,!0),e.addEventListener(`mousemove`,y,!0),e.addEventListener(`mouseup`,b,!0),e.addEventListener(`keydown`,S),e.addEventListener(`keyup`,C),e.defaultView?.addEventListener(`blur`,w),{get:()=>a,set:f,fitAll:E,centerOn:ee,focusBox:e=>m(Je(e,u())),zoomToPercent:e=>f(qe(a,e,u())),consumeDragClick:()=>{let e=c;return c=!1,e},handleKey:T,setSpace:x,destroy:()=>{e.removeEventListener(`wheel`,g),e.removeEventListener(`mousedown`,v,!0),e.removeEventListener(`mousemove`,y,!0),e.removeEventListener(`mouseup`,b,!0),e.removeEventListener(`keydown`,S),e.removeEventListener(`keyup`,C),e.defaultView?.removeEventListener(`blur`,w)}}}var tt=`[data-ptr-selected]{outline:2px solid #908030 !important;outline-offset:-2px;}
|
|
2
|
+
[data-ptr-hover]:not([data-ptr-selected]){outline:1px dashed rgba(144,128,48,.55) !important;outline-offset:-2px;}
|
|
3
|
+
[data-ptr-changed]{box-shadow:inset 0 0 0 2px rgba(144,128,48,1);animation:ptr-pulse 2s ease-in-out infinite;}
|
|
4
|
+
@keyframes ptr-pulse{0%,100%{box-shadow:inset 0 0 0 2px rgba(144,128,48,1)}50%{box-shadow:inset 0 0 0 2px rgba(144,128,48,.25)}}
|
|
5
|
+
@media (prefers-reduced-motion: reduce){[data-ptr-changed]{animation:none !important;}}
|
|
6
|
+
html{cursor:default;}
|
|
7
|
+
html,body{overflow:hidden;}
|
|
8
|
+
html,body{background:var(--ptr-canvas-bg,#ffffff);}`;function nt(e){let{clientX:t,rectLeft:n,rectWidth:r,pad:i,thumb:a,count:o}=e,s=r-i*2-a;if(s<=0||o<2)return null;let c=(t-n-i-a/2)/s;return Math.max(0,Math.min(o-1,c*(o-1)))}var rt=U(`<div class=canvas-bg><span class=canvas-bg-label></span><div class=canvas-bg-track role=slider tabindex=0 aria-valuemin=0 style=--pad:3px;--thumb:20px><div class=canvas-bg-thumb aria-hidden=true><span class=canvas-bg-dot>`),$=[`light`,`gray`,`dark`],it={light:`Light`,gray:`Gray`,dark:`Dark`},at={light:`#ffffff`,gray:`#d2cec7`,dark:`#242b36`},ot=`paintress:canvas-bg`;function st(e){return $.includes(e)}function ct(){try{let e=localStorage.getItem(ot);if(st(e))return e}catch{}return`light`}function lt(e){try{localStorage.setItem(ot,e)}catch{}}var ut=3,dt=20;function ft(e){let[t,n]=y(!1),[r,i]=y(null),[a,o]=y(29),s,c=()=>$.indexOf(e.value),l=()=>r()??c();T(()=>{let e=()=>{let e=s;if(!e)return;let t=e.getBoundingClientRect().width-6-dt;o(t/($.length-1))};if(e(),typeof ResizeObserver>`u`||!s)return;let t=new ResizeObserver(e);t.observe(s),E(()=>t.disconnect())});function u(e){let t=s;if(!t)return c();let n=t.getBoundingClientRect();return nt({clientX:e.clientX,rectLeft:n.left,rectWidth:n.width,pad:ut,thumb:dt,count:$.length})??c()}function d(t){let n=$[Math.round(t)];n!==void 0&&n!==e.value&&e.onChange(n)}function f(e){e.button===0&&(e.preventDefault(),e.currentTarget.setPointerCapture(e.pointerId),n(!0),i(u(e)))}function p(e){t()&&i(u(e))}function m(e){if(!t())return;let r=e.currentTarget;n(!1),i(null),d(u(e)),r.hasPointerCapture(e.pointerId)&&r.releasePointerCapture(e.pointerId)}function h(){n(!1),i(null)}function g(t){let n=t.key===`ArrowRight`||t.key===`ArrowUp`?1:t.key===`ArrowLeft`||t.key===`ArrowDown`?-1:0;if(n===0)return;t.preventDefault();let r=$[Math.max(0,Math.min($.length-1,c()+n))];r!==void 0&&e.onChange(r)}return(()=>{var n=rt(),r=n.firstChild,i=r.nextSibling,o=i.firstChild.firstChild;q(r,()=>it[e.value]),i.$$keydown=g,i.addEventListener(`lostpointercapture`,h),i.addEventListener(`pointercancel`,h),i.$$pointerup=m,i.$$pointermove=p,i.$$pointerdown=f;var u=s;return typeof u==`function`?ge(u,i):s=i,b(n=>{var r=!!t(),s=e.label,u=$.length-1,d=c(),f=it[e.value],p=e.label,m=`${a()}px`,h=String(l()),g=at[e.value];return r!==n.e&&i.classList.toggle(`dragging`,n.e=r),s!==n.t&&G(i,`aria-label`,n.t=s),u!==n.a&&G(i,`aria-valuemax`,n.a=u),d!==n.o&&G(i,`aria-valuenow`,n.o=d),f!==n.i&&G(i,`aria-valuetext`,n.i=f),p!==n.n&&G(i,`title`,n.n=p),m!==n.s&&K(i,`--step`,n.s=m),h!==n.h&&K(i,`--pos`,n.h=h),g!==n.r&&K(o,`--dot`,n.r=g),n},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0,s:void 0,h:void 0,r:void 0}),n})()}W([`pointerdown`,`pointermove`,`pointerup`,`keydown`]);var pt={zh:{projects:`项目`,noProjects:`还没有注册项目`,projectFiles:e=>`${e} 个设计稿`,designs:`设计稿`,depth:`depth`,noFiles:`没有 .ptr / .pen 文件`,marks:`标记`,clear:`清空`,liveReload:`实时刷新`,refreshList:`刷新列表`,pickProject:`从左侧选择项目`,pickFile:`从左侧选择一个设计稿`,fit:`适应`,fitTitle:`适应窗口(Shift+1)`,actualSize:`1:1`,actualSizeTitle:`100%(Ctrl/Cmd+0)`,rerender:`重新渲染`,allBoards:`全部`,canvasBackground:`画布背景`,language:`界面语言`,unwatch:`解绑`,unwatchTitle:`解绑项目`,unwatchBody:e=>`「${e}」将从项目列表中移除。设计稿文件不受影响;agent 下次启动会自动重新注册。`,closeServer:`关闭服务器`,closeServerTitle:`关闭 web 进程`,closeServerBody:(e,t)=>`将断开 ${t} 个长连接并停止进程 pid ${e}。之后可用 paintress web 重新启动。`,cancel:`取消`,serverClosed:`服务已关闭`,serverClosedHint:`可以关闭此页面;需要时重新启动 paintress web。`,updateAvailable:(e,t)=>`新版 v${e}(当前 v${t})`,updateTitle:`有新版本`,updatePrompt:`把 paintress 升级到最新版:npm install -g paintress@latest,完成后重启 MCP 会话。`,updateSteps:`把上面这句话交给你的 AI 即可;或自己在终端执行那条命令。`,updateRepo:`GitHub`,copy:`复制`,copied:`已复制`,close:`关闭`,versionTitle:`版本`},en:{projects:`Projects`,noProjects:`No projects registered yet`,projectFiles:e=>`${e} design${e===1?``:`s`}`,designs:`Designs`,depth:`depth`,noFiles:`No .ptr / .pen files`,marks:`Marks`,clear:`Clear`,liveReload:`Live reload`,refreshList:`Refresh`,pickProject:`Pick a project on the left`,pickFile:`Pick a design on the left`,fit:`Fit`,fitTitle:`Fit to window (Shift+1)`,actualSize:`1:1`,actualSizeTitle:`100% (Ctrl/Cmd+0)`,rerender:`Re-render`,allBoards:`All`,canvasBackground:`Canvas background`,language:`Language`,unwatch:`Unbind`,unwatchTitle:`Unbind project`,unwatchBody:e=>`“${e}” will be removed from the project list. Design files are untouched; the agent re-registers it on next start.`,closeServer:`Stop server`,closeServerTitle:`Stop web process`,closeServerBody:(e,t)=>`This drops ${t} live connection${t===1?``:`s`} and stops process pid ${e}. Restart later with paintress web.`,cancel:`Cancel`,serverClosed:`Server stopped`,serverClosedHint:`You can close this page; run paintress web to start it again.`,updateAvailable:(e,t)=>`v${e} available (running v${t})`,updateTitle:`Update available`,updatePrompt:`Upgrade paintress to the latest version: npm install -g paintress@latest, then restart the MCP session.`,updateSteps:`Hand that line to your AI, or run the command yourself in a terminal.`,updateRepo:`GitHub`,copy:`Copy`,copied:`Copied`,close:`Close`,versionTitle:`Version`}};function mt(e){return pt[e]}function ht(e){return(e?.languages?.[0]??e?.language??``).toLowerCase().startsWith(`zh`)?`zh`:`en`}var gt=`paintress:lang`;function _t(e){return e===`zh`||e===`en`}function vt(){try{let e=localStorage.getItem(gt);if(_t(e))return e}catch{}return ht(typeof navigator>`u`?void 0:navigator)}function yt(e){try{localStorage.setItem(gt,e)}catch{}}var bt=U(`<button class="badge badge-stack"><span>v</span><span class=badge-new>v`),xt=U(`<ul class=list>`),St=U(`<section class="section files"><h2> <span class=hint> `),Ct=U(`<section class="section marks"><h2><button class="ghost tiny"></button></h2><ul class=list>`),wt=U(`<span class=hint>pid `),Tt=U(`<div class=error>`),Et=U(`<code>/`),Dt=U(`<span class="hint zoom">%`),Ot=U(`<button class="ghost tiny">`),kt=U(`<button class=ghost>`),At=U(`<span class=tool-sep>`),jt=U(`<div class=boardbar><button class=board>`),Mt=U(`<iframe class=preview title="design preview"sandbox="allow-same-origin allow-scripts">`),Nt=U(`<div class=modal-backdrop><div class=modal role=status><h3></h3><p class=modal-body>`),Pt=U(`<p class=modal-body>`),Ft=U(`<pre class=prompt>`),It=U(`<div class=app><aside class=sidebar><header class=sidebar-head><img class=brand-mark src=/logo.svg alt><h1>paintress</h1></header><section class=section><h2></h2></section><footer class=sidebar-foot><label class=toggle><input type=checkbox></label><button class=ghost></button><button class=ghost></button></footer></aside><main class=stage><div class=toolbar><div class=crumbs></div><div class=tools><div class=lang-switch role=group><button class=lang-opt>中</button><button class=lang-opt>EN`),Lt=U(`<span class=badge>v`),Rt=U(`<p class=empty><br><code>paintress watch <name> <dir>`),zt=U(`<li class=row><button class=item><span class=item-name></span><span class=item-meta></span></button><button class=row-action>×`),Bt=U(`<p class=empty>`),Vt=U(`<li><button class=item><span class=item-name>`),Ht=U(`<li><button class=item><span class=item-name><b class=mark-no>#</b> </span><span class=item-meta>`),Ut=U(`<span class=sep>/`),Wt=U(`<button class=crumb>`),Gt=U(`<p>`),Kt=U(`<div class=placeholder>`),qt=U(`<button class=board><span class=board-size>×`),Jt=U(`<a class=ghost href=https://github.com/aliciai-dev/paintress target=_blank rel=noreferrer>`);function Yt(e){return typeof CSS<`u`&&typeof CSS.escape==`function`?CSS.escape(e):e.replace(/["\\]/g,`\\$&`)}function Xt(){let[e,t]=y([]),[n,r]=y(null),[i,a]=y([]),[o,s]=y(null),[c,l]=y([]),[u,d]=y(null),[f,p]=y([]),[m,h]=y(null),[g,_]=y({}),[v,S]=y(0),[C,ee]=y(!0),[te,D]=y(``),[ne,O]=y([]),[re,k]=y(null),[ie,ae]=y(1),[A,j]=y(vt()),[M,oe]=y(ct()),[se,N]=y(null),[P,F]=y(!1),[ce,le]=y(!1),[ue,I]=y(!1),L=()=>mt(A()),de,R,B=null,me;function H(){let e=new URLSearchParams,t=n(),r=o();t&&e.set(`project`,t),r&&e.set(`file`,r);let i=e.toString();history.replaceState(null,``,i?`?${i}`:location.pathname)}async function he(){try{let e=await xe();t(e.projects),_({pid:e.pid,version:e.version,latest:e.latest??null,connections:e.connections}),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}async function U(){try{let e=await Se();_({pid:e.pid,version:e.version,latest:e.latest??null,connections:e.connections})}catch{}}async function W(e){try{l((await De(e)).marks)}catch{l([])}}async function K(e){r(e),s(null),d(null),p([]);try{let t=await Ce(e);a(t.files),h(null)}catch(e){a([]),h(e instanceof Error?e.message:String(e))}W(e),H()}async function _e(){await he();let t=n();if(t!==null){if(!e().some(e=>e.name===t))r(null),s(null),a([]),d(null),p([]),H();else{try{let n=await Ce(t),r=i();a(n.files);let c=o();if(c===null){let i=n.files.filter(e=>!r.includes(e));i.length>0&&e().some(e=>e.name===t)&&ve(i[0])}else n.files.includes(c)||(s(null),d(null),p([]),H())}catch{}W(t)}}}function ve(e){s(e),d(null),p([]),H()}function J(){let e=g().latest??null,t=g().version??null;return e===null||t===null?null:He(e,t)?e:null}async function ye(){try{await navigator.clipboard.writeText(L().updatePrompt),I(!0),setTimeout(()=>I(!1),1500)}catch{}}function be(e){N({kind:`unwatch`,name:e})}function Y(){N({kind:`shutdown`}),U()}function X(){let e=se();return e===null?{title:``,body:``,confirm:``}:e.kind===`unwatch`?{title:L().unwatchTitle,body:L().unwatchBody(e.name),confirm:L().unwatch}:{title:L().closeServerTitle,body:L().closeServerBody(g().pid??0,g().connections??0),confirm:L().closeServer}}async function Ae(){let e=se();if(N(null),e!==null)try{e.kind===`unwatch`?(await je(e.name),await _e()):(await Me(),F(!0))}catch(e){h(e instanceof Error?e.message:String(e))}}T(()=>{let e=new EventSource(Ee());e.addEventListener(`projects`,()=>void _e()),E(()=>e.close());let t=setTimeout(()=>{P()||U()},4e3),n=setInterval(()=>{P()||U()},6e4);E(()=>{clearTimeout(t),clearInterval(n)});let r=e=>{let t=e.target;return t?.tagName===`INPUT`||t?.tagName===`TEXTAREA`||t?.isContentEditable===!0},i=e=>{r(e)||(e.key===` `&&!e.ctrlKey&&!e.metaKey&&!e.altKey?(B?.setSpace(!0),e.preventDefault()):B?.handleKey(e)===!0&&e.preventDefault())},a=e=>{e.key===` `&&B?.setSpace(!1)};window.addEventListener(`keydown`,i),window.addEventListener(`keyup`,a),E(()=>{window.removeEventListener(`keydown`,i),window.removeEventListener(`keyup`,a)});let o=new URLSearchParams(location.search);(async()=>{await he();let e=o.get(`project`);if(e){await K(e);let t=o.get(`file`);t&&ve(t)}})()});let Z=()=>de?.contentDocument??null;function Pe(){let e=Z();if(!e||e.getElementById(`ptr-style`))return;let t=e.createElement(`style`);t.id=`ptr-style`,t.textContent=tt,e.head.appendChild(t)}function Fe(){let e=Z();if(!e)return;for(let t of e.querySelectorAll(`[data-ptr-selected]`))t.removeAttribute(`data-ptr-selected`);let t=u();t&&e.querySelector(`[data-node-id="${Yt(t)}"]`)?.setAttribute(`data-ptr-selected`,``)}function Ie(e){return e.parentElement?.closest(`[data-node-id]`)??null}function Le(e){return e.querySelector(`:scope > [data-node-id]`)}function Be(e){if(B?.consumeDragClick()===!0){e.preventDefault(),e.stopPropagation();return}let t=e.target?.closest(`[data-node-id]`);t&&(e.preventDefault(),e.stopPropagation(),Qe(e.altKey?Ie(t)??t:t))}function Ve(e,t){let n=Z();if(!n)return;let r=u(),i=r===null?null:n.querySelector(`[data-node-id="${Yt(r)}"]`);if(i===null){let e=(n.elementFromPoint(t.x,t.y)?.closest(`[data-node-id]`))?.dataset.nodeId;e!==void 0&&$e(e);return}let a=(e===1?Ie(i):Le(i))?.dataset.nodeId;a!==void 0&&$e(a)}function Ue(e){let t=Z();if(t){for(let e of t.querySelectorAll(`[data-ptr-hover]`))e.removeAttribute(`data-ptr-hover`);(e.target?.closest(`[data-node-id]`))?.setAttribute(`data-ptr-hover`,``)}}async function We(){let e=n(),t=o();if(e&&t)try{let n=await Ne(e,t);if(!n.ok||n.ids.length===0)return;let r=Z();if(!r)return;for(let e of n.ids)r.querySelector(`[data-node-id="${Yt(e)}"]`)?.setAttribute(`data-ptr-changed`,``)}catch{}}function Ge(){let e=Z();return e?Array.from(e.querySelectorAll(`[data-board]`)).map(e=>{let t=e.dataset;return{id:t.nodeId??``,...t.boardName===void 0?{}:{name:t.boardName},x:Number(t.boardX??0),y:Number(t.boardY??0),w:Number(t.boardW??0),h:Number(t.boardH??0)}}):[]}function Q(){let e=n(),t=o();return e&&t?`paintress:viewport:${e}/${t}`:null}function Ke(e){let t=Q();t!==null&&(clearTimeout(me),me=setTimeout(()=>{try{localStorage.setItem(t,JSON.stringify(e))}catch{}},300))}function qe(){let e=Z();e&&(Pe(),rt(),B?.destroy(),B=et({doc:e,onChange:e=>{ae(e.z),Ke(e)},onLevelStep:Ve}),O(Ge()),k(null),Je(),e.addEventListener(`click`,Be,!0),e.addEventListener(`mousemove`,Ue,!0),Fe(),We())}function Je(){if(!B)return;let e=Q(),t=e===null?null:localStorage.getItem(e),n=t===null?null:Ze(t);n===null?B.fitAll():B.set(n)}function Ye(e){if(k(e),!B)return;if(e===null){B.fitAll();return}let t=ne().find(t=>t.id===e);t&&B.focusBox({x:t.x,y:t.y,w:t.w,h:t.h})}function Xe(e){let t=[],n=e;for(;n;){let e=n.closest(`[data-node-id]`);if(!e)break;let r=e;t.unshift({id:r.dataset.nodeId??``,type:r.dataset.nodeType??`?`,name:r.dataset.nodeName}),n=e.parentElement}return t}async function Qe(e){let t=e.dataset.nodeId??``;if(t===``)return;let r=Xe(e);d(t),p(r),Fe();let i=n();if(i)try{await Oe({project:i,nodeId:t,...e.dataset.nodeName===void 0?{}:{name:e.dataset.nodeName},...e.dataset.nodeType===void 0?{}:{type:e.dataset.nodeType},path:r.map(e=>e.name??e.type).join(` / `)}),l((await De(i)).marks),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}function $e(e){d(e),Fe();let t=Z(),n=t?.querySelector(`[data-node-id="${Yt(e)}"]`);if(!n||!t){p([]);return}p(Xe(n));let r=t.querySelector(`.ptr-canvas`);if(!r||!B){n.scrollIntoView({block:`center`});return}let i=n.getBoundingClientRect(),a=r.getBoundingClientRect(),o=B.get().z;B.centerOn({x:(i.left-a.left)/o,y:(i.top-a.top)/o,w:i.width/o,h:i.height/o})}async function nt(){let e=n();if(e)try{await ke(e),l([]),d(null),p([]),Fe()}catch(e){h(e instanceof Error?e.message:String(e))}}x(()=>{let e=A();document.documentElement.lang=e===`zh`?`zh-CN`:`en`,yt(e)});function rt(){if(R!==void 0){if(o()===null)R.style.removeProperty(`--canvas-bg`),R.removeAttribute(`data-canvas-bg`);else{let e=at[M()];R.style.setProperty(`--canvas-bg`,e),R.setAttribute(`data-canvas-bg`,M())}Z()?.documentElement.style.setProperty(`--ptr-canvas-bg`,at[M()])}}x(()=>{M(),lt(M()),rt()}),x(w([n,o,v],()=>{let e=n(),t=o();D(e&&t?`${we(e,t)}&r=${v()}`:``),rt()}));let $=null;return x(w([n,o,C],()=>{$?.close(),$=null;let e=n(),t=o();C()&&e&&t&&($=new EventSource(Te(e,t)),$.addEventListener(`change`,()=>S(e=>e+1)))})),E(()=>$?.close()),(()=>{var t=It(),r=t.firstChild,a=r.firstChild;a.firstChild.nextSibling;var s=a.nextSibling,l=s.firstChild,d=s.nextSibling,p=d.firstChild,h=p.firstChild,_=p.nextSibling,v=_.nextSibling,y=r.nextSibling,x=y.firstChild,w=x.firstChild,T=w.nextSibling,E=T.firstChild,D=E.firstChild,O=D.nextSibling;return q(a,z(V,{get when(){return g().version},get children(){return z(V,{get when(){return J()},get fallback(){return(()=>{var e=Lt();return e.firstChild,q(e,()=>g().version,null),b(()=>G(e,`title`,L().versionTitle)),e})()},get children(){var e=bt(),t=e.firstChild;t.firstChild;var n=t.nextSibling;return n.firstChild,e.$$click=()=>le(!0),q(t,()=>g().version,null),q(n,J,null),b(()=>G(e,`title`,L().updateTitle)),e}})}}),null),q(l,()=>L().projects),q(s,z(V,{get when(){return e().length>0},get fallback(){return(()=>{var e=Rt(),t=e.firstChild;return q(e,()=>L().noProjects,t),e})()},get children(){var t=xt();return q(t,z(fe,{get each(){return e()},children:e=>(()=>{var t=zt(),r=t.firstChild,i=r.firstChild,a=i.nextSibling,o=r.nextSibling;return r.$$click=()=>void K(e.name),q(i,()=>e.name),q(a,()=>L().projectFiles(e.fileCount)),o.$$click=()=>be(e.name),b(t=>{var i=n()===e.name,a=L().unwatch,s=`${L().unwatch} ${e.name}`;return i!==t.e&&r.classList.toggle(`active`,t.e=i),a!==t.t&&G(o,`title`,t.t=a),s!==t.a&&G(o,`aria-label`,t.a=s),t},{e:void 0,t:void 0,a:void 0}),t})()})),t}}),null),q(r,z(V,{get when(){return n()},get children(){var t=St(),r=t.firstChild,a=r.firstChild,s=a.nextSibling,c=s.firstChild;return q(r,()=>L().designs,a),q(s,()=>L().depth,c),q(s,()=>e().find(e=>e.name===n())?.depth??`-`,null),q(t,z(V,{get when(){return i().length>0},get fallback(){return(()=>{var e=Bt();return q(e,()=>L().noFiles),e})()},get children(){var e=xt();return q(e,z(fe,{get each(){return i()},children:e=>(()=>{var t=Vt(),n=t.firstChild,r=n.firstChild;return n.$$click=()=>ve(e),q(r,e),b(()=>n.classList.toggle(`active`,o()===e)),t})()})),e}}),null),t}}),d),q(r,z(V,{get when(){return c().length>0},get children(){var e=Ct(),t=e.firstChild,n=t.firstChild,r=t.nextSibling;return q(t,()=>L().marks,n),n.$$click=()=>void nt(),q(n,()=>L().clear),q(r,z(fe,{get each(){return c()},children:e=>(()=>{var t=Ht(),n=t.firstChild,r=n.firstChild,i=r.firstChild;i.firstChild,i.nextSibling;var a=r.nextSibling;return n.$$click=()=>$e(e.nodeId),q(i,()=>e.shortId,null),q(r,()=>e.name??e.nodeId,null),q(a,()=>e.path),b(()=>n.classList.toggle(`active`,u()===e.nodeId)),t})()})),e}}),d),h.addEventListener(`change`,e=>ee(e.currentTarget.checked)),q(p,()=>L().liveReload,null),_.$$click=()=>void he(),q(_,()=>L().refreshList),v.$$click=()=>Y(),q(v,()=>L().closeServer),q(d,z(V,{get when(){return g().pid},get children(){var e=wt();return e.firstChild,q(e,()=>g().pid,null),e}}),null),ge(e=>{R=e},y),q(y,z(V,{get when(){return m()},get children(){var e=Tt();return q(e,m),e}}),x),q(w,z(V,{get when(){return f().length===0},get fallback(){return z(fe,{get each(){return f()},children:(e,t)=>[z(V,{get when(){return t()>0},get children(){return Ut()}}),(()=>{var t=Wt();return t.$$click=()=>$e(e.id),q(t,()=>e.name??e.type),b(()=>t.classList.toggle(`active`,u()===e.id)),t})()]})},get children(){return z(V,{get when(){return pe(()=>n()!==null)()&&o()!==null},get children(){var e=Et(),t=e.firstChild;return q(e,n,t),q(e,o,null),e}})}})),q(T,z(V,{get when(){return pe(()=>n()!==null)()&&o()!==null},get children(){return[(()=>{var e=Dt(),t=e.firstChild;return q(e,()=>Math.round(ie()*100),t),e})(),(()=>{var e=Ot();return e.$$click=()=>B?.fitAll(),q(e,()=>L().fit),b(()=>G(e,`title`,L().fitTitle)),e})(),(()=>{var e=Ot();return e.$$click=()=>B?.zoomToPercent(1),q(e,()=>L().actualSize),b(()=>G(e,`title`,L().actualSizeTitle)),e})(),(()=>{var e=kt();return e.$$click=()=>S(e=>e+1),q(e,()=>L().rerender),e})(),At()]}}),E),q(T,z(ft,{get value(){return M()},onChange:oe,get label(){return L().canvasBackground}}),E),D.$$click=()=>j(`zh`),O.$$click=()=>j(`en`),q(y,z(V,{get when(){return pe(()=>n()!==null)()&&o()!==null},get fallback(){return(()=>{var e=Kt();return q(e,z(V,{get when(){return n()},get fallback(){return(()=>{var e=Gt();return q(e,()=>L().pickProject),e})()},get children(){var e=Gt();return q(e,()=>L().pickFile),e}})),e})()},get children(){return[z(V,{get when(){return ne().length>1},get children(){var e=jt(),t=e.firstChild;return t.$$click=()=>Ye(null),q(t,()=>L().allBoards),q(e,z(fe,{get each(){return ne()},children:e=>(()=>{var t=qt(),n=t.firstChild,r=n.firstChild;return t.$$click=()=>Ye(e.id),q(t,()=>e.name??`#${e.id}`,n),q(n,()=>Math.round(e.w),r),q(n,()=>Math.round(e.h),null),b(()=>t.classList.toggle(`active`,re()===e.id)),t})()}),null),b(()=>t.classList.toggle(`active`,re()===null)),e}}),(()=>{var e=Mt();return e.addEventListener(`load`,qe),ge(e=>{de=e},e),b(()=>G(e,`src`,te())),e})()]}}),null),q(t,z(ze,{get open(){return se()!==null},get title(){return X().title},get body(){return X().body},get confirmLabel(){return X().confirm},get cancelLabel(){return L().cancel},onConfirm:()=>void Ae(),onCancel:()=>N(null)}),null),q(t,z(V,{get when(){return P()},get children(){var e=Nt(),t=e.firstChild.firstChild,n=t.nextSibling;return q(t,()=>L().serverClosed),q(n,()=>L().serverClosedHint),e}}),null),q(t,z(Re,{get open(){return ce()},get title(){return L().updateTitle},onClose:()=>le(!1),get actions(){return[(()=>{var e=Jt();return q(e,()=>L().updateRepo),e})(),(()=>{var e=kt();return e.$$click=()=>le(!1),q(e,()=>L().close),e})()]},get children(){return[(()=>{var e=Pt();return q(e,()=>L().updateAvailable(J()??``,g().version??``)),e})(),(()=>{var e=Ft();return q(e,()=>L().updatePrompt),e})(),(()=>{var e=Ot();return e.$$click=()=>void ye(),q(e,(()=>{var e=pe(()=>!!ue());return()=>e()?L().copied:L().copy})()),e})(),(()=>{var e=Pt();return q(e,()=>L().updateSteps),e})()]}}),null),b(e=>{var t=L().language,n=L().language,r=A()===`zh`,i=A()===`zh`,a=A()===`en`,o=A()===`en`;return t!==e.e&&G(E,`aria-label`,e.e=t),n!==e.t&&G(E,`title`,e.t=n),r!==e.a&&D.classList.toggle(`active`,e.a=r),i!==e.o&&G(D,`aria-pressed`,e.o=i),a!==e.i&&O.classList.toggle(`active`,e.i=a),o!==e.n&&G(O,`aria-pressed`,e.n=o),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0}),b(()=>h.checked=C()),t})()}W([`click`]);var Zt=document.getElementById(`root`);if(!Zt)throw Error(`缺少 #root 容器`);he(()=>z(Xt,{}),Zt);
|
package/ui/dist/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>paintress</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-kPX0SDa0.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Dyrrkh92.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--bg:#f6f1ea;--panel:#fffcf8;--border:#e6ded2;--text:#1f2a37;--muted:#7a7166;--accent:#205080;--accent-soft:#20508014;--gold:#908030;--gold-soft:#90803073;--radius:8px}*{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:100%}body{color:var(--text);background:var(--bg);-webkit-font-smoothing:antialiased;font:14px/1.55 system-ui,-apple-system,Segoe UI,Noto Sans SC,sans-serif}.app{grid-template-columns:280px 1fr;height:100%;display:grid}.sidebar{background:var(--panel);border-right:1px solid var(--border);flex-direction:column;min-height:0;display:flex}.sidebar-head{border-bottom:1px solid var(--border);align-items:center;gap:8px;padding:16px 16px 12px;display:flex}.sidebar-head h1{letter-spacing:-.01em;color:var(--accent);font-size:15px;font-weight:650}.badge{color:var(--muted);background:var(--bg);border-radius:999px;padding:1px 6px;font-size:11px}.section{min-height:0;padding:12px 8px 4px;overflow-y:auto}.section.files{border-top:1px solid var(--border);flex:1;padding-top:12px}.section h2{text-transform:uppercase;letter-spacing:.06em;color:var(--muted);justify-content:space-between;gap:8px;padding:0 8px 8px;font-size:11px;font-weight:600;display:flex}.hint{color:var(--muted);text-transform:none;letter-spacing:0;font-size:11px;font-weight:400}.list{list-style:none}.item{text-align:left;cursor:pointer;width:100%;font:inherit;color:inherit;background:0 0;border:0;border-radius:6px;flex-direction:column;gap:1px;padding:7px 8px;display:flex}.item:hover{background:var(--bg)}.item.active{background:var(--accent-soft);color:var(--accent)}.item-name{text-overflow:ellipsis;white-space:nowrap;font-size:13px;overflow:hidden}.item-meta{color:var(--muted);font-size:11px}.item.active .item-meta{color:var(--accent);opacity:.75}.empty{color:var(--muted);padding:4px 8px 12px;font-size:12px;line-height:1.7}.empty code{background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:1px 5px;font-size:11px}.sidebar-foot{border-top:1px solid var(--border);color:var(--muted);flex-wrap:wrap;align-items:center;gap:8px;padding:10px 16px;font-size:12px;display:flex}.toggle{cursor:pointer;align-items:center;gap:5px;display:inline-flex}.ghost{background:var(--bg);border:1px solid var(--border);font:inherit;color:var(--text);cursor:pointer;border-radius:6px;padding:3px 9px;font-size:12px}.ghost:hover{border-color:var(--accent);color:var(--accent)}.stage{background:var(--canvas-bg,var(--bg));flex-direction:column;min-width:0;min-height:0;display:flex}.toolbar{border-bottom:1px solid var(--border);background:var(--panel);justify-content:space-between;align-items:center;gap:12px;padding:8px 14px;display:flex}.toolbar code{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.preview{border:1px solid var(--border);background:var(--canvas-bg,#fff);border-radius:10px;flex:1;width:calc(100% - 24px);min-height:0;margin:12px;box-shadow:0 1px 2px #1f2a370d,0 8px 24px #1f2a370d}.stage[data-canvas-bg=dark] .preview{border-color:#ffffff1f;box-shadow:0 1px 2px #00000059,0 10px 30px #00000052}.placeholder{color:var(--muted);flex:1;place-items:center;display:grid}.error{border-radius:var(--radius);color:#b91c1c;white-space:pre-wrap;background:#fef2f2;border:1px solid #fecaca;margin:12px;padding:10px 12px;font-size:12px}.section.marks{border-top:1px solid var(--border);flex:0 auto;max-height:34vh}.mark-no{background:var(--accent-soft);min-width:20px;color:var(--accent);font-variant-numeric:tabular-nums;border-radius:4px;margin-right:4px;padding:0 4px;font-size:11px;display:inline-block}.item.active .mark-no{background:#fff}.ghost.tiny{text-transform:none;letter-spacing:0;padding:1px 6px;font-size:11px}.crumbs{flex-wrap:wrap;align-items:center;gap:3px;min-width:0;display:flex;overflow:hidden}.crumbs code{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.crumb{font:inherit;color:var(--muted);cursor:pointer;text-overflow:ellipsis;white-space:nowrap;background:0 0;border:0;border-radius:4px;max-width:220px;padding:2px 5px;font-size:12px;overflow:hidden}.crumb:hover{background:var(--bg);color:var(--text)}.crumb.active{color:var(--accent);background:var(--accent-soft)}.sep{color:var(--border);font-size:11px}.brand-mark{flex:none;width:auto;height:32px}.canvas-bg{-webkit-user-select:none;user-select:none;flex:none;align-items:center;gap:8px;display:inline-flex}.canvas-bg-label{letter-spacing:.04em;text-transform:uppercase;color:var(--muted);text-align:right;min-width:34px;font-size:11px;font-weight:500}.canvas-bg-track{width:84px;height:calc(var(--thumb) + var(--pad) * 2);cursor:pointer;touch-action:none;background:linear-gradient(#e7e0d5,#f3eee6 60%,#f7f2ea);border-radius:999px;position:relative;box-shadow:inset 0 1px 2px #1f2a373d,inset 0 -1px #ffffffe6,inset 0 0 0 1px #1f2a3712,0 1px #fff}.canvas-bg-track:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.canvas-bg-thumb{top:var(--pad);left:var(--pad);width:var(--thumb);height:var(--thumb);transform:translateX(calc(var(--pos) * var(--step)));background:linear-gradient(#fff,#f1ebe1);border-radius:50%;justify-content:center;align-items:center;transition:transform .17s cubic-bezier(.22,.61,.36,1);display:flex;position:absolute;box-shadow:0 1px 2px #1f2a374d,0 0 0 1px #1f2a3714,inset 0 1px #fff}.canvas-bg-track.dragging .canvas-bg-thumb{transition:none}.canvas-bg-dot{background:var(--dot,#fff);border-radius:50%;width:11px;height:11px;transition:background .17s;box-shadow:0 0 0 1px #1f2a3742,0 1px 1px #1f2a371f}.lang-switch{background:linear-gradient(#ece6dc,#f6f1e9);border-radius:999px;flex:none;align-items:center;gap:2px;margin-left:4px;padding:2px;display:inline-flex;box-shadow:inset 0 1px 2px #1f2a3729,inset 0 0 0 1px #1f2a370d}.lang-opt{font:inherit;color:var(--muted);cursor:pointer;background:0 0;border:0;border-radius:999px;padding:2px 7px;font-size:11px;line-height:16px}.lang-opt:hover{color:var(--text)}.lang-opt.active{color:var(--accent);background:linear-gradient(#fffdf9,#f3ede4);font-weight:600;box-shadow:0 1px 2px #1f2a372e,inset 0 1px #fff}.tool-sep{background:var(--border);flex:none;width:1px;height:18px;margin:0 2px}.tools{flex:none;align-items:center;gap:6px;display:flex}.zoom{font-variant-numeric:tabular-nums;text-align:right;min-width:40px}.boardbar{border-bottom:1px solid var(--border);background:var(--panel);align-items:center;gap:6px;padding:6px 14px;display:flex;overflow-x:auto}.board{background:var(--bg);border:1px solid var(--border);font:inherit;color:var(--text);cursor:pointer;border-radius:6px;flex:none;align-items:baseline;gap:6px;padding:3px 9px;font-size:12px;display:inline-flex}.board:hover{border-color:var(--accent);color:var(--accent)}.board.active{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}.board-size{color:var(--muted);font-variant-numeric:tabular-nums;font-size:10px}.board.active .board-size{color:var(--accent);opacity:.75}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e={context:void 0,registry:void 0,effects:void 0,done:!1,getContextId(){return t(this.context.count)},getNextContextId(){return t(this.context.count++)}};function t(t){let n=String(t),r=n.length-1;return e.context.id+(r?String.fromCharCode(96+r):``)+n}function n(t){e.context=t}var r=(e,t)=>e===t,i=Symbol(`solid-track`),a={equals:r},o=null,s=oe,c=1,l=2,u={owned:null,cleanups:null,context:null,owner:null},d=null,f=null,p=null,m=null,h=null,g=0;function _(e,t){let n=p,r=d,i=e.length===0,a=t===void 0?r:t,o=i?u:{owned:null,cleanups:null,context:a?a.context:null,owner:a},s=i?e:()=>e(v(o));d=o,p=null;try{return j(s,!0)}finally{p=n,d=r}}function v(e){return()=>C(()=>I(e))}function y(e,t){t=t?Object.assign({},a,t):a;let n={value:e,observers:null,observerSlots:null,comparator:t.equals||void 0};return[ne.bind(n),e=>(typeof e==`function`&&(e=f&&f.running&&f.sources.has(n)?e(n.tValue):e(n.value)),re(n,e))]}function b(e,t,n){k(ae(e,t,!1,c))}function x(e,t,n){s=N;let r=ae(e,t,!1,c),i=O&&D(O);i&&(r.suspense=i),n&&n.render||(r.user=!0),h?h.push(r):k(r)}function S(e,t,n){n=n?Object.assign({},a,n):a;let r=ae(e,t,!0,0);return r.observers=null,r.observerSlots=null,r.comparator=n.equals||void 0,k(r),ne.bind(r)}function C(e){if(p===null)return e();let t=p;p=null;try{return e()}finally{p=t}}function w(e,t,n){let r=Array.isArray(e),i,a=n&&n.defer;return n=>{let o;if(r){o=Array(e.length);for(let t=0;t<e.length;t++)o[t]=e[t]()}else o=e();if(a)return a=!1,n;let s=C(()=>t(o,i,n));return i=o,s}}function T(e){x(()=>C(e))}function E(e){return d===null||(d.cleanups===null?d.cleanups=[e]:d.cleanups.push(e)),e}var[ee,te]=y(!1);function D(e){let t;return d&&d.context&&(t=d.context[e.id])!==void 0?t:e.defaultValue}var O;function ne(){let e=f&&f.running;if(this.sources&&(e?this.tState:this.state)){if((e?this.tState:this.state)===c)k(this);else{let e=m;m=null,j(()=>P(this),!1),m=e}}if(p){let e=this.observers;if(!e||e[e.length-1]!==p){let t=e?e.length:0;p.sources?(p.sources.push(this),p.sourceSlots.push(t)):(p.sources=[this],p.sourceSlots=[t]),e?(e.push(p),this.observerSlots.push(p.sources.length-1)):(this.observers=[p],this.observerSlots=[p.sources.length-1])}}return e&&f.sources.has(this)?this.tValue:this.value}function re(e,t,n){let r=f&&f.running&&f.sources.has(e)?e.tValue:e.value;if(!e.comparator||!e.comparator(r,t)){if(f){let r=f.running;(r||!n&&f.sources.has(e))&&(f.sources.add(e),e.tValue=t),r||(e.value=t)}else e.value=t;e.observers&&e.observers.length&&j(()=>{for(let t=0;t<e.observers.length;t+=1){let n=e.observers[t],r=f&&f.running;r&&f.disposed.has(n)||((r?!n.tState:!n.state)&&(n.pure?m.push(n):h.push(n),n.observers&&F(n)),r?n.tState=c:n.state=c)}if(m.length>1e6)throw m=[],Error()},!1)}return t}function k(e){if(!e.fn)return;I(e);let t=g;ie(e,f&&f.running&&f.sources.has(e)?e.tValue:e.value,t),f&&!f.running&&f.sources.has(e)&&queueMicrotask(()=>{j(()=>{f&&(f.running=!0),p=d=e,ie(e,e.tValue,t),p=d=null},!1)})}function ie(e,t,n){let r,i=d,a=p;p=d=e;try{r=e.fn(t)}catch(t){return e.pure&&(f&&f.running?(e.tState=c,e.tOwned&&e.tOwned.forEach(I),e.tOwned=void 0):(e.state=c,e.owned&&e.owned.forEach(I),e.owned=null)),e.updatedAt=n+1,ue(t)}finally{p=a,d=i}(!e.updatedAt||e.updatedAt<=n)&&(e.updatedAt!=null&&`observers`in e?re(e,r,!0):f&&f.running&&e.pure?(f.sources.has(e)||(e.value=r),f.sources.add(e),e.tValue=r):e.value=r,e.updatedAt=n)}function ae(e,t,n,r=c,i){let a={fn:e,state:r,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:t,owner:d,context:d?d.context:null,pure:n};return f&&f.running&&(a.state=0,a.tState=r),d===null||d!==u&&(f&&f.running&&d.pure?d.tOwned?d.tOwned.push(a):d.tOwned=[a]:d.owned?d.owned.push(a):d.owned=[a]),a}function A(e){let t=f&&f.running;if((t?e.tState:e.state)===0)return;if((t?e.tState:e.state)===l)return P(e);if(e.suspense&&C(e.suspense.inFallback))return e.suspense.effects.push(e);let n=[e];for(;(e=e.owner)&&(!e.updatedAt||e.updatedAt<g);){if(t&&f.disposed.has(e))return;(t?e.tState:e.state)&&n.push(e)}for(let r=n.length-1;r>=0;r--){if(e=n[r],t){let t=e,i=n[r+1];for(;(t=t.owner)&&t!==i;)if(f.disposed.has(t))return}if((t?e.tState:e.state)===c)k(e);else if((t?e.tState:e.state)===l){let t=m;m=null,j(()=>P(e,n[0]),!1),m=t}}}function j(e,t){if(m)return e();let n=!1;t||(m=[]),h?n=!0:h=[],g++;try{let t=e();return M(n),t}catch(e){n||(h=null),m=null,ue(e)}}function M(e){if(m&&=(oe(m),null),e)return;let t;if(f){if(!f.promises.size&&!f.queue.size){let e=f.sources,n=f.disposed;h.push.apply(h,f.effects),t=f.resolve;for(let e of h)`tState`in e&&(e.state=e.tState),delete e.tState;f=null,j(()=>{for(let e of n)I(e);for(let t of e){if(t.value=t.tValue,t.owned)for(let e=0,n=t.owned.length;e<n;e++)I(t.owned[e]);t.tOwned&&(t.owned=t.tOwned),delete t.tValue,delete t.tOwned,t.tState=0}te(!1)},!1)}else if(f.running){f.running=!1,f.effects.push.apply(f.effects,h),h=null,te(!0);return}}let n=h;h=null,n.length&&j(()=>s(n),!1),t&&t()}function oe(e){for(let t=0;t<e.length;t++)A(e[t])}function N(t){let r,i=0;for(r=0;r<t.length;r++){let e=t[r];e.user?t[i++]=e:A(e)}if(e.context){if(e.count){e.effects||=[],e.effects.push(...t.slice(0,i));return}n()}for(e.effects&&(e.done||!e.count)&&(t=[...e.effects,...t],i+=e.effects.length,delete e.effects),r=0;r<i;r++)A(t[r])}function P(e,t){let n=f&&f.running;n?e.tState=0:e.state=0;for(let r=0;r<e.sources.length;r+=1){let i=e.sources[r];if(i.sources){let e=n?i.tState:i.state;e===c?i!==t&&(!i.updatedAt||i.updatedAt<g)&&A(i):e===l&&P(i,t)}}}function F(e){let t=f&&f.running;for(let n=0;n<e.observers.length;n+=1){let r=e.observers[n];(t?!r.tState:!r.state)&&(t?r.tState=l:r.state=l,r.pure?m.push(r):h.push(r),r.observers&&F(r))}}function I(e){let t;if(e.sources)for(;e.sources.length;){let t=e.sources.pop(),n=e.sourceSlots.pop(),r=t.observers;if(r&&r.length){let e=r.pop(),i=t.observerSlots.pop();n<r.length&&(e.sourceSlots[i]=n,r[n]=e,t.observerSlots[n]=i)}}if(e.tOwned){for(t=e.tOwned.length-1;t>=0;t--)I(e.tOwned[t]);delete e.tOwned}if(f&&f.running&&e.pure)se(e,!0);else if(e.owned){for(t=e.owned.length-1;t>=0;t--)I(e.owned[t]);e.owned=null}if(e.cleanups){for(t=e.cleanups.length-1;t>=0;t--)e.cleanups[t]();e.cleanups=null}f&&f.running?e.tState=0:e.state=0}function se(e,t){if(t||(e.tState=0,f.disposed.add(e)),e.owned)for(let t=0;t<e.owned.length;t++)se(e.owned[t])}function ce(e){return e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e})}function le(e,t,n){try{for(let n of t)n(e)}catch(e){ue(e,n&&n.owner||null)}}function ue(e,t=d){let n=o&&t&&t.context&&t.context[o],r=ce(e);if(!n)throw r;h?h.push({fn(){le(r,n,t)},state:c}):le(r,n,t)}var de=Symbol(`fallback`);function fe(e){for(let t=0;t<e.length;t++)e[t]()}function pe(e,t,n={}){let r=[],a=[],o=[],s=0,c=t.length>1?[]:null;return E(()=>fe(o)),()=>{let l=e()||[],u=l.length,d,f;return l[i],C(()=>{let e,t,i,m,h,g,v,y,b;if(u===0)s!==0&&(fe(o),o=[],r=[],a=[],s=0,c&&=[]),n.fallback&&(r=[de],a[0]=_(e=>(o[0]=e,n.fallback())),s=1);else if(s===0){for(a=Array(u),f=0;f<u;f++)r[f]=l[f],a[f]=_(p);s=u}else{for(i=Array(u),m=Array(u),c&&(h=Array(u)),g=0,v=Math.min(s,u);g<v&&r[g]===l[g];g++);for(v=s-1,y=u-1;v>=g&&y>=g&&r[v]===l[y];v--,y--)i[y]=a[v],m[y]=o[v],c&&(h[y]=c[v]);for(e=new Map,t=Array(y+1),f=y;f>=g;f--)b=l[f],d=e.get(b),t[f]=d===void 0?-1:d,e.set(b,f);for(d=g;d<=v;d++)b=r[d],f=e.get(b),f!==void 0&&f!==-1?(i[f]=a[d],m[f]=o[d],c&&(h[f]=c[d]),f=t[f],e.set(b,f)):o[d]();for(f=g;f<u;f++)f in i?(a[f]=i[f],o[f]=m[f],c&&(c[f]=h[f],c[f](f))):a[f]=_(p);a=a.slice(0,s=u),r=l.slice(0)}return a});function p(e){if(o[f]=e,c){let[e,n]=y(f);return c[f]=n,t(l[f],e)}return t(l[f])}}}function L(e,t){return C(()=>e(t||{}))}var R=e=>`Stale read from <${e}>.`;function z(e){let t=`fallback`in e&&{fallback:()=>e.fallback};return S(pe(()=>e.each,e.children,t||void 0))}function B(e){let t=e.keyed,n=S(()=>e.when,void 0,void 0),r=t?n:S(n,void 0,{equals:(e,t)=>!e==!t});return S(()=>{let i=r();if(i){let a=e.children;return typeof a==`function`&&a.length>0?C(()=>a(t?i:()=>{if(!C(r))throw R(`Show`);return n()})):a}return e.fallback},void 0,void 0)}var me=e=>S(()=>e());function he(e,t,n){let r=n.length,i=t.length,a=r,o=0,s=0,c=t[i-1].nextSibling,l=null;for(;o<i||s<a;)if(t[o]===n[s])o++,s++;else{for(;t[i-1]===n[a-1];)i--,a--;if(i===o){let t=a<r?s?n[s-1].nextSibling:n[a-s]:c;for(;s<a;)e.insertBefore(n[s++],t)}else if(a===s)for(;o<i;)l&&l.has(t[o])||t[o].remove(),o++;else if(t[o]===n[a-1]&&n[s]===t[i-1]){let r=t[--i].nextSibling;e.insertBefore(n[s++],t[o++].nextSibling),e.insertBefore(n[--a],r),t[i]=n[a]}else{if(!l){l=new Map;let e=s;for(;e<a;)l.set(n[e],e++)}let r=l.get(t[o]);if(r!=null){if(s<r&&r<a){let c=o,u=1,d;for(;++c<i&&c<a&&(d=l.get(t[c]))!=null&&d===r+u;)u++;if(u>r-s){let i=t[o];for(;s<r;)e.insertBefore(n[s++],i)}else e.replaceChild(n[s++],t[o++])}else o++}else t[o++].remove()}}}var V=`_$DX_DELEGATE`;function ge(e,t,n,r={}){let i;return _(r=>{i=r,t===document?e():W(t,e(),!n&&t.firstChild?null:void 0,n)},r.owner),()=>{i(),t.textContent=``}}function H(e,t,n,r){let i,a=()=>{let t=r?document.createElementNS(`http://www.w3.org/1998/Math/MathML`,`template`):document.createElement(`template`);return t.innerHTML=e,n?t.content.firstChild.firstChild:r?t.firstChild:t.content.firstChild},o=t?()=>C(()=>document.importNode(i||=a(),!0)):()=>(i||=a()).cloneNode(!0);return o.cloneNode=o,o}function _e(e,t=window.document){let n=t[V]||(t[V]=new Set);for(let r=0,i=e.length;r<i;r++){let i=e[r];n.has(i)||(n.add(i),t.addEventListener(i,xe))}}function U(e,t,n){be(e)||(n==null?e.removeAttribute(t):e.setAttribute(t,n))}function ve(e,t,n){n==null?e.style.removeProperty(t):e.style.setProperty(t,n)}function ye(e,t,n){return C(()=>e(t,n))}function W(e,t,n,r){if(n!==void 0&&!r&&(r=[]),typeof t!=`function`)return G(e,t,r,n);b(r=>G(e,t(),r,n),r)}function be(t){return!!e.context&&!e.done&&(!t||t.isConnected)}function xe(t){if(e.registry&&e.events&&e.events.find(([e,n])=>n===t))return;let n=t.target,r=`$$${t.type}`,i=t.target,a=t.currentTarget,o=e=>Object.defineProperty(t,"target",{configurable:!0,value:e}),s=()=>{let e=n[r];if(e&&!n.disabled){let i=n[`${r}Data`];if(i===void 0?e.call(n,t):e.call(n,i,t),t.cancelBubble)return}return n.host&&typeof n.host!=`string`&&!n.host._$host&&n.contains(t.target)&&o(n.host),!0},c=()=>{for(;s()&&(n=n._$host||n.parentNode||n.host););};Object.defineProperty(t,"currentTarget",{configurable:!0,get(){return n||document}}),e.registry&&!e.done&&(e.done=_$HY.done=!0);try{if(t.composedPath){let e=t.composedPath();o(e[0]);for(let t=0;t<e.length-2&&(n=e[t],s());t++){if(n._$host){n=n._$host,c();break}if(n.parentNode===a)break}}else c();o(i)}finally{t=n=null}}function G(e,t,n,r,i){let a=be(e);if(a){!n&&(n=[...e.childNodes]);let t=[];for(let e=0;e<n.length;e++){let r=n[e];r.nodeType===8&&r.data.slice(0,2)===`!$`?r.remove():t.push(r)}n=t}for(;typeof n==`function`;)n=n();if(t===n)return n;let o=typeof t,s=r!==void 0;if(e=s&&n[0]&&n[0].parentNode||e,o===`string`||o===`number`){if(a||o===`number`&&(t=t.toString(),t===n))return n;if(s){let i=n[0];i&&i.nodeType===3?i.data!==t&&(i.data=t):i=document.createTextNode(t),n=q(e,n,r,i)}else n=n!==``&&typeof n==`string`?e.firstChild.data=t:e.textContent=t}else if(t==null||o===`boolean`){if(a)return n;n=q(e,n,r)}else if(o===`function`)return b(()=>{let i=t();for(;typeof i==`function`;)i=i();n=G(e,i,n,r)}),()=>n;else if(Array.isArray(t)){let o=[],c=n&&Array.isArray(n);if(K(o,t,n,i))return b(()=>n=G(e,o,n,r,!0)),()=>n;if(a){if(!o.length)return n;if(r===void 0)return n=[...e.childNodes];let t=o[0];if(t.parentNode!==e)return n;let i=[t];for(;(t=t.nextSibling)!==r;)i.push(t);return n=i}if(o.length===0){if(n=q(e,n,r),s)return n}else c?n.length===0?Se(e,o,r):he(e,n,o):(n&&q(e),Se(e,o));n=o}else if(t.nodeType){if(a&&t.parentNode)return n=s?[t]:t;if(Array.isArray(n)){if(s)return n=q(e,n,r,t);q(e,n,null,t)}else n==null||n===``||!e.firstChild?e.appendChild(t):e.replaceChild(t,e.firstChild);n=t}return n}function K(e,t,n,r){let i=!1;for(let a=0,o=t.length;a<o;a++){let o=t[a],s=n&&n[e.length],c;if(o!=null&&o!==!0&&o!==!1){if((c=typeof o)==`object`&&o.nodeType)e.push(o);else if(Array.isArray(o))i=K(e,o,s)||i;else if(c===`function`){if(r){for(;typeof o==`function`;)o=o();i=K(e,Array.isArray(o)?o:[o],Array.isArray(s)?s:[s])||i}else e.push(o),i=!0}else{let t=String(o);s&&s.nodeType===3&&s.data===t?e.push(s):e.push(document.createTextNode(t))}}}return i}function Se(e,t,n=null){for(let r=0,i=t.length;r<i;r++)e.insertBefore(t[r],n)}function q(e,t,n,r){if(n===void 0)return e.textContent=``;let i=r||document.createTextNode(``);if(t.length){let r=!1;for(let a=t.length-1;a>=0;a--){let o=t[a];if(i!==o){let t=o.parentNode===e;!r&&!a?t?e.replaceChild(i,o):e.insertBefore(i,n):t&&o.remove()}else r=!0}}else e.insertBefore(i,n);return[i]}async function J(e){let t=await fetch(e,{headers:{accept:`application/json`}});if(!t.ok){let e=await t.text().catch(()=>``);throw Error(`HTTP ${t.status}${e?`: ${e.slice(0,200)}`:``}`)}return await t.json()}function Ce(){return J(`/api/projects`)}function we(e){return J(`/api/projects/${encodeURIComponent(e)}/files`)}function Te(e,t){return`/render/${encodeURIComponent(e)}/${t.split(`/`).map(encodeURIComponent).join(`/`)}?embed=1`}function Ee(e,t){return`/events?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`}function De(){return`/events`}function Oe(e){return J(`/api/marks?project=${encodeURIComponent(e)}`)}async function ke(e){let t=await fetch(`/api/marks`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e)});if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.json();if(!n.ok)throw Error(n.error??`添加标记失败`);return n.mark}async function Ae(e){let t=await fetch(`/api/marks?project=${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok)throw Error(`HTTP ${t.status}`);return(await t.json()).cleared}function je(e,t){return J(`/api/changes?project=${encodeURIComponent(e)}&path=${encodeURIComponent(t)}`)}var Y=.1,X=.02;function Me(e,t){return t===0||Math.abs(e)>=Math.abs(t)?null:t>0?-1:1}function Z(e,t=Y){return Math.min(4,Math.max(t,e))}function Ne(e,t,n,r,i=Y){let a=Z(e.z*t,i);if(a===e.z)return e;let o=a/e.z;return{z:a,tx:n-(n-e.tx)*o,ty:r-(r-e.ty)*o}}function Pe(e,t,n,r=Y){return Ne(e,Z(t,r)/e.z,n.width/2,n.height/2,r)}function Q(e,t,n=24){let r=Math.max(1,e.w),i=Math.max(1,e.h),a=Math.max(1,t.width-n*2),o=Math.max(1,t.height-n*2),s=Z(Math.min(a/r,o/i),X);return{z:s,tx:(t.width-r*s)/2-e.x*s,ty:(t.height-i*s)/2-e.y*s}}function Fe(e,t,n){return{z:e.z,tx:e.tx+t,ty:e.ty+n}}function Ie(e){return`translate(${e.tx}px, ${e.ty}px) scale(${e.z})`}function Le(e){if(e===null||e===``)return null;let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=`object`||!t)return null;let{z:n,tx:r,ty:i}=t;return typeof n!=`number`||typeof r!=`number`||typeof i!=`number`||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(i)||n<=0?null:{z:Z(n,X),tx:r,ty:i}}var Re=3,ze=.0015;function Be({doc:e,onChange:t,onLevelStep:n}){let r=e.querySelector(`.ptr-canvas`);if(r===null)return null;let i=r;i.style.transformOrigin=`0 0`;let a={z:1,tx:0,ty:0},o=!1,s=!1,c=!1,l=null,u=()=>({width:e.documentElement.clientWidth||1,height:e.documentElement.clientHeight||1});function d(){i.style.transform=Ie(a),t?.(a)}function f(e){a=e,d()}function p(){i.style.transition=``}function m(e){i.style.transition=`transform 180ms ease-out`,f(e),setTimeout(p,220)}function h(t){e.documentElement.style.cursor=t}function g(e){if(e.preventDefault(),e.altKey&&n!==void 0){let t=Me(e.deltaX,e.deltaY);t!==null&&n(t,{x:e.clientX,y:e.clientY});return}p();let t=1;e.deltaMode===1?t=16:e.deltaMode===2&&(t=u().height);let r=a.z<.1?X:Y;f(Ne(a,Math.exp(-e.deltaY*t*ze),e.clientX,e.clientY,r))}function _(t){return t.button===1?!0:t.button===0?o?!0:t.target===i||t.target===e.body||t.target===e.documentElement:!1}function v(e){_(e)&&(e.preventDefault(),l={lastX:e.clientX,lastY:e.clientY,startX:e.clientX,startY:e.clientY},s=!1)}function y(t){if(!l)return;if(!s){if(Math.hypot(t.clientX-l.startX,t.clientY-l.startY)<Re)return;s=!0,p(),e.body.style.userSelect=`none`,h(`grabbing`)}let n=t.clientX-l.lastX,r=t.clientY-l.lastY;l.lastX=t.clientX,l.lastY=t.clientY,f(Fe(a,n,r))}function b(){l&&(l=null,s&&(s=!1,c=!0,e.body.style.userSelect=``,h(o?`grab`:``)))}function x(e){o!==e&&(o=e,s||h(e?`grab`:``))}function S(e){if(e.key===` `&&!e.metaKey&&!e.ctrlKey&&!e.altKey){let t=e.target,n=t?.tagName??``;if(n===`INPUT`||n===`TEXTAREA`||t?.isContentEditable===!0)return;x(!0),e.preventDefault()}else T(e)&&e.preventDefault()}function C(e){e.key===` `&&x(!1)}function w(){x(!1),b()}function T(e){return(e.ctrlKey||e.metaKey)&&(e.key===`0`||e.key===`)`||e.code===`Digit0`||e.code===`Numpad0`)?(f(Pe(a,1,u())),!0):e.shiftKey&&!e.ctrlKey&&!e.metaKey&&(e.key===`!`||e.code===`Digit1`)?(E(),!0):!1}function E(){f(Q({x:0,y:0,w:i.offsetWidth,h:i.offsetHeight},u()))}function ee(e){let t=u();m({z:a.z,tx:t.width/2-(e.x+e.w/2)*a.z,ty:t.height/2-(e.y+e.h/2)*a.z})}return e.addEventListener(`wheel`,g,{passive:!1}),e.addEventListener(`mousedown`,v,!0),e.addEventListener(`mousemove`,y,!0),e.addEventListener(`mouseup`,b,!0),e.addEventListener(`keydown`,S),e.addEventListener(`keyup`,C),e.defaultView?.addEventListener(`blur`,w),{get:()=>a,set:f,fitAll:E,centerOn:ee,focusBox:e=>m(Q(e,u())),zoomToPercent:e=>f(Pe(a,e,u())),consumeDragClick:()=>{let e=c;return c=!1,e},handleKey:T,setSpace:x,destroy:()=>{e.removeEventListener(`wheel`,g),e.removeEventListener(`mousedown`,v,!0),e.removeEventListener(`mousemove`,y,!0),e.removeEventListener(`mouseup`,b,!0),e.removeEventListener(`keydown`,S),e.removeEventListener(`keyup`,C),e.defaultView?.removeEventListener(`blur`,w)}}}function Ve(e){let{clientX:t,rectLeft:n,rectWidth:r,pad:i,thumb:a,count:o}=e,s=r-i*2-a;if(s<=0||o<2)return null;let c=(t-n-i-a/2)/s;return Math.max(0,Math.min(o-1,c*(o-1)))}var He=H(`<div class=canvas-bg><span class=canvas-bg-label></span><div class=canvas-bg-track role=slider tabindex=0 aria-valuemin=0 style=--pad:3px;--thumb:20px><div class=canvas-bg-thumb aria-hidden=true><span class=canvas-bg-dot>`),$=[`light`,`gray`,`dark`],Ue={light:`Light`,gray:`Gray`,dark:`Dark`},We={light:`#ffffff`,gray:`#d2cec7`,dark:`#242b36`},Ge=`paintress:canvas-bg`;function Ke(e){return $.includes(e)}function qe(){try{let e=localStorage.getItem(Ge);if(Ke(e))return e}catch{}return`light`}function Je(e){try{localStorage.setItem(Ge,e)}catch{}}var Ye=3,Xe=20;function Ze(e){let[t,n]=y(!1),[r,i]=y(null),[a,o]=y(29),s,c=()=>$.indexOf(e.value),l=()=>r()??c();T(()=>{let e=()=>{let e=s;if(!e)return;let t=e.getBoundingClientRect().width-6-Xe;o(t/($.length-1))};if(e(),typeof ResizeObserver>`u`||!s)return;let t=new ResizeObserver(e);t.observe(s),E(()=>t.disconnect())});function u(e){let t=s;if(!t)return c();let n=t.getBoundingClientRect();return Ve({clientX:e.clientX,rectLeft:n.left,rectWidth:n.width,pad:Ye,thumb:Xe,count:$.length})??c()}function d(t){let n=$[Math.round(t)];n!==void 0&&n!==e.value&&e.onChange(n)}function f(e){e.button===0&&(e.preventDefault(),e.currentTarget.setPointerCapture(e.pointerId),n(!0),i(u(e)))}function p(e){t()&&i(u(e))}function m(e){if(!t())return;let r=e.currentTarget;n(!1),i(null),d(u(e)),r.hasPointerCapture(e.pointerId)&&r.releasePointerCapture(e.pointerId)}function h(){n(!1),i(null)}function g(t){let n=t.key===`ArrowRight`||t.key===`ArrowUp`?1:t.key===`ArrowLeft`||t.key===`ArrowDown`?-1:0;if(n===0)return;t.preventDefault();let r=$[Math.max(0,Math.min($.length-1,c()+n))];r!==void 0&&e.onChange(r)}return(()=>{var n=He(),r=n.firstChild,i=r.nextSibling,o=i.firstChild.firstChild;W(r,()=>Ue[e.value]),i.$$keydown=g,i.addEventListener(`lostpointercapture`,h),i.addEventListener(`pointercancel`,h),i.$$pointerup=m,i.$$pointermove=p,i.$$pointerdown=f;var u=s;return typeof u==`function`?ye(u,i):s=i,b(n=>{var r=!!t(),s=e.label,u=$.length-1,d=c(),f=Ue[e.value],p=e.label,m=`${a()}px`,h=String(l()),g=We[e.value];return r!==n.e&&i.classList.toggle(`dragging`,n.e=r),s!==n.t&&U(i,`aria-label`,n.t=s),u!==n.a&&U(i,`aria-valuemax`,n.a=u),d!==n.o&&U(i,`aria-valuenow`,n.o=d),f!==n.i&&U(i,`aria-valuetext`,n.i=f),p!==n.n&&U(i,`title`,n.n=p),m!==n.s&&ve(i,`--step`,n.s=m),h!==n.h&&ve(i,`--pos`,n.h=h),g!==n.r&&ve(o,`--dot`,n.r=g),n},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0,s:void 0,h:void 0,r:void 0}),n})()}_e([`pointerdown`,`pointermove`,`pointerup`,`keydown`]);var Qe={zh:{projects:`项目`,noProjects:`还没有注册项目`,projectFiles:e=>`${e} 个设计稿`,designs:`设计稿`,depth:`depth`,noFiles:`没有 .ptr / .pen 文件`,marks:`标记`,clear:`清空`,liveReload:`实时刷新`,refreshList:`刷新列表`,pickProject:`从左侧选择项目`,pickFile:`从左侧选择一个设计稿`,fit:`适应`,fitTitle:`适应窗口(Shift+1)`,actualSize:`1:1`,actualSizeTitle:`100%(Ctrl/Cmd+0)`,rerender:`重新渲染`,allBoards:`全部`,canvasBackground:`画布背景`,language:`界面语言`},en:{projects:`Projects`,noProjects:`No projects registered yet`,projectFiles:e=>`${e} design${e===1?``:`s`}`,designs:`Designs`,depth:`depth`,noFiles:`No .ptr / .pen files`,marks:`Marks`,clear:`Clear`,liveReload:`Live reload`,refreshList:`Refresh`,pickProject:`Pick a project on the left`,pickFile:`Pick a design on the left`,fit:`Fit`,fitTitle:`Fit to window (Shift+1)`,actualSize:`1:1`,actualSizeTitle:`100% (Ctrl/Cmd+0)`,rerender:`Re-render`,allBoards:`All`,canvasBackground:`Canvas background`,language:`Language`}};function $e(e){return Qe[e]}function et(e){return(e?.languages?.[0]??e?.language??``).toLowerCase().startsWith(`zh`)?`zh`:`en`}var tt=`paintress:lang`;function nt(e){return e===`zh`||e===`en`}function rt(){try{let e=localStorage.getItem(tt);if(nt(e))return e}catch{}return et(typeof navigator>`u`?void 0:navigator)}function it(e){try{localStorage.setItem(tt,e)}catch{}}var at=H(`<span class=badge>v`),ot=H(`<ul class=list>`),st=H(`<section class="section files"><h2> <span class=hint> `),ct=H(`<section class="section marks"><h2><button class="ghost tiny"></button></h2><ul class=list>`),lt=H(`<span class=hint>pid `),ut=H(`<div class=error>`),dt=H(`<code>/`),ft=H(`<span class="hint zoom">%`),pt=H(`<button class="ghost tiny">`),mt=H(`<button class=ghost>`),ht=H(`<span class=tool-sep>`),gt=H(`<div class=boardbar><button class=board>`),_t=H(`<iframe class=preview title="design preview"sandbox="allow-same-origin allow-scripts">`),vt=H(`<div class=app><aside class=sidebar><header class=sidebar-head><img class=brand-mark src=/logo.svg alt><h1>paintress</h1></header><section class=section><h2></h2></section><footer class=sidebar-foot><label class=toggle><input type=checkbox></label><button class=ghost></button></footer></aside><main class=stage><div class=toolbar><div class=crumbs></div><div class=tools><div class=lang-switch role=group><button class=lang-opt>中</button><button class=lang-opt>EN`),yt=H(`<p class=empty><br><code>paintress watch <name> <dir>`),bt=H(`<li><button class=item><span class=item-name></span><span class=item-meta>`),xt=H(`<p class=empty>`),St=H(`<li><button class=item><span class=item-name>`),Ct=H(`<li><button class=item><span class=item-name><b class=mark-no>#</b> </span><span class=item-meta>`),wt=H(`<span class=sep>/`),Tt=H(`<button class=crumb>`),Et=H(`<p>`),Dt=H(`<div class=placeholder>`),Ot=H(`<button class=board><span class=board-size>×`);function kt(e){return typeof CSS<`u`&&typeof CSS.escape==`function`?CSS.escape(e):e.replace(/["\\]/g,`\\$&`)}function At(){let[e,t]=y([]),[n,r]=y(null),[i,a]=y([]),[o,s]=y(null),[c,l]=y([]),[u,d]=y(null),[f,p]=y([]),[m,h]=y(null),[g,_]=y({}),[v,S]=y(0),[C,ee]=y(!0),[te,D]=y(``),[O,ne]=y([]),[re,k]=y(null),[ie,ae]=y(1),[A,j]=y(rt()),[M,oe]=y(qe()),N=()=>$e(A()),P,F,I=null,se;function ce(){let e=new URLSearchParams,t=n(),r=o();t&&e.set(`project`,t),r&&e.set(`file`,r);let i=e.toString();history.replaceState(null,``,i?`?${i}`:location.pathname)}async function le(){try{let e=await Ce();t(e.projects),_({pid:e.pid,version:e.version}),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}async function ue(e){try{l((await Oe(e)).marks)}catch{l([])}}async function de(e){r(e),s(null),d(null),p([]);try{let t=await we(e);a(t.files),h(null)}catch(e){a([]),h(e instanceof Error?e.message:String(e))}ue(e),ce()}async function fe(){await le();let t=n();if(t!==null){if(!e().some(e=>e.name===t))r(null),s(null),a([]),d(null),p([]),ce();else{try{let n=await we(t),r=i();a(n.files);let c=o();if(c===null){let i=n.files.filter(e=>!r.includes(e));i.length>0&&e().some(e=>e.name===t)&&pe(i[0])}else n.files.includes(c)||(s(null),d(null),p([]),ce())}catch{}ue(t)}}}function pe(e){s(e),d(null),p([]),ce()}T(()=>{let e=new EventSource(De());e.addEventListener(`projects`,()=>void fe()),E(()=>e.close());let t=e=>{let t=e.target;return t?.tagName===`INPUT`||t?.tagName===`TEXTAREA`||t?.isContentEditable===!0},n=e=>{t(e)||(e.key===` `&&!e.ctrlKey&&!e.metaKey&&!e.altKey?(I?.setSpace(!0),e.preventDefault()):I?.handleKey(e)===!0&&e.preventDefault())},r=e=>{e.key===` `&&I?.setSpace(!1)};window.addEventListener(`keydown`,n),window.addEventListener(`keyup`,r),E(()=>{window.removeEventListener(`keydown`,n),window.removeEventListener(`keyup`,r)});let i=new URLSearchParams(location.search);(async()=>{await le();let e=i.get(`project`);if(e){await de(e);let t=i.get(`file`);t&&pe(t)}})()});let R=()=>P?.contentDocument??null;function he(){let e=R();if(!e||e.getElementById(`ptr-style`))return;let t=e.createElement(`style`);t.id=`ptr-style`,t.textContent=`[data-ptr-selected]{outline:2px solid #908030 !important;outline-offset:-2px;}
|
|
2
|
-
[data-ptr-hover]:not([data-ptr-selected]){outline:1px dashed rgba(144,128,48,.55) !important;outline-offset:-2px;}
|
|
3
|
-
[data-ptr-changed]{box-shadow:inset 0 0 0 2px #908030 !important;animation:ptr-pulse 1.4s ease-in-out 3;}
|
|
4
|
-
@keyframes ptr-pulse{0%,100%{box-shadow:inset 0 0 0 2px #908030}50%{box-shadow:inset 0 0 0 2px rgba(144,128,48,.35)}}
|
|
5
|
-
html{cursor:default;}
|
|
6
|
-
html,body{overflow:hidden;}
|
|
7
|
-
html,body{background:var(--ptr-canvas-bg,#ffffff);}`,e.head.appendChild(t)}function V(){let e=R();if(!e)return;for(let t of e.querySelectorAll(`[data-ptr-selected]`))t.removeAttribute(`data-ptr-selected`);let t=u();t&&e.querySelector(`[data-node-id="${kt(t)}"]`)?.setAttribute(`data-ptr-selected`,``)}function ge(e){return e.parentElement?.closest(`[data-node-id]`)??null}function H(e){return e.querySelector(`:scope > [data-node-id]`)}function _e(e){if(I?.consumeDragClick()===!0){e.preventDefault(),e.stopPropagation();return}let t=e.target?.closest(`[data-node-id]`);t&&(e.preventDefault(),e.stopPropagation(),Me(e.altKey?ge(t)??t:t))}function ve(e,t){let n=R();if(!n)return;let r=u(),i=r===null?null:n.querySelector(`[data-node-id="${kt(r)}"]`);if(i===null){let e=(n.elementFromPoint(t.x,t.y)?.closest(`[data-node-id]`))?.dataset.nodeId;e!==void 0&&Z(e);return}let a=(e===1?ge(i):H(i))?.dataset.nodeId;a!==void 0&&Z(a)}function be(e){let t=R();if(t){for(let e of t.querySelectorAll(`[data-ptr-hover]`))e.removeAttribute(`data-ptr-hover`);(e.target?.closest(`[data-node-id]`))?.setAttribute(`data-ptr-hover`,``)}}async function xe(){let e=n(),t=o();if(e&&t)try{let n=await je(e,t);if(!n.ok||n.ids.length===0)return;let r=R();if(!r)return;for(let e of n.ids)r.querySelector(`[data-node-id="${kt(e)}"]`)?.setAttribute(`data-ptr-changed`,``)}catch{}}function G(){let e=R();return e?Array.from(e.querySelectorAll(`[data-board]`)).map(e=>{let t=e.dataset;return{id:t.nodeId??``,...t.boardName===void 0?{}:{name:t.boardName},x:Number(t.boardX??0),y:Number(t.boardY??0),w:Number(t.boardW??0),h:Number(t.boardH??0)}}):[]}function K(){let e=n(),t=o();return e&&t?`paintress:viewport:${e}/${t}`:null}function Se(e){let t=K();t!==null&&(clearTimeout(se),se=setTimeout(()=>{try{localStorage.setItem(t,JSON.stringify(e))}catch{}},300))}function q(){let e=R();e&&(he(),Pe(),I?.destroy(),I=Be({doc:e,onChange:e=>{ae(e.z),Se(e)},onLevelStep:ve}),ne(G()),k(null),J(),e.addEventListener(`click`,_e,!0),e.addEventListener(`mousemove`,be,!0),V(),xe())}function J(){if(!I)return;let e=K(),t=e===null?null:localStorage.getItem(e),n=t===null?null:Le(t);n===null?I.fitAll():I.set(n)}function Y(e){if(k(e),!I)return;if(e===null){I.fitAll();return}let t=O().find(t=>t.id===e);t&&I.focusBox({x:t.x,y:t.y,w:t.w,h:t.h})}function X(e){let t=[],n=e;for(;n;){let e=n.closest(`[data-node-id]`);if(!e)break;let r=e;t.unshift({id:r.dataset.nodeId??``,type:r.dataset.nodeType??`?`,name:r.dataset.nodeName}),n=e.parentElement}return t}async function Me(e){let t=e.dataset.nodeId??``;if(t===``)return;let r=X(e);d(t),p(r),V();let i=n();if(i)try{await ke({project:i,nodeId:t,...e.dataset.nodeName===void 0?{}:{name:e.dataset.nodeName},...e.dataset.nodeType===void 0?{}:{type:e.dataset.nodeType},path:r.map(e=>e.name??e.type).join(` / `)}),l((await Oe(i)).marks),h(null)}catch(e){h(e instanceof Error?e.message:String(e))}}function Z(e){d(e),V();let t=R(),n=t?.querySelector(`[data-node-id="${kt(e)}"]`);if(!n||!t){p([]);return}p(X(n));let r=t.querySelector(`.ptr-canvas`);if(!r||!I){n.scrollIntoView({block:`center`});return}let i=n.getBoundingClientRect(),a=r.getBoundingClientRect(),o=I.get().z;I.centerOn({x:(i.left-a.left)/o,y:(i.top-a.top)/o,w:i.width/o,h:i.height/o})}async function Ne(){let e=n();if(e)try{await Ae(e),l([]),d(null),p([]),V()}catch(e){h(e instanceof Error?e.message:String(e))}}x(()=>{let e=A();document.documentElement.lang=e===`zh`?`zh-CN`:`en`,it(e)});function Pe(){if(F!==void 0){if(o()===null)F.style.removeProperty(`--canvas-bg`),F.removeAttribute(`data-canvas-bg`);else{let e=We[M()];F.style.setProperty(`--canvas-bg`,e),F.setAttribute(`data-canvas-bg`,M())}R()?.documentElement.style.setProperty(`--ptr-canvas-bg`,We[M()])}}x(()=>{M(),Je(M()),Pe()}),x(w([n,o,v],()=>{let e=n(),t=o();D(e&&t?`${Te(e,t)}&r=${v()}`:``),Pe()}));let Q=null;return x(w([n,o,C],()=>{Q?.close(),Q=null;let e=n(),t=o();C()&&e&&t&&(Q=new EventSource(Ee(e,t)),Q.addEventListener(`change`,()=>S(e=>e+1)))})),E(()=>Q?.close()),(()=>{var t=vt(),r=t.firstChild,a=r.firstChild;a.firstChild.nextSibling;var s=a.nextSibling,l=s.firstChild,d=s.nextSibling,p=d.firstChild,h=p.firstChild,_=p.nextSibling,v=r.nextSibling,y=v.firstChild,x=y.firstChild,w=x.nextSibling,T=w.firstChild,E=T.firstChild,D=E.nextSibling;return W(a,L(B,{get when(){return g().version},get children(){var e=at();return e.firstChild,W(e,()=>g().version,null),e}}),null),W(l,()=>N().projects),W(s,L(B,{get when(){return e().length>0},get fallback(){return(()=>{var e=yt(),t=e.firstChild;return W(e,()=>N().noProjects,t),e})()},get children(){var t=ot();return W(t,L(z,{get each(){return e()},children:e=>(()=>{var t=bt(),r=t.firstChild,i=r.firstChild,a=i.nextSibling;return r.$$click=()=>void de(e.name),W(i,()=>e.name),W(a,()=>N().projectFiles(e.fileCount)),b(()=>r.classList.toggle(`active`,n()===e.name)),t})()})),t}}),null),W(r,L(B,{get when(){return n()},get children(){var t=st(),r=t.firstChild,a=r.firstChild,s=a.nextSibling,c=s.firstChild;return W(r,()=>N().designs,a),W(s,()=>N().depth,c),W(s,()=>e().find(e=>e.name===n())?.depth??`-`,null),W(t,L(B,{get when(){return i().length>0},get fallback(){return(()=>{var e=xt();return W(e,()=>N().noFiles),e})()},get children(){var e=ot();return W(e,L(z,{get each(){return i()},children:e=>(()=>{var t=St(),n=t.firstChild,r=n.firstChild;return n.$$click=()=>pe(e),W(r,e),b(()=>n.classList.toggle(`active`,o()===e)),t})()})),e}}),null),t}}),d),W(r,L(B,{get when(){return c().length>0},get children(){var e=ct(),t=e.firstChild,n=t.firstChild,r=t.nextSibling;return W(t,()=>N().marks,n),n.$$click=()=>void Ne(),W(n,()=>N().clear),W(r,L(z,{get each(){return c()},children:e=>(()=>{var t=Ct(),n=t.firstChild,r=n.firstChild,i=r.firstChild;i.firstChild,i.nextSibling;var a=r.nextSibling;return n.$$click=()=>Z(e.nodeId),W(i,()=>e.shortId,null),W(r,()=>e.name??e.nodeId,null),W(a,()=>e.path),b(()=>n.classList.toggle(`active`,u()===e.nodeId)),t})()})),e}}),d),h.addEventListener(`change`,e=>ee(e.currentTarget.checked)),W(p,()=>N().liveReload,null),_.$$click=()=>void le(),W(_,()=>N().refreshList),W(d,L(B,{get when(){return g().pid},get children(){var e=lt();return e.firstChild,W(e,()=>g().pid,null),e}}),null),ye(e=>{F=e},v),W(v,L(B,{get when(){return m()},get children(){var e=ut();return W(e,m),e}}),y),W(x,L(B,{get when(){return f().length===0},get fallback(){return L(z,{get each(){return f()},children:(e,t)=>[L(B,{get when(){return t()>0},get children(){return wt()}}),(()=>{var t=Tt();return t.$$click=()=>Z(e.id),W(t,()=>e.name??e.type),b(()=>t.classList.toggle(`active`,u()===e.id)),t})()]})},get children(){return L(B,{get when(){return me(()=>n()!==null)()&&o()!==null},get children(){var e=dt(),t=e.firstChild;return W(e,n,t),W(e,o,null),e}})}})),W(w,L(B,{get when(){return me(()=>n()!==null)()&&o()!==null},get children(){return[(()=>{var e=ft(),t=e.firstChild;return W(e,()=>Math.round(ie()*100),t),e})(),(()=>{var e=pt();return e.$$click=()=>I?.fitAll(),W(e,()=>N().fit),b(()=>U(e,`title`,N().fitTitle)),e})(),(()=>{var e=pt();return e.$$click=()=>I?.zoomToPercent(1),W(e,()=>N().actualSize),b(()=>U(e,`title`,N().actualSizeTitle)),e})(),(()=>{var e=mt();return e.$$click=()=>S(e=>e+1),W(e,()=>N().rerender),e})(),ht()]}}),T),W(w,L(Ze,{get value(){return M()},onChange:oe,get label(){return N().canvasBackground}}),T),E.$$click=()=>j(`zh`),D.$$click=()=>j(`en`),W(v,L(B,{get when(){return me(()=>n()!==null)()&&o()!==null},get fallback(){return(()=>{var e=Dt();return W(e,L(B,{get when(){return n()},get fallback(){return(()=>{var e=Et();return W(e,()=>N().pickProject),e})()},get children(){var e=Et();return W(e,()=>N().pickFile),e}})),e})()},get children(){return[L(B,{get when(){return O().length>1},get children(){var e=gt(),t=e.firstChild;return t.$$click=()=>Y(null),W(t,()=>N().allBoards),W(e,L(z,{get each(){return O()},children:e=>(()=>{var t=Ot(),n=t.firstChild,r=n.firstChild;return t.$$click=()=>Y(e.id),W(t,()=>e.name??`#${e.id}`,n),W(n,()=>Math.round(e.w),r),W(n,()=>Math.round(e.h),null),b(()=>t.classList.toggle(`active`,re()===e.id)),t})()}),null),b(()=>t.classList.toggle(`active`,re()===null)),e}}),(()=>{var e=_t();return e.addEventListener(`load`,q),ye(e=>{P=e},e),b(()=>U(e,`src`,te())),e})()]}}),null),b(e=>{var t=N().language,n=N().language,r=A()===`zh`,i=A()===`zh`,a=A()===`en`,o=A()===`en`;return t!==e.e&&U(T,`aria-label`,e.e=t),n!==e.t&&U(T,`title`,e.t=n),r!==e.a&&E.classList.toggle(`active`,e.a=r),i!==e.o&&U(E,`aria-pressed`,e.o=i),a!==e.i&&D.classList.toggle(`active`,e.i=a),o!==e.n&&U(D,`aria-pressed`,e.n=o),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0}),b(()=>h.checked=C()),t})()}_e([`click`]);var jt=document.getElementById(`root`);if(!jt)throw Error(`缺少 #root 容器`);ge(()=>L(At,{}),jt);
|