@mindbowser_inc/ui-feedback-plugin 0.4.1 → 0.6.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,8 +1,8 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
const
|
|
5
|
-
let
|
|
1
|
+
var me = Object.defineProperty;
|
|
2
|
+
var ge = (e, t, r) => t in e ? me(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
|
|
3
|
+
var O = (e, t, r) => ge(e, typeof t != "symbol" ? t + "" : t, r);
|
|
4
|
+
const I = /* @__PURE__ */ new Set();
|
|
5
|
+
let R = {
|
|
6
6
|
active: !1,
|
|
7
7
|
userName: null,
|
|
8
8
|
comments: [],
|
|
@@ -12,24 +12,24 @@ let T = {
|
|
|
12
12
|
filter: "open",
|
|
13
13
|
config: {}
|
|
14
14
|
};
|
|
15
|
-
function
|
|
16
|
-
return
|
|
15
|
+
function A() {
|
|
16
|
+
return R;
|
|
17
17
|
}
|
|
18
|
-
function
|
|
19
|
-
|
|
18
|
+
function k(e) {
|
|
19
|
+
R = { ...R, ...e }, I.forEach((t) => t(R));
|
|
20
20
|
}
|
|
21
|
-
function
|
|
22
|
-
return
|
|
21
|
+
function oe(e) {
|
|
22
|
+
return I.add(e), () => I.delete(e);
|
|
23
23
|
}
|
|
24
|
-
function
|
|
25
|
-
if (
|
|
24
|
+
function re() {
|
|
25
|
+
if (R.userName) return R.userName;
|
|
26
26
|
const e = localStorage.getItem("ufp_user_name");
|
|
27
|
-
return e ? (
|
|
27
|
+
return e ? (k({ userName: e }), e) : null;
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
localStorage.setItem("ufp_user_name", e),
|
|
29
|
+
function ie(e) {
|
|
30
|
+
localStorage.setItem("ufp_user_name", e), k({ userName: e });
|
|
31
31
|
}
|
|
32
|
-
function
|
|
32
|
+
function Q(e) {
|
|
33
33
|
try {
|
|
34
34
|
const t = new URL(e);
|
|
35
35
|
return t.origin + t.pathname;
|
|
@@ -37,7 +37,7 @@ function I(e) {
|
|
|
37
37
|
return e;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
function
|
|
40
|
+
function xe(e) {
|
|
41
41
|
return `
|
|
42
42
|
:host {
|
|
43
43
|
--ufp-primary: ${e};
|
|
@@ -592,13 +592,13 @@ function Q(e) {
|
|
|
592
592
|
}
|
|
593
593
|
`;
|
|
594
594
|
}
|
|
595
|
-
const
|
|
595
|
+
const ye = {
|
|
596
596
|
"bottom-right": { bottom: "24px", right: "24px" },
|
|
597
597
|
"bottom-left": { bottom: "24px", left: "24px" },
|
|
598
598
|
"top-right": { top: "24px", right: "24px" },
|
|
599
599
|
"top-left": { top: "24px", left: "24px" }
|
|
600
|
-
},
|
|
601
|
-
function
|
|
600
|
+
}, q = "#6366f1", Z = "#4f46e5", ee = "#4338ca";
|
|
601
|
+
function ve(e, t, r, n) {
|
|
602
602
|
const o = document.createElement("div");
|
|
603
603
|
Object.assign(o.style, {
|
|
604
604
|
position: "fixed",
|
|
@@ -609,43 +609,43 @@ function ee(e, t, r, n) {
|
|
|
609
609
|
boxShadow: "0 4px 20px rgba(0,0,0,0.28), 0 1px 4px rgba(0,0,0,0.16)",
|
|
610
610
|
overflow: "hidden",
|
|
611
611
|
userSelect: "none",
|
|
612
|
-
...
|
|
612
|
+
...ye[t]
|
|
613
613
|
});
|
|
614
614
|
const a = document.createElement("button");
|
|
615
|
-
a.id = "ufp-btn-annotate", a.title = "Add feedback annotation",
|
|
615
|
+
a.id = "ufp-btn-annotate", a.title = "Add feedback annotation", te(a), a.style.padding = "10px 16px 10px 14px", a.innerHTML = `
|
|
616
616
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" style="flex-shrink:0">
|
|
617
617
|
<path d="M12 20h9"/>
|
|
618
618
|
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
|
|
619
619
|
</svg>
|
|
620
620
|
<span id="ufp-annotate-label" style="font-size:14px;font-weight:600;">Feedback</span>
|
|
621
621
|
`;
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
const
|
|
625
|
-
|
|
622
|
+
const p = document.createElement("div");
|
|
623
|
+
p.style.cssText = "width:1px;background:rgba(255,255,255,0.3);flex-shrink:0;";
|
|
624
|
+
const c = document.createElement("button");
|
|
625
|
+
c.id = "ufp-btn-panel", c.title = "View all comments", te(c), c.style.padding = "10px 14px", c.innerHTML = `
|
|
626
626
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" style="flex-shrink:0">
|
|
627
627
|
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
|
628
628
|
</svg>
|
|
629
629
|
<span id="ufp-panel-count" style="font-size:13px;font-weight:600;min-width:8px;text-align:center;"></span>
|
|
630
|
-
`, o.appendChild(a), o.appendChild(
|
|
631
|
-
const
|
|
632
|
-
return a.addEventListener("click", (
|
|
633
|
-
if (
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
}),
|
|
637
|
-
|
|
638
|
-
}),
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
}),
|
|
630
|
+
`, o.appendChild(a), o.appendChild(p), o.appendChild(c), e.appendChild(o);
|
|
631
|
+
const i = o.querySelector("#ufp-annotate-label"), l = o.querySelector("#ufp-panel-count");
|
|
632
|
+
return a.addEventListener("click", (s) => {
|
|
633
|
+
if (s.stopPropagation(), o._dragged) return;
|
|
634
|
+
const h = A();
|
|
635
|
+
h.active || (h.panelOpen ? (n(), setTimeout(r, 220)) : r());
|
|
636
|
+
}), c.addEventListener("click", (s) => {
|
|
637
|
+
s.stopPropagation(), !o._dragged && (A().active || n());
|
|
638
|
+
}), ne(a, () => (A().panelOpen, q), Z), ne(c, () => A().panelOpen ? ee : q, Z), oe((s) => {
|
|
639
|
+
const h = s.comments.filter((v) => !v.resolved).length;
|
|
640
|
+
l.textContent = h > 0 ? String(h) : "", s.active ? (i.textContent = "Drawing…", a.style.opacity = "0.65", c.style.opacity = "0.65", a.style.pointerEvents = "none", c.style.pointerEvents = "none") : (i.textContent = "Feedback", a.style.opacity = "1", c.style.opacity = "1", a.style.pointerEvents = "auto", c.style.pointerEvents = "auto"), c.style.background = s.panelOpen ? ee : q;
|
|
641
|
+
}), be(o), o;
|
|
642
642
|
}
|
|
643
|
-
function
|
|
643
|
+
function te(e) {
|
|
644
644
|
Object.assign(e.style, {
|
|
645
645
|
display: "flex",
|
|
646
646
|
alignItems: "center",
|
|
647
647
|
gap: "7px",
|
|
648
|
-
background:
|
|
648
|
+
background: q,
|
|
649
649
|
color: "#ffffff",
|
|
650
650
|
border: "none",
|
|
651
651
|
cursor: "pointer",
|
|
@@ -654,32 +654,32 @@ function D(e) {
|
|
|
654
654
|
transition: "background 0.12s"
|
|
655
655
|
});
|
|
656
656
|
}
|
|
657
|
-
function
|
|
657
|
+
function ne(e, t, r) {
|
|
658
658
|
e.addEventListener("mouseenter", () => {
|
|
659
659
|
e.style.background = r;
|
|
660
660
|
}), e.addEventListener("mouseleave", () => {
|
|
661
661
|
e.style.background = t();
|
|
662
662
|
});
|
|
663
663
|
}
|
|
664
|
-
function
|
|
664
|
+
function be(e) {
|
|
665
665
|
let t = 0, r = 0, n = 0, o = 0;
|
|
666
666
|
e.addEventListener("pointerdown", (a) => {
|
|
667
667
|
if (a.button !== 0) return;
|
|
668
668
|
t = a.clientX, r = a.clientY;
|
|
669
|
-
const
|
|
670
|
-
n =
|
|
671
|
-
const
|
|
672
|
-
const
|
|
673
|
-
!e._dragged && Math.sqrt(
|
|
674
|
-
},
|
|
675
|
-
document.removeEventListener("pointermove",
|
|
669
|
+
const p = e.getBoundingClientRect();
|
|
670
|
+
n = p.left, o = p.top, e._dragged = !1;
|
|
671
|
+
const c = (l) => {
|
|
672
|
+
const s = l.clientX - t, h = l.clientY - r;
|
|
673
|
+
!e._dragged && Math.sqrt(s * s + h * h) < 5 || (e._dragged = !0, e.style.left = `${Math.max(0, Math.min(window.innerWidth - e.offsetWidth, n + s))}px`, e.style.top = `${Math.max(0, Math.min(window.innerHeight - e.offsetHeight, o + h))}px`, e.style.right = "auto", e.style.bottom = "auto");
|
|
674
|
+
}, i = () => {
|
|
675
|
+
document.removeEventListener("pointermove", c), document.removeEventListener("pointerup", i), requestAnimationFrame(() => {
|
|
676
676
|
e._dragged = !1;
|
|
677
677
|
});
|
|
678
678
|
};
|
|
679
|
-
document.addEventListener("pointermove",
|
|
679
|
+
document.addEventListener("pointermove", c), document.addEventListener("pointerup", i);
|
|
680
680
|
});
|
|
681
681
|
}
|
|
682
|
-
function
|
|
682
|
+
function we(e) {
|
|
683
683
|
return new Promise((t) => {
|
|
684
684
|
const r = document.createElement("div");
|
|
685
685
|
r.className = "ufp-modal-backdrop", r.innerHTML = `
|
|
@@ -704,20 +704,20 @@ function ne(e) {
|
|
|
704
704
|
o.disabled = n.value.trim().length === 0;
|
|
705
705
|
});
|
|
706
706
|
const a = () => {
|
|
707
|
-
const
|
|
708
|
-
|
|
707
|
+
const p = n.value.trim();
|
|
708
|
+
p && (ie(p), r.remove(), t(p));
|
|
709
709
|
};
|
|
710
|
-
o.addEventListener("click", a), n.addEventListener("keydown", (
|
|
711
|
-
|
|
710
|
+
o.addEventListener("click", a), n.addEventListener("keydown", (p) => {
|
|
711
|
+
p.key === "Enter" && a();
|
|
712
712
|
}), requestAnimationFrame(() => n.focus());
|
|
713
713
|
});
|
|
714
714
|
}
|
|
715
|
-
const
|
|
716
|
-
function
|
|
715
|
+
const L = "#6366f1", z = 3;
|
|
716
|
+
function B(e, t = 1, r = 1) {
|
|
717
717
|
switch (e.type) {
|
|
718
718
|
case "pen": {
|
|
719
719
|
const n = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
720
|
-
return n.setAttribute("d",
|
|
720
|
+
return n.setAttribute("d", Ee(e.points, t, r)), n.setAttribute("stroke", e.color), n.setAttribute("stroke-width", String(e.width * Math.min(t, r))), n.setAttribute("fill", "none"), n.setAttribute("stroke-linecap", "round"), n.setAttribute("stroke-linejoin", "round"), n;
|
|
721
721
|
}
|
|
722
722
|
case "rect": {
|
|
723
723
|
const n = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
|
@@ -733,19 +733,19 @@ function z(e, t = 1, r = 1) {
|
|
|
733
733
|
}
|
|
734
734
|
}
|
|
735
735
|
}
|
|
736
|
-
function
|
|
736
|
+
function ke(e, t, r, n) {
|
|
737
737
|
const o = r / t.pageWidth, a = n / t.pageHeight;
|
|
738
738
|
e.innerHTML = "";
|
|
739
|
-
const
|
|
740
|
-
|
|
739
|
+
const p = document.createElementNS("http://www.w3.org/2000/svg", "defs");
|
|
740
|
+
p.innerHTML = `
|
|
741
741
|
<marker id="ufp-arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
742
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="${
|
|
742
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="${L}" />
|
|
743
743
|
</marker>
|
|
744
|
-
`, e.appendChild(
|
|
745
|
-
e.appendChild(
|
|
744
|
+
`, e.appendChild(p), t.shapes.forEach((c) => {
|
|
745
|
+
e.appendChild(B(c, o, a));
|
|
746
746
|
});
|
|
747
747
|
}
|
|
748
|
-
function
|
|
748
|
+
function Ee(e, t, r) {
|
|
749
749
|
if (e.length === 0) return "";
|
|
750
750
|
if (e.length === 1) {
|
|
751
751
|
const o = e[0];
|
|
@@ -756,54 +756,95 @@ function oe(e, t, r) {
|
|
|
756
756
|
n += ` L ${e[o].x * t} ${e[o].y * r}`;
|
|
757
757
|
return n;
|
|
758
758
|
}
|
|
759
|
-
function
|
|
759
|
+
function Se(e, t, r) {
|
|
760
|
+
if (window.scrollX === 0 && window.scrollY === 0) return null;
|
|
761
|
+
const n = window.innerWidth, o = window.innerHeight, a = document.elementsFromPoint(e, t).find((p) => p !== r);
|
|
762
|
+
for (let p = a ?? null; p && p !== document.documentElement; p = p.parentElement) {
|
|
763
|
+
const c = getComputedStyle(p);
|
|
764
|
+
if (c.position !== "fixed" && c.position !== "sticky") continue;
|
|
765
|
+
const i = p.getBoundingClientRect();
|
|
766
|
+
if (!(i.width >= n * 0.9 && i.height >= o * 0.9)) {
|
|
767
|
+
if (c.position === "sticky") {
|
|
768
|
+
if (i.top < o * 0.25) return "top";
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
return o - i.bottom < i.top ? "bottom" : "top";
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
function Ce(e, t, r) {
|
|
777
|
+
if (!t && !r) return e;
|
|
778
|
+
switch (e.type) {
|
|
779
|
+
case "pen":
|
|
780
|
+
return { ...e, points: e.points.map((n) => ({ x: n.x + t, y: n.y + r })) };
|
|
781
|
+
case "rect":
|
|
782
|
+
return { ...e, x: e.x + t, y: e.y + r };
|
|
783
|
+
case "circle":
|
|
784
|
+
return { ...e, cx: e.cx + t, cy: e.cy + r };
|
|
785
|
+
case "arrow":
|
|
786
|
+
return { ...e, x1: e.x1 + t, y1: e.y1 + r, x2: e.x2 + t, y2: e.y2 + r };
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
function Le(e) {
|
|
760
790
|
return new Promise((t) => {
|
|
761
791
|
let r = "pen";
|
|
762
792
|
const n = [];
|
|
763
|
-
let o = !1, a = 0,
|
|
764
|
-
const
|
|
765
|
-
|
|
793
|
+
let o = !1, a = 0, p = 0, c = [], i = null, l = null, s = !1, h = 0;
|
|
794
|
+
const v = [];
|
|
795
|
+
let m = null;
|
|
796
|
+
const b = () => m ? { x: 0, y: 0 } : { x: window.scrollX, y: window.scrollY }, x = document.createElement("div");
|
|
797
|
+
x.style.cssText = "position:fixed;inset:0;z-index:2147483645;cursor:crosshair;background:rgba(99,102,241,0.04);touch-action:none;user-select:none;-webkit-user-select:none;";
|
|
766
798
|
const u = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
767
799
|
u.style.cssText = "position:absolute;inset:0;width:100%;height:100%;pointer-events:none;overflow:visible;", u.innerHTML = `
|
|
768
800
|
<defs>
|
|
769
801
|
<marker id="ufp-arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
770
|
-
<polygon points="0 0, 10 3.5, 0 7" fill="${
|
|
802
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="${L}" />
|
|
771
803
|
</marker>
|
|
772
804
|
</defs>
|
|
773
|
-
`,
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
805
|
+
`, x.appendChild(u);
|
|
806
|
+
const w = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
807
|
+
u.appendChild(w);
|
|
808
|
+
const C = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
809
|
+
u.appendChild(C);
|
|
810
|
+
const N = () => w.setAttribute("transform", `translate(${-window.scrollX} ${-window.scrollY})`);
|
|
811
|
+
N(), window.addEventListener("scroll", N, { passive: !0 });
|
|
812
|
+
function H() {
|
|
813
|
+
window.removeEventListener("scroll", N);
|
|
814
|
+
for (const d of X) window.removeEventListener(d, K, !0);
|
|
815
|
+
for (const d of Y) window.removeEventListener(d, G, !0);
|
|
816
|
+
x.remove(), P.remove(), l == null || l.remove();
|
|
817
|
+
}
|
|
818
|
+
function j() {
|
|
819
|
+
w.innerHTML = "", C.innerHTML = "", n.forEach((d, g) => (v[g] ? C : w).appendChild(B(d)));
|
|
820
|
+
}
|
|
821
|
+
function _() {
|
|
822
|
+
let d = 0, g = 0, y = 0;
|
|
823
|
+
return n.forEach((f, E) => {
|
|
824
|
+
const S = v[E] ? 0 : window.scrollX, M = v[E] ? 0 : window.scrollY;
|
|
825
|
+
if (f.type === "pen" && f.points.length) {
|
|
826
|
+
const $ = f.points[f.points.length - 1];
|
|
827
|
+
d += $.x - S, g += $.y - M, y++;
|
|
828
|
+
} else f.type === "rect" ? (d += f.x + f.width - S, g += f.y + f.height - M, y++) : f.type === "circle" ? (d += f.cx - S, g += f.cy - M, y++) : f.type === "arrow" && (d += f.x2 - S, g += f.y2 - M, y++);
|
|
788
829
|
}), {
|
|
789
|
-
anchorX:
|
|
790
|
-
anchorY:
|
|
830
|
+
anchorX: y > 0 ? d / y : window.innerWidth / 2,
|
|
831
|
+
anchorY: y > 0 ? g / y : window.innerHeight / 2
|
|
791
832
|
};
|
|
792
833
|
}
|
|
793
|
-
function
|
|
794
|
-
|
|
834
|
+
function ae() {
|
|
835
|
+
s = !0, o = !1, x.style.pointerEvents = "none", P.style.pointerEvents = "none", se();
|
|
795
836
|
}
|
|
796
|
-
function
|
|
797
|
-
|
|
798
|
-
const { anchorX:
|
|
799
|
-
let
|
|
800
|
-
|
|
801
|
-
position:fixed;left:${
|
|
802
|
-
background:#fff;border-radius:12px;padding:16px;width:${
|
|
837
|
+
function se() {
|
|
838
|
+
l && l.remove();
|
|
839
|
+
const { anchorX: d, anchorY: g } = _(), y = 300, f = 12;
|
|
840
|
+
let E = d + f, S = g + f;
|
|
841
|
+
E + y > window.innerWidth - f && (E = d - y - f), E < f && (E = f), S + 210 > window.innerHeight - f && (S = window.innerHeight - 210 - f), S < f && (S = f), l = document.createElement("div"), l.style.cssText = `
|
|
842
|
+
position:fixed;left:${E}px;top:${S}px;z-index:2147483647;
|
|
843
|
+
background:#fff;border-radius:12px;padding:16px;width:${y}px;
|
|
803
844
|
box-shadow:0 4px 24px rgba(0,0,0,0.18);
|
|
804
845
|
display:flex;flex-direction:column;gap:10px;
|
|
805
846
|
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
|
|
806
|
-
`,
|
|
847
|
+
`, l.innerHTML = `
|
|
807
848
|
<div style="font-size:13px;font-weight:600;color:#374151;">Add your comment</div>
|
|
808
849
|
<textarea id="ufp-inline-text" placeholder="Describe your feedback…" rows="3"
|
|
809
850
|
style="width:100%;padding:9px 12px;border:1.5px solid #e5e7eb;border-radius:8px;
|
|
@@ -819,66 +860,94 @@ function ie(e) {
|
|
|
819
860
|
font-family:inherit;cursor:pointer;background:#6366f1;border:none;
|
|
820
861
|
color:#fff;opacity:0.45;transition:opacity 0.15s;">Submit</button>
|
|
821
862
|
</div>
|
|
822
|
-
`, e.appendChild(
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
const
|
|
826
|
-
|
|
827
|
-
}),
|
|
828
|
-
const
|
|
829
|
-
if (!
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
}),
|
|
835
|
-
|
|
836
|
-
|
|
863
|
+
`, e.appendChild(l);
|
|
864
|
+
const M = l.querySelector("#ufp-inline-text"), $ = l.querySelector("#ufp-popup-submit"), de = l.querySelector("#ufp-popup-cancel");
|
|
865
|
+
M.addEventListener("input", () => {
|
|
866
|
+
const W = M.value.trim().length > 0;
|
|
867
|
+
$.disabled = !W, $.style.opacity = W ? "1" : "0.45";
|
|
868
|
+
}), $.addEventListener("click", () => {
|
|
869
|
+
const W = M.value.trim();
|
|
870
|
+
if (!W) return;
|
|
871
|
+
const ue = _();
|
|
872
|
+
H();
|
|
873
|
+
const fe = n.map((J, he) => v[he] ? J : Ce(J, -window.scrollX, -window.scrollY));
|
|
874
|
+
t({ shapes: fe, text: W, ...ue });
|
|
875
|
+
}), de.addEventListener("click", () => {
|
|
876
|
+
H(), t(null);
|
|
877
|
+
}), requestAnimationFrame(() => M.focus());
|
|
878
|
+
}
|
|
879
|
+
const P = Me(
|
|
837
880
|
e,
|
|
838
|
-
(
|
|
839
|
-
r =
|
|
881
|
+
(d) => {
|
|
882
|
+
r = d;
|
|
840
883
|
},
|
|
841
884
|
() => {
|
|
842
|
-
|
|
885
|
+
H(), t(null);
|
|
843
886
|
},
|
|
844
887
|
() => {
|
|
845
|
-
n.length !== 0 && (
|
|
888
|
+
n.length !== 0 && (l && (l.remove(), l = null, x.style.pointerEvents = "auto", P.style.pointerEvents = "auto", s = !1), n.pop(), v.pop(), j());
|
|
846
889
|
}
|
|
847
890
|
);
|
|
848
|
-
e.appendChild(
|
|
849
|
-
|
|
850
|
-
|
|
891
|
+
e.appendChild(x);
|
|
892
|
+
const X = ["pointerdown", "pointermove", "pointerup", "pointercancel"], Y = ["mousedown", "mouseup", "click", "dblclick", "auxclick", "touchstart", "touchmove", "contextmenu", "dragstart", "selectstart"];
|
|
893
|
+
function V(d) {
|
|
894
|
+
const g = d.composedPath();
|
|
895
|
+
return g.includes(e.host) && !g.includes(x);
|
|
896
|
+
}
|
|
897
|
+
function G(d) {
|
|
898
|
+
V(d) || s && performance.now() > h || (d.preventDefault(), d.stopPropagation());
|
|
899
|
+
}
|
|
900
|
+
function K(d) {
|
|
901
|
+
if (s || V(d)) return;
|
|
902
|
+
d.stopPropagation();
|
|
903
|
+
const g = d;
|
|
904
|
+
d.type === "pointerdown" ? le(g) : d.type === "pointermove" ? pe(g) : d.type === "pointerup" ? ce(g) : d.type === "pointercancel" && (o = !1, i && (i.remove(), i = null));
|
|
905
|
+
}
|
|
906
|
+
function le(d) {
|
|
907
|
+
if (d.button === 0) {
|
|
908
|
+
d.preventDefault();
|
|
909
|
+
try {
|
|
910
|
+
x.setPointerCapture(d.pointerId);
|
|
911
|
+
} catch {
|
|
912
|
+
}
|
|
913
|
+
o = !0, m = Se(d.clientX, d.clientY, e.host), a = d.clientX + b().x, p = d.clientY + b().y, r === "pen" && (c = [{ x: a, y: p }]);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function pe(d) {
|
|
851
917
|
if (!o) return;
|
|
852
|
-
const
|
|
853
|
-
if (
|
|
854
|
-
|
|
918
|
+
const g = d.clientX + b().x, y = d.clientY + b().y;
|
|
919
|
+
if (i && i.remove(), r === "pen")
|
|
920
|
+
c.push({ x: g, y }), i = B({ type: "pen", points: [...c], color: L, width: z });
|
|
855
921
|
else if (r === "rect") {
|
|
856
|
-
const
|
|
857
|
-
|
|
922
|
+
const f = { type: "rect", x: Math.min(a, g), y: Math.min(p, y), width: Math.abs(g - a), height: Math.abs(y - p), color: L, strokeWidth: z };
|
|
923
|
+
i = B(f);
|
|
858
924
|
} else if (r === "circle") {
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
} else r === "arrow" && (
|
|
862
|
-
|
|
863
|
-
}
|
|
925
|
+
const f = Math.abs(g - a) / 2, E = Math.abs(y - p) / 2, S = { type: "circle", cx: Math.min(a, g) + f, cy: Math.min(p, y) + E, rx: f, ry: E, color: L, strokeWidth: z };
|
|
926
|
+
i = B(S);
|
|
927
|
+
} else r === "arrow" && (i = B({ type: "arrow", x1: a, y1: p, x2: g, y2: y, color: L, width: z }));
|
|
928
|
+
i && (m ? C : w).appendChild(i);
|
|
929
|
+
}
|
|
930
|
+
function ce(d) {
|
|
864
931
|
if (!o) return;
|
|
865
|
-
o = !1,
|
|
866
|
-
const
|
|
867
|
-
let
|
|
868
|
-
if (r === "pen" &&
|
|
869
|
-
n.push({ type: "pen", points: [...
|
|
932
|
+
h = performance.now() + 400, o = !1, i && (i.remove(), i = null);
|
|
933
|
+
const g = d.clientX + b().x, y = d.clientY + b().y;
|
|
934
|
+
let f = !1;
|
|
935
|
+
if (r === "pen" && c.length > 1)
|
|
936
|
+
n.push({ type: "pen", points: [...c], color: L, width: z }), c = [], f = !0;
|
|
870
937
|
else if (r === "rect") {
|
|
871
|
-
const
|
|
872
|
-
|
|
938
|
+
const E = Math.abs(g - a), S = Math.abs(y - p);
|
|
939
|
+
E > 4 && S > 4 && (n.push({ type: "rect", x: Math.min(a, g), y: Math.min(p, y), width: E, height: S, color: L, strokeWidth: z }), f = !0);
|
|
873
940
|
} else if (r === "circle") {
|
|
874
|
-
const
|
|
875
|
-
|
|
876
|
-
} else r === "arrow" && Math.sqrt((
|
|
877
|
-
|
|
878
|
-
}
|
|
941
|
+
const E = Math.abs(g - a) / 2, S = Math.abs(y - p) / 2;
|
|
942
|
+
E > 4 && S > 4 && (n.push({ type: "circle", cx: Math.min(a, g) + E, cy: Math.min(p, y) + S, rx: E, ry: S, color: L, strokeWidth: z }), f = !0);
|
|
943
|
+
} else r === "arrow" && Math.sqrt((g - a) ** 2 + (y - p) ** 2) > 10 && (n.push({ type: "arrow", x1: a, y1: p, x2: g, y2: y, color: L, width: z }), f = !0);
|
|
944
|
+
f && (v.push(m), j(), ae());
|
|
945
|
+
}
|
|
946
|
+
for (const d of X) window.addEventListener(d, K, { capture: !0, passive: !1 });
|
|
947
|
+
for (const d of Y) window.addEventListener(d, G, { capture: !0, passive: !1 });
|
|
879
948
|
});
|
|
880
949
|
}
|
|
881
|
-
function
|
|
950
|
+
function Me(e, t, r, n) {
|
|
882
951
|
const o = document.createElement("div");
|
|
883
952
|
return o.className = "ufp-toolbar", o.innerHTML = `
|
|
884
953
|
<span class="ufp-toolbar-label">Draw to annotate</span>
|
|
@@ -909,11 +978,11 @@ function ae(e, t, r, n) {
|
|
|
909
978
|
<button class="ufp-btn ufp-btn-ghost" id="ufp-cancel-btn">Cancel</button>
|
|
910
979
|
`, o.querySelectorAll("[data-tool]").forEach((a) => {
|
|
911
980
|
a.addEventListener("click", () => {
|
|
912
|
-
o.querySelectorAll("[data-tool]").forEach((
|
|
981
|
+
o.querySelectorAll("[data-tool]").forEach((p) => p.classList.remove("active")), a.classList.add("active"), t(a.dataset.tool);
|
|
913
982
|
});
|
|
914
983
|
}), o.querySelector("#ufp-undo-btn").addEventListener("click", n), o.querySelector("#ufp-cancel-btn").addEventListener("click", r), e.appendChild(o), o;
|
|
915
984
|
}
|
|
916
|
-
function
|
|
985
|
+
function U(e) {
|
|
917
986
|
const t = Date.now() - e, r = Math.floor(t / 1e3);
|
|
918
987
|
if (r < 60) return "just now";
|
|
919
988
|
const n = Math.floor(r / 60);
|
|
@@ -923,39 +992,39 @@ function W(e) {
|
|
|
923
992
|
const a = Math.floor(o / 24);
|
|
924
993
|
return a < 7 ? `${a}d ago` : new Date(e).toLocaleDateString();
|
|
925
994
|
}
|
|
926
|
-
function
|
|
995
|
+
function D(e) {
|
|
927
996
|
return e.split(" ").filter(Boolean).slice(0, 2).map((t) => t[0].toUpperCase()).join("");
|
|
928
997
|
}
|
|
929
|
-
function
|
|
998
|
+
function T(e) {
|
|
930
999
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
931
1000
|
}
|
|
932
|
-
function
|
|
1001
|
+
function Ae(e, t, r, n) {
|
|
933
1002
|
let o = [...t];
|
|
934
1003
|
const a = document.createElement("div");
|
|
935
1004
|
a.className = "ufp-replies";
|
|
936
|
-
const
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
const
|
|
940
|
-
if (
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
const
|
|
944
|
-
|
|
1005
|
+
const p = (m) => {
|
|
1006
|
+
const b = a.querySelector(".ufp-replies-list");
|
|
1007
|
+
b && b.remove();
|
|
1008
|
+
const x = document.createElement("div");
|
|
1009
|
+
if (x.className = "ufp-replies-list", x.style.cssText = "display:flex;flex-direction:column;gap:12px;", m.length > 0) {
|
|
1010
|
+
const u = document.createElement("div");
|
|
1011
|
+
u.className = "ufp-replies-title", u.textContent = `${m.length} ${m.length === 1 ? "Reply" : "Replies"}`, x.appendChild(u), m.forEach((w) => {
|
|
1012
|
+
const C = document.createElement("div");
|
|
1013
|
+
C.className = "ufp-reply", C.innerHTML = `
|
|
945
1014
|
<div class="ufp-reply-meta">
|
|
946
|
-
<div class="ufp-avatar" style="width:22px;height:22px;font-size:10px;">${
|
|
947
|
-
<span class="ufp-reply-author">${
|
|
948
|
-
<span class="ufp-reply-time">${
|
|
1015
|
+
<div class="ufp-avatar" style="width:22px;height:22px;font-size:10px;">${D(w.authorName)}</div>
|
|
1016
|
+
<span class="ufp-reply-author">${T(w.authorName)}</span>
|
|
1017
|
+
<span class="ufp-reply-time">${U(w.createdAt)}</span>
|
|
949
1018
|
</div>
|
|
950
|
-
<div class="ufp-reply-text">${
|
|
951
|
-
`,
|
|
1019
|
+
<div class="ufp-reply-text">${T(w.text)}</div>
|
|
1020
|
+
`, x.appendChild(C);
|
|
952
1021
|
});
|
|
953
1022
|
}
|
|
954
|
-
a.insertBefore(
|
|
955
|
-
},
|
|
956
|
-
|
|
957
|
-
const
|
|
958
|
-
|
|
1023
|
+
a.insertBefore(x, a.querySelector(".ufp-reply-input-area"));
|
|
1024
|
+
}, c = document.createElement("div");
|
|
1025
|
+
c.className = "ufp-reply-input-area";
|
|
1026
|
+
const i = re();
|
|
1027
|
+
c.innerHTML = `
|
|
959
1028
|
<div class="ufp-reply-name-row">
|
|
960
1029
|
<span class="ufp-reply-name-label">Replying as:</span>
|
|
961
1030
|
<input
|
|
@@ -963,7 +1032,7 @@ function se(e, t, r, n) {
|
|
|
963
1032
|
id="ufp-reply-name"
|
|
964
1033
|
type="text"
|
|
965
1034
|
placeholder="Your name"
|
|
966
|
-
value="${
|
|
1035
|
+
value="${T(i ?? "")}"
|
|
967
1036
|
style="flex:1;"
|
|
968
1037
|
/>
|
|
969
1038
|
</div>
|
|
@@ -978,32 +1047,32 @@ function se(e, t, r, n) {
|
|
|
978
1047
|
<button class="ufp-btn ufp-btn-primary" id="ufp-reply-submit" disabled style="font-size:13px;padding:7px 14px;">Reply</button>
|
|
979
1048
|
</div>
|
|
980
1049
|
`;
|
|
981
|
-
const
|
|
982
|
-
|
|
1050
|
+
const l = c.querySelector("#ufp-reply-name"), s = c.querySelector("#ufp-reply-text"), h = c.querySelector("#ufp-reply-submit"), v = () => {
|
|
1051
|
+
h.disabled = l.value.trim().length === 0 || s.value.trim().length === 0;
|
|
983
1052
|
};
|
|
984
|
-
return
|
|
985
|
-
const
|
|
986
|
-
if (!
|
|
987
|
-
|
|
988
|
-
const
|
|
1053
|
+
return l.addEventListener("input", v), s.addEventListener("input", v), h.addEventListener("click", async () => {
|
|
1054
|
+
const m = l.value.trim(), b = s.value.trim();
|
|
1055
|
+
if (!m || !b) return;
|
|
1056
|
+
h.disabled = !0, h.textContent = "Sending…", ie(m);
|
|
1057
|
+
const x = {
|
|
989
1058
|
commentId: e,
|
|
990
|
-
authorName:
|
|
991
|
-
text:
|
|
1059
|
+
authorName: m,
|
|
1060
|
+
text: b,
|
|
992
1061
|
createdAt: Date.now()
|
|
993
1062
|
};
|
|
994
1063
|
try {
|
|
995
|
-
const
|
|
996
|
-
|
|
997
|
-
} catch (
|
|
998
|
-
console.error("[ui-feedback-plugin] Failed to save reply:",
|
|
1064
|
+
const w = { id: await r.addReply(x), ...x };
|
|
1065
|
+
s.value = "", h.textContent = "Reply", h.disabled = !0, o = [...o, w], p(o), n(w);
|
|
1066
|
+
} catch (u) {
|
|
1067
|
+
console.error("[ui-feedback-plugin] Failed to save reply:", u), h.disabled = !1, h.textContent = "Reply";
|
|
999
1068
|
}
|
|
1000
|
-
}), a.appendChild(
|
|
1001
|
-
o = [...o,
|
|
1069
|
+
}), a.appendChild(c), p(o), a.addReply = (m) => {
|
|
1070
|
+
o = [...o, m], p(o);
|
|
1002
1071
|
}, a;
|
|
1003
1072
|
}
|
|
1004
|
-
function
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1073
|
+
function ze(e, t, r, n, o, a, p, c) {
|
|
1074
|
+
const i = document.createElement("div");
|
|
1075
|
+
i.className = "ufp-detail", i.innerHTML = `
|
|
1007
1076
|
<div class="ufp-detail-image-area">
|
|
1008
1077
|
<div class="ufp-detail-image-wrap">
|
|
1009
1078
|
<img class="ufp-detail-screenshot" src="${t.screenshotUrl}" alt="Page screenshot" />
|
|
@@ -1034,59 +1103,59 @@ function le(e, t, r, n, o, a, d, l) {
|
|
|
1034
1103
|
<div class="ufp-detail-body">
|
|
1035
1104
|
<div class="ufp-detail-comment">
|
|
1036
1105
|
<div class="ufp-comment-meta">
|
|
1037
|
-
<div class="ufp-avatar">${
|
|
1106
|
+
<div class="ufp-avatar">${D(t.authorName)}</div>
|
|
1038
1107
|
<div>
|
|
1039
|
-
<div class="ufp-comment-author">${
|
|
1040
|
-
<div class="ufp-comment-time">${
|
|
1108
|
+
<div class="ufp-comment-author">${T(t.authorName)}</div>
|
|
1109
|
+
<div class="ufp-comment-time">${U(t.createdAt)}</div>
|
|
1041
1110
|
</div>
|
|
1042
1111
|
</div>
|
|
1043
|
-
<div class="ufp-detail-comment-text">${
|
|
1112
|
+
<div class="ufp-detail-comment-text">${T(t.text)}</div>
|
|
1044
1113
|
<div class="ufp-detail-actions" id="ufp-detail-actions"></div>
|
|
1045
1114
|
</div>
|
|
1046
1115
|
<div id="ufp-detail-replies"></div>
|
|
1047
1116
|
</div>
|
|
1048
1117
|
</div>
|
|
1049
|
-
`, e.appendChild(
|
|
1050
|
-
|
|
1118
|
+
`, e.appendChild(i), i.querySelector("#ufp-detail-back").addEventListener("click", () => {
|
|
1119
|
+
i.remove(), k({ panelOpen: !0 });
|
|
1051
1120
|
});
|
|
1052
|
-
const
|
|
1121
|
+
const l = i.querySelector("#ufp-detail-actions");
|
|
1053
1122
|
if (t.resolved) {
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1123
|
+
const u = document.createElement("button");
|
|
1124
|
+
u.className = "ufp-btn ufp-btn-ghost", u.style.fontSize = "13px", u.innerHTML = `
|
|
1056
1125
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
|
|
1057
1126
|
style="vertical-align:middle;margin-right:4px"><polyline points="9 14 4 9 9 4"/><path d="M20 20v-7a4 4 0 0 0-4-4H4"/></svg>
|
|
1058
1127
|
Reopen
|
|
1059
|
-
`,
|
|
1060
|
-
|
|
1061
|
-
}),
|
|
1128
|
+
`, u.addEventListener("click", async () => {
|
|
1129
|
+
u.disabled = !0, u.textContent = "Reopening…", await n.updateComment(t.id, { resolved: !1 }), a(t.id), i.remove(), k({ panelOpen: !0 });
|
|
1130
|
+
}), l.appendChild(u);
|
|
1062
1131
|
} else {
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1132
|
+
const u = document.createElement("button");
|
|
1133
|
+
u.className = "ufp-btn ufp-btn-primary", u.style.fontSize = "13px", u.innerHTML = `
|
|
1065
1134
|
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
|
|
1066
1135
|
style="vertical-align:middle;margin-right:4px"><polyline points="20 6 9 17 4 12"/></svg>
|
|
1067
1136
|
Mark Resolved
|
|
1068
|
-
`,
|
|
1069
|
-
|
|
1070
|
-
}),
|
|
1137
|
+
`, u.addEventListener("click", async () => {
|
|
1138
|
+
u.disabled = !0, u.textContent = "Resolving…", await n.updateComment(t.id, { resolved: !0 }), o(t.id), i.remove(), k({ panelOpen: !0 });
|
|
1139
|
+
}), l.appendChild(u);
|
|
1071
1140
|
}
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
confirm("Delete this comment and all its replies?") && (
|
|
1075
|
-
}),
|
|
1076
|
-
const
|
|
1077
|
-
var
|
|
1078
|
-
(
|
|
1141
|
+
const s = document.createElement("button");
|
|
1142
|
+
s.className = "ufp-btn ufp-btn-ghost", s.style.fontSize = "13px", s.textContent = "Delete", s.addEventListener("click", async () => {
|
|
1143
|
+
confirm("Delete this comment and all its replies?") && (s.disabled = !0, await n.deleteComment(t.id), p(t.id), i.remove(), k({ panelOpen: !0 }));
|
|
1144
|
+
}), l.appendChild(s);
|
|
1145
|
+
const h = i.querySelector("#ufp-detail-replies"), v = Ae(t.id, r, n, (u) => {
|
|
1146
|
+
var w;
|
|
1147
|
+
(w = v.addReply) == null || w.call(v, u), c == null || c(u);
|
|
1079
1148
|
});
|
|
1080
|
-
|
|
1081
|
-
const
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
|
|
1149
|
+
h.appendChild(v);
|
|
1150
|
+
const m = i.querySelector(".ufp-detail-screenshot"), b = i.querySelector(".ufp-detail-annotation-svg"), x = () => {
|
|
1151
|
+
const u = m.clientWidth, w = m.clientHeight;
|
|
1152
|
+
b.setAttribute("viewBox", `0 0 ${u} ${w}`), ke(b, t.annotation, u, w), b.querySelectorAll("[marker-end]").forEach((C) => {
|
|
1153
|
+
C.setAttribute("marker-end", "url(#ufp-detail-arrowhead)");
|
|
1085
1154
|
});
|
|
1086
1155
|
};
|
|
1087
|
-
|
|
1156
|
+
m.complete && m.naturalWidth > 0 ? x() : m.addEventListener("load", x);
|
|
1088
1157
|
}
|
|
1089
|
-
function
|
|
1158
|
+
function Te(e, t, r) {
|
|
1090
1159
|
const n = document.createElement("div");
|
|
1091
1160
|
n.className = "ufp-panel", n.innerHTML = `
|
|
1092
1161
|
<div class="ufp-panel-header">
|
|
@@ -1109,138 +1178,171 @@ function pe(e, t, r) {
|
|
|
1109
1178
|
</div>
|
|
1110
1179
|
<div class="ufp-panel-list" id="ufp-comment-list"></div>
|
|
1111
1180
|
`, e.appendChild(n), n.querySelector("#ufp-panel-close").addEventListener("click", () => {
|
|
1112
|
-
|
|
1181
|
+
k({ panelOpen: !1 });
|
|
1113
1182
|
}), n.querySelector("#ufp-new-feedback").addEventListener("click", () => {
|
|
1114
|
-
|
|
1115
|
-
}), n.querySelectorAll(".ufp-filter-tab").forEach((
|
|
1116
|
-
|
|
1117
|
-
n.querySelectorAll(".ufp-filter-tab").forEach((
|
|
1183
|
+
k({ panelOpen: !1 }), r();
|
|
1184
|
+
}), n.querySelectorAll(".ufp-filter-tab").forEach((c) => {
|
|
1185
|
+
c.addEventListener("click", () => {
|
|
1186
|
+
n.querySelectorAll(".ufp-filter-tab").forEach((i) => i.classList.remove("active")), c.classList.add("active"), k({ filter: c.dataset.filter });
|
|
1118
1187
|
});
|
|
1119
1188
|
});
|
|
1120
|
-
const o = n.querySelector("#ufp-comment-list"), a = /* @__PURE__ */ new Map(),
|
|
1121
|
-
const
|
|
1122
|
-
if (o.innerHTML = "",
|
|
1189
|
+
const o = n.querySelector("#ufp-comment-list"), a = /* @__PURE__ */ new Map(), p = async (c, i) => {
|
|
1190
|
+
const l = c.filter((s) => i === "open" ? !s.resolved : s.resolved);
|
|
1191
|
+
if (o.innerHTML = "", l.length === 0) {
|
|
1123
1192
|
o.innerHTML = `
|
|
1124
1193
|
<div class="ufp-panel-empty">
|
|
1125
1194
|
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" opacity="0.4">
|
|
1126
1195
|
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
|
1127
1196
|
</svg>
|
|
1128
|
-
<span>No ${
|
|
1129
|
-
${
|
|
1197
|
+
<span>No ${i} comments yet</span>
|
|
1198
|
+
${i === "open" ? '<span style="font-size:12px;color:#9ca3af;">Click <strong>New</strong> to add feedback</span>' : ""}
|
|
1130
1199
|
</div>
|
|
1131
1200
|
`;
|
|
1132
1201
|
return;
|
|
1133
1202
|
}
|
|
1134
|
-
for (const
|
|
1135
|
-
if (!a.has(
|
|
1203
|
+
for (const s of l) {
|
|
1204
|
+
if (!a.has(s.id))
|
|
1136
1205
|
try {
|
|
1137
|
-
a.set(
|
|
1206
|
+
a.set(s.id, await t.getReplies(s.id));
|
|
1138
1207
|
} catch {
|
|
1139
|
-
a.set(
|
|
1208
|
+
a.set(s.id, []);
|
|
1140
1209
|
}
|
|
1141
1210
|
o.appendChild(
|
|
1142
|
-
|
|
1211
|
+
Ne(s, a, e, t)
|
|
1143
1212
|
);
|
|
1144
1213
|
}
|
|
1145
1214
|
};
|
|
1146
|
-
return
|
|
1147
|
-
n.classList.toggle("open",
|
|
1215
|
+
return oe(async (c) => {
|
|
1216
|
+
n.classList.toggle("open", c.panelOpen), c.panelOpen && await p(c.comments, c.filter);
|
|
1148
1217
|
}), n;
|
|
1149
1218
|
}
|
|
1150
|
-
function
|
|
1151
|
-
const a = t.get(e.id) ?? [],
|
|
1152
|
-
return
|
|
1219
|
+
function Ne(e, t, r, n, o) {
|
|
1220
|
+
const a = t.get(e.id) ?? [], p = document.createElement("div");
|
|
1221
|
+
return p.className = "ufp-comment-card", p.dataset.id = e.id, p.innerHTML = `
|
|
1153
1222
|
<div class="ufp-comment-card-header">
|
|
1154
1223
|
<div class="ufp-comment-meta">
|
|
1155
|
-
<div class="ufp-avatar">${
|
|
1224
|
+
<div class="ufp-avatar">${D(e.authorName)}</div>
|
|
1156
1225
|
<div>
|
|
1157
|
-
<div class="ufp-comment-author">${
|
|
1158
|
-
<div class="ufp-comment-time">${
|
|
1226
|
+
<div class="ufp-comment-author">${T(e.authorName)}</div>
|
|
1227
|
+
<div class="ufp-comment-time">${U(e.createdAt)}</div>
|
|
1159
1228
|
</div>
|
|
1160
1229
|
</div>
|
|
1161
1230
|
${e.resolved ? '<span class="ufp-resolved-badge">Resolved</span>' : ""}
|
|
1162
1231
|
</div>
|
|
1163
1232
|
<img class="ufp-comment-thumbnail" src="${e.screenshotUrl}" alt="Screenshot" loading="lazy" />
|
|
1164
|
-
<div class="ufp-comment-text">${
|
|
1233
|
+
<div class="ufp-comment-text">${T(e.text)}</div>
|
|
1165
1234
|
<div class="ufp-comment-footer">
|
|
1166
1235
|
<span class="ufp-reply-count">
|
|
1167
1236
|
${a.length > 0 ? `${a.length} ${a.length === 1 ? "reply" : "replies"}` : "No replies yet — click to reply"}
|
|
1168
1237
|
</span>
|
|
1169
1238
|
</div>
|
|
1170
|
-
`,
|
|
1171
|
-
let
|
|
1239
|
+
`, p.addEventListener("click", async () => {
|
|
1240
|
+
let c = t.get(e.id) ?? [];
|
|
1172
1241
|
try {
|
|
1173
|
-
|
|
1174
|
-
} catch (
|
|
1175
|
-
console.error("[ui-feedback-plugin] Failed to fetch replies:",
|
|
1242
|
+
c = await n.getReplies(e.id), t.set(e.id, c);
|
|
1243
|
+
} catch (i) {
|
|
1244
|
+
console.error("[ui-feedback-plugin] Failed to fetch replies:", i);
|
|
1176
1245
|
}
|
|
1177
|
-
|
|
1246
|
+
ze(
|
|
1178
1247
|
r,
|
|
1179
1248
|
e,
|
|
1180
|
-
|
|
1249
|
+
c,
|
|
1181
1250
|
n,
|
|
1182
|
-
(
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1251
|
+
(i) => {
|
|
1252
|
+
const l = A();
|
|
1253
|
+
k({ comments: l.comments.map((s) => s.id === i ? { ...s, resolved: !0 } : s) });
|
|
1185
1254
|
},
|
|
1186
|
-
(
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1255
|
+
(i) => {
|
|
1256
|
+
const l = A();
|
|
1257
|
+
k({ comments: l.comments.map((s) => s.id === i ? { ...s, resolved: !1 } : s) });
|
|
1189
1258
|
},
|
|
1190
|
-
(
|
|
1191
|
-
const
|
|
1192
|
-
|
|
1259
|
+
(i) => {
|
|
1260
|
+
const l = A();
|
|
1261
|
+
k({ comments: l.comments.filter((s) => s.id !== i) }), t.delete(i);
|
|
1193
1262
|
},
|
|
1194
1263
|
// When a reply is added in the detail view, update badge count immediately
|
|
1195
|
-
(
|
|
1196
|
-
const
|
|
1197
|
-
t.set(e.id, [...
|
|
1198
|
-
const
|
|
1199
|
-
|
|
1264
|
+
(i) => {
|
|
1265
|
+
const l = t.get(e.id) ?? [];
|
|
1266
|
+
t.set(e.id, [...l, i]);
|
|
1267
|
+
const s = A();
|
|
1268
|
+
k({ comments: [...s.comments] });
|
|
1200
1269
|
}
|
|
1201
1270
|
);
|
|
1202
|
-
}),
|
|
1271
|
+
}), p;
|
|
1203
1272
|
}
|
|
1204
|
-
async function
|
|
1273
|
+
async function He() {
|
|
1205
1274
|
try {
|
|
1206
|
-
const e = await
|
|
1207
|
-
return await
|
|
1275
|
+
const e = await $e();
|
|
1276
|
+
return await Be(e);
|
|
1208
1277
|
} catch (e) {
|
|
1209
|
-
return console.error("[ui-feedback-plugin] capturePageScreenshot failed:", e),
|
|
1278
|
+
return console.error("[ui-feedback-plugin] capturePageScreenshot failed:", e), Re();
|
|
1210
1279
|
}
|
|
1211
1280
|
}
|
|
1212
|
-
async function
|
|
1281
|
+
async function $e() {
|
|
1213
1282
|
return (await import("./html2canvas-pro.esm-QETbiPYt.mjs")).default;
|
|
1214
1283
|
}
|
|
1215
|
-
async function
|
|
1216
|
-
const t =
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
ignoreElements: (o) => o.tagName === "UI-FEEDBACK-PLUGIN"
|
|
1231
|
-
})).toDataURL("image/png");
|
|
1232
|
-
} finally {
|
|
1233
|
-
window.scrollTo(t, r);
|
|
1234
|
-
}
|
|
1284
|
+
async function Be(e) {
|
|
1285
|
+
const t = document.documentElement.clientWidth, r = window.innerHeight;
|
|
1286
|
+
return (await e(document.body, {
|
|
1287
|
+
allowTaint: !1,
|
|
1288
|
+
useCORS: !0,
|
|
1289
|
+
logging: !1,
|
|
1290
|
+
scale: Math.min(window.devicePixelRatio, 2),
|
|
1291
|
+
x: window.scrollX,
|
|
1292
|
+
y: window.scrollY,
|
|
1293
|
+
width: t,
|
|
1294
|
+
height: r,
|
|
1295
|
+
windowWidth: t,
|
|
1296
|
+
windowHeight: r,
|
|
1297
|
+
ignoreElements: (o) => o.tagName === "UI-FEEDBACK-PLUGIN"
|
|
1298
|
+
})).toDataURL("image/png");
|
|
1235
1299
|
}
|
|
1236
|
-
function
|
|
1300
|
+
function Re() {
|
|
1237
1301
|
const e = document.createElement("canvas");
|
|
1238
1302
|
e.width = window.innerWidth, e.height = window.innerHeight;
|
|
1239
1303
|
const t = e.getContext("2d");
|
|
1240
1304
|
return t.fillStyle = "#f3f4f6", t.fillRect(0, 0, e.width, e.height), t.fillStyle = "#9ca3af", t.font = "16px -apple-system, sans-serif", t.textAlign = "center", t.fillText("Screenshot unavailable", e.width / 2, e.height / 2), e.toDataURL("image/png");
|
|
1241
1305
|
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1306
|
+
async function We(e, t) {
|
|
1307
|
+
try {
|
|
1308
|
+
const r = await new Promise((i, l) => {
|
|
1309
|
+
const s = new Image();
|
|
1310
|
+
s.onload = () => i(s), s.onerror = () => l(new Error("screenshot failed to load")), s.src = e;
|
|
1311
|
+
}), n = document.createElement("canvas");
|
|
1312
|
+
n.width = r.naturalWidth, n.height = r.naturalHeight;
|
|
1313
|
+
const o = n.getContext("2d");
|
|
1314
|
+
o.drawImage(r, 0, 0);
|
|
1315
|
+
const a = n.width / t.pageWidth, p = n.height / t.pageHeight, c = Math.min(a, p);
|
|
1316
|
+
o.lineCap = "round", o.lineJoin = "round";
|
|
1317
|
+
for (const i of t.shapes)
|
|
1318
|
+
switch (o.strokeStyle = i.color, o.fillStyle = i.color, o.beginPath(), i.type) {
|
|
1319
|
+
case "pen": {
|
|
1320
|
+
o.lineWidth = i.width * c, i.points.forEach((l, s) => s === 0 ? o.moveTo(l.x * a, l.y * p) : o.lineTo(l.x * a, l.y * p)), o.stroke();
|
|
1321
|
+
break;
|
|
1322
|
+
}
|
|
1323
|
+
case "rect": {
|
|
1324
|
+
o.lineWidth = i.strokeWidth * c, o.roundRect(i.x * a, i.y * p, i.width * a, i.height * p, 3 * c), o.stroke();
|
|
1325
|
+
break;
|
|
1326
|
+
}
|
|
1327
|
+
case "circle": {
|
|
1328
|
+
o.lineWidth = i.strokeWidth * c, o.ellipse(i.cx * a, i.cy * p, i.rx * a, i.ry * p, 0, 0, Math.PI * 2), o.stroke();
|
|
1329
|
+
break;
|
|
1330
|
+
}
|
|
1331
|
+
case "arrow": {
|
|
1332
|
+
const l = i.width * c, s = i.x1 * a, h = i.y1 * p, v = i.x2 * a, m = i.y2 * p;
|
|
1333
|
+
o.lineWidth = l, o.lineCap = "butt", o.moveTo(s, h), o.lineTo(v, m), o.stroke(), o.lineCap = "round";
|
|
1334
|
+
const b = Math.hypot(v - s, m - h) || 1, x = (v - s) / b, u = (m - h) / b, w = v + x * l, C = m + u * l, N = w - x * 10 * l, H = C - u * 10 * l;
|
|
1335
|
+
o.beginPath(), o.moveTo(w, C), o.lineTo(N - u * 3.5 * l, H + x * 3.5 * l), o.lineTo(N + u * 3.5 * l, H - x * 3.5 * l), o.closePath(), o.fill();
|
|
1336
|
+
break;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
return n.toDataURL("image/png");
|
|
1340
|
+
} catch (r) {
|
|
1341
|
+
return console.error("[ui-feedback-plugin] drawAnnotationsOnScreenshot failed:", r), e;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
const F = "ui-feedback-plugin";
|
|
1345
|
+
async function Oe(e) {
|
|
1244
1346
|
const { backend: t } = e;
|
|
1245
1347
|
if (t.provider === "firebase") {
|
|
1246
1348
|
const { FirebaseAdapter: r } = await import("./firebase-BGU5KpRU.mjs"), n = new r(t);
|
|
@@ -1260,112 +1362,114 @@ async function he(e) {
|
|
|
1260
1362
|
}
|
|
1261
1363
|
throw new Error("[ui-feedback-plugin] Unknown backend provider");
|
|
1262
1364
|
}
|
|
1263
|
-
function
|
|
1264
|
-
var
|
|
1265
|
-
if (customElements.get(
|
|
1365
|
+
function Pe(e) {
|
|
1366
|
+
var p;
|
|
1367
|
+
if (customElements.get(F))
|
|
1266
1368
|
return console.warn("[ui-feedback-plugin] Already initialized."), () => {
|
|
1267
1369
|
};
|
|
1268
|
-
const t = ((
|
|
1269
|
-
|
|
1370
|
+
const t = ((p = e.theme) == null ? void 0 : p.primaryColor) ?? "#6366f1", r = e.projectKey ?? "default", n = e.position ?? "bottom-right";
|
|
1371
|
+
k({ config: e });
|
|
1270
1372
|
class o extends HTMLElement {
|
|
1271
1373
|
constructor() {
|
|
1272
1374
|
super();
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1375
|
+
O(this, "shadow");
|
|
1376
|
+
O(this, "db");
|
|
1377
|
+
O(this, "screenshot");
|
|
1378
|
+
O(this, "unsubscribe", null);
|
|
1277
1379
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
1278
1380
|
}
|
|
1279
1381
|
async connectedCallback() {
|
|
1280
|
-
const
|
|
1281
|
-
|
|
1382
|
+
const l = document.createElement("style");
|
|
1383
|
+
l.textContent = xe(t), this.shadow.appendChild(l);
|
|
1282
1384
|
try {
|
|
1283
|
-
const
|
|
1284
|
-
this.db =
|
|
1285
|
-
} catch (
|
|
1286
|
-
console.error("[ui-feedback-plugin] Failed to initialise backend:",
|
|
1385
|
+
const s = await Oe(e);
|
|
1386
|
+
this.db = s.db, this.screenshot = s.screenshot;
|
|
1387
|
+
} catch (s) {
|
|
1388
|
+
console.error("[ui-feedback-plugin] Failed to initialise backend:", s);
|
|
1287
1389
|
return;
|
|
1288
1390
|
}
|
|
1289
1391
|
this.mount();
|
|
1290
1392
|
}
|
|
1291
1393
|
disconnectedCallback() {
|
|
1292
|
-
var
|
|
1293
|
-
(
|
|
1394
|
+
var l;
|
|
1395
|
+
(l = this.unsubscribe) == null || l.call(this);
|
|
1294
1396
|
}
|
|
1295
1397
|
mount() {
|
|
1296
|
-
const
|
|
1297
|
-
|
|
1398
|
+
const l = Q(window.location.href);
|
|
1399
|
+
Te(this.shadow, this.db, () => this.startAnnotation()), ve(
|
|
1298
1400
|
this.shadow,
|
|
1299
1401
|
n,
|
|
1300
1402
|
() => this.startAnnotation(),
|
|
1301
|
-
() =>
|
|
1302
|
-
), this.unsubscribe = this.db.subscribeToComments(
|
|
1303
|
-
|
|
1403
|
+
() => k({ panelOpen: !A().panelOpen })
|
|
1404
|
+
), this.unsubscribe = this.db.subscribeToComments(l, r, (s) => {
|
|
1405
|
+
k({ comments: s });
|
|
1304
1406
|
});
|
|
1305
1407
|
}
|
|
1306
1408
|
async startAnnotation() {
|
|
1307
|
-
let
|
|
1308
|
-
if (!
|
|
1409
|
+
let l = re();
|
|
1410
|
+
if (!l && (l = await we(this.shadow), !l))
|
|
1309
1411
|
return;
|
|
1310
|
-
|
|
1311
|
-
const
|
|
1312
|
-
if (!
|
|
1313
|
-
|
|
1412
|
+
k({ active: !0, panelOpen: !1 });
|
|
1413
|
+
const s = await Le(this.shadow);
|
|
1414
|
+
if (!s) {
|
|
1415
|
+
k({ active: !1 });
|
|
1314
1416
|
return;
|
|
1315
1417
|
}
|
|
1316
|
-
|
|
1418
|
+
k({ active: !1 }), this.showToast("Saving comment…", "info");
|
|
1317
1419
|
try {
|
|
1318
|
-
await this.saveComment(
|
|
1319
|
-
} catch (
|
|
1320
|
-
console.error("[ui-feedback-plugin] Failed to save comment:",
|
|
1420
|
+
await this.saveComment(l, s.text, s.shapes), this.showToast("Comment saved!", "success");
|
|
1421
|
+
} catch (h) {
|
|
1422
|
+
console.error("[ui-feedback-plugin] Failed to save comment:", h), this.showToast("Failed to save — check the browser console for details.", "error");
|
|
1321
1423
|
return;
|
|
1322
1424
|
}
|
|
1323
|
-
|
|
1324
|
-
}
|
|
1325
|
-
async saveComment(
|
|
1326
|
-
const
|
|
1327
|
-
shapes:
|
|
1328
|
-
|
|
1329
|
-
|
|
1425
|
+
k({ panelOpen: !0 });
|
|
1426
|
+
}
|
|
1427
|
+
async saveComment(l, s, h) {
|
|
1428
|
+
const v = Q(window.location.href), m = {
|
|
1429
|
+
shapes: h,
|
|
1430
|
+
// Shapes are in viewport coordinates; the screenshot covers just the visible viewport.
|
|
1431
|
+
pageWidth: document.documentElement.clientWidth,
|
|
1432
|
+
pageHeight: window.innerHeight
|
|
1330
1433
|
};
|
|
1331
1434
|
this.style.visibility = "hidden";
|
|
1332
|
-
let
|
|
1435
|
+
let b;
|
|
1333
1436
|
try {
|
|
1334
|
-
|
|
1437
|
+
b = await He();
|
|
1335
1438
|
} finally {
|
|
1336
1439
|
this.style.visibility = "";
|
|
1337
1440
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1441
|
+
b = await We(b, m);
|
|
1442
|
+
const x = {
|
|
1443
|
+
pageUrl: v,
|
|
1340
1444
|
projectKey: r,
|
|
1341
|
-
authorName:
|
|
1342
|
-
text:
|
|
1445
|
+
authorName: l,
|
|
1446
|
+
text: s,
|
|
1343
1447
|
screenshotUrl: "",
|
|
1344
|
-
annotation:
|
|
1448
|
+
annotation: m,
|
|
1345
1449
|
resolved: !1,
|
|
1346
1450
|
createdAt: Date.now()
|
|
1347
|
-
},
|
|
1348
|
-
await this.db.updateComment(
|
|
1349
|
-
}
|
|
1350
|
-
showToast(
|
|
1351
|
-
const
|
|
1352
|
-
|
|
1353
|
-
const
|
|
1354
|
-
|
|
1451
|
+
}, u = await this.db.addComment(x), w = await this.screenshot.uploadScreenshot(u, b);
|
|
1452
|
+
await this.db.updateComment(u, { screenshotUrl: w });
|
|
1453
|
+
}
|
|
1454
|
+
showToast(l, s) {
|
|
1455
|
+
const h = this.shadow.querySelector(".ufp-toast");
|
|
1456
|
+
h == null || h.remove();
|
|
1457
|
+
const v = { info: "#6366f1", success: "#10b981", error: "#ef4444" }, m = document.createElement("div");
|
|
1458
|
+
m.className = "ufp-toast", m.style.cssText = `
|
|
1355
1459
|
position:fixed;bottom:80px;left:50%;transform:translateX(-50%);
|
|
1356
|
-
background:${
|
|
1460
|
+
background:${v[s]};color:white;padding:10px 20px;border-radius:8px;
|
|
1357
1461
|
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
|
|
1358
1462
|
font-size:13px;font-weight:500;z-index:2147483647;
|
|
1359
1463
|
box-shadow:0 4px 12px rgba(0,0,0,0.2);pointer-events:none;
|
|
1360
1464
|
max-width:360px;text-align:center;
|
|
1361
|
-
`,
|
|
1465
|
+
`, m.textContent = l, this.shadow.appendChild(m), setTimeout(() => m.remove(), s === "error" ? 6e3 : 2500);
|
|
1362
1466
|
}
|
|
1363
1467
|
}
|
|
1364
|
-
customElements.define(
|
|
1365
|
-
const a = document.createElement(
|
|
1468
|
+
customElements.define(F, o);
|
|
1469
|
+
const a = document.createElement(F);
|
|
1366
1470
|
return document.body.appendChild(a), () => a.remove();
|
|
1367
1471
|
}
|
|
1368
1472
|
export {
|
|
1369
|
-
|
|
1473
|
+
Pe as initFeedbackPlugin
|
|
1370
1474
|
};
|
|
1371
1475
|
//# sourceMappingURL=ui-feedback-plugin.es.js.map
|