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.
Files changed (55) hide show
  1. package/.github/workflows/docs.yml +54 -0
  2. package/AGENTS.md +133 -0
  3. package/README.md +1 -1
  4. package/dist/{chunk-6A7FFDIB.js → chunk-6VA7GBAO.js} +29 -4
  5. package/dist/chunk-6VA7GBAO.js.map +1 -0
  6. package/dist/{chunk-ANMR5WBH.js → chunk-G2Y3CXCY.js} +2 -2
  7. package/dist/{chunk-BSKNG4V7.js → chunk-ILRYKMME.js} +30 -1
  8. package/dist/chunk-ILRYKMME.js.map +1 -0
  9. package/dist/{chunk-X7C5CHBO.js → chunk-SKCMT2DE.js} +637 -76
  10. package/dist/chunk-SKCMT2DE.js.map +1 -0
  11. package/dist/{chunk-ZLNGOOH2.js → chunk-SPCIROIU.js} +65 -3
  12. package/dist/chunk-SPCIROIU.js.map +1 -0
  13. package/dist/cli/index.js +115 -2
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/client/index.cjs +637 -75
  16. package/dist/client/index.d.ts +16 -2
  17. package/dist/client/index.js +2 -2
  18. package/dist/client.iife.js +393 -72
  19. package/dist/core/index.d.ts +12 -4
  20. package/dist/core/index.js +9 -3
  21. package/dist/daemon/index.d.ts +1 -1
  22. package/dist/daemon/index.js +3 -3
  23. package/dist/{engine-DKloFjvs.d.ts → engine-CeT9URuN.d.ts} +4 -0
  24. package/dist/index.d.ts +4 -3
  25. package/dist/index.js +13 -7
  26. package/dist/mcp/index.d.ts +2 -2
  27. package/dist/mcp/index.js +2 -2
  28. package/dist/{server-CN-se8td.d.ts → server-Dd8NX2Mk.d.ts} +1 -1
  29. package/docboot.config.js +16 -0
  30. package/docs/cli.md +51 -0
  31. package/docs/closed-loop-verification.md +57 -0
  32. package/docs/getting-started.md +122 -0
  33. package/docs/incidents-diagnostics.md +61 -0
  34. package/docs/index.md +46 -0
  35. package/docs/mcp-reference.md +128 -0
  36. package/docs/security-privacy.md +32 -0
  37. package/docs/visual-notes.md +67 -0
  38. package/package.json +6 -2
  39. package/packages/client/package.json +2 -2
  40. package/packages/client/src/notes/inspector.ts +689 -79
  41. package/packages/client/src/transport/websocket.ts +15 -0
  42. package/packages/core/package.json +3 -0
  43. package/packages/core/src/redaction.ts +40 -5
  44. package/packages/daemon/src/server/ws.ts +72 -1
  45. package/packages/daemon/src/session/manager.ts +21 -0
  46. package/packages/daemon/src/storage/db.ts +10 -1
  47. package/test/client/interceptors.test.ts +61 -0
  48. package/test/core/redaction.test.ts +12 -0
  49. package/dist/chunk-6A7FFDIB.js.map +0 -1
  50. package/dist/chunk-BSKNG4V7.js.map +0 -1
  51. package/dist/chunk-X7C5CHBO.js.map +0 -1
  52. package/dist/chunk-ZLNGOOH2.js.map +0 -1
  53. package/packages/core/dist/index.d.ts +0 -317
  54. package/packages/core/dist/index.js +0 -221
  55. /package/dist/{chunk-ANMR5WBH.js.map → chunk-G2Y3CXCY.js.map} +0 -0
