web-remarq 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -3
- package/dist/core/index.cjs +193 -41
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +76 -14
- package/dist/core/index.d.ts +76 -14
- package/dist/core/index.js +187 -40
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +557 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -3
- package/dist/index.d.ts +60 -3
- package/dist/index.js +556 -119
- package/dist/index.js.map +1 -1
- package/dist/web-remarq.global.global.js +556 -119
- package/dist/web-remarq.global.global.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65,79 +65,151 @@ function destroyViewportListener() {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// src/core/storage.ts
|
|
68
|
-
|
|
68
|
+
function migrateAnnotation(legacy) {
|
|
69
|
+
const rawStatus = legacy.status;
|
|
70
|
+
const status = rawStatus === "resolved" ? "verified" : rawStatus;
|
|
71
|
+
if (Array.isArray(legacy.lifecycle) && legacy.lifecycle.length > 0) {
|
|
72
|
+
return __spreadProps(__spreadValues({}, legacy), { status, lifecycle: legacy.lifecycle });
|
|
73
|
+
}
|
|
74
|
+
const createdTs = typeof legacy.timestamp === "number" ? legacy.timestamp : Date.now();
|
|
75
|
+
const lifecycle = [
|
|
76
|
+
{ type: "created", actor: "designer", timestamp: createdTs }
|
|
77
|
+
];
|
|
78
|
+
if (rawStatus === "resolved") {
|
|
79
|
+
lifecycle.push({ type: "migrated", actor: null, timestamp: Date.now() });
|
|
80
|
+
}
|
|
81
|
+
return __spreadProps(__spreadValues({}, legacy), { status, lifecycle });
|
|
82
|
+
}
|
|
69
83
|
var AnnotationStorage = class {
|
|
70
|
-
constructor() {
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
this.
|
|
74
|
-
|
|
84
|
+
constructor(adapter) {
|
|
85
|
+
this.adapter = adapter;
|
|
86
|
+
this.cache = [];
|
|
87
|
+
this.ready = this.init();
|
|
88
|
+
}
|
|
89
|
+
get isMemoryOnly() {
|
|
90
|
+
var _a3;
|
|
91
|
+
return (_a3 = this.adapter.isMemoryOnly) != null ? _a3 : false;
|
|
75
92
|
}
|
|
76
93
|
getAll() {
|
|
77
|
-
return [...this.
|
|
94
|
+
return [...this.cache];
|
|
78
95
|
}
|
|
79
96
|
getByRoute(route) {
|
|
80
|
-
return this.
|
|
97
|
+
return this.cache.filter((a) => a.route === route);
|
|
81
98
|
}
|
|
82
|
-
|
|
83
|
-
this.
|
|
84
|
-
this.save();
|
|
99
|
+
getById(id) {
|
|
100
|
+
return this.cache.find((a) => a.id === id);
|
|
85
101
|
}
|
|
86
|
-
|
|
87
|
-
this.
|
|
88
|
-
this.save();
|
|
102
|
+
async add(annotation) {
|
|
103
|
+
this.cache.push(annotation);
|
|
104
|
+
await this.adapter.save(annotation);
|
|
89
105
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.annotations[idx] = __spreadValues(__spreadValues({}, this.annotations[idx]), changes);
|
|
94
|
-
this.save();
|
|
95
|
-
}
|
|
106
|
+
async remove(id) {
|
|
107
|
+
this.cache = this.cache.filter((a) => a.id !== id);
|
|
108
|
+
await this.adapter.remove(id);
|
|
96
109
|
}
|
|
97
|
-
|
|
98
|
-
this.
|
|
99
|
-
|
|
110
|
+
async update(id, changes) {
|
|
111
|
+
const idx = this.cache.findIndex((a) => a.id === id);
|
|
112
|
+
if (idx === -1) return;
|
|
113
|
+
const updated = __spreadValues(__spreadValues({}, this.cache[idx]), changes);
|
|
114
|
+
this.cache[idx] = updated;
|
|
115
|
+
await this.adapter.save(updated);
|
|
116
|
+
}
|
|
117
|
+
async clearAll() {
|
|
118
|
+
this.cache = [];
|
|
119
|
+
await this.adapter.clear();
|
|
100
120
|
}
|
|
101
121
|
exportJSON() {
|
|
102
122
|
return {
|
|
103
123
|
version: 1,
|
|
104
|
-
annotations: [...this.
|
|
124
|
+
annotations: [...this.cache]
|
|
105
125
|
};
|
|
106
126
|
}
|
|
107
|
-
importJSON(data) {
|
|
108
|
-
this.
|
|
127
|
+
async importJSON(data) {
|
|
128
|
+
this.cache = data.annotations.map(migrateAnnotation);
|
|
109
129
|
this.migrateViewportBuckets();
|
|
110
|
-
this.
|
|
130
|
+
await this.adapter.clear();
|
|
131
|
+
for (const ann of this.cache) {
|
|
132
|
+
await this.adapter.save(ann);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async init() {
|
|
136
|
+
const data = await this.adapter.load();
|
|
137
|
+
if (data) {
|
|
138
|
+
this.cache = data.annotations.map(migrateAnnotation);
|
|
139
|
+
this.migrateViewportBuckets();
|
|
140
|
+
}
|
|
111
141
|
}
|
|
112
142
|
migrateViewportBuckets() {
|
|
113
|
-
for (const ann of this.
|
|
143
|
+
for (const ann of this.cache) {
|
|
114
144
|
if (ann.viewportBucket == null && ann.viewport) {
|
|
115
145
|
const width = parseInt(ann.viewport.split("x")[0], 10);
|
|
116
146
|
ann.viewportBucket = toBucket(width);
|
|
117
147
|
}
|
|
118
148
|
}
|
|
119
149
|
}
|
|
120
|
-
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// src/core/local-storage-adapter.ts
|
|
153
|
+
var STORAGE_KEY = "remarq:annotations";
|
|
154
|
+
var LocalStorageAdapter = class {
|
|
155
|
+
constructor() {
|
|
156
|
+
this.isMemoryOnly = false;
|
|
157
|
+
this.extraFields = {};
|
|
158
|
+
this.memoryStore = null;
|
|
159
|
+
}
|
|
160
|
+
async load() {
|
|
161
|
+
if (this.isMemoryOnly) return this.memoryStore;
|
|
121
162
|
try {
|
|
122
163
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
123
|
-
if (raw)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
164
|
+
if (!raw) return null;
|
|
165
|
+
const parsed = JSON.parse(raw);
|
|
166
|
+
const _a3 = parsed, { version, annotations } = _a3, rest = __objRest(_a3, ["version", "annotations"]);
|
|
167
|
+
this.extraFields = rest;
|
|
168
|
+
const store = {
|
|
169
|
+
version: 1,
|
|
170
|
+
annotations: Array.isArray(annotations) ? annotations : []
|
|
171
|
+
};
|
|
172
|
+
this.memoryStore = store;
|
|
173
|
+
return store;
|
|
130
174
|
} catch (e) {
|
|
131
175
|
this.isMemoryOnly = true;
|
|
176
|
+
return this.memoryStore;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async save(annotation) {
|
|
180
|
+
const store = await this.ensureStore();
|
|
181
|
+
const idx = store.annotations.findIndex((a) => a.id === annotation.id);
|
|
182
|
+
if (idx === -1) {
|
|
183
|
+
store.annotations.push(annotation);
|
|
184
|
+
} else {
|
|
185
|
+
store.annotations[idx] = annotation;
|
|
132
186
|
}
|
|
187
|
+
this.persist(store);
|
|
188
|
+
}
|
|
189
|
+
async remove(id) {
|
|
190
|
+
const store = await this.ensureStore();
|
|
191
|
+
store.annotations = store.annotations.filter((a) => a.id !== id);
|
|
192
|
+
this.persist(store);
|
|
193
|
+
}
|
|
194
|
+
async clear() {
|
|
195
|
+
const store = await this.ensureStore();
|
|
196
|
+
store.annotations = [];
|
|
197
|
+
this.persist(store);
|
|
133
198
|
}
|
|
134
|
-
|
|
199
|
+
async ensureStore() {
|
|
200
|
+
if (this.memoryStore) return this.memoryStore;
|
|
201
|
+
const loaded = await this.load();
|
|
202
|
+
if (loaded) return loaded;
|
|
203
|
+
this.memoryStore = { version: 1, annotations: [] };
|
|
204
|
+
return this.memoryStore;
|
|
205
|
+
}
|
|
206
|
+
persist(store) {
|
|
135
207
|
if (this.isMemoryOnly) return;
|
|
136
208
|
try {
|
|
137
209
|
const data = __spreadProps(__spreadValues({
|
|
138
210
|
version: 1
|
|
139
211
|
}, this.extraFields), {
|
|
140
|
-
annotations:
|
|
212
|
+
annotations: store.annotations
|
|
141
213
|
});
|
|
142
214
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
143
215
|
} catch (e) {
|
|
@@ -533,7 +605,16 @@ function generateAgentExport(annotations, viewportBucket) {
|
|
|
533
605
|
status: ann.status,
|
|
534
606
|
timestamp: ann.timestamp,
|
|
535
607
|
source: resolveSource(ann.fingerprint),
|
|
536
|
-
searchHints: buildSearchHints(ann.fingerprint)
|
|
608
|
+
searchHints: buildSearchHints(ann.fingerprint),
|
|
609
|
+
lifecycle: ann.lifecycle.map((ev) => {
|
|
610
|
+
const out = {
|
|
611
|
+
type: ev.type,
|
|
612
|
+
actor: ev.actor,
|
|
613
|
+
timestamp: ev.timestamp
|
|
614
|
+
};
|
|
615
|
+
if (ev.reason !== void 0) out.reason = ev.reason;
|
|
616
|
+
return out;
|
|
617
|
+
})
|
|
537
618
|
}));
|
|
538
619
|
return {
|
|
539
620
|
version: 1,
|
|
@@ -543,6 +624,67 @@ function generateAgentExport(annotations, viewportBucket) {
|
|
|
543
624
|
};
|
|
544
625
|
}
|
|
545
626
|
|
|
627
|
+
// src/core/lifecycle.ts
|
|
628
|
+
var InvalidTransitionError = class extends Error {
|
|
629
|
+
constructor(from, action) {
|
|
630
|
+
super(`Cannot ${action} from status "${from}"`);
|
|
631
|
+
this.name = "InvalidTransitionError";
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
var ACTION_TO_EVENT = {
|
|
635
|
+
acknowledge: "acknowledged",
|
|
636
|
+
claimFix: "fix_claimed",
|
|
637
|
+
verify: "verified",
|
|
638
|
+
reject: "rejected",
|
|
639
|
+
dismiss: "dismissed",
|
|
640
|
+
reopen: "reopened"
|
|
641
|
+
};
|
|
642
|
+
var DEFAULT_ACTOR_BY_EVENT = {
|
|
643
|
+
created: "designer",
|
|
644
|
+
acknowledged: "developer",
|
|
645
|
+
fix_claimed: "agent",
|
|
646
|
+
verified: "developer",
|
|
647
|
+
rejected: "developer",
|
|
648
|
+
dismissed: "developer",
|
|
649
|
+
reopened: "developer",
|
|
650
|
+
migrated: null
|
|
651
|
+
};
|
|
652
|
+
function createEvent(type, opts = {}) {
|
|
653
|
+
var _a3, _b;
|
|
654
|
+
const event = {
|
|
655
|
+
type,
|
|
656
|
+
actor: (_a3 = opts.actor) != null ? _a3 : DEFAULT_ACTOR_BY_EVENT[type],
|
|
657
|
+
timestamp: (_b = opts.timestamp) != null ? _b : Date.now()
|
|
658
|
+
};
|
|
659
|
+
if (opts.actorName !== void 0) event.actorName = opts.actorName;
|
|
660
|
+
if (opts.reason !== void 0) event.reason = opts.reason;
|
|
661
|
+
return event;
|
|
662
|
+
}
|
|
663
|
+
function nextStatus(from, action) {
|
|
664
|
+
switch (action) {
|
|
665
|
+
case "acknowledge":
|
|
666
|
+
return from === "pending" ? "in_progress" : null;
|
|
667
|
+
case "claimFix":
|
|
668
|
+
return from === "pending" || from === "in_progress" ? "fixed_unverified" : null;
|
|
669
|
+
case "verify":
|
|
670
|
+
return from === "fixed_unverified" || from === "in_progress" ? "verified" : null;
|
|
671
|
+
case "reject":
|
|
672
|
+
return from === "fixed_unverified" ? "pending" : null;
|
|
673
|
+
case "dismiss":
|
|
674
|
+
return from === "pending" || from === "in_progress" || from === "fixed_unverified" ? "dismissed" : null;
|
|
675
|
+
case "reopen":
|
|
676
|
+
return from === "dismissed" || from === "verified" ? "pending" : null;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
function transition(annotation, action, opts = {}) {
|
|
680
|
+
const next = nextStatus(annotation.status, action);
|
|
681
|
+
if (next === null) {
|
|
682
|
+
throw new InvalidTransitionError(annotation.status, action);
|
|
683
|
+
}
|
|
684
|
+
const event = createEvent(ACTION_TO_EVENT[action], opts);
|
|
685
|
+
return { status: next, event };
|
|
686
|
+
}
|
|
687
|
+
|
|
546
688
|
// src/ui/styles.ts
|
|
547
689
|
var STYLES_ID = "data-remarq-styles";
|
|
548
690
|
var CSS = `
|
|
@@ -557,6 +699,11 @@ var CSS = `
|
|
|
557
699
|
--remarq-resolved: #22c55e;
|
|
558
700
|
--remarq-overlay: rgba(59, 130, 246, 0.15);
|
|
559
701
|
--remarq-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
702
|
+
--remarq-status-pending: #f97316;
|
|
703
|
+
--remarq-status-in-progress: #eab308;
|
|
704
|
+
--remarq-status-fixed-unverified: #3b82f6;
|
|
705
|
+
--remarq-status-verified: #22c55e;
|
|
706
|
+
--remarq-status-dismissed: #6b7280;
|
|
560
707
|
}
|
|
561
708
|
|
|
562
709
|
[data-remarq-theme="dark"] {
|
|
@@ -570,6 +717,11 @@ var CSS = `
|
|
|
570
717
|
--remarq-resolved: #4ade80;
|
|
571
718
|
--remarq-overlay: rgba(96, 165, 250, 0.15);
|
|
572
719
|
--remarq-shadow: 0 4px 12px rgba(0,0,0,0.4);
|
|
720
|
+
--remarq-status-pending: #fb923c;
|
|
721
|
+
--remarq-status-in-progress: #facc15;
|
|
722
|
+
--remarq-status-fixed-unverified: #60a5fa;
|
|
723
|
+
--remarq-status-verified: #4ade80;
|
|
724
|
+
--remarq-status-dismissed: #9ca3af;
|
|
573
725
|
}
|
|
574
726
|
|
|
575
727
|
.remarq-toolbar {
|
|
@@ -613,19 +765,29 @@ var CSS = `
|
|
|
613
765
|
|
|
614
766
|
.remarq-badge {
|
|
615
767
|
position: absolute;
|
|
616
|
-
top: -
|
|
617
|
-
right: -
|
|
618
|
-
|
|
619
|
-
height:
|
|
620
|
-
padding: 0
|
|
621
|
-
border-radius:
|
|
768
|
+
top: -6px;
|
|
769
|
+
right: -6px;
|
|
770
|
+
width: 18px;
|
|
771
|
+
height: 18px;
|
|
772
|
+
padding: 0;
|
|
773
|
+
border-radius: 50%;
|
|
622
774
|
background: var(--remarq-pending);
|
|
623
775
|
color: #ffffff;
|
|
624
776
|
font-size: 10px;
|
|
625
777
|
font-weight: 600;
|
|
778
|
+
line-height: 1;
|
|
626
779
|
display: flex;
|
|
627
780
|
align-items: center;
|
|
628
781
|
justify-content: center;
|
|
782
|
+
box-sizing: border-box;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
.remarq-toolbar-badge--verification {
|
|
786
|
+
top: auto;
|
|
787
|
+
bottom: -6px;
|
|
788
|
+
right: -6px;
|
|
789
|
+
background: var(--remarq-status-fixed-unverified);
|
|
790
|
+
cursor: pointer;
|
|
629
791
|
}
|
|
630
792
|
|
|
631
793
|
.remarq-overlay {
|
|
@@ -675,8 +837,11 @@ var CSS = `
|
|
|
675
837
|
}
|
|
676
838
|
|
|
677
839
|
.remarq-marker:hover { transform: scale(1.2); }
|
|
678
|
-
.remarq-marker
|
|
679
|
-
.remarq-marker
|
|
840
|
+
.remarq-marker--pending { background: var(--remarq-status-pending); }
|
|
841
|
+
.remarq-marker--in-progress { background: var(--remarq-status-in-progress); }
|
|
842
|
+
.remarq-marker--fixed-unverified { background: var(--remarq-status-fixed-unverified); }
|
|
843
|
+
.remarq-marker--verified { background: var(--remarq-status-verified); opacity: 0.7; }
|
|
844
|
+
.remarq-marker--dismissed { background: var(--remarq-status-dismissed); opacity: 0.5; }
|
|
680
845
|
|
|
681
846
|
.remarq-popup {
|
|
682
847
|
position: absolute;
|
|
@@ -721,14 +886,30 @@ var CSS = `
|
|
|
721
886
|
|
|
722
887
|
.remarq-popup-actions {
|
|
723
888
|
display: flex;
|
|
724
|
-
|
|
725
|
-
gap:
|
|
889
|
+
flex-direction: column;
|
|
890
|
+
gap: 6px;
|
|
726
891
|
padding: 8px 12px;
|
|
727
892
|
border-top: 1px solid var(--remarq-border);
|
|
728
893
|
}
|
|
729
894
|
|
|
895
|
+
.remarq-popup-actions-row {
|
|
896
|
+
display: flex;
|
|
897
|
+
flex-wrap: wrap;
|
|
898
|
+
gap: 6px;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.remarq-popup-actions-row--transitions {
|
|
902
|
+
justify-content: flex-start;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
.remarq-popup-actions-row--utility {
|
|
906
|
+
justify-content: flex-end;
|
|
907
|
+
padding-top: 6px;
|
|
908
|
+
border-top: 1px dashed var(--remarq-border);
|
|
909
|
+
}
|
|
910
|
+
|
|
730
911
|
.remarq-popup-actions button {
|
|
731
|
-
padding:
|
|
912
|
+
padding: 5px 12px;
|
|
732
913
|
border: 1px solid var(--remarq-border);
|
|
733
914
|
border-radius: 4px;
|
|
734
915
|
background: var(--remarq-bg);
|
|
@@ -743,6 +924,19 @@ var CSS = `
|
|
|
743
924
|
color: #ffffff;
|
|
744
925
|
}
|
|
745
926
|
|
|
927
|
+
.remarq-popup-utility-btn {
|
|
928
|
+
font-size: 11px !important;
|
|
929
|
+
padding: 3px 10px !important;
|
|
930
|
+
color: var(--remarq-text-secondary) !important;
|
|
931
|
+
background: transparent !important;
|
|
932
|
+
border-color: transparent !important;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
.remarq-popup-utility-btn:hover {
|
|
936
|
+
background: var(--remarq-bg-secondary) !important;
|
|
937
|
+
color: var(--remarq-text) !important;
|
|
938
|
+
}
|
|
939
|
+
|
|
746
940
|
.remarq-detached-panel {
|
|
747
941
|
position: fixed;
|
|
748
942
|
z-index: 2147483646;
|
|
@@ -1001,6 +1195,51 @@ var CSS = `
|
|
|
1001
1195
|
color: var(--remarq-text-secondary);
|
|
1002
1196
|
margin-top: 4px;
|
|
1003
1197
|
}
|
|
1198
|
+
|
|
1199
|
+
.remarq-popup-history {
|
|
1200
|
+
margin-top: 8px;
|
|
1201
|
+
font-size: 12px;
|
|
1202
|
+
color: var(--remarq-text-secondary);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
.remarq-popup-history summary {
|
|
1206
|
+
cursor: pointer;
|
|
1207
|
+
padding: 4px 0;
|
|
1208
|
+
user-select: none;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
.remarq-popup-history-list {
|
|
1212
|
+
list-style: none;
|
|
1213
|
+
margin: 4px 0 0 0;
|
|
1214
|
+
padding: 0;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
.remarq-popup-history-list li {
|
|
1218
|
+
padding: 2px 0;
|
|
1219
|
+
font-size: 11px;
|
|
1220
|
+
line-height: 1.4;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.remarq-popup-reason {
|
|
1224
|
+
width: 100%;
|
|
1225
|
+
min-height: 50px;
|
|
1226
|
+
margin-bottom: 8px;
|
|
1227
|
+
padding: 6px;
|
|
1228
|
+
border: 1px solid var(--remarq-border);
|
|
1229
|
+
border-radius: 4px;
|
|
1230
|
+
background: var(--remarq-bg-secondary);
|
|
1231
|
+
color: var(--remarq-text);
|
|
1232
|
+
font-family: inherit;
|
|
1233
|
+
font-size: 12px;
|
|
1234
|
+
resize: vertical;
|
|
1235
|
+
box-sizing: border-box;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
.remarq-popup-reason-row {
|
|
1239
|
+
display: flex;
|
|
1240
|
+
justify-content: flex-end;
|
|
1241
|
+
gap: 8px;
|
|
1242
|
+
}
|
|
1004
1243
|
`;
|
|
1005
1244
|
function injectStyles() {
|
|
1006
1245
|
if (document.querySelector(`style[${STYLES_ID}]`)) return;
|
|
@@ -1108,8 +1347,19 @@ var Toolbar = class {
|
|
|
1108
1347
|
this.inspectBtn = this.createButton("inspect", ICONS.inspect, () => callbacks.onInspect());
|
|
1109
1348
|
this.badgeEl = document.createElement("span");
|
|
1110
1349
|
this.badgeEl.className = "remarq-badge";
|
|
1350
|
+
this.badgeEl.title = "Needs attention";
|
|
1111
1351
|
this.badgeEl.style.display = "none";
|
|
1112
1352
|
this.inspectBtn.appendChild(this.badgeEl);
|
|
1353
|
+
this.verificationBadgeEl = document.createElement("span");
|
|
1354
|
+
this.verificationBadgeEl.className = "remarq-badge remarq-toolbar-badge--verification";
|
|
1355
|
+
this.verificationBadgeEl.title = "Pending your verification";
|
|
1356
|
+
this.verificationBadgeEl.style.display = "none";
|
|
1357
|
+
this.verificationBadgeEl.addEventListener("click", (e) => {
|
|
1358
|
+
var _a3;
|
|
1359
|
+
e.stopPropagation();
|
|
1360
|
+
(_a3 = callbacks.onVerificationBadgeClick) == null ? void 0 : _a3.call(callbacks);
|
|
1361
|
+
});
|
|
1362
|
+
this.inspectBtn.appendChild(this.verificationBadgeEl);
|
|
1113
1363
|
this.spacingBtn = this.createButton("spacing", ICONS.spacing, () => callbacks.onSpacingToggle());
|
|
1114
1364
|
this.spacingBtn.disabled = true;
|
|
1115
1365
|
const copyBtn = this.createButton("copy", ICONS.copy, () => callbacks.onCopy());
|
|
@@ -1156,6 +1406,10 @@ var Toolbar = class {
|
|
|
1156
1406
|
this.badgeEl.textContent = String(count);
|
|
1157
1407
|
this.badgeEl.style.display = count > 0 ? "flex" : "none";
|
|
1158
1408
|
}
|
|
1409
|
+
setVerificationBadgeCount(count) {
|
|
1410
|
+
this.verificationBadgeEl.textContent = String(count);
|
|
1411
|
+
this.verificationBadgeEl.style.display = count > 0 ? "flex" : "none";
|
|
1412
|
+
}
|
|
1159
1413
|
getFileInput() {
|
|
1160
1414
|
return this.fileInput;
|
|
1161
1415
|
}
|
|
@@ -1639,6 +1893,47 @@ var SpacingOverlay = class {
|
|
|
1639
1893
|
};
|
|
1640
1894
|
|
|
1641
1895
|
// src/ui/popup.ts
|
|
1896
|
+
var STATUS_LABEL = {
|
|
1897
|
+
pending: "Pending",
|
|
1898
|
+
in_progress: "In progress",
|
|
1899
|
+
fixed_unverified: "Fix claimed",
|
|
1900
|
+
verified: "Verified",
|
|
1901
|
+
dismissed: "Dismissed"
|
|
1902
|
+
};
|
|
1903
|
+
var EVENT_LABEL = {
|
|
1904
|
+
created: "Created",
|
|
1905
|
+
acknowledged: "In progress",
|
|
1906
|
+
fix_claimed: "Fix claimed",
|
|
1907
|
+
verified: "Verified",
|
|
1908
|
+
rejected: "Rejected",
|
|
1909
|
+
dismissed: "Dismissed",
|
|
1910
|
+
reopened: "Reopened",
|
|
1911
|
+
migrated: "Migrated"
|
|
1912
|
+
};
|
|
1913
|
+
function actionsForStatus(status) {
|
|
1914
|
+
switch (status) {
|
|
1915
|
+
case "pending":
|
|
1916
|
+
return [
|
|
1917
|
+
{ label: "Acknowledge", action: "acknowledge", primary: true },
|
|
1918
|
+
{ label: "Dismiss", action: "dismiss", needsReason: true }
|
|
1919
|
+
];
|
|
1920
|
+
case "in_progress":
|
|
1921
|
+
return [
|
|
1922
|
+
{ label: "Mark verified", action: "verify", primary: true },
|
|
1923
|
+
{ label: "Dismiss", action: "dismiss", needsReason: true }
|
|
1924
|
+
];
|
|
1925
|
+
case "fixed_unverified":
|
|
1926
|
+
return [
|
|
1927
|
+
{ label: "Verify", action: "verify", primary: true },
|
|
1928
|
+
{ label: "Reject", action: "reject", needsReason: true },
|
|
1929
|
+
{ label: "Dismiss", action: "dismiss", needsReason: true }
|
|
1930
|
+
];
|
|
1931
|
+
case "verified":
|
|
1932
|
+
return [{ label: "Reopen", action: "reopen" }];
|
|
1933
|
+
case "dismissed":
|
|
1934
|
+
return [{ label: "Reopen", action: "reopen" }];
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1642
1937
|
var POPUP_WIDTH = 300;
|
|
1643
1938
|
var POPUP_MARGIN = 8;
|
|
1644
1939
|
var Popup = class {
|
|
@@ -1647,6 +1942,7 @@ var Popup = class {
|
|
|
1647
1942
|
this.popupEl = null;
|
|
1648
1943
|
this.keyHandler = null;
|
|
1649
1944
|
this.outsideClickHandler = null;
|
|
1945
|
+
this.pendingEditFlush = null;
|
|
1650
1946
|
}
|
|
1651
1947
|
show(info, position, onSubmit, onCancel) {
|
|
1652
1948
|
this.hide();
|
|
@@ -1731,7 +2027,7 @@ var Popup = class {
|
|
|
1731
2027
|
popup2.className = "remarq-popup";
|
|
1732
2028
|
const header = document.createElement("div");
|
|
1733
2029
|
header.className = "remarq-popup-header";
|
|
1734
|
-
header.textContent = `<${info.tag}>${info.text ? ` "${info.text}"` : ""} [${info.status}]`;
|
|
2030
|
+
header.textContent = `<${info.tag}>${info.text ? ` "${info.text}"` : ""} [${STATUS_LABEL[info.status]}]`;
|
|
1735
2031
|
const body = document.createElement("div");
|
|
1736
2032
|
body.className = "remarq-popup-body";
|
|
1737
2033
|
const makeCommentEl = () => {
|
|
@@ -1743,38 +2039,10 @@ var Popup = class {
|
|
|
1743
2039
|
return el;
|
|
1744
2040
|
};
|
|
1745
2041
|
body.appendChild(makeCommentEl());
|
|
2042
|
+
body.appendChild(this.buildLifecycleViewer(info.lifecycle));
|
|
1746
2043
|
const actions = document.createElement("div");
|
|
1747
2044
|
actions.className = "remarq-popup-actions";
|
|
1748
|
-
|
|
1749
|
-
const resolveBtn = document.createElement("button");
|
|
1750
|
-
resolveBtn.className = "remarq-primary";
|
|
1751
|
-
resolveBtn.textContent = "Resolve";
|
|
1752
|
-
resolveBtn.addEventListener("click", () => {
|
|
1753
|
-
this.hide();
|
|
1754
|
-
callbacks.onResolve();
|
|
1755
|
-
});
|
|
1756
|
-
actions.appendChild(resolveBtn);
|
|
1757
|
-
}
|
|
1758
|
-
const copyBtn = document.createElement("button");
|
|
1759
|
-
copyBtn.textContent = "Copy";
|
|
1760
|
-
copyBtn.addEventListener("click", () => {
|
|
1761
|
-
callbacks.onCopy();
|
|
1762
|
-
});
|
|
1763
|
-
actions.appendChild(copyBtn);
|
|
1764
|
-
const deleteBtn = document.createElement("button");
|
|
1765
|
-
deleteBtn.textContent = "Delete";
|
|
1766
|
-
deleteBtn.addEventListener("click", () => {
|
|
1767
|
-
this.hide();
|
|
1768
|
-
callbacks.onDelete();
|
|
1769
|
-
});
|
|
1770
|
-
actions.appendChild(deleteBtn);
|
|
1771
|
-
const closeBtn = document.createElement("button");
|
|
1772
|
-
closeBtn.textContent = "Close";
|
|
1773
|
-
closeBtn.addEventListener("click", () => {
|
|
1774
|
-
this.hide();
|
|
1775
|
-
callbacks.onClose();
|
|
1776
|
-
});
|
|
1777
|
-
actions.appendChild(closeBtn);
|
|
2045
|
+
this.renderActionButtons(actions, info, callbacks);
|
|
1778
2046
|
popup2.appendChild(header);
|
|
1779
2047
|
popup2.appendChild(body);
|
|
1780
2048
|
popup2.appendChild(actions);
|
|
@@ -1801,7 +2069,103 @@ var Popup = class {
|
|
|
1801
2069
|
document.addEventListener("mousedown", this.outsideClickHandler);
|
|
1802
2070
|
}, 0);
|
|
1803
2071
|
}
|
|
2072
|
+
buildLifecycleViewer(lifecycle) {
|
|
2073
|
+
var _a3, _b;
|
|
2074
|
+
const details = document.createElement("details");
|
|
2075
|
+
details.className = "remarq-popup-history";
|
|
2076
|
+
const summary = document.createElement("summary");
|
|
2077
|
+
summary.textContent = `History (${lifecycle.length})`;
|
|
2078
|
+
details.appendChild(summary);
|
|
2079
|
+
const list = document.createElement("ul");
|
|
2080
|
+
list.className = "remarq-popup-history-list";
|
|
2081
|
+
for (const ev of lifecycle) {
|
|
2082
|
+
const li = document.createElement("li");
|
|
2083
|
+
const when = new Date(ev.timestamp).toLocaleString();
|
|
2084
|
+
const who = (_a3 = ev.actor) != null ? _a3 : "system";
|
|
2085
|
+
const what = (_b = EVENT_LABEL[ev.type]) != null ? _b : ev.type;
|
|
2086
|
+
let text = `${when} \xB7 ${who} \xB7 ${what}`;
|
|
2087
|
+
if (ev.reason) text += ` \u2014 ${ev.reason}`;
|
|
2088
|
+
li.textContent = text;
|
|
2089
|
+
list.appendChild(li);
|
|
2090
|
+
}
|
|
2091
|
+
details.appendChild(list);
|
|
2092
|
+
return details;
|
|
2093
|
+
}
|
|
2094
|
+
renderActionButtons(container, info, callbacks) {
|
|
2095
|
+
container.replaceChildren();
|
|
2096
|
+
const transitions = document.createElement("div");
|
|
2097
|
+
transitions.className = "remarq-popup-actions-row remarq-popup-actions-row--transitions";
|
|
2098
|
+
for (const def of actionsForStatus(info.status)) {
|
|
2099
|
+
const btn = document.createElement("button");
|
|
2100
|
+
btn.textContent = def.label;
|
|
2101
|
+
if (def.primary) btn.className = "remarq-primary";
|
|
2102
|
+
btn.addEventListener("click", () => {
|
|
2103
|
+
if (def.needsReason) {
|
|
2104
|
+
this.showReasonInput(container, info, callbacks, def);
|
|
2105
|
+
} else {
|
|
2106
|
+
this.hide();
|
|
2107
|
+
callbacks.onTransition(def.action);
|
|
2108
|
+
}
|
|
2109
|
+
});
|
|
2110
|
+
transitions.appendChild(btn);
|
|
2111
|
+
}
|
|
2112
|
+
container.appendChild(transitions);
|
|
2113
|
+
const utility = document.createElement("div");
|
|
2114
|
+
utility.className = "remarq-popup-actions-row remarq-popup-actions-row--utility";
|
|
2115
|
+
const copyBtn = document.createElement("button");
|
|
2116
|
+
copyBtn.className = "remarq-popup-utility-btn";
|
|
2117
|
+
copyBtn.textContent = "Copy";
|
|
2118
|
+
copyBtn.addEventListener("click", () => callbacks.onCopy());
|
|
2119
|
+
utility.appendChild(copyBtn);
|
|
2120
|
+
const deleteBtn = document.createElement("button");
|
|
2121
|
+
deleteBtn.className = "remarq-popup-utility-btn";
|
|
2122
|
+
deleteBtn.textContent = "Delete";
|
|
2123
|
+
deleteBtn.addEventListener("click", () => {
|
|
2124
|
+
this.hide();
|
|
2125
|
+
callbacks.onDelete();
|
|
2126
|
+
});
|
|
2127
|
+
utility.appendChild(deleteBtn);
|
|
2128
|
+
const closeBtn = document.createElement("button");
|
|
2129
|
+
closeBtn.className = "remarq-popup-utility-btn";
|
|
2130
|
+
closeBtn.textContent = "Close";
|
|
2131
|
+
closeBtn.addEventListener("click", () => {
|
|
2132
|
+
this.hide();
|
|
2133
|
+
callbacks.onClose();
|
|
2134
|
+
});
|
|
2135
|
+
utility.appendChild(closeBtn);
|
|
2136
|
+
container.appendChild(utility);
|
|
2137
|
+
}
|
|
2138
|
+
showReasonInput(container, info, callbacks, def) {
|
|
2139
|
+
container.replaceChildren();
|
|
2140
|
+
const textarea = document.createElement("textarea");
|
|
2141
|
+
textarea.placeholder = `Reason for ${def.label.toLowerCase()} (optional)\u2026`;
|
|
2142
|
+
textarea.className = "remarq-popup-reason";
|
|
2143
|
+
container.appendChild(textarea);
|
|
2144
|
+
const row = document.createElement("div");
|
|
2145
|
+
row.className = "remarq-popup-reason-row";
|
|
2146
|
+
const cancel = document.createElement("button");
|
|
2147
|
+
cancel.textContent = "Cancel";
|
|
2148
|
+
cancel.addEventListener("click", () => {
|
|
2149
|
+
this.renderActionButtons(container, info, callbacks);
|
|
2150
|
+
});
|
|
2151
|
+
const submit = document.createElement("button");
|
|
2152
|
+
submit.className = "remarq-primary";
|
|
2153
|
+
submit.textContent = "Submit";
|
|
2154
|
+
submit.addEventListener("click", () => {
|
|
2155
|
+
const reason = textarea.value.trim() || void 0;
|
|
2156
|
+
this.hide();
|
|
2157
|
+
callbacks.onTransition(def.action, reason);
|
|
2158
|
+
});
|
|
2159
|
+
row.appendChild(cancel);
|
|
2160
|
+
row.appendChild(submit);
|
|
2161
|
+
container.appendChild(row);
|
|
2162
|
+
textarea.focus();
|
|
2163
|
+
}
|
|
1804
2164
|
hide() {
|
|
2165
|
+
if (this.pendingEditFlush) {
|
|
2166
|
+
this.pendingEditFlush();
|
|
2167
|
+
this.pendingEditFlush = null;
|
|
2168
|
+
}
|
|
1805
2169
|
if (this.popupEl) {
|
|
1806
2170
|
this.popupEl.remove();
|
|
1807
2171
|
this.popupEl = null;
|
|
@@ -1836,12 +2200,8 @@ var Popup = class {
|
|
|
1836
2200
|
commentEl.replaceWith(textarea);
|
|
1837
2201
|
textarea.focus();
|
|
1838
2202
|
textarea.selectionStart = textarea.value.length;
|
|
1839
|
-
const
|
|
1840
|
-
|
|
1841
|
-
if (newComment && newComment !== info.comment) {
|
|
1842
|
-
info.comment = newComment;
|
|
1843
|
-
callbacks.onEdit(newComment);
|
|
1844
|
-
}
|
|
2203
|
+
const restoreView = () => {
|
|
2204
|
+
if (!textarea.isConnected) return;
|
|
1845
2205
|
const restored = document.createElement("div");
|
|
1846
2206
|
restored.textContent = info.comment;
|
|
1847
2207
|
restored.style.cursor = "pointer";
|
|
@@ -1849,26 +2209,33 @@ var Popup = class {
|
|
|
1849
2209
|
restored.addEventListener("click", () => this.enterEditMode(restored, info, callbacks));
|
|
1850
2210
|
textarea.replaceWith(restored);
|
|
1851
2211
|
};
|
|
2212
|
+
const commitEdit = () => {
|
|
2213
|
+
this.pendingEditFlush = null;
|
|
2214
|
+
const newComment = textarea.value.trim();
|
|
2215
|
+
if (newComment && newComment !== info.comment) {
|
|
2216
|
+
info.comment = newComment;
|
|
2217
|
+
callbacks.onEdit(newComment);
|
|
2218
|
+
}
|
|
2219
|
+
restoreView();
|
|
2220
|
+
};
|
|
2221
|
+
const cancelEdit = () => {
|
|
2222
|
+
this.pendingEditFlush = null;
|
|
2223
|
+
restoreView();
|
|
2224
|
+
};
|
|
2225
|
+
this.pendingEditFlush = commitEdit;
|
|
1852
2226
|
textarea.addEventListener("keydown", (e) => {
|
|
1853
2227
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
1854
2228
|
e.preventDefault();
|
|
1855
|
-
|
|
2229
|
+
commitEdit();
|
|
1856
2230
|
}
|
|
1857
2231
|
if (e.key === "Escape") {
|
|
1858
2232
|
e.stopPropagation();
|
|
1859
|
-
|
|
1860
|
-
restored.textContent = info.comment;
|
|
1861
|
-
restored.style.cursor = "pointer";
|
|
1862
|
-
restored.title = "Click to edit";
|
|
1863
|
-
restored.addEventListener("click", () => this.enterEditMode(restored, info, callbacks));
|
|
1864
|
-
textarea.replaceWith(restored);
|
|
2233
|
+
cancelEdit();
|
|
1865
2234
|
}
|
|
1866
2235
|
});
|
|
1867
2236
|
textarea.addEventListener("blur", () => {
|
|
1868
2237
|
setTimeout(() => {
|
|
1869
|
-
if (textarea.isConnected)
|
|
1870
|
-
saveEdit();
|
|
1871
|
-
}
|
|
2238
|
+
if (textarea.isConnected) commitEdit();
|
|
1872
2239
|
}, 50);
|
|
1873
2240
|
});
|
|
1874
2241
|
}
|
|
@@ -1896,6 +2263,16 @@ var Popup = class {
|
|
|
1896
2263
|
};
|
|
1897
2264
|
|
|
1898
2265
|
// src/ui/markers.ts
|
|
2266
|
+
var STATUS_COLOR = {
|
|
2267
|
+
pending: "var(--remarq-status-pending)",
|
|
2268
|
+
in_progress: "var(--remarq-status-in-progress)",
|
|
2269
|
+
fixed_unverified: "var(--remarq-status-fixed-unverified)",
|
|
2270
|
+
verified: "var(--remarq-status-verified)",
|
|
2271
|
+
dismissed: "var(--remarq-status-dismissed)"
|
|
2272
|
+
};
|
|
2273
|
+
function statusClass(status) {
|
|
2274
|
+
return `remarq-marker--${status.replace("_", "-")}`;
|
|
2275
|
+
}
|
|
1899
2276
|
var MarkerManager = class {
|
|
1900
2277
|
constructor(container, onClick) {
|
|
1901
2278
|
this.container = container;
|
|
@@ -1908,7 +2285,7 @@ var MarkerManager = class {
|
|
|
1908
2285
|
addMarker(annotation, target) {
|
|
1909
2286
|
this.counter++;
|
|
1910
2287
|
const markerEl = document.createElement("div");
|
|
1911
|
-
markerEl.className =
|
|
2288
|
+
markerEl.className = `remarq-marker ${statusClass(annotation.status)}`;
|
|
1912
2289
|
markerEl.setAttribute("data-status", annotation.status);
|
|
1913
2290
|
markerEl.setAttribute("data-annotation-id", annotation.id);
|
|
1914
2291
|
markerEl.textContent = String(this.counter);
|
|
@@ -1934,7 +2311,17 @@ var MarkerManager = class {
|
|
|
1934
2311
|
const entry = this.markers.get(id);
|
|
1935
2312
|
if (entry) {
|
|
1936
2313
|
entry.annotation.status = status;
|
|
2314
|
+
entry.markerEl.className = `remarq-marker ${statusClass(status)}`;
|
|
1937
2315
|
entry.markerEl.setAttribute("data-status", status);
|
|
2316
|
+
this.applyOutline(entry.target, status);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
scrollToMarker(id) {
|
|
2320
|
+
const entry = this.markers.get(id);
|
|
2321
|
+
if (!entry) return;
|
|
2322
|
+
try {
|
|
2323
|
+
entry.target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
2324
|
+
} catch (e) {
|
|
1938
2325
|
}
|
|
1939
2326
|
}
|
|
1940
2327
|
clear() {
|
|
@@ -1953,7 +2340,7 @@ var MarkerManager = class {
|
|
|
1953
2340
|
this.clear();
|
|
1954
2341
|
}
|
|
1955
2342
|
applyOutline(target, status) {
|
|
1956
|
-
const color = status
|
|
2343
|
+
const color = STATUS_COLOR[status];
|
|
1957
2344
|
target.style.outline = `2px solid ${color}`;
|
|
1958
2345
|
target.style.outlineOffset = "2px";
|
|
1959
2346
|
}
|
|
@@ -2300,8 +2687,18 @@ function refreshMarkers() {
|
|
|
2300
2687
|
markers.addMarker(ann, el);
|
|
2301
2688
|
}
|
|
2302
2689
|
detachedPanel.update(otherBreakpoint, detached);
|
|
2303
|
-
const
|
|
2304
|
-
|
|
2690
|
+
const needsAttention = anns.filter(
|
|
2691
|
+
(a) => a.status === "pending" || a.status === "in_progress"
|
|
2692
|
+
).length;
|
|
2693
|
+
const needsVerification = anns.filter((a) => a.status === "fixed_unverified").length;
|
|
2694
|
+
toolbar.setBadgeCount(needsAttention);
|
|
2695
|
+
toolbar.setVerificationBadgeCount(needsVerification);
|
|
2696
|
+
}
|
|
2697
|
+
function jumpToFirstUnverified() {
|
|
2698
|
+
if (!storage || !markers) return;
|
|
2699
|
+
const ann = storage.getByRoute(currentRoute()).find((a) => a.status === "fixed_unverified");
|
|
2700
|
+
if (!ann) return;
|
|
2701
|
+
markers.scrollToMarker(ann.id);
|
|
2305
2702
|
}
|
|
2306
2703
|
function scheduleRefresh() {
|
|
2307
2704
|
if (refreshScheduled) return;
|
|
@@ -2334,6 +2731,7 @@ function handleInspectClick(e) {
|
|
|
2334
2731
|
classFilter: options.classFilter,
|
|
2335
2732
|
dataAttribute: options.dataAttribute
|
|
2336
2733
|
});
|
|
2734
|
+
const now = Date.now();
|
|
2337
2735
|
const ann = {
|
|
2338
2736
|
id: generateId(),
|
|
2339
2737
|
comment,
|
|
@@ -2341,8 +2739,9 @@ function handleInspectClick(e) {
|
|
|
2341
2739
|
route: currentRoute(),
|
|
2342
2740
|
viewport: `${window.innerWidth}x${window.innerHeight}`,
|
|
2343
2741
|
viewportBucket: toBucket(window.innerWidth),
|
|
2344
|
-
timestamp:
|
|
2345
|
-
status: "pending"
|
|
2742
|
+
timestamp: now,
|
|
2743
|
+
status: "pending",
|
|
2744
|
+
lifecycle: [{ type: "created", actor: "designer", timestamp: now }]
|
|
2346
2745
|
};
|
|
2347
2746
|
cacheElement(ann.id, target);
|
|
2348
2747
|
storage.add(ann);
|
|
@@ -2434,7 +2833,8 @@ function handleMarkerClick(annotationId) {
|
|
|
2434
2833
|
tag: ann.fingerprint.tagName,
|
|
2435
2834
|
text: (_a3 = ann.fingerprint.textContent) != null ? _a3 : "",
|
|
2436
2835
|
comment: ann.comment,
|
|
2437
|
-
status: ann.status
|
|
2836
|
+
status: ann.status,
|
|
2837
|
+
lifecycle: ann.lifecycle
|
|
2438
2838
|
},
|
|
2439
2839
|
{
|
|
2440
2840
|
top: window.scrollY + rect.bottom + 8,
|
|
@@ -2442,9 +2842,8 @@ function handleMarkerClick(annotationId) {
|
|
|
2442
2842
|
anchorBottom: window.scrollY + rect.top - 8
|
|
2443
2843
|
},
|
|
2444
2844
|
{
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
refreshMarkers();
|
|
2845
|
+
onTransition: (action, reason) => {
|
|
2846
|
+
applyTransition(ann.id, action, reason ? { reason } : void 0);
|
|
2448
2847
|
},
|
|
2449
2848
|
onDelete: () => {
|
|
2450
2849
|
elementCache.delete(ann.id);
|
|
@@ -2458,12 +2857,14 @@ function handleMarkerClick(annotationId) {
|
|
|
2458
2857
|
refreshMarkers();
|
|
2459
2858
|
},
|
|
2460
2859
|
onCopy: () => {
|
|
2461
|
-
|
|
2860
|
+
var _a4;
|
|
2861
|
+
const fresh = (_a4 = storage.getById(ann.id)) != null ? _a4 : ann;
|
|
2862
|
+
const fp = fresh.fingerprint;
|
|
2462
2863
|
const lines = [
|
|
2463
|
-
`[${
|
|
2864
|
+
`[${fresh.status}] "${fresh.comment}"`,
|
|
2464
2865
|
`Element: <${fp.tagName}>${fp.textContent ? ` "${fp.textContent}"` : ""}`,
|
|
2465
|
-
`Route: ${
|
|
2466
|
-
`Viewport: ${
|
|
2866
|
+
`Route: ${fresh.route}`,
|
|
2867
|
+
`Viewport: ${fresh.viewportBucket}px`
|
|
2467
2868
|
];
|
|
2468
2869
|
if (fp.sourceLocation) lines.push(`Source: ${fp.sourceLocation}`);
|
|
2469
2870
|
navigator.clipboard.writeText(lines.join("\n")).then(() => {
|
|
@@ -2598,6 +2999,16 @@ function copyAgentToClipboard() {
|
|
|
2598
2999
|
console.warn("[web-remarq] Clipboard write failed");
|
|
2599
3000
|
});
|
|
2600
3001
|
}
|
|
3002
|
+
function applyTransition(id, action, opts = {}) {
|
|
3003
|
+
if (!storage) return;
|
|
3004
|
+
const ann = storage.getById(id);
|
|
3005
|
+
if (!ann) return;
|
|
3006
|
+
const { status, event } = transition(ann, action, opts);
|
|
3007
|
+
const lifecycle = [...ann.lifecycle, event];
|
|
3008
|
+
storage.update(id, { status, lifecycle });
|
|
3009
|
+
markers == null ? void 0 : markers.updateStatus(id, status);
|
|
3010
|
+
refreshMarkers();
|
|
3011
|
+
}
|
|
2601
3012
|
function setupMutationObserver() {
|
|
2602
3013
|
mutationObserver = new MutationObserver((mutations) => {
|
|
2603
3014
|
let hasExternalMutation = false;
|
|
@@ -2617,18 +3028,18 @@ function setupMutationObserver() {
|
|
|
2617
3028
|
}
|
|
2618
3029
|
var WebRemarq = {
|
|
2619
3030
|
init(opts) {
|
|
2620
|
-
var _a3;
|
|
3031
|
+
var _a3, _b;
|
|
2621
3032
|
if (initialized) return;
|
|
2622
3033
|
options = opts != null ? opts : {};
|
|
2623
3034
|
try {
|
|
2624
3035
|
injectStyles();
|
|
2625
|
-
storage = new AnnotationStorage();
|
|
3036
|
+
storage = new AnnotationStorage((_a3 = options.storage) != null ? _a3 : new LocalStorageAdapter());
|
|
2626
3037
|
themeManager = new ThemeManager(document.body, options.theme);
|
|
2627
3038
|
overlay = new Overlay(themeManager.container);
|
|
2628
3039
|
spacingOverlay = new SpacingOverlay(themeManager.container);
|
|
2629
3040
|
popup = new Popup(themeManager.container);
|
|
2630
3041
|
markers = new MarkerManager(themeManager.container, handleMarkerClick);
|
|
2631
|
-
const position = (
|
|
3042
|
+
const position = (_b = options.position) != null ? _b : "bottom-right";
|
|
2632
3043
|
detachedPanel = new DetachedPanel(themeManager.container, (id) => {
|
|
2633
3044
|
elementCache.delete(id);
|
|
2634
3045
|
storage.remove(id);
|
|
@@ -2659,11 +3070,9 @@ var WebRemarq = {
|
|
|
2659
3070
|
showToast(themeManager.container, "All annotations cleared");
|
|
2660
3071
|
},
|
|
2661
3072
|
onThemeToggle: () => themeManager.toggle(),
|
|
2662
|
-
onHelp: () => showShortcutsModal(themeManager.container)
|
|
3073
|
+
onHelp: () => showShortcutsModal(themeManager.container),
|
|
3074
|
+
onVerificationBadgeClick: jumpToFirstUnverified
|
|
2663
3075
|
}, position);
|
|
2664
|
-
if (storage.isMemoryOnly) {
|
|
2665
|
-
toolbar.setMemoryWarning(true);
|
|
2666
|
-
}
|
|
2667
3076
|
routeObserver = new RouteObserver();
|
|
2668
3077
|
unsubRoute = routeObserver.onChange(() => refreshMarkers());
|
|
2669
3078
|
document.addEventListener("click", handleInspectClick, true);
|
|
@@ -2671,8 +3080,13 @@ var WebRemarq = {
|
|
|
2671
3080
|
document.addEventListener("keydown", handleInspectKeydown);
|
|
2672
3081
|
setupMutationObserver();
|
|
2673
3082
|
initViewportListener(() => refreshMarkers());
|
|
3083
|
+
storage.ready.then(() => {
|
|
3084
|
+
if (storage.isMemoryOnly) {
|
|
3085
|
+
toolbar.setMemoryWarning(true);
|
|
3086
|
+
}
|
|
3087
|
+
refreshMarkers();
|
|
3088
|
+
});
|
|
2674
3089
|
console.debug(`[web-remarq] Initialized on route: ${currentRoute()}`);
|
|
2675
|
-
refreshMarkers();
|
|
2676
3090
|
initialized = true;
|
|
2677
3091
|
} catch (err) {
|
|
2678
3092
|
console.error("[web-remarq] Init failed:", err);
|
|
@@ -2751,9 +3165,32 @@ var WebRemarq = {
|
|
|
2751
3165
|
elementCache.clear();
|
|
2752
3166
|
storage == null ? void 0 : storage.clearAll();
|
|
2753
3167
|
if (initialized) refreshMarkers();
|
|
3168
|
+
},
|
|
3169
|
+
acknowledge(id, opts) {
|
|
3170
|
+
applyTransition(id, "acknowledge", opts);
|
|
3171
|
+
},
|
|
3172
|
+
claimFix(id, opts) {
|
|
3173
|
+
applyTransition(id, "claimFix", opts);
|
|
3174
|
+
},
|
|
3175
|
+
verify(id, opts) {
|
|
3176
|
+
applyTransition(id, "verify", opts);
|
|
3177
|
+
},
|
|
3178
|
+
reject(id, opts) {
|
|
3179
|
+
applyTransition(id, "reject", opts);
|
|
3180
|
+
},
|
|
3181
|
+
dismiss(id, opts) {
|
|
3182
|
+
applyTransition(id, "dismiss", opts);
|
|
3183
|
+
},
|
|
3184
|
+
reopen(id, opts) {
|
|
3185
|
+
applyTransition(id, "reopen", opts);
|
|
3186
|
+
},
|
|
3187
|
+
/** @deprecated Use verify() instead. */
|
|
3188
|
+
markResolved(id) {
|
|
3189
|
+
applyTransition(id, "verify");
|
|
2754
3190
|
}
|
|
2755
3191
|
};
|
|
2756
3192
|
export {
|
|
3193
|
+
LocalStorageAdapter,
|
|
2757
3194
|
WebRemarq
|
|
2758
3195
|
};
|
|
2759
3196
|
//# sourceMappingURL=index.js.map
|