@ourroadmaps/web-sdk 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-EBLPFIUM.js → chunk-SCGNQ7Z7.js} +614 -4
- package/dist/chunk-SCGNQ7Z7.js.map +1 -0
- package/dist/{chunk-MLFQENR7.cjs → chunk-VXDCDIG3.cjs} +615 -5
- package/dist/chunk-VXDCDIG3.cjs.map +1 -0
- package/dist/index.cjs +7 -7
- package/dist/index.js +2 -2
- package/dist/review/index.cjs +2 -2
- package/dist/review/index.js +1 -1
- package/dist/review.global.js +367 -8
- package/dist/review.global.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-EBLPFIUM.js.map +0 -1
- package/dist/chunk-MLFQENR7.cjs.map +0 -1
|
@@ -5,7 +5,7 @@ var chunk4DE2IREA_cjs = require('./chunk-4DE2IREA.cjs');
|
|
|
5
5
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
6
6
|
// src/review/api.ts
|
|
7
7
|
var API_URL = (() => {
|
|
8
|
-
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-
|
|
8
|
+
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-VXDCDIG3.cjs', document.baseURI).href)) }) !== "undefined" && undefined?.VITE_API_URL) {
|
|
9
9
|
return undefined.VITE_API_URL;
|
|
10
10
|
}
|
|
11
11
|
return "https://api.ourroadmaps.com";
|
|
@@ -18,6 +18,17 @@ async function validateToken(token) {
|
|
|
18
18
|
const body = await res.json();
|
|
19
19
|
return body.data;
|
|
20
20
|
}
|
|
21
|
+
async function identify(token, name, email) {
|
|
22
|
+
const body = {};
|
|
23
|
+
if (name) body.name = name;
|
|
24
|
+
if (email) body.email = email;
|
|
25
|
+
const res = await fetch(`${API_URL}/v1/prototype-review/${token}/identify`, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: { "Content-Type": "application/json" },
|
|
28
|
+
body: JSON.stringify(body)
|
|
29
|
+
});
|
|
30
|
+
if (!res.ok) throw new ReviewError("error", "Failed to identify");
|
|
31
|
+
}
|
|
21
32
|
async function submitComment(token, comment) {
|
|
22
33
|
const res = await fetch(`${API_URL}/v1/prototype-review/${token}/comments`, {
|
|
23
34
|
method: "POST",
|
|
@@ -228,6 +239,242 @@ var REVIEW_STYLES = `
|
|
|
228
239
|
box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.2);
|
|
229
240
|
}
|
|
230
241
|
|
|
242
|
+
/* \u2500\u2500\u2500 Mode Toggle \u2500\u2500\u2500 */
|
|
243
|
+
.review-mode-toggle {
|
|
244
|
+
display: flex;
|
|
245
|
+
border-radius: 6px;
|
|
246
|
+
overflow: hidden;
|
|
247
|
+
background: rgba(255, 255, 255, 0.1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.review-mode-btn {
|
|
251
|
+
padding: 5px 10px;
|
|
252
|
+
font-family: inherit;
|
|
253
|
+
font-size: 12px;
|
|
254
|
+
font-weight: 500;
|
|
255
|
+
border: none;
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
color: rgba(255, 255, 255, 0.6);
|
|
258
|
+
background: transparent;
|
|
259
|
+
transition: background 0.15s ease, color 0.15s ease;
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
gap: 4px;
|
|
263
|
+
white-space: nowrap;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.review-mode-btn:hover {
|
|
267
|
+
color: rgba(255, 255, 255, 0.85);
|
|
268
|
+
background: rgba(255, 255, 255, 0.08);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.review-mode-btn--active {
|
|
272
|
+
background: #7c3aed;
|
|
273
|
+
color: #fff;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.review-mode-btn--active:hover {
|
|
277
|
+
background: #6d28d9;
|
|
278
|
+
color: #fff;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* \u2500\u2500\u2500 Comments Panel \u2500\u2500\u2500 */
|
|
282
|
+
.review-panel {
|
|
283
|
+
position: fixed;
|
|
284
|
+
top: 0;
|
|
285
|
+
right: 0;
|
|
286
|
+
bottom: 0;
|
|
287
|
+
width: 320px;
|
|
288
|
+
background: #111;
|
|
289
|
+
color: #fff;
|
|
290
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
291
|
+
z-index: 10001;
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-direction: column;
|
|
294
|
+
border-left: 1px solid rgba(255, 255, 255, 0.1);
|
|
295
|
+
transform: translateX(100%);
|
|
296
|
+
transition: transform 0.2s ease;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.review-panel--open {
|
|
300
|
+
transform: translateX(0);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.review-panel-header {
|
|
304
|
+
display: flex;
|
|
305
|
+
align-items: center;
|
|
306
|
+
justify-content: space-between;
|
|
307
|
+
padding: 14px 16px;
|
|
308
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
309
|
+
flex-shrink: 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.review-panel-header h3 {
|
|
313
|
+
margin: 0;
|
|
314
|
+
font-size: 14px;
|
|
315
|
+
font-weight: 600;
|
|
316
|
+
color: rgba(255, 255, 255, 0.9);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.review-panel-close {
|
|
320
|
+
background: none;
|
|
321
|
+
border: none;
|
|
322
|
+
color: rgba(255, 255, 255, 0.5);
|
|
323
|
+
cursor: pointer;
|
|
324
|
+
padding: 4px;
|
|
325
|
+
border-radius: 4px;
|
|
326
|
+
display: flex;
|
|
327
|
+
align-items: center;
|
|
328
|
+
justify-content: center;
|
|
329
|
+
transition: color 0.15s ease, background 0.15s ease;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.review-panel-close:hover {
|
|
333
|
+
color: rgba(255, 255, 255, 0.9);
|
|
334
|
+
background: rgba(255, 255, 255, 0.1);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.review-panel-body {
|
|
338
|
+
flex: 1;
|
|
339
|
+
overflow-y: auto;
|
|
340
|
+
padding: 12px 16px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.review-panel-section {
|
|
344
|
+
margin-bottom: 16px;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.review-panel-section-header {
|
|
348
|
+
font-size: 11px;
|
|
349
|
+
font-weight: 600;
|
|
350
|
+
text-transform: uppercase;
|
|
351
|
+
letter-spacing: 0.05em;
|
|
352
|
+
color: rgba(255, 255, 255, 0.4);
|
|
353
|
+
margin-bottom: 8px;
|
|
354
|
+
padding-bottom: 6px;
|
|
355
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.review-panel-section-toggle {
|
|
359
|
+
display: flex;
|
|
360
|
+
align-items: center;
|
|
361
|
+
gap: 6px;
|
|
362
|
+
font-size: 11px;
|
|
363
|
+
font-weight: 600;
|
|
364
|
+
text-transform: uppercase;
|
|
365
|
+
letter-spacing: 0.05em;
|
|
366
|
+
color: rgba(255, 255, 255, 0.4);
|
|
367
|
+
margin-bottom: 8px;
|
|
368
|
+
padding-bottom: 6px;
|
|
369
|
+
border: none;
|
|
370
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
371
|
+
background: none;
|
|
372
|
+
cursor: pointer;
|
|
373
|
+
width: 100%;
|
|
374
|
+
text-align: left;
|
|
375
|
+
transition: color 0.15s ease;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.review-panel-section-toggle:hover {
|
|
379
|
+
color: rgba(255, 255, 255, 0.6);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.review-panel-section-toggle svg {
|
|
383
|
+
transition: transform 0.15s ease;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.review-panel-section-toggle--expanded svg {
|
|
387
|
+
transform: rotate(90deg);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.review-panel-page-label {
|
|
391
|
+
font-size: 11px;
|
|
392
|
+
color: rgba(255, 255, 255, 0.3);
|
|
393
|
+
margin: 10px 0 6px;
|
|
394
|
+
font-family: monospace;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.review-panel-page-label:first-child {
|
|
398
|
+
margin-top: 0;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* \u2500\u2500\u2500 Comment Item \u2500\u2500\u2500 */
|
|
402
|
+
.review-panel-comment {
|
|
403
|
+
background: rgba(255, 255, 255, 0.05);
|
|
404
|
+
border-radius: 6px;
|
|
405
|
+
padding: 10px 12px;
|
|
406
|
+
margin-bottom: 6px;
|
|
407
|
+
cursor: pointer;
|
|
408
|
+
transition: background 0.15s ease;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.review-panel-comment:hover {
|
|
412
|
+
background: rgba(255, 255, 255, 0.08);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.review-panel-comment-header {
|
|
416
|
+
display: flex;
|
|
417
|
+
align-items: center;
|
|
418
|
+
gap: 8px;
|
|
419
|
+
margin-bottom: 4px;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.review-panel-pin-badge {
|
|
423
|
+
width: 18px;
|
|
424
|
+
height: 18px;
|
|
425
|
+
border-radius: 50%;
|
|
426
|
+
background: #7c3aed;
|
|
427
|
+
color: #fff;
|
|
428
|
+
font-size: 10px;
|
|
429
|
+
font-weight: 600;
|
|
430
|
+
display: flex;
|
|
431
|
+
align-items: center;
|
|
432
|
+
justify-content: center;
|
|
433
|
+
flex-shrink: 0;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.review-panel-general-badge {
|
|
437
|
+
width: 18px;
|
|
438
|
+
height: 18px;
|
|
439
|
+
display: flex;
|
|
440
|
+
align-items: center;
|
|
441
|
+
justify-content: center;
|
|
442
|
+
flex-shrink: 0;
|
|
443
|
+
color: rgba(255, 255, 255, 0.5);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.review-panel-comment-author {
|
|
447
|
+
font-size: 12px;
|
|
448
|
+
font-weight: 600;
|
|
449
|
+
color: rgba(255, 255, 255, 0.8);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.review-panel-comment-text {
|
|
453
|
+
font-size: 13px;
|
|
454
|
+
color: rgba(255, 255, 255, 0.6);
|
|
455
|
+
line-height: 1.4;
|
|
456
|
+
margin-bottom: 4px;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.review-panel-comment-time {
|
|
460
|
+
font-size: 11px;
|
|
461
|
+
color: rgba(255, 255, 255, 0.3);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.review-panel-empty {
|
|
465
|
+
text-align: center;
|
|
466
|
+
padding: 24px 16px;
|
|
467
|
+
color: rgba(255, 255, 255, 0.3);
|
|
468
|
+
font-size: 13px;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.review-panel-loading {
|
|
472
|
+
text-align: center;
|
|
473
|
+
padding: 24px 16px;
|
|
474
|
+
color: rgba(255, 255, 255, 0.4);
|
|
475
|
+
font-size: 13px;
|
|
476
|
+
}
|
|
477
|
+
|
|
231
478
|
/* \u2500\u2500\u2500 Comment Card \u2500\u2500\u2500 */
|
|
232
479
|
.review-comment-card {
|
|
233
480
|
position: fixed;
|
|
@@ -408,6 +655,81 @@ var REVIEW_STYLES = `
|
|
|
408
655
|
backdrop-filter: blur(8px);
|
|
409
656
|
}
|
|
410
657
|
|
|
658
|
+
/* \u2500\u2500\u2500 Name Entry Overlay \u2500\u2500\u2500 */
|
|
659
|
+
.review-name-overlay {
|
|
660
|
+
position: fixed;
|
|
661
|
+
inset: 0;
|
|
662
|
+
background: rgba(0, 0, 0, 0.4);
|
|
663
|
+
display: flex;
|
|
664
|
+
align-items: center;
|
|
665
|
+
justify-content: center;
|
|
666
|
+
z-index: 10003;
|
|
667
|
+
backdrop-filter: blur(2px);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.review-name-card {
|
|
671
|
+
background: #fff;
|
|
672
|
+
border-radius: 12px;
|
|
673
|
+
padding: 28px 32px;
|
|
674
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
675
|
+
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2);
|
|
676
|
+
max-width: 360px;
|
|
677
|
+
width: 90%;
|
|
678
|
+
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.review-name-card h3 {
|
|
682
|
+
margin: 0 0 4px;
|
|
683
|
+
font-size: 17px;
|
|
684
|
+
font-weight: 600;
|
|
685
|
+
color: #111;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.review-name-card p {
|
|
689
|
+
margin: 0 0 20px;
|
|
690
|
+
font-size: 14px;
|
|
691
|
+
color: #666;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.review-name-card label {
|
|
695
|
+
display: block;
|
|
696
|
+
font-size: 13px;
|
|
697
|
+
font-weight: 500;
|
|
698
|
+
color: #374151;
|
|
699
|
+
margin-bottom: 6px;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
.review-name-card input {
|
|
703
|
+
width: 100%;
|
|
704
|
+
border: 1px solid #d1d5db;
|
|
705
|
+
border-radius: 8px;
|
|
706
|
+
padding: 10px 12px;
|
|
707
|
+
font-family: inherit;
|
|
708
|
+
font-size: 14px;
|
|
709
|
+
color: #1f2937;
|
|
710
|
+
background: #fafafa;
|
|
711
|
+
box-sizing: border-box;
|
|
712
|
+
outline: none;
|
|
713
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.review-name-card input:focus {
|
|
717
|
+
border-color: #7c3aed;
|
|
718
|
+
box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.15);
|
|
719
|
+
background: #fff;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.review-name-card input::placeholder {
|
|
723
|
+
color: #9ca3af;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.review-name-actions {
|
|
727
|
+
display: flex;
|
|
728
|
+
justify-content: flex-end;
|
|
729
|
+
gap: 8px;
|
|
730
|
+
margin-top: 20px;
|
|
731
|
+
}
|
|
732
|
+
|
|
411
733
|
/* \u2500\u2500\u2500 Reduced Motion \u2500\u2500\u2500 */
|
|
412
734
|
@media (prefers-reduced-motion: reduce) {
|
|
413
735
|
*, *::before, *::after {
|
|
@@ -495,6 +817,11 @@ var PinManager = class {
|
|
|
495
817
|
document.body.appendChild(this.container);
|
|
496
818
|
}
|
|
497
819
|
addPin(pinNumber, x, y, isMine, pageUrl) {
|
|
820
|
+
const existing = this.pins.get(pinNumber);
|
|
821
|
+
if (existing) {
|
|
822
|
+
existing.el.remove();
|
|
823
|
+
this.pins.delete(pinNumber);
|
|
824
|
+
}
|
|
498
825
|
const pin = document.createElement("div");
|
|
499
826
|
pin.className = isMine ? "review-pin" : "review-pin review-pin--other";
|
|
500
827
|
pin.textContent = String(pinNumber);
|
|
@@ -684,6 +1011,173 @@ var PageNavigationListener = class {
|
|
|
684
1011
|
}
|
|
685
1012
|
};
|
|
686
1013
|
|
|
1014
|
+
// src/review/CommentListPanel.ts
|
|
1015
|
+
var CommentListPanel = class {
|
|
1016
|
+
constructor(token, shadowRoot, pinManager) {
|
|
1017
|
+
this.token = token;
|
|
1018
|
+
this.shadowRoot = shadowRoot;
|
|
1019
|
+
this.pinManager = pinManager;
|
|
1020
|
+
chunk4DE2IREA_cjs.__publicField(this, "panelEl");
|
|
1021
|
+
chunk4DE2IREA_cjs.__publicField(this, "bodyEl", null);
|
|
1022
|
+
chunk4DE2IREA_cjs.__publicField(this, "isOpen", false);
|
|
1023
|
+
chunk4DE2IREA_cjs.__publicField(this, "allPagesExpanded", false);
|
|
1024
|
+
chunk4DE2IREA_cjs.__publicField(this, "comments", []);
|
|
1025
|
+
this.panelEl = document.createElement("div");
|
|
1026
|
+
this.panelEl.className = "review-panel";
|
|
1027
|
+
this.panelEl.innerHTML = `
|
|
1028
|
+
<div class="review-panel-header">
|
|
1029
|
+
<h3>Comments</h3>
|
|
1030
|
+
<button class="review-panel-close" title="Close">
|
|
1031
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
1032
|
+
</button>
|
|
1033
|
+
</div>
|
|
1034
|
+
<div class="review-panel-body"></div>
|
|
1035
|
+
`;
|
|
1036
|
+
this.bodyEl = this.panelEl.querySelector(".review-panel-body");
|
|
1037
|
+
this.panelEl.querySelector(".review-panel-close")?.addEventListener("click", () => this.close());
|
|
1038
|
+
this.shadowRoot.appendChild(this.panelEl);
|
|
1039
|
+
}
|
|
1040
|
+
async toggle() {
|
|
1041
|
+
if (this.isOpen) {
|
|
1042
|
+
this.close();
|
|
1043
|
+
} else {
|
|
1044
|
+
await this.open();
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
async open() {
|
|
1048
|
+
this.isOpen = true;
|
|
1049
|
+
this.panelEl.classList.add("review-panel--open");
|
|
1050
|
+
await this.refresh();
|
|
1051
|
+
}
|
|
1052
|
+
close() {
|
|
1053
|
+
this.isOpen = false;
|
|
1054
|
+
this.panelEl.classList.remove("review-panel--open");
|
|
1055
|
+
this.pinManager.clearHighlight();
|
|
1056
|
+
}
|
|
1057
|
+
async refresh() {
|
|
1058
|
+
if (!this.isOpen || !this.bodyEl) return;
|
|
1059
|
+
this.bodyEl.innerHTML = '<div class="review-panel-loading">Loading comments...</div>';
|
|
1060
|
+
try {
|
|
1061
|
+
this.comments = await fetchComments(this.token);
|
|
1062
|
+
this.render();
|
|
1063
|
+
} catch {
|
|
1064
|
+
this.bodyEl.innerHTML = '<div class="review-panel-empty">Failed to load comments</div>';
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
render() {
|
|
1068
|
+
if (!this.bodyEl) return;
|
|
1069
|
+
const withText = this.comments.filter((c) => c.commentText);
|
|
1070
|
+
if (withText.length === 0) {
|
|
1071
|
+
this.bodyEl.innerHTML = '<div class="review-panel-empty">No comments yet</div>';
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
const currentPage = getCurrentPageId();
|
|
1075
|
+
const currentPageComments = withText.filter((c) => c.pageUrl === currentPage);
|
|
1076
|
+
const otherComments = withText.filter((c) => c.pageUrl !== currentPage);
|
|
1077
|
+
let html = "";
|
|
1078
|
+
html += '<div class="review-panel-section">';
|
|
1079
|
+
html += `<div class="review-panel-section-header">This Page</div>`;
|
|
1080
|
+
if (currentPageComments.length === 0) {
|
|
1081
|
+
html += '<div class="review-panel-empty" style="padding:8px 0;">No comments on this page</div>';
|
|
1082
|
+
} else {
|
|
1083
|
+
html += this.renderComments(currentPageComments);
|
|
1084
|
+
}
|
|
1085
|
+
html += "</div>";
|
|
1086
|
+
if (otherComments.length > 0) {
|
|
1087
|
+
const groups = this.groupByPage(otherComments);
|
|
1088
|
+
html += '<div class="review-panel-section">';
|
|
1089
|
+
html += `<button class="review-panel-section-toggle ${this.allPagesExpanded ? "review-panel-section-toggle--expanded" : ""}" data-action="toggle-all">
|
|
1090
|
+
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
|
|
1091
|
+
All Pages (${otherComments.length} comment${otherComments.length !== 1 ? "s" : ""})
|
|
1092
|
+
</button>`;
|
|
1093
|
+
if (this.allPagesExpanded) {
|
|
1094
|
+
html += '<div class="review-panel-all-pages">';
|
|
1095
|
+
for (const group of groups) {
|
|
1096
|
+
html += `<div class="review-panel-page-label">${this.escapeHtml(this.formatPageUrl(group.pageUrl))}</div>`;
|
|
1097
|
+
html += this.renderComments(group.comments);
|
|
1098
|
+
}
|
|
1099
|
+
html += "</div>";
|
|
1100
|
+
}
|
|
1101
|
+
html += "</div>";
|
|
1102
|
+
}
|
|
1103
|
+
this.bodyEl.innerHTML = html;
|
|
1104
|
+
this.attachEventListeners();
|
|
1105
|
+
}
|
|
1106
|
+
renderComments(comments) {
|
|
1107
|
+
return comments.map((c) => {
|
|
1108
|
+
const badge = c.pinNumber != null ? `<span class="review-panel-pin-badge">${c.pinNumber}</span>` : `<span class="review-panel-general-badge"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>`;
|
|
1109
|
+
const author = c.reviewerName || "Anonymous";
|
|
1110
|
+
const text = c.commentText || "";
|
|
1111
|
+
const time = this.formatTime(c.createdAt);
|
|
1112
|
+
const pinAttr = c.pinNumber != null ? `data-pin="${c.pinNumber}"` : "";
|
|
1113
|
+
const pageAttr = c.pageUrl ? `data-page="${this.escapeAttr(c.pageUrl)}"` : "";
|
|
1114
|
+
return `<div class="review-panel-comment" ${pinAttr} ${pageAttr}>
|
|
1115
|
+
<div class="review-panel-comment-header">
|
|
1116
|
+
${badge}
|
|
1117
|
+
<span class="review-panel-comment-author">${this.escapeHtml(author)}</span>
|
|
1118
|
+
</div>
|
|
1119
|
+
<div class="review-panel-comment-text">${this.escapeHtml(text)}</div>
|
|
1120
|
+
<div class="review-panel-comment-time">${time}</div>
|
|
1121
|
+
</div>`;
|
|
1122
|
+
}).join("");
|
|
1123
|
+
}
|
|
1124
|
+
attachEventListeners() {
|
|
1125
|
+
if (!this.bodyEl) return;
|
|
1126
|
+
this.bodyEl.querySelector('[data-action="toggle-all"]')?.addEventListener("click", () => {
|
|
1127
|
+
this.allPagesExpanded = !this.allPagesExpanded;
|
|
1128
|
+
this.render();
|
|
1129
|
+
});
|
|
1130
|
+
this.bodyEl.querySelectorAll(".review-panel-comment[data-pin]").forEach((el) => {
|
|
1131
|
+
el.addEventListener("click", () => {
|
|
1132
|
+
const pinNumber = Number(el.dataset.pin);
|
|
1133
|
+
if (pinNumber) {
|
|
1134
|
+
this.pinManager.highlightPin(pinNumber);
|
|
1135
|
+
}
|
|
1136
|
+
});
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
groupByPage(comments) {
|
|
1140
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1141
|
+
for (const c of comments) {
|
|
1142
|
+
const key = c.pageUrl || "(unknown)";
|
|
1143
|
+
const arr = groups.get(key) || [];
|
|
1144
|
+
arr.push(c);
|
|
1145
|
+
groups.set(key, arr);
|
|
1146
|
+
}
|
|
1147
|
+
return Array.from(groups.entries()).map(([pageUrl, comments2]) => ({ pageUrl, comments: comments2 }));
|
|
1148
|
+
}
|
|
1149
|
+
formatPageUrl(url) {
|
|
1150
|
+
try {
|
|
1151
|
+
const u = new URL(url, "https://placeholder");
|
|
1152
|
+
return u.pathname + u.search + u.hash;
|
|
1153
|
+
} catch {
|
|
1154
|
+
return url || "/";
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
formatTime(iso) {
|
|
1158
|
+
const date = new Date(iso);
|
|
1159
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
1160
|
+
const now = Date.now();
|
|
1161
|
+
const diffMs = Math.max(0, now - date.getTime());
|
|
1162
|
+
const diffMin = Math.floor(diffMs / 6e4);
|
|
1163
|
+
if (diffMin < 1) return "just now";
|
|
1164
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
1165
|
+
const diffHr = Math.floor(diffMin / 60);
|
|
1166
|
+
if (diffHr < 24) return `${diffHr}h ago`;
|
|
1167
|
+
const diffDays = Math.floor(diffHr / 24);
|
|
1168
|
+
return `${diffDays}d ago`;
|
|
1169
|
+
}
|
|
1170
|
+
escapeHtml(str) {
|
|
1171
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1172
|
+
}
|
|
1173
|
+
escapeAttr(str) {
|
|
1174
|
+
return str.replace(/"/g, """).replace(/'/g, "'");
|
|
1175
|
+
}
|
|
1176
|
+
destroy() {
|
|
1177
|
+
this.panelEl.remove();
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
|
|
687
1181
|
// src/review/ReviewMode.ts
|
|
688
1182
|
var ReviewMode = class {
|
|
689
1183
|
constructor(token, shadowRoot, initData) {
|
|
@@ -698,15 +1192,22 @@ var ReviewMode = class {
|
|
|
698
1192
|
chunk4DE2IREA_cjs.__publicField(this, "toolbarEl", null);
|
|
699
1193
|
chunk4DE2IREA_cjs.__publicField(this, "clickHandler", null);
|
|
700
1194
|
chunk4DE2IREA_cjs.__publicField(this, "pageListener", null);
|
|
1195
|
+
chunk4DE2IREA_cjs.__publicField(this, "mode", "comment");
|
|
1196
|
+
chunk4DE2IREA_cjs.__publicField(this, "keydownHandler", null);
|
|
1197
|
+
chunk4DE2IREA_cjs.__publicField(this, "commentPanel", null);
|
|
701
1198
|
this.pinManager = new PinManager();
|
|
702
1199
|
this.commentCard = new CommentCard(shadowRoot);
|
|
703
1200
|
this.nextPinNumber = initData.nextPinNumber;
|
|
704
1201
|
}
|
|
705
1202
|
async init() {
|
|
1203
|
+
if (!this.initData.reviewer.name) {
|
|
1204
|
+
await this.showNameEntry();
|
|
1205
|
+
}
|
|
706
1206
|
document.body.style.cursor = "crosshair";
|
|
707
1207
|
this.pinManager.mount();
|
|
708
1208
|
this.showPrompt();
|
|
709
1209
|
this.renderToolbar();
|
|
1210
|
+
this.commentPanel = new CommentListPanel(this.token, this.shadowRoot, this.pinManager);
|
|
710
1211
|
await this.loadExistingPins();
|
|
711
1212
|
this.pinManager.filterByPage(getCurrentPageId());
|
|
712
1213
|
this.pageListener = new PageNavigationListener((pageId) => {
|
|
@@ -715,6 +1216,15 @@ var ReviewMode = class {
|
|
|
715
1216
|
this.pageListener.start();
|
|
716
1217
|
this.clickHandler = (e) => this.handleClick(e);
|
|
717
1218
|
document.addEventListener("click", this.clickHandler, true);
|
|
1219
|
+
this.keydownHandler = (e) => {
|
|
1220
|
+
const tag = e.target?.tagName;
|
|
1221
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
|
|
1222
|
+
if (e.target?.isContentEditable) return;
|
|
1223
|
+
if (e.key === "c" && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
1224
|
+
this.setMode(this.mode === "comment" ? "navigate" : "comment");
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
document.addEventListener("keydown", this.keydownHandler);
|
|
718
1228
|
}
|
|
719
1229
|
showPrompt() {
|
|
720
1230
|
this.promptEl = document.createElement("div");
|
|
@@ -732,6 +1242,59 @@ var ReviewMode = class {
|
|
|
732
1242
|
this.promptEl = null;
|
|
733
1243
|
}
|
|
734
1244
|
}
|
|
1245
|
+
showNameEntry() {
|
|
1246
|
+
return new Promise((resolve) => {
|
|
1247
|
+
const overlay = document.createElement("div");
|
|
1248
|
+
overlay.className = "review-name-overlay";
|
|
1249
|
+
overlay.innerHTML = `
|
|
1250
|
+
<div class="review-name-card">
|
|
1251
|
+
<h3>Welcome to the review</h3>
|
|
1252
|
+
<p>Optionally enter your name so the team knows who left the feedback.</p>
|
|
1253
|
+
<div style="margin-bottom:12px;">
|
|
1254
|
+
<label>Name</label>
|
|
1255
|
+
<input type="text" class="review-name-input" placeholder="Your name (optional)" />
|
|
1256
|
+
</div>
|
|
1257
|
+
<div>
|
|
1258
|
+
<label>Email</label>
|
|
1259
|
+
<input type="email" class="review-email-input" placeholder="Your email (optional)" />
|
|
1260
|
+
</div>
|
|
1261
|
+
<div class="review-name-actions">
|
|
1262
|
+
<button class="review-btn review-btn--cancel review-name-skip">Skip</button>
|
|
1263
|
+
<button class="review-btn review-btn--submit review-name-continue">Continue</button>
|
|
1264
|
+
</div>
|
|
1265
|
+
</div>
|
|
1266
|
+
`;
|
|
1267
|
+
this.shadowRoot.appendChild(overlay);
|
|
1268
|
+
const nameInput = overlay.querySelector(".review-name-input");
|
|
1269
|
+
const emailInput = overlay.querySelector(".review-email-input");
|
|
1270
|
+
const skipBtn = overlay.querySelector(".review-name-skip");
|
|
1271
|
+
const continueBtn = overlay.querySelector(".review-name-continue");
|
|
1272
|
+
const finish = async () => {
|
|
1273
|
+
const name = nameInput.value.trim() || void 0;
|
|
1274
|
+
const email = emailInput.value.trim() || void 0;
|
|
1275
|
+
try {
|
|
1276
|
+
await identify(this.token, name, email);
|
|
1277
|
+
} catch {
|
|
1278
|
+
}
|
|
1279
|
+
overlay.remove();
|
|
1280
|
+
resolve();
|
|
1281
|
+
};
|
|
1282
|
+
skipBtn.addEventListener("click", () => {
|
|
1283
|
+
identify(this.token).catch(() => {
|
|
1284
|
+
});
|
|
1285
|
+
overlay.remove();
|
|
1286
|
+
resolve();
|
|
1287
|
+
});
|
|
1288
|
+
continueBtn.addEventListener("click", finish);
|
|
1289
|
+
nameInput.addEventListener("keydown", (e) => {
|
|
1290
|
+
if (e.key === "Enter") finish();
|
|
1291
|
+
});
|
|
1292
|
+
emailInput.addEventListener("keydown", (e) => {
|
|
1293
|
+
if (e.key === "Enter") finish();
|
|
1294
|
+
});
|
|
1295
|
+
nameInput.focus();
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
735
1298
|
renderToolbar() {
|
|
736
1299
|
this.toolbarEl = document.createElement("div");
|
|
737
1300
|
this.toolbarEl.className = "review-toolbar";
|
|
@@ -741,15 +1304,41 @@ var ReviewMode = class {
|
|
|
741
1304
|
updateToolbar() {
|
|
742
1305
|
if (!this.toolbarEl) return;
|
|
743
1306
|
const pinCount = this.nextPinNumber - 1;
|
|
1307
|
+
const isNav = this.mode === "navigate";
|
|
1308
|
+
const isComment = this.mode === "comment";
|
|
744
1309
|
this.toolbarEl.innerHTML = `
|
|
1310
|
+
<div class="review-mode-toggle">
|
|
1311
|
+
<button class="review-mode-btn ${isNav ? "review-mode-btn--active" : ""}" data-mode="navigate">
|
|
1312
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
|
|
1313
|
+
Navigate
|
|
1314
|
+
</button>
|
|
1315
|
+
<button class="review-mode-btn ${isComment ? "review-mode-btn--active" : ""}" data-mode="comment">
|
|
1316
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0Z"/><circle cx="12" cy="10" r="3"/></svg>
|
|
1317
|
+
Comment
|
|
1318
|
+
</button>
|
|
1319
|
+
</div>
|
|
745
1320
|
<span style="font-weight:500;">${this.initData.session.name}</span>
|
|
746
1321
|
<span style="opacity:0.7;">${pinCount} pin${pinCount !== 1 ? "s" : ""}</span>
|
|
747
|
-
<button class="review-btn review-btn--submit" style="margin-left:auto;padding:6px 12px;font-size:13px;">General Comment</button>
|
|
1322
|
+
<button class="review-btn review-btn--submit" data-action="general" style="margin-left:auto;padding:6px 12px;font-size:13px;">General Comment</button>
|
|
1323
|
+
<button class="review-mode-btn" data-action="panel" title="View all comments" style="padding:5px 8px;">
|
|
1324
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
1325
|
+
</button>
|
|
748
1326
|
`;
|
|
749
|
-
this.toolbarEl.
|
|
1327
|
+
this.toolbarEl.querySelectorAll("[data-mode]").forEach((btn) => {
|
|
1328
|
+
btn.addEventListener("click", (e) => {
|
|
1329
|
+
e.stopPropagation();
|
|
1330
|
+
const mode = btn.dataset.mode;
|
|
1331
|
+
this.setMode(mode);
|
|
1332
|
+
});
|
|
1333
|
+
});
|
|
1334
|
+
this.toolbarEl.querySelector('[data-action="general"]')?.addEventListener("click", (e) => {
|
|
750
1335
|
e.stopPropagation();
|
|
751
1336
|
this.handleGeneralComment();
|
|
752
1337
|
});
|
|
1338
|
+
this.toolbarEl.querySelector('[data-action="panel"]')?.addEventListener("click", (e) => {
|
|
1339
|
+
e.stopPropagation();
|
|
1340
|
+
this.toggleCommentPanel();
|
|
1341
|
+
});
|
|
753
1342
|
}
|
|
754
1343
|
async loadExistingPins() {
|
|
755
1344
|
try {
|
|
@@ -764,6 +1353,7 @@ var ReviewMode = class {
|
|
|
764
1353
|
}
|
|
765
1354
|
}
|
|
766
1355
|
handleClick(e) {
|
|
1356
|
+
if (this.mode === "navigate") return;
|
|
767
1357
|
const path = e.composedPath();
|
|
768
1358
|
if (path.some((el) => el instanceof HTMLElement && el.closest?.("#ourroadmaps-review"))) return;
|
|
769
1359
|
if (this.pendingPinNumber != null) return;
|
|
@@ -786,6 +1376,7 @@ var ReviewMode = class {
|
|
|
786
1376
|
this.nextPinNumber++;
|
|
787
1377
|
this.updateToolbar();
|
|
788
1378
|
this.showToast("Comment saved");
|
|
1379
|
+
this.commentPanel?.refresh();
|
|
789
1380
|
},
|
|
790
1381
|
onCancel: () => {
|
|
791
1382
|
this.pinManager.removePin(pinNumber);
|
|
@@ -795,6 +1386,14 @@ var ReviewMode = class {
|
|
|
795
1386
|
e.preventDefault();
|
|
796
1387
|
e.stopPropagation();
|
|
797
1388
|
}
|
|
1389
|
+
setMode(newMode) {
|
|
1390
|
+
this.mode = newMode;
|
|
1391
|
+
document.body.style.cursor = newMode === "comment" ? "crosshair" : "";
|
|
1392
|
+
this.updateToolbar();
|
|
1393
|
+
}
|
|
1394
|
+
toggleCommentPanel() {
|
|
1395
|
+
this.commentPanel?.toggle();
|
|
1396
|
+
}
|
|
798
1397
|
handleGeneralComment() {
|
|
799
1398
|
if (this.pendingPinNumber != null) return;
|
|
800
1399
|
this.commentCard.showForGeneral({
|
|
@@ -806,6 +1405,7 @@ var ReviewMode = class {
|
|
|
806
1405
|
pageUrl: getCurrentPageId()
|
|
807
1406
|
});
|
|
808
1407
|
this.showToast("Comment saved");
|
|
1408
|
+
this.commentPanel?.refresh();
|
|
809
1409
|
},
|
|
810
1410
|
onCancel: () => {
|
|
811
1411
|
}
|
|
@@ -824,9 +1424,13 @@ var ReviewMode = class {
|
|
|
824
1424
|
document.removeEventListener("click", this.clickHandler, true);
|
|
825
1425
|
}
|
|
826
1426
|
this.pageListener?.destroy();
|
|
1427
|
+
if (this.keydownHandler) {
|
|
1428
|
+
document.removeEventListener("keydown", this.keydownHandler);
|
|
1429
|
+
}
|
|
827
1430
|
this.dismissPrompt();
|
|
828
1431
|
this.toolbarEl?.remove();
|
|
829
1432
|
this.commentCard.hide();
|
|
1433
|
+
this.commentPanel?.destroy();
|
|
830
1434
|
this.pinManager.destroy();
|
|
831
1435
|
}
|
|
832
1436
|
};
|
|
@@ -1092,10 +1696,16 @@ var Review = class {
|
|
|
1092
1696
|
tokenType = "review";
|
|
1093
1697
|
token = reviewToken;
|
|
1094
1698
|
storeToken("review", reviewToken);
|
|
1699
|
+
const clean = new URL(window.location.href);
|
|
1700
|
+
clean.searchParams.delete("review");
|
|
1701
|
+
history.replaceState(null, "", clean.toString());
|
|
1095
1702
|
} else if (triageToken) {
|
|
1096
1703
|
tokenType = "triage";
|
|
1097
1704
|
token = triageToken;
|
|
1098
1705
|
storeToken("triage", triageToken);
|
|
1706
|
+
const clean = new URL(window.location.href);
|
|
1707
|
+
clean.searchParams.delete("triage");
|
|
1708
|
+
history.replaceState(null, "", clean.toString());
|
|
1099
1709
|
} else {
|
|
1100
1710
|
const stored = getStoredToken();
|
|
1101
1711
|
if (stored) {
|
|
@@ -1159,5 +1769,5 @@ var Review = class {
|
|
|
1159
1769
|
exports.Review = Review;
|
|
1160
1770
|
exports.getStoredToken = getStoredToken;
|
|
1161
1771
|
exports.storeToken = storeToken;
|
|
1162
|
-
//# sourceMappingURL=chunk-
|
|
1163
|
-
//# sourceMappingURL=chunk-
|
|
1772
|
+
//# sourceMappingURL=chunk-VXDCDIG3.cjs.map
|
|
1773
|
+
//# sourceMappingURL=chunk-VXDCDIG3.cjs.map
|