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.cjs
CHANGED
|
@@ -49,6 +49,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
49
49
|
// src/index.ts
|
|
50
50
|
var src_exports = {};
|
|
51
51
|
__export(src_exports, {
|
|
52
|
+
LocalStorageAdapter: () => LocalStorageAdapter,
|
|
52
53
|
WebRemarq: () => WebRemarq
|
|
53
54
|
});
|
|
54
55
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -88,79 +89,151 @@ function destroyViewportListener() {
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
// src/core/storage.ts
|
|
91
|
-
|
|
92
|
+
function migrateAnnotation(legacy) {
|
|
93
|
+
const rawStatus = legacy.status;
|
|
94
|
+
const status = rawStatus === "resolved" ? "verified" : rawStatus;
|
|
95
|
+
if (Array.isArray(legacy.lifecycle) && legacy.lifecycle.length > 0) {
|
|
96
|
+
return __spreadProps(__spreadValues({}, legacy), { status, lifecycle: legacy.lifecycle });
|
|
97
|
+
}
|
|
98
|
+
const createdTs = typeof legacy.timestamp === "number" ? legacy.timestamp : Date.now();
|
|
99
|
+
const lifecycle = [
|
|
100
|
+
{ type: "created", actor: "designer", timestamp: createdTs }
|
|
101
|
+
];
|
|
102
|
+
if (rawStatus === "resolved") {
|
|
103
|
+
lifecycle.push({ type: "migrated", actor: null, timestamp: Date.now() });
|
|
104
|
+
}
|
|
105
|
+
return __spreadProps(__spreadValues({}, legacy), { status, lifecycle });
|
|
106
|
+
}
|
|
92
107
|
var AnnotationStorage = class {
|
|
93
|
-
constructor() {
|
|
94
|
-
this.
|
|
95
|
-
this.
|
|
96
|
-
this.
|
|
97
|
-
|
|
108
|
+
constructor(adapter) {
|
|
109
|
+
this.adapter = adapter;
|
|
110
|
+
this.cache = [];
|
|
111
|
+
this.ready = this.init();
|
|
112
|
+
}
|
|
113
|
+
get isMemoryOnly() {
|
|
114
|
+
var _a3;
|
|
115
|
+
return (_a3 = this.adapter.isMemoryOnly) != null ? _a3 : false;
|
|
98
116
|
}
|
|
99
117
|
getAll() {
|
|
100
|
-
return [...this.
|
|
118
|
+
return [...this.cache];
|
|
101
119
|
}
|
|
102
120
|
getByRoute(route) {
|
|
103
|
-
return this.
|
|
121
|
+
return this.cache.filter((a) => a.route === route);
|
|
104
122
|
}
|
|
105
|
-
|
|
106
|
-
this.
|
|
107
|
-
this.save();
|
|
123
|
+
getById(id) {
|
|
124
|
+
return this.cache.find((a) => a.id === id);
|
|
108
125
|
}
|
|
109
|
-
|
|
110
|
-
this.
|
|
111
|
-
this.save();
|
|
126
|
+
async add(annotation) {
|
|
127
|
+
this.cache.push(annotation);
|
|
128
|
+
await this.adapter.save(annotation);
|
|
112
129
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
this.annotations[idx] = __spreadValues(__spreadValues({}, this.annotations[idx]), changes);
|
|
117
|
-
this.save();
|
|
118
|
-
}
|
|
130
|
+
async remove(id) {
|
|
131
|
+
this.cache = this.cache.filter((a) => a.id !== id);
|
|
132
|
+
await this.adapter.remove(id);
|
|
119
133
|
}
|
|
120
|
-
|
|
121
|
-
this.
|
|
122
|
-
|
|
134
|
+
async update(id, changes) {
|
|
135
|
+
const idx = this.cache.findIndex((a) => a.id === id);
|
|
136
|
+
if (idx === -1) return;
|
|
137
|
+
const updated = __spreadValues(__spreadValues({}, this.cache[idx]), changes);
|
|
138
|
+
this.cache[idx] = updated;
|
|
139
|
+
await this.adapter.save(updated);
|
|
140
|
+
}
|
|
141
|
+
async clearAll() {
|
|
142
|
+
this.cache = [];
|
|
143
|
+
await this.adapter.clear();
|
|
123
144
|
}
|
|
124
145
|
exportJSON() {
|
|
125
146
|
return {
|
|
126
147
|
version: 1,
|
|
127
|
-
annotations: [...this.
|
|
148
|
+
annotations: [...this.cache]
|
|
128
149
|
};
|
|
129
150
|
}
|
|
130
|
-
importJSON(data) {
|
|
131
|
-
this.
|
|
151
|
+
async importJSON(data) {
|
|
152
|
+
this.cache = data.annotations.map(migrateAnnotation);
|
|
132
153
|
this.migrateViewportBuckets();
|
|
133
|
-
this.
|
|
154
|
+
await this.adapter.clear();
|
|
155
|
+
for (const ann of this.cache) {
|
|
156
|
+
await this.adapter.save(ann);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async init() {
|
|
160
|
+
const data = await this.adapter.load();
|
|
161
|
+
if (data) {
|
|
162
|
+
this.cache = data.annotations.map(migrateAnnotation);
|
|
163
|
+
this.migrateViewportBuckets();
|
|
164
|
+
}
|
|
134
165
|
}
|
|
135
166
|
migrateViewportBuckets() {
|
|
136
|
-
for (const ann of this.
|
|
167
|
+
for (const ann of this.cache) {
|
|
137
168
|
if (ann.viewportBucket == null && ann.viewport) {
|
|
138
169
|
const width = parseInt(ann.viewport.split("x")[0], 10);
|
|
139
170
|
ann.viewportBucket = toBucket(width);
|
|
140
171
|
}
|
|
141
172
|
}
|
|
142
173
|
}
|
|
143
|
-
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/core/local-storage-adapter.ts
|
|
177
|
+
var STORAGE_KEY = "remarq:annotations";
|
|
178
|
+
var LocalStorageAdapter = class {
|
|
179
|
+
constructor() {
|
|
180
|
+
this.isMemoryOnly = false;
|
|
181
|
+
this.extraFields = {};
|
|
182
|
+
this.memoryStore = null;
|
|
183
|
+
}
|
|
184
|
+
async load() {
|
|
185
|
+
if (this.isMemoryOnly) return this.memoryStore;
|
|
144
186
|
try {
|
|
145
187
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
146
|
-
if (raw)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
188
|
+
if (!raw) return null;
|
|
189
|
+
const parsed = JSON.parse(raw);
|
|
190
|
+
const _a3 = parsed, { version, annotations } = _a3, rest = __objRest(_a3, ["version", "annotations"]);
|
|
191
|
+
this.extraFields = rest;
|
|
192
|
+
const store = {
|
|
193
|
+
version: 1,
|
|
194
|
+
annotations: Array.isArray(annotations) ? annotations : []
|
|
195
|
+
};
|
|
196
|
+
this.memoryStore = store;
|
|
197
|
+
return store;
|
|
153
198
|
} catch (e) {
|
|
154
199
|
this.isMemoryOnly = true;
|
|
200
|
+
return this.memoryStore;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async save(annotation) {
|
|
204
|
+
const store = await this.ensureStore();
|
|
205
|
+
const idx = store.annotations.findIndex((a) => a.id === annotation.id);
|
|
206
|
+
if (idx === -1) {
|
|
207
|
+
store.annotations.push(annotation);
|
|
208
|
+
} else {
|
|
209
|
+
store.annotations[idx] = annotation;
|
|
155
210
|
}
|
|
211
|
+
this.persist(store);
|
|
212
|
+
}
|
|
213
|
+
async remove(id) {
|
|
214
|
+
const store = await this.ensureStore();
|
|
215
|
+
store.annotations = store.annotations.filter((a) => a.id !== id);
|
|
216
|
+
this.persist(store);
|
|
217
|
+
}
|
|
218
|
+
async clear() {
|
|
219
|
+
const store = await this.ensureStore();
|
|
220
|
+
store.annotations = [];
|
|
221
|
+
this.persist(store);
|
|
156
222
|
}
|
|
157
|
-
|
|
223
|
+
async ensureStore() {
|
|
224
|
+
if (this.memoryStore) return this.memoryStore;
|
|
225
|
+
const loaded = await this.load();
|
|
226
|
+
if (loaded) return loaded;
|
|
227
|
+
this.memoryStore = { version: 1, annotations: [] };
|
|
228
|
+
return this.memoryStore;
|
|
229
|
+
}
|
|
230
|
+
persist(store) {
|
|
158
231
|
if (this.isMemoryOnly) return;
|
|
159
232
|
try {
|
|
160
233
|
const data = __spreadProps(__spreadValues({
|
|
161
234
|
version: 1
|
|
162
235
|
}, this.extraFields), {
|
|
163
|
-
annotations:
|
|
236
|
+
annotations: store.annotations
|
|
164
237
|
});
|
|
165
238
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
|
|
166
239
|
} catch (e) {
|
|
@@ -556,7 +629,16 @@ function generateAgentExport(annotations, viewportBucket) {
|
|
|
556
629
|
status: ann.status,
|
|
557
630
|
timestamp: ann.timestamp,
|
|
558
631
|
source: resolveSource(ann.fingerprint),
|
|
559
|
-
searchHints: buildSearchHints(ann.fingerprint)
|
|
632
|
+
searchHints: buildSearchHints(ann.fingerprint),
|
|
633
|
+
lifecycle: ann.lifecycle.map((ev) => {
|
|
634
|
+
const out = {
|
|
635
|
+
type: ev.type,
|
|
636
|
+
actor: ev.actor,
|
|
637
|
+
timestamp: ev.timestamp
|
|
638
|
+
};
|
|
639
|
+
if (ev.reason !== void 0) out.reason = ev.reason;
|
|
640
|
+
return out;
|
|
641
|
+
})
|
|
560
642
|
}));
|
|
561
643
|
return {
|
|
562
644
|
version: 1,
|
|
@@ -566,6 +648,67 @@ function generateAgentExport(annotations, viewportBucket) {
|
|
|
566
648
|
};
|
|
567
649
|
}
|
|
568
650
|
|
|
651
|
+
// src/core/lifecycle.ts
|
|
652
|
+
var InvalidTransitionError = class extends Error {
|
|
653
|
+
constructor(from, action) {
|
|
654
|
+
super(`Cannot ${action} from status "${from}"`);
|
|
655
|
+
this.name = "InvalidTransitionError";
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
var ACTION_TO_EVENT = {
|
|
659
|
+
acknowledge: "acknowledged",
|
|
660
|
+
claimFix: "fix_claimed",
|
|
661
|
+
verify: "verified",
|
|
662
|
+
reject: "rejected",
|
|
663
|
+
dismiss: "dismissed",
|
|
664
|
+
reopen: "reopened"
|
|
665
|
+
};
|
|
666
|
+
var DEFAULT_ACTOR_BY_EVENT = {
|
|
667
|
+
created: "designer",
|
|
668
|
+
acknowledged: "developer",
|
|
669
|
+
fix_claimed: "agent",
|
|
670
|
+
verified: "developer",
|
|
671
|
+
rejected: "developer",
|
|
672
|
+
dismissed: "developer",
|
|
673
|
+
reopened: "developer",
|
|
674
|
+
migrated: null
|
|
675
|
+
};
|
|
676
|
+
function createEvent(type, opts = {}) {
|
|
677
|
+
var _a3, _b;
|
|
678
|
+
const event = {
|
|
679
|
+
type,
|
|
680
|
+
actor: (_a3 = opts.actor) != null ? _a3 : DEFAULT_ACTOR_BY_EVENT[type],
|
|
681
|
+
timestamp: (_b = opts.timestamp) != null ? _b : Date.now()
|
|
682
|
+
};
|
|
683
|
+
if (opts.actorName !== void 0) event.actorName = opts.actorName;
|
|
684
|
+
if (opts.reason !== void 0) event.reason = opts.reason;
|
|
685
|
+
return event;
|
|
686
|
+
}
|
|
687
|
+
function nextStatus(from, action) {
|
|
688
|
+
switch (action) {
|
|
689
|
+
case "acknowledge":
|
|
690
|
+
return from === "pending" ? "in_progress" : null;
|
|
691
|
+
case "claimFix":
|
|
692
|
+
return from === "pending" || from === "in_progress" ? "fixed_unverified" : null;
|
|
693
|
+
case "verify":
|
|
694
|
+
return from === "fixed_unverified" || from === "in_progress" ? "verified" : null;
|
|
695
|
+
case "reject":
|
|
696
|
+
return from === "fixed_unverified" ? "pending" : null;
|
|
697
|
+
case "dismiss":
|
|
698
|
+
return from === "pending" || from === "in_progress" || from === "fixed_unverified" ? "dismissed" : null;
|
|
699
|
+
case "reopen":
|
|
700
|
+
return from === "dismissed" || from === "verified" ? "pending" : null;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function transition(annotation, action, opts = {}) {
|
|
704
|
+
const next = nextStatus(annotation.status, action);
|
|
705
|
+
if (next === null) {
|
|
706
|
+
throw new InvalidTransitionError(annotation.status, action);
|
|
707
|
+
}
|
|
708
|
+
const event = createEvent(ACTION_TO_EVENT[action], opts);
|
|
709
|
+
return { status: next, event };
|
|
710
|
+
}
|
|
711
|
+
|
|
569
712
|
// src/ui/styles.ts
|
|
570
713
|
var STYLES_ID = "data-remarq-styles";
|
|
571
714
|
var CSS = `
|
|
@@ -580,6 +723,11 @@ var CSS = `
|
|
|
580
723
|
--remarq-resolved: #22c55e;
|
|
581
724
|
--remarq-overlay: rgba(59, 130, 246, 0.15);
|
|
582
725
|
--remarq-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
726
|
+
--remarq-status-pending: #f97316;
|
|
727
|
+
--remarq-status-in-progress: #eab308;
|
|
728
|
+
--remarq-status-fixed-unverified: #3b82f6;
|
|
729
|
+
--remarq-status-verified: #22c55e;
|
|
730
|
+
--remarq-status-dismissed: #6b7280;
|
|
583
731
|
}
|
|
584
732
|
|
|
585
733
|
[data-remarq-theme="dark"] {
|
|
@@ -593,6 +741,11 @@ var CSS = `
|
|
|
593
741
|
--remarq-resolved: #4ade80;
|
|
594
742
|
--remarq-overlay: rgba(96, 165, 250, 0.15);
|
|
595
743
|
--remarq-shadow: 0 4px 12px rgba(0,0,0,0.4);
|
|
744
|
+
--remarq-status-pending: #fb923c;
|
|
745
|
+
--remarq-status-in-progress: #facc15;
|
|
746
|
+
--remarq-status-fixed-unverified: #60a5fa;
|
|
747
|
+
--remarq-status-verified: #4ade80;
|
|
748
|
+
--remarq-status-dismissed: #9ca3af;
|
|
596
749
|
}
|
|
597
750
|
|
|
598
751
|
.remarq-toolbar {
|
|
@@ -636,19 +789,29 @@ var CSS = `
|
|
|
636
789
|
|
|
637
790
|
.remarq-badge {
|
|
638
791
|
position: absolute;
|
|
639
|
-
top: -
|
|
640
|
-
right: -
|
|
641
|
-
|
|
642
|
-
height:
|
|
643
|
-
padding: 0
|
|
644
|
-
border-radius:
|
|
792
|
+
top: -6px;
|
|
793
|
+
right: -6px;
|
|
794
|
+
width: 18px;
|
|
795
|
+
height: 18px;
|
|
796
|
+
padding: 0;
|
|
797
|
+
border-radius: 50%;
|
|
645
798
|
background: var(--remarq-pending);
|
|
646
799
|
color: #ffffff;
|
|
647
800
|
font-size: 10px;
|
|
648
801
|
font-weight: 600;
|
|
802
|
+
line-height: 1;
|
|
649
803
|
display: flex;
|
|
650
804
|
align-items: center;
|
|
651
805
|
justify-content: center;
|
|
806
|
+
box-sizing: border-box;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.remarq-toolbar-badge--verification {
|
|
810
|
+
top: auto;
|
|
811
|
+
bottom: -6px;
|
|
812
|
+
right: -6px;
|
|
813
|
+
background: var(--remarq-status-fixed-unverified);
|
|
814
|
+
cursor: pointer;
|
|
652
815
|
}
|
|
653
816
|
|
|
654
817
|
.remarq-overlay {
|
|
@@ -698,8 +861,11 @@ var CSS = `
|
|
|
698
861
|
}
|
|
699
862
|
|
|
700
863
|
.remarq-marker:hover { transform: scale(1.2); }
|
|
701
|
-
.remarq-marker
|
|
702
|
-
.remarq-marker
|
|
864
|
+
.remarq-marker--pending { background: var(--remarq-status-pending); }
|
|
865
|
+
.remarq-marker--in-progress { background: var(--remarq-status-in-progress); }
|
|
866
|
+
.remarq-marker--fixed-unverified { background: var(--remarq-status-fixed-unverified); }
|
|
867
|
+
.remarq-marker--verified { background: var(--remarq-status-verified); opacity: 0.7; }
|
|
868
|
+
.remarq-marker--dismissed { background: var(--remarq-status-dismissed); opacity: 0.5; }
|
|
703
869
|
|
|
704
870
|
.remarq-popup {
|
|
705
871
|
position: absolute;
|
|
@@ -744,14 +910,30 @@ var CSS = `
|
|
|
744
910
|
|
|
745
911
|
.remarq-popup-actions {
|
|
746
912
|
display: flex;
|
|
747
|
-
|
|
748
|
-
gap:
|
|
913
|
+
flex-direction: column;
|
|
914
|
+
gap: 6px;
|
|
749
915
|
padding: 8px 12px;
|
|
750
916
|
border-top: 1px solid var(--remarq-border);
|
|
751
917
|
}
|
|
752
918
|
|
|
919
|
+
.remarq-popup-actions-row {
|
|
920
|
+
display: flex;
|
|
921
|
+
flex-wrap: wrap;
|
|
922
|
+
gap: 6px;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
.remarq-popup-actions-row--transitions {
|
|
926
|
+
justify-content: flex-start;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.remarq-popup-actions-row--utility {
|
|
930
|
+
justify-content: flex-end;
|
|
931
|
+
padding-top: 6px;
|
|
932
|
+
border-top: 1px dashed var(--remarq-border);
|
|
933
|
+
}
|
|
934
|
+
|
|
753
935
|
.remarq-popup-actions button {
|
|
754
|
-
padding:
|
|
936
|
+
padding: 5px 12px;
|
|
755
937
|
border: 1px solid var(--remarq-border);
|
|
756
938
|
border-radius: 4px;
|
|
757
939
|
background: var(--remarq-bg);
|
|
@@ -766,6 +948,19 @@ var CSS = `
|
|
|
766
948
|
color: #ffffff;
|
|
767
949
|
}
|
|
768
950
|
|
|
951
|
+
.remarq-popup-utility-btn {
|
|
952
|
+
font-size: 11px !important;
|
|
953
|
+
padding: 3px 10px !important;
|
|
954
|
+
color: var(--remarq-text-secondary) !important;
|
|
955
|
+
background: transparent !important;
|
|
956
|
+
border-color: transparent !important;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.remarq-popup-utility-btn:hover {
|
|
960
|
+
background: var(--remarq-bg-secondary) !important;
|
|
961
|
+
color: var(--remarq-text) !important;
|
|
962
|
+
}
|
|
963
|
+
|
|
769
964
|
.remarq-detached-panel {
|
|
770
965
|
position: fixed;
|
|
771
966
|
z-index: 2147483646;
|
|
@@ -1024,6 +1219,51 @@ var CSS = `
|
|
|
1024
1219
|
color: var(--remarq-text-secondary);
|
|
1025
1220
|
margin-top: 4px;
|
|
1026
1221
|
}
|
|
1222
|
+
|
|
1223
|
+
.remarq-popup-history {
|
|
1224
|
+
margin-top: 8px;
|
|
1225
|
+
font-size: 12px;
|
|
1226
|
+
color: var(--remarq-text-secondary);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
.remarq-popup-history summary {
|
|
1230
|
+
cursor: pointer;
|
|
1231
|
+
padding: 4px 0;
|
|
1232
|
+
user-select: none;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.remarq-popup-history-list {
|
|
1236
|
+
list-style: none;
|
|
1237
|
+
margin: 4px 0 0 0;
|
|
1238
|
+
padding: 0;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
.remarq-popup-history-list li {
|
|
1242
|
+
padding: 2px 0;
|
|
1243
|
+
font-size: 11px;
|
|
1244
|
+
line-height: 1.4;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
.remarq-popup-reason {
|
|
1248
|
+
width: 100%;
|
|
1249
|
+
min-height: 50px;
|
|
1250
|
+
margin-bottom: 8px;
|
|
1251
|
+
padding: 6px;
|
|
1252
|
+
border: 1px solid var(--remarq-border);
|
|
1253
|
+
border-radius: 4px;
|
|
1254
|
+
background: var(--remarq-bg-secondary);
|
|
1255
|
+
color: var(--remarq-text);
|
|
1256
|
+
font-family: inherit;
|
|
1257
|
+
font-size: 12px;
|
|
1258
|
+
resize: vertical;
|
|
1259
|
+
box-sizing: border-box;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
.remarq-popup-reason-row {
|
|
1263
|
+
display: flex;
|
|
1264
|
+
justify-content: flex-end;
|
|
1265
|
+
gap: 8px;
|
|
1266
|
+
}
|
|
1027
1267
|
`;
|
|
1028
1268
|
function injectStyles() {
|
|
1029
1269
|
if (document.querySelector(`style[${STYLES_ID}]`)) return;
|
|
@@ -1131,8 +1371,19 @@ var Toolbar = class {
|
|
|
1131
1371
|
this.inspectBtn = this.createButton("inspect", ICONS.inspect, () => callbacks.onInspect());
|
|
1132
1372
|
this.badgeEl = document.createElement("span");
|
|
1133
1373
|
this.badgeEl.className = "remarq-badge";
|
|
1374
|
+
this.badgeEl.title = "Needs attention";
|
|
1134
1375
|
this.badgeEl.style.display = "none";
|
|
1135
1376
|
this.inspectBtn.appendChild(this.badgeEl);
|
|
1377
|
+
this.verificationBadgeEl = document.createElement("span");
|
|
1378
|
+
this.verificationBadgeEl.className = "remarq-badge remarq-toolbar-badge--verification";
|
|
1379
|
+
this.verificationBadgeEl.title = "Pending your verification";
|
|
1380
|
+
this.verificationBadgeEl.style.display = "none";
|
|
1381
|
+
this.verificationBadgeEl.addEventListener("click", (e) => {
|
|
1382
|
+
var _a3;
|
|
1383
|
+
e.stopPropagation();
|
|
1384
|
+
(_a3 = callbacks.onVerificationBadgeClick) == null ? void 0 : _a3.call(callbacks);
|
|
1385
|
+
});
|
|
1386
|
+
this.inspectBtn.appendChild(this.verificationBadgeEl);
|
|
1136
1387
|
this.spacingBtn = this.createButton("spacing", ICONS.spacing, () => callbacks.onSpacingToggle());
|
|
1137
1388
|
this.spacingBtn.disabled = true;
|
|
1138
1389
|
const copyBtn = this.createButton("copy", ICONS.copy, () => callbacks.onCopy());
|
|
@@ -1179,6 +1430,10 @@ var Toolbar = class {
|
|
|
1179
1430
|
this.badgeEl.textContent = String(count);
|
|
1180
1431
|
this.badgeEl.style.display = count > 0 ? "flex" : "none";
|
|
1181
1432
|
}
|
|
1433
|
+
setVerificationBadgeCount(count) {
|
|
1434
|
+
this.verificationBadgeEl.textContent = String(count);
|
|
1435
|
+
this.verificationBadgeEl.style.display = count > 0 ? "flex" : "none";
|
|
1436
|
+
}
|
|
1182
1437
|
getFileInput() {
|
|
1183
1438
|
return this.fileInput;
|
|
1184
1439
|
}
|
|
@@ -1662,6 +1917,47 @@ var SpacingOverlay = class {
|
|
|
1662
1917
|
};
|
|
1663
1918
|
|
|
1664
1919
|
// src/ui/popup.ts
|
|
1920
|
+
var STATUS_LABEL = {
|
|
1921
|
+
pending: "Pending",
|
|
1922
|
+
in_progress: "In progress",
|
|
1923
|
+
fixed_unverified: "Fix claimed",
|
|
1924
|
+
verified: "Verified",
|
|
1925
|
+
dismissed: "Dismissed"
|
|
1926
|
+
};
|
|
1927
|
+
var EVENT_LABEL = {
|
|
1928
|
+
created: "Created",
|
|
1929
|
+
acknowledged: "In progress",
|
|
1930
|
+
fix_claimed: "Fix claimed",
|
|
1931
|
+
verified: "Verified",
|
|
1932
|
+
rejected: "Rejected",
|
|
1933
|
+
dismissed: "Dismissed",
|
|
1934
|
+
reopened: "Reopened",
|
|
1935
|
+
migrated: "Migrated"
|
|
1936
|
+
};
|
|
1937
|
+
function actionsForStatus(status) {
|
|
1938
|
+
switch (status) {
|
|
1939
|
+
case "pending":
|
|
1940
|
+
return [
|
|
1941
|
+
{ label: "Acknowledge", action: "acknowledge", primary: true },
|
|
1942
|
+
{ label: "Dismiss", action: "dismiss", needsReason: true }
|
|
1943
|
+
];
|
|
1944
|
+
case "in_progress":
|
|
1945
|
+
return [
|
|
1946
|
+
{ label: "Mark verified", action: "verify", primary: true },
|
|
1947
|
+
{ label: "Dismiss", action: "dismiss", needsReason: true }
|
|
1948
|
+
];
|
|
1949
|
+
case "fixed_unverified":
|
|
1950
|
+
return [
|
|
1951
|
+
{ label: "Verify", action: "verify", primary: true },
|
|
1952
|
+
{ label: "Reject", action: "reject", needsReason: true },
|
|
1953
|
+
{ label: "Dismiss", action: "dismiss", needsReason: true }
|
|
1954
|
+
];
|
|
1955
|
+
case "verified":
|
|
1956
|
+
return [{ label: "Reopen", action: "reopen" }];
|
|
1957
|
+
case "dismissed":
|
|
1958
|
+
return [{ label: "Reopen", action: "reopen" }];
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1665
1961
|
var POPUP_WIDTH = 300;
|
|
1666
1962
|
var POPUP_MARGIN = 8;
|
|
1667
1963
|
var Popup = class {
|
|
@@ -1670,6 +1966,7 @@ var Popup = class {
|
|
|
1670
1966
|
this.popupEl = null;
|
|
1671
1967
|
this.keyHandler = null;
|
|
1672
1968
|
this.outsideClickHandler = null;
|
|
1969
|
+
this.pendingEditFlush = null;
|
|
1673
1970
|
}
|
|
1674
1971
|
show(info, position, onSubmit, onCancel) {
|
|
1675
1972
|
this.hide();
|
|
@@ -1754,7 +2051,7 @@ var Popup = class {
|
|
|
1754
2051
|
popup2.className = "remarq-popup";
|
|
1755
2052
|
const header = document.createElement("div");
|
|
1756
2053
|
header.className = "remarq-popup-header";
|
|
1757
|
-
header.textContent = `<${info.tag}>${info.text ? ` "${info.text}"` : ""} [${info.status}]`;
|
|
2054
|
+
header.textContent = `<${info.tag}>${info.text ? ` "${info.text}"` : ""} [${STATUS_LABEL[info.status]}]`;
|
|
1758
2055
|
const body = document.createElement("div");
|
|
1759
2056
|
body.className = "remarq-popup-body";
|
|
1760
2057
|
const makeCommentEl = () => {
|
|
@@ -1766,38 +2063,10 @@ var Popup = class {
|
|
|
1766
2063
|
return el;
|
|
1767
2064
|
};
|
|
1768
2065
|
body.appendChild(makeCommentEl());
|
|
2066
|
+
body.appendChild(this.buildLifecycleViewer(info.lifecycle));
|
|
1769
2067
|
const actions = document.createElement("div");
|
|
1770
2068
|
actions.className = "remarq-popup-actions";
|
|
1771
|
-
|
|
1772
|
-
const resolveBtn = document.createElement("button");
|
|
1773
|
-
resolveBtn.className = "remarq-primary";
|
|
1774
|
-
resolveBtn.textContent = "Resolve";
|
|
1775
|
-
resolveBtn.addEventListener("click", () => {
|
|
1776
|
-
this.hide();
|
|
1777
|
-
callbacks.onResolve();
|
|
1778
|
-
});
|
|
1779
|
-
actions.appendChild(resolveBtn);
|
|
1780
|
-
}
|
|
1781
|
-
const copyBtn = document.createElement("button");
|
|
1782
|
-
copyBtn.textContent = "Copy";
|
|
1783
|
-
copyBtn.addEventListener("click", () => {
|
|
1784
|
-
callbacks.onCopy();
|
|
1785
|
-
});
|
|
1786
|
-
actions.appendChild(copyBtn);
|
|
1787
|
-
const deleteBtn = document.createElement("button");
|
|
1788
|
-
deleteBtn.textContent = "Delete";
|
|
1789
|
-
deleteBtn.addEventListener("click", () => {
|
|
1790
|
-
this.hide();
|
|
1791
|
-
callbacks.onDelete();
|
|
1792
|
-
});
|
|
1793
|
-
actions.appendChild(deleteBtn);
|
|
1794
|
-
const closeBtn = document.createElement("button");
|
|
1795
|
-
closeBtn.textContent = "Close";
|
|
1796
|
-
closeBtn.addEventListener("click", () => {
|
|
1797
|
-
this.hide();
|
|
1798
|
-
callbacks.onClose();
|
|
1799
|
-
});
|
|
1800
|
-
actions.appendChild(closeBtn);
|
|
2069
|
+
this.renderActionButtons(actions, info, callbacks);
|
|
1801
2070
|
popup2.appendChild(header);
|
|
1802
2071
|
popup2.appendChild(body);
|
|
1803
2072
|
popup2.appendChild(actions);
|
|
@@ -1824,7 +2093,103 @@ var Popup = class {
|
|
|
1824
2093
|
document.addEventListener("mousedown", this.outsideClickHandler);
|
|
1825
2094
|
}, 0);
|
|
1826
2095
|
}
|
|
2096
|
+
buildLifecycleViewer(lifecycle) {
|
|
2097
|
+
var _a3, _b;
|
|
2098
|
+
const details = document.createElement("details");
|
|
2099
|
+
details.className = "remarq-popup-history";
|
|
2100
|
+
const summary = document.createElement("summary");
|
|
2101
|
+
summary.textContent = `History (${lifecycle.length})`;
|
|
2102
|
+
details.appendChild(summary);
|
|
2103
|
+
const list = document.createElement("ul");
|
|
2104
|
+
list.className = "remarq-popup-history-list";
|
|
2105
|
+
for (const ev of lifecycle) {
|
|
2106
|
+
const li = document.createElement("li");
|
|
2107
|
+
const when = new Date(ev.timestamp).toLocaleString();
|
|
2108
|
+
const who = (_a3 = ev.actor) != null ? _a3 : "system";
|
|
2109
|
+
const what = (_b = EVENT_LABEL[ev.type]) != null ? _b : ev.type;
|
|
2110
|
+
let text = `${when} \xB7 ${who} \xB7 ${what}`;
|
|
2111
|
+
if (ev.reason) text += ` \u2014 ${ev.reason}`;
|
|
2112
|
+
li.textContent = text;
|
|
2113
|
+
list.appendChild(li);
|
|
2114
|
+
}
|
|
2115
|
+
details.appendChild(list);
|
|
2116
|
+
return details;
|
|
2117
|
+
}
|
|
2118
|
+
renderActionButtons(container, info, callbacks) {
|
|
2119
|
+
container.replaceChildren();
|
|
2120
|
+
const transitions = document.createElement("div");
|
|
2121
|
+
transitions.className = "remarq-popup-actions-row remarq-popup-actions-row--transitions";
|
|
2122
|
+
for (const def of actionsForStatus(info.status)) {
|
|
2123
|
+
const btn = document.createElement("button");
|
|
2124
|
+
btn.textContent = def.label;
|
|
2125
|
+
if (def.primary) btn.className = "remarq-primary";
|
|
2126
|
+
btn.addEventListener("click", () => {
|
|
2127
|
+
if (def.needsReason) {
|
|
2128
|
+
this.showReasonInput(container, info, callbacks, def);
|
|
2129
|
+
} else {
|
|
2130
|
+
this.hide();
|
|
2131
|
+
callbacks.onTransition(def.action);
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2134
|
+
transitions.appendChild(btn);
|
|
2135
|
+
}
|
|
2136
|
+
container.appendChild(transitions);
|
|
2137
|
+
const utility = document.createElement("div");
|
|
2138
|
+
utility.className = "remarq-popup-actions-row remarq-popup-actions-row--utility";
|
|
2139
|
+
const copyBtn = document.createElement("button");
|
|
2140
|
+
copyBtn.className = "remarq-popup-utility-btn";
|
|
2141
|
+
copyBtn.textContent = "Copy";
|
|
2142
|
+
copyBtn.addEventListener("click", () => callbacks.onCopy());
|
|
2143
|
+
utility.appendChild(copyBtn);
|
|
2144
|
+
const deleteBtn = document.createElement("button");
|
|
2145
|
+
deleteBtn.className = "remarq-popup-utility-btn";
|
|
2146
|
+
deleteBtn.textContent = "Delete";
|
|
2147
|
+
deleteBtn.addEventListener("click", () => {
|
|
2148
|
+
this.hide();
|
|
2149
|
+
callbacks.onDelete();
|
|
2150
|
+
});
|
|
2151
|
+
utility.appendChild(deleteBtn);
|
|
2152
|
+
const closeBtn = document.createElement("button");
|
|
2153
|
+
closeBtn.className = "remarq-popup-utility-btn";
|
|
2154
|
+
closeBtn.textContent = "Close";
|
|
2155
|
+
closeBtn.addEventListener("click", () => {
|
|
2156
|
+
this.hide();
|
|
2157
|
+
callbacks.onClose();
|
|
2158
|
+
});
|
|
2159
|
+
utility.appendChild(closeBtn);
|
|
2160
|
+
container.appendChild(utility);
|
|
2161
|
+
}
|
|
2162
|
+
showReasonInput(container, info, callbacks, def) {
|
|
2163
|
+
container.replaceChildren();
|
|
2164
|
+
const textarea = document.createElement("textarea");
|
|
2165
|
+
textarea.placeholder = `Reason for ${def.label.toLowerCase()} (optional)\u2026`;
|
|
2166
|
+
textarea.className = "remarq-popup-reason";
|
|
2167
|
+
container.appendChild(textarea);
|
|
2168
|
+
const row = document.createElement("div");
|
|
2169
|
+
row.className = "remarq-popup-reason-row";
|
|
2170
|
+
const cancel = document.createElement("button");
|
|
2171
|
+
cancel.textContent = "Cancel";
|
|
2172
|
+
cancel.addEventListener("click", () => {
|
|
2173
|
+
this.renderActionButtons(container, info, callbacks);
|
|
2174
|
+
});
|
|
2175
|
+
const submit = document.createElement("button");
|
|
2176
|
+
submit.className = "remarq-primary";
|
|
2177
|
+
submit.textContent = "Submit";
|
|
2178
|
+
submit.addEventListener("click", () => {
|
|
2179
|
+
const reason = textarea.value.trim() || void 0;
|
|
2180
|
+
this.hide();
|
|
2181
|
+
callbacks.onTransition(def.action, reason);
|
|
2182
|
+
});
|
|
2183
|
+
row.appendChild(cancel);
|
|
2184
|
+
row.appendChild(submit);
|
|
2185
|
+
container.appendChild(row);
|
|
2186
|
+
textarea.focus();
|
|
2187
|
+
}
|
|
1827
2188
|
hide() {
|
|
2189
|
+
if (this.pendingEditFlush) {
|
|
2190
|
+
this.pendingEditFlush();
|
|
2191
|
+
this.pendingEditFlush = null;
|
|
2192
|
+
}
|
|
1828
2193
|
if (this.popupEl) {
|
|
1829
2194
|
this.popupEl.remove();
|
|
1830
2195
|
this.popupEl = null;
|
|
@@ -1859,12 +2224,8 @@ var Popup = class {
|
|
|
1859
2224
|
commentEl.replaceWith(textarea);
|
|
1860
2225
|
textarea.focus();
|
|
1861
2226
|
textarea.selectionStart = textarea.value.length;
|
|
1862
|
-
const
|
|
1863
|
-
|
|
1864
|
-
if (newComment && newComment !== info.comment) {
|
|
1865
|
-
info.comment = newComment;
|
|
1866
|
-
callbacks.onEdit(newComment);
|
|
1867
|
-
}
|
|
2227
|
+
const restoreView = () => {
|
|
2228
|
+
if (!textarea.isConnected) return;
|
|
1868
2229
|
const restored = document.createElement("div");
|
|
1869
2230
|
restored.textContent = info.comment;
|
|
1870
2231
|
restored.style.cursor = "pointer";
|
|
@@ -1872,26 +2233,33 @@ var Popup = class {
|
|
|
1872
2233
|
restored.addEventListener("click", () => this.enterEditMode(restored, info, callbacks));
|
|
1873
2234
|
textarea.replaceWith(restored);
|
|
1874
2235
|
};
|
|
2236
|
+
const commitEdit = () => {
|
|
2237
|
+
this.pendingEditFlush = null;
|
|
2238
|
+
const newComment = textarea.value.trim();
|
|
2239
|
+
if (newComment && newComment !== info.comment) {
|
|
2240
|
+
info.comment = newComment;
|
|
2241
|
+
callbacks.onEdit(newComment);
|
|
2242
|
+
}
|
|
2243
|
+
restoreView();
|
|
2244
|
+
};
|
|
2245
|
+
const cancelEdit = () => {
|
|
2246
|
+
this.pendingEditFlush = null;
|
|
2247
|
+
restoreView();
|
|
2248
|
+
};
|
|
2249
|
+
this.pendingEditFlush = commitEdit;
|
|
1875
2250
|
textarea.addEventListener("keydown", (e) => {
|
|
1876
2251
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
1877
2252
|
e.preventDefault();
|
|
1878
|
-
|
|
2253
|
+
commitEdit();
|
|
1879
2254
|
}
|
|
1880
2255
|
if (e.key === "Escape") {
|
|
1881
2256
|
e.stopPropagation();
|
|
1882
|
-
|
|
1883
|
-
restored.textContent = info.comment;
|
|
1884
|
-
restored.style.cursor = "pointer";
|
|
1885
|
-
restored.title = "Click to edit";
|
|
1886
|
-
restored.addEventListener("click", () => this.enterEditMode(restored, info, callbacks));
|
|
1887
|
-
textarea.replaceWith(restored);
|
|
2257
|
+
cancelEdit();
|
|
1888
2258
|
}
|
|
1889
2259
|
});
|
|
1890
2260
|
textarea.addEventListener("blur", () => {
|
|
1891
2261
|
setTimeout(() => {
|
|
1892
|
-
if (textarea.isConnected)
|
|
1893
|
-
saveEdit();
|
|
1894
|
-
}
|
|
2262
|
+
if (textarea.isConnected) commitEdit();
|
|
1895
2263
|
}, 50);
|
|
1896
2264
|
});
|
|
1897
2265
|
}
|
|
@@ -1919,6 +2287,16 @@ var Popup = class {
|
|
|
1919
2287
|
};
|
|
1920
2288
|
|
|
1921
2289
|
// src/ui/markers.ts
|
|
2290
|
+
var STATUS_COLOR = {
|
|
2291
|
+
pending: "var(--remarq-status-pending)",
|
|
2292
|
+
in_progress: "var(--remarq-status-in-progress)",
|
|
2293
|
+
fixed_unverified: "var(--remarq-status-fixed-unverified)",
|
|
2294
|
+
verified: "var(--remarq-status-verified)",
|
|
2295
|
+
dismissed: "var(--remarq-status-dismissed)"
|
|
2296
|
+
};
|
|
2297
|
+
function statusClass(status) {
|
|
2298
|
+
return `remarq-marker--${status.replace("_", "-")}`;
|
|
2299
|
+
}
|
|
1922
2300
|
var MarkerManager = class {
|
|
1923
2301
|
constructor(container, onClick) {
|
|
1924
2302
|
this.container = container;
|
|
@@ -1931,7 +2309,7 @@ var MarkerManager = class {
|
|
|
1931
2309
|
addMarker(annotation, target) {
|
|
1932
2310
|
this.counter++;
|
|
1933
2311
|
const markerEl = document.createElement("div");
|
|
1934
|
-
markerEl.className =
|
|
2312
|
+
markerEl.className = `remarq-marker ${statusClass(annotation.status)}`;
|
|
1935
2313
|
markerEl.setAttribute("data-status", annotation.status);
|
|
1936
2314
|
markerEl.setAttribute("data-annotation-id", annotation.id);
|
|
1937
2315
|
markerEl.textContent = String(this.counter);
|
|
@@ -1957,7 +2335,17 @@ var MarkerManager = class {
|
|
|
1957
2335
|
const entry = this.markers.get(id);
|
|
1958
2336
|
if (entry) {
|
|
1959
2337
|
entry.annotation.status = status;
|
|
2338
|
+
entry.markerEl.className = `remarq-marker ${statusClass(status)}`;
|
|
1960
2339
|
entry.markerEl.setAttribute("data-status", status);
|
|
2340
|
+
this.applyOutline(entry.target, status);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
scrollToMarker(id) {
|
|
2344
|
+
const entry = this.markers.get(id);
|
|
2345
|
+
if (!entry) return;
|
|
2346
|
+
try {
|
|
2347
|
+
entry.target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
2348
|
+
} catch (e) {
|
|
1961
2349
|
}
|
|
1962
2350
|
}
|
|
1963
2351
|
clear() {
|
|
@@ -1976,7 +2364,7 @@ var MarkerManager = class {
|
|
|
1976
2364
|
this.clear();
|
|
1977
2365
|
}
|
|
1978
2366
|
applyOutline(target, status) {
|
|
1979
|
-
const color = status
|
|
2367
|
+
const color = STATUS_COLOR[status];
|
|
1980
2368
|
target.style.outline = `2px solid ${color}`;
|
|
1981
2369
|
target.style.outlineOffset = "2px";
|
|
1982
2370
|
}
|
|
@@ -2323,8 +2711,18 @@ function refreshMarkers() {
|
|
|
2323
2711
|
markers.addMarker(ann, el);
|
|
2324
2712
|
}
|
|
2325
2713
|
detachedPanel.update(otherBreakpoint, detached);
|
|
2326
|
-
const
|
|
2327
|
-
|
|
2714
|
+
const needsAttention = anns.filter(
|
|
2715
|
+
(a) => a.status === "pending" || a.status === "in_progress"
|
|
2716
|
+
).length;
|
|
2717
|
+
const needsVerification = anns.filter((a) => a.status === "fixed_unverified").length;
|
|
2718
|
+
toolbar.setBadgeCount(needsAttention);
|
|
2719
|
+
toolbar.setVerificationBadgeCount(needsVerification);
|
|
2720
|
+
}
|
|
2721
|
+
function jumpToFirstUnverified() {
|
|
2722
|
+
if (!storage || !markers) return;
|
|
2723
|
+
const ann = storage.getByRoute(currentRoute()).find((a) => a.status === "fixed_unverified");
|
|
2724
|
+
if (!ann) return;
|
|
2725
|
+
markers.scrollToMarker(ann.id);
|
|
2328
2726
|
}
|
|
2329
2727
|
function scheduleRefresh() {
|
|
2330
2728
|
if (refreshScheduled) return;
|
|
@@ -2357,6 +2755,7 @@ function handleInspectClick(e) {
|
|
|
2357
2755
|
classFilter: options.classFilter,
|
|
2358
2756
|
dataAttribute: options.dataAttribute
|
|
2359
2757
|
});
|
|
2758
|
+
const now = Date.now();
|
|
2360
2759
|
const ann = {
|
|
2361
2760
|
id: generateId(),
|
|
2362
2761
|
comment,
|
|
@@ -2364,8 +2763,9 @@ function handleInspectClick(e) {
|
|
|
2364
2763
|
route: currentRoute(),
|
|
2365
2764
|
viewport: `${window.innerWidth}x${window.innerHeight}`,
|
|
2366
2765
|
viewportBucket: toBucket(window.innerWidth),
|
|
2367
|
-
timestamp:
|
|
2368
|
-
status: "pending"
|
|
2766
|
+
timestamp: now,
|
|
2767
|
+
status: "pending",
|
|
2768
|
+
lifecycle: [{ type: "created", actor: "designer", timestamp: now }]
|
|
2369
2769
|
};
|
|
2370
2770
|
cacheElement(ann.id, target);
|
|
2371
2771
|
storage.add(ann);
|
|
@@ -2457,7 +2857,8 @@ function handleMarkerClick(annotationId) {
|
|
|
2457
2857
|
tag: ann.fingerprint.tagName,
|
|
2458
2858
|
text: (_a3 = ann.fingerprint.textContent) != null ? _a3 : "",
|
|
2459
2859
|
comment: ann.comment,
|
|
2460
|
-
status: ann.status
|
|
2860
|
+
status: ann.status,
|
|
2861
|
+
lifecycle: ann.lifecycle
|
|
2461
2862
|
},
|
|
2462
2863
|
{
|
|
2463
2864
|
top: window.scrollY + rect.bottom + 8,
|
|
@@ -2465,9 +2866,8 @@ function handleMarkerClick(annotationId) {
|
|
|
2465
2866
|
anchorBottom: window.scrollY + rect.top - 8
|
|
2466
2867
|
},
|
|
2467
2868
|
{
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
refreshMarkers();
|
|
2869
|
+
onTransition: (action, reason) => {
|
|
2870
|
+
applyTransition(ann.id, action, reason ? { reason } : void 0);
|
|
2471
2871
|
},
|
|
2472
2872
|
onDelete: () => {
|
|
2473
2873
|
elementCache.delete(ann.id);
|
|
@@ -2481,12 +2881,14 @@ function handleMarkerClick(annotationId) {
|
|
|
2481
2881
|
refreshMarkers();
|
|
2482
2882
|
},
|
|
2483
2883
|
onCopy: () => {
|
|
2484
|
-
|
|
2884
|
+
var _a4;
|
|
2885
|
+
const fresh = (_a4 = storage.getById(ann.id)) != null ? _a4 : ann;
|
|
2886
|
+
const fp = fresh.fingerprint;
|
|
2485
2887
|
const lines = [
|
|
2486
|
-
`[${
|
|
2888
|
+
`[${fresh.status}] "${fresh.comment}"`,
|
|
2487
2889
|
`Element: <${fp.tagName}>${fp.textContent ? ` "${fp.textContent}"` : ""}`,
|
|
2488
|
-
`Route: ${
|
|
2489
|
-
`Viewport: ${
|
|
2890
|
+
`Route: ${fresh.route}`,
|
|
2891
|
+
`Viewport: ${fresh.viewportBucket}px`
|
|
2490
2892
|
];
|
|
2491
2893
|
if (fp.sourceLocation) lines.push(`Source: ${fp.sourceLocation}`);
|
|
2492
2894
|
navigator.clipboard.writeText(lines.join("\n")).then(() => {
|
|
@@ -2621,6 +3023,16 @@ function copyAgentToClipboard() {
|
|
|
2621
3023
|
console.warn("[web-remarq] Clipboard write failed");
|
|
2622
3024
|
});
|
|
2623
3025
|
}
|
|
3026
|
+
function applyTransition(id, action, opts = {}) {
|
|
3027
|
+
if (!storage) return;
|
|
3028
|
+
const ann = storage.getById(id);
|
|
3029
|
+
if (!ann) return;
|
|
3030
|
+
const { status, event } = transition(ann, action, opts);
|
|
3031
|
+
const lifecycle = [...ann.lifecycle, event];
|
|
3032
|
+
storage.update(id, { status, lifecycle });
|
|
3033
|
+
markers == null ? void 0 : markers.updateStatus(id, status);
|
|
3034
|
+
refreshMarkers();
|
|
3035
|
+
}
|
|
2624
3036
|
function setupMutationObserver() {
|
|
2625
3037
|
mutationObserver = new MutationObserver((mutations) => {
|
|
2626
3038
|
let hasExternalMutation = false;
|
|
@@ -2640,18 +3052,18 @@ function setupMutationObserver() {
|
|
|
2640
3052
|
}
|
|
2641
3053
|
var WebRemarq = {
|
|
2642
3054
|
init(opts) {
|
|
2643
|
-
var _a3;
|
|
3055
|
+
var _a3, _b;
|
|
2644
3056
|
if (initialized) return;
|
|
2645
3057
|
options = opts != null ? opts : {};
|
|
2646
3058
|
try {
|
|
2647
3059
|
injectStyles();
|
|
2648
|
-
storage = new AnnotationStorage();
|
|
3060
|
+
storage = new AnnotationStorage((_a3 = options.storage) != null ? _a3 : new LocalStorageAdapter());
|
|
2649
3061
|
themeManager = new ThemeManager(document.body, options.theme);
|
|
2650
3062
|
overlay = new Overlay(themeManager.container);
|
|
2651
3063
|
spacingOverlay = new SpacingOverlay(themeManager.container);
|
|
2652
3064
|
popup = new Popup(themeManager.container);
|
|
2653
3065
|
markers = new MarkerManager(themeManager.container, handleMarkerClick);
|
|
2654
|
-
const position = (
|
|
3066
|
+
const position = (_b = options.position) != null ? _b : "bottom-right";
|
|
2655
3067
|
detachedPanel = new DetachedPanel(themeManager.container, (id) => {
|
|
2656
3068
|
elementCache.delete(id);
|
|
2657
3069
|
storage.remove(id);
|
|
@@ -2682,11 +3094,9 @@ var WebRemarq = {
|
|
|
2682
3094
|
showToast(themeManager.container, "All annotations cleared");
|
|
2683
3095
|
},
|
|
2684
3096
|
onThemeToggle: () => themeManager.toggle(),
|
|
2685
|
-
onHelp: () => showShortcutsModal(themeManager.container)
|
|
3097
|
+
onHelp: () => showShortcutsModal(themeManager.container),
|
|
3098
|
+
onVerificationBadgeClick: jumpToFirstUnverified
|
|
2686
3099
|
}, position);
|
|
2687
|
-
if (storage.isMemoryOnly) {
|
|
2688
|
-
toolbar.setMemoryWarning(true);
|
|
2689
|
-
}
|
|
2690
3100
|
routeObserver = new RouteObserver();
|
|
2691
3101
|
unsubRoute = routeObserver.onChange(() => refreshMarkers());
|
|
2692
3102
|
document.addEventListener("click", handleInspectClick, true);
|
|
@@ -2694,8 +3104,13 @@ var WebRemarq = {
|
|
|
2694
3104
|
document.addEventListener("keydown", handleInspectKeydown);
|
|
2695
3105
|
setupMutationObserver();
|
|
2696
3106
|
initViewportListener(() => refreshMarkers());
|
|
3107
|
+
storage.ready.then(() => {
|
|
3108
|
+
if (storage.isMemoryOnly) {
|
|
3109
|
+
toolbar.setMemoryWarning(true);
|
|
3110
|
+
}
|
|
3111
|
+
refreshMarkers();
|
|
3112
|
+
});
|
|
2697
3113
|
console.debug(`[web-remarq] Initialized on route: ${currentRoute()}`);
|
|
2698
|
-
refreshMarkers();
|
|
2699
3114
|
initialized = true;
|
|
2700
3115
|
} catch (err) {
|
|
2701
3116
|
console.error("[web-remarq] Init failed:", err);
|
|
@@ -2774,10 +3189,33 @@ var WebRemarq = {
|
|
|
2774
3189
|
elementCache.clear();
|
|
2775
3190
|
storage == null ? void 0 : storage.clearAll();
|
|
2776
3191
|
if (initialized) refreshMarkers();
|
|
3192
|
+
},
|
|
3193
|
+
acknowledge(id, opts) {
|
|
3194
|
+
applyTransition(id, "acknowledge", opts);
|
|
3195
|
+
},
|
|
3196
|
+
claimFix(id, opts) {
|
|
3197
|
+
applyTransition(id, "claimFix", opts);
|
|
3198
|
+
},
|
|
3199
|
+
verify(id, opts) {
|
|
3200
|
+
applyTransition(id, "verify", opts);
|
|
3201
|
+
},
|
|
3202
|
+
reject(id, opts) {
|
|
3203
|
+
applyTransition(id, "reject", opts);
|
|
3204
|
+
},
|
|
3205
|
+
dismiss(id, opts) {
|
|
3206
|
+
applyTransition(id, "dismiss", opts);
|
|
3207
|
+
},
|
|
3208
|
+
reopen(id, opts) {
|
|
3209
|
+
applyTransition(id, "reopen", opts);
|
|
3210
|
+
},
|
|
3211
|
+
/** @deprecated Use verify() instead. */
|
|
3212
|
+
markResolved(id) {
|
|
3213
|
+
applyTransition(id, "verify");
|
|
2777
3214
|
}
|
|
2778
3215
|
};
|
|
2779
3216
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2780
3217
|
0 && (module.exports = {
|
|
3218
|
+
LocalStorageAdapter,
|
|
2781
3219
|
WebRemarq
|
|
2782
3220
|
});
|
|
2783
3221
|
//# sourceMappingURL=index.cjs.map
|