@nuniapp/widget 0.1.10 → 0.1.12
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 +2 -0
- package/dist/{dom-BWcT-q7S.js → dom-YEIbiA4X.js} +3 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +309 -76
- package/dist/nuni-screenshot.global.js +1 -1
- package/dist/nuni.global.js +18 -5
- package/dist/{screenshot-tools-Dk-xNV0c.js → screenshot-tools-BFj-93o4.js} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as isProjectId, a as initials, c as IMAGE_TYPES, d as CAPTURE_MARK, f as MASK_ATTRIBUTE, g as generateSecret, h as REACTIONS, i as icon, m as LIMITS, n as copyText, o as parseColor, p as MASK_SELECTOR, r as h, s as readableOn, t as colorFor, u as imageFromFile } from "./dom-
|
|
1
|
+
import { _ as isProjectId, a as initials, c as IMAGE_TYPES, d as CAPTURE_MARK, f as MASK_ATTRIBUTE, g as generateSecret, h as REACTIONS, i as icon, m as LIMITS, n as copyText, o as parseColor, p as MASK_SELECTOR, r as h, s as readableOn, t as colorFor, u as imageFromFile } from "./dom-YEIbiA4X.js";
|
|
2
2
|
//#region ../shared/src/path.ts
|
|
3
3
|
/**
|
|
4
4
|
* Normalize a URL to the key comments are matched by. Query and hash are
|
|
@@ -176,7 +176,7 @@ function buildCommentPrompt(comment, options = {}) {
|
|
|
176
176
|
}
|
|
177
177
|
//#endregion
|
|
178
178
|
//#region src/config.ts
|
|
179
|
-
const VERSION = "0.1.
|
|
179
|
+
const VERSION = "0.1.12";
|
|
180
180
|
function resolveConfig(options) {
|
|
181
181
|
return {
|
|
182
182
|
project: options.project,
|
|
@@ -5285,12 +5285,16 @@ var NuniApi = class {
|
|
|
5285
5285
|
}, (comments) => cb(comments), onError);
|
|
5286
5286
|
}
|
|
5287
5287
|
/** The visitor's own comments on every page, live. */
|
|
5288
|
-
onMine(
|
|
5288
|
+
onMine(author, cb) {
|
|
5289
5289
|
return this.client.onUpdate(api.comments.listMine, {
|
|
5290
5290
|
publicId: this.config.project,
|
|
5291
|
-
|
|
5291
|
+
...author
|
|
5292
5292
|
}, (comments) => cb(comments), () => {});
|
|
5293
5293
|
}
|
|
5294
|
+
/** Comments on every page, newest first, live. */
|
|
5295
|
+
onSite(cb) {
|
|
5296
|
+
return this.client.onUpdate(api.comments.listForSite, { publicId: this.config.project }, (comments) => cb(comments), () => {});
|
|
5297
|
+
}
|
|
5294
5298
|
onPages(cb) {
|
|
5295
5299
|
return this.client.onUpdate(api.comments.pagesWithComments, { publicId: this.config.project }, cb, () => {});
|
|
5296
5300
|
}
|
|
@@ -5300,6 +5304,24 @@ var NuniApi = class {
|
|
|
5300
5304
|
sessionToken
|
|
5301
5305
|
}, cb, () => {});
|
|
5302
5306
|
}
|
|
5307
|
+
/** Who a stored commenter sign-in belongs to, live (invalid once revoked). */
|
|
5308
|
+
onCommenter(commenterToken, cb) {
|
|
5309
|
+
return this.client.onUpdate(api.commenters.validate, {
|
|
5310
|
+
publicId: this.config.project,
|
|
5311
|
+
commenterToken
|
|
5312
|
+
}, cb, () => {});
|
|
5313
|
+
}
|
|
5314
|
+
/** Right after signing in: this browser's guest comments become the account's. */
|
|
5315
|
+
linkBrowser(authorSecret, commenterToken) {
|
|
5316
|
+
return this.run(this.client.mutation(api.commenters.linkBrowser, {
|
|
5317
|
+
publicId: this.config.project,
|
|
5318
|
+
authorSecret,
|
|
5319
|
+
commenterToken
|
|
5320
|
+
}));
|
|
5321
|
+
}
|
|
5322
|
+
signOutCommenter(commenterToken) {
|
|
5323
|
+
return this.client.mutation(api.commenters.signOut, { commenterToken }).catch(() => null);
|
|
5324
|
+
}
|
|
5303
5325
|
/** A comment with the owner-only context (screenshot, console, DOM). */
|
|
5304
5326
|
onOwnerComment(id, sessionToken, cb) {
|
|
5305
5327
|
return this.client.onUpdate(api.comments.getForOwner, {
|
|
@@ -5360,21 +5382,22 @@ var NuniApi = class {
|
|
|
5360
5382
|
return data.id;
|
|
5361
5383
|
}
|
|
5362
5384
|
/** Attach the element's screenshot (for the owner) to a just-posted comment. */
|
|
5363
|
-
uploadScreenshot(id,
|
|
5364
|
-
return this.upload("screenshot", id,
|
|
5385
|
+
uploadScreenshot(id, author, image) {
|
|
5386
|
+
return this.upload("screenshot", id, author, image);
|
|
5365
5387
|
}
|
|
5366
5388
|
/** An image for everyone: picked, pasted or a marked-up screenshot. */
|
|
5367
|
-
uploadImage(id,
|
|
5368
|
-
return this.upload("image", id,
|
|
5389
|
+
uploadImage(id, author, image) {
|
|
5390
|
+
return this.upload("image", id, author, image);
|
|
5369
5391
|
}
|
|
5370
|
-
async upload(kind, id,
|
|
5392
|
+
async upload(kind, id, author, image) {
|
|
5371
5393
|
const response = await fetch(`${this.config.convexSiteUrl}/widget/${kind}`, {
|
|
5372
5394
|
method: "POST",
|
|
5373
5395
|
headers: {
|
|
5374
5396
|
"Content-Type": image.type,
|
|
5375
5397
|
"X-Nuni-Project": this.config.project,
|
|
5376
5398
|
"X-Nuni-Comment": id,
|
|
5377
|
-
"X-Nuni-Author": authorSecret
|
|
5399
|
+
"X-Nuni-Author": author.authorSecret,
|
|
5400
|
+
...author.commenterToken ? { "X-Nuni-Commenter": author.commenterToken } : {}
|
|
5378
5401
|
},
|
|
5379
5402
|
body: image
|
|
5380
5403
|
});
|
|
@@ -5390,18 +5413,18 @@ var NuniApi = class {
|
|
|
5390
5413
|
throw new NuniApiError(errorMessage(error), "error");
|
|
5391
5414
|
}
|
|
5392
5415
|
}
|
|
5393
|
-
editOwn(id,
|
|
5416
|
+
editOwn(id, author, body, suggestion) {
|
|
5394
5417
|
return this.run(this.client.mutation(api.comments.editOwn, {
|
|
5395
5418
|
id,
|
|
5396
|
-
|
|
5419
|
+
...author,
|
|
5397
5420
|
body,
|
|
5398
5421
|
suggestion
|
|
5399
5422
|
}));
|
|
5400
5423
|
}
|
|
5401
|
-
deleteOwn(id,
|
|
5424
|
+
deleteOwn(id, author) {
|
|
5402
5425
|
return this.run(this.client.mutation(api.comments.deleteOwn, {
|
|
5403
5426
|
id,
|
|
5404
|
-
|
|
5427
|
+
...author
|
|
5405
5428
|
}));
|
|
5406
5429
|
}
|
|
5407
5430
|
resolve(id, sessionToken, resolution) {
|
|
@@ -5444,17 +5467,17 @@ var NuniApi = class {
|
|
|
5444
5467
|
sessionToken
|
|
5445
5468
|
}));
|
|
5446
5469
|
}
|
|
5447
|
-
editReply(id,
|
|
5470
|
+
editReply(id, author, body) {
|
|
5448
5471
|
return this.run(this.client.mutation(api.replies.editOwn, {
|
|
5449
5472
|
id,
|
|
5450
|
-
|
|
5473
|
+
...author,
|
|
5451
5474
|
body
|
|
5452
5475
|
}));
|
|
5453
5476
|
}
|
|
5454
|
-
deleteReply(id,
|
|
5477
|
+
deleteReply(id, author) {
|
|
5455
5478
|
return this.run(this.client.mutation(api.replies.deleteOwn, {
|
|
5456
5479
|
id,
|
|
5457
|
-
|
|
5480
|
+
...author
|
|
5458
5481
|
}));
|
|
5459
5482
|
}
|
|
5460
5483
|
removeReply(id, sessionToken) {
|
|
@@ -5463,13 +5486,13 @@ var NuniApi = class {
|
|
|
5463
5486
|
sessionToken
|
|
5464
5487
|
}));
|
|
5465
5488
|
}
|
|
5466
|
-
toggleReaction(commentId, targetId, emoji,
|
|
5489
|
+
toggleReaction(commentId, targetId, emoji, author) {
|
|
5467
5490
|
return this.run(this.client.mutation(api.reactions.toggle, {
|
|
5468
5491
|
publicId: this.config.project,
|
|
5469
5492
|
commentId,
|
|
5470
5493
|
targetId,
|
|
5471
5494
|
emoji,
|
|
5472
|
-
|
|
5495
|
+
...author
|
|
5473
5496
|
}));
|
|
5474
5497
|
}
|
|
5475
5498
|
remove(id, sessionToken) {
|
|
@@ -5497,6 +5520,8 @@ const EN = {
|
|
|
5497
5520
|
pickElement: "Pick an element",
|
|
5498
5521
|
allComments: "All comments",
|
|
5499
5522
|
openCount: "Comments on this page: {count} open",
|
|
5523
|
+
hideComments: "Hide comments",
|
|
5524
|
+
hideCommentsKey: "Hide comments (Shift+{key})",
|
|
5500
5525
|
commentSelection: "Comment on the selected text",
|
|
5501
5526
|
commentSelectionKey: "Comment on the selected text ({key})",
|
|
5502
5527
|
pickHint: "Click anything to comment, or drag to mark an area",
|
|
@@ -5531,6 +5556,11 @@ const EN = {
|
|
|
5531
5556
|
yourName: "Your name",
|
|
5532
5557
|
leaveComment: "Leave a comment",
|
|
5533
5558
|
notYou: "Not you?",
|
|
5559
|
+
signIn: "Sign in",
|
|
5560
|
+
signInGithub: "Sign in with GitHub to comment as yourself",
|
|
5561
|
+
signOut: "Sign out",
|
|
5562
|
+
signedInAs: "Signed in as {name}",
|
|
5563
|
+
signedInGithub: "Signed in with GitHub",
|
|
5534
5564
|
cancel: "Cancel",
|
|
5535
5565
|
post: "Post",
|
|
5536
5566
|
posting: "Posting…",
|
|
@@ -5604,7 +5634,12 @@ const EN = {
|
|
|
5604
5634
|
copied: "Copied for your coding agent",
|
|
5605
5635
|
copyFailed: "Couldn't copy",
|
|
5606
5636
|
signedIn: "You're signed in as the owner",
|
|
5637
|
+
commenterSignedIn: "You're signed in",
|
|
5638
|
+
signedOut: "Signed out",
|
|
5607
5639
|
linkGone: "That comment was deleted or is on another page",
|
|
5640
|
+
commentsHidden: "Comments hidden",
|
|
5641
|
+
commentsHiddenKey: "Comments hidden. Press Shift+{key} to show them",
|
|
5642
|
+
commentsShown: "Comments shown",
|
|
5608
5643
|
enterName: "Enter your name",
|
|
5609
5644
|
writeFirst: "Write a comment first",
|
|
5610
5645
|
changeTextFirst: "Change the text to suggest an edit",
|
|
@@ -5678,6 +5713,8 @@ const s = (d) => `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" wi
|
|
|
5678
5713
|
const ICONS = {
|
|
5679
5714
|
comment: s("<path d=\"M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z\"/>"),
|
|
5680
5715
|
list: s("<path d=\"M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01\"/>"),
|
|
5716
|
+
eye: s("<path d=\"M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>"),
|
|
5717
|
+
eyeOff: s("<path d=\"M10.7 5.1A10 10 0 0 1 12 5c6.5 0 10 7 10 7a17 17 0 0 1-2.2 3.2M6.6 6.6A17 17 0 0 0 2 12s3.5 7 10 7a9.7 9.7 0 0 0 5.4-1.6M9.9 9.9a3 3 0 0 0 4.2 4.2M2 2l20 20\"/>"),
|
|
5681
5718
|
close: s("<path d=\"M18 6 6 18M6 6l12 12\"/>"),
|
|
5682
5719
|
check: s("<path d=\"M20 6 9 17l-5-5\"/>"),
|
|
5683
5720
|
undo: s("<path d=\"M3 7v6h6\"/><path d=\"M21 17a9 9 0 0 0-15-6.7L3 13\"/>"),
|
|
@@ -5947,10 +5984,14 @@ const KEYS = {
|
|
|
5947
5984
|
name: "nuni:name",
|
|
5948
5985
|
secret: "nuni:author-secret",
|
|
5949
5986
|
session: (project) => `nuni:session:${project}`,
|
|
5987
|
+
/** A visitor's sign-in to comment under their account. */
|
|
5988
|
+
commenter: (project) => `nuni:commenter:${project}`,
|
|
5950
5989
|
/** Where this visitor dragged the toolbar. */
|
|
5951
5990
|
position: (project) => `nuni:position:${project}`,
|
|
5952
5991
|
/** The comment this visitor opened last, marked in the panel. */
|
|
5953
|
-
lastViewed: (project) => `nuni:last-viewed:${project}
|
|
5992
|
+
lastViewed: (project) => `nuni:last-viewed:${project}`,
|
|
5993
|
+
/** This visitor hid the pins (Shift+C). */
|
|
5994
|
+
hidden: (project) => `nuni:hidden:${project}`
|
|
5954
5995
|
};
|
|
5955
5996
|
//#endregion
|
|
5956
5997
|
//#region src/styles.ts
|
|
@@ -6066,6 +6107,9 @@ button { cursor: pointer; }
|
|
|
6066
6107
|
justify-content: center;
|
|
6067
6108
|
}
|
|
6068
6109
|
.tb-btn[aria-pressed="true"] .tb-count { background: rgba(255,255,255,0.25); color: inherit; }
|
|
6110
|
+
.tb-icon { width: 36px; padding: 0; justify-content: center; }
|
|
6111
|
+
/* Pins hidden: the count stays, dimmed, so the comments aren't lost. */
|
|
6112
|
+
.toolbar[data-pins-hidden] .tb-count { opacity: 0.55; }
|
|
6069
6113
|
|
|
6070
6114
|
/* Picking */
|
|
6071
6115
|
.pick-hint {
|
|
@@ -6281,6 +6325,10 @@ button { cursor: pointer; }
|
|
|
6281
6325
|
justify-content: center;
|
|
6282
6326
|
flex: none;
|
|
6283
6327
|
}
|
|
6328
|
+
.avatar { position: relative; overflow: hidden; }
|
|
6329
|
+
.avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
|
|
6330
|
+
.signed-in { display: inline-flex; flex: none; color: var(--n-fg-muted); }
|
|
6331
|
+
.signed-in .icon { width: 13px; height: 13px; }
|
|
6284
6332
|
.author { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
6285
6333
|
.meta { color: var(--n-fg-muted); font-size: 12px; white-space: nowrap; }
|
|
6286
6334
|
.badge {
|
|
@@ -6509,6 +6557,10 @@ textarea.field { resize: vertical; min-height: 72px; max-height: 240px; }
|
|
|
6509
6557
|
white-space: nowrap;
|
|
6510
6558
|
}
|
|
6511
6559
|
.cmp-link:hover { color: var(--n-fg); }
|
|
6560
|
+
.cmp-head-guest { padding-right: 116px; }
|
|
6561
|
+
.cmp-sign-in { position: absolute; top: 13px; right: 44px; height: 32px; display: inline-flex; align-items: center; gap: 4px; }
|
|
6562
|
+
.cmp-sign-in .icon { width: 13px; height: 13px; }
|
|
6563
|
+
.signed-in-as { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
6512
6564
|
.composer .quote, .composer .suggest { margin: 6px 14px 0; }
|
|
6513
6565
|
.suggest {
|
|
6514
6566
|
display: grid;
|
|
@@ -6691,6 +6743,8 @@ textarea.field { resize: vertical; min-height: 72px; max-height: 240px; }
|
|
|
6691
6743
|
.panel-search .field { padding-left: 32px; }
|
|
6692
6744
|
.item-text { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
|
|
6693
6745
|
.section-label { padding: 12px 10px 4px; font-size: 11px; font-weight: 650; letter-spacing: 0.04em; text-transform: uppercase; color: var(--n-fg-muted); }
|
|
6746
|
+
/* A page's path, as written: paths are case-sensitive. */
|
|
6747
|
+
.section-path { text-transform: none; letter-spacing: 0; font-size: 12px; overflow-wrap: anywhere; }
|
|
6694
6748
|
.empty { padding: 32px 16px; text-align: center; color: var(--n-fg-muted); }
|
|
6695
6749
|
.panel-foot { padding: 12px; border-top: 1px solid var(--n-border); display: grid; gap: 8px; font-size: 13px; }
|
|
6696
6750
|
.link { border: 0; background: none; padding: 0; color: var(--n-accent); font-weight: 600; text-decoration: none; }
|
|
@@ -6830,11 +6884,23 @@ function isTypingTarget(target) {
|
|
|
6830
6884
|
const el = target;
|
|
6831
6885
|
return el.isContentEditable || el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT";
|
|
6832
6886
|
}
|
|
6833
|
-
|
|
6834
|
-
|
|
6887
|
+
/** Initials, under the account photo of an author who signed in. */
|
|
6888
|
+
function avatar(name, photo) {
|
|
6889
|
+
const el = h("span", {
|
|
6835
6890
|
class: "avatar",
|
|
6836
6891
|
style: `background:${colorFor(name)}`
|
|
6837
6892
|
}, initials(name));
|
|
6893
|
+
if (photo?.startsWith("https://")) {
|
|
6894
|
+
const img = h("img", {
|
|
6895
|
+
src: photo,
|
|
6896
|
+
alt: "",
|
|
6897
|
+
loading: "lazy",
|
|
6898
|
+
referrerpolicy: "no-referrer",
|
|
6899
|
+
onerror: () => img.remove()
|
|
6900
|
+
});
|
|
6901
|
+
el.append(img);
|
|
6902
|
+
}
|
|
6903
|
+
return el;
|
|
6838
6904
|
}
|
|
6839
6905
|
function describeElement(el) {
|
|
6840
6906
|
const tag = el.tagName.toLowerCase();
|
|
@@ -6894,10 +6960,13 @@ var NuniWidget = class {
|
|
|
6894
6960
|
_defineProperty(this, "status", null);
|
|
6895
6961
|
_defineProperty(this, "pages", []);
|
|
6896
6962
|
_defineProperty(this, "picking", false);
|
|
6963
|
+
_defineProperty(this, "pinsHidden", void 0);
|
|
6897
6964
|
_defineProperty(this, "panelOpen", false);
|
|
6898
6965
|
_defineProperty(this, "tab", "open");
|
|
6899
6966
|
_defineProperty(this, "mine", null);
|
|
6900
6967
|
_defineProperty(this, "mineUnsub", null);
|
|
6968
|
+
_defineProperty(this, "site", null);
|
|
6969
|
+
_defineProperty(this, "siteUnsub", null);
|
|
6901
6970
|
_defineProperty(this, "repinId", null);
|
|
6902
6971
|
_defineProperty(this, "pinReported", /* @__PURE__ */ new Map());
|
|
6903
6972
|
_defineProperty(this, "pinReportTimer", 0);
|
|
@@ -6913,6 +6982,10 @@ var NuniWidget = class {
|
|
|
6913
6982
|
_defineProperty(this, "secretHash", "");
|
|
6914
6983
|
_defineProperty(this, "ownerToken", void 0);
|
|
6915
6984
|
_defineProperty(this, "ownerName", null);
|
|
6985
|
+
_defineProperty(this, "commenterToken", void 0);
|
|
6986
|
+
_defineProperty(this, "commenter", null);
|
|
6987
|
+
_defineProperty(this, "commenterUnsub", null);
|
|
6988
|
+
_defineProperty(this, "mineToken", null);
|
|
6916
6989
|
_defineProperty(this, "deepLinkId", null);
|
|
6917
6990
|
_defineProperty(this, "extraComment", null);
|
|
6918
6991
|
_defineProperty(this, "ownerDetail", null);
|
|
@@ -7023,7 +7096,9 @@ var NuniWidget = class {
|
|
|
7023
7096
|
}
|
|
7024
7097
|
this.secret = secret;
|
|
7025
7098
|
this.ownerToken = read(KEYS.session(config.project));
|
|
7099
|
+
this.commenterToken = read(KEYS.commenter(config.project));
|
|
7026
7100
|
this.lastViewedId = read(KEYS.lastViewed(config.project));
|
|
7101
|
+
this.pinsHidden = read(KEYS.hidden(config.project)) === "1";
|
|
7027
7102
|
this.position = oneOf(read(KEYS.position(config.project)) ?? void 0, POSITIONS, config.position);
|
|
7028
7103
|
this.host = document.createElement("div");
|
|
7029
7104
|
this.host.id = "nuni-root";
|
|
@@ -7100,6 +7175,7 @@ var NuniWidget = class {
|
|
|
7100
7175
|
this.render();
|
|
7101
7176
|
}));
|
|
7102
7177
|
if (this.ownerToken) this.watchSession(this.ownerToken);
|
|
7178
|
+
if (this.commenterToken) this.watchCommenter(this.commenterToken);
|
|
7103
7179
|
this.readDeepLink();
|
|
7104
7180
|
this.subscribePage();
|
|
7105
7181
|
this.cleanups.push(onLocationChange(() => {
|
|
@@ -7172,9 +7248,11 @@ var NuniWidget = class {
|
|
|
7172
7248
|
this.endToolbarDrag?.();
|
|
7173
7249
|
this.pageUnsub?.();
|
|
7174
7250
|
this.sessionUnsub?.();
|
|
7251
|
+
this.commenterUnsub?.();
|
|
7175
7252
|
this.ownerDetailUnsub?.();
|
|
7176
7253
|
this.threadUnsub?.();
|
|
7177
7254
|
this.mineUnsub?.();
|
|
7255
|
+
this.siteUnsub?.();
|
|
7178
7256
|
clearTimeout(this.pinReportTimer);
|
|
7179
7257
|
this.resolveRun++;
|
|
7180
7258
|
for (const stop of this.scopeWatchers.values()) stop();
|
|
@@ -7228,6 +7306,62 @@ var NuniWidget = class {
|
|
|
7228
7306
|
this.render();
|
|
7229
7307
|
});
|
|
7230
7308
|
}
|
|
7309
|
+
watchCommenter(token) {
|
|
7310
|
+
this.commenterUnsub?.();
|
|
7311
|
+
this.commenterUnsub = this.api.onCommenter(token, (result) => {
|
|
7312
|
+
if (this.commenterToken !== token) return;
|
|
7313
|
+
if (result.valid) {
|
|
7314
|
+
const { name, avatarUrl, authorKey } = result;
|
|
7315
|
+
this.commenter = {
|
|
7316
|
+
name,
|
|
7317
|
+
avatarUrl,
|
|
7318
|
+
authorKey
|
|
7319
|
+
};
|
|
7320
|
+
} else this.forgetCommenter();
|
|
7321
|
+
this.render();
|
|
7322
|
+
});
|
|
7323
|
+
}
|
|
7324
|
+
/** Back to commenting as a guest in this browser. */
|
|
7325
|
+
forgetCommenter() {
|
|
7326
|
+
this.commenterUnsub?.();
|
|
7327
|
+
this.commenterUnsub = null;
|
|
7328
|
+
this.commenterToken = null;
|
|
7329
|
+
this.commenter = null;
|
|
7330
|
+
write(KEYS.commenter(this.config.project), null);
|
|
7331
|
+
this.syncMine();
|
|
7332
|
+
}
|
|
7333
|
+
/** Who is writing, for every comment, reply, reaction and upload. */
|
|
7334
|
+
get author() {
|
|
7335
|
+
return {
|
|
7336
|
+
authorSecret: this.secret,
|
|
7337
|
+
commenterToken: this.commenterToken ?? void 0
|
|
7338
|
+
};
|
|
7339
|
+
}
|
|
7340
|
+
/** The name new comments go out under. */
|
|
7341
|
+
get displayName() {
|
|
7342
|
+
return this.commenter?.name ?? this.name;
|
|
7343
|
+
}
|
|
7344
|
+
/** The key on what this visitor writes now. */
|
|
7345
|
+
get authorKey() {
|
|
7346
|
+
return this.commenter?.authorKey ?? this.secretHash;
|
|
7347
|
+
}
|
|
7348
|
+
/** Signed in or not, this browser's own guest comments stay editable. */
|
|
7349
|
+
ownsKey(key) {
|
|
7350
|
+
return Boolean(key) && (key === this.secretHash || key === this.commenter?.authorKey);
|
|
7351
|
+
}
|
|
7352
|
+
/** An author's photo and name, marked when they wrote it signed in. */
|
|
7353
|
+
authorLine(row) {
|
|
7354
|
+
return [
|
|
7355
|
+
avatar(row.authorName, row.signedIn ? row.avatarUrl : void 0),
|
|
7356
|
+
h("span", { class: "author" }, row.authorName),
|
|
7357
|
+
row.signedIn ? h("span", {
|
|
7358
|
+
class: "signed-in",
|
|
7359
|
+
role: "img",
|
|
7360
|
+
"aria-label": this.t("signedInGithub"),
|
|
7361
|
+
title: this.t("signedInGithub")
|
|
7362
|
+
}, icon(ICONS.github)) : null
|
|
7363
|
+
];
|
|
7364
|
+
}
|
|
7231
7365
|
/** Keep the owner-only details of the open thread subscribed. */
|
|
7232
7366
|
syncOwnerDetail() {
|
|
7233
7367
|
const token = this.ownerToken;
|
|
@@ -7265,10 +7399,19 @@ var NuniWidget = class {
|
|
|
7265
7399
|
return Boolean(this.ownerToken && this.ownerName);
|
|
7266
7400
|
}
|
|
7267
7401
|
isMine(comment) {
|
|
7268
|
-
return
|
|
7402
|
+
return this.ownsKey(comment.authorKeyHash);
|
|
7269
7403
|
}
|
|
7404
|
+
/** The open thread keeps its pin while the rest are hidden. */
|
|
7270
7405
|
visibleComments() {
|
|
7271
|
-
return this.comments.filter((c) => c.status === (this.panelOpen && this.tab === "resolved" ? "resolved" : "open") || this.card?.kind === "thread" && this.card.id === c._id);
|
|
7406
|
+
return this.comments.filter((c) => !this.pinsHidden && c.status === (this.panelOpen && this.tab === "resolved" ? "resolved" : "open") || this.card?.kind === "thread" && this.card.id === c._id);
|
|
7407
|
+
}
|
|
7408
|
+
/** Hide or show the pins, like Figma's Shift+C. */
|
|
7409
|
+
setPinsHidden(hidden, quiet = false) {
|
|
7410
|
+
if (this.pinsHidden === hidden) return;
|
|
7411
|
+
this.pinsHidden = hidden;
|
|
7412
|
+
write(KEYS.hidden(this.config.project), hidden ? "1" : null);
|
|
7413
|
+
if (quiet) return;
|
|
7414
|
+
this.showToast(hidden ? this.withKey("commentsHidden", "commentsHiddenKey") : this.t("commentsShown"));
|
|
7272
7415
|
}
|
|
7273
7416
|
scheduleResolve() {
|
|
7274
7417
|
clearTimeout(this.resolveTimer);
|
|
@@ -7515,6 +7658,7 @@ var NuniWidget = class {
|
|
|
7515
7658
|
this.dragBox = null;
|
|
7516
7659
|
if (on) {
|
|
7517
7660
|
this.card = null;
|
|
7661
|
+
this.setPinsHidden(false, true);
|
|
7518
7662
|
if (window.matchMedia(MOBILE_QUERY).matches) this.panelOpen = false;
|
|
7519
7663
|
this.pickDocs = [document, ...frameDocuments(document)];
|
|
7520
7664
|
for (const doc of this.pickDocs) {
|
|
@@ -7635,6 +7779,7 @@ var NuniWidget = class {
|
|
|
7635
7779
|
this.movePin(repinId, draft);
|
|
7636
7780
|
return;
|
|
7637
7781
|
}
|
|
7782
|
+
this.setPinsHidden(false, true);
|
|
7638
7783
|
if (this.config.capture.dom) try {
|
|
7639
7784
|
draft.dom = domContext(element);
|
|
7640
7785
|
} catch {}
|
|
@@ -7692,7 +7837,7 @@ var NuniWidget = class {
|
|
|
7692
7837
|
async attachScreenshot(id, shot) {
|
|
7693
7838
|
try {
|
|
7694
7839
|
const image = await shot;
|
|
7695
|
-
if (image) await this.api.uploadScreenshot(id, this.
|
|
7840
|
+
if (image) await this.api.uploadScreenshot(id, this.author, image);
|
|
7696
7841
|
} catch {}
|
|
7697
7842
|
}
|
|
7698
7843
|
/** One after another, so they keep their order. */
|
|
@@ -7700,7 +7845,7 @@ var NuniWidget = class {
|
|
|
7700
7845
|
const images = draft.images ?? [];
|
|
7701
7846
|
revokeImages(draft);
|
|
7702
7847
|
try {
|
|
7703
|
-
for (const image of images) await this.api.uploadImage(id, this.
|
|
7848
|
+
for (const image of images) await this.api.uploadImage(id, this.author, image.blob);
|
|
7704
7849
|
} catch (error) {
|
|
7705
7850
|
this.showToast(error instanceof NuniApiError ? error.message : this.t("imageFailed"));
|
|
7706
7851
|
}
|
|
@@ -7827,7 +7972,8 @@ var NuniWidget = class {
|
|
|
7827
7972
|
const hotkey = this.config.hotkey;
|
|
7828
7973
|
if (hotkey && e.key.toLowerCase() === hotkey) {
|
|
7829
7974
|
e.preventDefault();
|
|
7830
|
-
if (
|
|
7975
|
+
if (e.shiftKey && hotkey !== hotkey.toUpperCase()) this.setPinsHidden(!this.pinsHidden);
|
|
7976
|
+
else if (!this.picking && this.pageSelection()) this.commentOnSelection();
|
|
7831
7977
|
else this.setPicking(!this.picking);
|
|
7832
7978
|
}
|
|
7833
7979
|
}
|
|
@@ -7983,6 +8129,29 @@ var NuniWidget = class {
|
|
|
7983
8129
|
url.searchParams.set("origin", location.origin);
|
|
7984
8130
|
if (!window.open(url.toString(), "nuni-claim", "popup,width=480,height=680")) location.href = url.toString();
|
|
7985
8131
|
}
|
|
8132
|
+
/** Sign in to comment under an account, in a popup on the dashboard. */
|
|
8133
|
+
openCommenterSignIn() {
|
|
8134
|
+
const url = new URL(`${this.config.appUrl}/dashboard/comment-sign-in`);
|
|
8135
|
+
url.searchParams.set("project", this.config.project);
|
|
8136
|
+
url.searchParams.set("origin", location.origin);
|
|
8137
|
+
if (!window.open(url.toString(), "nuni-comment-sign-in", "popup,width=480,height=680")) location.href = url.toString();
|
|
8138
|
+
}
|
|
8139
|
+
async onCommenterSignedIn(token) {
|
|
8140
|
+
this.commenterToken = token;
|
|
8141
|
+
write(KEYS.commenter(this.config.project), token);
|
|
8142
|
+
await this.api.linkBrowser(this.secret, token).catch(() => null);
|
|
8143
|
+
if (this.commenterToken !== token) return;
|
|
8144
|
+
this.watchCommenter(token);
|
|
8145
|
+
this.syncMine();
|
|
8146
|
+
this.showToast(this.t("commenterSignedIn"));
|
|
8147
|
+
}
|
|
8148
|
+
signOutCommenter() {
|
|
8149
|
+
const token = this.commenterToken;
|
|
8150
|
+
if (!token) return;
|
|
8151
|
+
this.forgetCommenter();
|
|
8152
|
+
this.api.signOutCommenter(token);
|
|
8153
|
+
this.showToast(this.t("signedOut"));
|
|
8154
|
+
}
|
|
7986
8155
|
onMessage(e) {
|
|
7987
8156
|
let appOrigin;
|
|
7988
8157
|
try {
|
|
@@ -7992,7 +8161,12 @@ var NuniWidget = class {
|
|
|
7992
8161
|
}
|
|
7993
8162
|
if (e.origin !== appOrigin) return;
|
|
7994
8163
|
const data = e.data;
|
|
7995
|
-
if (!data || data.
|
|
8164
|
+
if (!data || data.project !== this.config.project) return;
|
|
8165
|
+
if (data.type === "nuni:commenter" && typeof data.token === "string" && data.token.startsWith("nuni_c_")) {
|
|
8166
|
+
this.onCommenterSignedIn(data.token);
|
|
8167
|
+
return;
|
|
8168
|
+
}
|
|
8169
|
+
if (data.type !== "nuni:session") return;
|
|
7996
8170
|
if (typeof data.token !== "string" || !data.token.startsWith("nuni_s_")) return;
|
|
7997
8171
|
this.ownerToken = data.token;
|
|
7998
8172
|
write(KEYS.session(this.config.project), data.token);
|
|
@@ -8040,7 +8214,8 @@ var NuniWidget = class {
|
|
|
8040
8214
|
setTimeout(() => this.scheduleLayout(), 400);
|
|
8041
8215
|
}
|
|
8042
8216
|
async submitDraft(draft, body, name) {
|
|
8043
|
-
const
|
|
8217
|
+
const signedIn = Boolean(this.commenter);
|
|
8218
|
+
const cleanName = (this.commenter?.name ?? name).trim().slice(0, LIMITS.nameMaxLength);
|
|
8044
8219
|
const cleanBody = body.trim();
|
|
8045
8220
|
if (!cleanName) return this.setDraftError(draft, this.t("enterName"));
|
|
8046
8221
|
const before = draft.suggesting ? draft.suggestFrom : null;
|
|
@@ -8053,8 +8228,10 @@ var NuniWidget = class {
|
|
|
8053
8228
|
} : void 0;
|
|
8054
8229
|
if (!cleanBody && !suggestion) return this.setDraftError(draft, this.t("writeFirst"));
|
|
8055
8230
|
if (cleanBody.length > LIMITS.bodyMaxLength) return this.setDraftError(draft, this.t("commentTooLong", { count: LIMITS.bodyMaxLength }));
|
|
8056
|
-
|
|
8057
|
-
|
|
8231
|
+
if (!signedIn) {
|
|
8232
|
+
this.name = cleanName;
|
|
8233
|
+
write(KEYS.name, cleanName);
|
|
8234
|
+
}
|
|
8058
8235
|
draft.sending = true;
|
|
8059
8236
|
draft.error = void 0;
|
|
8060
8237
|
this.render();
|
|
@@ -8065,7 +8242,7 @@ var NuniWidget = class {
|
|
|
8065
8242
|
body: cleanBody,
|
|
8066
8243
|
suggestion,
|
|
8067
8244
|
authorName: cleanName,
|
|
8068
|
-
|
|
8245
|
+
...this.author,
|
|
8069
8246
|
page: {
|
|
8070
8247
|
...loc,
|
|
8071
8248
|
path: this.pageKey,
|
|
@@ -8174,7 +8351,7 @@ var NuniWidget = class {
|
|
|
8174
8351
|
async deleteComment(c) {
|
|
8175
8352
|
if (!await this.ask(this.t("confirmDeleteComment"), this.t("delete"))) return;
|
|
8176
8353
|
const token = this.ownerToken;
|
|
8177
|
-
const action = this.isMine(c) ? () => this.api.deleteOwn(c._id, this.
|
|
8354
|
+
const action = this.isMine(c) ? () => this.api.deleteOwn(c._id, this.author) : token ? () => this.api.remove(c._id, token) : null;
|
|
8178
8355
|
if (!action) return;
|
|
8179
8356
|
this.act(c._id, action, this.t("deleted")).then((ok) => {
|
|
8180
8357
|
if (!ok) return;
|
|
@@ -8185,12 +8362,12 @@ var NuniWidget = class {
|
|
|
8185
8362
|
});
|
|
8186
8363
|
}
|
|
8187
8364
|
isMyReply(reply) {
|
|
8188
|
-
return
|
|
8365
|
+
return this.ownsKey(reply.authorKeyHash);
|
|
8189
8366
|
}
|
|
8190
8367
|
async sendReply(comment, body, name) {
|
|
8191
8368
|
const card = this.card;
|
|
8192
8369
|
if (card?.kind !== "thread" || card.id !== comment._id) return;
|
|
8193
|
-
const authorName = (this.isOwner ? this.ownerName : name)?.trim().slice(0, LIMITS.nameMaxLength);
|
|
8370
|
+
const authorName = (this.isOwner ? this.ownerName : this.commenter?.name ?? name)?.trim().slice(0, LIMITS.nameMaxLength);
|
|
8194
8371
|
const clean = body.trim();
|
|
8195
8372
|
if (!clean) return;
|
|
8196
8373
|
if (!authorName) {
|
|
@@ -8203,7 +8380,7 @@ var NuniWidget = class {
|
|
|
8203
8380
|
this.render();
|
|
8204
8381
|
return;
|
|
8205
8382
|
}
|
|
8206
|
-
if (!this.isOwner) {
|
|
8383
|
+
if (!this.isOwner && !this.commenter) {
|
|
8207
8384
|
this.name = authorName;
|
|
8208
8385
|
write(KEYS.name, authorName);
|
|
8209
8386
|
}
|
|
@@ -8215,7 +8392,7 @@ var NuniWidget = class {
|
|
|
8215
8392
|
commentId: comment._id,
|
|
8216
8393
|
body: clean,
|
|
8217
8394
|
authorName,
|
|
8218
|
-
|
|
8395
|
+
...this.author,
|
|
8219
8396
|
sessionToken: this.ownerToken ?? void 0
|
|
8220
8397
|
});
|
|
8221
8398
|
const box = this.uiLayer.querySelector("[data-focus-key=\"reply\"]");
|
|
@@ -8227,7 +8404,7 @@ var NuniWidget = class {
|
|
|
8227
8404
|
this.render();
|
|
8228
8405
|
}
|
|
8229
8406
|
toggleReaction(comment, targetId, emoji) {
|
|
8230
|
-
this.api.toggleReaction(comment._id, targetId, emoji, this.
|
|
8407
|
+
this.api.toggleReaction(comment._id, targetId, emoji, this.author).catch((error) => {
|
|
8231
8408
|
if (this.card?.kind === "thread" && this.card.id === comment._id) {
|
|
8232
8409
|
this.card.error = error instanceof Error ? error.message : this.t("reactFailed");
|
|
8233
8410
|
this.render();
|
|
@@ -8237,11 +8414,11 @@ var NuniWidget = class {
|
|
|
8237
8414
|
async deleteReply(comment, reply) {
|
|
8238
8415
|
if (!await this.ask(this.t("confirmDeleteReply"), this.t("delete"))) return;
|
|
8239
8416
|
const token = this.ownerToken;
|
|
8240
|
-
const action = this.isMyReply(reply) ? () => this.api.deleteReply(reply._id, this.
|
|
8417
|
+
const action = this.isMyReply(reply) ? () => this.api.deleteReply(reply._id, this.author) : token ? () => this.api.removeReply(reply._id, token) : null;
|
|
8241
8418
|
if (action) this.act(comment._id, action, this.t("replyDeleted"));
|
|
8242
8419
|
}
|
|
8243
8420
|
saveReplyEdit(comment, reply, body) {
|
|
8244
|
-
this.act(comment._id, () => this.api.editReply(reply._id, this.
|
|
8421
|
+
this.act(comment._id, () => this.api.editReply(reply._id, this.author, body), this.t("saved")).then((ok) => {
|
|
8245
8422
|
if (ok && this.card?.kind === "thread") {
|
|
8246
8423
|
this.card.replyEditing = void 0;
|
|
8247
8424
|
this.render();
|
|
@@ -8249,7 +8426,7 @@ var NuniWidget = class {
|
|
|
8249
8426
|
});
|
|
8250
8427
|
}
|
|
8251
8428
|
saveEdit(c, body, suggestion) {
|
|
8252
|
-
this.act(c._id, () => this.api.editOwn(c._id, this.
|
|
8429
|
+
this.act(c._id, () => this.api.editOwn(c._id, this.author, body, suggestion), this.t("saved"));
|
|
8253
8430
|
}
|
|
8254
8431
|
/** For the owner: the suggested words, ready to paste into the code. */
|
|
8255
8432
|
copyNewTextButton(text) {
|
|
@@ -8268,11 +8445,24 @@ var NuniWidget = class {
|
|
|
8268
8445
|
}, 2400);
|
|
8269
8446
|
this.render();
|
|
8270
8447
|
}
|
|
8448
|
+
/** Keep Yours subscribed with the current sign-in, once the panel opened. */
|
|
8449
|
+
syncMine() {
|
|
8450
|
+
if (!this.mineUnsub && !this.panelOpen) return;
|
|
8451
|
+
if (this.mineUnsub && this.mineToken === this.commenterToken) return;
|
|
8452
|
+
this.mineUnsub?.();
|
|
8453
|
+
this.mine = null;
|
|
8454
|
+
this.mineToken = this.commenterToken;
|
|
8455
|
+
this.mineUnsub = this.api.onMine(this.author, (mine) => {
|
|
8456
|
+
this.mine = mine;
|
|
8457
|
+
this.render();
|
|
8458
|
+
});
|
|
8459
|
+
}
|
|
8271
8460
|
togglePanel(open = !this.panelOpen) {
|
|
8272
8461
|
if (open === this.panelOpen) return;
|
|
8273
8462
|
this.panelOpen = open;
|
|
8274
|
-
if (open
|
|
8275
|
-
|
|
8463
|
+
if (open) this.syncMine();
|
|
8464
|
+
if (open && !this.siteUnsub) this.siteUnsub = this.api.onSite((site) => {
|
|
8465
|
+
this.site = site;
|
|
8276
8466
|
this.render();
|
|
8277
8467
|
});
|
|
8278
8468
|
if (open) {
|
|
@@ -8370,8 +8560,8 @@ var NuniWidget = class {
|
|
|
8370
8560
|
const pin = h("div", {
|
|
8371
8561
|
class: "pin pin-draft pin-pending",
|
|
8372
8562
|
"aria-hidden": "true"
|
|
8373
|
-
}, this.
|
|
8374
|
-
pin.style.background = this.
|
|
8563
|
+
}, this.displayName ? initials(this.displayName) : "+");
|
|
8564
|
+
pin.style.background = this.displayName ? colorFor(this.displayName) : "var(--n-accent)";
|
|
8375
8565
|
pin.style.transform = `translate(${Math.round(x)}px, ${Math.round(y)}px)`;
|
|
8376
8566
|
this.pinLayer.append(pin);
|
|
8377
8567
|
}
|
|
@@ -8414,6 +8604,7 @@ var NuniWidget = class {
|
|
|
8414
8604
|
role: "toolbar",
|
|
8415
8605
|
"aria-label": this.t("toolbar"),
|
|
8416
8606
|
"data-dragging": !!drag,
|
|
8607
|
+
"data-pins-hidden": this.pinsHidden,
|
|
8417
8608
|
style: drag && `transform: translate(${drag.dx}px, ${drag.dy}px)`,
|
|
8418
8609
|
onpointerdown: (e) => this.startToolbarDrag(e)
|
|
8419
8610
|
}, h("button", {
|
|
@@ -8432,7 +8623,15 @@ var NuniWidget = class {
|
|
|
8432
8623
|
"aria-label": this.t("openCount", { count: open }),
|
|
8433
8624
|
title: this.t("allComments"),
|
|
8434
8625
|
onclick: () => this.togglePanel()
|
|
8435
|
-
}, icon(ICONS.list), h("span", { class: "tb-count" }, String(open)))
|
|
8626
|
+
}, icon(ICONS.list), h("span", { class: "tb-count" }, String(open))), h("button", {
|
|
8627
|
+
class: "tb-btn tb-icon",
|
|
8628
|
+
type: "button",
|
|
8629
|
+
"aria-pressed": String(this.pinsHidden),
|
|
8630
|
+
"data-focus-key": "tb-hide",
|
|
8631
|
+
"aria-label": this.t("hideComments"),
|
|
8632
|
+
title: this.withKey("hideComments", "hideCommentsKey"),
|
|
8633
|
+
onclick: () => this.setPinsHidden(!this.pinsHidden)
|
|
8634
|
+
}, icon(this.pinsHidden ? ICONS.eyeOff : ICONS.eye)));
|
|
8436
8635
|
}
|
|
8437
8636
|
/**
|
|
8438
8637
|
* Drag the toolbar anywhere; on release it glides to the nearest corner or
|
|
@@ -8515,10 +8714,18 @@ var NuniWidget = class {
|
|
|
8515
8714
|
const query = this.search.trim().toLocaleLowerCase();
|
|
8516
8715
|
const matches = (...texts) => !query || texts.some((t) => t?.toLocaleLowerCase().includes(query));
|
|
8517
8716
|
const mine = this.mine ?? [];
|
|
8518
|
-
const list = (this.tab === "open" ? open : this.tab === "resolved" ? resolved : mine).filter((c) => matches(c.body, c.authorName, c.anchor.quote?.exact, c.suggestion?.after,
|
|
8717
|
+
const list = (this.tab === "open" ? open : this.tab === "resolved" ? resolved : mine).filter((c) => matches(c.body, c.authorName, c.anchor.quote?.exact, c.suggestion?.after, c.page.path));
|
|
8519
8718
|
const placed = list.filter((c) => this.placements.get(c._id)?.element);
|
|
8520
8719
|
const lost = list.filter((c) => !this.placements.get(c._id)?.element);
|
|
8521
|
-
const
|
|
8720
|
+
const elsewhere = (this.site ?? []).filter((c) => c.page.path !== this.pageKey);
|
|
8721
|
+
const elsewhereOf = (status) => elsewhere.filter((c) => c.status === status);
|
|
8722
|
+
const groups = /* @__PURE__ */ new Map();
|
|
8723
|
+
for (const c of elsewhereOf(this.tab === "resolved" ? "resolved" : "open")) {
|
|
8724
|
+
if (!matches(c.body, c.authorName, c.anchor.quote?.exact, c.suggestion?.after, c.page.path)) continue;
|
|
8725
|
+
groups.set(c.page.path, [...groups.get(c.page.path) ?? [], c]);
|
|
8726
|
+
}
|
|
8727
|
+
const listed = new Set(elsewhereOf(this.tab === "resolved" ? "resolved" : "open").map((c) => c.page.path));
|
|
8728
|
+
const otherPages = this.pages.filter((p) => p.path !== this.pageKey && !listed.has(p.path) && matches(p.path));
|
|
8522
8729
|
const content = (c) => [c.suggestion ? renderSuggestionLine(c.suggestion) : c.anchor.quote ? h("div", { class: "item-quote" }, c.anchor.quote.exact) : null, c.body ? h("div", { class: "item-text" }, c.body) : null];
|
|
8523
8730
|
const mineItem = (c) => {
|
|
8524
8731
|
const here = c.page.path === this.pageKey;
|
|
@@ -8537,16 +8744,15 @@ var NuniWidget = class {
|
|
|
8537
8744
|
href
|
|
8538
8745
|
}, h("div", { class: "row" }, h("span", { class: "author" }, here ? this.t("thisPage") : c.page.path), h("span", { class: "meta" }, this.i18n.timeAgo(c.createdAt)), h("span", { class: "spacer" }), h("span", { class: resolvedBadge ? "badge badge-ok" : "badge" }, resolvedBadge ? icon(ICONS.check) : null, this.t(!resolvedBadge ? "statusOpen" : c.resolution === "outdated" ? "outdated" : "resolved"))), ...content(c));
|
|
8539
8746
|
};
|
|
8540
|
-
const item = (c) => h("button", {
|
|
8747
|
+
const item = (c, href) => h(href === void 0 ? "button" : href === null ? "div" : "a", {
|
|
8541
8748
|
class: "item",
|
|
8542
|
-
type: "button",
|
|
8543
8749
|
"aria-current": c._id === this.lastViewedId ? "true" : null,
|
|
8544
8750
|
"data-focus-key": `item-${c._id}`,
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
},
|
|
8751
|
+
...href === void 0 ? {
|
|
8752
|
+
type: "button",
|
|
8753
|
+
onclick: () => this.focusComment(c._id)
|
|
8754
|
+
} : { href }
|
|
8755
|
+
}, h("div", { class: "row" }, ...this.authorLine(c), h("span", { class: "meta" }, this.i18n.timeAgo(c.createdAt) + (c.replyCount ? ` · ${this.t("replyCount", { count: c.replyCount })}` : "")), c.page.origin !== location.origin ? h("span", {
|
|
8550
8756
|
class: "badge",
|
|
8551
8757
|
title: c.page.origin
|
|
8552
8758
|
}, new URL(c.page.origin).host) : null, c.resolution === "outdated" ? h("span", { class: "badge" }, this.t("outdated")) : null), ...content(c));
|
|
@@ -8556,14 +8762,20 @@ var NuniWidget = class {
|
|
|
8556
8762
|
else if (!list.length) children.push(h("div", { class: "empty" }, query ? this.t("noMatches", { query: this.search.trim() }) : this.t("noYours")));
|
|
8557
8763
|
else children.push(...list.map(mineItem));
|
|
8558
8764
|
} else if (!this.loaded) children.push(h("div", { class: "empty" }, this.t("loading")));
|
|
8559
|
-
else if (!list.length && query) children.push(h("div", { class: "empty" }, this.t("noMatches", { query: this.search.trim() })));
|
|
8560
|
-
else if (!list.length) children.push(h("div", { class: "empty" }, this.tab === "open" ? this.withKey("noOpen", "noOpenKey") : this.t("noResolved")));
|
|
8561
8765
|
else {
|
|
8562
|
-
children.push(
|
|
8563
|
-
if (
|
|
8564
|
-
children.push(
|
|
8565
|
-
|
|
8766
|
+
if ((groups.size > 0 || otherPages.length > 0) && (list.length || !query)) children.push(h("div", { class: "section-label" }, this.t("thisPage")));
|
|
8767
|
+
if (list.length) {
|
|
8768
|
+
children.push(...placed.map((c) => item(c)));
|
|
8769
|
+
if (lost.length) {
|
|
8770
|
+
children.push(h("div", { class: "section-label" }, this.t("notFoundHere")));
|
|
8771
|
+
children.push(...lost.map((c) => item(c)));
|
|
8772
|
+
}
|
|
8773
|
+
} else if (!query) children.push(h("div", { class: "empty" }, this.tab === "open" ? this.withKey("noOpen", "noOpenKey") : this.t("noResolved")));
|
|
8774
|
+
for (const [path, comments] of groups) {
|
|
8775
|
+
children.push(h("div", { class: "section-label section-path" }, path));
|
|
8776
|
+
children.push(...comments.map((c) => item(c, commentHref(c, location))));
|
|
8566
8777
|
}
|
|
8778
|
+
if (!children.length && !otherPages.length) children.push(h("div", { class: "empty" }, this.t("noMatches", { query: this.search.trim() })));
|
|
8567
8779
|
}
|
|
8568
8780
|
if (otherPages.length && this.tab !== "mine") {
|
|
8569
8781
|
children.push(h("div", { class: "section-label" }, this.t("otherPages")));
|
|
@@ -8584,7 +8796,7 @@ var NuniWidget = class {
|
|
|
8584
8796
|
type: "button",
|
|
8585
8797
|
"aria-label": this.t("close"),
|
|
8586
8798
|
onclick: () => this.togglePanel(false)
|
|
8587
|
-
}, icon(ICONS.close))), this.comments.length || this.mine?.length ? h("div", { class: "panel-search" }, icon(ICONS.search), h("input", {
|
|
8799
|
+
}, icon(ICONS.close))), this.comments.length || this.mine?.length || this.site?.length ? h("div", { class: "panel-search" }, icon(ICONS.search), h("input", {
|
|
8588
8800
|
class: "field",
|
|
8589
8801
|
type: "search",
|
|
8590
8802
|
value: this.search,
|
|
@@ -8628,22 +8840,30 @@ var NuniWidget = class {
|
|
|
8628
8840
|
this.tab = tab;
|
|
8629
8841
|
this.render();
|
|
8630
8842
|
}
|
|
8631
|
-
}, tab === "open" ? this.t("tabOpen", { count: open.length }) : tab === "resolved" ? this.t("tabResolved", { count: resolved.length }) : this.mine ? this.t("tabYours", { count: this.mine.length }) : this.t("yours")))), h("div", {
|
|
8843
|
+
}, tab === "open" ? this.t("tabOpen", { count: open.length + elsewhereOf("open").length }) : tab === "resolved" ? this.t("tabResolved", { count: resolved.length + elsewhereOf("resolved").length }) : this.mine ? this.t("tabYours", { count: this.mine.length }) : this.t("yours")))), h("div", {
|
|
8632
8844
|
class: "panel-list",
|
|
8633
8845
|
id: "nuni-panel-list",
|
|
8634
8846
|
role: "tabpanel",
|
|
8635
8847
|
"aria-labelledby": `nuni-tab-${this.tab}`
|
|
8636
|
-
}, ...children), this.
|
|
8848
|
+
}, ...children), this.renderPanelFooter());
|
|
8637
8849
|
}
|
|
8638
8850
|
renderPanelFooter() {
|
|
8639
|
-
|
|
8851
|
+
const claimable = this.status && !this.status.claimed && !this.isOwner;
|
|
8852
|
+
const commenter = this.commenter;
|
|
8853
|
+
if (!claimable && !commenter) return null;
|
|
8854
|
+
return h("div", { class: "panel-foot" }, commenter ? h("div", { class: "row" }, avatar(commenter.name, commenter.avatarUrl), h("span", { class: "meta signed-in-as" }, this.t("signedInAs", { name: commenter.name })), h("span", { class: "spacer" }), h("button", {
|
|
8855
|
+
class: "cmp-link",
|
|
8856
|
+
type: "button",
|
|
8857
|
+
onclick: () => this.signOutCommenter()
|
|
8858
|
+
}, this.t("signOut"))) : null, claimable ? h("div", { class: "row" }, h("span", { class: "meta" }, this.t("ownSite")), h("span", { class: "spacer" }), h("button", {
|
|
8640
8859
|
class: "btn",
|
|
8641
8860
|
type: "button",
|
|
8642
8861
|
onclick: () => this.openClaim()
|
|
8643
|
-
}, icon(ICONS.github), this.t("claim"))));
|
|
8862
|
+
}, icon(ICONS.github), this.t("claim"))) : null);
|
|
8644
8863
|
}
|
|
8645
8864
|
renderComposer(draft, cls) {
|
|
8646
|
-
const
|
|
8865
|
+
const commenter = this.commenter;
|
|
8866
|
+
const needsName = !commenter && !this.name;
|
|
8647
8867
|
const avatar = h("span", {
|
|
8648
8868
|
class: "avatar cmp-avatar",
|
|
8649
8869
|
"aria-hidden": "true"
|
|
@@ -8769,7 +8989,15 @@ var NuniWidget = class {
|
|
|
8769
8989
|
e.preventDefault();
|
|
8770
8990
|
submit();
|
|
8771
8991
|
}
|
|
8772
|
-
}, h("div", { class: "cmp-head" },
|
|
8992
|
+
}, commenter ? h("div", { class: "cmp-head" }, ...this.authorLine({
|
|
8993
|
+
authorName: commenter.name,
|
|
8994
|
+
avatarUrl: commenter.avatarUrl,
|
|
8995
|
+
signedIn: true
|
|
8996
|
+
}), h("span", { class: "spacer" }), h("button", {
|
|
8997
|
+
class: "cmp-link",
|
|
8998
|
+
type: "button",
|
|
8999
|
+
onclick: () => this.signOutCommenter()
|
|
9000
|
+
}, this.t("signOut"))) : h("div", { class: "cmp-head cmp-head-guest" }, avatar, needsName ? nameInput : h("span", { class: "author" }, this.name), h("span", { class: "spacer" }), needsName ? null : h("button", {
|
|
8773
9001
|
class: "cmp-link",
|
|
8774
9002
|
type: "button",
|
|
8775
9003
|
onclick: () => {
|
|
@@ -8818,7 +9046,12 @@ var NuniWidget = class {
|
|
|
8818
9046
|
title: this.t(draft.preparingMarkup ? "preparingScreenshot" : "markUpScreenshot"),
|
|
8819
9047
|
disabled: Boolean(draft.preparingMarkup),
|
|
8820
9048
|
onclick: () => void this.markUpScreenshot(draft)
|
|
8821
|
-
}, icon(ICONS.pen)) : null, fileInput, counter, h("span", { class: "spacer" }), post), h("button", {
|
|
9049
|
+
}, icon(ICONS.pen)) : null, fileInput, counter, h("span", { class: "spacer" }), post), commenter ? null : h("button", {
|
|
9050
|
+
class: "cmp-link cmp-sign-in",
|
|
9051
|
+
type: "button",
|
|
9052
|
+
title: this.t("signInGithub"),
|
|
9053
|
+
onclick: () => this.openCommenterSignIn()
|
|
9054
|
+
}, icon(ICONS.github), this.t("signIn")), h("button", {
|
|
8822
9055
|
class: "icon-btn cmp-close",
|
|
8823
9056
|
type: "button",
|
|
8824
9057
|
"aria-label": this.t("cancel"),
|
|
@@ -8889,7 +9122,7 @@ var NuniWidget = class {
|
|
|
8889
9122
|
].filter((badge) => badge !== null);
|
|
8890
9123
|
const contextPending = owner && !(this.ownerDetailLoaded && this.ownerDetailId === comment._id);
|
|
8891
9124
|
const resolved = comment.status === "resolved";
|
|
8892
|
-
body = h("div", { class: "card-body msg" }, h("div", { class: "card-head" },
|
|
9125
|
+
body = h("div", { class: "card-body msg" }, h("div", { class: "card-head" }, ...this.authorLine(comment), h("span", { class: "meta" }, this.i18n.timeAgo(comment.createdAt) + (comment.editedAt ? ` · ${this.t("edited")}` : "")), h("span", { class: "spacer" }), owner ? h("button", {
|
|
8893
9126
|
class: `icon-btn${resolved ? " is-resolved" : ""}`,
|
|
8894
9127
|
type: "button",
|
|
8895
9128
|
"aria-label": this.t(resolved ? "reopen" : "resolve"),
|
|
@@ -8982,7 +9215,7 @@ var NuniWidget = class {
|
|
|
8982
9215
|
const open = card.picker === targetId;
|
|
8983
9216
|
if (!withAdd && !summaries.length && !open) return null;
|
|
8984
9217
|
return h("div", { class: "reactions" }, ...summaries.map((r) => {
|
|
8985
|
-
const mine = r.authorKeyHashes.includes(this.
|
|
9218
|
+
const mine = r.authorKeyHashes.includes(this.authorKey);
|
|
8986
9219
|
return h("button", {
|
|
8987
9220
|
class: "reaction",
|
|
8988
9221
|
type: "button",
|
|
@@ -9055,7 +9288,7 @@ var NuniWidget = class {
|
|
|
9055
9288
|
return h("div", {
|
|
9056
9289
|
class: "reply msg",
|
|
9057
9290
|
"data-reply": reply._id
|
|
9058
|
-
}, h("div", { class: "card-head" },
|
|
9291
|
+
}, h("div", { class: "card-head" }, ...this.authorLine(reply), reply.isOwner ? h("span", { class: "badge badge-owner" }, this.t("owner")) : null, h("span", { class: "meta" }, this.i18n.timeAgo(reply.createdAt) + (reply.editedAt ? ` · ${this.t("edited")}` : "")), h("span", { class: "spacer" }), h("span", { class: "msg-tools" }, this.reactionAdd(reply._id, "icon-btn"), mine ? h("button", {
|
|
9059
9292
|
class: "icon-btn",
|
|
9060
9293
|
type: "button",
|
|
9061
9294
|
"aria-label": this.t("editReply"),
|
|
@@ -9074,7 +9307,7 @@ var NuniWidget = class {
|
|
|
9074
9307
|
onclick: () => void this.deleteReply(comment, reply)
|
|
9075
9308
|
}, icon(ICONS.trash)) : null)), h("div", { class: "msg-main" }, h("div", { class: "comment-body" }, reply.body), this.renderReactions(comment, reply._id, false)));
|
|
9076
9309
|
});
|
|
9077
|
-
const needsName = !owner && !this.
|
|
9310
|
+
const needsName = !owner && !this.displayName;
|
|
9078
9311
|
const nameInput = h("input", {
|
|
9079
9312
|
class: "reply-name",
|
|
9080
9313
|
placeholder: this.t("yourName"),
|
|
@@ -9167,7 +9400,7 @@ var NuniWidget = class {
|
|
|
9167
9400
|
}
|
|
9168
9401
|
focusComposer() {
|
|
9169
9402
|
requestAnimationFrame(() => {
|
|
9170
|
-
this.uiLayer.querySelector(this.
|
|
9403
|
+
this.uiLayer.querySelector(this.displayName ? "[data-focus-key=\"body\"]" : "[data-focus-key=\"name\"]")?.focus();
|
|
9171
9404
|
});
|
|
9172
9405
|
}
|
|
9173
9406
|
};
|
|
@@ -9269,7 +9502,7 @@ function unmount(state) {
|
|
|
9269
9502
|
* down the widget it was created for.
|
|
9270
9503
|
*/
|
|
9271
9504
|
function init(options) {
|
|
9272
|
-
return mount(options, { loadScreenshot: () => import("./screenshot-tools-
|
|
9505
|
+
return mount(options, { loadScreenshot: () => import("./screenshot-tools-BFj-93o4.js").then((m) => m.screenshotTools) });
|
|
9273
9506
|
}
|
|
9274
9507
|
//#endregion
|
|
9275
9508
|
export { VERSION, init, EN as messages };
|