qapture2 0.7.5 → 0.7.7
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 +16 -7
- package/dist/{chunk-FBFESAG6.js → chunk-FVQKCQC3.js} +382 -109
- package/dist/{chunk-COQKFGKZ.cjs → chunk-WU7QMHPK.cjs} +382 -109
- package/dist/index.cjs +5 -5
- package/dist/index.js +1 -1
- package/dist/next.cjs +4 -4
- package/dist/next.js +1 -1
- package/dist/standalone.cjs +2 -2
- package/dist/standalone.js +1 -1
- package/package.json +3 -2
|
@@ -51,10 +51,10 @@ function openDB(dbName) {
|
|
|
51
51
|
dbCache.set(dbName, promise);
|
|
52
52
|
return promise;
|
|
53
53
|
}
|
|
54
|
-
function run(dbName, store,
|
|
54
|
+
function run(dbName, store, mode2, fn) {
|
|
55
55
|
return openDB(dbName).then(
|
|
56
56
|
(db) => new Promise((resolve, reject) => {
|
|
57
|
-
const tx = db.transaction(store,
|
|
57
|
+
const tx = db.transaction(store, mode2);
|
|
58
58
|
const s = tx.objectStore(store);
|
|
59
59
|
let result;
|
|
60
60
|
const req = fn(s);
|
|
@@ -1755,10 +1755,10 @@ var STR = {
|
|
|
1755
1755
|
copied: "Copied",
|
|
1756
1756
|
copy_failed: "Copy failed",
|
|
1757
1757
|
copy_prompt: "Copy as agent prompt",
|
|
1758
|
-
severity_label: "
|
|
1758
|
+
severity_label: "What is this?",
|
|
1759
1759
|
sev_bug: "Bug",
|
|
1760
|
-
|
|
1761
|
-
|
|
1760
|
+
sev_design: "Design",
|
|
1761
|
+
sev_enhance: "Enhance",
|
|
1762
1762
|
status_open: "Open",
|
|
1763
1763
|
status_verified: "Verified",
|
|
1764
1764
|
context_attached: "{n} runtime events attached",
|
|
@@ -1774,10 +1774,10 @@ var STR = {
|
|
|
1774
1774
|
no_evidence: "ticked, no capture",
|
|
1775
1775
|
expected_label: "Expected",
|
|
1776
1776
|
exact_label: "Pixel-exact shots",
|
|
1777
|
-
exact_hint: "Screenshots become a real photo
|
|
1777
|
+
exact_hint: "Screenshots become a real photo instead of a redraw. Asks once to share this tab (or, in Safari and Firefox, this window); nothing leaves your device.",
|
|
1778
1778
|
redraw_notice: "This is a redraw of the page, not a real photo.",
|
|
1779
1779
|
redraw_action: "Use real screenshots",
|
|
1780
|
-
redraw_no_engine: "This browser cannot photograph
|
|
1780
|
+
redraw_no_engine: "This browser cannot photograph the screen at all, so charts and canvases may come out wrong. Open the app on a desktop browser for true screenshots.",
|
|
1781
1781
|
fab_title: "Qapture \u2014 click to open, drag to move it out of the way",
|
|
1782
1782
|
exact_on: "Pixel-exact screenshots on",
|
|
1783
1783
|
exact_off: "Back to redrawn screenshots",
|
|
@@ -1953,10 +1953,10 @@ var STR = {
|
|
|
1953
1953
|
copied: "\u062A\u0645 \u0627\u0644\u0646\u0633\u062E",
|
|
1954
1954
|
copy_failed: "\u0641\u0634\u0644 \u0627\u0644\u0646\u0633\u062E",
|
|
1955
1955
|
copy_prompt: "\u0646\u0633\u062E \u0643\u0645\u0648\u062C\u0651\u0647 \u0644\u0644\u0648\u0643\u064A\u0644",
|
|
1956
|
-
severity_label: "\u0627\
|
|
1957
|
-
sev_bug: "
|
|
1958
|
-
|
|
1959
|
-
|
|
1956
|
+
severity_label: "\u0645\u0627 \u0647\u0630\u0627\u061F",
|
|
1957
|
+
sev_bug: "Bug",
|
|
1958
|
+
sev_design: "Design",
|
|
1959
|
+
sev_enhance: "Enhance",
|
|
1960
1960
|
status_open: "\u0645\u0641\u062A\u0648\u062D",
|
|
1961
1961
|
status_verified: "\u062A\u0645 \u0627\u0644\u062A\u062D\u0642\u0642",
|
|
1962
1962
|
context_attached: "{n} \u0645\u0646 \u0623\u062D\u062F\u0627\u062B \u0627\u0644\u062A\u0634\u063A\u064A\u0644 \u0645\u0631\u0641\u0642\u0629",
|
|
@@ -1972,10 +1972,10 @@ var STR = {
|
|
|
1972
1972
|
no_evidence: "\u0645\u064F\u0639\u0644\u0651\u0645 \u0628\u062F\u0648\u0646 \u0627\u0644\u062A\u0642\u0627\u0637",
|
|
1973
1973
|
expected_label: "\u0627\u0644\u0645\u062A\u0648\u0642\u0639",
|
|
1974
1974
|
exact_label: "\u0644\u0642\u0637\u0627\u062A \u0645\u0637\u0627\u0628\u0642\u0629 \u062A\u0645\u0627\u0645\u064B\u0627",
|
|
1975
|
-
exact_hint: "\u062A\u0635\u0628\u062D \u0627\u0644\u0644\u0642\u0637\u0629 \u0635\u0648\u0631\u0629 \u062D\u0642\u064A\u0642\u064A\u0629 \
|
|
1975
|
+
exact_hint: "\u062A\u0635\u0628\u062D \u0627\u0644\u0644\u0642\u0637\u0629 \u0635\u0648\u0631\u0629 \u062D\u0642\u064A\u0642\u064A\u0629 \u0628\u062F\u0644 \u0625\u0639\u0627\u062F\u0629 \u0627\u0644\u0631\u0633\u0645. \u064A\u064F\u0637\u0644\u0628 \u0627\u0644\u0625\u0630\u0646 \u0645\u0631\u0629 \u0648\u0627\u062D\u062F\u0629 \u0644\u0645\u0634\u0627\u0631\u0643\u0629 \u0627\u0644\u062A\u0628\u0648\u064A\u0628 (\u0623\u0648 \u0627\u0644\u0646\u0627\u0641\u0630\u0629 \u0641\u064A Safari \u0648Firefox)\u060C \u0648\u0644\u0627 \u0634\u064A\u0621 \u064A\u063A\u0627\u062F\u0631 \u062C\u0647\u0627\u0632\u0643.",
|
|
1976
1976
|
redraw_notice: "\u0647\u0630\u0647 \u0625\u0639\u0627\u062F\u0629 \u0631\u0633\u0645 \u0644\u0644\u0635\u0641\u062D\u0629\u060C \u0648\u0644\u064A\u0633\u062A \u0635\u0648\u0631\u0629 \u062D\u0642\u064A\u0642\u064A\u0629.",
|
|
1977
1977
|
redraw_action: "\u0627\u0633\u062A\u062E\u062F\u0645 \u0644\u0642\u0637\u0627\u062A \u062D\u0642\u064A\u0642\u064A\u0629",
|
|
1978
|
-
redraw_no_engine: "\u0644\u0627 \u064A\u0633\u062A\u0637\u064A\u0639 \u0647\u0630\u0627 \u0627\u0644\u0645\u062A\u0635\u0641\u062D \u062A\u0635\u0648\u064A\u0631 \u0627\u0644\
|
|
1978
|
+
redraw_no_engine: "\u0644\u0627 \u064A\u0633\u062A\u0637\u064A\u0639 \u0647\u0630\u0627 \u0627\u0644\u0645\u062A\u0635\u0641\u062D \u062A\u0635\u0648\u064A\u0631 \u0627\u0644\u0634\u0627\u0634\u0629 \u0625\u0637\u0644\u0627\u0642\u064B\u0627\u060C \u0644\u0630\u0627 \u0642\u062F \u062A\u0638\u0647\u0631 \u0627\u0644\u0645\u062E\u0637\u0637\u0627\u062A \u0648\u0627\u0644\u0644\u0648\u062D\u0627\u062A \u0628\u0634\u0643\u0644 \u062E\u0627\u0637\u0626. \u0627\u0641\u062A\u062D \u0627\u0644\u062A\u0637\u0628\u064A\u0642 \u0639\u0644\u0649 \u0645\u062A\u0635\u0641\u062D \u0633\u0637\u062D \u0645\u0643\u062A\u0628 \u0644\u0644\u062D\u0635\u0648\u0644 \u0639\u0644\u0649 \u0644\u0642\u0637\u0627\u062A \u062D\u0642\u064A\u0642\u064A\u0629.",
|
|
1979
1979
|
fab_title: "Qapture \u2014 \u0627\u0636\u063A\u0637 \u0644\u0644\u0641\u062A\u062D\u060C \u0648\u0627\u0633\u062D\u0628 \u0644\u062A\u062D\u0631\u064A\u0643\u0647 \u0645\u0646 \u0645\u0643\u0627\u0646\u0647",
|
|
1980
1980
|
exact_on: "\u062A\u0645 \u062A\u0641\u0639\u064A\u0644 \u0627\u0644\u0644\u0642\u0637\u0627\u062A \u0627\u0644\u0645\u0637\u0627\u0628\u0642\u0629",
|
|
1981
1981
|
exact_off: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0625\u0644\u0649 \u0627\u0644\u0644\u0642\u0637\u0627\u062A \u0627\u0644\u0645\u064F\u0639\u0627\u062F \u0631\u0633\u0645\u0647\u0627",
|
|
@@ -2175,8 +2175,168 @@ function computeCoverage(journey, guideChecked, skipped) {
|
|
|
2175
2175
|
};
|
|
2176
2176
|
}
|
|
2177
2177
|
|
|
2178
|
+
// src/lib/frameCalibration.ts
|
|
2179
|
+
var MARKER_SIZE = 28;
|
|
2180
|
+
var MARKERS = [
|
|
2181
|
+
{ key: "tl", color: [255, 0, 0] },
|
|
2182
|
+
{ key: "tr", color: [0, 255, 0] },
|
|
2183
|
+
{ key: "bl", color: [0, 0, 255] },
|
|
2184
|
+
{ key: "br", color: [255, 0, 255] }
|
|
2185
|
+
];
|
|
2186
|
+
function markerCentres(vw, vh) {
|
|
2187
|
+
const h = MARKER_SIZE / 2;
|
|
2188
|
+
return {
|
|
2189
|
+
tl: { x: h, y: h },
|
|
2190
|
+
tr: { x: vw - h, y: h },
|
|
2191
|
+
bl: { x: h, y: vh - h },
|
|
2192
|
+
br: { x: vw - h, y: vh - h }
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
function dist2(r, g, b, c) {
|
|
2196
|
+
const dr = r - c[0];
|
|
2197
|
+
const dg = g - c[1];
|
|
2198
|
+
const db = b - c[2];
|
|
2199
|
+
return dr * dr + dg * dg + db * db;
|
|
2200
|
+
}
|
|
2201
|
+
var COLOR_TOLERANCE_2 = 90 * 90;
|
|
2202
|
+
var CLUSTER_CELL = 8;
|
|
2203
|
+
var MAX_CANDIDATES = 4;
|
|
2204
|
+
function findMarkerCandidates(data, width, height) {
|
|
2205
|
+
const cols = Math.ceil(width / CLUSTER_CELL);
|
|
2206
|
+
const rows = Math.ceil(height / CLUSTER_CELL);
|
|
2207
|
+
const cells = {};
|
|
2208
|
+
for (const m of MARKERS) cells[m.key] = new Int32Array(cols * rows);
|
|
2209
|
+
for (let y = 0; y < height; y++) {
|
|
2210
|
+
const row = y * width * 4;
|
|
2211
|
+
const cy = y / CLUSTER_CELL | 0;
|
|
2212
|
+
for (let x = 0; x < width; x++) {
|
|
2213
|
+
const i = row + x * 4;
|
|
2214
|
+
if (data[i + 3] < 128) continue;
|
|
2215
|
+
const r = data[i];
|
|
2216
|
+
const g = data[i + 1];
|
|
2217
|
+
const b = data[i + 2];
|
|
2218
|
+
if (Math.max(r, g, b) - Math.min(r, g, b) < 60) continue;
|
|
2219
|
+
for (const m of MARKERS) {
|
|
2220
|
+
if (dist2(r, g, b, m.color) <= COLOR_TOLERANCE_2) {
|
|
2221
|
+
cells[m.key][cy * cols + (x / CLUSTER_CELL | 0)]++;
|
|
2222
|
+
break;
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
const out = {};
|
|
2228
|
+
for (const m of MARKERS) {
|
|
2229
|
+
const grid = cells[m.key];
|
|
2230
|
+
const seen = new Uint8Array(cols * rows);
|
|
2231
|
+
const blobs = [];
|
|
2232
|
+
for (let start = 0; start < grid.length; start++) {
|
|
2233
|
+
if (!grid[start] || seen[start]) continue;
|
|
2234
|
+
const queue = [start];
|
|
2235
|
+
seen[start] = 1;
|
|
2236
|
+
let sumX = 0;
|
|
2237
|
+
let sumY = 0;
|
|
2238
|
+
let total = 0;
|
|
2239
|
+
while (queue.length) {
|
|
2240
|
+
const idx = queue.pop();
|
|
2241
|
+
const n = grid[idx];
|
|
2242
|
+
const cx = idx % cols;
|
|
2243
|
+
const cy = idx / cols | 0;
|
|
2244
|
+
sumX += (cx * CLUSTER_CELL + CLUSTER_CELL / 2) * n;
|
|
2245
|
+
sumY += (cy * CLUSTER_CELL + CLUSTER_CELL / 2) * n;
|
|
2246
|
+
total += n;
|
|
2247
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
2248
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
2249
|
+
const nx = cx + dx;
|
|
2250
|
+
const ny = cy + dy;
|
|
2251
|
+
if (nx < 0 || ny < 0 || nx >= cols || ny >= rows) continue;
|
|
2252
|
+
const nIdx = ny * cols + nx;
|
|
2253
|
+
if (seen[nIdx] || !grid[nIdx]) continue;
|
|
2254
|
+
seen[nIdx] = 1;
|
|
2255
|
+
queue.push(nIdx);
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
if (total < 16) continue;
|
|
2260
|
+
blobs.push({ x: sumX / total, y: sumY / total, count: total });
|
|
2261
|
+
}
|
|
2262
|
+
blobs.sort((a, b) => b.count - a.count);
|
|
2263
|
+
out[m.key] = blobs.slice(0, MAX_CANDIDATES);
|
|
2264
|
+
}
|
|
2265
|
+
return out;
|
|
2266
|
+
}
|
|
2267
|
+
var VERIFY_TOLERANCE = 0.02;
|
|
2268
|
+
var SQUARENESS_TOLERANCE = 0.05;
|
|
2269
|
+
function deriveMapping(candidates, vw, vh, frameW, frameH) {
|
|
2270
|
+
const tls = candidates.tl ?? [];
|
|
2271
|
+
const brs = candidates.br ?? [];
|
|
2272
|
+
for (const tl of tls) {
|
|
2273
|
+
for (const br of brs) {
|
|
2274
|
+
const m = solveFrom(tl, br, candidates, vw, vh, frameW, frameH);
|
|
2275
|
+
if (m) return m;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
return null;
|
|
2279
|
+
}
|
|
2280
|
+
function solveFrom(tl, br, candidates, vw, vh, frameW, frameH) {
|
|
2281
|
+
if (!(vw > MARKER_SIZE) || !(vh > MARKER_SIZE)) return null;
|
|
2282
|
+
const centres = markerCentres(vw, vh);
|
|
2283
|
+
const spanCssX = centres.br.x - centres.tl.x;
|
|
2284
|
+
const spanCssY = centres.br.y - centres.tl.y;
|
|
2285
|
+
if (spanCssX <= 0 || spanCssY <= 0) return null;
|
|
2286
|
+
const scaleX = (br.x - tl.x) / spanCssX;
|
|
2287
|
+
const scaleY = (br.y - tl.y) / spanCssY;
|
|
2288
|
+
if (!(scaleX > 0.05) || !(scaleY > 0.05)) return null;
|
|
2289
|
+
if (!Number.isFinite(scaleX) || !Number.isFinite(scaleY)) return null;
|
|
2290
|
+
if (Math.abs(scaleX - scaleY) / Math.max(scaleX, scaleY) > SQUARENESS_TOLERANCE) return null;
|
|
2291
|
+
const originX = tl.x - centres.tl.x * scaleX;
|
|
2292
|
+
const originY = tl.y - centres.tl.y * scaleY;
|
|
2293
|
+
const mapping2 = { scaleX, scaleY, originX, originY };
|
|
2294
|
+
const farX = originX + vw * scaleX;
|
|
2295
|
+
const farY = originY + vh * scaleY;
|
|
2296
|
+
const slack = Math.max(4, frameW * 0.01);
|
|
2297
|
+
if (originX < -slack || originY < -slack || farX > frameW + slack || farY > frameH + slack) {
|
|
2298
|
+
return null;
|
|
2299
|
+
}
|
|
2300
|
+
const tolerance = Math.max(6, Math.max(frameW, frameH) * VERIFY_TOLERANCE);
|
|
2301
|
+
let verified = 0;
|
|
2302
|
+
for (const key of ["tr", "bl"]) {
|
|
2303
|
+
const hits = candidates[key] ?? [];
|
|
2304
|
+
if (!hits.length) continue;
|
|
2305
|
+
const want = centres[key];
|
|
2306
|
+
const px = originX + want.x * scaleX;
|
|
2307
|
+
const py = originY + want.y * scaleY;
|
|
2308
|
+
if (!hits.some((h) => Math.hypot(px - h.x, py - h.y) <= tolerance)) return null;
|
|
2309
|
+
verified++;
|
|
2310
|
+
}
|
|
2311
|
+
if (verified === 0) return null;
|
|
2312
|
+
return mapping2;
|
|
2313
|
+
}
|
|
2314
|
+
function mapRectToFrame(rect, m, frameW, frameH) {
|
|
2315
|
+
const x0 = m.originX + rect.left * m.scaleX;
|
|
2316
|
+
const y0 = m.originY + rect.top * m.scaleY;
|
|
2317
|
+
const sx = Math.max(0, Math.min(frameW, Math.round(x0)));
|
|
2318
|
+
const sy = Math.max(0, Math.min(frameH, Math.round(y0)));
|
|
2319
|
+
const sw = Math.min(frameW - sx, Math.round(rect.width * m.scaleX));
|
|
2320
|
+
const sh = Math.min(frameH - sy, Math.round(rect.height * m.scaleY));
|
|
2321
|
+
if (sw < 1 || sh < 1) return null;
|
|
2322
|
+
return { sx, sy, sw, sh };
|
|
2323
|
+
}
|
|
2324
|
+
function environmentSignature() {
|
|
2325
|
+
if (typeof window === "undefined") return "";
|
|
2326
|
+
return [
|
|
2327
|
+
window.innerWidth,
|
|
2328
|
+
window.innerHeight,
|
|
2329
|
+
window.outerWidth,
|
|
2330
|
+
window.outerHeight,
|
|
2331
|
+
window.screenX,
|
|
2332
|
+
window.screenY,
|
|
2333
|
+
Math.round((window.devicePixelRatio || 1) * 100)
|
|
2334
|
+
].join("x");
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2178
2337
|
// src/lib/screenCapture.ts
|
|
2179
2338
|
var ASPECT_TOLERANCE = 0.08;
|
|
2339
|
+
var CALIBRATION_SETTLE_MS = 220;
|
|
2180
2340
|
var FRESH_FRAME_TIMEOUT_MS = 500;
|
|
2181
2341
|
var VIDEO_READY_TIMEOUT_MS = 4e3;
|
|
2182
2342
|
var stream = null;
|
|
@@ -2184,22 +2344,14 @@ var track = null;
|
|
|
2184
2344
|
var video = null;
|
|
2185
2345
|
var grabber = null;
|
|
2186
2346
|
var declined = false;
|
|
2187
|
-
function supportsPreferCurrentTab() {
|
|
2188
|
-
const nav = navigator;
|
|
2189
|
-
const brands = nav.userAgentData?.brands;
|
|
2190
|
-
if (Array.isArray(brands) && brands.length) {
|
|
2191
|
-
return brands.some((b) => /chromium/i.test(b.brand));
|
|
2192
|
-
}
|
|
2193
|
-
const ua = navigator.userAgent || "";
|
|
2194
|
-
if (/CriOS|FxiOS|EdgiOS|Firefox/i.test(ua)) return false;
|
|
2195
|
-
return /Chrome|Chromium|Edg\//i.test(ua);
|
|
2196
|
-
}
|
|
2197
2347
|
function isExactCaptureSupported() {
|
|
2198
2348
|
if (typeof navigator === "undefined" || typeof document === "undefined") return false;
|
|
2199
2349
|
const md = navigator.mediaDevices;
|
|
2200
|
-
|
|
2201
|
-
return supportsPreferCurrentTab();
|
|
2350
|
+
return !!md && typeof md.getDisplayMedia === "function";
|
|
2202
2351
|
}
|
|
2352
|
+
var mode = "tab";
|
|
2353
|
+
var mapping = null;
|
|
2354
|
+
var mappingSignature = "";
|
|
2203
2355
|
function getExactCaptureStatus() {
|
|
2204
2356
|
if (!isExactCaptureSupported()) return "unsupported";
|
|
2205
2357
|
if (track && track.readyState === "live") return "live";
|
|
@@ -2227,6 +2379,9 @@ function teardown() {
|
|
|
2227
2379
|
stream = null;
|
|
2228
2380
|
track = null;
|
|
2229
2381
|
grabber = null;
|
|
2382
|
+
mode = "tab";
|
|
2383
|
+
mapping = null;
|
|
2384
|
+
mappingSignature = "";
|
|
2230
2385
|
}
|
|
2231
2386
|
function stopExactCapture() {
|
|
2232
2387
|
teardown();
|
|
@@ -2281,6 +2436,78 @@ function validateFrameMapping(frameW, frameH) {
|
|
|
2281
2436
|
const viewAspect = vw / vh;
|
|
2282
2437
|
return Math.abs(frameAspect - viewAspect) / viewAspect <= ASPECT_TOLERANCE;
|
|
2283
2438
|
}
|
|
2439
|
+
async function grabFrameCanvas() {
|
|
2440
|
+
if (!video) return null;
|
|
2441
|
+
await nextPresentedFrame(video);
|
|
2442
|
+
let source = video;
|
|
2443
|
+
let w = video.videoWidth;
|
|
2444
|
+
let h = video.videoHeight;
|
|
2445
|
+
let bitmap = null;
|
|
2446
|
+
if (grabber) {
|
|
2447
|
+
try {
|
|
2448
|
+
bitmap = await grabber.grabFrame();
|
|
2449
|
+
source = bitmap;
|
|
2450
|
+
w = bitmap.width;
|
|
2451
|
+
h = bitmap.height;
|
|
2452
|
+
} catch {
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
if (!w || !h) {
|
|
2456
|
+
bitmap?.close?.();
|
|
2457
|
+
return null;
|
|
2458
|
+
}
|
|
2459
|
+
const c = document.createElement("canvas");
|
|
2460
|
+
c.width = w;
|
|
2461
|
+
c.height = h;
|
|
2462
|
+
const ctx = c.getContext("2d", { willReadFrequently: true });
|
|
2463
|
+
if (!ctx) {
|
|
2464
|
+
bitmap?.close?.();
|
|
2465
|
+
return null;
|
|
2466
|
+
}
|
|
2467
|
+
ctx.drawImage(source, 0, 0);
|
|
2468
|
+
bitmap?.close?.();
|
|
2469
|
+
return c;
|
|
2470
|
+
}
|
|
2471
|
+
async function calibrate() {
|
|
2472
|
+
if (!video) return false;
|
|
2473
|
+
const vw = window.innerWidth;
|
|
2474
|
+
const vh = window.innerHeight;
|
|
2475
|
+
if (vw <= MARKER_SIZE || vh <= MARKER_SIZE) return false;
|
|
2476
|
+
const card = document.createElement("div");
|
|
2477
|
+
card.setAttribute("data-qa-calibration", "true");
|
|
2478
|
+
card.style.cssText = "position:fixed;inset:0;z-index:2147483647;background:#0a0a0a;pointer-events:none;contain:strict;";
|
|
2479
|
+
const centres = markerCentres(vw, vh);
|
|
2480
|
+
for (const m of MARKERS) {
|
|
2481
|
+
const dot = document.createElement("div");
|
|
2482
|
+
const c = centres[m.key];
|
|
2483
|
+
dot.style.cssText = `position:absolute;width:${MARKER_SIZE}px;height:${MARKER_SIZE}px;left:${c.x - MARKER_SIZE / 2}px;top:${c.y - MARKER_SIZE / 2}px;background:rgb(${m.color[0]},${m.color[1]},${m.color[2]});`;
|
|
2484
|
+
card.appendChild(dot);
|
|
2485
|
+
}
|
|
2486
|
+
document.body.appendChild(card);
|
|
2487
|
+
try {
|
|
2488
|
+
await new Promise((r) => setTimeout(r, CALIBRATION_SETTLE_MS));
|
|
2489
|
+
const frame = await grabFrameCanvas();
|
|
2490
|
+
if (!frame) return false;
|
|
2491
|
+
const ctx = frame.getContext("2d", { willReadFrequently: true });
|
|
2492
|
+
if (!ctx) return false;
|
|
2493
|
+
const { data } = ctx.getImageData(0, 0, frame.width, frame.height);
|
|
2494
|
+
const found = deriveMapping(
|
|
2495
|
+
findMarkerCandidates(data, frame.width, frame.height),
|
|
2496
|
+
vw,
|
|
2497
|
+
vh,
|
|
2498
|
+
frame.width,
|
|
2499
|
+
frame.height
|
|
2500
|
+
);
|
|
2501
|
+
if (!found) return false;
|
|
2502
|
+
mapping = found;
|
|
2503
|
+
mappingSignature = environmentSignature();
|
|
2504
|
+
return true;
|
|
2505
|
+
} catch {
|
|
2506
|
+
return false;
|
|
2507
|
+
} finally {
|
|
2508
|
+
card.remove();
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2284
2511
|
async function startExactCapture() {
|
|
2285
2512
|
if (!isExactCaptureSupported()) return false;
|
|
2286
2513
|
if (track && track.readyState === "live" && video) return true;
|
|
@@ -2310,11 +2537,7 @@ async function startExactCapture() {
|
|
|
2310
2537
|
return false;
|
|
2311
2538
|
}
|
|
2312
2539
|
const settings = t.getSettings();
|
|
2313
|
-
|
|
2314
|
-
for (const x of s.getTracks()) x.stop();
|
|
2315
|
-
declined = true;
|
|
2316
|
-
return false;
|
|
2317
|
-
}
|
|
2540
|
+
const sharedTab = !settings.displaySurface || settings.displaySurface === "browser";
|
|
2318
2541
|
const el = document.createElement("video");
|
|
2319
2542
|
el.setAttribute("data-qa-overlay", "true");
|
|
2320
2543
|
el.muted = true;
|
|
@@ -2327,17 +2550,31 @@ async function startExactCapture() {
|
|
|
2327
2550
|
} catch {
|
|
2328
2551
|
}
|
|
2329
2552
|
const ready = await waitFor(() => el.videoWidth > 0 && el.videoHeight > 0, VIDEO_READY_TIMEOUT_MS);
|
|
2330
|
-
|
|
2553
|
+
const giveUp = () => {
|
|
2331
2554
|
el.remove();
|
|
2332
2555
|
for (const x of s.getTracks()) x.stop();
|
|
2333
2556
|
declined = true;
|
|
2334
2557
|
return false;
|
|
2335
|
-
}
|
|
2558
|
+
};
|
|
2559
|
+
if (!ready) return giveUp();
|
|
2560
|
+
const isDirect = sharedTab && validateFrameMapping(el.videoWidth, el.videoHeight);
|
|
2336
2561
|
stream = s;
|
|
2337
2562
|
track = t;
|
|
2338
2563
|
video = el;
|
|
2339
2564
|
const IC = window.ImageCapture;
|
|
2340
2565
|
grabber = IC ? new IC(t) : null;
|
|
2566
|
+
if (isDirect) {
|
|
2567
|
+
mode = "tab";
|
|
2568
|
+
mapping = null;
|
|
2569
|
+
mappingSignature = "";
|
|
2570
|
+
} else {
|
|
2571
|
+
mode = "surface";
|
|
2572
|
+
if (!await calibrate()) {
|
|
2573
|
+
teardown();
|
|
2574
|
+
declined = true;
|
|
2575
|
+
return false;
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2341
2578
|
t.addEventListener("ended", () => {
|
|
2342
2579
|
teardown();
|
|
2343
2580
|
});
|
|
@@ -2350,6 +2587,11 @@ async function startExactCapture() {
|
|
|
2350
2587
|
}
|
|
2351
2588
|
async function grabExactRegion(rect) {
|
|
2352
2589
|
if (!track || track.readyState !== "live" || !video) return null;
|
|
2590
|
+
if (mode === "surface") {
|
|
2591
|
+
if (!mapping || environmentSignature() !== mappingSignature) {
|
|
2592
|
+
if (!await calibrate()) return null;
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2353
2595
|
await nextPresentedFrame(video);
|
|
2354
2596
|
let source;
|
|
2355
2597
|
let frameW;
|
|
@@ -2372,13 +2614,24 @@ async function grabExactRegion(rect) {
|
|
|
2372
2614
|
frameH = video.videoHeight;
|
|
2373
2615
|
}
|
|
2374
2616
|
try {
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2617
|
+
let sx;
|
|
2618
|
+
let sy;
|
|
2619
|
+
let sw;
|
|
2620
|
+
let sh;
|
|
2621
|
+
if (mode === "surface") {
|
|
2622
|
+
if (!mapping) return null;
|
|
2623
|
+
const mapped = mapRectToFrame(rect, mapping, frameW, frameH);
|
|
2624
|
+
if (!mapped) return null;
|
|
2625
|
+
({ sx, sy, sw, sh } = mapped);
|
|
2626
|
+
} else {
|
|
2627
|
+
if (!validateFrameMapping(frameW, frameH)) return null;
|
|
2628
|
+
const scaleX = frameW / window.innerWidth;
|
|
2629
|
+
const scaleY = frameH / window.innerHeight;
|
|
2630
|
+
sx = Math.max(0, Math.min(frameW, Math.round(rect.left * scaleX)));
|
|
2631
|
+
sy = Math.max(0, Math.min(frameH, Math.round(rect.top * scaleY)));
|
|
2632
|
+
sw = Math.max(1, Math.min(frameW - sx, Math.round(rect.width * scaleX)));
|
|
2633
|
+
sh = Math.max(1, Math.min(frameH - sy, Math.round(rect.height * scaleY)));
|
|
2634
|
+
}
|
|
2382
2635
|
const canvas = document.createElement("canvas");
|
|
2383
2636
|
canvas.width = sw;
|
|
2384
2637
|
canvas.height = sh;
|
|
@@ -3024,15 +3277,15 @@ function fmtPct(n, d) {
|
|
|
3024
3277
|
}
|
|
3025
3278
|
function summariseSession(notes, stamp) {
|
|
3026
3279
|
if (!notes.length) return "No points captured.";
|
|
3027
|
-
let bugs = 0,
|
|
3280
|
+
let bugs = 0, enhancements = 0, designs = 0, verified = 0, awaiting = 0;
|
|
3028
3281
|
const pages = /* @__PURE__ */ new Set();
|
|
3029
3282
|
let earliest = Number.POSITIVE_INFINITY;
|
|
3030
3283
|
let latest = 0;
|
|
3031
3284
|
for (const n of notes) {
|
|
3032
3285
|
const sev = n.severity ?? "bug";
|
|
3033
3286
|
if (sev === "bug") bugs++;
|
|
3034
|
-
else if (sev === "
|
|
3035
|
-
else
|
|
3287
|
+
else if (sev === "enhance") enhancements++;
|
|
3288
|
+
else designs++;
|
|
3036
3289
|
const status = n.status ?? "open";
|
|
3037
3290
|
if (status === "verified") verified++;
|
|
3038
3291
|
else if (status === "fixed") awaiting++;
|
|
@@ -3047,8 +3300,8 @@ function summariseSession(notes, stamp) {
|
|
|
3047
3300
|
`${notes.length} point${notes.length === 1 ? "" : "s"}`,
|
|
3048
3301
|
`${bugs} bug${bugs === 1 ? "" : "s"}`
|
|
3049
3302
|
];
|
|
3050
|
-
if (
|
|
3051
|
-
if (
|
|
3303
|
+
if (enhancements) parts.push(`${enhancements} enhancement${enhancements === 1 ? "" : "s"}`);
|
|
3304
|
+
if (designs) parts.push(`${designs} design`);
|
|
3052
3305
|
if (verified) parts.push(`${verified} verified`);
|
|
3053
3306
|
if (awaiting) parts.push(`${awaiting} awaiting re-test`);
|
|
3054
3307
|
parts.push(`${pages.size} page${pages.size === 1 ? "" : "s"}`);
|
|
@@ -3079,6 +3332,37 @@ Exported: ${stamp}
|
|
|
3079
3332
|
Points: ${noteCount}
|
|
3080
3333
|
|
|
3081
3334
|
**Session:** ${summariseSession(notes, stamp)}`
|
|
3335
|
+
);
|
|
3336
|
+
sections.push(
|
|
3337
|
+
`## What the tags mean
|
|
3338
|
+
|
|
3339
|
+
Every point below is tagged **Bug**, **Design** or **Enhance**. These are not priorities \u2014 they are three different kinds of work. Read the tag before you decide what to do.
|
|
3340
|
+
|
|
3341
|
+
### Bug \u2014 something is broken
|
|
3342
|
+
|
|
3343
|
+
Find the **root cause**, not the symptom. Do not patch over it.
|
|
3344
|
+
|
|
3345
|
+
State the cause in one plain sentence before you change anything \u2014 e.g. "the date was wrong because the server sends UTC and the list formats in local time". **If you cannot write that sentence, you have not found the cause yet.** Keep looking. The real cause is often something small and silly; that is normal, and it is still the cause.
|
|
3346
|
+
|
|
3347
|
+
**The cause is not always in the code.** If the code does exactly what it was asked to do and the result is still wrong, then nothing is broken \u2014 what was *asked for* and what was *meant* did not match. That mismatch is the bug. Realign to what the owner meant and fix it there. If the note already says what they meant ("this isn't what I wanted, I wanted X"), they have told you \u2014 just do X. Do not stop to ask a question they have already answered.
|
|
3348
|
+
|
|
3349
|
+
### Design \u2014 it works, but it looks or feels wrong
|
|
3350
|
+
|
|
3351
|
+
The functionality is fine and is not in question. Do not go hunting for a fault; there isn't one. Think properly about the interface and the experience \u2014 layout, spacing, hierarchy, wording, states, what the person is actually trying to do \u2014 and change how it looks and feels.
|
|
3352
|
+
|
|
3353
|
+
### Enhance \u2014 a new idea, thought of while using the app
|
|
3354
|
+
|
|
3355
|
+
The tester wants something added or changed: a new section, a new feature, a different way of doing it.
|
|
3356
|
+
|
|
3357
|
+
**Plan it before you build it.** Read the surrounding code, work out what it touches and what it might break, and choose an approach that fits how the app is already built. Then build it. You do not need to stop and ask for approval \u2014 plan well, then go.
|
|
3358
|
+
|
|
3359
|
+
Push back only when you have a real reason: it would break something, or it conflicts with an invariant below. Then say so plainly and propose the alternative you would build instead.
|
|
3360
|
+
|
|
3361
|
+
### When the tag and the words disagree
|
|
3362
|
+
|
|
3363
|
+
The tag sets your starting posture; **the words win.** A point tagged Design that says "this crashes" is a bug \u2014 treat it as one, and mention that you changed lane. People pick the wrong chip all the time; that is not a reason to do the wrong work.
|
|
3364
|
+
|
|
3365
|
+
And if a point is phrased as a question rather than a report, **answer it \u2014 do not change code on a maybe.**`
|
|
3082
3366
|
);
|
|
3083
3367
|
const stack = typeof p.stack === "string" && p.stack.trim() ? p.stack.trim() : "(not provided)";
|
|
3084
3368
|
const runArr = toStrings(p.runCommands);
|
|
@@ -3674,12 +3958,12 @@ function campaignJsonText(allNotes) {
|
|
|
3674
3958
|
function reportMarkdownText(allNotes) {
|
|
3675
3959
|
if (!campaign) return "";
|
|
3676
3960
|
const ordered = orderedKnownNotes(allNotes);
|
|
3677
|
-
const counts = { bug: 0,
|
|
3961
|
+
const counts = { bug: 0, design: 0, enhance: 0, verified: 0 };
|
|
3678
3962
|
for (const n of ordered) {
|
|
3679
3963
|
const sev = n.severity ?? "bug";
|
|
3680
3964
|
if (sev === "bug") counts.bug++;
|
|
3681
|
-
else if (sev === "
|
|
3682
|
-
else counts.
|
|
3965
|
+
else if (sev === "enhance") counts.enhance++;
|
|
3966
|
+
else counts.design++;
|
|
3683
3967
|
if (n.status === "verified") counts.verified++;
|
|
3684
3968
|
}
|
|
3685
3969
|
const header = [
|
|
@@ -3688,7 +3972,7 @@ function reportMarkdownText(allNotes) {
|
|
|
3688
3972
|
campaign.tester ? `Tester: ${campaign.tester} ` : "",
|
|
3689
3973
|
`Started: ${campaign.startedAt} `,
|
|
3690
3974
|
`Updated: ${(/* @__PURE__ */ new Date()).toISOString()} `,
|
|
3691
|
-
`Points: ${ordered.length} (${counts.bug} bug, ${counts.
|
|
3975
|
+
`Points: ${ordered.length} (${counts.bug} bug, ${counts.design} design, ${counts.enhance} enhance \xB7 ${counts.verified} verified)`,
|
|
3692
3976
|
"",
|
|
3693
3977
|
getFsSyncEngine() === "download" ? "Saved by Qapture as the campaign was tested. Screenshots are in" : "Written live by Qapture as each point was saved. Screenshots are in",
|
|
3694
3978
|
"`screenshots/`, one Markdown file per point in `notes/`.",
|
|
@@ -4040,6 +4324,12 @@ function QaProvider({
|
|
|
4040
4324
|
for (const id of pendingIds) void idb.delete(id);
|
|
4041
4325
|
storage.setJSON(PENDING_DELETE_KEY, []);
|
|
4042
4326
|
}
|
|
4327
|
+
live = live.map((n) => {
|
|
4328
|
+
const legacy = n.severity;
|
|
4329
|
+
if (legacy === "question") return { ...n, severity: "enhance" };
|
|
4330
|
+
if (legacy === "polish") return { ...n, severity: "design" };
|
|
4331
|
+
return n;
|
|
4332
|
+
});
|
|
4043
4333
|
const sorted = live.slice().sort(
|
|
4044
4334
|
(a, b) => a.timestamp < b.timestamp ? 1 : -1
|
|
4045
4335
|
);
|
|
@@ -4638,8 +4928,8 @@ function QaProvider({
|
|
|
4638
4928
|
const counts = {
|
|
4639
4929
|
all: notes.length,
|
|
4640
4930
|
bug: 0,
|
|
4641
|
-
|
|
4642
|
-
|
|
4931
|
+
design: 0,
|
|
4932
|
+
enhance: 0,
|
|
4643
4933
|
open: 0,
|
|
4644
4934
|
fixed: 0,
|
|
4645
4935
|
verified: 0,
|
|
@@ -4648,8 +4938,8 @@ function QaProvider({
|
|
|
4648
4938
|
for (const n of notes) {
|
|
4649
4939
|
const sev = n.severity ?? "bug";
|
|
4650
4940
|
if (sev === "bug") counts.bug++;
|
|
4651
|
-
else if (sev === "
|
|
4652
|
-
else counts.
|
|
4941
|
+
else if (sev === "enhance") counts.enhance++;
|
|
4942
|
+
else counts.design++;
|
|
4653
4943
|
const status = n.status ?? "open";
|
|
4654
4944
|
if (status === "verified") counts.verified++;
|
|
4655
4945
|
else if (status === "fixed") counts.fixed++;
|
|
@@ -5038,7 +5328,11 @@ function QaProvider({
|
|
|
5038
5328
|
pendingShare,
|
|
5039
5329
|
sharePending,
|
|
5040
5330
|
retestNote,
|
|
5041
|
-
|
|
5331
|
+
// The greeting explains how to capture. Once a note exists, the tester has
|
|
5332
|
+
// either done it or found their own way, so the line has nothing left to
|
|
5333
|
+
// say — take it away rather than making them dismiss it. (The stored flag
|
|
5334
|
+
// still governs a first visit; this only hides it early.)
|
|
5335
|
+
showWelcome: showWelcome && notes.length === 0,
|
|
5042
5336
|
dismissWelcome,
|
|
5043
5337
|
// v0.6
|
|
5044
5338
|
panelSide,
|
|
@@ -5491,8 +5785,8 @@ function QaFab() {
|
|
|
5491
5785
|
}
|
|
5492
5786
|
var SEVERITIES = [
|
|
5493
5787
|
{ value: "bug", labelKey: "sev_bug", icon: "Bug" },
|
|
5494
|
-
{ value: "
|
|
5495
|
-
{ value: "
|
|
5788
|
+
{ value: "enhance", labelKey: "sev_enhance" },
|
|
5789
|
+
{ value: "design", labelKey: "sev_design" }
|
|
5496
5790
|
];
|
|
5497
5791
|
function SeverityChipRow({
|
|
5498
5792
|
value,
|
|
@@ -6237,13 +6531,13 @@ function KindBadge({
|
|
|
6237
6531
|
}
|
|
6238
6532
|
var SEVERITY_CLASS = {
|
|
6239
6533
|
bug: "qa-bg-danger-tint qa-text-danger",
|
|
6240
|
-
|
|
6241
|
-
|
|
6534
|
+
enhance: "qa-bg-warn-tint qa-text-warn",
|
|
6535
|
+
design: "qa-bg-accent-tint qa-text-accent"
|
|
6242
6536
|
};
|
|
6243
6537
|
var SEVERITY_LABEL_KEY = {
|
|
6244
6538
|
bug: "sev_bug",
|
|
6245
|
-
|
|
6246
|
-
|
|
6539
|
+
enhance: "sev_enhance",
|
|
6540
|
+
design: "sev_design"
|
|
6247
6541
|
};
|
|
6248
6542
|
function SeverityChip({ severity, t }) {
|
|
6249
6543
|
return /* @__PURE__ */ jsxs(
|
|
@@ -6348,7 +6642,7 @@ function NoteItem({
|
|
|
6348
6642
|
notify(t("copy_failed"), { tone: "error" });
|
|
6349
6643
|
}
|
|
6350
6644
|
};
|
|
6351
|
-
const severityDot = severity === "bug" ? "var(--qa-danger)" : severity === "
|
|
6645
|
+
const severityDot = severity === "bug" ? "var(--qa-danger)" : severity === "enhance" ? "var(--qa-warn)" : "var(--qa-accent)";
|
|
6352
6646
|
if (dense && !open && !editing) {
|
|
6353
6647
|
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
6354
6648
|
"button",
|
|
@@ -6891,22 +7185,22 @@ function NoteFilterBar() {
|
|
|
6891
7185
|
onClick: sev("bug")
|
|
6892
7186
|
},
|
|
6893
7187
|
{
|
|
6894
|
-
key: "
|
|
6895
|
-
label: t("
|
|
6896
|
-
count: noteCounts.
|
|
6897
|
-
active: filter.severity === "
|
|
6898
|
-
icon: "
|
|
7188
|
+
key: "enhance",
|
|
7189
|
+
label: t("sev_enhance"),
|
|
7190
|
+
count: noteCounts.enhance,
|
|
7191
|
+
active: filter.severity === "enhance",
|
|
7192
|
+
icon: "Plus",
|
|
6899
7193
|
tone: "warn",
|
|
6900
|
-
onClick: sev("
|
|
7194
|
+
onClick: sev("enhance")
|
|
6901
7195
|
},
|
|
6902
7196
|
{
|
|
6903
|
-
key: "
|
|
6904
|
-
label: t("
|
|
6905
|
-
count: noteCounts.
|
|
6906
|
-
active: filter.severity === "
|
|
7197
|
+
key: "design",
|
|
7198
|
+
label: t("sev_design"),
|
|
7199
|
+
count: noteCounts.design,
|
|
7200
|
+
active: filter.severity === "design",
|
|
6907
7201
|
icon: "Pencil",
|
|
6908
7202
|
tone: "accent",
|
|
6909
|
-
onClick: sev("
|
|
7203
|
+
onClick: sev("design")
|
|
6910
7204
|
},
|
|
6911
7205
|
{
|
|
6912
7206
|
key: "open",
|
|
@@ -7345,46 +7639,25 @@ function SettingsSheet({ onClose }) {
|
|
|
7345
7639
|
);
|
|
7346
7640
|
}
|
|
7347
7641
|
function WelcomeCard() {
|
|
7348
|
-
const { t,
|
|
7642
|
+
const { t, dismissWelcome } = useQa();
|
|
7349
7643
|
return /* @__PURE__ */ jsxs(
|
|
7350
7644
|
"div",
|
|
7351
7645
|
{
|
|
7352
|
-
className: "qa-rounded-xl qa-border qa-border-subtle qa-bg-1 qa-
|
|
7646
|
+
className: "qa-flex qa-items-center qa-gap-2 qa-rounded-xl qa-border qa-border-subtle qa-bg-1 qa-px-3 qa-py-2",
|
|
7353
7647
|
role: "note",
|
|
7354
7648
|
children: [
|
|
7355
|
-
/* @__PURE__ */
|
|
7356
|
-
|
|
7357
|
-
"span",
|
|
7358
|
-
{
|
|
7359
|
-
"aria-hidden": "true",
|
|
7360
|
-
className: "qa-shrink-0",
|
|
7361
|
-
style: { width: 6, height: 6, background: "var(--qa-accent)" }
|
|
7362
|
-
}
|
|
7363
|
-
),
|
|
7364
|
-
t("welcome_title", { brand: brand.label })
|
|
7365
|
-
] }),
|
|
7366
|
-
/* @__PURE__ */ jsxs("ul", { className: "qa-m-0 qa-space-y-1 qa-text-xs qa-text-mid", children: [
|
|
7367
|
-
/* @__PURE__ */ jsxs("li", { className: "qa-flex qa-items-start qa-gap-1.5", children: [
|
|
7368
|
-
/* @__PURE__ */ jsx(Icon, { name: "Crosshair", size: 12, className: "qa-shrink-0 qa-mt-1" }),
|
|
7369
|
-
/* @__PURE__ */ jsx("span", { children: t("welcome_capture") })
|
|
7370
|
-
] }),
|
|
7371
|
-
/* @__PURE__ */ jsxs("li", { className: "qa-flex qa-items-start qa-gap-1.5", children: [
|
|
7372
|
-
/* @__PURE__ */ jsx(Icon, { name: "Pencil", size: 12, className: "qa-shrink-0 qa-mt-1" }),
|
|
7373
|
-
/* @__PURE__ */ jsx("span", { children: t("welcome_say") })
|
|
7374
|
-
] }),
|
|
7375
|
-
/* @__PURE__ */ jsxs("li", { className: "qa-flex qa-items-start qa-gap-1.5", children: [
|
|
7376
|
-
/* @__PURE__ */ jsx(Icon, { name: "CheckCircle2", size: 12, className: "qa-shrink-0 qa-mt-1" }),
|
|
7377
|
-
/* @__PURE__ */ jsx("span", { children: t("welcome_safe") })
|
|
7378
|
-
] })
|
|
7379
|
-
] }),
|
|
7649
|
+
/* @__PURE__ */ jsx(Icon, { name: "Crosshair", size: 13, className: "qa-shrink-0 qa-text-accent" }),
|
|
7650
|
+
/* @__PURE__ */ jsx("span", { className: "qa-flex-1 qa-text-xs qa-text-mid", children: t("welcome_capture") }),
|
|
7380
7651
|
/* @__PURE__ */ jsx(
|
|
7381
7652
|
"button",
|
|
7382
7653
|
{
|
|
7383
7654
|
type: "button",
|
|
7384
7655
|
onClick: dismissWelcome,
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7656
|
+
"aria-label": t("welcome_got_it"),
|
|
7657
|
+
title: t("welcome_got_it"),
|
|
7658
|
+
className: "qa-tap-icon qa-shrink-0 qa-rounded-full qa-text-mid qa-focus-ring",
|
|
7659
|
+
style: { background: "transparent", border: "none", cursor: "pointer", padding: 2 },
|
|
7660
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "X", size: 13 })
|
|
7388
7661
|
}
|
|
7389
7662
|
)
|
|
7390
7663
|
]
|
|
@@ -8851,16 +9124,16 @@ function unlockPageScroll() {
|
|
|
8851
9124
|
var DRAG_THRESHOLD2 = 6;
|
|
8852
9125
|
var TOUCH_DRAG_THRESHOLD = 12;
|
|
8853
9126
|
var MIN_REGION_SIZE = 8;
|
|
8854
|
-
var SEVERITIES2 = ["bug", "
|
|
9127
|
+
var SEVERITIES2 = ["bug", "design", "enhance"];
|
|
8855
9128
|
var SEVERITY_ICON = {
|
|
8856
9129
|
bug: "Bug",
|
|
8857
|
-
|
|
8858
|
-
|
|
9130
|
+
design: "Pencil",
|
|
9131
|
+
enhance: "Plus"
|
|
8859
9132
|
};
|
|
8860
9133
|
var SEVERITY_LABEL_KEY2 = {
|
|
8861
9134
|
bug: "sev_bug",
|
|
8862
|
-
|
|
8863
|
-
|
|
9135
|
+
design: "sev_design",
|
|
9136
|
+
enhance: "sev_enhance"
|
|
8864
9137
|
};
|
|
8865
9138
|
function clampRegionRect(rect) {
|
|
8866
9139
|
const vw = typeof window !== "undefined" ? window.innerWidth : rect.left + rect.width;
|
|
@@ -9814,7 +10087,7 @@ function CaptureMode() {
|
|
|
9814
10087
|
/* @__PURE__ */ jsx("span", { className: "qa-text-11 qa-text-mid qa-me-1", children: t("severity_label") }),
|
|
9815
10088
|
SEVERITIES2.map((sev) => {
|
|
9816
10089
|
const active = severity === sev;
|
|
9817
|
-
const toneClass = sev === "bug" ? "qa-bg-danger-tint qa-text-danger" : sev === "
|
|
10090
|
+
const toneClass = sev === "bug" ? "qa-bg-danger-tint qa-text-danger" : sev === "enhance" ? "qa-bg-warn-tint qa-text-warn" : "qa-bg-accent-tint qa-text-accent";
|
|
9818
10091
|
return /* @__PURE__ */ jsxs(
|
|
9819
10092
|
"button",
|
|
9820
10093
|
{
|
|
@@ -10092,5 +10365,5 @@ function Qapture({ config }) {
|
|
|
10092
10365
|
}
|
|
10093
10366
|
|
|
10094
10367
|
export { Qapture, deleteQaDatabase, initQaStudio };
|
|
10095
|
-
//# sourceMappingURL=chunk-
|
|
10096
|
-
//# sourceMappingURL=chunk-
|
|
10368
|
+
//# sourceMappingURL=chunk-FVQKCQC3.js.map
|
|
10369
|
+
//# sourceMappingURL=chunk-FVQKCQC3.js.map
|