@ourroadmaps/web-sdk 1.4.2 → 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.
@@ -1,4 +1,4 @@
1
- "use strict";var OurRoadmaps=(()=>{var v=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var W=(n,e,t)=>e in n?v(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var B=(n,e)=>{for(var t in e)v(n,t,{get:e[t],enumerable:!0})},j=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of X(e))!F.call(n,o)&&o!==t&&v(n,o,{get:()=>e[o],enumerable:!(i=_(e,o))||i.enumerable});return n};var q=n=>j(v({},"__esModule",{value:!0}),n);var r=(n,e,t)=>W(n,typeof e!="symbol"?e+"":e,t);var Q={};B(Q,{Review:()=>P});var G={},S=(typeof G<"u","https://api.ourroadmaps.com");async function L(n){let e=await fetch(`${S}/v1/prototype-review/${n}`);if(e.status===410)throw new m("expired","This feedback session has expired");if(e.status===404)throw new m("invalid","This review link is not valid");if(!e.ok)throw new m("error","Something went wrong");return(await e.json()).data}async function M(n,e){let t=await fetch(`${S}/v1/prototype-review/${n}/comments`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new m("error","Failed to submit comment");return(await t.json()).data}async function w(n){let e=await fetch(`${S}/v1/prototype-review/${n}/comments`);if(!e.ok)throw new m("error","Failed to load comments");return(await e.json()).data}var m=class extends Error{constructor(t,i){super(i);this.code=t;this.name="ReviewError"}};function z(n,e){let t=document.elementFromPoint(n,e),i=document.documentElement,o=(n+window.scrollX)/i.scrollWidth*100,s=(e+window.scrollY)/i.scrollHeight*100;if(!t||t===document.body||t===i)return{pinX:o,pinY:s,element:{selector:"body",tag:"body",text:"",ariaLabel:null,className:"",boundingBox:{x:0,y:0,w:i.scrollWidth,h:i.scrollHeight}},context:{parentTag:"",parentText:"",grandparentTag:"",siblings:[],nearbyText:""},viewportWidth:window.innerWidth,viewportHeight:window.innerHeight};let a=t.getBoundingClientRect();return{pinX:o,pinY:s,element:{selector:J(t),tag:t.tagName.toLowerCase(),text:b(t).slice(0,200),ariaLabel:t.getAttribute("aria-label"),className:t.className&&typeof t.className=="string"?t.className:"",boundingBox:{x:Math.round(a.x),y:Math.round(a.y),w:Math.round(a.width),h:Math.round(a.height)}},context:{parentTag:t.parentElement?`${t.parentElement.tagName.toLowerCase()}${D(t.parentElement)}`:"",parentText:t.parentElement?b(t.parentElement).slice(0,100):"",grandparentTag:t.parentElement?.parentElement?`${t.parentElement.parentElement.tagName.toLowerCase()}${D(t.parentElement.parentElement)}`:"",siblings:K(t),nearbyText:V(t).slice(0,200)},viewportWidth:window.innerWidth,viewportHeight:window.innerHeight}}function J(n){let e=[],t=n;for(;t&&t!==document.body;){if(t.id){e.unshift(`#${t.id}`);break}let i=t.tagName.toLowerCase();if(t.className&&typeof t.className=="string"){let o=t.className.trim().split(/\s+/).slice(0,2).join(".");o&&(i+=`.${o}`)}e.unshift(i),t=t.parentElement}return e.join(" > ")}function b(n){let e="";for(let t of n.childNodes)t.nodeType===Node.TEXT_NODE&&(e+=t.textContent?.trim()||"");return e.trim()||n.textContent?.trim().slice(0,200)||""}function D(n){if(!n.className||typeof n.className!="string")return"";let e=n.className.trim().split(/\s+/).slice(0,2).join(".");return e?`.${e}`:""}function K(n){if(!n.parentElement)return[];let e=[];for(let t of n.parentElement.children){if(t===n)continue;let i=t.tagName.toLowerCase(),o=(t.textContent?.trim()||"").slice(0,50);if(e.push(o?`${i}:${o}`:i),e.length>=4)break}return e}function V(n){let e=n.parentElement,t=0;for(;e&&t<3;){let i=b(e);if(i&&i!==b(n))return i;e=e.parentElement,t++}return""}var I=`
1
+ "use strict";var OurRoadmaps=(()=>{var w=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var F=(o,e,t)=>e in o?w(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var W=(o,e)=>{for(var t in e)w(o,t,{get:e[t],enumerable:!0})},K=(o,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of X(e))!_.call(o,n)&&n!==t&&w(o,n,{get:()=>e[n],enumerable:!(i=q(e,n))||i.enumerable});return o};var G=o=>K(w({},"__esModule",{value:!0}),o);var s=(o,e,t)=>F(o,typeof e!="symbol"?e+"":e,t);var ee={};W(ee,{Review:()=>T});var V={},b=(typeof V<"u","https://api.ourroadmaps.com");async function M(o){let e=await fetch(`${b}/v1/prototype-review/${o}`);if(e.status===410)throw new h("expired","This feedback session has expired");if(e.status===404)throw new h("invalid","This review link is not valid");if(!e.ok)throw new h("error","Something went wrong");return(await e.json()).data}async function S(o,e,t){let i={};if(e&&(i.name=e),t&&(i.email=t),!(await fetch(`${b}/v1/prototype-review/${o}/identify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})).ok)throw new h("error","Failed to identify")}async function H(o,e){let t=await fetch(`${b}/v1/prototype-review/${o}/comments`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new h("error","Failed to submit comment");return(await t.json()).data}async function g(o){let e=await fetch(`${b}/v1/prototype-review/${o}/comments`);if(!e.ok)throw new h("error","Failed to load comments");return(await e.json()).data}var h=class extends Error{constructor(t,i){super(i);this.code=t;this.name="ReviewError"}};function I(o,e){let t=document.elementFromPoint(o,e),i=document.documentElement,n=(o+window.scrollX)/i.scrollWidth*100,r=(e+window.scrollY)/i.scrollHeight*100;if(!t||t===document.body||t===i)return{pinX:n,pinY:r,element:{selector:"body",tag:"body",text:"",ariaLabel:null,className:"",boundingBox:{x:0,y:0,w:i.scrollWidth,h:i.scrollHeight}},context:{parentTag:"",parentText:"",grandparentTag:"",siblings:[],nearbyText:""},viewportWidth:window.innerWidth,viewportHeight:window.innerHeight};let a=t.getBoundingClientRect();return{pinX:n,pinY:r,element:{selector:J(t),tag:t.tagName.toLowerCase(),text:x(t).slice(0,200),ariaLabel:t.getAttribute("aria-label"),className:t.className&&typeof t.className=="string"?t.className:"",boundingBox:{x:Math.round(a.x),y:Math.round(a.y),w:Math.round(a.width),h:Math.round(a.height)}},context:{parentTag:t.parentElement?`${t.parentElement.tagName.toLowerCase()}${U(t.parentElement)}`:"",parentText:t.parentElement?x(t.parentElement).slice(0,100):"",grandparentTag:t.parentElement?.parentElement?`${t.parentElement.parentElement.tagName.toLowerCase()}${U(t.parentElement.parentElement)}`:"",siblings:Z(t),nearbyText:Q(t).slice(0,200)},viewportWidth:window.innerWidth,viewportHeight:window.innerHeight}}function J(o){let e=[],t=o;for(;t&&t!==document.body;){if(t.id){e.unshift(`#${t.id}`);break}let i=t.tagName.toLowerCase();if(t.className&&typeof t.className=="string"){let n=t.className.trim().split(/\s+/).slice(0,2).join(".");n&&(i+=`.${n}`)}e.unshift(i),t=t.parentElement}return e.join(" > ")}function x(o){let e="";for(let t of o.childNodes)t.nodeType===Node.TEXT_NODE&&(e+=t.textContent?.trim()||"");return e.trim()||o.textContent?.trim().slice(0,200)||""}function U(o){if(!o.className||typeof o.className!="string")return"";let e=o.className.trim().split(/\s+/).slice(0,2).join(".");return e?`.${e}`:""}function Z(o){if(!o.parentElement)return[];let e=[];for(let t of o.parentElement.children){if(t===o)continue;let i=t.tagName.toLowerCase(),n=(t.textContent?.trim()||"").slice(0,50);if(e.push(n?`${i}:${n}`:i),e.length>=4)break}return e}function Q(o){let e=o.parentElement,t=0;for(;e&&t<3;){let i=x(e);if(i&&i!==x(o))return i;e=e.parentElement,t++}return""}var A=`
2
2
  :host {
3
3
  all: initial;
4
4
  }
@@ -70,6 +70,242 @@
70
70
  box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.2);
71
71
  }
72
72
 
73
+ /* \u2500\u2500\u2500 Mode Toggle \u2500\u2500\u2500 */
74
+ .review-mode-toggle {
75
+ display: flex;
76
+ border-radius: 6px;
77
+ overflow: hidden;
78
+ background: rgba(255, 255, 255, 0.1);
79
+ }
80
+
81
+ .review-mode-btn {
82
+ padding: 5px 10px;
83
+ font-family: inherit;
84
+ font-size: 12px;
85
+ font-weight: 500;
86
+ border: none;
87
+ cursor: pointer;
88
+ color: rgba(255, 255, 255, 0.6);
89
+ background: transparent;
90
+ transition: background 0.15s ease, color 0.15s ease;
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 4px;
94
+ white-space: nowrap;
95
+ }
96
+
97
+ .review-mode-btn:hover {
98
+ color: rgba(255, 255, 255, 0.85);
99
+ background: rgba(255, 255, 255, 0.08);
100
+ }
101
+
102
+ .review-mode-btn--active {
103
+ background: #7c3aed;
104
+ color: #fff;
105
+ }
106
+
107
+ .review-mode-btn--active:hover {
108
+ background: #6d28d9;
109
+ color: #fff;
110
+ }
111
+
112
+ /* \u2500\u2500\u2500 Comments Panel \u2500\u2500\u2500 */
113
+ .review-panel {
114
+ position: fixed;
115
+ top: 0;
116
+ right: 0;
117
+ bottom: 0;
118
+ width: 320px;
119
+ background: #111;
120
+ color: #fff;
121
+ font-family: system-ui, -apple-system, sans-serif;
122
+ z-index: 10001;
123
+ display: flex;
124
+ flex-direction: column;
125
+ border-left: 1px solid rgba(255, 255, 255, 0.1);
126
+ transform: translateX(100%);
127
+ transition: transform 0.2s ease;
128
+ }
129
+
130
+ .review-panel--open {
131
+ transform: translateX(0);
132
+ }
133
+
134
+ .review-panel-header {
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: space-between;
138
+ padding: 14px 16px;
139
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
140
+ flex-shrink: 0;
141
+ }
142
+
143
+ .review-panel-header h3 {
144
+ margin: 0;
145
+ font-size: 14px;
146
+ font-weight: 600;
147
+ color: rgba(255, 255, 255, 0.9);
148
+ }
149
+
150
+ .review-panel-close {
151
+ background: none;
152
+ border: none;
153
+ color: rgba(255, 255, 255, 0.5);
154
+ cursor: pointer;
155
+ padding: 4px;
156
+ border-radius: 4px;
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: center;
160
+ transition: color 0.15s ease, background 0.15s ease;
161
+ }
162
+
163
+ .review-panel-close:hover {
164
+ color: rgba(255, 255, 255, 0.9);
165
+ background: rgba(255, 255, 255, 0.1);
166
+ }
167
+
168
+ .review-panel-body {
169
+ flex: 1;
170
+ overflow-y: auto;
171
+ padding: 12px 16px;
172
+ }
173
+
174
+ .review-panel-section {
175
+ margin-bottom: 16px;
176
+ }
177
+
178
+ .review-panel-section-header {
179
+ font-size: 11px;
180
+ font-weight: 600;
181
+ text-transform: uppercase;
182
+ letter-spacing: 0.05em;
183
+ color: rgba(255, 255, 255, 0.4);
184
+ margin-bottom: 8px;
185
+ padding-bottom: 6px;
186
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
187
+ }
188
+
189
+ .review-panel-section-toggle {
190
+ display: flex;
191
+ align-items: center;
192
+ gap: 6px;
193
+ font-size: 11px;
194
+ font-weight: 600;
195
+ text-transform: uppercase;
196
+ letter-spacing: 0.05em;
197
+ color: rgba(255, 255, 255, 0.4);
198
+ margin-bottom: 8px;
199
+ padding-bottom: 6px;
200
+ border: none;
201
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
202
+ background: none;
203
+ cursor: pointer;
204
+ width: 100%;
205
+ text-align: left;
206
+ transition: color 0.15s ease;
207
+ }
208
+
209
+ .review-panel-section-toggle:hover {
210
+ color: rgba(255, 255, 255, 0.6);
211
+ }
212
+
213
+ .review-panel-section-toggle svg {
214
+ transition: transform 0.15s ease;
215
+ }
216
+
217
+ .review-panel-section-toggle--expanded svg {
218
+ transform: rotate(90deg);
219
+ }
220
+
221
+ .review-panel-page-label {
222
+ font-size: 11px;
223
+ color: rgba(255, 255, 255, 0.3);
224
+ margin: 10px 0 6px;
225
+ font-family: monospace;
226
+ }
227
+
228
+ .review-panel-page-label:first-child {
229
+ margin-top: 0;
230
+ }
231
+
232
+ /* \u2500\u2500\u2500 Comment Item \u2500\u2500\u2500 */
233
+ .review-panel-comment {
234
+ background: rgba(255, 255, 255, 0.05);
235
+ border-radius: 6px;
236
+ padding: 10px 12px;
237
+ margin-bottom: 6px;
238
+ cursor: pointer;
239
+ transition: background 0.15s ease;
240
+ }
241
+
242
+ .review-panel-comment:hover {
243
+ background: rgba(255, 255, 255, 0.08);
244
+ }
245
+
246
+ .review-panel-comment-header {
247
+ display: flex;
248
+ align-items: center;
249
+ gap: 8px;
250
+ margin-bottom: 4px;
251
+ }
252
+
253
+ .review-panel-pin-badge {
254
+ width: 18px;
255
+ height: 18px;
256
+ border-radius: 50%;
257
+ background: #7c3aed;
258
+ color: #fff;
259
+ font-size: 10px;
260
+ font-weight: 600;
261
+ display: flex;
262
+ align-items: center;
263
+ justify-content: center;
264
+ flex-shrink: 0;
265
+ }
266
+
267
+ .review-panel-general-badge {
268
+ width: 18px;
269
+ height: 18px;
270
+ display: flex;
271
+ align-items: center;
272
+ justify-content: center;
273
+ flex-shrink: 0;
274
+ color: rgba(255, 255, 255, 0.5);
275
+ }
276
+
277
+ .review-panel-comment-author {
278
+ font-size: 12px;
279
+ font-weight: 600;
280
+ color: rgba(255, 255, 255, 0.8);
281
+ }
282
+
283
+ .review-panel-comment-text {
284
+ font-size: 13px;
285
+ color: rgba(255, 255, 255, 0.6);
286
+ line-height: 1.4;
287
+ margin-bottom: 4px;
288
+ }
289
+
290
+ .review-panel-comment-time {
291
+ font-size: 11px;
292
+ color: rgba(255, 255, 255, 0.3);
293
+ }
294
+
295
+ .review-panel-empty {
296
+ text-align: center;
297
+ padding: 24px 16px;
298
+ color: rgba(255, 255, 255, 0.3);
299
+ font-size: 13px;
300
+ }
301
+
302
+ .review-panel-loading {
303
+ text-align: center;
304
+ padding: 24px 16px;
305
+ color: rgba(255, 255, 255, 0.4);
306
+ font-size: 13px;
307
+ }
308
+
73
309
  /* \u2500\u2500\u2500 Comment Card \u2500\u2500\u2500 */
74
310
  .review-comment-card {
75
311
  position: fixed;
@@ -250,6 +486,81 @@
250
486
  backdrop-filter: blur(8px);
251
487
  }
252
488
 
489
+ /* \u2500\u2500\u2500 Name Entry Overlay \u2500\u2500\u2500 */
490
+ .review-name-overlay {
491
+ position: fixed;
492
+ inset: 0;
493
+ background: rgba(0, 0, 0, 0.4);
494
+ display: flex;
495
+ align-items: center;
496
+ justify-content: center;
497
+ z-index: 10003;
498
+ backdrop-filter: blur(2px);
499
+ }
500
+
501
+ .review-name-card {
502
+ background: #fff;
503
+ border-radius: 12px;
504
+ padding: 28px 32px;
505
+ font-family: system-ui, -apple-system, sans-serif;
506
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2);
507
+ max-width: 360px;
508
+ width: 90%;
509
+ border: 1px solid rgba(0, 0, 0, 0.06);
510
+ }
511
+
512
+ .review-name-card h3 {
513
+ margin: 0 0 4px;
514
+ font-size: 17px;
515
+ font-weight: 600;
516
+ color: #111;
517
+ }
518
+
519
+ .review-name-card p {
520
+ margin: 0 0 20px;
521
+ font-size: 14px;
522
+ color: #666;
523
+ }
524
+
525
+ .review-name-card label {
526
+ display: block;
527
+ font-size: 13px;
528
+ font-weight: 500;
529
+ color: #374151;
530
+ margin-bottom: 6px;
531
+ }
532
+
533
+ .review-name-card input {
534
+ width: 100%;
535
+ border: 1px solid #d1d5db;
536
+ border-radius: 8px;
537
+ padding: 10px 12px;
538
+ font-family: inherit;
539
+ font-size: 14px;
540
+ color: #1f2937;
541
+ background: #fafafa;
542
+ box-sizing: border-box;
543
+ outline: none;
544
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
545
+ }
546
+
547
+ .review-name-card input:focus {
548
+ border-color: #7c3aed;
549
+ box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.15);
550
+ background: #fff;
551
+ }
552
+
553
+ .review-name-card input::placeholder {
554
+ color: #9ca3af;
555
+ }
556
+
557
+ .review-name-actions {
558
+ display: flex;
559
+ justify-content: flex-end;
560
+ gap: 8px;
561
+ margin-top: 20px;
562
+ }
563
+
253
564
  /* \u2500\u2500\u2500 Reduced Motion \u2500\u2500\u2500 */
254
565
  @media (prefers-reduced-motion: reduce) {
255
566
  *, *::before, *::after {
@@ -257,7 +568,7 @@
257
568
  transition-duration: 0.01ms !important;
258
569
  }
259
570
  }
260
- `,U=`
571
+ `,B=`
261
572
  body {
262
573
  position: relative !important;
263
574
  }
@@ -314,25 +625,73 @@ body {
314
625
  transition-duration: 0.01ms !important;
315
626
  }
316
627
  }
317
- `;var k="roadmaps-review-pin-styles",u=class{constructor(){r(this,"container");r(this,"pins",new Map);r(this,"styleEl",null);this.container=document.createElement("div"),this.container.className="pin-container"}mount(){document.getElementById(k)||(this.styleEl=document.createElement("style"),this.styleEl.id=k,this.styleEl.textContent=U,document.head.appendChild(this.styleEl)),document.body.appendChild(this.container)}addPin(e,t,i,o,s){let a=this.pins.get(e);a&&(a.el.remove(),this.pins.delete(e));let l=document.createElement("div");l.className=o?"review-pin":"review-pin review-pin--other",l.textContent=String(e),l.style.left=`${t}%`,l.style.top=`${i}%`,l.dataset.pinNumber=String(e),l.dataset.pageUrl=s,this.container.appendChild(l),this.pins.set(e,{el:l,pageUrl:s})}removePin(e){let t=this.pins.get(e);t&&(t.el.remove(),this.pins.delete(e))}highlightPin(e){for(let[t,{el:i}]of this.pins)i.classList.toggle("review-pin--highlighted",t===e)}clearHighlight(){for(let{el:e}of this.pins.values())e.classList.remove("review-pin--highlighted")}filterByPage(e){for(let{el:t,pageUrl:i}of this.pins.values())t.style.display=i===e?"":"none"}showAll(){for(let{el:e}of this.pins.values())e.style.display=""}countForPage(e){let t=0;for(let{pageUrl:i}of this.pins.values())i===e&&t++;return t}destroy(){this.container.remove(),this.pins.clear(),this.styleEl?(this.styleEl.remove(),this.styleEl=null):document.getElementById(k)?.remove()}};var x=class{constructor(e){this.shadowRoot=e;r(this,"card",null);r(this,"onSubmit",null);r(this,"onCancel",null)}show(e){this.hide(),this.onSubmit=e.onSubmit,this.onCancel=e.onCancel,this.card=document.createElement("div"),this.card.className="review-comment-card",this.card.style.left=`${Math.min(e.x,window.innerWidth-320)}px`,this.card.style.top=`${Math.min(e.y+20,window.innerHeight-200)}px`,this.card.innerHTML=`
628
+ `;var N="roadmaps-review-pin-styles",u=class{constructor(){s(this,"container");s(this,"pins",new Map);s(this,"styleEl",null);this.container=document.createElement("div"),this.container.className="pin-container"}mount(){document.getElementById(N)||(this.styleEl=document.createElement("style"),this.styleEl.id=N,this.styleEl.textContent=B,document.head.appendChild(this.styleEl)),document.body.appendChild(this.container)}addPin(e,t,i,n,r){let a=this.pins.get(e);a&&(a.el.remove(),this.pins.delete(e));let l=document.createElement("div");l.className=n?"review-pin":"review-pin review-pin--other",l.textContent=String(e),l.style.left=`${t}%`,l.style.top=`${i}%`,l.dataset.pinNumber=String(e),l.dataset.pageUrl=r,this.container.appendChild(l),this.pins.set(e,{el:l,pageUrl:r})}removePin(e){let t=this.pins.get(e);t&&(t.el.remove(),this.pins.delete(e))}highlightPin(e){for(let[t,{el:i}]of this.pins)i.classList.toggle("review-pin--highlighted",t===e)}clearHighlight(){for(let{el:e}of this.pins.values())e.classList.remove("review-pin--highlighted")}filterByPage(e){for(let{el:t,pageUrl:i}of this.pins.values())t.style.display=i===e?"":"none"}showAll(){for(let{el:e}of this.pins.values())e.style.display=""}countForPage(e){let t=0;for(let{pageUrl:i}of this.pins.values())i===e&&t++;return t}destroy(){this.container.remove(),this.pins.clear(),this.styleEl?(this.styleEl.remove(),this.styleEl=null):document.getElementById(N)?.remove()}};var y=class{constructor(e){this.shadowRoot=e;s(this,"card",null);s(this,"onSubmit",null);s(this,"onCancel",null)}show(e){this.hide(),this.onSubmit=e.onSubmit,this.onCancel=e.onCancel,this.card=document.createElement("div"),this.card.className="review-comment-card",this.card.style.left=`${Math.min(e.x,window.innerWidth-320)}px`,this.card.style.top=`${Math.min(e.y+20,window.innerHeight-200)}px`,this.card.innerHTML=`
318
629
  <textarea class="review-comment-input" placeholder="Leave your feedback..." rows="3"></textarea>
319
630
  <div class="review-comment-actions">
320
631
  <button class="review-btn review-btn--cancel">Cancel</button>
321
632
  <button class="review-btn review-btn--submit">Submit</button>
322
633
  </div>
323
634
  <div class="review-comment-error" style="display:none"></div>
324
- `,this.attachListeners(),this.shadowRoot.appendChild(this.card),this.card.querySelector("textarea")?.focus()}hide(){this.card?.remove(),this.card=null}showForGeneral(e){this.show({x:window.innerWidth/2-150,y:window.innerHeight/2-100,onSubmit:e.onSubmit,onCancel:e.onCancel})}attachListeners(){this.card&&(this.card.querySelector(".review-btn--cancel")?.addEventListener("click",()=>{this.onCancel?.(),this.hide()}),this.card.querySelector(".review-btn--submit")?.addEventListener("click",()=>this.handleSubmit()),this.card.querySelector("textarea")?.addEventListener("keydown",e=>{(e.metaKey||e.ctrlKey)&&e.key==="Enter"&&(e.preventDefault(),this.handleSubmit())}))}async handleSubmit(){if(!this.card)return;let e=this.card.querySelector("textarea"),t=e.value.trim();if(!t)return;let i=this.card.querySelector(".review-btn--submit"),o=this.card.querySelector(".review-comment-error");i.disabled=!0,i.textContent="Submitting...",e.disabled=!0,o.style.display="none";try{await this.onSubmit?.(t),this.hide()}catch(s){i.disabled=!1,i.textContent="Submit",e.disabled=!1,o.textContent=s instanceof Error?s.message:"Failed to submit",o.style.display="block"}}};function c(){return window.location.pathname+window.location.search+window.location.hash}var g=class{constructor(e){this.onChange=e;r(this,"popstateHandler",null);r(this,"hashchangeHandler",null);r(this,"originalPushState",null);r(this,"originalReplaceState",null);r(this,"lastPageId");this.lastPageId=c()}start(){if(this.originalPushState)return;let e=()=>{let t=c();t!==this.lastPageId&&(this.lastPageId=t,this.onChange(t))};this.popstateHandler=e,window.addEventListener("popstate",this.popstateHandler),this.hashchangeHandler=e,window.addEventListener("hashchange",this.hashchangeHandler),this.originalPushState=history.pushState.bind(history),this.originalReplaceState=history.replaceState.bind(history),history.pushState=(...t)=>{this.originalPushState(...t),e()},history.replaceState=(...t)=>{this.originalReplaceState(...t),e()}}destroy(){this.popstateHandler&&window.removeEventListener("popstate",this.popstateHandler),this.hashchangeHandler&&window.removeEventListener("hashchange",this.hashchangeHandler),this.originalPushState&&(history.pushState=this.originalPushState),this.originalReplaceState&&(history.replaceState=this.originalReplaceState)}};var y=class{constructor(e,t,i){this.token=e;this.shadowRoot=t;this.initData=i;r(this,"pinManager");r(this,"commentCard");r(this,"nextPinNumber");r(this,"pendingPinNumber",null);r(this,"promptEl",null);r(this,"toolbarEl",null);r(this,"clickHandler",null);r(this,"pageListener",null);this.pinManager=new u,this.commentCard=new x(t),this.nextPinNumber=i.nextPinNumber}async init(){document.body.style.cursor="crosshair",this.pinManager.mount(),this.showPrompt(),this.renderToolbar(),await this.loadExistingPins(),this.pinManager.filterByPage(c()),this.pageListener=new g(e=>{this.pinManager.filterByPage(e)}),this.pageListener.start(),this.clickHandler=e=>this.handleClick(e),document.addEventListener("click",this.clickHandler,!0)}showPrompt(){this.promptEl=document.createElement("div"),this.promptEl.className="review-prompt",this.promptEl.innerHTML=`
635
+ `,this.attachListeners(),this.shadowRoot.appendChild(this.card),this.card.querySelector("textarea")?.focus()}hide(){this.card?.remove(),this.card=null}showForGeneral(e){this.show({x:window.innerWidth/2-150,y:window.innerHeight/2-100,onSubmit:e.onSubmit,onCancel:e.onCancel})}attachListeners(){this.card&&(this.card.querySelector(".review-btn--cancel")?.addEventListener("click",()=>{this.onCancel?.(),this.hide()}),this.card.querySelector(".review-btn--submit")?.addEventListener("click",()=>this.handleSubmit()),this.card.querySelector("textarea")?.addEventListener("keydown",e=>{(e.metaKey||e.ctrlKey)&&e.key==="Enter"&&(e.preventDefault(),this.handleSubmit())}))}async handleSubmit(){if(!this.card)return;let e=this.card.querySelector("textarea"),t=e.value.trim();if(!t)return;let i=this.card.querySelector(".review-btn--submit"),n=this.card.querySelector(".review-comment-error");i.disabled=!0,i.textContent="Submitting...",e.disabled=!0,n.style.display="none";try{await this.onSubmit?.(t),this.hide()}catch(r){i.disabled=!1,i.textContent="Submit",e.disabled=!1,n.textContent=r instanceof Error?r.message:"Failed to submit",n.style.display="block"}}};function c(){return window.location.pathname+window.location.search+window.location.hash}var v=class{constructor(e){this.onChange=e;s(this,"popstateHandler",null);s(this,"hashchangeHandler",null);s(this,"originalPushState",null);s(this,"originalReplaceState",null);s(this,"lastPageId");this.lastPageId=c()}start(){if(this.originalPushState)return;let e=()=>{let t=c();t!==this.lastPageId&&(this.lastPageId=t,this.onChange(t))};this.popstateHandler=e,window.addEventListener("popstate",this.popstateHandler),this.hashchangeHandler=e,window.addEventListener("hashchange",this.hashchangeHandler),this.originalPushState=history.pushState.bind(history),this.originalReplaceState=history.replaceState.bind(history),history.pushState=(...t)=>{this.originalPushState(...t),e()},history.replaceState=(...t)=>{this.originalReplaceState(...t),e()}}destroy(){this.popstateHandler&&window.removeEventListener("popstate",this.popstateHandler),this.hashchangeHandler&&window.removeEventListener("hashchange",this.hashchangeHandler),this.originalPushState&&(history.pushState=this.originalPushState),this.originalReplaceState&&(history.replaceState=this.originalReplaceState)}};var E=class{constructor(e,t,i){this.token=e;this.shadowRoot=t;this.pinManager=i;s(this,"panelEl");s(this,"bodyEl",null);s(this,"isOpen",!1);s(this,"allPagesExpanded",!1);s(this,"comments",[]);this.panelEl=document.createElement("div"),this.panelEl.className="review-panel",this.panelEl.innerHTML=`
636
+ <div class="review-panel-header">
637
+ <h3>Comments</h3>
638
+ <button class="review-panel-close" title="Close">
639
+ <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>
640
+ </button>
641
+ </div>
642
+ <div class="review-panel-body"></div>
643
+ `,this.bodyEl=this.panelEl.querySelector(".review-panel-body"),this.panelEl.querySelector(".review-panel-close")?.addEventListener("click",()=>this.close()),this.shadowRoot.appendChild(this.panelEl)}async toggle(){this.isOpen?this.close():await this.open()}async open(){this.isOpen=!0,this.panelEl.classList.add("review-panel--open"),await this.refresh()}close(){this.isOpen=!1,this.panelEl.classList.remove("review-panel--open"),this.pinManager.clearHighlight()}async refresh(){if(!(!this.isOpen||!this.bodyEl)){this.bodyEl.innerHTML='<div class="review-panel-loading">Loading comments...</div>';try{this.comments=await g(this.token),this.render()}catch{this.bodyEl.innerHTML='<div class="review-panel-empty">Failed to load comments</div>'}}}render(){if(!this.bodyEl)return;let e=this.comments.filter(a=>a.commentText);if(e.length===0){this.bodyEl.innerHTML='<div class="review-panel-empty">No comments yet</div>';return}let t=c(),i=e.filter(a=>a.pageUrl===t),n=e.filter(a=>a.pageUrl!==t),r="";if(r+='<div class="review-panel-section">',r+='<div class="review-panel-section-header">This Page</div>',i.length===0?r+='<div class="review-panel-empty" style="padding:8px 0;">No comments on this page</div>':r+=this.renderComments(i),r+="</div>",n.length>0){let a=this.groupByPage(n);if(r+='<div class="review-panel-section">',r+=`<button class="review-panel-section-toggle ${this.allPagesExpanded?"review-panel-section-toggle--expanded":""}" data-action="toggle-all">
644
+ <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>
645
+ All Pages (${n.length} comment${n.length!==1?"s":""})
646
+ </button>`,this.allPagesExpanded){r+='<div class="review-panel-all-pages">';for(let l of a)r+=`<div class="review-panel-page-label">${this.escapeHtml(this.formatPageUrl(l.pageUrl))}</div>`,r+=this.renderComments(l.comments);r+="</div>"}r+="</div>"}this.bodyEl.innerHTML=r,this.attachEventListeners()}renderComments(e){return e.map(t=>{let i=t.pinNumber!=null?`<span class="review-panel-pin-badge">${t.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>',n=t.reviewerName||"Anonymous",r=t.commentText||"",a=this.formatTime(t.createdAt),l=t.pinNumber!=null?`data-pin="${t.pinNumber}"`:"",p=t.pageUrl?`data-page="${this.escapeAttr(t.pageUrl)}"`:"";return`<div class="review-panel-comment" ${l} ${p}>
647
+ <div class="review-panel-comment-header">
648
+ ${i}
649
+ <span class="review-panel-comment-author">${this.escapeHtml(n)}</span>
650
+ </div>
651
+ <div class="review-panel-comment-text">${this.escapeHtml(r)}</div>
652
+ <div class="review-panel-comment-time">${a}</div>
653
+ </div>`}).join("")}attachEventListeners(){this.bodyEl&&(this.bodyEl.querySelector('[data-action="toggle-all"]')?.addEventListener("click",()=>{this.allPagesExpanded=!this.allPagesExpanded,this.render()}),this.bodyEl.querySelectorAll(".review-panel-comment[data-pin]").forEach(e=>{e.addEventListener("click",()=>{let t=Number(e.dataset.pin);t&&this.pinManager.highlightPin(t)})}))}groupByPage(e){let t=new Map;for(let i of e){let n=i.pageUrl||"(unknown)",r=t.get(n)||[];r.push(i),t.set(n,r)}return Array.from(t.entries()).map(([i,n])=>({pageUrl:i,comments:n}))}formatPageUrl(e){try{let t=new URL(e,"https://placeholder");return t.pathname+t.search+t.hash}catch{return e||"/"}}formatTime(e){let t=new Date(e);if(Number.isNaN(t.getTime()))return"";let i=Date.now(),n=Math.max(0,i-t.getTime()),r=Math.floor(n/6e4);if(r<1)return"just now";if(r<60)return`${r}m ago`;let a=Math.floor(r/60);return a<24?`${a}h ago`:`${Math.floor(a/24)}d ago`}escapeHtml(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}escapeAttr(e){return e.replace(/"/g,"&quot;").replace(/'/g,"&#39;")}destroy(){this.panelEl.remove()}};var P=class{constructor(e,t,i){this.token=e;this.shadowRoot=t;this.initData=i;s(this,"pinManager");s(this,"commentCard");s(this,"nextPinNumber");s(this,"pendingPinNumber",null);s(this,"promptEl",null);s(this,"toolbarEl",null);s(this,"clickHandler",null);s(this,"pageListener",null);s(this,"mode","comment");s(this,"keydownHandler",null);s(this,"commentPanel",null);this.pinManager=new u,this.commentCard=new y(t),this.nextPinNumber=i.nextPinNumber}async init(){this.initData.reviewer.name||await this.showNameEntry(),document.body.style.cursor="crosshair",this.pinManager.mount(),this.showPrompt(),this.renderToolbar(),this.commentPanel=new E(this.token,this.shadowRoot,this.pinManager),await this.loadExistingPins(),this.pinManager.filterByPage(c()),this.pageListener=new v(e=>{this.pinManager.filterByPage(e)}),this.pageListener.start(),this.clickHandler=e=>this.handleClick(e),document.addEventListener("click",this.clickHandler,!0),this.keydownHandler=e=>{let t=e.target?.tagName;t==="INPUT"||t==="TEXTAREA"||t==="SELECT"||e.target?.isContentEditable||e.key==="c"&&!e.ctrlKey&&!e.metaKey&&!e.altKey&&this.setMode(this.mode==="comment"?"navigate":"comment")},document.addEventListener("keydown",this.keydownHandler)}showPrompt(){this.promptEl=document.createElement("div"),this.promptEl.className="review-prompt",this.promptEl.innerHTML=`
325
654
  <h3 style="margin:0 0 8px;font-size:16px;">Click anywhere to leave feedback</h3>
326
655
  <p style="margin:0;color:#666;font-size:14px;">Drop numbered pins on elements you want to comment on</p>
327
- `,this.shadowRoot.appendChild(this.promptEl),setTimeout(()=>this.dismissPrompt(),5e3)}dismissPrompt(){this.promptEl&&(this.promptEl.remove(),this.promptEl=null)}renderToolbar(){this.toolbarEl=document.createElement("div"),this.toolbarEl.className="review-toolbar",this.updateToolbar(),this.shadowRoot.appendChild(this.toolbarEl)}updateToolbar(){if(!this.toolbarEl)return;let e=this.nextPinNumber-1;this.toolbarEl.innerHTML=`
656
+ `,this.shadowRoot.appendChild(this.promptEl),setTimeout(()=>this.dismissPrompt(),5e3)}dismissPrompt(){this.promptEl&&(this.promptEl.remove(),this.promptEl=null)}showNameEntry(){return new Promise(e=>{let t=document.createElement("div");t.className="review-name-overlay",t.innerHTML=`
657
+ <div class="review-name-card">
658
+ <h3>Welcome to the review</h3>
659
+ <p>Optionally enter your name so the team knows who left the feedback.</p>
660
+ <div style="margin-bottom:12px;">
661
+ <label>Name</label>
662
+ <input type="text" class="review-name-input" placeholder="Your name (optional)" />
663
+ </div>
664
+ <div>
665
+ <label>Email</label>
666
+ <input type="email" class="review-email-input" placeholder="Your email (optional)" />
667
+ </div>
668
+ <div class="review-name-actions">
669
+ <button class="review-btn review-btn--cancel review-name-skip">Skip</button>
670
+ <button class="review-btn review-btn--submit review-name-continue">Continue</button>
671
+ </div>
672
+ </div>
673
+ `,this.shadowRoot.appendChild(t);let i=t.querySelector(".review-name-input"),n=t.querySelector(".review-email-input"),r=t.querySelector(".review-name-skip"),a=t.querySelector(".review-name-continue"),l=async()=>{let p=i.value.trim()||void 0,d=n.value.trim()||void 0;try{await S(this.token,p,d)}catch{}t.remove(),e()};r.addEventListener("click",()=>{S(this.token).catch(()=>{}),t.remove(),e()}),a.addEventListener("click",l),i.addEventListener("keydown",p=>{p.key==="Enter"&&l()}),n.addEventListener("keydown",p=>{p.key==="Enter"&&l()}),i.focus()})}renderToolbar(){this.toolbarEl=document.createElement("div"),this.toolbarEl.className="review-toolbar",this.updateToolbar(),this.shadowRoot.appendChild(this.toolbarEl)}updateToolbar(){if(!this.toolbarEl)return;let e=this.nextPinNumber-1,t=this.mode==="navigate",i=this.mode==="comment";this.toolbarEl.innerHTML=`
674
+ <div class="review-mode-toggle">
675
+ <button class="review-mode-btn ${t?"review-mode-btn--active":""}" data-mode="navigate">
676
+ <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>
677
+ Navigate
678
+ </button>
679
+ <button class="review-mode-btn ${i?"review-mode-btn--active":""}" data-mode="comment">
680
+ <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>
681
+ Comment
682
+ </button>
683
+ </div>
328
684
  <span style="font-weight:500;">${this.initData.session.name}</span>
329
685
  <span style="opacity:0.7;">${e} pin${e!==1?"s":""}</span>
330
- <button class="review-btn review-btn--submit" style="margin-left:auto;padding:6px 12px;font-size:13px;">General Comment</button>
331
- `,this.toolbarEl.querySelector("button")?.addEventListener("click",t=>{t.stopPropagation(),this.handleGeneralComment()})}async loadExistingPins(){try{let e=await w(this.token);for(let t of e)if(t.pinNumber!=null&&t.pinData){let i=t.commentText!=null;this.pinManager.addPin(t.pinNumber,t.pinData.pinX,t.pinData.pinY,i,t.pageUrl??"")}}catch{}}handleClick(e){if(e.composedPath().some(s=>s instanceof HTMLElement&&s.closest?.("#ourroadmaps-review"))||this.pendingPinNumber!=null)return;this.dismissPrompt();let i=z(e.clientX,e.clientY),o=this.nextPinNumber;this.pinManager.addPin(o,i.pinX,i.pinY,!0,c()),this.pendingPinNumber=o,this.commentCard.show({x:e.clientX,y:e.clientY,onSubmit:async s=>{await M(this.token,{commentText:s,pinNumber:o,pinData:i,pageUrl:c()}),this.pendingPinNumber=null,this.nextPinNumber++,this.updateToolbar(),this.showToast("Comment saved")},onCancel:()=>{this.pinManager.removePin(o),this.pendingPinNumber=null}}),e.preventDefault(),e.stopPropagation()}handleGeneralComment(){this.pendingPinNumber==null&&this.commentCard.showForGeneral({onSubmit:async e=>{await M(this.token,{commentText:e,pinNumber:null,pinData:null,pageUrl:c()}),this.showToast("Comment saved")},onCancel:()=>{}})}showToast(e){let t=document.createElement("div");t.className="review-toast",t.textContent=e,this.shadowRoot.appendChild(t),setTimeout(()=>t.remove(),2500)}destroy(){document.body.style.cursor="",this.clickHandler&&document.removeEventListener("click",this.clickHandler,!0),this.pageListener?.destroy(),this.dismissPrompt(),this.toolbarEl?.remove(),this.commentCard.hide(),this.pinManager.destroy()}};var N="ourroadmaps:token";function H(n,e){try{sessionStorage.setItem(N,JSON.stringify({type:n,token:e}))}catch{}}function A(){try{let n=sessionStorage.getItem(N);if(!n)return null;let e=JSON.parse(n);return e&&typeof e.type=="string"&&typeof e.token=="string"?e:null}catch{return null}}function R(){try{sessionStorage.removeItem(N)}catch{}}var E=class{constructor(e,t){this.token=e;this.shadowRoot=t;r(this,"pinManager");r(this,"toolbarEl",null);r(this,"tooltipEl",null);r(this,"comments",[]);r(this,"pinClickHandler",null);r(this,"pageListener",null);r(this,"showAllPages",!1);this.pinManager=new u}async init(){this.pinManager.mount();try{this.comments=await w(this.token);for(let e of this.comments)e.pinNumber!=null&&e.pinData&&this.pinManager.addPin(e.pinNumber,e.pinData.pinX,e.pinData.pinY,!0,e.pageUrl??"")}catch{}this.pinManager.filterByPage(c()),this.renderToolbar(),this.pageListener=new g(e=>{this.showAllPages||this.pinManager.filterByPage(e),this.updateToolbar()}),this.pageListener.start(),this.pinClickHandler=e=>{let t=e.target;if(t.classList?.contains("review-pin")){let i=Number(t.dataset.pinNumber);i&&this.handlePinClick(i,e)}},document.addEventListener("click",this.pinClickHandler,!0),this.autoFocusPin()}renderToolbar(){this.toolbarEl=document.createElement("div"),this.toolbarEl.className="review-toolbar",this.updateToolbar(),this.shadowRoot.appendChild(this.toolbarEl)}updateToolbar(){if(!this.toolbarEl)return;let e=this.comments.filter(p=>p.pinNumber!=null).length,t=c(),i=this.pinManager.countForPage(t),o=new URL(t,window.location.origin),s=o.hash?`${o.pathname}${o.hash.split("?")[0]}`:o.pathname||"/";this.toolbarEl.innerHTML="";let a=document.createElement("span");a.style.fontWeight="500",a.textContent="Triage Mode",this.toolbarEl.appendChild(a);let l=document.createElement("span");l.style.opacity="0.7",this.showAllPages?l.textContent=`${e} pin${e!==1?"s":""}`:l.textContent=`${i} pin${i!==1?"s":""} on ${s} (${e} total)`,this.toolbarEl.appendChild(l);let h=document.createElement("button");h.className="review-btn review-btn--submit",h.style.cssText="margin-left:auto;padding:6px 12px;font-size:13px;",h.textContent=this.showAllPages?"This page":"All pages",h.addEventListener("click",p=>{p.stopPropagation(),this.togglePageFilter()}),this.toolbarEl.appendChild(h)}togglePageFilter(){this.showAllPages=!this.showAllPages,this.showAllPages?this.pinManager.showAll():this.pinManager.filterByPage(c()),this.updateToolbar()}handlePinClick(e,t){this.hideTooltip(),this.pinManager.highlightPin(e),this.showTooltipForPin(e,t.clientX+16,t.clientY-10)}showTooltipForPin(e,t,i){this.hideTooltip();let o=this.comments.find(d=>d.pinNumber===e);if(!o)return;this.tooltipEl=document.createElement("div"),this.tooltipEl.className="review-tooltip";let s=new Date(o.createdAt).toLocaleString(),a=document.createElement("div");if(a.style.cssText="font-weight:500;margin-bottom:4px;",a.textContent=`Pin #${e}`,this.tooltipEl.appendChild(a),o.reviewerName){let d=document.createElement("div");d.style.cssText="font-size:11px;opacity:0.7;margin-bottom:2px;",d.textContent=o.reviewerName,this.tooltipEl.appendChild(d)}let l=document.createElement("div");l.style.cssText="margin-bottom:4px;",l.textContent=o.commentText||"(no text)",this.tooltipEl.appendChild(l);let h=document.createElement("div");h.style.cssText="font-size:11px;opacity:0.7;",h.textContent=s,this.tooltipEl.appendChild(h);let p=o.pageUrl??"";if(p&&p!==c()){let d=document.createElement("div");d.style.cssText="margin-top:6px;padding-top:6px;border-top:1px solid rgba(255,255,255,0.2);font-size:12px;";let C=document.createElement("span");C.style.opacity="0.7",C.textContent=`Page: ${p.split("?")[0].split("#")[0]||"/"} \u2014 `,d.appendChild(C);let f=document.createElement("a");f.style.cssText="color:#a78bfa;cursor:pointer;text-decoration:underline;pointer-events:auto;",f.textContent="Navigate there?",f.addEventListener("click",O=>{O.stopPropagation(),this.navigateToPin(p,e)}),d.appendChild(f),this.tooltipEl.appendChild(d),this.tooltipEl.style.pointerEvents="auto"}let T=t??window.innerWidth/2,Y=i??window.innerHeight/3;this.tooltipEl.style.position="fixed",this.tooltipEl.style.left=`${Math.min(T,window.innerWidth-300)}px`,this.tooltipEl.style.top=`${Math.min(Y,window.innerHeight-150)}px`,this.shadowRoot.appendChild(this.tooltipEl);let $=d=>{d.target!==this.tooltipEl&&!this.tooltipEl?.contains(d.target)&&(this.hideTooltip(),this.pinManager.clearHighlight(),document.removeEventListener("click",$,!0))};setTimeout(()=>document.addEventListener("click",$,!0),0)}navigateToPin(e,t){this.hideTooltip(),this.pinManager.clearHighlight();let i=new URL(e,window.location.origin);i.searchParams.set("pin",String(t)),window.location.href=i.toString()}autoFocusPin(){let t=new URLSearchParams(window.location.search).get("pin");if(!t)return;let i=Number(t);if(!i)return;let o=this.comments.find(p=>p.pinNumber===i);if(!o?.pinData)return;let s=o.pageUrl??"";if(s){let p=new URL(window.location.href);p.searchParams.delete("pin");let T=p.pathname+p.search+p.hash;if(s!==T){this.navigateToPin(s,i);return}}this.pinManager.showAll(),this.showAllPages=!0,this.updateToolbar();let a=document.documentElement,l=o.pinData.pinX/100*a.scrollWidth,h=o.pinData.pinY/100*a.scrollHeight;window.scrollTo({left:l-window.innerWidth/2,top:h-window.innerHeight/2,behavior:"smooth"}),setTimeout(()=>{this.pinManager.highlightPin(i),this.showTooltipForPin(i)},500)}hideTooltip(){this.tooltipEl?.remove(),this.tooltipEl=null}destroy(){this.pinClickHandler&&document.removeEventListener("click",this.pinClickHandler,!0),this.pageListener?.destroy(),this.hideTooltip(),this.toolbarEl?.remove(),this.pinManager.destroy()}};var P=class{constructor(e={}){r(this,"root");r(this,"shadow");r(this,"mode",null);r(this,"_isDestroyed",!1);this.root=document.createElement("div"),this.root.id="ourroadmaps-review",this.shadow=this.root.attachShadow({mode:"open"});let t=document.createElement("style");t.textContent=I,this.shadow.appendChild(t),document.body.appendChild(this.root)}async init(e,t){if(!e||!t){let i=new URLSearchParams(window.location.search),o=i.get("review"),s=i.get("triage");if(o){e="review",t=o,H("review",o);let a=new URL(window.location.href);a.searchParams.delete("review"),history.replaceState(null,"",a.toString())}else if(s){e="triage",t=s,H("triage",s);let a=new URL(window.location.href);a.searchParams.delete("triage"),history.replaceState(null,"",a.toString())}else{let a=A();if(a)e=a.type,t=a.token;else return}}if(e==="review")try{let i=await L(t);this.mode=new y(t,this.shadow,i),await this.mode.init()}catch(i){i instanceof m&&(R(),this.showErrorOverlay(i.code==="expired"?"This feedback session has expired":"This review link is no longer valid"))}else if(e==="triage")try{await L(t),this.mode=new E(t,this.shadow),await this.mode.init()}catch(i){i instanceof m&&(R(),this.showErrorOverlay(i.code==="expired"?"This feedback session has expired":"This review link is no longer valid"))}}showErrorOverlay(e){let t=document.createElement("div");t.className="review-expired-overlay",t.innerHTML=`
686
+ <button class="review-btn review-btn--submit" data-action="general" style="margin-left:auto;padding:6px 12px;font-size:13px;">General Comment</button>
687
+ <button class="review-mode-btn" data-action="panel" title="View all comments" style="padding:5px 8px;">
688
+ <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>
689
+ </button>
690
+ `,this.toolbarEl.querySelectorAll("[data-mode]").forEach(n=>{n.addEventListener("click",r=>{r.stopPropagation();let a=n.dataset.mode;this.setMode(a)})}),this.toolbarEl.querySelector('[data-action="general"]')?.addEventListener("click",n=>{n.stopPropagation(),this.handleGeneralComment()}),this.toolbarEl.querySelector('[data-action="panel"]')?.addEventListener("click",n=>{n.stopPropagation(),this.toggleCommentPanel()})}async loadExistingPins(){try{let e=await g(this.token);for(let t of e)if(t.pinNumber!=null&&t.pinData){let i=t.commentText!=null;this.pinManager.addPin(t.pinNumber,t.pinData.pinX,t.pinData.pinY,i,t.pageUrl??"")}}catch{}}handleClick(e){if(this.mode==="navigate"||e.composedPath().some(r=>r instanceof HTMLElement&&r.closest?.("#ourroadmaps-review"))||this.pendingPinNumber!=null)return;this.dismissPrompt();let i=I(e.clientX,e.clientY),n=this.nextPinNumber;this.pinManager.addPin(n,i.pinX,i.pinY,!0,c()),this.pendingPinNumber=n,this.commentCard.show({x:e.clientX,y:e.clientY,onSubmit:async r=>{await H(this.token,{commentText:r,pinNumber:n,pinData:i,pageUrl:c()}),this.pendingPinNumber=null,this.nextPinNumber++,this.updateToolbar(),this.showToast("Comment saved"),this.commentPanel?.refresh()},onCancel:()=>{this.pinManager.removePin(n),this.pendingPinNumber=null}}),e.preventDefault(),e.stopPropagation()}setMode(e){this.mode=e,document.body.style.cursor=e==="comment"?"crosshair":"",this.updateToolbar()}toggleCommentPanel(){this.commentPanel?.toggle()}handleGeneralComment(){this.pendingPinNumber==null&&this.commentCard.showForGeneral({onSubmit:async e=>{await H(this.token,{commentText:e,pinNumber:null,pinData:null,pageUrl:c()}),this.showToast("Comment saved"),this.commentPanel?.refresh()},onCancel:()=>{}})}showToast(e){let t=document.createElement("div");t.className="review-toast",t.textContent=e,this.shadowRoot.appendChild(t),setTimeout(()=>t.remove(),2500)}destroy(){document.body.style.cursor="",this.clickHandler&&document.removeEventListener("click",this.clickHandler,!0),this.pageListener?.destroy(),this.keydownHandler&&document.removeEventListener("keydown",this.keydownHandler),this.dismissPrompt(),this.toolbarEl?.remove(),this.commentCard.hide(),this.commentPanel?.destroy(),this.pinManager.destroy()}};var R="ourroadmaps:token";function $(o,e){try{sessionStorage.setItem(R,JSON.stringify({type:o,token:e}))}catch{}}function j(){try{let o=sessionStorage.getItem(R);if(!o)return null;let e=JSON.parse(o);return e&&typeof e.type=="string"&&typeof e.token=="string"?e:null}catch{return null}}function z(){try{sessionStorage.removeItem(R)}catch{}}var k=class{constructor(e,t){this.token=e;this.shadowRoot=t;s(this,"pinManager");s(this,"toolbarEl",null);s(this,"tooltipEl",null);s(this,"comments",[]);s(this,"pinClickHandler",null);s(this,"pageListener",null);s(this,"showAllPages",!1);this.pinManager=new u}async init(){this.pinManager.mount();try{this.comments=await g(this.token);for(let e of this.comments)e.pinNumber!=null&&e.pinData&&this.pinManager.addPin(e.pinNumber,e.pinData.pinX,e.pinData.pinY,!0,e.pageUrl??"")}catch{}this.pinManager.filterByPage(c()),this.renderToolbar(),this.pageListener=new v(e=>{this.showAllPages||this.pinManager.filterByPage(e),this.updateToolbar()}),this.pageListener.start(),this.pinClickHandler=e=>{let t=e.target;if(t.classList?.contains("review-pin")){let i=Number(t.dataset.pinNumber);i&&this.handlePinClick(i,e)}},document.addEventListener("click",this.pinClickHandler,!0),this.autoFocusPin()}renderToolbar(){this.toolbarEl=document.createElement("div"),this.toolbarEl.className="review-toolbar",this.updateToolbar(),this.shadowRoot.appendChild(this.toolbarEl)}updateToolbar(){if(!this.toolbarEl)return;let e=this.comments.filter(d=>d.pinNumber!=null).length,t=c(),i=this.pinManager.countForPage(t),n=new URL(t,window.location.origin),r=n.hash?`${n.pathname}${n.hash.split("?")[0]}`:n.pathname||"/";this.toolbarEl.innerHTML="";let a=document.createElement("span");a.style.fontWeight="500",a.textContent="Triage Mode",this.toolbarEl.appendChild(a);let l=document.createElement("span");l.style.opacity="0.7",this.showAllPages?l.textContent=`${e} pin${e!==1?"s":""}`:l.textContent=`${i} pin${i!==1?"s":""} on ${r} (${e} total)`,this.toolbarEl.appendChild(l);let p=document.createElement("button");p.className="review-btn review-btn--submit",p.style.cssText="margin-left:auto;padding:6px 12px;font-size:13px;",p.textContent=this.showAllPages?"This page":"All pages",p.addEventListener("click",d=>{d.stopPropagation(),this.togglePageFilter()}),this.toolbarEl.appendChild(p)}togglePageFilter(){this.showAllPages=!this.showAllPages,this.showAllPages?this.pinManager.showAll():this.pinManager.filterByPage(c()),this.updateToolbar()}handlePinClick(e,t){this.hideTooltip(),this.pinManager.highlightPin(e),this.showTooltipForPin(e,t.clientX+16,t.clientY-10)}showTooltipForPin(e,t,i){this.hideTooltip();let n=this.comments.find(m=>m.pinNumber===e);if(!n)return;this.tooltipEl=document.createElement("div"),this.tooltipEl.className="review-tooltip";let r=new Date(n.createdAt).toLocaleString(),a=document.createElement("div");if(a.style.cssText="font-weight:500;margin-bottom:4px;",a.textContent=`Pin #${e}`,this.tooltipEl.appendChild(a),n.reviewerName){let m=document.createElement("div");m.style.cssText="font-size:11px;opacity:0.7;margin-bottom:2px;",m.textContent=n.reviewerName,this.tooltipEl.appendChild(m)}let l=document.createElement("div");l.style.cssText="margin-bottom:4px;",l.textContent=n.commentText||"(no text)",this.tooltipEl.appendChild(l);let p=document.createElement("div");p.style.cssText="font-size:11px;opacity:0.7;",p.textContent=r,this.tooltipEl.appendChild(p);let d=n.pageUrl??"";if(d&&d!==c()){let m=document.createElement("div");m.style.cssText="margin-top:6px;padding-top:6px;border-top:1px solid rgba(255,255,255,0.2);font-size:12px;";let L=document.createElement("span");L.style.opacity="0.7",L.textContent=`Page: ${d.split("?")[0].split("#")[0]||"/"} \u2014 `,m.appendChild(L);let f=document.createElement("a");f.style.cssText="color:#a78bfa;cursor:pointer;text-decoration:underline;pointer-events:auto;",f.textContent="Navigate there?",f.addEventListener("click",Y=>{Y.stopPropagation(),this.navigateToPin(d,e)}),m.appendChild(f),this.tooltipEl.appendChild(m),this.tooltipEl.style.pointerEvents="auto"}let C=t??window.innerWidth/2,O=i??window.innerHeight/3;this.tooltipEl.style.position="fixed",this.tooltipEl.style.left=`${Math.min(C,window.innerWidth-300)}px`,this.tooltipEl.style.top=`${Math.min(O,window.innerHeight-150)}px`,this.shadowRoot.appendChild(this.tooltipEl);let D=m=>{m.target!==this.tooltipEl&&!this.tooltipEl?.contains(m.target)&&(this.hideTooltip(),this.pinManager.clearHighlight(),document.removeEventListener("click",D,!0))};setTimeout(()=>document.addEventListener("click",D,!0),0)}navigateToPin(e,t){this.hideTooltip(),this.pinManager.clearHighlight();let i=new URL(e,window.location.origin);i.searchParams.set("pin",String(t)),window.location.href=i.toString()}autoFocusPin(){let t=new URLSearchParams(window.location.search).get("pin");if(!t)return;let i=Number(t);if(!i)return;let n=this.comments.find(d=>d.pinNumber===i);if(!n?.pinData)return;let r=n.pageUrl??"";if(r){let d=new URL(window.location.href);d.searchParams.delete("pin");let C=d.pathname+d.search+d.hash;if(r!==C){this.navigateToPin(r,i);return}}this.pinManager.showAll(),this.showAllPages=!0,this.updateToolbar();let a=document.documentElement,l=n.pinData.pinX/100*a.scrollWidth,p=n.pinData.pinY/100*a.scrollHeight;window.scrollTo({left:l-window.innerWidth/2,top:p-window.innerHeight/2,behavior:"smooth"}),setTimeout(()=>{this.pinManager.highlightPin(i),this.showTooltipForPin(i)},500)}hideTooltip(){this.tooltipEl?.remove(),this.tooltipEl=null}destroy(){this.pinClickHandler&&document.removeEventListener("click",this.pinClickHandler,!0),this.pageListener?.destroy(),this.hideTooltip(),this.toolbarEl?.remove(),this.pinManager.destroy()}};var T=class{constructor(e={}){s(this,"root");s(this,"shadow");s(this,"mode",null);s(this,"_isDestroyed",!1);this.root=document.createElement("div"),this.root.id="ourroadmaps-review",this.shadow=this.root.attachShadow({mode:"open"});let t=document.createElement("style");t.textContent=A,this.shadow.appendChild(t),document.body.appendChild(this.root)}async init(e,t){if(!e||!t){let i=new URLSearchParams(window.location.search),n=i.get("review"),r=i.get("triage");if(n){e="review",t=n,$("review",n);let a=new URL(window.location.href);a.searchParams.delete("review"),history.replaceState(null,"",a.toString())}else if(r){e="triage",t=r,$("triage",r);let a=new URL(window.location.href);a.searchParams.delete("triage"),history.replaceState(null,"",a.toString())}else{let a=j();if(a)e=a.type,t=a.token;else return}}if(e==="review")try{let i=await M(t);this.mode=new P(t,this.shadow,i),await this.mode.init()}catch(i){i instanceof h&&(z(),this.showErrorOverlay(i.code==="expired"?"This feedback session has expired":"This review link is no longer valid"))}else if(e==="triage")try{await M(t),this.mode=new k(t,this.shadow),await this.mode.init()}catch(i){i instanceof h&&(z(),this.showErrorOverlay(i.code==="expired"?"This feedback session has expired":"This review link is no longer valid"))}}showErrorOverlay(e){let t=document.createElement("div");t.className="review-expired-overlay",t.innerHTML=`
332
691
  <div class="review-expired-card">
333
692
  <h2 style="margin:0 0 8px;font-size:18px;">Session Unavailable</h2>
334
693
  <p style="margin:0;color:#666;font-size:14px;">${e}</p>
335
694
  <p style="margin:12px 0 0;color:#999;font-size:13px;">Contact the prototype owner for a new link.</p>
336
695
  </div>
337
- `,this.shadow.appendChild(t),document.body.style.filter="grayscale(0.8)"}destroy(){this._isDestroyed||(this._isDestroyed=!0,this.mode?.destroy(),this.root.remove(),document.body.style.filter="")}};return q(Q);})();
696
+ `,this.shadow.appendChild(t),document.body.style.filter="grayscale(0.8)"}destroy(){this._isDestroyed||(this._isDestroyed=!0,this.mode?.destroy(),this.root.remove(),document.body.style.filter="")}};return G(ee);})();
338
697
  //# sourceMappingURL=review.global.js.map