getobsrv 0.7.2 → 0.9.0
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 +43 -2
- package/bin/install-skill.js +113 -0
- package/bin/obsrv.js +8 -0
- package/out/cli/args.js +2 -0
- package/out/main/cli.js +2 -0
- package/out/main/index.js +35 -6
- package/out/mcp/server.js +11 -1
- package/out/preload/app.js +10 -0
- package/out/renderer/assets/{index-BeroS4wv.css → index-CasW01OP.css} +208 -80
- package/out/renderer/assets/{index-Cgx8iixu.js → index-CpeTWcl6.js} +529 -145
- package/out/renderer/index.html +2 -2
- package/out/shared/control.js +12 -1
- package/out/shared/ipcPayloads.js +7 -0
- package/package.json +2 -1
|
@@ -12783,6 +12783,7 @@ const useStore = create()((set) => ({
|
|
|
12783
12783
|
image: null,
|
|
12784
12784
|
surround: "graphite",
|
|
12785
12785
|
viewMode: "1:1",
|
|
12786
|
+
panes: "both",
|
|
12786
12787
|
fitScale: null,
|
|
12787
12788
|
agentPan: null,
|
|
12788
12789
|
agentHighlight: null,
|
|
@@ -12810,6 +12811,9 @@ const useStore = create()((set) => ({
|
|
|
12810
12811
|
setImage: (image) => set({ image }),
|
|
12811
12812
|
setSurround: (surround) => set({ surround }),
|
|
12812
12813
|
setViewMode: (viewMode) => set({ viewMode }),
|
|
12814
|
+
// No `agentHighlight: null` here, unlike setPreset: hiding a pane does not
|
|
12815
|
+
// re-raster the target, so the highlight still marks the pixels it marked.
|
|
12816
|
+
setPanes: (panes) => set({ panes }),
|
|
12813
12817
|
setFitScale: (fitScale2) => set({ fitScale: fitScale2 }),
|
|
12814
12818
|
requestAgentPan: (p) => set((s) => ({ agentPan: { ...p, seq: (s.agentPan?.seq ?? 0) + 1 } })),
|
|
12815
12819
|
clearAgentPan: () => set({ agentPan: null }),
|
|
@@ -14271,6 +14275,321 @@ function Toast() {
|
|
|
14271
14275
|
if (!toast) return null;
|
|
14272
14276
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "toast", role: "status", children: toast });
|
|
14273
14277
|
}
|
|
14278
|
+
/**
|
|
14279
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14280
|
+
*
|
|
14281
|
+
* This source code is licensed under the ISC license.
|
|
14282
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14283
|
+
*/
|
|
14284
|
+
const mergeClasses = (...classes) => classes.filter((className, index, array) => {
|
|
14285
|
+
return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
|
|
14286
|
+
}).join(" ").trim();
|
|
14287
|
+
/**
|
|
14288
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14289
|
+
*
|
|
14290
|
+
* This source code is licensed under the ISC license.
|
|
14291
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14292
|
+
*/
|
|
14293
|
+
const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
14294
|
+
/**
|
|
14295
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14296
|
+
*
|
|
14297
|
+
* This source code is licensed under the ISC license.
|
|
14298
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14299
|
+
*/
|
|
14300
|
+
const toCamelCase = (string) => string.replace(
|
|
14301
|
+
/^([A-Z])|[\s-_]+(\w)/g,
|
|
14302
|
+
(match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
|
|
14303
|
+
);
|
|
14304
|
+
/**
|
|
14305
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14306
|
+
*
|
|
14307
|
+
* This source code is licensed under the ISC license.
|
|
14308
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14309
|
+
*/
|
|
14310
|
+
const toPascalCase = (string) => {
|
|
14311
|
+
const camelCase = toCamelCase(string);
|
|
14312
|
+
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
|
14313
|
+
};
|
|
14314
|
+
/**
|
|
14315
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14316
|
+
*
|
|
14317
|
+
* This source code is licensed under the ISC license.
|
|
14318
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14319
|
+
*/
|
|
14320
|
+
var defaultAttributes = {
|
|
14321
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14322
|
+
width: 24,
|
|
14323
|
+
height: 24,
|
|
14324
|
+
viewBox: "0 0 24 24",
|
|
14325
|
+
fill: "none",
|
|
14326
|
+
stroke: "currentColor",
|
|
14327
|
+
strokeWidth: 2,
|
|
14328
|
+
strokeLinecap: "round",
|
|
14329
|
+
strokeLinejoin: "round"
|
|
14330
|
+
};
|
|
14331
|
+
/**
|
|
14332
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14333
|
+
*
|
|
14334
|
+
* This source code is licensed under the ISC license.
|
|
14335
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14336
|
+
*/
|
|
14337
|
+
const hasA11yProp = (props) => {
|
|
14338
|
+
for (const prop in props) {
|
|
14339
|
+
if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
|
|
14340
|
+
return true;
|
|
14341
|
+
}
|
|
14342
|
+
}
|
|
14343
|
+
return false;
|
|
14344
|
+
};
|
|
14345
|
+
const LucideContext = reactExports.createContext({});
|
|
14346
|
+
const useLucideContext = () => reactExports.useContext(LucideContext);
|
|
14347
|
+
const Icon$1 = reactExports.forwardRef(
|
|
14348
|
+
({ color, size, strokeWidth, absoluteStrokeWidth, className = "", children, iconNode, ...rest }, ref) => {
|
|
14349
|
+
const {
|
|
14350
|
+
size: contextSize = 24,
|
|
14351
|
+
strokeWidth: contextStrokeWidth = 2,
|
|
14352
|
+
absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,
|
|
14353
|
+
color: contextColor = "currentColor",
|
|
14354
|
+
className: contextClass = ""
|
|
14355
|
+
} = useLucideContext() ?? {};
|
|
14356
|
+
const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;
|
|
14357
|
+
return reactExports.createElement(
|
|
14358
|
+
"svg",
|
|
14359
|
+
{
|
|
14360
|
+
ref,
|
|
14361
|
+
...defaultAttributes,
|
|
14362
|
+
width: size ?? contextSize ?? defaultAttributes.width,
|
|
14363
|
+
height: size ?? contextSize ?? defaultAttributes.height,
|
|
14364
|
+
stroke: color ?? contextColor,
|
|
14365
|
+
strokeWidth: calculatedStrokeWidth,
|
|
14366
|
+
className: mergeClasses("lucide", contextClass, className),
|
|
14367
|
+
...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
|
|
14368
|
+
...rest
|
|
14369
|
+
},
|
|
14370
|
+
[
|
|
14371
|
+
...iconNode.map(([tag, attrs]) => reactExports.createElement(tag, attrs)),
|
|
14372
|
+
...Array.isArray(children) ? children : [children]
|
|
14373
|
+
]
|
|
14374
|
+
);
|
|
14375
|
+
}
|
|
14376
|
+
);
|
|
14377
|
+
/**
|
|
14378
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14379
|
+
*
|
|
14380
|
+
* This source code is licensed under the ISC license.
|
|
14381
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14382
|
+
*/
|
|
14383
|
+
const createLucideIcon = (iconName, iconNode) => {
|
|
14384
|
+
const Component = reactExports.forwardRef(
|
|
14385
|
+
({ className, ...props }, ref) => reactExports.createElement(Icon$1, {
|
|
14386
|
+
ref,
|
|
14387
|
+
iconNode,
|
|
14388
|
+
className: mergeClasses(
|
|
14389
|
+
`lucide-${toKebabCase(toPascalCase(iconName))}`,
|
|
14390
|
+
`lucide-${iconName}`,
|
|
14391
|
+
className
|
|
14392
|
+
),
|
|
14393
|
+
...props
|
|
14394
|
+
})
|
|
14395
|
+
);
|
|
14396
|
+
Component.displayName = toPascalCase(iconName);
|
|
14397
|
+
return Component;
|
|
14398
|
+
};
|
|
14399
|
+
/**
|
|
14400
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14401
|
+
*
|
|
14402
|
+
* This source code is licensed under the ISC license.
|
|
14403
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14404
|
+
*/
|
|
14405
|
+
const __iconNode$7 = [
|
|
14406
|
+
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
14407
|
+
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
14408
|
+
];
|
|
14409
|
+
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$7);
|
|
14410
|
+
/**
|
|
14411
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14412
|
+
*
|
|
14413
|
+
* This source code is licensed under the ISC license.
|
|
14414
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14415
|
+
*/
|
|
14416
|
+
const __iconNode$6 = [
|
|
14417
|
+
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
14418
|
+
["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
|
|
14419
|
+
];
|
|
14420
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$6);
|
|
14421
|
+
/**
|
|
14422
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14423
|
+
*
|
|
14424
|
+
* This source code is licensed under the ISC license.
|
|
14425
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14426
|
+
*/
|
|
14427
|
+
const __iconNode$5 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
14428
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$5);
|
|
14429
|
+
/**
|
|
14430
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14431
|
+
*
|
|
14432
|
+
* This source code is licensed under the ISC license.
|
|
14433
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14434
|
+
*/
|
|
14435
|
+
const __iconNode$4 = [
|
|
14436
|
+
["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
|
|
14437
|
+
["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
|
|
14438
|
+
["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
|
|
14439
|
+
];
|
|
14440
|
+
const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$4);
|
|
14441
|
+
/**
|
|
14442
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14443
|
+
*
|
|
14444
|
+
* This source code is licensed under the ISC license.
|
|
14445
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14446
|
+
*/
|
|
14447
|
+
const __iconNode$3 = [
|
|
14448
|
+
["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
|
|
14449
|
+
["path", { d: "M21 3v5h-5", key: "1q7to0" }]
|
|
14450
|
+
];
|
|
14451
|
+
const RotateCw = createLucideIcon("rotate-cw", __iconNode$3);
|
|
14452
|
+
/**
|
|
14453
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14454
|
+
*
|
|
14455
|
+
* This source code is licensed under the ISC license.
|
|
14456
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14457
|
+
*/
|
|
14458
|
+
const __iconNode$2 = [
|
|
14459
|
+
[
|
|
14460
|
+
"path",
|
|
14461
|
+
{
|
|
14462
|
+
d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",
|
|
14463
|
+
key: "1i5ecw"
|
|
14464
|
+
}
|
|
14465
|
+
],
|
|
14466
|
+
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
14467
|
+
];
|
|
14468
|
+
const Settings = createLucideIcon("settings", __iconNode$2);
|
|
14469
|
+
/**
|
|
14470
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14471
|
+
*
|
|
14472
|
+
* This source code is licensed under the ISC license.
|
|
14473
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14474
|
+
*/
|
|
14475
|
+
const __iconNode$1 = [
|
|
14476
|
+
["path", { d: "M10 5H3", key: "1qgfaw" }],
|
|
14477
|
+
["path", { d: "M12 19H3", key: "yhmn1j" }],
|
|
14478
|
+
["path", { d: "M14 3v4", key: "1sua03" }],
|
|
14479
|
+
["path", { d: "M16 17v4", key: "1q0r14" }],
|
|
14480
|
+
["path", { d: "M21 12h-9", key: "1o4lsq" }],
|
|
14481
|
+
["path", { d: "M21 19h-5", key: "1rlt1p" }],
|
|
14482
|
+
["path", { d: "M21 5h-7", key: "1oszz2" }],
|
|
14483
|
+
["path", { d: "M8 10v4", key: "tgpxqk" }],
|
|
14484
|
+
["path", { d: "M8 12H3", key: "a7s4jb" }]
|
|
14485
|
+
];
|
|
14486
|
+
const SlidersHorizontal = createLucideIcon("sliders-horizontal", __iconNode$1);
|
|
14487
|
+
/**
|
|
14488
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14489
|
+
*
|
|
14490
|
+
* This source code is licensed under the ISC license.
|
|
14491
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14492
|
+
*/
|
|
14493
|
+
const __iconNode = [
|
|
14494
|
+
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
14495
|
+
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
14496
|
+
];
|
|
14497
|
+
const X = createLucideIcon("x", __iconNode);
|
|
14498
|
+
const ICONS = {
|
|
14499
|
+
back: ArrowLeft,
|
|
14500
|
+
forward: ArrowRight,
|
|
14501
|
+
reload: RotateCw,
|
|
14502
|
+
overflow: EllipsisVertical,
|
|
14503
|
+
close: X,
|
|
14504
|
+
sliders: SlidersHorizontal,
|
|
14505
|
+
gear: Settings,
|
|
14506
|
+
chevron: ChevronDown
|
|
14507
|
+
};
|
|
14508
|
+
function Icon({ name, size = 16 }) {
|
|
14509
|
+
const Glyph = ICONS[name];
|
|
14510
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Glyph, { size, strokeWidth: 1.5, "aria-hidden": "true", focusable: "false" });
|
|
14511
|
+
}
|
|
14512
|
+
function OverflowMenu({ children }) {
|
|
14513
|
+
const [open, setOpen] = reactExports.useState(false);
|
|
14514
|
+
const ref = reactExports.useRef(null);
|
|
14515
|
+
const buttonRef = reactExports.useRef(null);
|
|
14516
|
+
const close = () => setOpen(false);
|
|
14517
|
+
reactExports.useEffect(() => {
|
|
14518
|
+
if (!open) return;
|
|
14519
|
+
const onDown = (e) => {
|
|
14520
|
+
if (!ref.current?.contains(e.target)) setOpen(false);
|
|
14521
|
+
};
|
|
14522
|
+
const onKey = (e) => {
|
|
14523
|
+
if (e.key !== "Escape") return;
|
|
14524
|
+
setOpen(false);
|
|
14525
|
+
buttonRef.current?.focus();
|
|
14526
|
+
};
|
|
14527
|
+
const onBlur = () => setOpen(false);
|
|
14528
|
+
document.addEventListener("mousedown", onDown);
|
|
14529
|
+
document.addEventListener("keydown", onKey);
|
|
14530
|
+
window.addEventListener("blur", onBlur);
|
|
14531
|
+
const offNativeFocus = window.obsrv.onNativeFocused(onBlur);
|
|
14532
|
+
return () => {
|
|
14533
|
+
document.removeEventListener("mousedown", onDown);
|
|
14534
|
+
document.removeEventListener("keydown", onKey);
|
|
14535
|
+
window.removeEventListener("blur", onBlur);
|
|
14536
|
+
offNativeFocus();
|
|
14537
|
+
};
|
|
14538
|
+
}, [open]);
|
|
14539
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow", ref, children: [
|
|
14540
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14541
|
+
"button",
|
|
14542
|
+
{
|
|
14543
|
+
ref: buttonRef,
|
|
14544
|
+
className: "icon-button overflow-button",
|
|
14545
|
+
type: "button",
|
|
14546
|
+
title: "More",
|
|
14547
|
+
"aria-label": "More",
|
|
14548
|
+
"aria-haspopup": "true",
|
|
14549
|
+
"aria-expanded": open,
|
|
14550
|
+
onClick: () => setOpen((o) => !o),
|
|
14551
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "overflow" })
|
|
14552
|
+
}
|
|
14553
|
+
),
|
|
14554
|
+
open && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-menu", children: children(close) })
|
|
14555
|
+
] });
|
|
14556
|
+
}
|
|
14557
|
+
function Segmented({
|
|
14558
|
+
className,
|
|
14559
|
+
ariaLabel,
|
|
14560
|
+
value,
|
|
14561
|
+
options,
|
|
14562
|
+
onChange
|
|
14563
|
+
}) {
|
|
14564
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `segmented ${className}`, role: "group", "aria-label": ariaLabel, children: options.map((o) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14565
|
+
"button",
|
|
14566
|
+
{
|
|
14567
|
+
type: "button",
|
|
14568
|
+
className: o.className,
|
|
14569
|
+
title: o.title,
|
|
14570
|
+
"aria-pressed": value === o.id,
|
|
14571
|
+
onClick: () => onChange(o.id),
|
|
14572
|
+
children: o.label
|
|
14573
|
+
},
|
|
14574
|
+
o.id
|
|
14575
|
+
)) });
|
|
14576
|
+
}
|
|
14577
|
+
function Select({ className, value, label, ariaLabel, onChange, children }) {
|
|
14578
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "select-shell", children: [
|
|
14579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "select-label", "aria-hidden": "true", children: label }),
|
|
14580
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "select-chevron", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "chevron", size: 14 }) }),
|
|
14581
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14582
|
+
"select",
|
|
14583
|
+
{
|
|
14584
|
+
className,
|
|
14585
|
+
value,
|
|
14586
|
+
"aria-label": ariaLabel,
|
|
14587
|
+
onChange: (e) => onChange(e.target.value),
|
|
14588
|
+
children
|
|
14589
|
+
}
|
|
14590
|
+
)
|
|
14591
|
+
] });
|
|
14592
|
+
}
|
|
14274
14593
|
const SURROUNDS = [
|
|
14275
14594
|
{ id: "black", label: "Black surround", swatch: "#000000" },
|
|
14276
14595
|
{ id: "graphite", label: "Graphite surround", swatch: "#2a2a2a" },
|
|
@@ -14280,6 +14599,10 @@ const VIEWS = [
|
|
|
14280
14599
|
{ id: "1:1", label: "1:1", title: "Actual size" },
|
|
14281
14600
|
{ id: "fit", label: "Fit", title: "Fit the pane — not pixel-exact" }
|
|
14282
14601
|
];
|
|
14602
|
+
const PANES = [
|
|
14603
|
+
{ id: "both", label: "Both", title: "Native and target side by side" },
|
|
14604
|
+
{ id: "target", label: "Target", title: "The target render alone, full width" }
|
|
14605
|
+
];
|
|
14283
14606
|
function Toolbar({ drawer, onTogglePanel, onToggleSettings }) {
|
|
14284
14607
|
const mode = useStore((s) => s.mode);
|
|
14285
14608
|
const presetId = useStore((s) => s.presetId);
|
|
@@ -14300,6 +14623,8 @@ function Toolbar({ drawer, onTogglePanel, onToggleSettings }) {
|
|
|
14300
14623
|
const setSurround = useStore((s) => s.setSurround);
|
|
14301
14624
|
const viewMode = useStore((s) => s.viewMode);
|
|
14302
14625
|
const setViewMode = useStore((s) => s.setViewMode);
|
|
14626
|
+
const panes = useStore((s) => s.panes);
|
|
14627
|
+
const setPanes = useStore((s) => s.setPanes);
|
|
14303
14628
|
const agentControl = useStore((s) => s.settings.agentControl);
|
|
14304
14629
|
const setSettings = useStore((s) => s.setSettings);
|
|
14305
14630
|
const inputRef = reactExports.useRef(null);
|
|
@@ -14344,152 +14669,206 @@ function Toolbar({ drawer, onTogglePanel, onToggleSettings }) {
|
|
|
14344
14669
|
setUrl(applied);
|
|
14345
14670
|
setDraft(applied);
|
|
14346
14671
|
};
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
onKeyDown: (e) => {
|
|
14361
|
-
if (e.key === "Escape") setDraft(barText);
|
|
14672
|
+
const presetLabel = SCREEN_PRESETS.find((p) => p.id === presetId)?.label ?? "Custom";
|
|
14673
|
+
const profileLabel = PANEL_PROFILES.find((p) => p.id === profileId)?.label ?? profileId;
|
|
14674
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chrome", children: [
|
|
14675
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chrome-row chrome-browse", children: [
|
|
14676
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14677
|
+
"button",
|
|
14678
|
+
{
|
|
14679
|
+
className: "icon-button",
|
|
14680
|
+
type: "button",
|
|
14681
|
+
title: "Back",
|
|
14682
|
+
"aria-label": "Back",
|
|
14683
|
+
onClick: () => window.obsrv.back(),
|
|
14684
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "back" })
|
|
14362
14685
|
}
|
|
14363
|
-
|
|
14364
|
-
) }),
|
|
14365
|
-
mode === "image" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14366
|
-
"button",
|
|
14367
|
-
{
|
|
14368
|
-
className: "close-image",
|
|
14369
|
-
type: "button",
|
|
14370
|
-
title: "Back to the live page",
|
|
14371
|
-
"aria-label": "Back to the live page",
|
|
14372
|
-
onClick: () => setMode("url"),
|
|
14373
|
-
children: "✕"
|
|
14374
|
-
}
|
|
14375
|
-
),
|
|
14376
|
-
loading && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "muted", children: "loading…" }),
|
|
14377
|
-
error && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "badge-error", title: error.description, children: error.code }),
|
|
14378
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14379
|
-
"select",
|
|
14380
|
-
{
|
|
14381
|
-
className: "preset-select",
|
|
14382
|
-
value: presetId,
|
|
14383
|
-
onChange: (e) => setPreset(e.target.value),
|
|
14384
|
-
children: [
|
|
14385
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Laptops", children: SCREEN_PRESETS.filter((p) => p.group === "laptop").map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id)) }),
|
|
14386
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Desktops", children: SCREEN_PRESETS.filter((p) => p.group === "desktop").map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id)) }),
|
|
14387
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Mobile", children: SCREEN_PRESETS.filter((p) => p.group === "mobile").map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id)) }),
|
|
14388
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: CUSTOM_PRESET_ID, children: "Custom" })
|
|
14389
|
-
]
|
|
14390
|
-
}
|
|
14391
|
-
),
|
|
14392
|
-
viewport.clamped && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "warn", children: [
|
|
14393
|
-
"clamped to ",
|
|
14394
|
-
viewport.width,
|
|
14395
|
-
"×",
|
|
14396
|
-
viewport.height
|
|
14397
|
-
] }),
|
|
14398
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "view-control", role: "group", "aria-label": "Target view", children: VIEWS.map((v) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14399
|
-
"button",
|
|
14400
|
-
{
|
|
14401
|
-
type: "button",
|
|
14402
|
-
className: v.id === "fit" ? "view-fit" : "view-1x",
|
|
14403
|
-
title: v.title,
|
|
14404
|
-
"aria-pressed": viewMode === v.id,
|
|
14405
|
-
onClick: () => setViewMode(v.id),
|
|
14406
|
-
children: v.label
|
|
14407
|
-
},
|
|
14408
|
-
v.id
|
|
14409
|
-
)) }),
|
|
14410
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14411
|
-
"select",
|
|
14412
|
-
{
|
|
14413
|
-
className: "profile-select",
|
|
14414
|
-
value: profileId,
|
|
14415
|
-
onChange: (e) => setProfile(e.target.value),
|
|
14416
|
-
children: PANEL_PROFILES.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id))
|
|
14417
|
-
}
|
|
14418
|
-
),
|
|
14419
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "pixel-exact", children: [
|
|
14686
|
+
),
|
|
14420
14687
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14421
|
-
"
|
|
14688
|
+
"button",
|
|
14422
14689
|
{
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14690
|
+
className: "icon-button",
|
|
14691
|
+
type: "button",
|
|
14692
|
+
title: "Forward",
|
|
14693
|
+
"aria-label": "Forward",
|
|
14694
|
+
onClick: () => window.obsrv.forward(),
|
|
14695
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "forward" })
|
|
14696
|
+
}
|
|
14697
|
+
),
|
|
14698
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14699
|
+
"button",
|
|
14700
|
+
{
|
|
14701
|
+
className: "icon-button",
|
|
14702
|
+
type: "button",
|
|
14703
|
+
title: "Reload",
|
|
14704
|
+
"aria-label": "Reload",
|
|
14705
|
+
onClick: () => window.obsrv.reload(),
|
|
14706
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "reload" })
|
|
14426
14707
|
}
|
|
14427
14708
|
),
|
|
14428
|
-
"
|
|
14709
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("form", { className: "url-form", onSubmit: submit, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14710
|
+
"input",
|
|
14711
|
+
{
|
|
14712
|
+
ref: inputRef,
|
|
14713
|
+
value: draft,
|
|
14714
|
+
readOnly,
|
|
14715
|
+
spellCheck: false,
|
|
14716
|
+
placeholder: "Enter a URL, or drop a PNG",
|
|
14717
|
+
onChange: (e) => setDraft(e.target.value),
|
|
14718
|
+
onKeyDown: (e) => {
|
|
14719
|
+
if (e.key === "Escape") setDraft(barText);
|
|
14720
|
+
}
|
|
14721
|
+
}
|
|
14722
|
+
) }),
|
|
14723
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "status-cluster", children: [
|
|
14724
|
+
mode === "image" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14725
|
+
"button",
|
|
14726
|
+
{
|
|
14727
|
+
className: "icon-button close-image",
|
|
14728
|
+
type: "button",
|
|
14729
|
+
title: "Back to the live page",
|
|
14730
|
+
"aria-label": "Back to the live page",
|
|
14731
|
+
onClick: () => setMode("url"),
|
|
14732
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "close" })
|
|
14733
|
+
}
|
|
14734
|
+
),
|
|
14735
|
+
loading && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "muted", children: "loading…" }),
|
|
14736
|
+
error && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "badge-error", title: error.description, children: error.code }),
|
|
14737
|
+
viewport.clamped && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "warn", children: [
|
|
14738
|
+
"clamped to ",
|
|
14739
|
+
viewport.width,
|
|
14740
|
+
"×",
|
|
14741
|
+
viewport.height
|
|
14742
|
+
] }),
|
|
14743
|
+
update?.status === "available" && update.latest !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14744
|
+
"button",
|
|
14745
|
+
{
|
|
14746
|
+
className: "update-button",
|
|
14747
|
+
type: "button",
|
|
14748
|
+
title: `Obsrv ${update.latest} is available — opens the download page`,
|
|
14749
|
+
onClick: () => void window.obsrv.openRelease(),
|
|
14750
|
+
children: [
|
|
14751
|
+
"v",
|
|
14752
|
+
update.latest,
|
|
14753
|
+
" ↓"
|
|
14754
|
+
]
|
|
14755
|
+
}
|
|
14756
|
+
)
|
|
14757
|
+
] }),
|
|
14758
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(OverflowMenu, { children: (close) => /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
14759
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "menu-row pixel-exact", children: [
|
|
14760
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14761
|
+
"input",
|
|
14762
|
+
{
|
|
14763
|
+
type: "checkbox",
|
|
14764
|
+
checked: pixelExact,
|
|
14765
|
+
onChange: (e) => setPixelExact(e.target.checked)
|
|
14766
|
+
}
|
|
14767
|
+
),
|
|
14768
|
+
"Pixel-exact"
|
|
14769
|
+
] }),
|
|
14770
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14771
|
+
"button",
|
|
14772
|
+
{
|
|
14773
|
+
className: "menu-row toggle-panel",
|
|
14774
|
+
type: "button",
|
|
14775
|
+
"aria-pressed": drawer === "panel",
|
|
14776
|
+
onClick: () => {
|
|
14777
|
+
onTogglePanel();
|
|
14778
|
+
close();
|
|
14779
|
+
},
|
|
14780
|
+
children: [
|
|
14781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "sliders" }),
|
|
14782
|
+
"Panel controls"
|
|
14783
|
+
]
|
|
14784
|
+
}
|
|
14785
|
+
),
|
|
14786
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14787
|
+
"button",
|
|
14788
|
+
{
|
|
14789
|
+
className: "menu-row toggle-settings",
|
|
14790
|
+
type: "button",
|
|
14791
|
+
"aria-pressed": drawer === "settings",
|
|
14792
|
+
onClick: () => {
|
|
14793
|
+
onToggleSettings();
|
|
14794
|
+
close();
|
|
14795
|
+
},
|
|
14796
|
+
children: [
|
|
14797
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "gear" }),
|
|
14798
|
+
"Settings"
|
|
14799
|
+
]
|
|
14800
|
+
}
|
|
14801
|
+
),
|
|
14802
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "menu-sep" }),
|
|
14803
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "menu-row agent-toggle", children: [
|
|
14804
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: agentControl, onChange: toggleAgent }),
|
|
14805
|
+
"Agent control"
|
|
14806
|
+
] })
|
|
14807
|
+
] }) })
|
|
14429
14808
|
] }),
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
14434
|
-
|
|
14435
|
-
|
|
14436
|
-
|
|
14437
|
-
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
|
|
14445
|
-
|
|
14446
|
-
|
|
14447
|
-
|
|
14448
|
-
|
|
14449
|
-
|
|
14450
|
-
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
|
|
14454
|
-
|
|
14455
|
-
|
|
14456
|
-
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
14463
|
-
|
|
14464
|
-
|
|
14465
|
-
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14472
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
|
|
14483
|
-
|
|
14484
|
-
|
|
14485
|
-
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
|
|
14489
|
-
|
|
14490
|
-
|
|
14491
|
-
}
|
|
14492
|
-
)
|
|
14809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chrome-row chrome-screen", children: [
|
|
14810
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14811
|
+
Select,
|
|
14812
|
+
{
|
|
14813
|
+
className: "preset-select",
|
|
14814
|
+
value: presetId,
|
|
14815
|
+
label: presetLabel,
|
|
14816
|
+
ariaLabel: "Target screen",
|
|
14817
|
+
onChange: setPreset,
|
|
14818
|
+
children: [
|
|
14819
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Laptops", children: SCREEN_PRESETS.filter((p) => p.group === "laptop").map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id)) }),
|
|
14820
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Desktops", children: SCREEN_PRESETS.filter((p) => p.group === "desktop").map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id)) }),
|
|
14821
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: "Mobile", children: SCREEN_PRESETS.filter((p) => p.group === "mobile").map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id)) }),
|
|
14822
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: CUSTOM_PRESET_ID, children: "Custom" })
|
|
14823
|
+
]
|
|
14824
|
+
}
|
|
14825
|
+
),
|
|
14826
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14827
|
+
Segmented,
|
|
14828
|
+
{
|
|
14829
|
+
className: "view-control",
|
|
14830
|
+
ariaLabel: "Target view",
|
|
14831
|
+
value: viewMode,
|
|
14832
|
+
options: VIEWS.map((v) => ({ ...v, className: v.id === "fit" ? "view-fit" : "view-1x" })),
|
|
14833
|
+
onChange: setViewMode
|
|
14834
|
+
}
|
|
14835
|
+
),
|
|
14836
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14837
|
+
Segmented,
|
|
14838
|
+
{
|
|
14839
|
+
className: "panes-control",
|
|
14840
|
+
ariaLabel: "Panes",
|
|
14841
|
+
value: panes,
|
|
14842
|
+
options: PANES.map((p) => ({ ...p, className: `panes-${p.id}` })),
|
|
14843
|
+
onChange: setPanes
|
|
14844
|
+
}
|
|
14845
|
+
),
|
|
14846
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14847
|
+
Select,
|
|
14848
|
+
{
|
|
14849
|
+
className: "profile-select",
|
|
14850
|
+
value: profileId,
|
|
14851
|
+
label: profileLabel,
|
|
14852
|
+
ariaLabel: "Panel profile",
|
|
14853
|
+
onChange: setProfile,
|
|
14854
|
+
children: PANEL_PROFILES.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id))
|
|
14855
|
+
}
|
|
14856
|
+
),
|
|
14857
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "surround-control", role: "group", "aria-label": "Pane surround", children: SURROUNDS.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14858
|
+
"button",
|
|
14859
|
+
{
|
|
14860
|
+
type: "button",
|
|
14861
|
+
title: s.label,
|
|
14862
|
+
"aria-label": s.label,
|
|
14863
|
+
"aria-pressed": surround === s.id,
|
|
14864
|
+
onClick: () => setSurround(s.id),
|
|
14865
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "surround-swatch", style: { background: s.swatch } })
|
|
14866
|
+
},
|
|
14867
|
+
s.id
|
|
14868
|
+
)) }),
|
|
14869
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "chrome-spacer" }),
|
|
14870
|
+
agentControl && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `agent-activity${agentActive ? " active" : ""}`, children: "AGENT" })
|
|
14871
|
+
] })
|
|
14493
14872
|
] });
|
|
14494
14873
|
}
|
|
14495
14874
|
function App() {
|
|
@@ -14517,6 +14896,7 @@ function App() {
|
|
|
14517
14896
|
const presetId = useStore((s) => s.presetId);
|
|
14518
14897
|
const profileId = useStore((s) => s.profileId);
|
|
14519
14898
|
const viewMode = useStore((s) => s.viewMode);
|
|
14899
|
+
const panes = useStore((s) => s.panes);
|
|
14520
14900
|
reactExports.useEffect(() => {
|
|
14521
14901
|
window.obsrv.getHostInfo().then(setHost, (e) => console.warn("obsrv: getHostInfo failed", e));
|
|
14522
14902
|
window.obsrv.getSettings().then(setSettings, (e) => console.warn("obsrv: getSettings failed", e));
|
|
@@ -14544,6 +14924,9 @@ function App() {
|
|
|
14544
14924
|
reactExports.useEffect(() => {
|
|
14545
14925
|
window.obsrv.setMode(mode);
|
|
14546
14926
|
}, [mode]);
|
|
14927
|
+
reactExports.useEffect(() => {
|
|
14928
|
+
window.obsrv.setNativeVisible(panes === "both");
|
|
14929
|
+
}, [panes]);
|
|
14547
14930
|
reactExports.useEffect(() => {
|
|
14548
14931
|
const el = targetPaneRef.current;
|
|
14549
14932
|
if (!el) return;
|
|
@@ -14574,14 +14957,15 @@ function App() {
|
|
|
14574
14957
|
};
|
|
14575
14958
|
}, []);
|
|
14576
14959
|
reactExports.useEffect(() => {
|
|
14577
|
-
window.obsrv.reportUiState({ presetId, profileId, viewMode, mode, targetBounds, canvasBounds });
|
|
14578
|
-
}, [presetId, profileId, viewMode, mode, targetBounds, canvasBounds]);
|
|
14960
|
+
window.obsrv.reportUiState({ presetId, profileId, viewMode, panes, mode, targetBounds, canvasBounds });
|
|
14961
|
+
}, [presetId, profileId, viewMode, panes, mode, targetBounds, canvasBounds]);
|
|
14579
14962
|
reactExports.useEffect(() => {
|
|
14580
14963
|
return window.obsrv.onAgentApply((patch) => {
|
|
14581
14964
|
const s = useStore.getState();
|
|
14582
14965
|
if (patch.presetId !== void 0) s.setPreset(patch.presetId);
|
|
14583
14966
|
if (patch.profileId !== void 0) s.setProfile(patch.profileId);
|
|
14584
14967
|
if (patch.viewMode !== void 0) s.setViewMode(patch.viewMode);
|
|
14968
|
+
if (patch.panes !== void 0) s.setPanes(patch.panes);
|
|
14585
14969
|
if (patch.pixelExact !== void 0) s.setPixelExact(patch.pixelExact);
|
|
14586
14970
|
if (patch.panTo !== void 0) s.requestAgentPan(patch.panTo);
|
|
14587
14971
|
if (patch.highlight !== void 0) s.showAgentHighlight(patch.highlight);
|
|
@@ -14647,15 +15031,15 @@ function App() {
|
|
|
14647
15031
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Toolbar, { drawer, onTogglePanel: toggle("panel"), onToggleSettings: toggle("settings") }),
|
|
14648
15032
|
/* @__PURE__ */ jsxRuntimeExports.jsx(DropZone, { onImage }),
|
|
14649
15033
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "body", children: [
|
|
14650
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "panes", children: [
|
|
14651
|
-
mode === "image" && image ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
15034
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "panes", "data-panes": panes, children: [
|
|
15035
|
+
panes === "both" && (mode === "image" && image ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14652
15036
|
ImagePane,
|
|
14653
15037
|
{
|
|
14654
15038
|
src: image.objectUrl,
|
|
14655
15039
|
width: image.natural.width,
|
|
14656
15040
|
height: image.natural.height
|
|
14657
15041
|
}
|
|
14658
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(NativeSlot, {}),
|
|
15042
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(NativeSlot, {})),
|
|
14659
15043
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pane target-pane", ref: targetPaneRef, children: [
|
|
14660
15044
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pane-body", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TargetCanvas, { onFatal: setFatal, imageFrame }) }),
|
|
14661
15045
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TargetFooter, {})
|