@@ -16,9 +16,11 @@ export interface InspectorOptions {
16
16
  * Isolated Visual Note Inspector rendering in Shadow DOM.
17
17
  * Supports:
18
18
  * 1. Element selection (hover highlight & click)
19
- * 2. Region / Area selection (drag-and-drop rectangle on screen)
19
+ * 2. Region / Area selection (drag-and-drop rectangle on screen with cancel banner)
20
20
  * 3. Whole page note
21
- * 4. Floating quick dock / toolbar in bottom-right corner
21
+ * 4. Real-time Saved Note Markers (pins on elements/regions when page loads or syncs)
22
+ * 5. Interactive Note Detail Card (view message, target, resolve/delete actions)
23
+ * 6. Floating quick dock / toolbar in bottom-right corner with Notes count toggle
22
24
  */
23
25
  export class NoteInspector {
24
26
  private transport: WebSocketTransport;
@@ -30,8 +32,11 @@ export class NoteInspector {
30
32
  private highlightOverlay: HTMLDivElement | null = null;
31
33
  private regionOverlay: HTMLDivElement | null = null;
32
34
  private regionBox: HTMLDivElement | null = null;
35
+ private regionBanner: HTMLDivElement | null = null;
36
+ private markersContainer: HTMLDivElement | null = null;
33
37
  private toolbarElement: HTMLDivElement | null = null;
34
38
  private modalOverlay: HTMLDivElement | null = null;
39
+ private cardOverlay: HTMLDivElement | null = null;
35
40
 
36
41
  private activeMode: NoteInspectMode = 'idle';
37
42
  private hoveredElement: HTMLElement | null = null;
@@ -41,6 +46,9 @@ export class NoteInspector {
41
46
  private isDraggingRegion = false;
42
47
  private dragStartX = 0;
43
48
  private dragStartY = 0;
49
+
50
+ private savedNotes: VisualNote[] = [];
51
+ private showMarkers = true;
44
52
  private cleanups: (() => void)[] = [];
45
53
 
46
54
  constructor(transport: WebSocketTransport, screenshotDriver: ScreenshotDriver, options: InspectorOptions = {}) {
@@ -65,9 +73,23 @@ export class NoteInspector {
65
73
  this.ensureContainer();
66
74
  }
67
75
 
76
+ // Subscribe to incoming notes synchronization from daemon
77
+ const unsubscribe = this.transport.onMessage((msg) => {
78
+ if (msg && msg.type === 'notes_sync' && Array.isArray(msg.notes)) {
79
+ this.syncNotes(msg.notes);
80
+ }
81
+ });
82
+ this.cleanups.push(unsubscribe);
83
+
68
84
  this.setupListeners();
69
85
  }
70
86
 
87
+ public syncNotes(notes: VisualNote[]): void {
88
+ this.savedNotes = notes;
89
+ this.updateToolbarCount();
90
+ this.renderMarkers();
91
+ }
92
+
71
93
  public setMode(mode: NoteInspectMode): void {
72
94
  this.activeMode = mode;
73
95
  this.updateToolbarState();
@@ -98,20 +120,21 @@ export class NoteInspector {
98
120
 
99
121
  this.shadowRoot = this.container.attachShadow({ mode: 'open' });
100
122
 
101
- // Styles for highlight overlay, region drag box, floating toolbar and modal
123
+ // Styles for highlight overlay, region drag box, markers, floating toolbar and modals
102
124
  const style = document.createElement('style');
103
125
  style.textContent = `
104
126
  :host {
105
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
127
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
106
128
  color-scheme: dark;
107
129
  -webkit-font-smoothing: antialiased;
130
+ -moz-osx-font-smoothing: grayscale;
108
131
  }
109
132
 
110
133
  /* 1. Element Highlight Overlay */
111
134
  .bt-highlight {
112
135
  position: fixed;
113
136
  border: 2px solid #3b82f6;
114
- background: rgba(59, 130, 246, 0.15);
137
+ background: rgba(59, 130, 246, 0.16);
115
138
  border-radius: 4px;
116
139
  pointer-events: none;
117
140
  transition: all 0.05s ease-out;
@@ -121,18 +144,19 @@ export class NoteInspector {
121
144
 
122
145
  .bt-badge {
123
146
  position: absolute;
124
- top: -24px;
147
+ top: -26px;
125
148
  left: 0;
126
- background: #1e293b;
149
+ background: #0f172a;
127
150
  color: #38bdf8;
128
151
  border: 1px solid #3b82f6;
129
152
  font-size: 11px;
130
153
  font-weight: 600;
131
- padding: 2px 6px;
132
- border-radius: 3px;
154
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
155
+ padding: 2px 7px;
156
+ border-radius: 4px;
133
157
  white-space: nowrap;
134
158
  pointer-events: none;
135
- box-shadow: 0 2px 4px rgba(0,0,0,0.3);
159
+ box-shadow: 0 4px 6px -1px rgba(0,0,0,0.5);
136
160
  }
137
161
 
138
162
  /* 2. Region Selection Overlay */
@@ -144,7 +168,8 @@ export class NoteInspector {
144
168
  cursor: crosshair;
145
169
  z-index: 2147483642;
146
170
  pointer-events: auto;
147
- background: rgba(15, 23, 42, 0.2);
171
+ background: rgba(15, 23, 42, 0.25);
172
+ user-select: none;
148
173
  }
149
174
 
150
175
  .bt-region-box {
@@ -158,32 +183,171 @@ export class NoteInspector {
158
183
 
159
184
  .bt-region-badge {
160
185
  position: absolute;
161
- top: -24px;
186
+ top: -26px;
162
187
  left: 0;
163
188
  background: #0f172a;
164
189
  color: #38bdf8;
165
190
  border: 1px solid #0284c7;
166
191
  font-size: 11px;
167
192
  font-weight: 600;
168
- padding: 2px 6px;
169
- border-radius: 3px;
193
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
194
+ padding: 2px 7px;
195
+ border-radius: 4px;
170
196
  white-space: nowrap;
171
197
  pointer-events: none;
198
+ box-shadow: 0 4px 6px -1px rgba(0,0,0,0.5);
199
+ }
200
+
201
+ .bt-region-banner {
202
+ position: fixed;
203
+ top: 20px;
204
+ left: 50%;
205
+ transform: translateX(-50%);
206
+ background: #0f172a;
207
+ color: #f8fafc;
208
+ border: 1px solid #0284c7;
209
+ border-radius: 30px;
210
+ padding: 8px 16px;
211
+ display: flex;
212
+ align-items: center;
213
+ gap: 12px;
214
+ box-shadow: 0 10px 25px -5px rgba(0,0,0,0.6);
215
+ font-size: 12.5px;
216
+ font-weight: 500;
217
+ pointer-events: auto;
218
+ z-index: 2147483645;
219
+ user-select: none;
220
+ }
221
+
222
+ .bt-region-cancel-btn {
223
+ background: rgba(239, 68, 68, 0.15);
224
+ color: #fca5a5;
225
+ border: 1px solid rgba(239, 68, 68, 0.4);
226
+ padding: 3px 10px;
227
+ border-radius: 20px;
228
+ font-size: 11px;
229
+ font-weight: 600;
230
+ cursor: pointer;
231
+ transition: all 0.15s ease;
232
+ display: inline-flex;
233
+ align-items: center;
234
+ gap: 4px;
235
+ font-family: inherit;
172
236
  }
173
237
 
174
- /* 3. Floating Quick Toolbar */
238
+ .bt-region-cancel-btn:hover {
239
+ background: rgba(239, 68, 68, 0.3);
240
+ color: #ffffff;
241
+ }
242
+
243
+ /* 3. Note Markers on Page */
244
+ .bt-markers-layer {
245
+ position: fixed;
246
+ top: 0;
247
+ left: 0;
248
+ width: 0;
249
+ height: 0;
250
+ pointer-events: none;
251
+ z-index: 2147483638;
252
+ }
253
+
254
+ .bt-note-marker {
255
+ position: fixed;
256
+ pointer-events: auto;
257
+ background: linear-gradient(135deg, #2563eb, #1d4ed8);
258
+ color: #ffffff;
259
+ border: 2px solid #ffffff;
260
+ box-shadow: 0 4px 12px rgba(0,0,0,0.5), 0 0 0 1px rgba(37,99,235,0.4);
261
+ border-radius: 999px;
262
+ height: 26px;
263
+ min-width: 26px;
264
+ padding: 0 7px;
265
+ display: inline-flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ gap: 4px;
269
+ cursor: pointer;
270
+ font-size: 11px;
271
+ font-weight: 700;
272
+ user-select: none;
273
+ transition: transform 0.15s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.15s ease;
274
+ animation: bt-pop-in 0.2s ease-out;
275
+ box-sizing: border-box;
276
+ z-index: 2147483641;
277
+ }
278
+
279
+ @keyframes bt-pop-in {
280
+ 0% { transform: scale(0.6); opacity: 0; }
281
+ 100% { transform: scale(1); opacity: 1; }
282
+ }
283
+
284
+ .bt-note-marker:hover {
285
+ transform: scale(1.15) translateY(-2px);
286
+ box-shadow: 0 8px 20px rgba(37,99,235,0.6), 0 0 0 2px #60a5fa;
287
+ }
288
+
289
+ .bt-marker-resolved {
290
+ background: linear-gradient(135deg, #475569, #334155);
291
+ border-color: #94a3b8;
292
+ opacity: 0.75;
293
+ }
294
+
295
+ .bt-region-marker-box {
296
+ position: fixed;
297
+ border: 2px dashed #0284c7;
298
+ background: rgba(14, 165, 233, 0.08);
299
+ pointer-events: none;
300
+ box-sizing: border-box;
301
+ border-radius: 6px;
302
+ z-index: 2147483639;
303
+ }
304
+
305
+ .bt-page-notes-dock {
306
+ position: fixed;
307
+ top: 16px;
308
+ right: 16px;
309
+ display: flex;
310
+ flex-direction: column;
311
+ gap: 6px;
312
+ pointer-events: none;
313
+ z-index: 2147483641;
314
+ }
315
+
316
+ .bt-page-note-pill {
317
+ background: #0f172a;
318
+ color: #c084fc;
319
+ border: 1px solid #7e22ce;
320
+ border-radius: 20px;
321
+ padding: 5px 12px;
322
+ font-size: 11.5px;
323
+ font-weight: 600;
324
+ display: inline-flex;
325
+ align-items: center;
326
+ gap: 6px;
327
+ box-shadow: 0 4px 12px rgba(0,0,0,0.5);
328
+ cursor: pointer;
329
+ pointer-events: auto;
330
+ transition: all 0.15s ease;
331
+ }
332
+
333
+ .bt-page-note-pill:hover {
334
+ background: #1e1b4b;
335
+ transform: translateY(-1px);
336
+ }
337
+
338
+ /* 4. Floating Quick Toolbar */
175
339
  .bt-toolbar {
176
340
  position: fixed;
177
341
  bottom: 20px;
178
342
  right: 20px;
179
- background: #1e293b;
343
+ background: #0f172a;
180
344
  border: 1px solid #334155;
181
345
  border-radius: 30px;
182
346
  padding: 4px 6px;
183
347
  display: flex;
184
348
  align-items: center;
185
349
  gap: 4px;
186
- box-shadow: 0 10px 15px -3px rgba(0,0,0,0.5), 0 4px 6px -4px rgba(0,0,0,0.5);
350
+ box-shadow: 0 10px 25px -3px rgba(0,0,0,0.6), 0 4px 6px -4px rgba(0,0,0,0.4);
187
351
  pointer-events: auto;
188
352
  z-index: 2147483646;
189
353
  user-select: none;
@@ -196,17 +360,18 @@ export class NoteInspector {
196
360
  color: #94a3b8;
197
361
  font-size: 12px;
198
362
  font-weight: 500;
199
- padding: 6px 10px;
363
+ padding: 6px 12px;
200
364
  border-radius: 20px;
201
365
  cursor: pointer;
202
366
  display: flex;
203
367
  align-items: center;
204
- gap: 5px;
368
+ gap: 6px;
205
369
  transition: all 0.15s ease;
370
+ font-family: inherit;
206
371
  }
207
372
 
208
373
  .bt-toolbar-btn:hover {
209
- background: #334155;
374
+ background: #1e293b;
210
375
  color: #f8fafc;
211
376
  }
212
377
 
@@ -214,15 +379,27 @@ export class NoteInspector {
214
379
  background: #2563eb;
215
380
  color: #ffffff;
216
381
  font-weight: 600;
382
+ box-shadow: 0 2px 6px rgba(37, 99, 235, 0.35);
383
+ }
384
+
385
+ .bt-count-pill {
386
+ background: rgba(255, 255, 255, 0.2);
387
+ color: #ffffff;
388
+ font-size: 10px;
389
+ font-weight: 700;
390
+ padding: 1px 6px;
391
+ border-radius: 10px;
392
+ line-height: 1.2;
217
393
  }
218
394
 
219
395
  .bt-toolbar-divider {
220
396
  width: 1px;
221
397
  height: 16px;
222
398
  background: #334155;
399
+ margin: 0 2px;
223
400
  }
224
401
 
225
- /* 4. Modal Backdrop & Editor */
402
+ /* 5. Modals & Popover Card */
226
403
  .bt-modal-backdrop {
227
404
  position: fixed;
228
405
  top: 0;
@@ -230,7 +407,7 @@ export class NoteInspector {
230
407
  width: 100vw;
231
408
  height: 100vh;
232
409
  background: rgba(15, 23, 42, 0.75);
233
- backdrop-filter: blur(4px);
410
+ backdrop-filter: blur(6px);
234
411
  display: flex;
235
412
  align-items: center;
236
413
  justify-content: center;
@@ -238,20 +415,26 @@ export class NoteInspector {
238
415
  z-index: 2147483647;
239
416
  opacity: 1;
240
417
  box-sizing: border-box;
418
+ animation: bt-fade-in 0.15s ease-out;
419
+ }
420
+
421
+ @keyframes bt-fade-in {
422
+ from { opacity: 0; transform: scale(0.98); }
423
+ to { opacity: 1; transform: scale(1); }
241
424
  }
242
425
 
243
426
  .bt-modal {
244
- background: #1e293b;
427
+ background: #0f172a;
245
428
  color: #f8fafc;
246
429
  border: 1px solid #334155;
247
- border-radius: 12px;
248
- padding: 18px;
249
- width: 420px;
250
- max-width: 90vw;
251
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.7), 0 8px 10px -6px rgba(0, 0, 0, 0.7);
430
+ border-radius: 14px;
431
+ padding: 20px;
432
+ width: 450px;
433
+ max-width: 92vw;
434
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(255, 255, 255, 0.05);
252
435
  display: flex;
253
436
  flex-direction: column;
254
- gap: 12px;
437
+ gap: 14px;
255
438
  box-sizing: border-box;
256
439
  }
257
440
 
@@ -262,87 +445,181 @@ export class NoteInspector {
262
445
  }
263
446
 
264
447
  .bt-modal-title {
265
- font-size: 14px;
448
+ font-size: 14.5px;
266
449
  font-weight: 600;
450
+ letter-spacing: -0.01em;
267
451
  display: flex;
268
452
  align-items: center;
269
- gap: 6px;
453
+ gap: 8px;
270
454
  color: #f8fafc;
271
455
  }
272
456
 
273
457
  .bt-mode-badge {
274
458
  font-size: 10px;
275
459
  font-weight: 700;
460
+ letter-spacing: 0.05em;
276
461
  text-transform: uppercase;
277
- background: rgba(59, 130, 246, 0.2);
462
+ padding: 2px 7px;
463
+ border-radius: 6px;
464
+ }
465
+
466
+ .bt-badge-element {
467
+ background: rgba(59, 130, 246, 0.15);
278
468
  color: #60a5fa;
279
- border: 1px solid #3b82f6;
280
- padding: 2px 6px;
281
- border-radius: 4px;
469
+ border: 1px solid rgba(59, 130, 246, 0.4);
470
+ }
471
+
472
+ .bt-badge-region {
473
+ background: rgba(14, 165, 233, 0.15);
474
+ color: #38bdf8;
475
+ border: 1px solid rgba(14, 165, 233, 0.4);
476
+ }
477
+
478
+ .bt-badge-page {
479
+ background: rgba(168, 85, 247, 0.15);
480
+ color: #c084fc;
481
+ border: 1px solid rgba(168, 85, 247, 0.4);
482
+ }
483
+
484
+ .bt-badge-status-open {
485
+ background: rgba(16, 185, 129, 0.15);
486
+ color: #34d399;
487
+ border: 1px solid rgba(16, 185, 129, 0.4);
488
+ }
489
+
490
+ .bt-badge-status-resolved {
491
+ background: rgba(100, 116, 139, 0.2);
492
+ color: #94a3b8;
493
+ border: 1px solid rgba(100, 116, 139, 0.4);
282
494
  }
283
495
 
284
496
  .bt-close-btn {
285
497
  background: transparent;
286
498
  border: none;
287
499
  color: #94a3b8;
288
- font-size: 16px;
500
+ font-size: 15px;
289
501
  cursor: pointer;
290
- padding: 2px 6px;
291
- border-radius: 4px;
502
+ padding: 3px 7px;
503
+ border-radius: 6px;
504
+ transition: all 0.12s ease;
505
+ display: flex;
506
+ align-items: center;
507
+ justify-content: center;
292
508
  }
293
509
  .bt-close-btn:hover {
294
- background: #334155;
510
+ background: #1e293b;
295
511
  color: #ffffff;
296
512
  }
297
513
 
298
514
  .bt-target-pill {
299
- background: #0f172a;
515
+ background: #090d16;
300
516
  color: #94a3b8;
301
- border: 1px solid #334155;
302
- border-radius: 6px;
303
- padding: 6px 10px;
517
+ border: 1px solid #1e293b;
518
+ border-radius: 8px;
519
+ padding: 8px 12px;
304
520
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
305
- font-size: 11px;
521
+ font-size: 11.5px;
522
+ display: flex;
523
+ align-items: center;
524
+ gap: 8px;
525
+ overflow: hidden;
526
+ }
527
+
528
+ .bt-pill-content {
306
529
  overflow: hidden;
307
530
  text-overflow: ellipsis;
308
531
  white-space: nowrap;
532
+ color: #cbd5e1;
533
+ }
534
+
535
+ .bt-note-message-box {
536
+ background: #090d16;
537
+ border: 1px solid #1e293b;
538
+ border-radius: 8px;
539
+ padding: 12px 14px;
540
+ font-size: 13.5px;
541
+ line-height: 1.5;
542
+ color: #f1f5f9;
543
+ white-space: pre-wrap;
544
+ word-break: break-word;
545
+ max-height: 180px;
546
+ overflow-y: auto;
309
547
  }
310
548
 
311
549
  .bt-textarea {
312
- background: #0f172a;
550
+ background: #090d16;
313
551
  color: #f8fafc;
314
552
  border: 1px solid #334155;
315
- border-radius: 6px;
316
- padding: 10px;
317
- font-size: 13px;
553
+ border-radius: 8px;
554
+ padding: 12px;
555
+ font-size: 13.5px;
556
+ line-height: 1.5;
318
557
  resize: vertical;
319
- min-height: 85px;
558
+ min-height: 95px;
320
559
  outline: none;
321
560
  box-sizing: border-box;
322
561
  width: 100%;
323
562
  font-family: inherit;
563
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
564
+ }
565
+
566
+ .bt-textarea::placeholder {
567
+ color: #64748b;
324
568
  }
325
569
 
326
570
  .bt-textarea:focus {
327
571
  border-color: #3b82f6;
328
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.25);
572
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25);
573
+ }
574
+
575
+ .bt-modal-footer {
576
+ display: flex;
577
+ justify-content: space-between;
578
+ align-items: center;
579
+ gap: 12px;
580
+ margin-top: 2px;
581
+ }
582
+
583
+ .bt-kbd-hint {
584
+ font-size: 11px;
585
+ color: #64748b;
586
+ display: flex;
587
+ align-items: center;
588
+ gap: 4px;
589
+ user-select: none;
590
+ }
591
+
592
+ .bt-kbd-hint kbd {
593
+ background: #1e293b;
594
+ color: #94a3b8;
595
+ border: 1px solid #334155;
596
+ border-radius: 4px;
597
+ padding: 1px 5px;
598
+ font-family: inherit;
599
+ font-size: 10px;
600
+ font-weight: 600;
329
601
  }
330
602
 
331
603
  .bt-modal-actions {
332
604
  display: flex;
333
605
  justify-content: flex-end;
606
+ align-items: center;
334
607
  gap: 8px;
335
608
  }
336
609
 
337
610
  .bt-btn {
338
- padding: 8px 14px;
339
- border-radius: 6px;
340
- font-size: 12px;
611
+ padding: 8px 16px;
612
+ border-radius: 7px;
613
+ font-size: 12.5px;
341
614
  font-weight: 600;
342
615
  cursor: pointer;
343
616
  border: 1px solid transparent;
344
- transition: all 0.1s ease;
617
+ transition: all 0.15s ease;
345
618
  font-family: inherit;
619
+ display: inline-flex;
620
+ align-items: center;
621
+ justify-content: center;
622
+ gap: 6px;
346
623
  }
347
624
 
348
625
  .bt-btn-cancel {
@@ -350,31 +627,54 @@ export class NoteInspector {
350
627
  color: #94a3b8;
351
628
  }
352
629
  .bt-btn-cancel:hover {
353
- background: #334155;
630
+ background: #1e293b;
354
631
  color: #f8fafc;
355
632
  }
356
633
 
357
634
  .bt-btn-save {
358
635
  background: #2563eb;
359
636
  color: #ffffff;
637
+ box-shadow: 0 2px 6px rgba(37, 99, 235, 0.35);
360
638
  }
361
639
  .bt-btn-save:hover {
362
640
  background: #1d4ed8;
641
+ box-shadow: 0 4px 10px rgba(37, 99, 235, 0.45);
642
+ }
643
+
644
+ .bt-btn-resolve {
645
+ background: rgba(16, 185, 129, 0.15);
646
+ color: #6ee7b7;
647
+ border: 1px solid rgba(16, 185, 129, 0.35);
648
+ }
649
+ .bt-btn-resolve:hover {
650
+ background: rgba(16, 185, 129, 0.3);
651
+ color: #ffffff;
363
652
  }
364
- .bt-btn-save:disabled {
365
- opacity: 0.6;
366
- cursor: not-allowed;
653
+
654
+ .bt-btn-delete {
655
+ background: rgba(239, 68, 68, 0.15);
656
+ color: #fca5a5;
657
+ border: 1px solid rgba(239, 68, 68, 0.35);
658
+ }
659
+ .bt-btn-delete:hover {
660
+ background: rgba(239, 68, 68, 0.3);
661
+ color: #ffffff;
367
662
  }
368
663
  `;
369
664
 
370
665
  this.shadowRoot.appendChild(style);
371
666
 
372
- // Element Highlight
667
+ // Element Highlight Overlay
373
668
  this.highlightOverlay = document.createElement('div');
374
669
  this.highlightOverlay.className = 'bt-highlight';
375
670
  this.highlightOverlay.style.display = 'none';
376
671
  this.shadowRoot.appendChild(this.highlightOverlay);
377
672
 
673
+ // Markers container layer
674
+ this.markersContainer = document.createElement('div');
675
+ this.markersContainer.className = 'bt-markers-layer';
676
+ this.shadowRoot.appendChild(this.markersContainer);
677
+
378
678
  // Floating Toolbar
379
679
  if (this.options.showToolbar) {
380
680
  this.createToolbar();
@@ -406,24 +706,39 @@ export class NoteInspector {
406
706
  <button class="bt-toolbar-btn" id="bt-mode-page" title="Leave full-page note">
407
707
  <span>📄</span> Page
408
708
  </button>
709
+ <div class="bt-toolbar-divider"></div>
710
+ <button class="bt-toolbar-btn active" id="bt-toggle-notes" title="Toggle visible note markers on screen">
711
+ <span>📌</span> Notes <span class="bt-count-pill" id="bt-notes-count">0</span>
712
+ </button>
409
713
  `;
410
714
 
411
715
  const btnElement = this.toolbarElement.querySelector('#bt-mode-element') as HTMLButtonElement;
412
716
  const btnRegion = this.toolbarElement.querySelector('#bt-mode-region') as HTMLButtonElement;
413
717
  const btnPage = this.toolbarElement.querySelector('#bt-mode-page') as HTMLButtonElement;
718
+ const btnToggleNotes = this.toolbarElement.querySelector('#bt-toggle-notes') as HTMLButtonElement;
414
719
 
415
- btnElement.onclick = () => {
720
+ btnElement.onclick = (e: MouseEvent) => {
721
+ e.stopPropagation();
416
722
  this.setMode(this.activeMode === 'element' ? 'idle' : 'element');
417
723
  };
418
724
 
419
- btnRegion.onclick = () => {
725
+ btnRegion.onclick = (e: MouseEvent) => {
726
+ e.stopPropagation();
420
727
  this.setMode(this.activeMode === 'region' ? 'idle' : 'region');
421
728
  };
422
729
 
423
- btnPage.onclick = () => {
730
+ btnPage.onclick = (e: MouseEvent) => {
731
+ e.stopPropagation();
424
732
  this.setMode('page');
425
733
  };
426
734
 
735
+ btnToggleNotes.onclick = (e: MouseEvent) => {
736
+ e.stopPropagation();
737
+ this.showMarkers = !this.showMarkers;
738
+ btnToggleNotes.classList.toggle('active', this.showMarkers);
739
+ this.renderMarkers();
740
+ };
741
+
427
742
  this.shadowRoot.appendChild(this.toolbarElement);
428
743
  }
429
744
 
@@ -439,10 +754,225 @@ export class NoteInspector {
439
754
  btnPage?.classList.toggle('active', this.activeMode === 'page');
440
755
  }
441
756
 
757
+ private updateToolbarCount(): void {
758
+ if (!this.toolbarElement) return;
759
+ const countEl = this.toolbarElement.querySelector('#bt-notes-count');
760
+ if (countEl) {
761
+ const openCount = this.savedNotes.filter((n) => n.status === 'OPEN').length;
762
+ countEl.textContent = String(openCount);
763
+ }
764
+ }
765
+
766
+ public renderMarkers(): void {
767
+ const root = this.ensureContainer();
768
+ if (!root || !this.markersContainer) return;
769
+
770
+ this.markersContainer.innerHTML = '';
771
+ if (!this.showMarkers) return;
772
+
773
+ const currentPath = window.location.pathname;
774
+ // Filter open notes on this route or global
775
+ const activeNotes = this.savedNotes.filter(
776
+ (n) => n.status === 'OPEN' && (n.route === currentPath || !n.route || n.route === '/' || window.location.href.includes(n.route))
777
+ );
778
+
779
+ const pageNotes: VisualNote[] = [];
780
+
781
+ activeNotes.forEach((note, index) => {
782
+ if (note.type === 'page') {
783
+ pageNotes.push(note);
784
+ return;
785
+ }
786
+
787
+ if (note.type === 'region' && note.region) {
788
+ // Region box
789
+ const regBox = document.createElement('div');
790
+ regBox.className = 'bt-region-marker-box';
791
+ regBox.style.left = `${note.region.x}px`;
792
+ regBox.style.top = `${note.region.y}px`;
793
+ regBox.style.width = `${note.region.width}px`;
794
+ regBox.style.height = `${note.region.height}px`;
795
+ this.markersContainer!.appendChild(regBox);
796
+
797
+ // Pin on top-left of region
798
+ const pin = document.createElement('div');
799
+ pin.className = 'bt-note-marker';
800
+ pin.style.left = `${Math.max(4, note.region.x - 12)}px`;
801
+ pin.style.top = `${Math.max(4, note.region.y - 12)}px`;
802
+ pin.title = note.message;
803
+ pin.innerHTML = `<span>📐</span> <span>#${index + 1}</span>`;
804
+ pin.onclick = (e) => {
805
+ e.stopPropagation();
806
+ this.openNoteCard(note);
807
+ };
808
+ this.markersContainer!.appendChild(pin);
809
+ return;
810
+ }
811
+
812
+ // Element note
813
+ let targetEl: HTMLElement | null = null;
814
+ if (note.target?.selector) {
815
+ try {
816
+ targetEl = document.querySelector(note.target.selector) as HTMLElement | null;
817
+ } catch {}
818
+ }
819
+
820
+ const rect = targetEl ? targetEl.getBoundingClientRect() : note.target?.boundingRect;
821
+ if (rect) {
822
+ const pin = document.createElement('div');
823
+ pin.className = 'bt-note-marker';
824
+ pin.setAttribute('data-note-id', note.id);
825
+ pin.title = note.message;
826
+ pin.style.left = `${Math.max(4, rect.left - 10)}px`;
827
+ pin.style.top = `${Math.max(4, rect.top - 12)}px`;
828
+ pin.innerHTML = `<span>📝</span> <span>#${index + 1}</span>`;
829
+
830
+ pin.onclick = (e) => {
831
+ e.stopPropagation();
832
+ this.openNoteCard(note);
833
+ };
834
+
835
+ if (targetEl) {
836
+ pin.onmouseenter = () => this.updateHighlight(targetEl!);
837
+ pin.onmouseleave = () => this.hideHighlight();
838
+ }
839
+
840
+ this.markersContainer!.appendChild(pin);
841
+ }
842
+ });
843
+
844
+ // Page notes docked in top-right
845
+ if (pageNotes.length > 0) {
846
+ const pageDock = document.createElement('div');
847
+ pageDock.className = 'bt-page-notes-dock';
848
+ pageNotes.forEach((pNote, idx) => {
849
+ const pill = document.createElement('div');
850
+ pill.className = 'bt-page-note-pill';
851
+ pill.innerHTML = `<span>📄</span> <span>Page Note (${truncate(pNote.message, 25)})</span>`;
852
+ pill.onclick = (e) => {
853
+ e.stopPropagation();
854
+ this.openNoteCard(pNote);
855
+ };
856
+ pageDock.appendChild(pill);
857
+ });
858
+ this.markersContainer.appendChild(pageDock);
859
+ }
860
+ }
861
+
862
+ private updateMarkerPositions(): void {
863
+ if (!this.showMarkers || !this.markersContainer) return;
864
+ this.renderMarkers();
865
+ }
866
+
867
+ public openNoteCard(note: VisualNote): void {
868
+ const root = this.ensureContainer();
869
+ if (!root) return;
870
+
871
+ if (this.cardOverlay && this.cardOverlay.parentElement) {
872
+ this.cardOverlay.parentElement.removeChild(this.cardOverlay);
873
+ this.cardOverlay = null;
874
+ }
875
+
876
+ const backdrop = document.createElement('div');
877
+ backdrop.className = 'bt-modal-backdrop';
878
+ this.cardOverlay = backdrop;
879
+
880
+ const badgeClass = `bt-badge-${note.type.toLowerCase()}`;
881
+ const statusClass = note.status === 'OPEN' ? 'bt-badge-status-open' : 'bt-badge-status-resolved';
882
+ const icon = note.type === 'region' ? '📐' : note.type === 'page' ? '📄' : '🎯';
883
+ const contextText =
884
+ note.type === 'region' && note.region
885
+ ? `Region: ${note.region.width} × ${note.region.height} px · Route: ${note.route}`
886
+ : note.type === 'page'
887
+ ? `Page Note · Route: ${note.route}`
888
+ : `${note.target?.selector || 'Element'} (${note.target?.boundingRect?.width || 0}×${note.target?.boundingRect?.height || 0}px) · ${note.route}`;
889
+
890
+ const formattedDate = new Date(note.createdAt).toLocaleString();
891
+
892
+ backdrop.innerHTML = `
893
+ <div class="bt-modal">
894
+ <div class="bt-modal-header">
895
+ <div class="bt-modal-title">
896
+ <span>${icon} Visual Note Details</span>
897
+ <span class="bt-mode-badge ${badgeClass}">${note.type.toUpperCase()}</span>
898
+ <span class="bt-mode-badge ${statusClass}">${note.status}</span>
899
+ </div>
900
+ <button class="bt-close-btn" id="btn-card-close" title="Close (Esc)">✕</button>
901
+ </div>
902
+
903
+ <div class="bt-target-pill" title="${contextText}">
904
+ <span>🏷️</span>
905
+ <span class="bt-pill-content">${contextText}</span>
906
+ </div>
907
+
908
+ <div class="bt-note-message-box">${note.message}</div>
909
+
910
+ <div style="font-size: 11px; color: #64748b; display: flex; justify-content: space-between; padding: 0 2px;">
911
+ <span>Created: ${formattedDate}</span>
912
+ <span>ID: <code style="font-family: monospace; color: #94a3b8;">${note.id}</code></span>
913
+ </div>
914
+
915
+ <div class="bt-modal-footer">
916
+ <button class="bt-btn bt-btn-delete" id="btn-card-delete" title="Delete this note">
917
+ <span>🗑️</span> Delete
918
+ </button>
919
+ <div class="bt-modal-actions">
920
+ <button class="bt-btn bt-btn-cancel" id="btn-card-dismiss">Close</button>
921
+ <button class="bt-btn ${note.status === 'OPEN' ? 'bt-btn-resolve' : 'bt-btn-save'}" id="btn-card-resolve">
922
+ ${note.status === 'OPEN' ? '<span>✅</span> Resolve Note' : '<span>↺</span> Reopen'}
923
+ </button>
924
+ </div>
925
+ </div>
926
+ </div>
927
+ `;
928
+
929
+ const btnClose = backdrop.querySelector('#btn-card-close') as HTMLButtonElement;
930
+ const btnDismiss = backdrop.querySelector('#btn-card-dismiss') as HTMLButtonElement;
931
+ const btnResolve = backdrop.querySelector('#btn-card-resolve') as HTMLButtonElement;
932
+ const btnDelete = backdrop.querySelector('#btn-card-delete') as HTMLButtonElement;
933
+
934
+ const closeCard = () => {
935
+ if (this.cardOverlay) {
936
+ root.removeChild(this.cardOverlay);
937
+ this.cardOverlay = null;
938
+ this.hideHighlight();
939
+ }
940
+ };
941
+
942
+ btnClose.onclick = closeCard;
943
+ btnDismiss.onclick = closeCard;
944
+ backdrop.onclick = (e) => {
945
+ if (e.target === backdrop) closeCard();
946
+ };
947
+
948
+ btnResolve.onclick = () => {
949
+ if (note.status === 'OPEN') {
950
+ this.transport.send({ type: 'resolve_note', noteId: note.id });
951
+ } else {
952
+ this.transport.send({ type: 'reopen_note', noteId: note.id });
953
+ }
954
+ closeCard();
955
+ };
956
+
957
+ btnDelete.onclick = () => {
958
+ this.transport.send({ type: 'delete_note', noteId: note.id });
959
+ closeCard();
960
+ };
961
+
962
+ root.appendChild(backdrop);
963
+ }
964
+
442
965
  private setupListeners(): void {
443
966
  // 1. Mouse move: hover highlight in element mode or with Alt key
444
967
  const onMouseMove = (e: MouseEvent) => {
445
- if (this.modalOverlay || this.isDraggingRegion || this.activeMode === 'region') return;
968
+ if (this.modalOverlay || this.cardOverlay || this.isDraggingRegion || this.activeMode === 'region') return;
969
+
970
+ // Don't highlight elements if mouse is over our own inspector UI
971
+ const path = e.composedPath ? e.composedPath() : [];
972
+ if (this.container && path.includes(this.container)) {
973
+ this.hideHighlight();
974
+ return;
975
+ }
446
976
 
447
977
  if (e.altKey || this.activeMode === 'element') {
448
978
  const target = document.elementFromPoint(e.clientX, e.clientY) as HTMLElement | null;
@@ -460,7 +990,15 @@ export class NoteInspector {
460
990
 
461
991
  // 2. Click: Alt+Click or Element mode click selects element and opens editor
462
992
  const onClick = (e: MouseEvent) => {
463
- if (this.modalOverlay || this.activeMode === 'region') return;
993
+ if (this.modalOverlay || this.cardOverlay) return;
994
+
995
+ // If clicking inside inspector toolbar or container, do NOT intercept
996
+ const path = e.composedPath ? e.composedPath() : [];
997
+ if (this.container && path.includes(this.container)) {
998
+ return;
999
+ }
1000
+
1001
+ if (this.activeMode === 'region') return;
464
1002
 
465
1003
  if (e.altKey || this.activeMode === 'element') {
466
1004
  e.preventDefault();
@@ -477,21 +1015,45 @@ export class NoteInspector {
477
1015
  }
478
1016
  };
479
1017
 
480
- // 3. Keyup for Alt release
1018
+ // 3. Key handling: Escape cancels active modes, Alt release hides highlight
1019
+ const onKeyDown = (e: KeyboardEvent) => {
1020
+ if (e.key === 'Escape') {
1021
+ if (this.cardOverlay && this.cardOverlay.parentElement && this.shadowRoot) {
1022
+ this.shadowRoot.removeChild(this.cardOverlay);
1023
+ this.cardOverlay = null;
1024
+ } else if (this.activeMode === 'region' || this.activeMode === 'element') {
1025
+ this.setMode('idle');
1026
+ }
1027
+ }
1028
+ };
1029
+
481
1030
  const onKeyUp = (e: KeyboardEvent) => {
482
- if (e.key === 'Alt' && !this.modalOverlay && this.activeMode !== 'element') {
1031
+ if (e.key === 'Alt' && !this.modalOverlay && !this.cardOverlay && this.activeMode !== 'element') {
483
1032
  this.hideHighlight();
484
1033
  }
485
1034
  };
486
1035
 
1036
+ // 4. Scroll & resize: reposition markers accurately
1037
+ const onScrollOrResize = () => {
1038
+ requestAnimationFrame(() => {
1039
+ this.updateMarkerPositions();
1040
+ });
1041
+ };
1042
+
487
1043
  window.addEventListener('mousemove', onMouseMove, { capture: true, passive: true });
488
1044
  window.addEventListener('click', onClick, { capture: true });
1045
+ window.addEventListener('keydown', onKeyDown, { capture: true });
489
1046
  window.addEventListener('keyup', onKeyUp, { capture: true });
1047
+ window.addEventListener('scroll', onScrollOrResize, { capture: true, passive: true });
1048
+ window.addEventListener('resize', onScrollOrResize, { passive: true });
490
1049
 
491
1050
  this.cleanups.push(() => {
492
1051
  window.removeEventListener('mousemove', onMouseMove, { capture: true });
493
1052
  window.removeEventListener('click', onClick, { capture: true });
1053
+ window.removeEventListener('keydown', onKeyDown, { capture: true });
494
1054
  window.removeEventListener('keyup', onKeyUp, { capture: true });
1055
+ window.removeEventListener('scroll', onScrollOrResize, { capture: true });
1056
+ window.removeEventListener('resize', onScrollOrResize);
495
1057
  });
496
1058
  }
497
1059
 
@@ -508,8 +1070,34 @@ export class NoteInspector {
508
1070
  this.regionBox.style.display = 'none';
509
1071
  this.regionOverlay.appendChild(this.regionBox);
510
1072
 
1073
+ // Top helper & cancel banner
1074
+ this.regionBanner = document.createElement('div');
1075
+ this.regionBanner.className = 'bt-region-banner';
1076
+ this.regionBanner.innerHTML = `
1077
+ <span>📐 Drag rectangle on screen to select region</span>
1078
+ <button class="bt-region-cancel-btn" id="bt-region-cancel">✕ Cancel (Esc)</button>
1079
+ `;
1080
+
1081
+ const btnCancel = this.regionBanner.querySelector('#bt-region-cancel') as HTMLButtonElement;
1082
+ btnCancel.onclick = (e: MouseEvent) => {
1083
+ e.stopPropagation();
1084
+ this.setMode('idle');
1085
+ };
1086
+
1087
+ this.regionOverlay.appendChild(this.regionBanner);
1088
+
1089
+ // Right-click cancels region mode
1090
+ this.regionOverlay.oncontextmenu = (e: MouseEvent) => {
1091
+ e.preventDefault();
1092
+ this.setMode('idle');
1093
+ };
1094
+
511
1095
  // Drag events
512
1096
  this.regionOverlay.onmousedown = (e: MouseEvent) => {
1097
+ const path = e.composedPath ? e.composedPath() : [];
1098
+ if (this.regionBanner && path.includes(this.regionBanner)) return;
1099
+ if (this.toolbarElement && path.includes(this.toolbarElement)) return;
1100
+
513
1101
  this.isDraggingRegion = true;
514
1102
  this.dragStartX = e.clientX;
515
1103
  this.dragStartY = e.clientY;
@@ -558,7 +1146,7 @@ export class NoteInspector {
558
1146
  const width = Math.abs(currentX - this.dragStartX);
559
1147
  const height = Math.abs(currentY - this.dragStartY);
560
1148
 
561
- if (width > 20 && height > 20) {
1149
+ if (width > 15 && height > 15) {
562
1150
  this.selectedRegion = {
563
1151
  x: Math.round(left),
564
1152
  y: Math.round(top),
@@ -575,12 +1163,18 @@ export class NoteInspector {
575
1163
  };
576
1164
  }
577
1165
 
578
- root.appendChild(this.regionOverlay);
1166
+ // Always ensure regionOverlay is mounted before toolbar so toolbar is interactable
1167
+ if (this.toolbarElement && this.toolbarElement.parentNode === root) {
1168
+ root.insertBefore(this.regionOverlay, this.toolbarElement);
1169
+ } else {
1170
+ root.appendChild(this.regionOverlay);
1171
+ }
579
1172
  }
580
1173
 
581
1174
  private hideRegionOverlay(): void {
582
- if (this.regionOverlay && this.regionOverlay.parentElement) {
583
- this.regionOverlay.parentElement.removeChild(this.regionOverlay);
1175
+ this.isDraggingRegion = false;
1176
+ if (this.regionOverlay && this.regionOverlay.parentNode) {
1177
+ this.regionOverlay.parentNode.removeChild(this.regionOverlay);
584
1178
  }
585
1179
  if (this.regionBox) {
586
1180
  this.regionBox.style.display = 'none';
@@ -627,7 +1221,7 @@ export class NoteInspector {
627
1221
  }
628
1222
 
629
1223
  this.renderNoteModal({
630
- title: '📝 Add Visual Note',
1224
+ title: 'Add Visual Note',
631
1225
  modeBadge: noteType.toUpperCase(),
632
1226
  pillText:
633
1227
  noteType === 'page'
@@ -641,7 +1235,7 @@ export class NoteInspector {
641
1235
 
642
1236
  public openRegionNoteEditor(region: RegionContext): void {
643
1237
  this.renderNoteModal({
644
- title: '📝 Add Region Note',
1238
+ title: 'Add Region Note',
645
1239
  modeBadge: 'REGION',
646
1240
  pillText: `Selected Area: x:${region.x}, y:${region.y} (${region.width} × ${region.height} px)`,
647
1241
  onSave: async (message) => {
@@ -669,22 +1263,32 @@ export class NoteInspector {
669
1263
  backdrop.className = 'bt-modal-backdrop';
670
1264
  this.modalOverlay = backdrop;
671
1265
 
1266
+ const badgeClass = `bt-badge-${options.modeBadge.toLowerCase()}`;
1267
+ const icon = options.modeBadge === 'REGION' ? '📐' : options.modeBadge === 'PAGE' ? '📄' : '🎯';
1268
+ const isMac = typeof navigator !== 'undefined' && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
1269
+
672
1270
  backdrop.innerHTML = `
673
1271
  <div class="bt-modal">
674
1272
  <div class="bt-modal-header">
675
1273
  <div class="bt-modal-title">
676
- <span>${options.title}</span>
677
- <span class="bt-mode-badge">${options.modeBadge}</span>
1274
+ <span>📝 ${options.title}</span>
1275
+ <span class="bt-mode-badge ${badgeClass}">${options.modeBadge}</span>
678
1276
  </div>
679
- <button class="bt-close-btn" id="btn-close" title="Close">✕</button>
1277
+ <button class="bt-close-btn" id="btn-close" title="Close (Esc)">✕</button>
680
1278
  </div>
681
1279
  <div class="bt-target-pill" title="${options.pillText}">
682
- 🎯 ${options.pillText}
1280
+ <span>${icon}</span>
1281
+ <span class="bt-pill-content">${options.pillText}</span>
683
1282
  </div>
684
1283
  <textarea class="bt-textarea" placeholder="Describe the layout issue, styling bug, or note for AI agent..." autofocus></textarea>
685
- <div class="bt-modal-actions">
686
- <button class="bt-btn bt-btn-cancel" id="btn-cancel">Cancel</button>
687
- <button class="bt-btn bt-btn-save" id="btn-save">Save Note</button>
1284
+ <div class="bt-modal-footer">
1285
+ <div class="bt-kbd-hint">
1286
+ <kbd>${isMac ? '⌘' : 'Ctrl'}+Enter</kbd> save · <kbd>Esc</kbd> cancel
1287
+ </div>
1288
+ <div class="bt-modal-actions">
1289
+ <button class="bt-btn bt-btn-cancel" id="btn-cancel">Cancel</button>
1290
+ <button class="bt-btn bt-btn-save" id="btn-save">Save Note</button>
1291
+ </div>
688
1292
  </div>
689
1293
  </div>
690
1294
  `;
@@ -939,5 +1543,11 @@ export class NoteInspector {
939
1543
  this.container = null;
940
1544
  this.shadowRoot = null;
941
1545
  this.toolbarElement = null;
1546
+ this.regionOverlay = null;
1547
+ this.regionBox = null;
1548
+ this.regionBanner = null;
1549
+ this.markersContainer = null;
1550
+ this.modalOverlay = null;
1551
+ this.cardOverlay = null;
942
1552
  }
943
1553
  }