getobsrv 0.8.0 → 0.10.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 +19 -6
- 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-Cgx8iixu.js → index-CQVE5hF3.js} +541 -153
- package/out/renderer/assets/{index-BeroS4wv.css → index-CZUlXhEb.css} +233 -82
- 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
|
@@ -12782,7 +12782,13 @@ const useStore = create()((set) => ({
|
|
|
12782
12782
|
update: null,
|
|
12783
12783
|
image: null,
|
|
12784
12784
|
surround: "graphite",
|
|
12785
|
-
|
|
12785
|
+
// Fit, not 1:1: fit never enlarges past 1:1, so a render that already fits
|
|
12786
|
+
// its pane opens at true magnification anyway, while one that does not is
|
|
12787
|
+
// shown whole instead of as its top-left corner. Fit is interactive, so
|
|
12788
|
+
// this costs nothing — and the footer names the actual magnification
|
|
12789
|
+
// whenever fit is minifying.
|
|
12790
|
+
viewMode: "fit",
|
|
12791
|
+
panes: "both",
|
|
12786
12792
|
fitScale: null,
|
|
12787
12793
|
agentPan: null,
|
|
12788
12794
|
agentHighlight: null,
|
|
@@ -12810,6 +12816,9 @@ const useStore = create()((set) => ({
|
|
|
12810
12816
|
setImage: (image) => set({ image }),
|
|
12811
12817
|
setSurround: (surround) => set({ surround }),
|
|
12812
12818
|
setViewMode: (viewMode) => set({ viewMode }),
|
|
12819
|
+
// No `agentHighlight: null` here, unlike setPreset: hiding a pane does not
|
|
12820
|
+
// re-raster the target, so the highlight still marks the pixels it marked.
|
|
12821
|
+
setPanes: (panes) => set({ panes }),
|
|
12813
12822
|
setFitScale: (fitScale2) => set({ fitScale: fitScale2 }),
|
|
12814
12823
|
requestAgentPan: (p) => set((s) => ({ agentPan: { ...p, seq: (s.agentPan?.seq ?? 0) + 1 } })),
|
|
12815
12824
|
clearAgentPan: () => set({ agentPan: null }),
|
|
@@ -14021,7 +14030,6 @@ function TargetCanvas({ onFatal, imageFrame }) {
|
|
|
14021
14030
|
canvas.addEventListener("wheel", onWheel, { passive: false });
|
|
14022
14031
|
const onWindowUp = (e) => {
|
|
14023
14032
|
if (useStore.getState().mode !== "url") return;
|
|
14024
|
-
if (useStore.getState().viewMode !== "1:1") return;
|
|
14025
14033
|
if (panRef.current || e.button === 1) return;
|
|
14026
14034
|
if (e.altKey && !forwardDrag.current) return;
|
|
14027
14035
|
if (e.target === canvas) return;
|
|
@@ -14095,7 +14103,7 @@ function TargetCanvas({ onFatal, imageFrame }) {
|
|
|
14095
14103
|
return body instanceof HTMLElement ? body : null;
|
|
14096
14104
|
};
|
|
14097
14105
|
const startPan = (e) => {
|
|
14098
|
-
if (
|
|
14106
|
+
if (fit) return;
|
|
14099
14107
|
if (!(e.button === 1 || e.button === 0 && e.altKey)) return;
|
|
14100
14108
|
const body = paneBody();
|
|
14101
14109
|
if (!body) return;
|
|
@@ -14144,7 +14152,7 @@ function TargetCanvas({ onFatal, imageFrame }) {
|
|
|
14144
14152
|
pendingJump.current = null;
|
|
14145
14153
|
}, [viewMode]);
|
|
14146
14154
|
const jumpTo1x = (e) => {
|
|
14147
|
-
if (
|
|
14155
|
+
if (!fit || !e.altKey) return;
|
|
14148
14156
|
const r = e.currentTarget.getBoundingClientRect();
|
|
14149
14157
|
pendingJump.current = jumpScroll(
|
|
14150
14158
|
e.clientX - r.left,
|
|
@@ -14185,7 +14193,7 @@ function TargetCanvas({ onFatal, imageFrame }) {
|
|
|
14185
14193
|
}, [agentHighlight, clearAgentHighlight]);
|
|
14186
14194
|
const send = (type) => (e) => {
|
|
14187
14195
|
if (mode !== "url") return;
|
|
14188
|
-
if (
|
|
14196
|
+
if (panRef.current || e.button === 1) return;
|
|
14189
14197
|
if (e.altKey && !forwardDrag.current) return;
|
|
14190
14198
|
const out = mouseEvent(type, e, e.currentTarget.getBoundingClientRect(), scale * dsf / dpr);
|
|
14191
14199
|
if (out) {
|
|
@@ -14216,7 +14224,7 @@ function TargetCanvas({ onFatal, imageFrame }) {
|
|
|
14216
14224
|
"canvas",
|
|
14217
14225
|
{
|
|
14218
14226
|
ref: canvasRef,
|
|
14219
|
-
className: `target-canvas${
|
|
14227
|
+
className: `target-canvas${panning ? " panning" : altHeld ? fit ? " fit" : " pan-ready" : ""}`,
|
|
14220
14228
|
tabIndex: 0,
|
|
14221
14229
|
style: { width: `${cssW}px`, height: `${cssH}px` },
|
|
14222
14230
|
onClick: jumpTo1x,
|
|
@@ -14228,12 +14236,12 @@ function TargetCanvas({ onFatal, imageFrame }) {
|
|
|
14228
14236
|
onMouseUp: send("mouseUp"),
|
|
14229
14237
|
onMouseMove: send("mouseMove"),
|
|
14230
14238
|
onKeyDown: (e) => {
|
|
14231
|
-
if (mode !== "url"
|
|
14239
|
+
if (mode !== "url") return;
|
|
14232
14240
|
if (!e.metaKey && !e.ctrlKey) e.preventDefault();
|
|
14233
14241
|
for (const ev of keyDownEvents(e)) window.obsrv.sendInput(ev);
|
|
14234
14242
|
},
|
|
14235
14243
|
onKeyUp: (e) => {
|
|
14236
|
-
if (mode !== "url"
|
|
14244
|
+
if (mode !== "url") return;
|
|
14237
14245
|
const ev = keyUpEvent(e);
|
|
14238
14246
|
if (ev) window.obsrv.sendInput(ev);
|
|
14239
14247
|
}
|
|
@@ -14271,6 +14279,321 @@ function Toast() {
|
|
|
14271
14279
|
if (!toast) return null;
|
|
14272
14280
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "toast", role: "status", children: toast });
|
|
14273
14281
|
}
|
|
14282
|
+
/**
|
|
14283
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14284
|
+
*
|
|
14285
|
+
* This source code is licensed under the ISC license.
|
|
14286
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14287
|
+
*/
|
|
14288
|
+
const mergeClasses = (...classes) => classes.filter((className, index, array) => {
|
|
14289
|
+
return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
|
|
14290
|
+
}).join(" ").trim();
|
|
14291
|
+
/**
|
|
14292
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14293
|
+
*
|
|
14294
|
+
* This source code is licensed under the ISC license.
|
|
14295
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14296
|
+
*/
|
|
14297
|
+
const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
14298
|
+
/**
|
|
14299
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14300
|
+
*
|
|
14301
|
+
* This source code is licensed under the ISC license.
|
|
14302
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14303
|
+
*/
|
|
14304
|
+
const toCamelCase = (string) => string.replace(
|
|
14305
|
+
/^([A-Z])|[\s-_]+(\w)/g,
|
|
14306
|
+
(match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
|
|
14307
|
+
);
|
|
14308
|
+
/**
|
|
14309
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14310
|
+
*
|
|
14311
|
+
* This source code is licensed under the ISC license.
|
|
14312
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14313
|
+
*/
|
|
14314
|
+
const toPascalCase = (string) => {
|
|
14315
|
+
const camelCase = toCamelCase(string);
|
|
14316
|
+
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
|
14317
|
+
};
|
|
14318
|
+
/**
|
|
14319
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14320
|
+
*
|
|
14321
|
+
* This source code is licensed under the ISC license.
|
|
14322
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14323
|
+
*/
|
|
14324
|
+
var defaultAttributes = {
|
|
14325
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14326
|
+
width: 24,
|
|
14327
|
+
height: 24,
|
|
14328
|
+
viewBox: "0 0 24 24",
|
|
14329
|
+
fill: "none",
|
|
14330
|
+
stroke: "currentColor",
|
|
14331
|
+
strokeWidth: 2,
|
|
14332
|
+
strokeLinecap: "round",
|
|
14333
|
+
strokeLinejoin: "round"
|
|
14334
|
+
};
|
|
14335
|
+
/**
|
|
14336
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14337
|
+
*
|
|
14338
|
+
* This source code is licensed under the ISC license.
|
|
14339
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14340
|
+
*/
|
|
14341
|
+
const hasA11yProp = (props) => {
|
|
14342
|
+
for (const prop in props) {
|
|
14343
|
+
if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
|
|
14344
|
+
return true;
|
|
14345
|
+
}
|
|
14346
|
+
}
|
|
14347
|
+
return false;
|
|
14348
|
+
};
|
|
14349
|
+
const LucideContext = reactExports.createContext({});
|
|
14350
|
+
const useLucideContext = () => reactExports.useContext(LucideContext);
|
|
14351
|
+
const Icon$1 = reactExports.forwardRef(
|
|
14352
|
+
({ color, size, strokeWidth, absoluteStrokeWidth, className = "", children, iconNode, ...rest }, ref) => {
|
|
14353
|
+
const {
|
|
14354
|
+
size: contextSize = 24,
|
|
14355
|
+
strokeWidth: contextStrokeWidth = 2,
|
|
14356
|
+
absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,
|
|
14357
|
+
color: contextColor = "currentColor",
|
|
14358
|
+
className: contextClass = ""
|
|
14359
|
+
} = useLucideContext() ?? {};
|
|
14360
|
+
const calculatedStrokeWidth = absoluteStrokeWidth ?? contextAbsoluteStrokeWidth ? Number(strokeWidth ?? contextStrokeWidth) * 24 / Number(size ?? contextSize) : strokeWidth ?? contextStrokeWidth;
|
|
14361
|
+
return reactExports.createElement(
|
|
14362
|
+
"svg",
|
|
14363
|
+
{
|
|
14364
|
+
ref,
|
|
14365
|
+
...defaultAttributes,
|
|
14366
|
+
width: size ?? contextSize ?? defaultAttributes.width,
|
|
14367
|
+
height: size ?? contextSize ?? defaultAttributes.height,
|
|
14368
|
+
stroke: color ?? contextColor,
|
|
14369
|
+
strokeWidth: calculatedStrokeWidth,
|
|
14370
|
+
className: mergeClasses("lucide", contextClass, className),
|
|
14371
|
+
...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
|
|
14372
|
+
...rest
|
|
14373
|
+
},
|
|
14374
|
+
[
|
|
14375
|
+
...iconNode.map(([tag, attrs]) => reactExports.createElement(tag, attrs)),
|
|
14376
|
+
...Array.isArray(children) ? children : [children]
|
|
14377
|
+
]
|
|
14378
|
+
);
|
|
14379
|
+
}
|
|
14380
|
+
);
|
|
14381
|
+
/**
|
|
14382
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14383
|
+
*
|
|
14384
|
+
* This source code is licensed under the ISC license.
|
|
14385
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14386
|
+
*/
|
|
14387
|
+
const createLucideIcon = (iconName, iconNode) => {
|
|
14388
|
+
const Component = reactExports.forwardRef(
|
|
14389
|
+
({ className, ...props }, ref) => reactExports.createElement(Icon$1, {
|
|
14390
|
+
ref,
|
|
14391
|
+
iconNode,
|
|
14392
|
+
className: mergeClasses(
|
|
14393
|
+
`lucide-${toKebabCase(toPascalCase(iconName))}`,
|
|
14394
|
+
`lucide-${iconName}`,
|
|
14395
|
+
className
|
|
14396
|
+
),
|
|
14397
|
+
...props
|
|
14398
|
+
})
|
|
14399
|
+
);
|
|
14400
|
+
Component.displayName = toPascalCase(iconName);
|
|
14401
|
+
return Component;
|
|
14402
|
+
};
|
|
14403
|
+
/**
|
|
14404
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14405
|
+
*
|
|
14406
|
+
* This source code is licensed under the ISC license.
|
|
14407
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14408
|
+
*/
|
|
14409
|
+
const __iconNode$7 = [
|
|
14410
|
+
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
14411
|
+
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
14412
|
+
];
|
|
14413
|
+
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$7);
|
|
14414
|
+
/**
|
|
14415
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14416
|
+
*
|
|
14417
|
+
* This source code is licensed under the ISC license.
|
|
14418
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14419
|
+
*/
|
|
14420
|
+
const __iconNode$6 = [
|
|
14421
|
+
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
14422
|
+
["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
|
|
14423
|
+
];
|
|
14424
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$6);
|
|
14425
|
+
/**
|
|
14426
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14427
|
+
*
|
|
14428
|
+
* This source code is licensed under the ISC license.
|
|
14429
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14430
|
+
*/
|
|
14431
|
+
const __iconNode$5 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
14432
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$5);
|
|
14433
|
+
/**
|
|
14434
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14435
|
+
*
|
|
14436
|
+
* This source code is licensed under the ISC license.
|
|
14437
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14438
|
+
*/
|
|
14439
|
+
const __iconNode$4 = [
|
|
14440
|
+
["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
|
|
14441
|
+
["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
|
|
14442
|
+
["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
|
|
14443
|
+
];
|
|
14444
|
+
const EllipsisVertical = createLucideIcon("ellipsis-vertical", __iconNode$4);
|
|
14445
|
+
/**
|
|
14446
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14447
|
+
*
|
|
14448
|
+
* This source code is licensed under the ISC license.
|
|
14449
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14450
|
+
*/
|
|
14451
|
+
const __iconNode$3 = [
|
|
14452
|
+
["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
|
|
14453
|
+
["path", { d: "M21 3v5h-5", key: "1q7to0" }]
|
|
14454
|
+
];
|
|
14455
|
+
const RotateCw = createLucideIcon("rotate-cw", __iconNode$3);
|
|
14456
|
+
/**
|
|
14457
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14458
|
+
*
|
|
14459
|
+
* This source code is licensed under the ISC license.
|
|
14460
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14461
|
+
*/
|
|
14462
|
+
const __iconNode$2 = [
|
|
14463
|
+
[
|
|
14464
|
+
"path",
|
|
14465
|
+
{
|
|
14466
|
+
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",
|
|
14467
|
+
key: "1i5ecw"
|
|
14468
|
+
}
|
|
14469
|
+
],
|
|
14470
|
+
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
14471
|
+
];
|
|
14472
|
+
const Settings = createLucideIcon("settings", __iconNode$2);
|
|
14473
|
+
/**
|
|
14474
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14475
|
+
*
|
|
14476
|
+
* This source code is licensed under the ISC license.
|
|
14477
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14478
|
+
*/
|
|
14479
|
+
const __iconNode$1 = [
|
|
14480
|
+
["path", { d: "M10 5H3", key: "1qgfaw" }],
|
|
14481
|
+
["path", { d: "M12 19H3", key: "yhmn1j" }],
|
|
14482
|
+
["path", { d: "M14 3v4", key: "1sua03" }],
|
|
14483
|
+
["path", { d: "M16 17v4", key: "1q0r14" }],
|
|
14484
|
+
["path", { d: "M21 12h-9", key: "1o4lsq" }],
|
|
14485
|
+
["path", { d: "M21 19h-5", key: "1rlt1p" }],
|
|
14486
|
+
["path", { d: "M21 5h-7", key: "1oszz2" }],
|
|
14487
|
+
["path", { d: "M8 10v4", key: "tgpxqk" }],
|
|
14488
|
+
["path", { d: "M8 12H3", key: "a7s4jb" }]
|
|
14489
|
+
];
|
|
14490
|
+
const SlidersHorizontal = createLucideIcon("sliders-horizontal", __iconNode$1);
|
|
14491
|
+
/**
|
|
14492
|
+
* @license lucide-react v1.34.0 - ISC
|
|
14493
|
+
*
|
|
14494
|
+
* This source code is licensed under the ISC license.
|
|
14495
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
14496
|
+
*/
|
|
14497
|
+
const __iconNode = [
|
|
14498
|
+
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
14499
|
+
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
14500
|
+
];
|
|
14501
|
+
const X = createLucideIcon("x", __iconNode);
|
|
14502
|
+
const ICONS = {
|
|
14503
|
+
back: ArrowLeft,
|
|
14504
|
+
forward: ArrowRight,
|
|
14505
|
+
reload: RotateCw,
|
|
14506
|
+
overflow: EllipsisVertical,
|
|
14507
|
+
close: X,
|
|
14508
|
+
sliders: SlidersHorizontal,
|
|
14509
|
+
gear: Settings,
|
|
14510
|
+
chevron: ChevronDown
|
|
14511
|
+
};
|
|
14512
|
+
function Icon({ name, size = 16 }) {
|
|
14513
|
+
const Glyph = ICONS[name];
|
|
14514
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Glyph, { size, strokeWidth: 1.5, "aria-hidden": "true", focusable: "false" });
|
|
14515
|
+
}
|
|
14516
|
+
function OverflowMenu({ children }) {
|
|
14517
|
+
const [open, setOpen] = reactExports.useState(false);
|
|
14518
|
+
const ref = reactExports.useRef(null);
|
|
14519
|
+
const buttonRef = reactExports.useRef(null);
|
|
14520
|
+
const close = () => setOpen(false);
|
|
14521
|
+
reactExports.useEffect(() => {
|
|
14522
|
+
if (!open) return;
|
|
14523
|
+
const onDown = (e) => {
|
|
14524
|
+
if (!ref.current?.contains(e.target)) setOpen(false);
|
|
14525
|
+
};
|
|
14526
|
+
const onKey = (e) => {
|
|
14527
|
+
if (e.key !== "Escape") return;
|
|
14528
|
+
setOpen(false);
|
|
14529
|
+
buttonRef.current?.focus();
|
|
14530
|
+
};
|
|
14531
|
+
const onBlur = () => setOpen(false);
|
|
14532
|
+
document.addEventListener("mousedown", onDown);
|
|
14533
|
+
document.addEventListener("keydown", onKey);
|
|
14534
|
+
window.addEventListener("blur", onBlur);
|
|
14535
|
+
const offNativeFocus = window.obsrv.onNativeFocused(onBlur);
|
|
14536
|
+
return () => {
|
|
14537
|
+
document.removeEventListener("mousedown", onDown);
|
|
14538
|
+
document.removeEventListener("keydown", onKey);
|
|
14539
|
+
window.removeEventListener("blur", onBlur);
|
|
14540
|
+
offNativeFocus();
|
|
14541
|
+
};
|
|
14542
|
+
}, [open]);
|
|
14543
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow", ref, children: [
|
|
14544
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14545
|
+
"button",
|
|
14546
|
+
{
|
|
14547
|
+
ref: buttonRef,
|
|
14548
|
+
className: "icon-button overflow-button",
|
|
14549
|
+
type: "button",
|
|
14550
|
+
title: "More",
|
|
14551
|
+
"aria-label": "More",
|
|
14552
|
+
"aria-haspopup": "true",
|
|
14553
|
+
"aria-expanded": open,
|
|
14554
|
+
onClick: () => setOpen((o) => !o),
|
|
14555
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "overflow" })
|
|
14556
|
+
}
|
|
14557
|
+
),
|
|
14558
|
+
open && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-menu", children: children(close) })
|
|
14559
|
+
] });
|
|
14560
|
+
}
|
|
14561
|
+
function Segmented({
|
|
14562
|
+
className,
|
|
14563
|
+
ariaLabel,
|
|
14564
|
+
value,
|
|
14565
|
+
options,
|
|
14566
|
+
onChange
|
|
14567
|
+
}) {
|
|
14568
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `segmented ${className}`, role: "group", "aria-label": ariaLabel, children: options.map((o) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14569
|
+
"button",
|
|
14570
|
+
{
|
|
14571
|
+
type: "button",
|
|
14572
|
+
className: o.className,
|
|
14573
|
+
title: o.title,
|
|
14574
|
+
"aria-pressed": value === o.id,
|
|
14575
|
+
onClick: () => onChange(o.id),
|
|
14576
|
+
children: o.label
|
|
14577
|
+
},
|
|
14578
|
+
o.id
|
|
14579
|
+
)) });
|
|
14580
|
+
}
|
|
14581
|
+
function Select({ className, value, label, ariaLabel, onChange, children }) {
|
|
14582
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "select-shell", children: [
|
|
14583
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "select-label", "aria-hidden": "true", children: label }),
|
|
14584
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "select-chevron", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "chevron", size: 14 }) }),
|
|
14585
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14586
|
+
"select",
|
|
14587
|
+
{
|
|
14588
|
+
className,
|
|
14589
|
+
value,
|
|
14590
|
+
"aria-label": ariaLabel,
|
|
14591
|
+
onChange: (e) => onChange(e.target.value),
|
|
14592
|
+
children
|
|
14593
|
+
}
|
|
14594
|
+
)
|
|
14595
|
+
] });
|
|
14596
|
+
}
|
|
14274
14597
|
const SURROUNDS = [
|
|
14275
14598
|
{ id: "black", label: "Black surround", swatch: "#000000" },
|
|
14276
14599
|
{ id: "graphite", label: "Graphite surround", swatch: "#2a2a2a" },
|
|
@@ -14280,6 +14603,10 @@ const VIEWS = [
|
|
|
14280
14603
|
{ id: "1:1", label: "1:1", title: "Actual size" },
|
|
14281
14604
|
{ id: "fit", label: "Fit", title: "Fit the pane — not pixel-exact" }
|
|
14282
14605
|
];
|
|
14606
|
+
const PANES = [
|
|
14607
|
+
{ id: "both", label: "Both", title: "Native and target side by side" },
|
|
14608
|
+
{ id: "target", label: "Target", title: "The target render alone, full width" }
|
|
14609
|
+
];
|
|
14283
14610
|
function Toolbar({ drawer, onTogglePanel, onToggleSettings }) {
|
|
14284
14611
|
const mode = useStore((s) => s.mode);
|
|
14285
14612
|
const presetId = useStore((s) => s.presetId);
|
|
@@ -14300,6 +14627,8 @@ function Toolbar({ drawer, onTogglePanel, onToggleSettings }) {
|
|
|
14300
14627
|
const setSurround = useStore((s) => s.setSurround);
|
|
14301
14628
|
const viewMode = useStore((s) => s.viewMode);
|
|
14302
14629
|
const setViewMode = useStore((s) => s.setViewMode);
|
|
14630
|
+
const panes = useStore((s) => s.panes);
|
|
14631
|
+
const setPanes = useStore((s) => s.setPanes);
|
|
14303
14632
|
const agentControl = useStore((s) => s.settings.agentControl);
|
|
14304
14633
|
const setSettings = useStore((s) => s.setSettings);
|
|
14305
14634
|
const inputRef = reactExports.useRef(null);
|
|
@@ -14344,152 +14673,206 @@ function Toolbar({ drawer, onTogglePanel, onToggleSettings }) {
|
|
|
14344
14673
|
setUrl(applied);
|
|
14345
14674
|
setDraft(applied);
|
|
14346
14675
|
};
|
|
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);
|
|
14676
|
+
const presetLabel = SCREEN_PRESETS.find((p) => p.id === presetId)?.label ?? "Custom";
|
|
14677
|
+
const profileLabel = PANEL_PROFILES.find((p) => p.id === profileId)?.label ?? profileId;
|
|
14678
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chrome", children: [
|
|
14679
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chrome-row chrome-browse", children: [
|
|
14680
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14681
|
+
"button",
|
|
14682
|
+
{
|
|
14683
|
+
className: "icon-button",
|
|
14684
|
+
type: "button",
|
|
14685
|
+
title: "Back",
|
|
14686
|
+
"aria-label": "Back",
|
|
14687
|
+
onClick: () => window.obsrv.back(),
|
|
14688
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "back" })
|
|
14362
14689
|
}
|
|
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: [
|
|
14690
|
+
),
|
|
14420
14691
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14421
|
-
"
|
|
14692
|
+
"button",
|
|
14422
14693
|
{
|
|
14423
|
-
|
|
14424
|
-
|
|
14425
|
-
|
|
14694
|
+
className: "icon-button",
|
|
14695
|
+
type: "button",
|
|
14696
|
+
title: "Forward",
|
|
14697
|
+
"aria-label": "Forward",
|
|
14698
|
+
onClick: () => window.obsrv.forward(),
|
|
14699
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "forward" })
|
|
14700
|
+
}
|
|
14701
|
+
),
|
|
14702
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14703
|
+
"button",
|
|
14704
|
+
{
|
|
14705
|
+
className: "icon-button",
|
|
14706
|
+
type: "button",
|
|
14707
|
+
title: "Reload",
|
|
14708
|
+
"aria-label": "Reload",
|
|
14709
|
+
onClick: () => window.obsrv.reload(),
|
|
14710
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "reload" })
|
|
14426
14711
|
}
|
|
14427
14712
|
),
|
|
14428
|
-
"
|
|
14713
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("form", { className: "url-form", onSubmit: submit, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14714
|
+
"input",
|
|
14715
|
+
{
|
|
14716
|
+
ref: inputRef,
|
|
14717
|
+
value: draft,
|
|
14718
|
+
readOnly,
|
|
14719
|
+
spellCheck: false,
|
|
14720
|
+
placeholder: "Enter a URL, or drop a PNG",
|
|
14721
|
+
onChange: (e) => setDraft(e.target.value),
|
|
14722
|
+
onKeyDown: (e) => {
|
|
14723
|
+
if (e.key === "Escape") setDraft(barText);
|
|
14724
|
+
}
|
|
14725
|
+
}
|
|
14726
|
+
) }),
|
|
14727
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "status-cluster", children: [
|
|
14728
|
+
mode === "image" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14729
|
+
"button",
|
|
14730
|
+
{
|
|
14731
|
+
className: "icon-button close-image",
|
|
14732
|
+
type: "button",
|
|
14733
|
+
title: "Back to the live page",
|
|
14734
|
+
"aria-label": "Back to the live page",
|
|
14735
|
+
onClick: () => setMode("url"),
|
|
14736
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "close" })
|
|
14737
|
+
}
|
|
14738
|
+
),
|
|
14739
|
+
loading && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "muted", children: "loading…" }),
|
|
14740
|
+
error && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "badge-error", title: error.description, children: error.code }),
|
|
14741
|
+
viewport.clamped && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "warn", children: [
|
|
14742
|
+
"clamped to ",
|
|
14743
|
+
viewport.width,
|
|
14744
|
+
"×",
|
|
14745
|
+
viewport.height
|
|
14746
|
+
] }),
|
|
14747
|
+
update?.status === "available" && update.latest !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14748
|
+
"button",
|
|
14749
|
+
{
|
|
14750
|
+
className: "update-button",
|
|
14751
|
+
type: "button",
|
|
14752
|
+
title: `Obsrv ${update.latest} is available — opens the download page`,
|
|
14753
|
+
onClick: () => void window.obsrv.openRelease(),
|
|
14754
|
+
children: [
|
|
14755
|
+
"v",
|
|
14756
|
+
update.latest,
|
|
14757
|
+
" ↓"
|
|
14758
|
+
]
|
|
14759
|
+
}
|
|
14760
|
+
)
|
|
14761
|
+
] }),
|
|
14762
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(OverflowMenu, { children: (close) => /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
14763
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "menu-row pixel-exact", children: [
|
|
14764
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14765
|
+
"input",
|
|
14766
|
+
{
|
|
14767
|
+
type: "checkbox",
|
|
14768
|
+
checked: pixelExact,
|
|
14769
|
+
onChange: (e) => setPixelExact(e.target.checked)
|
|
14770
|
+
}
|
|
14771
|
+
),
|
|
14772
|
+
"Pixel-exact"
|
|
14773
|
+
] }),
|
|
14774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14775
|
+
"button",
|
|
14776
|
+
{
|
|
14777
|
+
className: "menu-row toggle-panel",
|
|
14778
|
+
type: "button",
|
|
14779
|
+
"aria-pressed": drawer === "panel",
|
|
14780
|
+
onClick: () => {
|
|
14781
|
+
onTogglePanel();
|
|
14782
|
+
close();
|
|
14783
|
+
},
|
|
14784
|
+
children: [
|
|
14785
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "sliders" }),
|
|
14786
|
+
"Panel controls"
|
|
14787
|
+
]
|
|
14788
|
+
}
|
|
14789
|
+
),
|
|
14790
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14791
|
+
"button",
|
|
14792
|
+
{
|
|
14793
|
+
className: "menu-row toggle-settings",
|
|
14794
|
+
type: "button",
|
|
14795
|
+
"aria-pressed": drawer === "settings",
|
|
14796
|
+
onClick: () => {
|
|
14797
|
+
onToggleSettings();
|
|
14798
|
+
close();
|
|
14799
|
+
},
|
|
14800
|
+
children: [
|
|
14801
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { name: "gear" }),
|
|
14802
|
+
"Settings"
|
|
14803
|
+
]
|
|
14804
|
+
}
|
|
14805
|
+
),
|
|
14806
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "menu-sep" }),
|
|
14807
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "menu-row agent-toggle", children: [
|
|
14808
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: agentControl, onChange: toggleAgent }),
|
|
14809
|
+
"Agent control"
|
|
14810
|
+
] })
|
|
14811
|
+
] }) })
|
|
14429
14812
|
] }),
|
|
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
|
-
)
|
|
14813
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chrome-row chrome-screen", children: [
|
|
14814
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14815
|
+
Select,
|
|
14816
|
+
{
|
|
14817
|
+
className: "preset-select",
|
|
14818
|
+
value: presetId,
|
|
14819
|
+
label: presetLabel,
|
|
14820
|
+
ariaLabel: "Target screen",
|
|
14821
|
+
onChange: setPreset,
|
|
14822
|
+
children: [
|
|
14823
|
+
/* @__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)) }),
|
|
14824
|
+
/* @__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)) }),
|
|
14825
|
+
/* @__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)) }),
|
|
14826
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: CUSTOM_PRESET_ID, children: "Custom" })
|
|
14827
|
+
]
|
|
14828
|
+
}
|
|
14829
|
+
),
|
|
14830
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14831
|
+
Segmented,
|
|
14832
|
+
{
|
|
14833
|
+
className: "view-control",
|
|
14834
|
+
ariaLabel: "Target view",
|
|
14835
|
+
value: viewMode,
|
|
14836
|
+
options: VIEWS.map((v) => ({ ...v, className: v.id === "fit" ? "view-fit" : "view-1x" })),
|
|
14837
|
+
onChange: setViewMode
|
|
14838
|
+
}
|
|
14839
|
+
),
|
|
14840
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14841
|
+
Segmented,
|
|
14842
|
+
{
|
|
14843
|
+
className: "panes-control",
|
|
14844
|
+
ariaLabel: "Panes",
|
|
14845
|
+
value: panes,
|
|
14846
|
+
options: PANES.map((p) => ({ ...p, className: `panes-${p.id}` })),
|
|
14847
|
+
onChange: setPanes
|
|
14848
|
+
}
|
|
14849
|
+
),
|
|
14850
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14851
|
+
Select,
|
|
14852
|
+
{
|
|
14853
|
+
className: "profile-select",
|
|
14854
|
+
value: profileId,
|
|
14855
|
+
label: profileLabel,
|
|
14856
|
+
ariaLabel: "Panel profile",
|
|
14857
|
+
onChange: setProfile,
|
|
14858
|
+
children: PANEL_PROFILES.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p.id, children: p.label }, p.id))
|
|
14859
|
+
}
|
|
14860
|
+
),
|
|
14861
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "surround-control", role: "group", "aria-label": "Pane surround", children: SURROUNDS.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14862
|
+
"button",
|
|
14863
|
+
{
|
|
14864
|
+
type: "button",
|
|
14865
|
+
title: s.label,
|
|
14866
|
+
"aria-label": s.label,
|
|
14867
|
+
"aria-pressed": surround === s.id,
|
|
14868
|
+
onClick: () => setSurround(s.id),
|
|
14869
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "surround-swatch", style: { background: s.swatch } })
|
|
14870
|
+
},
|
|
14871
|
+
s.id
|
|
14872
|
+
)) }),
|
|
14873
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "chrome-spacer" }),
|
|
14874
|
+
agentControl && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `agent-activity${agentActive ? " active" : ""}`, children: "AGENT" })
|
|
14875
|
+
] })
|
|
14493
14876
|
] });
|
|
14494
14877
|
}
|
|
14495
14878
|
function App() {
|
|
@@ -14517,6 +14900,7 @@ function App() {
|
|
|
14517
14900
|
const presetId = useStore((s) => s.presetId);
|
|
14518
14901
|
const profileId = useStore((s) => s.profileId);
|
|
14519
14902
|
const viewMode = useStore((s) => s.viewMode);
|
|
14903
|
+
const panes = useStore((s) => s.panes);
|
|
14520
14904
|
reactExports.useEffect(() => {
|
|
14521
14905
|
window.obsrv.getHostInfo().then(setHost, (e) => console.warn("obsrv: getHostInfo failed", e));
|
|
14522
14906
|
window.obsrv.getSettings().then(setSettings, (e) => console.warn("obsrv: getSettings failed", e));
|
|
@@ -14544,6 +14928,9 @@ function App() {
|
|
|
14544
14928
|
reactExports.useEffect(() => {
|
|
14545
14929
|
window.obsrv.setMode(mode);
|
|
14546
14930
|
}, [mode]);
|
|
14931
|
+
reactExports.useEffect(() => {
|
|
14932
|
+
window.obsrv.setNativeVisible(panes === "both");
|
|
14933
|
+
}, [panes]);
|
|
14547
14934
|
reactExports.useEffect(() => {
|
|
14548
14935
|
const el = targetPaneRef.current;
|
|
14549
14936
|
if (!el) return;
|
|
@@ -14574,14 +14961,15 @@ function App() {
|
|
|
14574
14961
|
};
|
|
14575
14962
|
}, []);
|
|
14576
14963
|
reactExports.useEffect(() => {
|
|
14577
|
-
window.obsrv.reportUiState({ presetId, profileId, viewMode, mode, targetBounds, canvasBounds });
|
|
14578
|
-
}, [presetId, profileId, viewMode, mode, targetBounds, canvasBounds]);
|
|
14964
|
+
window.obsrv.reportUiState({ presetId, profileId, viewMode, panes, mode, targetBounds, canvasBounds });
|
|
14965
|
+
}, [presetId, profileId, viewMode, panes, mode, targetBounds, canvasBounds]);
|
|
14579
14966
|
reactExports.useEffect(() => {
|
|
14580
14967
|
return window.obsrv.onAgentApply((patch) => {
|
|
14581
14968
|
const s = useStore.getState();
|
|
14582
14969
|
if (patch.presetId !== void 0) s.setPreset(patch.presetId);
|
|
14583
14970
|
if (patch.profileId !== void 0) s.setProfile(patch.profileId);
|
|
14584
14971
|
if (patch.viewMode !== void 0) s.setViewMode(patch.viewMode);
|
|
14972
|
+
if (patch.panes !== void 0) s.setPanes(patch.panes);
|
|
14585
14973
|
if (patch.pixelExact !== void 0) s.setPixelExact(patch.pixelExact);
|
|
14586
14974
|
if (patch.panTo !== void 0) s.requestAgentPan(patch.panTo);
|
|
14587
14975
|
if (patch.highlight !== void 0) s.showAgentHighlight(patch.highlight);
|
|
@@ -14647,15 +15035,15 @@ function App() {
|
|
|
14647
15035
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Toolbar, { drawer, onTogglePanel: toggle("panel"), onToggleSettings: toggle("settings") }),
|
|
14648
15036
|
/* @__PURE__ */ jsxRuntimeExports.jsx(DropZone, { onImage }),
|
|
14649
15037
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "body", children: [
|
|
14650
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "panes", children: [
|
|
14651
|
-
mode === "image" && image ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
15038
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "panes", "data-panes": panes, children: [
|
|
15039
|
+
panes === "both" && (mode === "image" && image ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14652
15040
|
ImagePane,
|
|
14653
15041
|
{
|
|
14654
15042
|
src: image.objectUrl,
|
|
14655
15043
|
width: image.natural.width,
|
|
14656
15044
|
height: image.natural.height
|
|
14657
15045
|
}
|
|
14658
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(NativeSlot, {}),
|
|
15046
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(NativeSlot, {})),
|
|
14659
15047
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pane target-pane", ref: targetPaneRef, children: [
|
|
14660
15048
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pane-body", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TargetCanvas, { onFatal: setFatal, imageFrame }) }),
|
|
14661
15049
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TargetFooter, {})
|