browsertrack 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/docs.yml +54 -0
- package/AGENTS.md +133 -0
- package/README.md +1 -1
- package/dist/{chunk-6A7FFDIB.js → chunk-6VA7GBAO.js} +29 -4
- package/dist/chunk-6VA7GBAO.js.map +1 -0
- package/dist/{chunk-ANMR5WBH.js → chunk-G2Y3CXCY.js} +2 -2
- package/dist/{chunk-BSKNG4V7.js → chunk-ILRYKMME.js} +30 -1
- package/dist/chunk-ILRYKMME.js.map +1 -0
- package/dist/{chunk-X7C5CHBO.js → chunk-SKCMT2DE.js} +637 -76
- package/dist/chunk-SKCMT2DE.js.map +1 -0
- package/dist/{chunk-ZLNGOOH2.js → chunk-SPCIROIU.js} +65 -3
- package/dist/chunk-SPCIROIU.js.map +1 -0
- package/dist/cli/index.js +115 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/client/index.cjs +637 -75
- package/dist/client/index.d.ts +16 -2
- package/dist/client/index.js +2 -2
- package/dist/client.iife.js +393 -72
- package/dist/core/index.d.ts +12 -4
- package/dist/core/index.js +9 -3
- package/dist/daemon/index.d.ts +1 -1
- package/dist/daemon/index.js +3 -3
- package/dist/{engine-DKloFjvs.d.ts → engine-CeT9URuN.d.ts} +4 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +13 -7
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +2 -2
- package/dist/{server-CN-se8td.d.ts → server-Dd8NX2Mk.d.ts} +1 -1
- package/docboot.config.js +16 -0
- package/docs/cli.md +51 -0
- package/docs/closed-loop-verification.md +57 -0
- package/docs/getting-started.md +122 -0
- package/docs/incidents-diagnostics.md +61 -0
- package/docs/index.md +46 -0
- package/docs/mcp-reference.md +128 -0
- package/docs/security-privacy.md +32 -0
- package/docs/visual-notes.md +67 -0
- package/package.json +6 -2
- package/packages/client/package.json +2 -2
- package/packages/client/src/notes/inspector.ts +689 -79
- package/packages/client/src/transport/websocket.ts +15 -0
- package/packages/core/package.json +3 -0
- package/packages/core/src/redaction.ts +40 -5
- package/packages/daemon/src/server/ws.ts +72 -1
- package/packages/daemon/src/session/manager.ts +21 -0
- package/packages/daemon/src/storage/db.ts +10 -1
- package/test/client/interceptors.test.ts +61 -0
- package/test/core/redaction.test.ts +12 -0
- package/dist/chunk-6A7FFDIB.js.map +0 -1
- package/dist/chunk-BSKNG4V7.js.map +0 -1
- package/dist/chunk-X7C5CHBO.js.map +0 -1
- package/dist/chunk-ZLNGOOH2.js.map +0 -1
- package/packages/core/dist/index.d.ts +0 -317
- package/packages/core/dist/index.js +0 -221
- /package/dist/{chunk-ANMR5WBH.js.map → chunk-G2Y3CXCY.js.map} +0 -0
package/dist/client/index.cjs
CHANGED
|
@@ -58,6 +58,8 @@ var BreadcrumbBuffer = class {
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
// packages/core/src/redaction.ts
|
|
61
|
+
var import_redact = require("@visulima/redact");
|
|
62
|
+
var REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
61
63
|
var SENSITIVE_KEY_PATTERNS = [
|
|
62
64
|
/^authorization$/i,
|
|
63
65
|
/^cookie$/i,
|
|
@@ -87,7 +89,6 @@ var SENSITIVE_QUERY_PARAMS = [
|
|
|
87
89
|
"code",
|
|
88
90
|
"signature"
|
|
89
91
|
];
|
|
90
|
-
var REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
91
92
|
function isSensitiveKey(key) {
|
|
92
93
|
if (!key) return false;
|
|
93
94
|
const cleaned = key.replace(/[-_]/g, "");
|
|
@@ -1020,6 +1021,7 @@ var WebSocketTransport = class {
|
|
|
1020
1021
|
__publicField(this, "maxReconnectDelay", 1e4);
|
|
1021
1022
|
__publicField(this, "reconnectTimer", null);
|
|
1022
1023
|
__publicField(this, "commandHandler");
|
|
1024
|
+
__publicField(this, "messageListeners", []);
|
|
1023
1025
|
__publicField(this, "isDestroyed", false);
|
|
1024
1026
|
this.wsUrl = options.url || "ws://127.0.0.1:7331";
|
|
1025
1027
|
this.projectId = options.projectId;
|
|
@@ -1028,6 +1030,12 @@ var WebSocketTransport = class {
|
|
|
1028
1030
|
setCommandHandler(handler) {
|
|
1029
1031
|
this.commandHandler = handler;
|
|
1030
1032
|
}
|
|
1033
|
+
onMessage(listener) {
|
|
1034
|
+
this.messageListeners.push(listener);
|
|
1035
|
+
return () => {
|
|
1036
|
+
this.messageListeners = this.messageListeners.filter((l) => l !== listener);
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1031
1039
|
getSessionId() {
|
|
1032
1040
|
return this.sessionId;
|
|
1033
1041
|
}
|
|
@@ -1051,6 +1059,12 @@ var WebSocketTransport = class {
|
|
|
1051
1059
|
const raw = typeof event.data === "string" ? event.data : "";
|
|
1052
1060
|
if (!raw) return;
|
|
1053
1061
|
const msg = JSON.parse(raw);
|
|
1062
|
+
for (const listener of this.messageListeners) {
|
|
1063
|
+
try {
|
|
1064
|
+
listener(msg);
|
|
1065
|
+
} catch {
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1054
1068
|
if (msg.type === "hello_ack") {
|
|
1055
1069
|
this.sessionId = msg.sessionId;
|
|
1056
1070
|
if (this.debug) {
|
|
@@ -1165,8 +1179,11 @@ var NoteInspector = class {
|
|
|
1165
1179
|
__publicField(this, "highlightOverlay", null);
|
|
1166
1180
|
__publicField(this, "regionOverlay", null);
|
|
1167
1181
|
__publicField(this, "regionBox", null);
|
|
1182
|
+
__publicField(this, "regionBanner", null);
|
|
1183
|
+
__publicField(this, "markersContainer", null);
|
|
1168
1184
|
__publicField(this, "toolbarElement", null);
|
|
1169
1185
|
__publicField(this, "modalOverlay", null);
|
|
1186
|
+
__publicField(this, "cardOverlay", null);
|
|
1170
1187
|
__publicField(this, "activeMode", "idle");
|
|
1171
1188
|
__publicField(this, "hoveredElement", null);
|
|
1172
1189
|
__publicField(this, "selectedElement", null);
|
|
@@ -1174,6 +1191,8 @@ var NoteInspector = class {
|
|
|
1174
1191
|
__publicField(this, "isDraggingRegion", false);
|
|
1175
1192
|
__publicField(this, "dragStartX", 0);
|
|
1176
1193
|
__publicField(this, "dragStartY", 0);
|
|
1194
|
+
__publicField(this, "savedNotes", []);
|
|
1195
|
+
__publicField(this, "showMarkers", true);
|
|
1177
1196
|
__publicField(this, "cleanups", []);
|
|
1178
1197
|
this.transport = transport;
|
|
1179
1198
|
this.screenshotDriver = screenshotDriver;
|
|
@@ -1193,8 +1212,19 @@ var NoteInspector = class {
|
|
|
1193
1212
|
} else {
|
|
1194
1213
|
this.ensureContainer();
|
|
1195
1214
|
}
|
|
1215
|
+
const unsubscribe = this.transport.onMessage((msg) => {
|
|
1216
|
+
if (msg && msg.type === "notes_sync" && Array.isArray(msg.notes)) {
|
|
1217
|
+
this.syncNotes(msg.notes);
|
|
1218
|
+
}
|
|
1219
|
+
});
|
|
1220
|
+
this.cleanups.push(unsubscribe);
|
|
1196
1221
|
this.setupListeners();
|
|
1197
1222
|
}
|
|
1223
|
+
syncNotes(notes) {
|
|
1224
|
+
this.savedNotes = notes;
|
|
1225
|
+
this.updateToolbarCount();
|
|
1226
|
+
this.renderMarkers();
|
|
1227
|
+
}
|
|
1198
1228
|
setMode(mode) {
|
|
1199
1229
|
this.activeMode = mode;
|
|
1200
1230
|
this.updateToolbarState();
|
|
@@ -1222,16 +1252,17 @@ var NoteInspector = class {
|
|
|
1222
1252
|
const style = document.createElement("style");
|
|
1223
1253
|
style.textContent = `
|
|
1224
1254
|
:host {
|
|
1225
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1255
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
1226
1256
|
color-scheme: dark;
|
|
1227
1257
|
-webkit-font-smoothing: antialiased;
|
|
1258
|
+
-moz-osx-font-smoothing: grayscale;
|
|
1228
1259
|
}
|
|
1229
1260
|
|
|
1230
1261
|
/* 1. Element Highlight Overlay */
|
|
1231
1262
|
.bt-highlight {
|
|
1232
1263
|
position: fixed;
|
|
1233
1264
|
border: 2px solid #3b82f6;
|
|
1234
|
-
background: rgba(59, 130, 246, 0.
|
|
1265
|
+
background: rgba(59, 130, 246, 0.16);
|
|
1235
1266
|
border-radius: 4px;
|
|
1236
1267
|
pointer-events: none;
|
|
1237
1268
|
transition: all 0.05s ease-out;
|
|
@@ -1241,18 +1272,19 @@ var NoteInspector = class {
|
|
|
1241
1272
|
|
|
1242
1273
|
.bt-badge {
|
|
1243
1274
|
position: absolute;
|
|
1244
|
-
top: -
|
|
1275
|
+
top: -26px;
|
|
1245
1276
|
left: 0;
|
|
1246
|
-
background: #
|
|
1277
|
+
background: #0f172a;
|
|
1247
1278
|
color: #38bdf8;
|
|
1248
1279
|
border: 1px solid #3b82f6;
|
|
1249
1280
|
font-size: 11px;
|
|
1250
1281
|
font-weight: 600;
|
|
1251
|
-
|
|
1252
|
-
|
|
1282
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
1283
|
+
padding: 2px 7px;
|
|
1284
|
+
border-radius: 4px;
|
|
1253
1285
|
white-space: nowrap;
|
|
1254
1286
|
pointer-events: none;
|
|
1255
|
-
box-shadow: 0
|
|
1287
|
+
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.5);
|
|
1256
1288
|
}
|
|
1257
1289
|
|
|
1258
1290
|
/* 2. Region Selection Overlay */
|
|
@@ -1264,7 +1296,8 @@ var NoteInspector = class {
|
|
|
1264
1296
|
cursor: crosshair;
|
|
1265
1297
|
z-index: 2147483642;
|
|
1266
1298
|
pointer-events: auto;
|
|
1267
|
-
background: rgba(15, 23, 42, 0.
|
|
1299
|
+
background: rgba(15, 23, 42, 0.25);
|
|
1300
|
+
user-select: none;
|
|
1268
1301
|
}
|
|
1269
1302
|
|
|
1270
1303
|
.bt-region-box {
|
|
@@ -1278,32 +1311,171 @@ var NoteInspector = class {
|
|
|
1278
1311
|
|
|
1279
1312
|
.bt-region-badge {
|
|
1280
1313
|
position: absolute;
|
|
1281
|
-
top: -
|
|
1314
|
+
top: -26px;
|
|
1282
1315
|
left: 0;
|
|
1283
1316
|
background: #0f172a;
|
|
1284
1317
|
color: #38bdf8;
|
|
1285
1318
|
border: 1px solid #0284c7;
|
|
1286
1319
|
font-size: 11px;
|
|
1287
1320
|
font-weight: 600;
|
|
1288
|
-
|
|
1289
|
-
|
|
1321
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
1322
|
+
padding: 2px 7px;
|
|
1323
|
+
border-radius: 4px;
|
|
1290
1324
|
white-space: nowrap;
|
|
1291
1325
|
pointer-events: none;
|
|
1326
|
+
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.5);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
.bt-region-banner {
|
|
1330
|
+
position: fixed;
|
|
1331
|
+
top: 20px;
|
|
1332
|
+
left: 50%;
|
|
1333
|
+
transform: translateX(-50%);
|
|
1334
|
+
background: #0f172a;
|
|
1335
|
+
color: #f8fafc;
|
|
1336
|
+
border: 1px solid #0284c7;
|
|
1337
|
+
border-radius: 30px;
|
|
1338
|
+
padding: 8px 16px;
|
|
1339
|
+
display: flex;
|
|
1340
|
+
align-items: center;
|
|
1341
|
+
gap: 12px;
|
|
1342
|
+
box-shadow: 0 10px 25px -5px rgba(0,0,0,0.6);
|
|
1343
|
+
font-size: 12.5px;
|
|
1344
|
+
font-weight: 500;
|
|
1345
|
+
pointer-events: auto;
|
|
1346
|
+
z-index: 2147483645;
|
|
1347
|
+
user-select: none;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
.bt-region-cancel-btn {
|
|
1351
|
+
background: rgba(239, 68, 68, 0.15);
|
|
1352
|
+
color: #fca5a5;
|
|
1353
|
+
border: 1px solid rgba(239, 68, 68, 0.4);
|
|
1354
|
+
padding: 3px 10px;
|
|
1355
|
+
border-radius: 20px;
|
|
1356
|
+
font-size: 11px;
|
|
1357
|
+
font-weight: 600;
|
|
1358
|
+
cursor: pointer;
|
|
1359
|
+
transition: all 0.15s ease;
|
|
1360
|
+
display: inline-flex;
|
|
1361
|
+
align-items: center;
|
|
1362
|
+
gap: 4px;
|
|
1363
|
+
font-family: inherit;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
.bt-region-cancel-btn:hover {
|
|
1367
|
+
background: rgba(239, 68, 68, 0.3);
|
|
1368
|
+
color: #ffffff;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/* 3. Note Markers on Page */
|
|
1372
|
+
.bt-markers-layer {
|
|
1373
|
+
position: fixed;
|
|
1374
|
+
top: 0;
|
|
1375
|
+
left: 0;
|
|
1376
|
+
width: 0;
|
|
1377
|
+
height: 0;
|
|
1378
|
+
pointer-events: none;
|
|
1379
|
+
z-index: 2147483638;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
.bt-note-marker {
|
|
1383
|
+
position: fixed;
|
|
1384
|
+
pointer-events: auto;
|
|
1385
|
+
background: linear-gradient(135deg, #2563eb, #1d4ed8);
|
|
1386
|
+
color: #ffffff;
|
|
1387
|
+
border: 2px solid #ffffff;
|
|
1388
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.5), 0 0 0 1px rgba(37,99,235,0.4);
|
|
1389
|
+
border-radius: 999px;
|
|
1390
|
+
height: 26px;
|
|
1391
|
+
min-width: 26px;
|
|
1392
|
+
padding: 0 7px;
|
|
1393
|
+
display: inline-flex;
|
|
1394
|
+
align-items: center;
|
|
1395
|
+
justify-content: center;
|
|
1396
|
+
gap: 4px;
|
|
1397
|
+
cursor: pointer;
|
|
1398
|
+
font-size: 11px;
|
|
1399
|
+
font-weight: 700;
|
|
1400
|
+
user-select: none;
|
|
1401
|
+
transition: transform 0.15s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.15s ease;
|
|
1402
|
+
animation: bt-pop-in 0.2s ease-out;
|
|
1403
|
+
box-sizing: border-box;
|
|
1404
|
+
z-index: 2147483641;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
@keyframes bt-pop-in {
|
|
1408
|
+
0% { transform: scale(0.6); opacity: 0; }
|
|
1409
|
+
100% { transform: scale(1); opacity: 1; }
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
.bt-note-marker:hover {
|
|
1413
|
+
transform: scale(1.15) translateY(-2px);
|
|
1414
|
+
box-shadow: 0 8px 20px rgba(37,99,235,0.6), 0 0 0 2px #60a5fa;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
.bt-marker-resolved {
|
|
1418
|
+
background: linear-gradient(135deg, #475569, #334155);
|
|
1419
|
+
border-color: #94a3b8;
|
|
1420
|
+
opacity: 0.75;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
.bt-region-marker-box {
|
|
1424
|
+
position: fixed;
|
|
1425
|
+
border: 2px dashed #0284c7;
|
|
1426
|
+
background: rgba(14, 165, 233, 0.08);
|
|
1427
|
+
pointer-events: none;
|
|
1428
|
+
box-sizing: border-box;
|
|
1429
|
+
border-radius: 6px;
|
|
1430
|
+
z-index: 2147483639;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
.bt-page-notes-dock {
|
|
1434
|
+
position: fixed;
|
|
1435
|
+
top: 16px;
|
|
1436
|
+
right: 16px;
|
|
1437
|
+
display: flex;
|
|
1438
|
+
flex-direction: column;
|
|
1439
|
+
gap: 6px;
|
|
1440
|
+
pointer-events: none;
|
|
1441
|
+
z-index: 2147483641;
|
|
1292
1442
|
}
|
|
1293
1443
|
|
|
1294
|
-
|
|
1444
|
+
.bt-page-note-pill {
|
|
1445
|
+
background: #0f172a;
|
|
1446
|
+
color: #c084fc;
|
|
1447
|
+
border: 1px solid #7e22ce;
|
|
1448
|
+
border-radius: 20px;
|
|
1449
|
+
padding: 5px 12px;
|
|
1450
|
+
font-size: 11.5px;
|
|
1451
|
+
font-weight: 600;
|
|
1452
|
+
display: inline-flex;
|
|
1453
|
+
align-items: center;
|
|
1454
|
+
gap: 6px;
|
|
1455
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.5);
|
|
1456
|
+
cursor: pointer;
|
|
1457
|
+
pointer-events: auto;
|
|
1458
|
+
transition: all 0.15s ease;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
.bt-page-note-pill:hover {
|
|
1462
|
+
background: #1e1b4b;
|
|
1463
|
+
transform: translateY(-1px);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
/* 4. Floating Quick Toolbar */
|
|
1295
1467
|
.bt-toolbar {
|
|
1296
1468
|
position: fixed;
|
|
1297
1469
|
bottom: 20px;
|
|
1298
1470
|
right: 20px;
|
|
1299
|
-
background: #
|
|
1471
|
+
background: #0f172a;
|
|
1300
1472
|
border: 1px solid #334155;
|
|
1301
1473
|
border-radius: 30px;
|
|
1302
1474
|
padding: 4px 6px;
|
|
1303
1475
|
display: flex;
|
|
1304
1476
|
align-items: center;
|
|
1305
1477
|
gap: 4px;
|
|
1306
|
-
box-shadow: 0 10px
|
|
1478
|
+
box-shadow: 0 10px 25px -3px rgba(0,0,0,0.6), 0 4px 6px -4px rgba(0,0,0,0.4);
|
|
1307
1479
|
pointer-events: auto;
|
|
1308
1480
|
z-index: 2147483646;
|
|
1309
1481
|
user-select: none;
|
|
@@ -1316,17 +1488,18 @@ var NoteInspector = class {
|
|
|
1316
1488
|
color: #94a3b8;
|
|
1317
1489
|
font-size: 12px;
|
|
1318
1490
|
font-weight: 500;
|
|
1319
|
-
padding: 6px
|
|
1491
|
+
padding: 6px 12px;
|
|
1320
1492
|
border-radius: 20px;
|
|
1321
1493
|
cursor: pointer;
|
|
1322
1494
|
display: flex;
|
|
1323
1495
|
align-items: center;
|
|
1324
|
-
gap:
|
|
1496
|
+
gap: 6px;
|
|
1325
1497
|
transition: all 0.15s ease;
|
|
1498
|
+
font-family: inherit;
|
|
1326
1499
|
}
|
|
1327
1500
|
|
|
1328
1501
|
.bt-toolbar-btn:hover {
|
|
1329
|
-
background: #
|
|
1502
|
+
background: #1e293b;
|
|
1330
1503
|
color: #f8fafc;
|
|
1331
1504
|
}
|
|
1332
1505
|
|
|
@@ -1334,15 +1507,27 @@ var NoteInspector = class {
|
|
|
1334
1507
|
background: #2563eb;
|
|
1335
1508
|
color: #ffffff;
|
|
1336
1509
|
font-weight: 600;
|
|
1510
|
+
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.35);
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
.bt-count-pill {
|
|
1514
|
+
background: rgba(255, 255, 255, 0.2);
|
|
1515
|
+
color: #ffffff;
|
|
1516
|
+
font-size: 10px;
|
|
1517
|
+
font-weight: 700;
|
|
1518
|
+
padding: 1px 6px;
|
|
1519
|
+
border-radius: 10px;
|
|
1520
|
+
line-height: 1.2;
|
|
1337
1521
|
}
|
|
1338
1522
|
|
|
1339
1523
|
.bt-toolbar-divider {
|
|
1340
1524
|
width: 1px;
|
|
1341
1525
|
height: 16px;
|
|
1342
1526
|
background: #334155;
|
|
1527
|
+
margin: 0 2px;
|
|
1343
1528
|
}
|
|
1344
1529
|
|
|
1345
|
-
/*
|
|
1530
|
+
/* 5. Modals & Popover Card */
|
|
1346
1531
|
.bt-modal-backdrop {
|
|
1347
1532
|
position: fixed;
|
|
1348
1533
|
top: 0;
|
|
@@ -1350,7 +1535,7 @@ var NoteInspector = class {
|
|
|
1350
1535
|
width: 100vw;
|
|
1351
1536
|
height: 100vh;
|
|
1352
1537
|
background: rgba(15, 23, 42, 0.75);
|
|
1353
|
-
backdrop-filter: blur(
|
|
1538
|
+
backdrop-filter: blur(6px);
|
|
1354
1539
|
display: flex;
|
|
1355
1540
|
align-items: center;
|
|
1356
1541
|
justify-content: center;
|
|
@@ -1358,20 +1543,26 @@ var NoteInspector = class {
|
|
|
1358
1543
|
z-index: 2147483647;
|
|
1359
1544
|
opacity: 1;
|
|
1360
1545
|
box-sizing: border-box;
|
|
1546
|
+
animation: bt-fade-in 0.15s ease-out;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
@keyframes bt-fade-in {
|
|
1550
|
+
from { opacity: 0; transform: scale(0.98); }
|
|
1551
|
+
to { opacity: 1; transform: scale(1); }
|
|
1361
1552
|
}
|
|
1362
1553
|
|
|
1363
1554
|
.bt-modal {
|
|
1364
|
-
background: #
|
|
1555
|
+
background: #0f172a;
|
|
1365
1556
|
color: #f8fafc;
|
|
1366
1557
|
border: 1px solid #334155;
|
|
1367
|
-
border-radius:
|
|
1368
|
-
padding:
|
|
1369
|
-
width:
|
|
1370
|
-
max-width:
|
|
1371
|
-
box-shadow: 0
|
|
1558
|
+
border-radius: 14px;
|
|
1559
|
+
padding: 20px;
|
|
1560
|
+
width: 450px;
|
|
1561
|
+
max-width: 92vw;
|
|
1562
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(255, 255, 255, 0.05);
|
|
1372
1563
|
display: flex;
|
|
1373
1564
|
flex-direction: column;
|
|
1374
|
-
gap:
|
|
1565
|
+
gap: 14px;
|
|
1375
1566
|
box-sizing: border-box;
|
|
1376
1567
|
}
|
|
1377
1568
|
|
|
@@ -1382,87 +1573,181 @@ var NoteInspector = class {
|
|
|
1382
1573
|
}
|
|
1383
1574
|
|
|
1384
1575
|
.bt-modal-title {
|
|
1385
|
-
font-size:
|
|
1576
|
+
font-size: 14.5px;
|
|
1386
1577
|
font-weight: 600;
|
|
1578
|
+
letter-spacing: -0.01em;
|
|
1387
1579
|
display: flex;
|
|
1388
1580
|
align-items: center;
|
|
1389
|
-
gap:
|
|
1581
|
+
gap: 8px;
|
|
1390
1582
|
color: #f8fafc;
|
|
1391
1583
|
}
|
|
1392
1584
|
|
|
1393
1585
|
.bt-mode-badge {
|
|
1394
1586
|
font-size: 10px;
|
|
1395
1587
|
font-weight: 700;
|
|
1588
|
+
letter-spacing: 0.05em;
|
|
1396
1589
|
text-transform: uppercase;
|
|
1397
|
-
|
|
1590
|
+
padding: 2px 7px;
|
|
1591
|
+
border-radius: 6px;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
.bt-badge-element {
|
|
1595
|
+
background: rgba(59, 130, 246, 0.15);
|
|
1398
1596
|
color: #60a5fa;
|
|
1399
|
-
border: 1px solid
|
|
1400
|
-
|
|
1401
|
-
|
|
1597
|
+
border: 1px solid rgba(59, 130, 246, 0.4);
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
.bt-badge-region {
|
|
1601
|
+
background: rgba(14, 165, 233, 0.15);
|
|
1602
|
+
color: #38bdf8;
|
|
1603
|
+
border: 1px solid rgba(14, 165, 233, 0.4);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
.bt-badge-page {
|
|
1607
|
+
background: rgba(168, 85, 247, 0.15);
|
|
1608
|
+
color: #c084fc;
|
|
1609
|
+
border: 1px solid rgba(168, 85, 247, 0.4);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
.bt-badge-status-open {
|
|
1613
|
+
background: rgba(16, 185, 129, 0.15);
|
|
1614
|
+
color: #34d399;
|
|
1615
|
+
border: 1px solid rgba(16, 185, 129, 0.4);
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
.bt-badge-status-resolved {
|
|
1619
|
+
background: rgba(100, 116, 139, 0.2);
|
|
1620
|
+
color: #94a3b8;
|
|
1621
|
+
border: 1px solid rgba(100, 116, 139, 0.4);
|
|
1402
1622
|
}
|
|
1403
1623
|
|
|
1404
1624
|
.bt-close-btn {
|
|
1405
1625
|
background: transparent;
|
|
1406
1626
|
border: none;
|
|
1407
1627
|
color: #94a3b8;
|
|
1408
|
-
font-size:
|
|
1628
|
+
font-size: 15px;
|
|
1409
1629
|
cursor: pointer;
|
|
1410
|
-
padding:
|
|
1411
|
-
border-radius:
|
|
1630
|
+
padding: 3px 7px;
|
|
1631
|
+
border-radius: 6px;
|
|
1632
|
+
transition: all 0.12s ease;
|
|
1633
|
+
display: flex;
|
|
1634
|
+
align-items: center;
|
|
1635
|
+
justify-content: center;
|
|
1412
1636
|
}
|
|
1413
1637
|
.bt-close-btn:hover {
|
|
1414
|
-
background: #
|
|
1638
|
+
background: #1e293b;
|
|
1415
1639
|
color: #ffffff;
|
|
1416
1640
|
}
|
|
1417
1641
|
|
|
1418
1642
|
.bt-target-pill {
|
|
1419
|
-
background: #
|
|
1643
|
+
background: #090d16;
|
|
1420
1644
|
color: #94a3b8;
|
|
1421
|
-
border: 1px solid #
|
|
1422
|
-
border-radius:
|
|
1423
|
-
padding:
|
|
1645
|
+
border: 1px solid #1e293b;
|
|
1646
|
+
border-radius: 8px;
|
|
1647
|
+
padding: 8px 12px;
|
|
1424
1648
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
1425
|
-
font-size:
|
|
1649
|
+
font-size: 11.5px;
|
|
1650
|
+
display: flex;
|
|
1651
|
+
align-items: center;
|
|
1652
|
+
gap: 8px;
|
|
1653
|
+
overflow: hidden;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
.bt-pill-content {
|
|
1426
1657
|
overflow: hidden;
|
|
1427
1658
|
text-overflow: ellipsis;
|
|
1428
1659
|
white-space: nowrap;
|
|
1660
|
+
color: #cbd5e1;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
.bt-note-message-box {
|
|
1664
|
+
background: #090d16;
|
|
1665
|
+
border: 1px solid #1e293b;
|
|
1666
|
+
border-radius: 8px;
|
|
1667
|
+
padding: 12px 14px;
|
|
1668
|
+
font-size: 13.5px;
|
|
1669
|
+
line-height: 1.5;
|
|
1670
|
+
color: #f1f5f9;
|
|
1671
|
+
white-space: pre-wrap;
|
|
1672
|
+
word-break: break-word;
|
|
1673
|
+
max-height: 180px;
|
|
1674
|
+
overflow-y: auto;
|
|
1429
1675
|
}
|
|
1430
1676
|
|
|
1431
1677
|
.bt-textarea {
|
|
1432
|
-
background: #
|
|
1678
|
+
background: #090d16;
|
|
1433
1679
|
color: #f8fafc;
|
|
1434
1680
|
border: 1px solid #334155;
|
|
1435
|
-
border-radius:
|
|
1436
|
-
padding:
|
|
1437
|
-
font-size:
|
|
1681
|
+
border-radius: 8px;
|
|
1682
|
+
padding: 12px;
|
|
1683
|
+
font-size: 13.5px;
|
|
1684
|
+
line-height: 1.5;
|
|
1438
1685
|
resize: vertical;
|
|
1439
|
-
min-height:
|
|
1686
|
+
min-height: 95px;
|
|
1440
1687
|
outline: none;
|
|
1441
1688
|
box-sizing: border-box;
|
|
1442
1689
|
width: 100%;
|
|
1443
1690
|
font-family: inherit;
|
|
1691
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
.bt-textarea::placeholder {
|
|
1695
|
+
color: #64748b;
|
|
1444
1696
|
}
|
|
1445
1697
|
|
|
1446
1698
|
.bt-textarea:focus {
|
|
1447
1699
|
border-color: #3b82f6;
|
|
1448
|
-
box-shadow: 0 0 0
|
|
1700
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25);
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
.bt-modal-footer {
|
|
1704
|
+
display: flex;
|
|
1705
|
+
justify-content: space-between;
|
|
1706
|
+
align-items: center;
|
|
1707
|
+
gap: 12px;
|
|
1708
|
+
margin-top: 2px;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
.bt-kbd-hint {
|
|
1712
|
+
font-size: 11px;
|
|
1713
|
+
color: #64748b;
|
|
1714
|
+
display: flex;
|
|
1715
|
+
align-items: center;
|
|
1716
|
+
gap: 4px;
|
|
1717
|
+
user-select: none;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
.bt-kbd-hint kbd {
|
|
1721
|
+
background: #1e293b;
|
|
1722
|
+
color: #94a3b8;
|
|
1723
|
+
border: 1px solid #334155;
|
|
1724
|
+
border-radius: 4px;
|
|
1725
|
+
padding: 1px 5px;
|
|
1726
|
+
font-family: inherit;
|
|
1727
|
+
font-size: 10px;
|
|
1728
|
+
font-weight: 600;
|
|
1449
1729
|
}
|
|
1450
1730
|
|
|
1451
1731
|
.bt-modal-actions {
|
|
1452
1732
|
display: flex;
|
|
1453
1733
|
justify-content: flex-end;
|
|
1734
|
+
align-items: center;
|
|
1454
1735
|
gap: 8px;
|
|
1455
1736
|
}
|
|
1456
1737
|
|
|
1457
1738
|
.bt-btn {
|
|
1458
|
-
padding: 8px
|
|
1459
|
-
border-radius:
|
|
1460
|
-
font-size:
|
|
1739
|
+
padding: 8px 16px;
|
|
1740
|
+
border-radius: 7px;
|
|
1741
|
+
font-size: 12.5px;
|
|
1461
1742
|
font-weight: 600;
|
|
1462
1743
|
cursor: pointer;
|
|
1463
1744
|
border: 1px solid transparent;
|
|
1464
|
-
transition: all 0.
|
|
1745
|
+
transition: all 0.15s ease;
|
|
1465
1746
|
font-family: inherit;
|
|
1747
|
+
display: inline-flex;
|
|
1748
|
+
align-items: center;
|
|
1749
|
+
justify-content: center;
|
|
1750
|
+
gap: 6px;
|
|
1466
1751
|
}
|
|
1467
1752
|
|
|
1468
1753
|
.bt-btn-cancel {
|
|
@@ -1470,20 +1755,38 @@ var NoteInspector = class {
|
|
|
1470
1755
|
color: #94a3b8;
|
|
1471
1756
|
}
|
|
1472
1757
|
.bt-btn-cancel:hover {
|
|
1473
|
-
background: #
|
|
1758
|
+
background: #1e293b;
|
|
1474
1759
|
color: #f8fafc;
|
|
1475
1760
|
}
|
|
1476
1761
|
|
|
1477
1762
|
.bt-btn-save {
|
|
1478
1763
|
background: #2563eb;
|
|
1479
1764
|
color: #ffffff;
|
|
1765
|
+
box-shadow: 0 2px 6px rgba(37, 99, 235, 0.35);
|
|
1480
1766
|
}
|
|
1481
1767
|
.bt-btn-save:hover {
|
|
1482
1768
|
background: #1d4ed8;
|
|
1769
|
+
box-shadow: 0 4px 10px rgba(37, 99, 235, 0.45);
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
.bt-btn-resolve {
|
|
1773
|
+
background: rgba(16, 185, 129, 0.15);
|
|
1774
|
+
color: #6ee7b7;
|
|
1775
|
+
border: 1px solid rgba(16, 185, 129, 0.35);
|
|
1776
|
+
}
|
|
1777
|
+
.bt-btn-resolve:hover {
|
|
1778
|
+
background: rgba(16, 185, 129, 0.3);
|
|
1779
|
+
color: #ffffff;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
.bt-btn-delete {
|
|
1783
|
+
background: rgba(239, 68, 68, 0.15);
|
|
1784
|
+
color: #fca5a5;
|
|
1785
|
+
border: 1px solid rgba(239, 68, 68, 0.35);
|
|
1483
1786
|
}
|
|
1484
|
-
.bt-btn-
|
|
1485
|
-
|
|
1486
|
-
|
|
1787
|
+
.bt-btn-delete:hover {
|
|
1788
|
+
background: rgba(239, 68, 68, 0.3);
|
|
1789
|
+
color: #ffffff;
|
|
1487
1790
|
}
|
|
1488
1791
|
`;
|
|
1489
1792
|
this.shadowRoot.appendChild(style);
|
|
@@ -1491,6 +1794,9 @@ var NoteInspector = class {
|
|
|
1491
1794
|
this.highlightOverlay.className = "bt-highlight";
|
|
1492
1795
|
this.highlightOverlay.style.display = "none";
|
|
1493
1796
|
this.shadowRoot.appendChild(this.highlightOverlay);
|
|
1797
|
+
this.markersContainer = document.createElement("div");
|
|
1798
|
+
this.markersContainer.className = "bt-markers-layer";
|
|
1799
|
+
this.shadowRoot.appendChild(this.markersContainer);
|
|
1494
1800
|
if (this.options.showToolbar) {
|
|
1495
1801
|
this.createToolbar();
|
|
1496
1802
|
}
|
|
@@ -1517,19 +1823,33 @@ var NoteInspector = class {
|
|
|
1517
1823
|
<button class="bt-toolbar-btn" id="bt-mode-page" title="Leave full-page note">
|
|
1518
1824
|
<span>\u{1F4C4}</span> Page
|
|
1519
1825
|
</button>
|
|
1826
|
+
<div class="bt-toolbar-divider"></div>
|
|
1827
|
+
<button class="bt-toolbar-btn active" id="bt-toggle-notes" title="Toggle visible note markers on screen">
|
|
1828
|
+
<span>\u{1F4CC}</span> Notes <span class="bt-count-pill" id="bt-notes-count">0</span>
|
|
1829
|
+
</button>
|
|
1520
1830
|
`;
|
|
1521
1831
|
const btnElement = this.toolbarElement.querySelector("#bt-mode-element");
|
|
1522
1832
|
const btnRegion = this.toolbarElement.querySelector("#bt-mode-region");
|
|
1523
1833
|
const btnPage = this.toolbarElement.querySelector("#bt-mode-page");
|
|
1524
|
-
|
|
1834
|
+
const btnToggleNotes = this.toolbarElement.querySelector("#bt-toggle-notes");
|
|
1835
|
+
btnElement.onclick = (e) => {
|
|
1836
|
+
e.stopPropagation();
|
|
1525
1837
|
this.setMode(this.activeMode === "element" ? "idle" : "element");
|
|
1526
1838
|
};
|
|
1527
|
-
btnRegion.onclick = () => {
|
|
1839
|
+
btnRegion.onclick = (e) => {
|
|
1840
|
+
e.stopPropagation();
|
|
1528
1841
|
this.setMode(this.activeMode === "region" ? "idle" : "region");
|
|
1529
1842
|
};
|
|
1530
|
-
btnPage.onclick = () => {
|
|
1843
|
+
btnPage.onclick = (e) => {
|
|
1844
|
+
e.stopPropagation();
|
|
1531
1845
|
this.setMode("page");
|
|
1532
1846
|
};
|
|
1847
|
+
btnToggleNotes.onclick = (e) => {
|
|
1848
|
+
e.stopPropagation();
|
|
1849
|
+
this.showMarkers = !this.showMarkers;
|
|
1850
|
+
btnToggleNotes.classList.toggle("active", this.showMarkers);
|
|
1851
|
+
this.renderMarkers();
|
|
1852
|
+
};
|
|
1533
1853
|
this.shadowRoot.appendChild(this.toolbarElement);
|
|
1534
1854
|
}
|
|
1535
1855
|
updateToolbarState() {
|
|
@@ -1541,9 +1861,186 @@ var NoteInspector = class {
|
|
|
1541
1861
|
btnRegion?.classList.toggle("active", this.activeMode === "region");
|
|
1542
1862
|
btnPage?.classList.toggle("active", this.activeMode === "page");
|
|
1543
1863
|
}
|
|
1864
|
+
updateToolbarCount() {
|
|
1865
|
+
if (!this.toolbarElement) return;
|
|
1866
|
+
const countEl = this.toolbarElement.querySelector("#bt-notes-count");
|
|
1867
|
+
if (countEl) {
|
|
1868
|
+
const openCount = this.savedNotes.filter((n) => n.status === "OPEN").length;
|
|
1869
|
+
countEl.textContent = String(openCount);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
renderMarkers() {
|
|
1873
|
+
const root = this.ensureContainer();
|
|
1874
|
+
if (!root || !this.markersContainer) return;
|
|
1875
|
+
this.markersContainer.innerHTML = "";
|
|
1876
|
+
if (!this.showMarkers) return;
|
|
1877
|
+
const currentPath = window.location.pathname;
|
|
1878
|
+
const activeNotes = this.savedNotes.filter(
|
|
1879
|
+
(n) => n.status === "OPEN" && (n.route === currentPath || !n.route || n.route === "/" || window.location.href.includes(n.route))
|
|
1880
|
+
);
|
|
1881
|
+
const pageNotes = [];
|
|
1882
|
+
activeNotes.forEach((note, index) => {
|
|
1883
|
+
if (note.type === "page") {
|
|
1884
|
+
pageNotes.push(note);
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
if (note.type === "region" && note.region) {
|
|
1888
|
+
const regBox = document.createElement("div");
|
|
1889
|
+
regBox.className = "bt-region-marker-box";
|
|
1890
|
+
regBox.style.left = `${note.region.x}px`;
|
|
1891
|
+
regBox.style.top = `${note.region.y}px`;
|
|
1892
|
+
regBox.style.width = `${note.region.width}px`;
|
|
1893
|
+
regBox.style.height = `${note.region.height}px`;
|
|
1894
|
+
this.markersContainer.appendChild(regBox);
|
|
1895
|
+
const pin = document.createElement("div");
|
|
1896
|
+
pin.className = "bt-note-marker";
|
|
1897
|
+
pin.style.left = `${Math.max(4, note.region.x - 12)}px`;
|
|
1898
|
+
pin.style.top = `${Math.max(4, note.region.y - 12)}px`;
|
|
1899
|
+
pin.title = note.message;
|
|
1900
|
+
pin.innerHTML = `<span>\u{1F4D0}</span> <span>#${index + 1}</span>`;
|
|
1901
|
+
pin.onclick = (e) => {
|
|
1902
|
+
e.stopPropagation();
|
|
1903
|
+
this.openNoteCard(note);
|
|
1904
|
+
};
|
|
1905
|
+
this.markersContainer.appendChild(pin);
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1908
|
+
let targetEl = null;
|
|
1909
|
+
if (note.target?.selector) {
|
|
1910
|
+
try {
|
|
1911
|
+
targetEl = document.querySelector(note.target.selector);
|
|
1912
|
+
} catch {
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
const rect = targetEl ? targetEl.getBoundingClientRect() : note.target?.boundingRect;
|
|
1916
|
+
if (rect) {
|
|
1917
|
+
const pin = document.createElement("div");
|
|
1918
|
+
pin.className = "bt-note-marker";
|
|
1919
|
+
pin.setAttribute("data-note-id", note.id);
|
|
1920
|
+
pin.title = note.message;
|
|
1921
|
+
pin.style.left = `${Math.max(4, rect.left - 10)}px`;
|
|
1922
|
+
pin.style.top = `${Math.max(4, rect.top - 12)}px`;
|
|
1923
|
+
pin.innerHTML = `<span>\u{1F4DD}</span> <span>#${index + 1}</span>`;
|
|
1924
|
+
pin.onclick = (e) => {
|
|
1925
|
+
e.stopPropagation();
|
|
1926
|
+
this.openNoteCard(note);
|
|
1927
|
+
};
|
|
1928
|
+
if (targetEl) {
|
|
1929
|
+
pin.onmouseenter = () => this.updateHighlight(targetEl);
|
|
1930
|
+
pin.onmouseleave = () => this.hideHighlight();
|
|
1931
|
+
}
|
|
1932
|
+
this.markersContainer.appendChild(pin);
|
|
1933
|
+
}
|
|
1934
|
+
});
|
|
1935
|
+
if (pageNotes.length > 0) {
|
|
1936
|
+
const pageDock = document.createElement("div");
|
|
1937
|
+
pageDock.className = "bt-page-notes-dock";
|
|
1938
|
+
pageNotes.forEach((pNote, idx) => {
|
|
1939
|
+
const pill = document.createElement("div");
|
|
1940
|
+
pill.className = "bt-page-note-pill";
|
|
1941
|
+
pill.innerHTML = `<span>\u{1F4C4}</span> <span>Page Note (${truncate(pNote.message, 25)})</span>`;
|
|
1942
|
+
pill.onclick = (e) => {
|
|
1943
|
+
e.stopPropagation();
|
|
1944
|
+
this.openNoteCard(pNote);
|
|
1945
|
+
};
|
|
1946
|
+
pageDock.appendChild(pill);
|
|
1947
|
+
});
|
|
1948
|
+
this.markersContainer.appendChild(pageDock);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
updateMarkerPositions() {
|
|
1952
|
+
if (!this.showMarkers || !this.markersContainer) return;
|
|
1953
|
+
this.renderMarkers();
|
|
1954
|
+
}
|
|
1955
|
+
openNoteCard(note) {
|
|
1956
|
+
const root = this.ensureContainer();
|
|
1957
|
+
if (!root) return;
|
|
1958
|
+
if (this.cardOverlay && this.cardOverlay.parentElement) {
|
|
1959
|
+
this.cardOverlay.parentElement.removeChild(this.cardOverlay);
|
|
1960
|
+
this.cardOverlay = null;
|
|
1961
|
+
}
|
|
1962
|
+
const backdrop = document.createElement("div");
|
|
1963
|
+
backdrop.className = "bt-modal-backdrop";
|
|
1964
|
+
this.cardOverlay = backdrop;
|
|
1965
|
+
const badgeClass = `bt-badge-${note.type.toLowerCase()}`;
|
|
1966
|
+
const statusClass = note.status === "OPEN" ? "bt-badge-status-open" : "bt-badge-status-resolved";
|
|
1967
|
+
const icon = note.type === "region" ? "\u{1F4D0}" : note.type === "page" ? "\u{1F4C4}" : "\u{1F3AF}";
|
|
1968
|
+
const contextText = note.type === "region" && note.region ? `Region: ${note.region.width} \xD7 ${note.region.height} px \xB7 Route: ${note.route}` : note.type === "page" ? `Page Note \xB7 Route: ${note.route}` : `${note.target?.selector || "Element"} (${note.target?.boundingRect?.width || 0}\xD7${note.target?.boundingRect?.height || 0}px) \xB7 ${note.route}`;
|
|
1969
|
+
const formattedDate = new Date(note.createdAt).toLocaleString();
|
|
1970
|
+
backdrop.innerHTML = `
|
|
1971
|
+
<div class="bt-modal">
|
|
1972
|
+
<div class="bt-modal-header">
|
|
1973
|
+
<div class="bt-modal-title">
|
|
1974
|
+
<span>${icon} Visual Note Details</span>
|
|
1975
|
+
<span class="bt-mode-badge ${badgeClass}">${note.type.toUpperCase()}</span>
|
|
1976
|
+
<span class="bt-mode-badge ${statusClass}">${note.status}</span>
|
|
1977
|
+
</div>
|
|
1978
|
+
<button class="bt-close-btn" id="btn-card-close" title="Close (Esc)">\u2715</button>
|
|
1979
|
+
</div>
|
|
1980
|
+
|
|
1981
|
+
<div class="bt-target-pill" title="${contextText}">
|
|
1982
|
+
<span>\u{1F3F7}\uFE0F</span>
|
|
1983
|
+
<span class="bt-pill-content">${contextText}</span>
|
|
1984
|
+
</div>
|
|
1985
|
+
|
|
1986
|
+
<div class="bt-note-message-box">${note.message}</div>
|
|
1987
|
+
|
|
1988
|
+
<div style="font-size: 11px; color: #64748b; display: flex; justify-content: space-between; padding: 0 2px;">
|
|
1989
|
+
<span>Created: ${formattedDate}</span>
|
|
1990
|
+
<span>ID: <code style="font-family: monospace; color: #94a3b8;">${note.id}</code></span>
|
|
1991
|
+
</div>
|
|
1992
|
+
|
|
1993
|
+
<div class="bt-modal-footer">
|
|
1994
|
+
<button class="bt-btn bt-btn-delete" id="btn-card-delete" title="Delete this note">
|
|
1995
|
+
<span>\u{1F5D1}\uFE0F</span> Delete
|
|
1996
|
+
</button>
|
|
1997
|
+
<div class="bt-modal-actions">
|
|
1998
|
+
<button class="bt-btn bt-btn-cancel" id="btn-card-dismiss">Close</button>
|
|
1999
|
+
<button class="bt-btn ${note.status === "OPEN" ? "bt-btn-resolve" : "bt-btn-save"}" id="btn-card-resolve">
|
|
2000
|
+
${note.status === "OPEN" ? "<span>\u2705</span> Resolve Note" : "<span>\u21BA</span> Reopen"}
|
|
2001
|
+
</button>
|
|
2002
|
+
</div>
|
|
2003
|
+
</div>
|
|
2004
|
+
</div>
|
|
2005
|
+
`;
|
|
2006
|
+
const btnClose = backdrop.querySelector("#btn-card-close");
|
|
2007
|
+
const btnDismiss = backdrop.querySelector("#btn-card-dismiss");
|
|
2008
|
+
const btnResolve = backdrop.querySelector("#btn-card-resolve");
|
|
2009
|
+
const btnDelete = backdrop.querySelector("#btn-card-delete");
|
|
2010
|
+
const closeCard = () => {
|
|
2011
|
+
if (this.cardOverlay) {
|
|
2012
|
+
root.removeChild(this.cardOverlay);
|
|
2013
|
+
this.cardOverlay = null;
|
|
2014
|
+
this.hideHighlight();
|
|
2015
|
+
}
|
|
2016
|
+
};
|
|
2017
|
+
btnClose.onclick = closeCard;
|
|
2018
|
+
btnDismiss.onclick = closeCard;
|
|
2019
|
+
backdrop.onclick = (e) => {
|
|
2020
|
+
if (e.target === backdrop) closeCard();
|
|
2021
|
+
};
|
|
2022
|
+
btnResolve.onclick = () => {
|
|
2023
|
+
if (note.status === "OPEN") {
|
|
2024
|
+
this.transport.send({ type: "resolve_note", noteId: note.id });
|
|
2025
|
+
} else {
|
|
2026
|
+
this.transport.send({ type: "reopen_note", noteId: note.id });
|
|
2027
|
+
}
|
|
2028
|
+
closeCard();
|
|
2029
|
+
};
|
|
2030
|
+
btnDelete.onclick = () => {
|
|
2031
|
+
this.transport.send({ type: "delete_note", noteId: note.id });
|
|
2032
|
+
closeCard();
|
|
2033
|
+
};
|
|
2034
|
+
root.appendChild(backdrop);
|
|
2035
|
+
}
|
|
1544
2036
|
setupListeners() {
|
|
1545
2037
|
const onMouseMove = (e) => {
|
|
1546
|
-
if (this.modalOverlay || this.isDraggingRegion || this.activeMode === "region") return;
|
|
2038
|
+
if (this.modalOverlay || this.cardOverlay || this.isDraggingRegion || this.activeMode === "region") return;
|
|
2039
|
+
const path = e.composedPath ? e.composedPath() : [];
|
|
2040
|
+
if (this.container && path.includes(this.container)) {
|
|
2041
|
+
this.hideHighlight();
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
1547
2044
|
if (e.altKey || this.activeMode === "element") {
|
|
1548
2045
|
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
1549
2046
|
if (target && target !== this.container && !this.container?.contains(target)) {
|
|
@@ -1557,7 +2054,12 @@ var NoteInspector = class {
|
|
|
1557
2054
|
}
|
|
1558
2055
|
};
|
|
1559
2056
|
const onClick = (e) => {
|
|
1560
|
-
if (this.modalOverlay || this.
|
|
2057
|
+
if (this.modalOverlay || this.cardOverlay) return;
|
|
2058
|
+
const path = e.composedPath ? e.composedPath() : [];
|
|
2059
|
+
if (this.container && path.includes(this.container)) {
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
if (this.activeMode === "region") return;
|
|
1561
2063
|
if (e.altKey || this.activeMode === "element") {
|
|
1562
2064
|
e.preventDefault();
|
|
1563
2065
|
e.stopPropagation();
|
|
@@ -1571,18 +2073,39 @@ var NoteInspector = class {
|
|
|
1571
2073
|
}
|
|
1572
2074
|
}
|
|
1573
2075
|
};
|
|
2076
|
+
const onKeyDown = (e) => {
|
|
2077
|
+
if (e.key === "Escape") {
|
|
2078
|
+
if (this.cardOverlay && this.cardOverlay.parentElement && this.shadowRoot) {
|
|
2079
|
+
this.shadowRoot.removeChild(this.cardOverlay);
|
|
2080
|
+
this.cardOverlay = null;
|
|
2081
|
+
} else if (this.activeMode === "region" || this.activeMode === "element") {
|
|
2082
|
+
this.setMode("idle");
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
};
|
|
1574
2086
|
const onKeyUp = (e) => {
|
|
1575
|
-
if (e.key === "Alt" && !this.modalOverlay && this.activeMode !== "element") {
|
|
2087
|
+
if (e.key === "Alt" && !this.modalOverlay && !this.cardOverlay && this.activeMode !== "element") {
|
|
1576
2088
|
this.hideHighlight();
|
|
1577
2089
|
}
|
|
1578
2090
|
};
|
|
2091
|
+
const onScrollOrResize = () => {
|
|
2092
|
+
requestAnimationFrame(() => {
|
|
2093
|
+
this.updateMarkerPositions();
|
|
2094
|
+
});
|
|
2095
|
+
};
|
|
1579
2096
|
window.addEventListener("mousemove", onMouseMove, { capture: true, passive: true });
|
|
1580
2097
|
window.addEventListener("click", onClick, { capture: true });
|
|
2098
|
+
window.addEventListener("keydown", onKeyDown, { capture: true });
|
|
1581
2099
|
window.addEventListener("keyup", onKeyUp, { capture: true });
|
|
2100
|
+
window.addEventListener("scroll", onScrollOrResize, { capture: true, passive: true });
|
|
2101
|
+
window.addEventListener("resize", onScrollOrResize, { passive: true });
|
|
1582
2102
|
this.cleanups.push(() => {
|
|
1583
2103
|
window.removeEventListener("mousemove", onMouseMove, { capture: true });
|
|
1584
2104
|
window.removeEventListener("click", onClick, { capture: true });
|
|
2105
|
+
window.removeEventListener("keydown", onKeyDown, { capture: true });
|
|
1585
2106
|
window.removeEventListener("keyup", onKeyUp, { capture: true });
|
|
2107
|
+
window.removeEventListener("scroll", onScrollOrResize, { capture: true });
|
|
2108
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
1586
2109
|
});
|
|
1587
2110
|
}
|
|
1588
2111
|
showRegionOverlay() {
|
|
@@ -1595,7 +2118,26 @@ var NoteInspector = class {
|
|
|
1595
2118
|
this.regionBox.className = "bt-region-box";
|
|
1596
2119
|
this.regionBox.style.display = "none";
|
|
1597
2120
|
this.regionOverlay.appendChild(this.regionBox);
|
|
2121
|
+
this.regionBanner = document.createElement("div");
|
|
2122
|
+
this.regionBanner.className = "bt-region-banner";
|
|
2123
|
+
this.regionBanner.innerHTML = `
|
|
2124
|
+
<span>\u{1F4D0} Drag rectangle on screen to select region</span>
|
|
2125
|
+
<button class="bt-region-cancel-btn" id="bt-region-cancel">\u2715 Cancel (Esc)</button>
|
|
2126
|
+
`;
|
|
2127
|
+
const btnCancel = this.regionBanner.querySelector("#bt-region-cancel");
|
|
2128
|
+
btnCancel.onclick = (e) => {
|
|
2129
|
+
e.stopPropagation();
|
|
2130
|
+
this.setMode("idle");
|
|
2131
|
+
};
|
|
2132
|
+
this.regionOverlay.appendChild(this.regionBanner);
|
|
2133
|
+
this.regionOverlay.oncontextmenu = (e) => {
|
|
2134
|
+
e.preventDefault();
|
|
2135
|
+
this.setMode("idle");
|
|
2136
|
+
};
|
|
1598
2137
|
this.regionOverlay.onmousedown = (e) => {
|
|
2138
|
+
const path = e.composedPath ? e.composedPath() : [];
|
|
2139
|
+
if (this.regionBanner && path.includes(this.regionBanner)) return;
|
|
2140
|
+
if (this.toolbarElement && path.includes(this.toolbarElement)) return;
|
|
1599
2141
|
this.isDraggingRegion = true;
|
|
1600
2142
|
this.dragStartX = e.clientX;
|
|
1601
2143
|
this.dragStartY = e.clientY;
|
|
@@ -1636,7 +2178,7 @@ var NoteInspector = class {
|
|
|
1636
2178
|
const top = Math.min(this.dragStartY, currentY);
|
|
1637
2179
|
const width = Math.abs(currentX - this.dragStartX);
|
|
1638
2180
|
const height = Math.abs(currentY - this.dragStartY);
|
|
1639
|
-
if (width >
|
|
2181
|
+
if (width > 15 && height > 15) {
|
|
1640
2182
|
this.selectedRegion = {
|
|
1641
2183
|
x: Math.round(left),
|
|
1642
2184
|
y: Math.round(top),
|
|
@@ -1652,11 +2194,16 @@ var NoteInspector = class {
|
|
|
1652
2194
|
}
|
|
1653
2195
|
};
|
|
1654
2196
|
}
|
|
1655
|
-
|
|
2197
|
+
if (this.toolbarElement && this.toolbarElement.parentNode === root) {
|
|
2198
|
+
root.insertBefore(this.regionOverlay, this.toolbarElement);
|
|
2199
|
+
} else {
|
|
2200
|
+
root.appendChild(this.regionOverlay);
|
|
2201
|
+
}
|
|
1656
2202
|
}
|
|
1657
2203
|
hideRegionOverlay() {
|
|
1658
|
-
|
|
1659
|
-
|
|
2204
|
+
this.isDraggingRegion = false;
|
|
2205
|
+
if (this.regionOverlay && this.regionOverlay.parentNode) {
|
|
2206
|
+
this.regionOverlay.parentNode.removeChild(this.regionOverlay);
|
|
1660
2207
|
}
|
|
1661
2208
|
if (this.regionBox) {
|
|
1662
2209
|
this.regionBox.style.display = "none";
|
|
@@ -1695,7 +2242,7 @@ var NoteInspector = class {
|
|
|
1695
2242
|
this.updateHighlight(targetEl);
|
|
1696
2243
|
}
|
|
1697
2244
|
this.renderNoteModal({
|
|
1698
|
-
title: "
|
|
2245
|
+
title: "Add Visual Note",
|
|
1699
2246
|
modeBadge: noteType.toUpperCase(),
|
|
1700
2247
|
pillText: noteType === "page" ? `Page Viewport: ${window.innerWidth} \xD7 ${window.innerHeight} px` : `${getSemanticSelector(targetEl)} (${Math.round(targetEl.getBoundingClientRect().width)}\xD7${Math.round(targetEl.getBoundingClientRect().height)}) \xB7 Viewport: ${window.innerWidth}\xD7${window.innerHeight}`,
|
|
1701
2248
|
onSave: async (message) => {
|
|
@@ -1705,7 +2252,7 @@ var NoteInspector = class {
|
|
|
1705
2252
|
}
|
|
1706
2253
|
openRegionNoteEditor(region) {
|
|
1707
2254
|
this.renderNoteModal({
|
|
1708
|
-
title: "
|
|
2255
|
+
title: "Add Region Note",
|
|
1709
2256
|
modeBadge: "REGION",
|
|
1710
2257
|
pillText: `Selected Area: x:${region.x}, y:${region.y} (${region.width} \xD7 ${region.height} px)`,
|
|
1711
2258
|
onSave: async (message) => {
|
|
@@ -1723,22 +2270,31 @@ var NoteInspector = class {
|
|
|
1723
2270
|
const backdrop = document.createElement("div");
|
|
1724
2271
|
backdrop.className = "bt-modal-backdrop";
|
|
1725
2272
|
this.modalOverlay = backdrop;
|
|
2273
|
+
const badgeClass = `bt-badge-${options.modeBadge.toLowerCase()}`;
|
|
2274
|
+
const icon = options.modeBadge === "REGION" ? "\u{1F4D0}" : options.modeBadge === "PAGE" ? "\u{1F4C4}" : "\u{1F3AF}";
|
|
2275
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
1726
2276
|
backdrop.innerHTML = `
|
|
1727
2277
|
<div class="bt-modal">
|
|
1728
2278
|
<div class="bt-modal-header">
|
|
1729
2279
|
<div class="bt-modal-title">
|
|
1730
|
-
<span
|
|
1731
|
-
<span class="bt-mode-badge">${options.modeBadge}</span>
|
|
2280
|
+
<span>\u{1F4DD} ${options.title}</span>
|
|
2281
|
+
<span class="bt-mode-badge ${badgeClass}">${options.modeBadge}</span>
|
|
1732
2282
|
</div>
|
|
1733
|
-
<button class="bt-close-btn" id="btn-close" title="Close">\u2715</button>
|
|
2283
|
+
<button class="bt-close-btn" id="btn-close" title="Close (Esc)">\u2715</button>
|
|
1734
2284
|
</div>
|
|
1735
2285
|
<div class="bt-target-pill" title="${options.pillText}">
|
|
1736
|
-
|
|
2286
|
+
<span>${icon}</span>
|
|
2287
|
+
<span class="bt-pill-content">${options.pillText}</span>
|
|
1737
2288
|
</div>
|
|
1738
2289
|
<textarea class="bt-textarea" placeholder="Describe the layout issue, styling bug, or note for AI agent..." autofocus></textarea>
|
|
1739
|
-
<div class="bt-modal-
|
|
1740
|
-
<
|
|
1741
|
-
|
|
2290
|
+
<div class="bt-modal-footer">
|
|
2291
|
+
<div class="bt-kbd-hint">
|
|
2292
|
+
<kbd>${isMac ? "\u2318" : "Ctrl"}+Enter</kbd> save \xB7 <kbd>Esc</kbd> cancel
|
|
2293
|
+
</div>
|
|
2294
|
+
<div class="bt-modal-actions">
|
|
2295
|
+
<button class="bt-btn bt-btn-cancel" id="btn-cancel">Cancel</button>
|
|
2296
|
+
<button class="bt-btn bt-btn-save" id="btn-save">Save Note</button>
|
|
2297
|
+
</div>
|
|
1742
2298
|
</div>
|
|
1743
2299
|
</div>
|
|
1744
2300
|
`;
|
|
@@ -1958,6 +2514,12 @@ var NoteInspector = class {
|
|
|
1958
2514
|
this.container = null;
|
|
1959
2515
|
this.shadowRoot = null;
|
|
1960
2516
|
this.toolbarElement = null;
|
|
2517
|
+
this.regionOverlay = null;
|
|
2518
|
+
this.regionBox = null;
|
|
2519
|
+
this.regionBanner = null;
|
|
2520
|
+
this.markersContainer = null;
|
|
2521
|
+
this.modalOverlay = null;
|
|
2522
|
+
this.cardOverlay = null;
|
|
1961
2523
|
}
|
|
1962
2524
|
};
|
|
1963
2525
|
|