@jay-framework/aiditor 0.17.1 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.client.js +875 -2
- package/dist/index.d.ts +98 -1
- package/dist/pages/aiditor/page.jay-html +211 -0
- package/package.json +6 -6
package/dist/index.client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { makeJayStackComponent } from "@jay-framework/fullstack-component";
|
|
2
|
-
import { createSignal, createMemo } from "@jay-framework/component";
|
|
2
|
+
import { createSignal, createMemo, createEffect } from "@jay-framework/component";
|
|
3
3
|
import { createStreamCaller, createActionCaller, setActionCallerOptions } from "@jay-framework/stack-client-runtime";
|
|
4
4
|
const submitTaskAction = createStreamCaller("aiditor.submitTask", { acceptsFiles: true });
|
|
5
5
|
const visualModeToForm = {
|
|
@@ -7919,6 +7919,93 @@ var parseBackgroundColor = function(context, element, backgroundColorOverride) {
|
|
|
7919
7919
|
var defaultBackgroundColor = typeof backgroundColorOverride === "string" ? parseColor(context, backgroundColorOverride) : backgroundColorOverride === null ? COLORS.TRANSPARENT : 4294967295;
|
|
7920
7920
|
return element === ownerDocument.documentElement ? isTransparent(documentBackgroundColor) ? isTransparent(bodyBackgroundColor) ? defaultBackgroundColor : bodyBackgroundColor : documentBackgroundColor : defaultBackgroundColor;
|
|
7921
7921
|
};
|
|
7922
|
+
const TRANSIENT_PSEUDOCLASSES = [
|
|
7923
|
+
":hover",
|
|
7924
|
+
":focus",
|
|
7925
|
+
":focus-within",
|
|
7926
|
+
":focus-visible"
|
|
7927
|
+
];
|
|
7928
|
+
const FREEZE_PROPS = [
|
|
7929
|
+
"background",
|
|
7930
|
+
"background-color",
|
|
7931
|
+
"background-image",
|
|
7932
|
+
"color",
|
|
7933
|
+
"opacity",
|
|
7934
|
+
"transform",
|
|
7935
|
+
"box-shadow",
|
|
7936
|
+
"border",
|
|
7937
|
+
"border-color",
|
|
7938
|
+
"border-width",
|
|
7939
|
+
"border-style",
|
|
7940
|
+
"border-radius",
|
|
7941
|
+
"outline",
|
|
7942
|
+
"outline-color",
|
|
7943
|
+
"outline-width",
|
|
7944
|
+
"outline-offset",
|
|
7945
|
+
"text-decoration",
|
|
7946
|
+
"text-decoration-color",
|
|
7947
|
+
"text-shadow",
|
|
7948
|
+
"filter",
|
|
7949
|
+
"visibility",
|
|
7950
|
+
"display",
|
|
7951
|
+
"scale",
|
|
7952
|
+
"cursor",
|
|
7953
|
+
"width",
|
|
7954
|
+
"height",
|
|
7955
|
+
"max-width",
|
|
7956
|
+
"max-height",
|
|
7957
|
+
"min-width",
|
|
7958
|
+
"min-height",
|
|
7959
|
+
"padding",
|
|
7960
|
+
"margin",
|
|
7961
|
+
"top",
|
|
7962
|
+
"left",
|
|
7963
|
+
"right",
|
|
7964
|
+
"bottom",
|
|
7965
|
+
"z-index",
|
|
7966
|
+
"overflow",
|
|
7967
|
+
"clip-path",
|
|
7968
|
+
"backdrop-filter"
|
|
7969
|
+
];
|
|
7970
|
+
function freezeTransientStyles(iframeEl) {
|
|
7971
|
+
const doc = iframeEl.contentDocument;
|
|
7972
|
+
const win = iframeEl.contentWindow;
|
|
7973
|
+
if (!doc || !win) return () => {
|
|
7974
|
+
};
|
|
7975
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7976
|
+
for (const pseudo of TRANSIENT_PSEUDOCLASSES) {
|
|
7977
|
+
try {
|
|
7978
|
+
for (const el of doc.querySelectorAll(pseudo)) seen.add(el);
|
|
7979
|
+
} catch {
|
|
7980
|
+
}
|
|
7981
|
+
}
|
|
7982
|
+
if (seen.size === 0) return () => {
|
|
7983
|
+
};
|
|
7984
|
+
const saved = [];
|
|
7985
|
+
for (const el of seen) {
|
|
7986
|
+
if (!("setAttribute" in el) || !("getAttribute" in el)) continue;
|
|
7987
|
+
let computed;
|
|
7988
|
+
try {
|
|
7989
|
+
computed = win.getComputedStyle(el);
|
|
7990
|
+
} catch {
|
|
7991
|
+
continue;
|
|
7992
|
+
}
|
|
7993
|
+
const prev = el.getAttribute("style");
|
|
7994
|
+
let inline = prev ?? "";
|
|
7995
|
+
for (const p of FREEZE_PROPS) {
|
|
7996
|
+
const v = computed.getPropertyValue(p);
|
|
7997
|
+
if (v) inline += `; ${p}: ${v} !important`;
|
|
7998
|
+
}
|
|
7999
|
+
saved.push({ el, prev });
|
|
8000
|
+
el.setAttribute("style", inline);
|
|
8001
|
+
}
|
|
8002
|
+
return () => {
|
|
8003
|
+
for (const { el, prev } of saved) {
|
|
8004
|
+
if (prev !== null) el.setAttribute("style", prev);
|
|
8005
|
+
else el.removeAttribute("style");
|
|
8006
|
+
}
|
|
8007
|
+
};
|
|
8008
|
+
}
|
|
7922
8009
|
function getIframeViewportScrollForHtml2Canvas(win, doc) {
|
|
7923
8010
|
let sx = win.pageXOffset;
|
|
7924
8011
|
let sy = win.pageYOffset;
|
|
@@ -8283,6 +8370,123 @@ async function capturePreviewForVideoFrame(rootEl, videoEl, mode = "full") {
|
|
|
8283
8370
|
if (mode === "full" && popoversEl) await drawLayer(popoversEl);
|
|
8284
8371
|
return canvasToPng(canvas);
|
|
8285
8372
|
}
|
|
8373
|
+
async function compositeMarkersOntoScreenshot(cleanBlob, annotations) {
|
|
8374
|
+
const img = await blobToImage(cleanBlob);
|
|
8375
|
+
const canvas = document.createElement("canvas");
|
|
8376
|
+
canvas.width = img.naturalWidth;
|
|
8377
|
+
canvas.height = img.naturalHeight;
|
|
8378
|
+
const ctx = canvas.getContext("2d");
|
|
8379
|
+
ctx.drawImage(img, 0, 0);
|
|
8380
|
+
const w = canvas.width;
|
|
8381
|
+
const h = canvas.height;
|
|
8382
|
+
const markerColor = "#c586ff";
|
|
8383
|
+
const markerBorder = "#ffffff";
|
|
8384
|
+
const fontSize2 = Math.max(12, Math.round(Math.min(w, h) * 0.018));
|
|
8385
|
+
for (const a2 of annotations) {
|
|
8386
|
+
const g = a2.geometry;
|
|
8387
|
+
if (g.kind === "point") {
|
|
8388
|
+
const px = g.x * w;
|
|
8389
|
+
const py = g.y * h;
|
|
8390
|
+
const r = Math.max(7, Math.round(Math.min(w, h) * 8e-3));
|
|
8391
|
+
ctx.beginPath();
|
|
8392
|
+
ctx.arc(px, py, r, 0, Math.PI * 2);
|
|
8393
|
+
ctx.fillStyle = markerColor;
|
|
8394
|
+
ctx.fill();
|
|
8395
|
+
ctx.lineWidth = 2;
|
|
8396
|
+
ctx.strokeStyle = markerBorder;
|
|
8397
|
+
ctx.stroke();
|
|
8398
|
+
drawMarkerLabel(ctx, a2.id, px + r + 2, py - r, fontSize2, markerColor);
|
|
8399
|
+
} else if (g.kind === "area") {
|
|
8400
|
+
const ax = g.x * w;
|
|
8401
|
+
const ay = g.y * h;
|
|
8402
|
+
const aw = g.w * w;
|
|
8403
|
+
const ah = g.h * h;
|
|
8404
|
+
ctx.strokeStyle = markerColor;
|
|
8405
|
+
ctx.lineWidth = 2;
|
|
8406
|
+
ctx.setLineDash([6, 4]);
|
|
8407
|
+
ctx.strokeRect(ax, ay, aw, ah);
|
|
8408
|
+
ctx.setLineDash([]);
|
|
8409
|
+
ctx.fillStyle = "rgba(197, 134, 255, 0.12)";
|
|
8410
|
+
ctx.fillRect(ax, ay, aw, ah);
|
|
8411
|
+
drawMarkerLabel(ctx, a2.id, ax + 4, ay + 4, fontSize2, markerColor);
|
|
8412
|
+
} else if (g.kind === "arrow") {
|
|
8413
|
+
const x1 = g.x1 * w;
|
|
8414
|
+
const y1 = g.y1 * h;
|
|
8415
|
+
const x2 = g.x2 * w;
|
|
8416
|
+
const y2 = g.y2 * h;
|
|
8417
|
+
ctx.strokeStyle = markerColor;
|
|
8418
|
+
ctx.lineWidth = 2;
|
|
8419
|
+
ctx.setLineDash([]);
|
|
8420
|
+
ctx.beginPath();
|
|
8421
|
+
ctx.moveTo(x1, y1);
|
|
8422
|
+
ctx.lineTo(x2, y2);
|
|
8423
|
+
ctx.stroke();
|
|
8424
|
+
drawArrowhead(ctx, x1, y1, x2, y2, 10, markerColor);
|
|
8425
|
+
const pinR = Math.max(11, Math.round(Math.min(w, h) * 0.014));
|
|
8426
|
+
ctx.beginPath();
|
|
8427
|
+
ctx.arc(x2, y2, pinR, 0, Math.PI * 2);
|
|
8428
|
+
ctx.fillStyle = markerColor;
|
|
8429
|
+
ctx.fill();
|
|
8430
|
+
ctx.lineWidth = 2;
|
|
8431
|
+
ctx.strokeStyle = markerBorder;
|
|
8432
|
+
ctx.stroke();
|
|
8433
|
+
ctx.fillStyle = "#1e1e1e";
|
|
8434
|
+
ctx.font = `bold ${Math.round(fontSize2 * 0.9)}px sans-serif`;
|
|
8435
|
+
ctx.textAlign = "center";
|
|
8436
|
+
ctx.textBaseline = "middle";
|
|
8437
|
+
ctx.fillText(a2.id, x2, y2);
|
|
8438
|
+
}
|
|
8439
|
+
}
|
|
8440
|
+
return canvasToPng(canvas);
|
|
8441
|
+
}
|
|
8442
|
+
function drawMarkerLabel(ctx, label, x, y, fontSize2, bgColor) {
|
|
8443
|
+
ctx.font = `bold ${fontSize2}px sans-serif`;
|
|
8444
|
+
const tm = ctx.measureText(label);
|
|
8445
|
+
const pad = 4;
|
|
8446
|
+
const lh = fontSize2 + 4;
|
|
8447
|
+
const lw = Math.max(tm.width + pad * 2, lh);
|
|
8448
|
+
const rx = x;
|
|
8449
|
+
const ry = y;
|
|
8450
|
+
ctx.fillStyle = bgColor;
|
|
8451
|
+
ctx.beginPath();
|
|
8452
|
+
ctx.roundRect(rx, ry, lw, lh, 4);
|
|
8453
|
+
ctx.fill();
|
|
8454
|
+
ctx.fillStyle = "#1e1e1e";
|
|
8455
|
+
ctx.textAlign = "center";
|
|
8456
|
+
ctx.textBaseline = "middle";
|
|
8457
|
+
ctx.fillText(label, rx + lw / 2, ry + lh / 2);
|
|
8458
|
+
}
|
|
8459
|
+
function drawArrowhead(ctx, x1, y1, x2, y2, size, color2) {
|
|
8460
|
+
const angle2 = Math.atan2(y2 - y1, x2 - x1);
|
|
8461
|
+
ctx.fillStyle = color2;
|
|
8462
|
+
ctx.beginPath();
|
|
8463
|
+
ctx.moveTo(x2, y2);
|
|
8464
|
+
ctx.lineTo(
|
|
8465
|
+
x2 - size * Math.cos(angle2 - Math.PI / 6),
|
|
8466
|
+
y2 - size * Math.sin(angle2 - Math.PI / 6)
|
|
8467
|
+
);
|
|
8468
|
+
ctx.lineTo(
|
|
8469
|
+
x2 - size * Math.cos(angle2 + Math.PI / 6),
|
|
8470
|
+
y2 - size * Math.sin(angle2 + Math.PI / 6)
|
|
8471
|
+
);
|
|
8472
|
+
ctx.closePath();
|
|
8473
|
+
ctx.fill();
|
|
8474
|
+
}
|
|
8475
|
+
function blobToImage(blob) {
|
|
8476
|
+
return new Promise((resolve, reject) => {
|
|
8477
|
+
const url = URL.createObjectURL(blob);
|
|
8478
|
+
const img = new Image();
|
|
8479
|
+
img.onload = () => {
|
|
8480
|
+
URL.revokeObjectURL(url);
|
|
8481
|
+
resolve(img);
|
|
8482
|
+
};
|
|
8483
|
+
img.onerror = () => {
|
|
8484
|
+
URL.revokeObjectURL(url);
|
|
8485
|
+
reject(new Error("Failed to load screenshot image for compositing"));
|
|
8486
|
+
};
|
|
8487
|
+
img.src = url;
|
|
8488
|
+
});
|
|
8489
|
+
}
|
|
8286
8490
|
async function captureVideoInstantDual(rootEl, videoEl) {
|
|
8287
8491
|
const clean = await capturePreviewForVideoFrame(rootEl, videoEl, "clean");
|
|
8288
8492
|
const markersOnly = await capturePreviewForVideoFrame(
|
|
@@ -8774,6 +8978,20 @@ function aiditorConstructor(_props, refs) {
|
|
|
8774
8978
|
const [videoRecordingNavLog, setVideoRecordingNavLog] = createSignal([]);
|
|
8775
8979
|
const [recordingDraftAnnotation, setRecordingDraftAnnotation] = createSignal(null);
|
|
8776
8980
|
const [videoPinsStagedDuringRecording, setVideoPinsStagedDuringRecording] = createSignal([]);
|
|
8981
|
+
const [showSnapshotModal, setShowSnapshotModal] = createSignal(false);
|
|
8982
|
+
const [snapshotCapture, setSnapshotCapture] = createSignal(null);
|
|
8983
|
+
const [snapshotAnnotations, setSnapshotAnnotations] = createSignal([]);
|
|
8984
|
+
const [snapshotTool, setSnapshotTool] = createSignal("point");
|
|
8985
|
+
const [snapshotAreaDraft, setSnapshotAreaDraft] = createSignal(null);
|
|
8986
|
+
const [snapshotDiscardConfirm, setSnapshotDiscardConfirm] = createSignal({
|
|
8987
|
+
visible: false
|
|
8988
|
+
});
|
|
8989
|
+
const [snapshotArrowPending, setSnapshotArrowPending] = createSignal(null);
|
|
8990
|
+
const [snapshotSubmitError, setSnapshotSubmitError] = createSignal("");
|
|
8991
|
+
let snapshotAreaDragActive = false;
|
|
8992
|
+
let snapshotAreaStartNorm = { x: 0, y: 0 };
|
|
8993
|
+
let snapshotAreaListeners = null;
|
|
8994
|
+
let snapshotAttachTargetPinId = null;
|
|
8777
8995
|
let areaDragActive = false;
|
|
8778
8996
|
let areaStartNorm = { x: 0, y: 0 };
|
|
8779
8997
|
let areaListeners = null;
|
|
@@ -8790,6 +9008,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
8790
9008
|
let recordingStartedAt = 0;
|
|
8791
9009
|
let recordingPreviewNavLog = [];
|
|
8792
9010
|
let previewProbeTimer = null;
|
|
9011
|
+
let iframeShortcutDoc = null;
|
|
8793
9012
|
let attachVideoTargetPinId = null;
|
|
8794
9013
|
let nextVideoPinSeq = 1;
|
|
8795
9014
|
let recordingArrowCarryFromDraft = null;
|
|
@@ -9210,6 +9429,126 @@ function aiditorConstructor(_props, refs) {
|
|
|
9210
9429
|
return false;
|
|
9211
9430
|
return list.some((a2) => a2.instruction.trim().length === 0);
|
|
9212
9431
|
});
|
|
9432
|
+
const snapshotImageSrc = createMemo(() => snapshotCapture()?.imageUrl ?? "");
|
|
9433
|
+
const snapshotCanSubmit = createMemo(() => snapshotAnnotations().length > 0 && !isRunning());
|
|
9434
|
+
const snapshotShowDiscardConfirm = createMemo(() => snapshotDiscardConfirm().visible);
|
|
9435
|
+
const snapshotToolNoneOn = createMemo(() => snapshotTool() === "none");
|
|
9436
|
+
const snapshotToolPointOn = createMemo(() => snapshotTool() === "point");
|
|
9437
|
+
const snapshotToolAreaOn = createMemo(() => snapshotTool() === "area");
|
|
9438
|
+
const snapshotToolArrowOn = createMemo(() => snapshotTool() === "arrow");
|
|
9439
|
+
const snapshotOverlayPointerNone = createMemo(() => snapshotTool() === "none");
|
|
9440
|
+
const snapshotPointDisplayItems = createMemo(() => {
|
|
9441
|
+
const list = snapshotAnnotations();
|
|
9442
|
+
let pin = 0;
|
|
9443
|
+
const out = [];
|
|
9444
|
+
for (const a2 of list) {
|
|
9445
|
+
pin += 1;
|
|
9446
|
+
if (a2.kind === "point") {
|
|
9447
|
+
out.push({
|
|
9448
|
+
id: a2.id,
|
|
9449
|
+
leftPct: a2.x * 100,
|
|
9450
|
+
topPct: a2.y * 100,
|
|
9451
|
+
indexLabel: String(pin)
|
|
9452
|
+
});
|
|
9453
|
+
}
|
|
9454
|
+
}
|
|
9455
|
+
return out;
|
|
9456
|
+
});
|
|
9457
|
+
const snapshotAreaDisplayItems = createMemo(() => {
|
|
9458
|
+
const list = snapshotAnnotations();
|
|
9459
|
+
let pin = 0;
|
|
9460
|
+
const out = [];
|
|
9461
|
+
for (const a2 of list) {
|
|
9462
|
+
pin += 1;
|
|
9463
|
+
if (a2.kind === "area") {
|
|
9464
|
+
out.push({
|
|
9465
|
+
id: a2.id,
|
|
9466
|
+
leftPct: a2.x * 100,
|
|
9467
|
+
topPct: a2.y * 100,
|
|
9468
|
+
widthPct: a2.w * 100,
|
|
9469
|
+
heightPct: a2.h * 100,
|
|
9470
|
+
indexLabel: String(pin)
|
|
9471
|
+
});
|
|
9472
|
+
}
|
|
9473
|
+
}
|
|
9474
|
+
return out;
|
|
9475
|
+
});
|
|
9476
|
+
const snapshotArrowDisplayItems = createMemo(() => {
|
|
9477
|
+
const list = snapshotAnnotations();
|
|
9478
|
+
const out = [];
|
|
9479
|
+
for (const a2 of list) {
|
|
9480
|
+
if (a2.kind === "arrow") {
|
|
9481
|
+
out.push({
|
|
9482
|
+
id: a2.id,
|
|
9483
|
+
x1Pct: a2.x1 * 100,
|
|
9484
|
+
y1Pct: a2.y1 * 100,
|
|
9485
|
+
x2Pct: a2.x2 * 100,
|
|
9486
|
+
y2Pct: a2.y2 * 100
|
|
9487
|
+
});
|
|
9488
|
+
}
|
|
9489
|
+
}
|
|
9490
|
+
return out;
|
|
9491
|
+
});
|
|
9492
|
+
const snapshotArrowPinItems = createMemo(() => {
|
|
9493
|
+
const list = snapshotAnnotations();
|
|
9494
|
+
let pin = 0;
|
|
9495
|
+
const out = [];
|
|
9496
|
+
for (const a2 of list) {
|
|
9497
|
+
pin += 1;
|
|
9498
|
+
if (a2.kind === "arrow") {
|
|
9499
|
+
out.push({
|
|
9500
|
+
id: a2.id,
|
|
9501
|
+
leftPct: a2.x2 * 100,
|
|
9502
|
+
topPct: a2.y2 * 100,
|
|
9503
|
+
indexLabel: String(pin)
|
|
9504
|
+
});
|
|
9505
|
+
}
|
|
9506
|
+
}
|
|
9507
|
+
return out;
|
|
9508
|
+
});
|
|
9509
|
+
const hasSnapshotArrowLines = createMemo(() => snapshotArrowDisplayItems().length > 0);
|
|
9510
|
+
const showSnapshotArrowPending = createMemo(() => snapshotArrowPending() !== null);
|
|
9511
|
+
const snapshotArrowPendingLeftPct = createMemo(() => (snapshotArrowPending()?.x ?? 0) * 100);
|
|
9512
|
+
const snapshotArrowPendingTopPct = createMemo(() => (snapshotArrowPending()?.y ?? 0) * 100);
|
|
9513
|
+
const snapshotAreaDraftNorm = createMemo(() => {
|
|
9514
|
+
const d = snapshotAreaDraft();
|
|
9515
|
+
if (!d)
|
|
9516
|
+
return null;
|
|
9517
|
+
return normalizeAreaRect(d.startX, d.startY, d.currentX, d.currentY);
|
|
9518
|
+
});
|
|
9519
|
+
const showSnapshotAreaDraft = createMemo(() => snapshotAreaDraftNorm() !== null);
|
|
9520
|
+
const snapshotAreaDraftLeftPct = createMemo(() => (snapshotAreaDraftNorm()?.x ?? 0) * 100);
|
|
9521
|
+
const snapshotAreaDraftTopPct = createMemo(() => (snapshotAreaDraftNorm()?.y ?? 0) * 100);
|
|
9522
|
+
const snapshotAreaDraftWidthPct = createMemo(() => (snapshotAreaDraftNorm()?.w ?? 0) * 100);
|
|
9523
|
+
const snapshotAreaDraftHeightPct = createMemo(() => (snapshotAreaDraftNorm()?.h ?? 0) * 100);
|
|
9524
|
+
const snapshotAnnotationItems = createMemo(() => snapshotAnnotations().map((a2) => {
|
|
9525
|
+
const { nx, ny } = bubbleAnchorNorm(a2);
|
|
9526
|
+
const leftPct = nx * 100;
|
|
9527
|
+
const topPct = ny * 100;
|
|
9528
|
+
const { flipX, flipY } = popoverFlipFromPct(leftPct, topPct);
|
|
9529
|
+
const attachmentChips = a2.attachments.map((at) => ({
|
|
9530
|
+
key: at.id,
|
|
9531
|
+
name: at.file.name,
|
|
9532
|
+
thumbUrl: at.previewUrl && at.file.type.startsWith("image/") ? at.previewUrl : "",
|
|
9533
|
+
annotationId: a2.id
|
|
9534
|
+
}));
|
|
9535
|
+
return {
|
|
9536
|
+
id: a2.id,
|
|
9537
|
+
indexLabel: a2.id,
|
|
9538
|
+
kindLabel: `${a2.id} — ${kindLabel(a2.kind)}`,
|
|
9539
|
+
instruction: a2.instruction,
|
|
9540
|
+
kind: a2.kind,
|
|
9541
|
+
leftPct,
|
|
9542
|
+
topPct,
|
|
9543
|
+
popoverFlipX: flipX,
|
|
9544
|
+
popoverFlipY: flipY,
|
|
9545
|
+
attachmentChips
|
|
9546
|
+
};
|
|
9547
|
+
}));
|
|
9548
|
+
const showSnapshotAnnotationsPanel = createMemo(() => snapshotAnnotations().length > 0);
|
|
9549
|
+
const showSnapshotSubmitError = createMemo(() => snapshotSubmitError().trim().length > 0);
|
|
9550
|
+
const showSnapshotPointMarkers = createMemo(() => snapshotPointDisplayItems().length > 0);
|
|
9551
|
+
const showSnapshotAreaItems = createMemo(() => snapshotAreaDisplayItems().length > 0);
|
|
9213
9552
|
const chunkItems = createMemo(() => chunks());
|
|
9214
9553
|
const hasChunks = createMemo(() => chunks().length > 0);
|
|
9215
9554
|
const outputEmpty = createMemo(() => chunks().length === 0 && !isRunning());
|
|
@@ -9267,6 +9606,8 @@ function aiditorConstructor(_props, refs) {
|
|
|
9267
9606
|
mediaRecorder?.stop();
|
|
9268
9607
|
}
|
|
9269
9608
|
tearDownVideoReviewModal();
|
|
9609
|
+
if (showSnapshotModal())
|
|
9610
|
+
tearDownSnapshotModal();
|
|
9270
9611
|
cancelRecordingDraftAndClear();
|
|
9271
9612
|
setVideoPinsStagedDuringRecording([]);
|
|
9272
9613
|
lastRecordingWallDurationSec = 0;
|
|
@@ -9287,6 +9628,152 @@ function aiditorConstructor(_props, refs) {
|
|
|
9287
9628
|
cancelAreaDragListeners();
|
|
9288
9629
|
setVisualTool(next);
|
|
9289
9630
|
}
|
|
9631
|
+
function cancelSnapshotAreaDragListeners() {
|
|
9632
|
+
snapshotAreaDragActive = false;
|
|
9633
|
+
if (snapshotAreaListeners) {
|
|
9634
|
+
snapshotAreaListeners();
|
|
9635
|
+
snapshotAreaListeners = null;
|
|
9636
|
+
}
|
|
9637
|
+
}
|
|
9638
|
+
function tearDownSnapshotModal() {
|
|
9639
|
+
cancelSnapshotAreaDragListeners();
|
|
9640
|
+
revokeAttachmentUrls(snapshotAnnotations());
|
|
9641
|
+
const cap = snapshotCapture();
|
|
9642
|
+
if (cap?.imageUrl)
|
|
9643
|
+
URL.revokeObjectURL(cap.imageUrl);
|
|
9644
|
+
setSnapshotCapture(null);
|
|
9645
|
+
setSnapshotAnnotations([]);
|
|
9646
|
+
setSnapshotTool("point");
|
|
9647
|
+
setSnapshotAreaDraft(null);
|
|
9648
|
+
setSnapshotArrowPending(null);
|
|
9649
|
+
setSnapshotDiscardConfirm({ visible: false });
|
|
9650
|
+
setSnapshotSubmitError("");
|
|
9651
|
+
setShowSnapshotModal(false);
|
|
9652
|
+
}
|
|
9653
|
+
function onSelectSnapshotTool(next) {
|
|
9654
|
+
setSnapshotArrowPending(null);
|
|
9655
|
+
setSnapshotAreaDraft(null);
|
|
9656
|
+
setSnapshotSubmitError("");
|
|
9657
|
+
cancelSnapshotAreaDragListeners();
|
|
9658
|
+
setSnapshotTool(next);
|
|
9659
|
+
}
|
|
9660
|
+
function setSnapshotAnnotationInstruction(id, instruction) {
|
|
9661
|
+
setSnapshotAnnotations((prev) => prev.map((a2) => a2.id === id ? { ...a2, instruction } : a2));
|
|
9662
|
+
setSnapshotSubmitError("");
|
|
9663
|
+
}
|
|
9664
|
+
function removeSnapshotAnnotation(id) {
|
|
9665
|
+
setSnapshotAnnotations((prev) => {
|
|
9666
|
+
const victim = prev.find((a2) => a2.id === id);
|
|
9667
|
+
if (victim)
|
|
9668
|
+
revokeAttachmentUrls([victim]);
|
|
9669
|
+
return renumberAnnotations(prev.filter((a2) => a2.id !== id));
|
|
9670
|
+
});
|
|
9671
|
+
setSnapshotSubmitError("");
|
|
9672
|
+
}
|
|
9673
|
+
function snapshotUndo() {
|
|
9674
|
+
setSnapshotAnnotations((prev) => {
|
|
9675
|
+
if (prev.length === 0)
|
|
9676
|
+
return prev;
|
|
9677
|
+
const victim = prev[prev.length - 1];
|
|
9678
|
+
revokeAttachmentUrls([victim]);
|
|
9679
|
+
return renumberAnnotations(prev.slice(0, -1));
|
|
9680
|
+
});
|
|
9681
|
+
}
|
|
9682
|
+
function snapshotClearAll() {
|
|
9683
|
+
revokeAttachmentUrls(snapshotAnnotations());
|
|
9684
|
+
setSnapshotAnnotations([]);
|
|
9685
|
+
setSnapshotArrowPending(null);
|
|
9686
|
+
setSnapshotAreaDraft(null);
|
|
9687
|
+
cancelSnapshotAreaDragListeners();
|
|
9688
|
+
}
|
|
9689
|
+
function tryDismissSnapshotModal() {
|
|
9690
|
+
if (snapshotAnnotations().length > 0) {
|
|
9691
|
+
setSnapshotDiscardConfirm({ visible: true });
|
|
9692
|
+
} else {
|
|
9693
|
+
tearDownSnapshotModal();
|
|
9694
|
+
}
|
|
9695
|
+
}
|
|
9696
|
+
function addFilesToSnapshotAnnotation(annotationId, files) {
|
|
9697
|
+
setSnapshotAnnotations((prev) => {
|
|
9698
|
+
const ix = prev.findIndex((a2) => a2.id === annotationId);
|
|
9699
|
+
if (ix < 0)
|
|
9700
|
+
return prev;
|
|
9701
|
+
const ann = prev[ix];
|
|
9702
|
+
let nextAtt = [...ann.attachments];
|
|
9703
|
+
let byteSum = nextAtt.reduce((s, x) => s + x.file.size, 0);
|
|
9704
|
+
for (const file of files) {
|
|
9705
|
+
if (nextAtt.length >= MAX_ATTACHMENTS_PER_PIN) {
|
|
9706
|
+
setSnapshotSubmitError(`Each pin allows at most ${MAX_ATTACHMENTS_PER_PIN} files.`);
|
|
9707
|
+
break;
|
|
9708
|
+
}
|
|
9709
|
+
if (byteSum + file.size > MAX_ATTACHMENT_BYTES_PER_PIN) {
|
|
9710
|
+
setSnapshotSubmitError(`File "${file.name}" is ${mbLabel(file.size)}; max per pin is ${mbLabel(MAX_ATTACHMENT_BYTES_PER_PIN)}.`);
|
|
9711
|
+
break;
|
|
9712
|
+
}
|
|
9713
|
+
const id = newLocalAttachmentId();
|
|
9714
|
+
const loc = { id, file };
|
|
9715
|
+
if (file.type.startsWith("image/")) {
|
|
9716
|
+
loc.previewUrl = URL.createObjectURL(file);
|
|
9717
|
+
}
|
|
9718
|
+
nextAtt = [...nextAtt, loc];
|
|
9719
|
+
byteSum += file.size;
|
|
9720
|
+
}
|
|
9721
|
+
const nextAnn = { ...ann, attachments: nextAtt };
|
|
9722
|
+
const copy = [...prev];
|
|
9723
|
+
copy[ix] = nextAnn;
|
|
9724
|
+
return copy;
|
|
9725
|
+
});
|
|
9726
|
+
}
|
|
9727
|
+
function removeSnapshotAttachmentFile(annotationId, attachmentId) {
|
|
9728
|
+
setSnapshotAnnotations((prev) => {
|
|
9729
|
+
const ix = prev.findIndex((a2) => a2.id === annotationId);
|
|
9730
|
+
if (ix < 0)
|
|
9731
|
+
return prev;
|
|
9732
|
+
const ann = prev[ix];
|
|
9733
|
+
const victim = ann.attachments.find((x) => x.id === attachmentId);
|
|
9734
|
+
if (victim?.previewUrl)
|
|
9735
|
+
URL.revokeObjectURL(victim.previewUrl);
|
|
9736
|
+
const nextAtt = ann.attachments.filter((x) => x.id !== attachmentId);
|
|
9737
|
+
const nextAnn = { ...ann, attachments: nextAtt };
|
|
9738
|
+
const copy = [...prev];
|
|
9739
|
+
copy[ix] = nextAnn;
|
|
9740
|
+
return copy;
|
|
9741
|
+
});
|
|
9742
|
+
}
|
|
9743
|
+
function snapshotNormFromEvent(overlayEl, imgEl, e2) {
|
|
9744
|
+
const imgRect = imgEl.getBoundingClientRect();
|
|
9745
|
+
const imgNaturalAspect = imgEl.naturalWidth / imgEl.naturalHeight;
|
|
9746
|
+
const containerAspect = imgRect.width / imgRect.height;
|
|
9747
|
+
let renderedW, renderedH, offsetX, offsetY;
|
|
9748
|
+
if (imgNaturalAspect > containerAspect) {
|
|
9749
|
+
renderedW = imgRect.width;
|
|
9750
|
+
renderedH = imgRect.width / imgNaturalAspect;
|
|
9751
|
+
offsetX = 0;
|
|
9752
|
+
offsetY = (imgRect.height - renderedH) / 2;
|
|
9753
|
+
} else {
|
|
9754
|
+
renderedH = imgRect.height;
|
|
9755
|
+
renderedW = imgRect.height * imgNaturalAspect;
|
|
9756
|
+
offsetX = (imgRect.width - renderedW) / 2;
|
|
9757
|
+
offsetY = 0;
|
|
9758
|
+
}
|
|
9759
|
+
const imgContentLeft = imgRect.left + offsetX;
|
|
9760
|
+
const imgContentTop = imgRect.top + offsetY;
|
|
9761
|
+
const x = (e2.clientX - imgContentLeft) / renderedW;
|
|
9762
|
+
const y = (e2.clientY - imgContentTop) / renderedH;
|
|
9763
|
+
if (x < 0 || x > 1 || y < 0 || y > 1)
|
|
9764
|
+
return null;
|
|
9765
|
+
return { x, y };
|
|
9766
|
+
}
|
|
9767
|
+
function focusLastSnapshotAnnotationTextarea() {
|
|
9768
|
+
requestAnimationFrame(() => {
|
|
9769
|
+
tryJayRefExec(refs.snapshotBackdrop, (backdrop) => {
|
|
9770
|
+
const textareas = backdrop.querySelectorAll("textarea.visual-annotation-instruction");
|
|
9771
|
+
const last = textareas[textareas.length - 1];
|
|
9772
|
+
if (last)
|
|
9773
|
+
last.focus();
|
|
9774
|
+
});
|
|
9775
|
+
});
|
|
9776
|
+
}
|
|
9290
9777
|
function validateVisualAnnotationsForSubmit() {
|
|
9291
9778
|
const list = visualAnnotations();
|
|
9292
9779
|
if (list.length === 0)
|
|
@@ -9593,6 +10080,24 @@ function aiditorConstructor(_props, refs) {
|
|
|
9593
10080
|
}
|
|
9594
10081
|
runBootstrap();
|
|
9595
10082
|
ensurePreviewProbePoll();
|
|
10083
|
+
function handleSnapshotShortcut() {
|
|
10084
|
+
if (visualTool() !== "none" || !showPreviewIframe() || showSnapshotModal() || showVideoReviewModal() || isVideoRecording())
|
|
10085
|
+
return;
|
|
10086
|
+
void triggerSnapshotCapture();
|
|
10087
|
+
}
|
|
10088
|
+
if (typeof document !== "undefined") {
|
|
10089
|
+
document.addEventListener("keydown", (e2) => {
|
|
10090
|
+
if ((e2.key === "s" || e2.key === "S") && (e2.metaKey || e2.ctrlKey) && e2.shiftKey && !e2.altKey) {
|
|
10091
|
+
e2.preventDefault();
|
|
10092
|
+
handleSnapshotShortcut();
|
|
10093
|
+
}
|
|
10094
|
+
}, true);
|
|
10095
|
+
}
|
|
10096
|
+
if (typeof window !== "undefined") {
|
|
10097
|
+
window.addEventListener("aiditor:snapshot-shortcut", () => {
|
|
10098
|
+
handleSnapshotShortcut();
|
|
10099
|
+
});
|
|
10100
|
+
}
|
|
9596
10101
|
if (typeof window !== "undefined") {
|
|
9597
10102
|
window.addEventListener("message", (e2) => {
|
|
9598
10103
|
if (e2.data?.type === "jay:freeze") {
|
|
@@ -9931,6 +10436,98 @@ function aiditorConstructor(_props, refs) {
|
|
|
9931
10436
|
setIsRunning(false);
|
|
9932
10437
|
}
|
|
9933
10438
|
}
|
|
10439
|
+
async function runSnapshotSubmit() {
|
|
10440
|
+
const list = snapshotAnnotations();
|
|
10441
|
+
if (list.length === 0) {
|
|
10442
|
+
setSnapshotSubmitError("Add at least one marker on the screenshot.");
|
|
10443
|
+
return;
|
|
10444
|
+
}
|
|
10445
|
+
const cap = snapshotCapture();
|
|
10446
|
+
if (!cap) {
|
|
10447
|
+
setSnapshotSubmitError("Screenshot data is missing.");
|
|
10448
|
+
return;
|
|
10449
|
+
}
|
|
10450
|
+
const notesJson = serializeAiditorNotes(toNotesPayload(list, previewBreakpoint()));
|
|
10451
|
+
try {
|
|
10452
|
+
setIsRunning(true);
|
|
10453
|
+
setSnapshotSubmitError("");
|
|
10454
|
+
const markerGeometries = list.map((a2) => ({
|
|
10455
|
+
id: a2.id,
|
|
10456
|
+
geometry: serializeGeometry(a2)
|
|
10457
|
+
}));
|
|
10458
|
+
const markersBlob = await compositeMarkersOntoScreenshot(cap.cleanBlob, markerGeometries);
|
|
10459
|
+
const attachmentsByAnnotationId = /* @__PURE__ */ new Map();
|
|
10460
|
+
for (const a2 of list) {
|
|
10461
|
+
if (a2.attachments.length > 0) {
|
|
10462
|
+
attachmentsByAnnotationId.set(a2.id, a2.attachments.map((x) => x.file));
|
|
10463
|
+
}
|
|
10464
|
+
}
|
|
10465
|
+
const dual = { clean: cap.cleanBlob, markersOnly: markersBlob };
|
|
10466
|
+
const route = cap.routePattern;
|
|
10467
|
+
const rendered = cap.renderedUrl;
|
|
10468
|
+
tearDownSnapshotModal();
|
|
10469
|
+
clearVisualSession();
|
|
10470
|
+
startAgentStream(notesJson, {
|
|
10471
|
+
mode: "multi",
|
|
10472
|
+
pageRoute: route,
|
|
10473
|
+
renderedUrl: rendered,
|
|
10474
|
+
dual,
|
|
10475
|
+
attachmentsByAnnotationId: attachmentsByAnnotationId.size > 0 ? attachmentsByAnnotationId : void 0
|
|
10476
|
+
});
|
|
10477
|
+
} catch (err) {
|
|
10478
|
+
console.error("snapshot submit:", err);
|
|
10479
|
+
setSnapshotSubmitError(err instanceof Error ? err.message : String(err));
|
|
10480
|
+
} finally {
|
|
10481
|
+
setIsRunning(false);
|
|
10482
|
+
}
|
|
10483
|
+
}
|
|
10484
|
+
async function triggerSnapshotCapture() {
|
|
10485
|
+
if (showSnapshotModal() || isRunning())
|
|
10486
|
+
return;
|
|
10487
|
+
const route = selectedPageUrl();
|
|
10488
|
+
const rendered = previewUrlBar().trim();
|
|
10489
|
+
if (!route || !rendered)
|
|
10490
|
+
return;
|
|
10491
|
+
if (!previewIsSameOriginForCapture(previewSrc()))
|
|
10492
|
+
return;
|
|
10493
|
+
let rootEl = null;
|
|
10494
|
+
tryJayRefExec(refs.previewCaptureRoot, (el) => {
|
|
10495
|
+
rootEl = el;
|
|
10496
|
+
});
|
|
10497
|
+
if (!rootEl)
|
|
10498
|
+
return;
|
|
10499
|
+
let iframeEl = null;
|
|
10500
|
+
tryJayRefExec(refs.previewIframe, (el) => {
|
|
10501
|
+
iframeEl = el;
|
|
10502
|
+
});
|
|
10503
|
+
try {
|
|
10504
|
+
const unfreeze = iframeEl ? freezeTransientStyles(iframeEl) : () => {
|
|
10505
|
+
};
|
|
10506
|
+
let cleanBlob;
|
|
10507
|
+
try {
|
|
10508
|
+
cleanBlob = await capturePreviewForTask(rootEl, "clean");
|
|
10509
|
+
} finally {
|
|
10510
|
+
unfreeze();
|
|
10511
|
+
}
|
|
10512
|
+
const imageUrl = URL.createObjectURL(cleanBlob);
|
|
10513
|
+
setSnapshotCapture({
|
|
10514
|
+
cleanBlob,
|
|
10515
|
+
imageUrl,
|
|
10516
|
+
previewUrl: rendered,
|
|
10517
|
+
routePattern: route,
|
|
10518
|
+
renderedUrl: rendered
|
|
10519
|
+
});
|
|
10520
|
+
setSnapshotAnnotations([]);
|
|
10521
|
+
setSnapshotTool("point");
|
|
10522
|
+
setSnapshotAreaDraft(null);
|
|
10523
|
+
setSnapshotArrowPending(null);
|
|
10524
|
+
setSnapshotDiscardConfirm({ visible: false });
|
|
10525
|
+
setSnapshotSubmitError("");
|
|
10526
|
+
setShowSnapshotModal(true);
|
|
10527
|
+
} catch (err) {
|
|
10528
|
+
console.error("[aiditor] snapshot capture failed:", err);
|
|
10529
|
+
}
|
|
10530
|
+
}
|
|
9934
10531
|
function formatClock(sec) {
|
|
9935
10532
|
if (!Number.isFinite(sec))
|
|
9936
10533
|
return "0:00";
|
|
@@ -9987,6 +10584,26 @@ function aiditorConstructor(_props, refs) {
|
|
|
9987
10584
|
}
|
|
9988
10585
|
}
|
|
9989
10586
|
}
|
|
10587
|
+
function ensureIframeShortcutForwarder() {
|
|
10588
|
+
tryJayRefExec(refs.previewIframe, (fr) => {
|
|
10589
|
+
const iframe = fr;
|
|
10590
|
+
try {
|
|
10591
|
+
const doc = iframe.contentDocument;
|
|
10592
|
+
if (!doc)
|
|
10593
|
+
return;
|
|
10594
|
+
if (iframeShortcutDoc?.deref() === doc)
|
|
10595
|
+
return;
|
|
10596
|
+
iframeShortcutDoc = new WeakRef(doc);
|
|
10597
|
+
doc.addEventListener("keydown", (e2) => {
|
|
10598
|
+
if ((e2.key === "s" || e2.key === "S") && (e2.metaKey || e2.ctrlKey) && e2.shiftKey && !e2.altKey) {
|
|
10599
|
+
e2.preventDefault();
|
|
10600
|
+
window.dispatchEvent(new CustomEvent("aiditor:snapshot-shortcut"));
|
|
10601
|
+
}
|
|
10602
|
+
}, true);
|
|
10603
|
+
} catch {
|
|
10604
|
+
}
|
|
10605
|
+
});
|
|
10606
|
+
}
|
|
9990
10607
|
function tickPreviewIframeProbe() {
|
|
9991
10608
|
if (!isPreviewMode() || previewLoading())
|
|
9992
10609
|
return;
|
|
@@ -9995,6 +10612,7 @@ function aiditorConstructor(_props, refs) {
|
|
|
9995
10612
|
const src = previewSrc();
|
|
9996
10613
|
if (!src || !previewIsSameOriginForCapture(src))
|
|
9997
10614
|
return;
|
|
10615
|
+
ensureIframeShortcutForwarder();
|
|
9998
10616
|
tryJayRefExec(refs.previewIframe, (fr) => {
|
|
9999
10617
|
const iframe = fr;
|
|
10000
10618
|
try {
|
|
@@ -10798,9 +11416,236 @@ function aiditorConstructor(_props, refs) {
|
|
|
10798
11416
|
tryJayRefExec(refs.videoReviewCloseBtn, (b) => b.click());
|
|
10799
11417
|
}
|
|
10800
11418
|
});
|
|
11419
|
+
refs.snapshotToolPointBtn.onclick(() => onSelectSnapshotTool("point"));
|
|
11420
|
+
refs.snapshotToolAreaBtn.onclick(() => onSelectSnapshotTool("area"));
|
|
11421
|
+
refs.snapshotToolArrowBtn.onclick(() => onSelectSnapshotTool("arrow"));
|
|
11422
|
+
refs.snapshotToolNoneBtn.onclick(() => onSelectSnapshotTool("none"));
|
|
11423
|
+
refs.snapshotUndoBtn.onclick(() => snapshotUndo());
|
|
11424
|
+
refs.snapshotClearBtn.onclick(() => {
|
|
11425
|
+
if (snapshotAnnotations().length > 2) {
|
|
11426
|
+
if (!window.confirm("Clear all markers?"))
|
|
11427
|
+
return;
|
|
11428
|
+
}
|
|
11429
|
+
snapshotClearAll();
|
|
11430
|
+
});
|
|
11431
|
+
refs.snapshotCloseBtn.onclick(() => tryDismissSnapshotModal());
|
|
11432
|
+
refs.snapshotCancelBtn.onclick(() => tryDismissSnapshotModal());
|
|
11433
|
+
refs.snapshotDiscardBtn.onclick(() => tearDownSnapshotModal());
|
|
11434
|
+
refs.snapshotKeepEditingBtn.onclick(() => setSnapshotDiscardConfirm({ visible: false }));
|
|
11435
|
+
refs.snapshotSendBtn.onclick(() => {
|
|
11436
|
+
void runSnapshotSubmit();
|
|
11437
|
+
});
|
|
11438
|
+
refs.snapshotBackdrop.onkeydown(({ event }) => {
|
|
11439
|
+
if (event.key === "Escape") {
|
|
11440
|
+
event.preventDefault();
|
|
11441
|
+
tryDismissSnapshotModal();
|
|
11442
|
+
return;
|
|
11443
|
+
}
|
|
11444
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
|
|
11445
|
+
event.preventDefault();
|
|
11446
|
+
if (snapshotCanSubmit())
|
|
11447
|
+
void runSnapshotSubmit();
|
|
11448
|
+
return;
|
|
11449
|
+
}
|
|
11450
|
+
});
|
|
11451
|
+
refs.snapshotOverlay.onmousedown(({ event }) => {
|
|
11452
|
+
const mode = snapshotTool();
|
|
11453
|
+
if (mode !== "area")
|
|
11454
|
+
return;
|
|
11455
|
+
const el = event.currentTarget;
|
|
11456
|
+
let imgEl = null;
|
|
11457
|
+
tryJayRefExec(refs.snapshotImg, (img) => {
|
|
11458
|
+
imgEl = img;
|
|
11459
|
+
});
|
|
11460
|
+
if (!imgEl)
|
|
11461
|
+
return;
|
|
11462
|
+
const n = snapshotNormFromEvent(el, imgEl, event);
|
|
11463
|
+
if (!n)
|
|
11464
|
+
return;
|
|
11465
|
+
event.preventDefault();
|
|
11466
|
+
snapshotAreaDragActive = true;
|
|
11467
|
+
snapshotAreaStartNorm = { x: n.x, y: n.y };
|
|
11468
|
+
setSnapshotAreaDraft({
|
|
11469
|
+
startX: n.x,
|
|
11470
|
+
startY: n.y,
|
|
11471
|
+
currentX: n.x,
|
|
11472
|
+
currentY: n.y
|
|
11473
|
+
});
|
|
11474
|
+
const move = (ev) => {
|
|
11475
|
+
if (!snapshotAreaDragActive || !imgEl)
|
|
11476
|
+
return;
|
|
11477
|
+
const cur = snapshotNormFromEvent(el, imgEl, ev);
|
|
11478
|
+
if (!cur)
|
|
11479
|
+
return;
|
|
11480
|
+
setSnapshotAreaDraft({
|
|
11481
|
+
startX: snapshotAreaStartNorm.x,
|
|
11482
|
+
startY: snapshotAreaStartNorm.y,
|
|
11483
|
+
currentX: cur.x,
|
|
11484
|
+
currentY: cur.y
|
|
11485
|
+
});
|
|
11486
|
+
};
|
|
11487
|
+
const up = (ev) => {
|
|
11488
|
+
if (!snapshotAreaDragActive || !imgEl)
|
|
11489
|
+
return;
|
|
11490
|
+
snapshotAreaDragActive = false;
|
|
11491
|
+
document.removeEventListener("mousemove", move);
|
|
11492
|
+
document.removeEventListener("mouseup", up);
|
|
11493
|
+
snapshotAreaListeners = null;
|
|
11494
|
+
const cur = snapshotNormFromEvent(el, imgEl, ev);
|
|
11495
|
+
if (cur) {
|
|
11496
|
+
const r = normalizeAreaRect(snapshotAreaStartNorm.x, snapshotAreaStartNorm.y, cur.x, cur.y);
|
|
11497
|
+
if (r.w > 8e-3 && r.h > 8e-3) {
|
|
11498
|
+
setSnapshotAnnotations((prev) => renumberAnnotations([
|
|
11499
|
+
...prev,
|
|
11500
|
+
{
|
|
11501
|
+
id: "_",
|
|
11502
|
+
kind: "area",
|
|
11503
|
+
...r,
|
|
11504
|
+
instruction: "",
|
|
11505
|
+
attachments: []
|
|
11506
|
+
}
|
|
11507
|
+
]));
|
|
11508
|
+
setSnapshotSubmitError("");
|
|
11509
|
+
focusLastSnapshotAnnotationTextarea();
|
|
11510
|
+
}
|
|
11511
|
+
}
|
|
11512
|
+
setSnapshotAreaDraft(null);
|
|
11513
|
+
};
|
|
11514
|
+
document.addEventListener("mousemove", move);
|
|
11515
|
+
document.addEventListener("mouseup", up);
|
|
11516
|
+
snapshotAreaListeners = () => {
|
|
11517
|
+
document.removeEventListener("mousemove", move);
|
|
11518
|
+
document.removeEventListener("mouseup", up);
|
|
11519
|
+
};
|
|
11520
|
+
});
|
|
11521
|
+
refs.snapshotOverlay.onclick(({ event }) => {
|
|
11522
|
+
const mode = snapshotTool();
|
|
11523
|
+
if (mode === "area")
|
|
11524
|
+
return;
|
|
11525
|
+
const el = event.currentTarget;
|
|
11526
|
+
let imgEl = null;
|
|
11527
|
+
tryJayRefExec(refs.snapshotImg, (img) => {
|
|
11528
|
+
imgEl = img;
|
|
11529
|
+
});
|
|
11530
|
+
if (!imgEl)
|
|
11531
|
+
return;
|
|
11532
|
+
const n = snapshotNormFromEvent(el, imgEl, event);
|
|
11533
|
+
if (!n)
|
|
11534
|
+
return;
|
|
11535
|
+
if (mode === "point") {
|
|
11536
|
+
setSnapshotAnnotations((prev) => renumberAnnotations([
|
|
11537
|
+
...prev,
|
|
11538
|
+
{
|
|
11539
|
+
id: "_",
|
|
11540
|
+
kind: "point",
|
|
11541
|
+
x: n.x,
|
|
11542
|
+
y: n.y,
|
|
11543
|
+
instruction: "",
|
|
11544
|
+
attachments: []
|
|
11545
|
+
}
|
|
11546
|
+
]));
|
|
11547
|
+
setSnapshotSubmitError("");
|
|
11548
|
+
focusLastSnapshotAnnotationTextarea();
|
|
11549
|
+
} else if (mode === "arrow") {
|
|
11550
|
+
const pending = snapshotArrowPending();
|
|
11551
|
+
if (!pending) {
|
|
11552
|
+
setSnapshotArrowPending(n);
|
|
11553
|
+
} else {
|
|
11554
|
+
const ln = { x1: pending.x, y1: pending.y, x2: n.x, y2: n.y };
|
|
11555
|
+
setSnapshotArrowPending(null);
|
|
11556
|
+
setSnapshotAnnotations((prev) => renumberAnnotations([
|
|
11557
|
+
...prev,
|
|
11558
|
+
{
|
|
11559
|
+
id: "_",
|
|
11560
|
+
kind: "arrow",
|
|
11561
|
+
...ln,
|
|
11562
|
+
instruction: "",
|
|
11563
|
+
attachments: []
|
|
11564
|
+
}
|
|
11565
|
+
]));
|
|
11566
|
+
setSnapshotSubmitError("");
|
|
11567
|
+
focusLastSnapshotAnnotationTextarea();
|
|
11568
|
+
}
|
|
11569
|
+
}
|
|
11570
|
+
});
|
|
11571
|
+
refs.snapshotAnnotationItems.snapshotAnnotationRow.oninput(({ event }) => {
|
|
11572
|
+
const t = event.target;
|
|
11573
|
+
if (t.tagName !== "TEXTAREA" || !t.classList.contains("visual-annotation-instruction"))
|
|
11574
|
+
return;
|
|
11575
|
+
const id = t.dataset.annotationId;
|
|
11576
|
+
if (!id)
|
|
11577
|
+
return;
|
|
11578
|
+
setSnapshotAnnotationInstruction(id, t.value);
|
|
11579
|
+
});
|
|
11580
|
+
refs.snapshotAnnotationItems.snapshotAnnotationRow.onkeydown(({ event }) => {
|
|
11581
|
+
const t = event.target;
|
|
11582
|
+
if (t.tagName !== "TEXTAREA" || !t.classList.contains("visual-annotation-instruction"))
|
|
11583
|
+
return;
|
|
11584
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
|
|
11585
|
+
event.preventDefault();
|
|
11586
|
+
if (snapshotCanSubmit())
|
|
11587
|
+
void runSnapshotSubmit();
|
|
11588
|
+
} else if (event.key === "Escape") {
|
|
11589
|
+
event.preventDefault();
|
|
11590
|
+
const id = t.dataset.annotationId;
|
|
11591
|
+
if (id)
|
|
11592
|
+
removeSnapshotAnnotation(id);
|
|
11593
|
+
}
|
|
11594
|
+
});
|
|
11595
|
+
refs.snapshotAnnotationItems.snapshotAnnotationRow.onclick(({ event }) => {
|
|
11596
|
+
const btn = event.target.closest("button");
|
|
11597
|
+
if (!btn)
|
|
11598
|
+
return;
|
|
11599
|
+
if (btn.classList.contains("snapshot-annotation-remove")) {
|
|
11600
|
+
event.preventDefault();
|
|
11601
|
+
const card = btn.closest("[data-annotation-id]");
|
|
11602
|
+
const id = card?.getAttribute("data-annotation-id");
|
|
11603
|
+
if (id)
|
|
11604
|
+
removeSnapshotAnnotation(id);
|
|
11605
|
+
return;
|
|
11606
|
+
}
|
|
11607
|
+
if (btn.classList.contains("snapshot-annotation-attach")) {
|
|
11608
|
+
event.preventDefault();
|
|
11609
|
+
const id = btn.dataset.annotationId;
|
|
11610
|
+
if (!id)
|
|
11611
|
+
return;
|
|
11612
|
+
snapshotAttachTargetPinId = id;
|
|
11613
|
+
tryJayRefExec(refs.snapshotAttachFileInput, (inp) => inp.click());
|
|
11614
|
+
return;
|
|
11615
|
+
}
|
|
11616
|
+
if (btn.classList.contains("visual-attachment-remove-file")) {
|
|
11617
|
+
event.preventDefault();
|
|
11618
|
+
const aid = btn.dataset.annotationId;
|
|
11619
|
+
const key = btn.dataset.attKey;
|
|
11620
|
+
if (aid && key)
|
|
11621
|
+
removeSnapshotAttachmentFile(aid, key);
|
|
11622
|
+
return;
|
|
11623
|
+
}
|
|
11624
|
+
});
|
|
11625
|
+
refs.snapshotAttachFileInput.onchange(({ event }) => {
|
|
11626
|
+
const inp = event.target;
|
|
11627
|
+
const files = inp.files;
|
|
11628
|
+
const pin = snapshotAttachTargetPinId;
|
|
11629
|
+
snapshotAttachTargetPinId = null;
|
|
11630
|
+
if (!pin || !files?.length)
|
|
11631
|
+
return;
|
|
11632
|
+
addFilesToSnapshotAnnotation(pin, Array.from(files));
|
|
11633
|
+
inp.value = "";
|
|
11634
|
+
});
|
|
11635
|
+
createEffect(() => {
|
|
11636
|
+
if (showSnapshotModal()) {
|
|
11637
|
+
requestAnimationFrame(() => {
|
|
11638
|
+
tryJayRefExec(refs.snapshotBackdrop, (el) => el.focus());
|
|
11639
|
+
});
|
|
11640
|
+
}
|
|
11641
|
+
});
|
|
10801
11642
|
function routePastedFilesToAnnotationField(id, ta, files) {
|
|
10802
11643
|
if (files.length === 0)
|
|
10803
11644
|
return;
|
|
11645
|
+
if (ta.closest(".snapshot-panel")) {
|
|
11646
|
+
addFilesToSnapshotAnnotation(id, files);
|
|
11647
|
+
return;
|
|
11648
|
+
}
|
|
10804
11649
|
if (ta.closest(".video-review-capture-root")) {
|
|
10805
11650
|
addFilesToVideoAnnotation(id, files);
|
|
10806
11651
|
return;
|
|
@@ -11039,7 +11884,35 @@ function aiditorConstructor(_props, refs) {
|
|
|
11039
11884
|
videoPlayPauseGlyph,
|
|
11040
11885
|
breakpointDesktopOn,
|
|
11041
11886
|
breakpointTabletOn,
|
|
11042
|
-
breakpointMobileOn
|
|
11887
|
+
breakpointMobileOn,
|
|
11888
|
+
showSnapshotModal,
|
|
11889
|
+
snapshotImageSrc,
|
|
11890
|
+
snapshotToolNoneOn,
|
|
11891
|
+
snapshotToolPointOn,
|
|
11892
|
+
snapshotToolAreaOn,
|
|
11893
|
+
snapshotToolArrowOn,
|
|
11894
|
+
snapshotCanSubmit,
|
|
11895
|
+
snapshotShowDiscardConfirm,
|
|
11896
|
+
snapshotOverlayPointerNone,
|
|
11897
|
+
snapshotPointDisplayItems,
|
|
11898
|
+
showSnapshotPointMarkers,
|
|
11899
|
+
snapshotAreaDisplayItems,
|
|
11900
|
+
showSnapshotAreaItems,
|
|
11901
|
+
snapshotAreaDraftLeftPct,
|
|
11902
|
+
snapshotAreaDraftTopPct,
|
|
11903
|
+
snapshotAreaDraftWidthPct,
|
|
11904
|
+
snapshotAreaDraftHeightPct,
|
|
11905
|
+
showSnapshotAreaDraft,
|
|
11906
|
+
snapshotArrowDisplayItems,
|
|
11907
|
+
snapshotArrowPinItems,
|
|
11908
|
+
hasSnapshotArrowLines,
|
|
11909
|
+
showSnapshotArrowPending,
|
|
11910
|
+
snapshotArrowPendingLeftPct,
|
|
11911
|
+
snapshotArrowPendingTopPct,
|
|
11912
|
+
snapshotAnnotationItems,
|
|
11913
|
+
showSnapshotAnnotationsPanel,
|
|
11914
|
+
showSnapshotSubmitError,
|
|
11915
|
+
snapshotSubmitError
|
|
11043
11916
|
})
|
|
11044
11917
|
};
|
|
11045
11918
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -152,6 +152,57 @@ interface VideoTimelineMarkerOfPageViewState {
|
|
|
152
152
|
label: string
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
interface SnapshotPointDisplayItemOfPageViewState {
|
|
156
|
+
id: string,
|
|
157
|
+
leftPct: number,
|
|
158
|
+
topPct: number,
|
|
159
|
+
indexLabel: string
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
interface SnapshotAreaDisplayItemOfPageViewState {
|
|
163
|
+
id: string,
|
|
164
|
+
leftPct: number,
|
|
165
|
+
topPct: number,
|
|
166
|
+
widthPct: number,
|
|
167
|
+
heightPct: number,
|
|
168
|
+
indexLabel: string
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
interface SnapshotArrowDisplayItemOfPageViewState {
|
|
172
|
+
id: string,
|
|
173
|
+
x1Pct: number,
|
|
174
|
+
y1Pct: number,
|
|
175
|
+
x2Pct: number,
|
|
176
|
+
y2Pct: number
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
interface SnapshotArrowPinItemOfPageViewState {
|
|
180
|
+
id: string,
|
|
181
|
+
leftPct: number,
|
|
182
|
+
topPct: number,
|
|
183
|
+
indexLabel: string
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
interface AttachmentChipOfSnapshotAnnotationItemOfPageViewState {
|
|
187
|
+
key: string,
|
|
188
|
+
name: string,
|
|
189
|
+
thumbUrl: string,
|
|
190
|
+
annotationId: string
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
interface SnapshotAnnotationItemOfPageViewState {
|
|
194
|
+
id: string,
|
|
195
|
+
indexLabel: string,
|
|
196
|
+
kindLabel: string,
|
|
197
|
+
instruction: string,
|
|
198
|
+
kind: string,
|
|
199
|
+
leftPct: number,
|
|
200
|
+
topPct: number,
|
|
201
|
+
popoverFlipX: boolean,
|
|
202
|
+
popoverFlipY: boolean,
|
|
203
|
+
attachmentChips: Array<AttachmentChipOfSnapshotAnnotationItemOfPageViewState>
|
|
204
|
+
}
|
|
205
|
+
|
|
155
206
|
interface PageViewState {
|
|
156
207
|
isBootstrapping: boolean,
|
|
157
208
|
showBootstrapError: boolean,
|
|
@@ -262,7 +313,35 @@ interface PageViewState {
|
|
|
262
313
|
videoPlayPauseGlyph: string,
|
|
263
314
|
breakpointDesktopOn: boolean,
|
|
264
315
|
breakpointTabletOn: boolean,
|
|
265
|
-
breakpointMobileOn: boolean
|
|
316
|
+
breakpointMobileOn: boolean,
|
|
317
|
+
showSnapshotModal: boolean,
|
|
318
|
+
snapshotImageSrc: string,
|
|
319
|
+
snapshotToolNoneOn: boolean,
|
|
320
|
+
snapshotToolPointOn: boolean,
|
|
321
|
+
snapshotToolAreaOn: boolean,
|
|
322
|
+
snapshotToolArrowOn: boolean,
|
|
323
|
+
snapshotCanSubmit: boolean,
|
|
324
|
+
snapshotShowDiscardConfirm: boolean,
|
|
325
|
+
snapshotOverlayPointerNone: boolean,
|
|
326
|
+
snapshotPointDisplayItems: Array<SnapshotPointDisplayItemOfPageViewState>,
|
|
327
|
+
showSnapshotPointMarkers: boolean,
|
|
328
|
+
snapshotAreaDisplayItems: Array<SnapshotAreaDisplayItemOfPageViewState>,
|
|
329
|
+
showSnapshotAreaItems: boolean,
|
|
330
|
+
snapshotAreaDraftLeftPct: number,
|
|
331
|
+
snapshotAreaDraftTopPct: number,
|
|
332
|
+
snapshotAreaDraftWidthPct: number,
|
|
333
|
+
snapshotAreaDraftHeightPct: number,
|
|
334
|
+
showSnapshotAreaDraft: boolean,
|
|
335
|
+
snapshotArrowDisplayItems: Array<SnapshotArrowDisplayItemOfPageViewState>,
|
|
336
|
+
snapshotArrowPinItems: Array<SnapshotArrowPinItemOfPageViewState>,
|
|
337
|
+
hasSnapshotArrowLines: boolean,
|
|
338
|
+
showSnapshotArrowPending: boolean,
|
|
339
|
+
snapshotArrowPendingLeftPct: number,
|
|
340
|
+
snapshotArrowPendingTopPct: number,
|
|
341
|
+
snapshotAnnotationItems: Array<SnapshotAnnotationItemOfPageViewState>,
|
|
342
|
+
showSnapshotAnnotationsPanel: boolean,
|
|
343
|
+
showSnapshotSubmitError: boolean,
|
|
344
|
+
snapshotSubmitError: string
|
|
266
345
|
}
|
|
267
346
|
|
|
268
347
|
|
|
@@ -306,11 +385,29 @@ interface PageElementRefs {
|
|
|
306
385
|
videoReviewDiscardBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
307
386
|
videoReviewSendBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
308
387
|
videoReviewBackdrop: HTMLElementProxy<PageViewState, HTMLDivElement>,
|
|
388
|
+
snapshotCloseBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
389
|
+
snapshotToolPointBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
390
|
+
snapshotToolAreaBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
391
|
+
snapshotToolArrowBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
392
|
+
snapshotToolNoneBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
393
|
+
snapshotUndoBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
394
|
+
snapshotClearBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
395
|
+
snapshotAttachFileInput: HTMLElementProxy<PageViewState, HTMLInputElement>,
|
|
396
|
+
snapshotImg: HTMLElementProxy<PageViewState, HTMLImageElement>,
|
|
397
|
+
snapshotOverlay: HTMLElementProxy<PageViewState, HTMLDivElement>,
|
|
398
|
+
snapshotDiscardBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
399
|
+
snapshotKeepEditingBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
400
|
+
snapshotCancelBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
401
|
+
snapshotSendBtn: HTMLElementProxy<PageViewState, HTMLButtonElement>,
|
|
402
|
+
snapshotBackdrop: HTMLElementProxy<PageViewState, HTMLDivElement>,
|
|
309
403
|
visualAnnotationRows: {
|
|
310
404
|
annotationRow: HTMLElementCollectionProxy<VisualAnnotationRowOfPageViewState, HTMLDivElement>
|
|
311
405
|
},
|
|
312
406
|
videoAnnotationRows: {
|
|
313
407
|
videoAnnotationRow: HTMLElementCollectionProxy<VideoAnnotationRowOfPageViewState, HTMLDivElement>
|
|
408
|
+
},
|
|
409
|
+
snapshotAnnotationItems: {
|
|
410
|
+
snapshotAnnotationRow: HTMLElementCollectionProxy<SnapshotAnnotationItemOfPageViewState, HTMLDivElement>
|
|
314
411
|
}
|
|
315
412
|
}
|
|
316
413
|
|
|
@@ -146,6 +146,34 @@
|
|
|
146
146
|
.video-review-primary { background: #0e639c; color: #fff; border: none; border-radius: 6px; padding: 8px 18px; font-size: 13px; cursor: pointer; }
|
|
147
147
|
.video-review-primary:hover { background: #1177bb; }
|
|
148
148
|
.video-review-primary:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
149
|
+
.snapshot-overlay { position: fixed; inset: 0; z-index: 200; background: rgba(0,0,0,0.78); display: flex; align-items: center; justify-content: center; padding: 20px; box-sizing: border-box; }
|
|
150
|
+
.snapshot-panel { background: #252526; border: 1px solid #3e3e3e; border-radius: 10px; width: min(1200px, 96vw); max-height: 94vh; display: flex; flex-direction: column; gap: 10px; padding: 14px 16px; overflow: hidden; }
|
|
151
|
+
.snapshot-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-shrink: 0; }
|
|
152
|
+
.snapshot-title { font-size: 15px; font-weight: 600; color: #9cdcfe; margin: 0; }
|
|
153
|
+
.snapshot-close { background: none; border: none; color: #888; font-size: 18px; cursor: pointer; padding: 0 4px; line-height: 1; }
|
|
154
|
+
.snapshot-close:hover { color: #fff; }
|
|
155
|
+
.snapshot-tools { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; flex-shrink: 0; }
|
|
156
|
+
.snapshot-body { display: flex; gap: 14px; flex: 1; min-height: 0; overflow: hidden; }
|
|
157
|
+
.snapshot-capture-area { flex: 2; min-width: 0; position: relative; display: flex; align-items: center; justify-content: center; background: #1e1e1e; border-radius: 8px; overflow: hidden; }
|
|
158
|
+
.snapshot-img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; user-select: none; -webkit-user-drag: none; }
|
|
159
|
+
.snapshot-img-overlay { position: absolute; inset: 0; z-index: 2; }
|
|
160
|
+
.snapshot-img-overlay-none { pointer-events: none; }
|
|
161
|
+
.snapshot-annotations-panel { flex: 1; min-width: 220px; max-width: 340px; display: flex; flex-direction: column; gap: 8px; overflow-y: auto; }
|
|
162
|
+
.snapshot-annotation-card { background: #1e1e1e; border: 1px solid #3e3e3e; border-radius: 8px; padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; }
|
|
163
|
+
.snapshot-annotation-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
164
|
+
.snapshot-annotation-kind { font-size: 11px; color: #9cdcfe; font-weight: 600; }
|
|
165
|
+
.snapshot-annotation-remove { background: transparent; color: #888; border: 1px solid #3e3e3e; border-radius: 4px; padding: 4px 8px; font-size: 11px; cursor: pointer; }
|
|
166
|
+
.snapshot-annotation-remove:hover { color: #f48771; border-color: #f48771; }
|
|
167
|
+
.snapshot-empty-hint { color: #888; font-size: 12px; font-style: italic; padding: 8px 0; }
|
|
168
|
+
.snapshot-footer { display: flex; gap: 10px; justify-content: flex-end; align-items: center; flex-wrap: wrap; flex-shrink: 0; margin-top: 4px; }
|
|
169
|
+
.snapshot-secondary { background: #3c3c3c; color: #ddd; border: 1px solid #555; border-radius: 6px; padding: 8px 16px; font-size: 13px; cursor: pointer; }
|
|
170
|
+
.snapshot-secondary:hover { background: #4a4a4a; }
|
|
171
|
+
.snapshot-primary { background: #0e639c; color: #fff; border: none; border-radius: 6px; padding: 8px 18px; font-size: 13px; cursor: pointer; }
|
|
172
|
+
.snapshot-primary:hover { background: #1177bb; }
|
|
173
|
+
.snapshot-primary:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
174
|
+
.snapshot-discard-confirm { display: flex; align-items: center; gap: 10px; font-size: 13px; color: #f48771; }
|
|
175
|
+
.snapshot-discard-confirm-msg { flex: 1; }
|
|
176
|
+
.snapshot-overlay .arrow-svg line { marker-end: url(#aiditor-snapshot-arrowhead); }
|
|
149
177
|
</style>
|
|
150
178
|
<script type="application/jay-data">
|
|
151
179
|
data:
|
|
@@ -350,6 +378,67 @@ data:
|
|
|
350
378
|
breakpointDesktopOn: boolean
|
|
351
379
|
breakpointTabletOn: boolean
|
|
352
380
|
breakpointMobileOn: boolean
|
|
381
|
+
showSnapshotModal: boolean
|
|
382
|
+
snapshotImageSrc: string
|
|
383
|
+
snapshotToolNoneOn: boolean
|
|
384
|
+
snapshotToolPointOn: boolean
|
|
385
|
+
snapshotToolAreaOn: boolean
|
|
386
|
+
snapshotToolArrowOn: boolean
|
|
387
|
+
snapshotCanSubmit: boolean
|
|
388
|
+
snapshotShowDiscardConfirm: boolean
|
|
389
|
+
snapshotOverlayPointerNone: boolean
|
|
390
|
+
snapshotPointDisplayItems:
|
|
391
|
+
- id: string
|
|
392
|
+
leftPct: number
|
|
393
|
+
topPct: number
|
|
394
|
+
indexLabel: string
|
|
395
|
+
showSnapshotPointMarkers: boolean
|
|
396
|
+
snapshotAreaDisplayItems:
|
|
397
|
+
- id: string
|
|
398
|
+
leftPct: number
|
|
399
|
+
topPct: number
|
|
400
|
+
widthPct: number
|
|
401
|
+
heightPct: number
|
|
402
|
+
indexLabel: string
|
|
403
|
+
showSnapshotAreaItems: boolean
|
|
404
|
+
snapshotAreaDraftLeftPct: number
|
|
405
|
+
snapshotAreaDraftTopPct: number
|
|
406
|
+
snapshotAreaDraftWidthPct: number
|
|
407
|
+
snapshotAreaDraftHeightPct: number
|
|
408
|
+
showSnapshotAreaDraft: boolean
|
|
409
|
+
snapshotArrowDisplayItems:
|
|
410
|
+
- id: string
|
|
411
|
+
x1Pct: number
|
|
412
|
+
y1Pct: number
|
|
413
|
+
x2Pct: number
|
|
414
|
+
y2Pct: number
|
|
415
|
+
snapshotArrowPinItems:
|
|
416
|
+
- id: string
|
|
417
|
+
leftPct: number
|
|
418
|
+
topPct: number
|
|
419
|
+
indexLabel: string
|
|
420
|
+
hasSnapshotArrowLines: boolean
|
|
421
|
+
showSnapshotArrowPending: boolean
|
|
422
|
+
snapshotArrowPendingLeftPct: number
|
|
423
|
+
snapshotArrowPendingTopPct: number
|
|
424
|
+
snapshotAnnotationItems:
|
|
425
|
+
- id: string
|
|
426
|
+
indexLabel: string
|
|
427
|
+
kindLabel: string
|
|
428
|
+
instruction: string
|
|
429
|
+
kind: string
|
|
430
|
+
leftPct: number
|
|
431
|
+
topPct: number
|
|
432
|
+
popoverFlipX: boolean
|
|
433
|
+
popoverFlipY: boolean
|
|
434
|
+
attachmentChips:
|
|
435
|
+
- key: string
|
|
436
|
+
name: string
|
|
437
|
+
thumbUrl: string
|
|
438
|
+
annotationId: string
|
|
439
|
+
showSnapshotAnnotationsPanel: boolean
|
|
440
|
+
showSnapshotSubmitError: boolean
|
|
441
|
+
snapshotSubmitError: string
|
|
353
442
|
</script>
|
|
354
443
|
</head>
|
|
355
444
|
<body>
|
|
@@ -754,6 +843,128 @@ data:
|
|
|
754
843
|
</div>
|
|
755
844
|
</div>
|
|
756
845
|
|
|
846
|
+
<div class="snapshot-overlay" if="showSnapshotModal" ref="snapshotBackdrop" tabindex="-1" role="dialog" aria-modal="true" aria-label="Snapshot annotation">
|
|
847
|
+
<div class="snapshot-panel">
|
|
848
|
+
<div class="snapshot-header">
|
|
849
|
+
<h2 class="snapshot-title">Snapshot Annotation</h2>
|
|
850
|
+
<button type="button" class="snapshot-close" ref="snapshotCloseBtn" aria-label="Close">✕</button>
|
|
851
|
+
</div>
|
|
852
|
+
<div class="snapshot-tools">
|
|
853
|
+
<button type="button" class="{snapshotToolPointOn ? visual-tool-on} visual-tool-btn" ref="snapshotToolPointBtn" title="Point" aria-label="Point tool">⊙</button>
|
|
854
|
+
<button type="button" class="{snapshotToolAreaOn ? visual-tool-on} visual-tool-btn" ref="snapshotToolAreaBtn" title="Area" aria-label="Area tool">▢</button>
|
|
855
|
+
<button type="button" class="{snapshotToolArrowOn ? visual-tool-on} visual-tool-btn" ref="snapshotToolArrowBtn" title="Arrow" aria-label="Arrow tool">↗</button>
|
|
856
|
+
<button type="button" class="{snapshotToolNoneOn ? visual-tool-on} visual-tool-btn" ref="snapshotToolNoneBtn" title="Select" aria-label="Select tool">⤢</button>
|
|
857
|
+
<span class="tool-group-sep"></span>
|
|
858
|
+
<button type="button" class="visual-tool-btn" ref="snapshotUndoBtn" title="Undo last marker" aria-label="Undo">↩</button>
|
|
859
|
+
<button type="button" class="visual-tool-btn" ref="snapshotClearBtn" title="Clear all markers" aria-label="Clear all">✕ Clear</button>
|
|
860
|
+
</div>
|
|
861
|
+
<input type="file" class="file-input-hidden" ref="snapshotAttachFileInput" multiple />
|
|
862
|
+
<div class="snapshot-body">
|
|
863
|
+
<div class="snapshot-capture-area">
|
|
864
|
+
<img class="snapshot-img" ref="snapshotImg" src="{snapshotImageSrc}" alt="Captured snapshot" draggable="false" />
|
|
865
|
+
<div class="{snapshotOverlayPointerNone ? snapshot-img-overlay-none} snapshot-img-overlay" ref="snapshotOverlay">
|
|
866
|
+
<div
|
|
867
|
+
class="point-marker"
|
|
868
|
+
forEach="snapshotPointDisplayItems"
|
|
869
|
+
trackBy="id"
|
|
870
|
+
style="left: {leftPct}%; top: {topPct}%;"
|
|
871
|
+
>
|
|
872
|
+
<span class="point-marker-idx">{indexLabel}</span>
|
|
873
|
+
</div>
|
|
874
|
+
<div
|
|
875
|
+
class="area-rect"
|
|
876
|
+
forEach="snapshotAreaDisplayItems"
|
|
877
|
+
trackBy="id"
|
|
878
|
+
style="left: {leftPct}%; top: {topPct}%; width: {widthPct}%; height: {heightPct}%;"
|
|
879
|
+
><span class="area-marker-idx">{indexLabel}</span></div>
|
|
880
|
+
<div
|
|
881
|
+
class="area-rect area-rect-draft"
|
|
882
|
+
if="showSnapshotAreaDraft"
|
|
883
|
+
style="left: {snapshotAreaDraftLeftPct}%; top: {snapshotAreaDraftTopPct}%; width: {snapshotAreaDraftWidthPct}%; height: {snapshotAreaDraftHeightPct}%;"
|
|
884
|
+
></div>
|
|
885
|
+
<div
|
|
886
|
+
class="arrow-pending-dot"
|
|
887
|
+
if="showSnapshotArrowPending"
|
|
888
|
+
style="left: {snapshotArrowPendingLeftPct}%; top: {snapshotArrowPendingTopPct}%;"
|
|
889
|
+
></div>
|
|
890
|
+
<svg class="arrow-svg" if="hasSnapshotArrowLines" viewBox="0 0 100 100" preserveAspectRatio="none">
|
|
891
|
+
<defs>
|
|
892
|
+
<marker id="aiditor-snapshot-arrowhead" markerWidth="8" markerHeight="8" refX="6" refY="4" orient="auto">
|
|
893
|
+
<polygon points="0 0, 8 4, 0 8" fill="#c586ff" />
|
|
894
|
+
</marker>
|
|
895
|
+
</defs>
|
|
896
|
+
<line
|
|
897
|
+
forEach="snapshotArrowDisplayItems"
|
|
898
|
+
trackBy="id"
|
|
899
|
+
x1="{x1Pct}"
|
|
900
|
+
y1="{y1Pct}"
|
|
901
|
+
x2="{x2Pct}"
|
|
902
|
+
y2="{y2Pct}"
|
|
903
|
+
/>
|
|
904
|
+
</svg>
|
|
905
|
+
<div
|
|
906
|
+
class="arrow-end-pin"
|
|
907
|
+
forEach="snapshotArrowPinItems"
|
|
908
|
+
trackBy="id"
|
|
909
|
+
style="left: {leftPct}%; top: {topPct}%;"
|
|
910
|
+
>{indexLabel}</div>
|
|
911
|
+
</div>
|
|
912
|
+
</div>
|
|
913
|
+
<div class="snapshot-annotations-panel">
|
|
914
|
+
<p class="snapshot-empty-hint" if="!showSnapshotAnnotationsPanel">Click the screenshot to place a marker, or select a tool from the toolbar.</p>
|
|
915
|
+
<div
|
|
916
|
+
class="snapshot-annotation-card"
|
|
917
|
+
forEach="snapshotAnnotationItems"
|
|
918
|
+
trackBy="id"
|
|
919
|
+
ref="snapshotAnnotationRow"
|
|
920
|
+
data-annotation-id="{id}"
|
|
921
|
+
>
|
|
922
|
+
<div class="snapshot-annotation-card-head">
|
|
923
|
+
<span class="snapshot-annotation-kind">{kindLabel}</span>
|
|
924
|
+
<button type="button" class="snapshot-annotation-remove" title="Remove annotation" aria-label="Remove annotation">×</button>
|
|
925
|
+
</div>
|
|
926
|
+
<textarea
|
|
927
|
+
class="visual-annotation-instruction"
|
|
928
|
+
placeholder="Instruction for this annotation…"
|
|
929
|
+
data-annotation-id="{id}"
|
|
930
|
+
value="{instruction}"
|
|
931
|
+
></textarea>
|
|
932
|
+
<div class="visual-annotation-files">
|
|
933
|
+
<div class="visual-attach-row">
|
|
934
|
+
<button type="button" class="visual-attach-btn snapshot-annotation-attach" data-annotation-id="{id}">
|
|
935
|
+
Attach file
|
|
936
|
+
</button>
|
|
937
|
+
</div>
|
|
938
|
+
<div class="visual-attachment-chips" forEach="attachmentChips" trackBy="key">
|
|
939
|
+
<div class="visual-attachment-chip">
|
|
940
|
+
<img if="thumbUrl" class="visual-attachment-thumb" src="{thumbUrl}" alt="" />
|
|
941
|
+
<span class="visual-attachment-name">{name}</span>
|
|
942
|
+
<button
|
|
943
|
+
type="button"
|
|
944
|
+
class="visual-attachment-remove-file"
|
|
945
|
+
data-annotation-id="{annotationId}"
|
|
946
|
+
data-att-key="{key}"
|
|
947
|
+
aria-label="Remove attachment"
|
|
948
|
+
>×</button>
|
|
949
|
+
</div>
|
|
950
|
+
</div>
|
|
951
|
+
</div>
|
|
952
|
+
</div>
|
|
953
|
+
</div>
|
|
954
|
+
</div>
|
|
955
|
+
<p class="visual-submit-error" if="showSnapshotSubmitError">{snapshotSubmitError}</p>
|
|
956
|
+
<div class="snapshot-footer">
|
|
957
|
+
<div class="snapshot-discard-confirm" if="snapshotShowDiscardConfirm">
|
|
958
|
+
<span class="snapshot-discard-confirm-msg">Discard annotations?</span>
|
|
959
|
+
<button type="button" class="snapshot-secondary" ref="snapshotDiscardBtn">Discard</button>
|
|
960
|
+
<button type="button" class="snapshot-secondary" ref="snapshotKeepEditingBtn">Keep editing</button>
|
|
961
|
+
</div>
|
|
962
|
+
<button type="button" class="snapshot-secondary" ref="snapshotCancelBtn" if="!snapshotShowDiscardConfirm">Cancel</button>
|
|
963
|
+
<button type="button" class="snapshot-primary" ref="snapshotSendBtn" disabled="!snapshotCanSubmit" if="!snapshotShowDiscardConfirm">Send to Agent</button>
|
|
964
|
+
</div>
|
|
965
|
+
</div>
|
|
966
|
+
</div>
|
|
967
|
+
|
|
757
968
|
</div>
|
|
758
969
|
</body>
|
|
759
970
|
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/aiditor",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AIditor — visual AI-driven code editor plugin for Jay Framework",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,16 +42,16 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
45
|
-
"@jay-framework/fullstack-component": "^0.17.
|
|
46
|
-
"@jay-framework/stack-client-runtime": "^0.17.
|
|
47
|
-
"@jay-framework/stack-server-runtime": "^0.17.
|
|
45
|
+
"@jay-framework/fullstack-component": "^0.17.2",
|
|
46
|
+
"@jay-framework/stack-client-runtime": "^0.17.2",
|
|
47
|
+
"@jay-framework/stack-server-runtime": "^0.17.2",
|
|
48
48
|
"busboy": "^1.6.0",
|
|
49
49
|
"html2canvas": "^1.4.1",
|
|
50
50
|
"zod": "^4.3.6"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@jay-framework/compiler-jay-stack": "^0.17.
|
|
54
|
-
"@jay-framework/jay-cli": "^0.17.
|
|
53
|
+
"@jay-framework/compiler-jay-stack": "^0.17.2",
|
|
54
|
+
"@jay-framework/jay-cli": "^0.17.2",
|
|
55
55
|
"@types/busboy": "^1",
|
|
56
56
|
"rimraf": "^5.0.5",
|
|
57
57
|
"tsup": "^8.5.1",
|