@nuniapp/widget 0.1.6 → 0.1.7
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/dist/index.d.ts +4 -3
- package/dist/index.js +462 -240
- package/dist/nuni.global.js +232 -59
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -165,7 +165,7 @@ function buildCommentPrompt(comment, options = {}) {
|
|
|
165
165
|
}
|
|
166
166
|
//#endregion
|
|
167
167
|
//#region src/config.ts
|
|
168
|
-
const VERSION = "0.1.
|
|
168
|
+
const VERSION = "0.1.7";
|
|
169
169
|
function resolveConfig(options) {
|
|
170
170
|
return {
|
|
171
171
|
project: options.project,
|
|
@@ -5567,14 +5567,15 @@ const EN = {
|
|
|
5567
5567
|
yourName: "Your name",
|
|
5568
5568
|
leaveComment: "Leave a comment",
|
|
5569
5569
|
notYou: "Not you?",
|
|
5570
|
-
screenshotAlt: "Screenshot that will be attached",
|
|
5571
|
-
screenshotNote: "Screenshot attached. Only the site owner sees it.",
|
|
5572
|
-
remove: "Remove",
|
|
5573
5570
|
cancel: "Cancel",
|
|
5574
5571
|
post: "Post",
|
|
5575
5572
|
posting: "Posting…",
|
|
5576
5573
|
save: "Save",
|
|
5577
5574
|
send: "{key} + Enter",
|
|
5575
|
+
charsLeft: {
|
|
5576
|
+
one: "{count} character left",
|
|
5577
|
+
other: "{count} characters left"
|
|
5578
|
+
},
|
|
5578
5579
|
pinLabel: "Comment by {name}: {body}",
|
|
5579
5580
|
commentBy: "Comment by {name}",
|
|
5580
5581
|
openScreenshot: "Open the screenshot",
|
|
@@ -5687,6 +5688,8 @@ const ICONS = {
|
|
|
5687
5688
|
send: s("<path d=\"m22 2-7 20-4-9-9-4z\"/><path d=\"M22 2 11 13\"/>"),
|
|
5688
5689
|
bot: s("<path d=\"M12 8V4H8\"/><rect width=\"16\" height=\"12\" x=\"4\" y=\"8\" rx=\"2\"/><path d=\"M2 14h2M20 14h2M15 13v2M9 13v2\"/>"),
|
|
5689
5690
|
smile: s("<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M8 14s1.5 2 4 2 4-2 4-2M9 9h.01M15 9h.01\"/>"),
|
|
5691
|
+
user: s("<circle cx=\"12\" cy=\"8\" r=\"4\"/><path d=\"M4 21a8 8 0 0 1 16 0\"/>"),
|
|
5692
|
+
arrowUp: s("<path d=\"M12 19V5M5 12l7-7 7 7\"/>"),
|
|
5690
5693
|
target: s("<circle cx=\"12\" cy=\"12\" r=\"9\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>"),
|
|
5691
5694
|
github: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M12 .5a11.5 11.5 0 0 0-3.6 22.4c.6.1.8-.3.8-.6v-2c-3.2.7-3.9-1.5-3.9-1.5-.5-1.3-1.3-1.7-1.3-1.7-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.7-1.6-2.6-.3-5.3-1.3-5.3-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.2 1.2a11 11 0 0 1 5.8 0c2.2-1.5 3.2-1.2 3.2-1.2.6 1.6.2 2.8.1 3.1.8.8 1.2 1.9 1.2 3.1 0 4.4-2.7 5.4-5.3 5.7.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A11.5 11.5 0 0 0 12 .5z"/></svg>`,
|
|
5692
5695
|
link: s("<path d=\"M15 3h6v6M10 14 21 3M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/>")
|
|
@@ -6226,59 +6229,34 @@ button { cursor: pointer; }
|
|
|
6226
6229
|
/* Cards (composer + thread) */
|
|
6227
6230
|
.card {
|
|
6228
6231
|
position: fixed;
|
|
6229
|
-
width:
|
|
6232
|
+
width: 340px;
|
|
6230
6233
|
max-width: calc(100vw - 24px);
|
|
6231
6234
|
background: var(--n-bg);
|
|
6232
6235
|
color: var(--n-fg);
|
|
6233
6236
|
border: 1px solid var(--n-border);
|
|
6234
|
-
border-radius:
|
|
6237
|
+
border-radius: 14px;
|
|
6235
6238
|
box-shadow: var(--n-shadow);
|
|
6236
6239
|
pointer-events: auto;
|
|
6237
6240
|
overflow: hidden;
|
|
6238
6241
|
}
|
|
6239
|
-
.card-body { padding: 12px; display: grid; gap: 10px; }
|
|
6242
|
+
.card-body { padding: 12px 14px; display: grid; gap: 10px; }
|
|
6240
6243
|
.card[data-card="thread"] { display: flex; flex-direction: column; max-height: calc(100vh - 24px); }
|
|
6241
|
-
.
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
.reply-form .field { flex: 1 1 100%; }
|
|
6248
|
-
/* A fixed size: growing on focus would move the Send button mid-click. */
|
|
6249
|
-
.reply-form .field-reply { flex: 1 1 0; min-height: 56px; height: 56px; resize: none; }
|
|
6250
|
-
.reactions { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; position: relative; }
|
|
6251
|
-
.reaction {
|
|
6252
|
-
display: inline-flex;
|
|
6253
|
-
align-items: center;
|
|
6254
|
-
gap: 4px;
|
|
6255
|
-
height: 24px;
|
|
6256
|
-
padding: 0 8px;
|
|
6257
|
-
border: 1px solid var(--n-border);
|
|
6258
|
-
border-radius: 999px;
|
|
6259
|
-
background: var(--n-bg);
|
|
6244
|
+
.card .quote {
|
|
6245
|
+
margin: 0;
|
|
6246
|
+
padding: 6px 10px;
|
|
6247
|
+
border-left: 0;
|
|
6248
|
+
border-radius: 8px;
|
|
6249
|
+
background: var(--n-accent-soft);
|
|
6260
6250
|
color: var(--n-fg);
|
|
6261
|
-
font-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
.reaction[aria-pressed="true"] { border-color: var(--n-accent); background: var(--n-accent-soft); }
|
|
6265
|
-
.reaction-add { color: var(--n-fg-muted); padding: 0 6px; }
|
|
6266
|
-
.reaction-picker {
|
|
6267
|
-
display: flex;
|
|
6268
|
-
gap: 2px;
|
|
6269
|
-
padding: 4px;
|
|
6270
|
-
border: 1px solid var(--n-border);
|
|
6271
|
-
border-radius: 999px;
|
|
6272
|
-
background: var(--n-bg);
|
|
6273
|
-
box-shadow: var(--n-shadow);
|
|
6251
|
+
font-style: normal;
|
|
6252
|
+
font-size: 13px;
|
|
6253
|
+
box-shadow: inset 2px 0 0 var(--n-accent);
|
|
6274
6254
|
}
|
|
6275
|
-
.
|
|
6276
|
-
.btn-xs { width: 24px; height: 24px; }
|
|
6277
|
-
.card-head { display: flex; align-items: center; gap: 8px; }
|
|
6255
|
+
.card-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
6278
6256
|
.card-head .spacer { flex: 1; }
|
|
6279
6257
|
.avatar {
|
|
6280
|
-
width:
|
|
6281
|
-
height:
|
|
6258
|
+
width: 26px;
|
|
6259
|
+
height: 26px;
|
|
6282
6260
|
border-radius: 999px;
|
|
6283
6261
|
color: #fff;
|
|
6284
6262
|
font-size: 10px;
|
|
@@ -6288,8 +6266,8 @@ button { cursor: pointer; }
|
|
|
6288
6266
|
justify-content: center;
|
|
6289
6267
|
flex: none;
|
|
6290
6268
|
}
|
|
6291
|
-
.author { font-weight: 600; }
|
|
6292
|
-
.meta { color: var(--n-fg-muted); font-size: 12px; }
|
|
6269
|
+
.author { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
6270
|
+
.meta { color: var(--n-fg-muted); font-size: 12px; white-space: nowrap; }
|
|
6293
6271
|
.badge {
|
|
6294
6272
|
display: inline-flex;
|
|
6295
6273
|
align-items: center;
|
|
@@ -6304,28 +6282,147 @@ button { cursor: pointer; }
|
|
|
6304
6282
|
text-overflow: ellipsis;
|
|
6305
6283
|
white-space: nowrap;
|
|
6306
6284
|
}
|
|
6285
|
+
.badge .icon { width: 12px; height: 12px; }
|
|
6307
6286
|
.badge-ok { background: rgba(31,157,85,0.14); color: var(--n-ok); }
|
|
6308
|
-
.
|
|
6287
|
+
.badge-owner { background: var(--n-accent-soft); color: var(--n-accent); }
|
|
6288
|
+
.comment-body { white-space: pre-wrap; word-break: break-word; line-height: 1.5; }
|
|
6309
6289
|
.shot {
|
|
6310
6290
|
display: block;
|
|
6311
6291
|
border: 1px solid var(--n-border);
|
|
6312
|
-
border-radius:
|
|
6292
|
+
border-radius: 10px;
|
|
6313
6293
|
overflow: hidden;
|
|
6314
6294
|
background: var(--n-bg-subtle);
|
|
6315
6295
|
}
|
|
6316
6296
|
.shot img { display: block; width: 100%; max-height: 160px; object-fit: cover; object-position: top; }
|
|
6317
|
-
.
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
width:
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
border: 1px solid var(--n-border);
|
|
6297
|
+
.icon-btn {
|
|
6298
|
+
display: inline-grid;
|
|
6299
|
+
place-items: center;
|
|
6300
|
+
width: 28px;
|
|
6301
|
+
height: 28px;
|
|
6302
|
+
padding: 0;
|
|
6303
|
+
border: 0;
|
|
6325
6304
|
border-radius: 8px;
|
|
6326
|
-
background:
|
|
6305
|
+
background: none;
|
|
6306
|
+
color: var(--n-fg-muted);
|
|
6307
|
+
flex: none;
|
|
6308
|
+
transition: background 120ms ease, color 120ms ease;
|
|
6327
6309
|
}
|
|
6328
|
-
.
|
|
6310
|
+
.icon-btn:hover { background: var(--n-bg-subtle); color: var(--n-fg); }
|
|
6311
|
+
.icon-btn:disabled { opacity: 0.4; cursor: default; background: none; }
|
|
6312
|
+
.icon-btn-danger:hover { background: color-mix(in srgb, var(--n-danger) 12%, transparent); color: var(--n-danger); }
|
|
6313
|
+
.icon-btn.is-resolved, .icon-btn.is-resolved:hover { background: rgba(31,157,85,0.14); color: var(--n-ok); }
|
|
6314
|
+
|
|
6315
|
+
/* A message (the comment or a reply): text lines up with the name. */
|
|
6316
|
+
.msg { gap: 2px; padding: 12px 8px 8px 14px; }
|
|
6317
|
+
.msg-main { display: grid; gap: 8px; padding: 0 6px 0 34px; min-width: 0; }
|
|
6318
|
+
.msg .card-head { min-height: 28px; }
|
|
6319
|
+
.badges { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
6320
|
+
.msg-foot { display: flex; align-items: center; gap: 2px; margin-right: -6px; }
|
|
6321
|
+
.msg-foot .spacer { flex: 1; }
|
|
6322
|
+
/* A reply's tools float over its header on hover, so names never truncate. */
|
|
6323
|
+
.msg-tools:empty { display: none; }
|
|
6324
|
+
.msg-tools {
|
|
6325
|
+
position: absolute;
|
|
6326
|
+
top: 4px;
|
|
6327
|
+
right: 8px;
|
|
6328
|
+
display: flex;
|
|
6329
|
+
gap: 2px;
|
|
6330
|
+
padding: 2px;
|
|
6331
|
+
border: 1px solid var(--n-border);
|
|
6332
|
+
border-radius: 10px;
|
|
6333
|
+
background: var(--n-bg);
|
|
6334
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.08);
|
|
6335
|
+
opacity: 0;
|
|
6336
|
+
pointer-events: none;
|
|
6337
|
+
transition: opacity 120ms ease;
|
|
6338
|
+
}
|
|
6339
|
+
.reply:hover .msg-tools, .reply:focus-within .msg-tools { opacity: 1; pointer-events: auto; }
|
|
6340
|
+
@media (hover: none) {
|
|
6341
|
+
.msg-tools { position: static; opacity: 1; pointer-events: auto; padding: 0; border: 0; box-shadow: none; background: none; }
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
/* Replies */
|
|
6345
|
+
.thread { border-top: 1px solid var(--n-border); display: grid; min-height: 0; }
|
|
6346
|
+
.replies { display: grid; padding: 4px 0; overflow-y: auto; max-height: 45vh; }
|
|
6347
|
+
.reply.msg { position: relative; display: grid; padding: 8px 8px 8px 14px; }
|
|
6348
|
+
.reply-form {
|
|
6349
|
+
display: grid;
|
|
6350
|
+
margin: 4px 12px 12px;
|
|
6351
|
+
border: 1px solid var(--n-border);
|
|
6352
|
+
border-radius: 12px;
|
|
6353
|
+
background: var(--n-bg);
|
|
6354
|
+
transition: box-shadow 140ms ease, border-color 140ms ease;
|
|
6355
|
+
}
|
|
6356
|
+
.reply-form:focus-within {
|
|
6357
|
+
border-color: color-mix(in srgb, var(--n-accent) 45%, var(--n-border));
|
|
6358
|
+
box-shadow: 0 0 0 3px var(--n-accent-soft);
|
|
6359
|
+
}
|
|
6360
|
+
.reply-name {
|
|
6361
|
+
padding: 8px 12px 6px;
|
|
6362
|
+
border: 0;
|
|
6363
|
+
border-bottom: 1px solid var(--n-border);
|
|
6364
|
+
background: none;
|
|
6365
|
+
outline: none;
|
|
6366
|
+
font-weight: 600;
|
|
6367
|
+
}
|
|
6368
|
+
.reply-row { display: flex; align-items: flex-end; gap: 4px; padding: 4px; }
|
|
6369
|
+
.reply-text {
|
|
6370
|
+
flex: 1;
|
|
6371
|
+
min-width: 0;
|
|
6372
|
+
min-height: 32px;
|
|
6373
|
+
max-height: 160px;
|
|
6374
|
+
padding: 6px 8px;
|
|
6375
|
+
border: 0;
|
|
6376
|
+
background: none;
|
|
6377
|
+
outline: none;
|
|
6378
|
+
resize: none;
|
|
6379
|
+
line-height: 1.4;
|
|
6380
|
+
}
|
|
6381
|
+
.reply-name::placeholder, .reply-text::placeholder { color: var(--n-fg-muted); opacity: 1; font-weight: 400; }
|
|
6382
|
+
.reply-send {
|
|
6383
|
+
display: inline-grid;
|
|
6384
|
+
place-items: center;
|
|
6385
|
+
width: 32px;
|
|
6386
|
+
height: 32px;
|
|
6387
|
+
border: 0;
|
|
6388
|
+
border-radius: 999px;
|
|
6389
|
+
background: var(--n-accent);
|
|
6390
|
+
color: var(--n-accent-fg);
|
|
6391
|
+
flex: none;
|
|
6392
|
+
}
|
|
6393
|
+
.reply-send:hover { filter: brightness(1.08); }
|
|
6394
|
+
.reply-send:disabled { opacity: 0.4; cursor: default; filter: none; }
|
|
6395
|
+
|
|
6396
|
+
/* Reactions */
|
|
6397
|
+
.reactions { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; position: relative; }
|
|
6398
|
+
.reaction {
|
|
6399
|
+
display: inline-flex;
|
|
6400
|
+
align-items: center;
|
|
6401
|
+
gap: 4px;
|
|
6402
|
+
height: 26px;
|
|
6403
|
+
padding: 0 8px;
|
|
6404
|
+
border: 1px solid var(--n-border);
|
|
6405
|
+
border-radius: 999px;
|
|
6406
|
+
background: var(--n-bg);
|
|
6407
|
+
color: var(--n-fg);
|
|
6408
|
+
font-size: 12px;
|
|
6409
|
+
}
|
|
6410
|
+
.reaction:hover { background: var(--n-bg-subtle); }
|
|
6411
|
+
.reaction[aria-pressed="true"] { border-color: color-mix(in srgb, var(--n-accent) 50%, transparent); background: var(--n-accent-soft); }
|
|
6412
|
+
.reaction-add { color: var(--n-fg-muted); padding: 0 6px; border-color: transparent; }
|
|
6413
|
+
.reaction-add:hover, .reaction-add[aria-expanded="true"] { color: var(--n-fg); }
|
|
6414
|
+
.reaction-picker {
|
|
6415
|
+
display: flex;
|
|
6416
|
+
gap: 2px;
|
|
6417
|
+
padding: 4px;
|
|
6418
|
+
border: 1px solid var(--n-border);
|
|
6419
|
+
border-radius: 999px;
|
|
6420
|
+
background: var(--n-bg);
|
|
6421
|
+
box-shadow: var(--n-shadow);
|
|
6422
|
+
}
|
|
6423
|
+
.reaction-picker .reaction { border-color: transparent; font-size: 14px; }
|
|
6424
|
+
|
|
6425
|
+
/* Shared controls */
|
|
6329
6426
|
.field {
|
|
6330
6427
|
width: 100%;
|
|
6331
6428
|
padding: 8px 10px;
|
|
@@ -6357,11 +6454,90 @@ textarea.field { resize: vertical; min-height: 72px; max-height: 240px; }
|
|
|
6357
6454
|
.btn-ghost { border-color: transparent; background: transparent; }
|
|
6358
6455
|
.btn-icon { width: 32px; padding: 0; justify-content: center; }
|
|
6359
6456
|
.btn-danger { color: var(--n-danger); }
|
|
6360
|
-
.kbd { color: var(--n-fg-muted); font-size: 11px; }
|
|
6361
6457
|
.error { color: var(--n-danger); font-size: 12px; }
|
|
6362
6458
|
.divider { height: 1px; background: var(--n-border); }
|
|
6363
|
-
|
|
6364
|
-
|
|
6459
|
+
|
|
6460
|
+
/* Composer: one surface, the card itself is the input. */
|
|
6461
|
+
.composer {
|
|
6462
|
+
display: grid;
|
|
6463
|
+
transition: box-shadow 140ms ease, border-color 140ms ease;
|
|
6464
|
+
}
|
|
6465
|
+
.composer:focus-within {
|
|
6466
|
+
border-color: color-mix(in srgb, var(--n-accent) 45%, var(--n-border));
|
|
6467
|
+
box-shadow: 0 0 0 4px var(--n-accent-soft), var(--n-shadow);
|
|
6468
|
+
}
|
|
6469
|
+
.composer.sheet:focus-within { border-color: var(--n-border); box-shadow: var(--n-shadow); }
|
|
6470
|
+
.composer .spacer { flex: 1; }
|
|
6471
|
+
.cmp-head { display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 10px 44px 4px 14px; }
|
|
6472
|
+
.avatar-empty { background: var(--n-bg-subtle); color: var(--n-fg-muted); }
|
|
6473
|
+
.avatar-empty .icon { width: 14px; height: 14px; }
|
|
6474
|
+
.cmp-name {
|
|
6475
|
+
flex: 1;
|
|
6476
|
+
min-width: 0;
|
|
6477
|
+
padding: 0;
|
|
6478
|
+
border: 0;
|
|
6479
|
+
background: none;
|
|
6480
|
+
outline: none;
|
|
6481
|
+
font-weight: 600;
|
|
6482
|
+
}
|
|
6483
|
+
.cmp-link {
|
|
6484
|
+
border: 0;
|
|
6485
|
+
background: none;
|
|
6486
|
+
padding: 2px 4px;
|
|
6487
|
+
border-radius: 6px;
|
|
6488
|
+
color: var(--n-fg-muted);
|
|
6489
|
+
font-size: 12px;
|
|
6490
|
+
white-space: nowrap;
|
|
6491
|
+
}
|
|
6492
|
+
.cmp-link:hover { color: var(--n-fg); }
|
|
6493
|
+
.composer .quote { margin: 6px 14px 0; }
|
|
6494
|
+
.cmp-text {
|
|
6495
|
+
display: block;
|
|
6496
|
+
width: 100%;
|
|
6497
|
+
min-height: 76px;
|
|
6498
|
+
max-height: 240px;
|
|
6499
|
+
padding: 8px 14px;
|
|
6500
|
+
border: 0;
|
|
6501
|
+
background: none;
|
|
6502
|
+
outline: none;
|
|
6503
|
+
resize: none;
|
|
6504
|
+
line-height: 1.5;
|
|
6505
|
+
}
|
|
6506
|
+
.cmp-name::placeholder, .cmp-text::placeholder { color: var(--n-fg-muted); opacity: 1; }
|
|
6507
|
+
.cmp-name::placeholder { font-weight: 500; }
|
|
6508
|
+
.cmp-error { padding: 0 14px 4px; }
|
|
6509
|
+
.cmp-foot { display: flex; align-items: center; gap: 8px; padding: 6px 8px 8px 14px; }
|
|
6510
|
+
.cmp-keys { display: inline-flex; gap: 3px; }
|
|
6511
|
+
.cmp-keys kbd {
|
|
6512
|
+
display: inline-grid;
|
|
6513
|
+
place-items: center;
|
|
6514
|
+
min-width: 20px;
|
|
6515
|
+
height: 20px;
|
|
6516
|
+
padding: 0 4px;
|
|
6517
|
+
border: 1px solid var(--n-border);
|
|
6518
|
+
border-bottom-width: 2px;
|
|
6519
|
+
border-radius: 5px;
|
|
6520
|
+
color: var(--n-fg-muted);
|
|
6521
|
+
font: 500 11px/1 var(--n-font);
|
|
6522
|
+
}
|
|
6523
|
+
.cmp-count { color: var(--n-fg-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
|
|
6524
|
+
.cmp-post {
|
|
6525
|
+
display: inline-flex;
|
|
6526
|
+
align-items: center;
|
|
6527
|
+
gap: 6px;
|
|
6528
|
+
height: 32px;
|
|
6529
|
+
padding: 0 10px 0 14px;
|
|
6530
|
+
border: 0;
|
|
6531
|
+
border-radius: 999px;
|
|
6532
|
+
background: var(--n-accent);
|
|
6533
|
+
color: var(--n-accent-fg);
|
|
6534
|
+
font-weight: 600;
|
|
6535
|
+
font-size: 13px;
|
|
6536
|
+
}
|
|
6537
|
+
.cmp-post:hover { filter: brightness(1.08); }
|
|
6538
|
+
.cmp-post:disabled { opacity: 0.4; cursor: default; filter: none; }
|
|
6539
|
+
.cmp-close { position: absolute; top: 13px; right: 8px; }
|
|
6540
|
+
@media (hover: none) { .cmp-keys { display: none; } }
|
|
6365
6541
|
|
|
6366
6542
|
/* Panel */
|
|
6367
6543
|
.panel {
|
|
@@ -6509,13 +6685,11 @@ function isTypingTarget(target) {
|
|
|
6509
6685
|
const el = target;
|
|
6510
6686
|
return el.isContentEditable || el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT";
|
|
6511
6687
|
}
|
|
6512
|
-
function
|
|
6513
|
-
return
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
reader.readAsDataURL(blob);
|
|
6518
|
-
});
|
|
6688
|
+
function avatar(name) {
|
|
6689
|
+
return h("span", {
|
|
6690
|
+
class: "avatar",
|
|
6691
|
+
style: `background:${colorFor(name)}`
|
|
6692
|
+
}, initials(name));
|
|
6519
6693
|
}
|
|
6520
6694
|
function describeElement(el) {
|
|
6521
6695
|
const tag = el.tagName.toLowerCase();
|
|
@@ -6599,6 +6773,7 @@ var NuniWidget = class {
|
|
|
6599
6773
|
_defineProperty(this, "layoutFrame", 0);
|
|
6600
6774
|
_defineProperty(this, "pinPositions", /* @__PURE__ */ new Map());
|
|
6601
6775
|
_defineProperty(this, "resolveTimer", 0);
|
|
6776
|
+
_defineProperty(this, "shownPlacements", "");
|
|
6602
6777
|
_defineProperty(this, "i18n", void 0);
|
|
6603
6778
|
_defineProperty(this, "isIgnored", (el) => el === this.host || this.host.contains(el));
|
|
6604
6779
|
_defineProperty(this, "onFrameKey", (e) => this.onKeyDown(e));
|
|
@@ -6960,10 +7135,18 @@ var NuniWidget = class {
|
|
|
6960
7135
|
this.renderPins();
|
|
6961
7136
|
this.layout();
|
|
6962
7137
|
if (queue.length) whenIdle(slice);
|
|
6963
|
-
else if ((onlyStale || run > 1) && this.panelOpen) this.render();
|
|
7138
|
+
else if ((onlyStale || run > 1) && this.panelOpen && this.placementSummary() !== this.shownPlacements) this.render();
|
|
6964
7139
|
};
|
|
6965
7140
|
slice();
|
|
6966
7141
|
}
|
|
7142
|
+
/** What the panel and cards show from the placements: found, approximate or lost. */
|
|
7143
|
+
placementSummary() {
|
|
7144
|
+
return this.comments.map((c) => {
|
|
7145
|
+
const placement = this.placements.get(c._id);
|
|
7146
|
+
if (!placement?.element) return "-";
|
|
7147
|
+
return placement.confidence === "low" ? "~" : "+";
|
|
7148
|
+
}).join("");
|
|
7149
|
+
}
|
|
6967
7150
|
/**
|
|
6968
7151
|
* Pins inside shadow roots and iframes: the page's observers don't see
|
|
6969
7152
|
* changes or scrolling in there, so watch each of those scopes too.
|
|
@@ -7245,12 +7428,12 @@ var NuniWidget = class {
|
|
|
7245
7428
|
this.activeId = null;
|
|
7246
7429
|
this.render();
|
|
7247
7430
|
this.focusComposer();
|
|
7248
|
-
this.takeScreenshot(draft);
|
|
7431
|
+
draft.screenshot = this.takeScreenshot(draft);
|
|
7249
7432
|
}
|
|
7250
7433
|
/** Capture while the person types, so posting stays instant. */
|
|
7251
7434
|
async takeScreenshot(draft) {
|
|
7252
7435
|
const load = this.runtime.loadScreenshot;
|
|
7253
|
-
if (!load || draft.element.ownerDocument !== document) return;
|
|
7436
|
+
if (!load || draft.element.ownerDocument !== document) return null;
|
|
7254
7437
|
const accent = getComputedStyle(this.host).getPropertyValue("--n-accent").trim() || "#d6246e";
|
|
7255
7438
|
try {
|
|
7256
7439
|
await new Promise((resolve) => setTimeout(resolve, 60));
|
|
@@ -7265,23 +7448,14 @@ var NuniWidget = class {
|
|
|
7265
7448
|
bottom: box.top + box.height
|
|
7266
7449
|
};
|
|
7267
7450
|
} : void 0;
|
|
7268
|
-
|
|
7451
|
+
return capture ? await capture(element, {
|
|
7269
7452
|
exclude: this.host,
|
|
7270
7453
|
accent,
|
|
7271
7454
|
focus
|
|
7272
7455
|
}) : null;
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
draft.screenshot = {
|
|
7277
|
-
blob,
|
|
7278
|
-
preview
|
|
7279
|
-
};
|
|
7280
|
-
this.render();
|
|
7281
|
-
} catch {}
|
|
7282
|
-
}
|
|
7283
|
-
isComposing(draft) {
|
|
7284
|
-
return this.card?.kind === "composer" && this.card.draft === draft;
|
|
7456
|
+
} catch {
|
|
7457
|
+
return null;
|
|
7458
|
+
}
|
|
7285
7459
|
}
|
|
7286
7460
|
collectContext(draft) {
|
|
7287
7461
|
const { collectors } = this.runtime;
|
|
@@ -7293,9 +7467,10 @@ var NuniWidget = class {
|
|
|
7293
7467
|
if (draft.dom) context.dom = draft.dom;
|
|
7294
7468
|
return Object.keys(context).length ? context : void 0;
|
|
7295
7469
|
}
|
|
7296
|
-
async attachScreenshot(id,
|
|
7470
|
+
async attachScreenshot(id, shot) {
|
|
7297
7471
|
try {
|
|
7298
|
-
|
|
7472
|
+
const image = await shot;
|
|
7473
|
+
if (image) await this.api.uploadScreenshot(id, this.secret, image);
|
|
7299
7474
|
} catch {}
|
|
7300
7475
|
}
|
|
7301
7476
|
copyForAgent(comment) {
|
|
@@ -7595,7 +7770,7 @@ var NuniWidget = class {
|
|
|
7595
7770
|
},
|
|
7596
7771
|
context: this.collectContext(draft)
|
|
7597
7772
|
});
|
|
7598
|
-
if (shot) this.attachScreenshot(id, shot
|
|
7773
|
+
if (shot) this.attachScreenshot(id, shot);
|
|
7599
7774
|
this.placements.set(id, {
|
|
7600
7775
|
element: draft.element,
|
|
7601
7776
|
confidence: "exact",
|
|
@@ -7766,7 +7941,7 @@ var NuniWidget = class {
|
|
|
7766
7941
|
kind: "thread",
|
|
7767
7942
|
id
|
|
7768
7943
|
};
|
|
7769
|
-
this.focusNext = "[data-card=\"thread\"] .card-
|
|
7944
|
+
this.focusNext = "[data-card=\"thread\"] .card-close";
|
|
7770
7945
|
}
|
|
7771
7946
|
render() {
|
|
7772
7947
|
this.syncOwnerDetail();
|
|
@@ -7829,6 +8004,7 @@ var NuniWidget = class {
|
|
|
7829
8004
|
}
|
|
7830
8005
|
}
|
|
7831
8006
|
renderUi() {
|
|
8007
|
+
this.shownPlacements = this.placementSummary();
|
|
7832
8008
|
const nodes = [this.renderToolbar()];
|
|
7833
8009
|
if (this.panelOpen) nodes.push(this.renderPanel());
|
|
7834
8010
|
const card = this.renderCard();
|
|
@@ -7973,80 +8149,112 @@ var NuniWidget = class {
|
|
|
7973
8149
|
onclick: () => this.openClaim()
|
|
7974
8150
|
}, icon(ICONS.github), this.t("claim"))));
|
|
7975
8151
|
}
|
|
8152
|
+
renderComposer(draft, cls) {
|
|
8153
|
+
const needsName = !this.name;
|
|
8154
|
+
const avatar = h("span", {
|
|
8155
|
+
class: "avatar cmp-avatar",
|
|
8156
|
+
"aria-hidden": "true"
|
|
8157
|
+
});
|
|
8158
|
+
const paintAvatar = (name) => {
|
|
8159
|
+
const clean = name.trim();
|
|
8160
|
+
avatar.classList.toggle("avatar-empty", !clean);
|
|
8161
|
+
if (clean) {
|
|
8162
|
+
avatar.textContent = initials(clean);
|
|
8163
|
+
avatar.style.background = colorFor(clean);
|
|
8164
|
+
} else {
|
|
8165
|
+
avatar.replaceChildren(icon(ICONS.user));
|
|
8166
|
+
avatar.style.background = "";
|
|
8167
|
+
}
|
|
8168
|
+
};
|
|
8169
|
+
const nameInput = h("input", {
|
|
8170
|
+
class: "cmp-name",
|
|
8171
|
+
placeholder: this.t("yourName"),
|
|
8172
|
+
value: this.name,
|
|
8173
|
+
maxlength: LIMITS.nameMaxLength,
|
|
8174
|
+
autocomplete: "name",
|
|
8175
|
+
"data-focus-key": "name",
|
|
8176
|
+
"aria-label": this.t("yourName")
|
|
8177
|
+
});
|
|
8178
|
+
const textarea = h("textarea", {
|
|
8179
|
+
class: "cmp-text",
|
|
8180
|
+
placeholder: this.t("leaveComment"),
|
|
8181
|
+
maxlength: LIMITS.bodyMaxLength,
|
|
8182
|
+
rows: 3,
|
|
8183
|
+
"data-focus-key": "body",
|
|
8184
|
+
"aria-label": this.t("comment")
|
|
8185
|
+
});
|
|
8186
|
+
const prev = this.uiLayer.querySelector("[data-focus-key=\"body\"]");
|
|
8187
|
+
if (prev) textarea.value = prev.value;
|
|
8188
|
+
const prevName = this.uiLayer.querySelector("[data-focus-key=\"name\"]");
|
|
8189
|
+
if (prevName) nameInput.value = prevName.value;
|
|
8190
|
+
paintAvatar(needsName ? nameInput.value : this.name);
|
|
8191
|
+
nameInput.addEventListener("input", () => paintAvatar(nameInput.value));
|
|
8192
|
+
const counter = h("span", {
|
|
8193
|
+
class: "cmp-count",
|
|
8194
|
+
"aria-live": "polite"
|
|
8195
|
+
});
|
|
8196
|
+
const post = h("button", {
|
|
8197
|
+
class: "cmp-post",
|
|
8198
|
+
type: "submit",
|
|
8199
|
+
disabled: Boolean(draft.sending) || !textarea.value.trim()
|
|
8200
|
+
}, draft.sending ? this.t("posting") : this.t("post"), icon(ICONS.arrowUp));
|
|
8201
|
+
const update = () => {
|
|
8202
|
+
post.disabled = Boolean(draft.sending) || !textarea.value.trim();
|
|
8203
|
+
const left = LIMITS.bodyMaxLength - textarea.value.length;
|
|
8204
|
+
counter.textContent = left <= LIMITS.bodyMaxLength * .1 ? this.t("charsLeft", { count: left }) : "";
|
|
8205
|
+
textarea.style.height = "auto";
|
|
8206
|
+
textarea.style.height = `${textarea.scrollHeight + 2}px`;
|
|
8207
|
+
};
|
|
8208
|
+
textarea.addEventListener("input", () => {
|
|
8209
|
+
update();
|
|
8210
|
+
this.positionCard();
|
|
8211
|
+
});
|
|
8212
|
+
requestAnimationFrame(() => {
|
|
8213
|
+
if (!textarea.isConnected) return;
|
|
8214
|
+
update();
|
|
8215
|
+
this.positionCard();
|
|
8216
|
+
});
|
|
8217
|
+
const submit = () => void this.submitDraft(draft, textarea.value, needsName ? nameInput.value : this.name);
|
|
8218
|
+
textarea.addEventListener("keydown", (e) => {
|
|
8219
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
8220
|
+
e.preventDefault();
|
|
8221
|
+
submit();
|
|
8222
|
+
}
|
|
8223
|
+
});
|
|
8224
|
+
return h("form", {
|
|
8225
|
+
class: `${cls} composer`,
|
|
8226
|
+
"data-card": "composer",
|
|
8227
|
+
onsubmit: (e) => {
|
|
8228
|
+
e.preventDefault();
|
|
8229
|
+
submit();
|
|
8230
|
+
}
|
|
8231
|
+
}, h("div", { class: "cmp-head" }, avatar, needsName ? nameInput : h("span", { class: "author" }, this.name), h("span", { class: "spacer" }), needsName ? null : h("button", {
|
|
8232
|
+
class: "cmp-link",
|
|
8233
|
+
type: "button",
|
|
8234
|
+
onclick: () => {
|
|
8235
|
+
this.name = "";
|
|
8236
|
+
this.render();
|
|
8237
|
+
this.focusComposer();
|
|
8238
|
+
}
|
|
8239
|
+
}, this.t("notYou"))), draft.anchor.quote ? h("blockquote", { class: "quote" }, draft.anchor.quote.exact) : null, textarea, draft.error ? h("div", {
|
|
8240
|
+
class: "error cmp-error",
|
|
8241
|
+
role: "alert"
|
|
8242
|
+
}, draft.error) : null, h("div", { class: "cmp-foot" }, h("span", {
|
|
8243
|
+
class: "cmp-keys",
|
|
8244
|
+
title: this.t("send", { key: this.i18n.mod })
|
|
8245
|
+
}, h("kbd", {}, this.i18n.mod), h("kbd", {}, "↵")), counter, h("span", { class: "spacer" }), post), h("button", {
|
|
8246
|
+
class: "icon-btn cmp-close",
|
|
8247
|
+
type: "button",
|
|
8248
|
+
"aria-label": this.t("cancel"),
|
|
8249
|
+
title: this.t("cancel"),
|
|
8250
|
+
onclick: () => this.closeCard()
|
|
8251
|
+
}, icon(ICONS.close)));
|
|
8252
|
+
}
|
|
7976
8253
|
renderCard() {
|
|
7977
8254
|
const card = this.card;
|
|
7978
8255
|
if (!card) return null;
|
|
7979
8256
|
const cls = `card${window.matchMedia(MOBILE_QUERY).matches ? " sheet" : ""}`;
|
|
7980
|
-
if (card.kind === "composer")
|
|
7981
|
-
const { draft } = card;
|
|
7982
|
-
const needsName = !this.name;
|
|
7983
|
-
const nameInput = h("input", {
|
|
7984
|
-
class: "field",
|
|
7985
|
-
placeholder: this.t("yourName"),
|
|
7986
|
-
value: this.name,
|
|
7987
|
-
maxlength: LIMITS.nameMaxLength,
|
|
7988
|
-
autocomplete: "name",
|
|
7989
|
-
"data-focus-key": "name",
|
|
7990
|
-
"aria-label": this.t("yourName")
|
|
7991
|
-
});
|
|
7992
|
-
const textarea = h("textarea", {
|
|
7993
|
-
class: "field",
|
|
7994
|
-
placeholder: this.t("leaveComment"),
|
|
7995
|
-
maxlength: LIMITS.bodyMaxLength,
|
|
7996
|
-
"data-focus-key": "body",
|
|
7997
|
-
"aria-label": this.t("comment")
|
|
7998
|
-
});
|
|
7999
|
-
const prev = this.uiLayer.querySelector("[data-focus-key=\"body\"]");
|
|
8000
|
-
if (prev) textarea.value = prev.value;
|
|
8001
|
-
const prevName = this.uiLayer.querySelector("[data-focus-key=\"name\"]");
|
|
8002
|
-
if (prevName) nameInput.value = prevName.value;
|
|
8003
|
-
const submit = () => void this.submitDraft(draft, textarea.value, needsName ? nameInput.value : this.name);
|
|
8004
|
-
textarea.addEventListener("keydown", (e) => {
|
|
8005
|
-
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
8006
|
-
e.preventDefault();
|
|
8007
|
-
submit();
|
|
8008
|
-
}
|
|
8009
|
-
});
|
|
8010
|
-
return h("form", {
|
|
8011
|
-
class: cls,
|
|
8012
|
-
"data-card": "composer",
|
|
8013
|
-
onsubmit: (e) => {
|
|
8014
|
-
e.preventDefault();
|
|
8015
|
-
submit();
|
|
8016
|
-
}
|
|
8017
|
-
}, h("div", { class: "card-body" }, needsName ? nameInput : h("div", { class: "row" }, h("span", {
|
|
8018
|
-
class: "avatar",
|
|
8019
|
-
style: `background:${colorFor(this.name)}`
|
|
8020
|
-
}, initials(this.name)), h("span", { class: "author" }, this.name), h("span", { class: "spacer" }), h("button", {
|
|
8021
|
-
class: "link",
|
|
8022
|
-
type: "button",
|
|
8023
|
-
onclick: () => {
|
|
8024
|
-
this.name = "";
|
|
8025
|
-
this.render();
|
|
8026
|
-
}
|
|
8027
|
-
}, this.t("notYou"))), draft.anchor.quote ? h("blockquote", { class: "quote" }, draft.anchor.quote.exact) : null, textarea, draft.screenshot ? h("div", { class: "shot-preview" }, h("img", {
|
|
8028
|
-
src: draft.screenshot.preview,
|
|
8029
|
-
alt: this.t("screenshotAlt")
|
|
8030
|
-
}), h("div", { class: "shot-note" }, h("span", {}, this.t("screenshotNote")), h("span", { class: "spacer" }), h("button", {
|
|
8031
|
-
class: "link",
|
|
8032
|
-
type: "button",
|
|
8033
|
-
onclick: () => {
|
|
8034
|
-
draft.screenshot = void 0;
|
|
8035
|
-
this.render();
|
|
8036
|
-
}
|
|
8037
|
-
}, this.t("remove")))) : null, draft.error ? h("div", {
|
|
8038
|
-
class: "error",
|
|
8039
|
-
role: "alert"
|
|
8040
|
-
}, draft.error) : null, h("div", { class: "row" }, h("span", { class: "kbd" }, this.t("send", { key: this.i18n.mod })), h("span", { class: "spacer" }), h("button", {
|
|
8041
|
-
class: "btn btn-ghost",
|
|
8042
|
-
type: "button",
|
|
8043
|
-
onclick: () => this.closeCard()
|
|
8044
|
-
}, this.t("cancel")), h("button", {
|
|
8045
|
-
class: "btn btn-primary",
|
|
8046
|
-
type: "submit",
|
|
8047
|
-
disabled: Boolean(draft.sending)
|
|
8048
|
-
}, icon(ICONS.send), draft.sending ? this.t("posting") : this.t("post")))));
|
|
8049
|
-
}
|
|
8257
|
+
if (card.kind === "composer") return this.renderComposer(card.draft, cls);
|
|
8050
8258
|
const comment = this.comments.find((c) => c._id === card.id);
|
|
8051
8259
|
if (!comment) return null;
|
|
8052
8260
|
const mine = this.isMine(comment);
|
|
@@ -8074,61 +8282,55 @@ var NuniWidget = class {
|
|
|
8074
8282
|
disabled: Boolean(card.busy),
|
|
8075
8283
|
onclick: () => this.saveEdit(comment, textarea.value)
|
|
8076
8284
|
}, this.t("save"))));
|
|
8077
|
-
} else
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
class: "
|
|
8096
|
-
|
|
8097
|
-
}, new URL(comment.page.origin).host) : null, placement?.confidence === "low" ? h("span", {
|
|
8098
|
-
class: "badge",
|
|
8099
|
-
title: this.t("approximateHint")
|
|
8100
|
-
}, this.t("approximate")) : null, !placement?.element ? h("span", {
|
|
8101
|
-
class: "badge",
|
|
8102
|
-
title: this.t("originallyOn", { text: comment.anchor.text || comment.anchor.tag })
|
|
8103
|
-
}, this.t("notFound")) : null), this.renderReactions(comment, comment._id), card.error ? h("div", {
|
|
8104
|
-
class: "error",
|
|
8105
|
-
role: "alert"
|
|
8106
|
-
}, card.error) : null);
|
|
8107
|
-
const actions = [];
|
|
8108
|
-
if (!card.editing) {
|
|
8109
|
-
if (owner) actions.push(comment.status === "open" ? h("button", {
|
|
8110
|
-
class: "btn",
|
|
8285
|
+
} else {
|
|
8286
|
+
const badges = [
|
|
8287
|
+
comment.status === "resolved" ? h("span", { class: "badge badge-ok" }, icon(ICONS.check), this.t("resolved")) : null,
|
|
8288
|
+
comment.page.origin !== location.origin ? h("span", {
|
|
8289
|
+
class: "badge",
|
|
8290
|
+
title: this.t("leftOn", { origin: comment.page.origin })
|
|
8291
|
+
}, new URL(comment.page.origin).host) : null,
|
|
8292
|
+
placement?.confidence === "low" ? h("span", {
|
|
8293
|
+
class: "badge",
|
|
8294
|
+
title: this.t("approximateHint")
|
|
8295
|
+
}, this.t("approximate")) : null,
|
|
8296
|
+
!placement?.element ? h("span", {
|
|
8297
|
+
class: "badge",
|
|
8298
|
+
title: this.t("originallyOn", { text: comment.anchor.text || comment.anchor.tag })
|
|
8299
|
+
}, this.t("notFound")) : null
|
|
8300
|
+
].filter((badge) => badge !== null);
|
|
8301
|
+
const contextPending = owner && !(this.ownerDetailLoaded && this.ownerDetailId === comment._id);
|
|
8302
|
+
const resolved = comment.status === "resolved";
|
|
8303
|
+
body = h("div", { class: "card-body msg" }, h("div", { class: "card-head" }, avatar(comment.authorName), h("span", { class: "author" }, comment.authorName), h("span", { class: "meta" }, this.i18n.timeAgo(comment.createdAt) + (comment.editedAt ? ` · ${this.t("edited")}` : "")), h("span", { class: "spacer" }), owner ? h("button", {
|
|
8304
|
+
class: `icon-btn${resolved ? " is-resolved" : ""}`,
|
|
8111
8305
|
type: "button",
|
|
8306
|
+
"aria-label": this.t(resolved ? "reopen" : "resolve"),
|
|
8307
|
+
title: this.t(resolved ? "reopen" : "resolve"),
|
|
8112
8308
|
disabled: Boolean(card.busy),
|
|
8113
|
-
onclick: () => this.resolveComment(comment)
|
|
8114
|
-
}, icon(ICONS.check)
|
|
8115
|
-
class: "btn",
|
|
8309
|
+
onclick: () => resolved ? this.reopenComment(comment) : this.resolveComment(comment)
|
|
8310
|
+
}, icon(ICONS.check)) : null, h("button", {
|
|
8311
|
+
class: "icon-btn card-close",
|
|
8116
8312
|
type: "button",
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8313
|
+
"aria-label": this.t("close"),
|
|
8314
|
+
title: this.t("close"),
|
|
8315
|
+
onclick: () => this.closeCard()
|
|
8316
|
+
}, icon(ICONS.close))), h("div", { class: "msg-main" }, comment.anchor.quote ? h("blockquote", { class: "quote" }, comment.anchor.quote.exact) : null, h("div", { class: "comment-body" }, comment.body), this.ownerDetail?._id === comment._id && this.ownerDetail.screenshotUrl ? h("a", {
|
|
8317
|
+
class: "shot",
|
|
8318
|
+
href: this.ownerDetail.screenshotUrl,
|
|
8319
|
+
target: "_blank",
|
|
8320
|
+
rel: "noreferrer",
|
|
8321
|
+
title: this.t("openScreenshot")
|
|
8322
|
+
}, h("img", {
|
|
8323
|
+
src: this.ownerDetail.screenshotUrl,
|
|
8324
|
+
alt: this.t("screenshotTaken")
|
|
8325
|
+
})) : null, badges.length ? h("div", { class: "badges" }, ...badges) : null, h("div", { class: "msg-foot" }, this.renderReactions(comment, comment._id), h("span", { class: "spacer" }), h("button", {
|
|
8326
|
+
class: "icon-btn",
|
|
8124
8327
|
type: "button",
|
|
8125
8328
|
"aria-label": this.t("copyForAgent"),
|
|
8126
8329
|
title: contextPending ? this.t("loadingContext") : this.t("copyForAgentHint"),
|
|
8127
8330
|
disabled: contextPending,
|
|
8128
8331
|
onclick: () => this.copyForAgent(comment)
|
|
8129
|
-
}, icon(ICONS.bot))
|
|
8130
|
-
|
|
8131
|
-
class: "btn btn-ghost btn-icon",
|
|
8332
|
+
}, icon(ICONS.bot)), mine ? h("button", {
|
|
8333
|
+
class: "icon-btn",
|
|
8132
8334
|
type: "button",
|
|
8133
8335
|
"aria-label": this.t("edit"),
|
|
8134
8336
|
title: this.t("edit"),
|
|
@@ -8136,30 +8338,36 @@ var NuniWidget = class {
|
|
|
8136
8338
|
card.editing = true;
|
|
8137
8339
|
this.render();
|
|
8138
8340
|
}
|
|
8139
|
-
}, icon(ICONS.edit))
|
|
8140
|
-
|
|
8141
|
-
class: "btn btn-ghost btn-icon btn-danger",
|
|
8341
|
+
}, icon(ICONS.edit)) : null, mine || owner ? h("button", {
|
|
8342
|
+
class: "icon-btn icon-btn-danger",
|
|
8142
8343
|
type: "button",
|
|
8143
8344
|
"aria-label": this.t("delete"),
|
|
8144
8345
|
title: this.t("delete"),
|
|
8145
8346
|
"data-focus-key": "delete",
|
|
8146
8347
|
disabled: Boolean(card.busy),
|
|
8147
8348
|
onclick: () => void this.deleteComment(comment)
|
|
8148
|
-
}, icon(ICONS.trash)))
|
|
8349
|
+
}, icon(ICONS.trash)) : null), card.error ? h("div", {
|
|
8350
|
+
class: "error",
|
|
8351
|
+
role: "alert"
|
|
8352
|
+
}, card.error) : null));
|
|
8149
8353
|
}
|
|
8150
8354
|
return h("div", {
|
|
8151
8355
|
class: cls,
|
|
8152
8356
|
"data-card": "thread",
|
|
8153
8357
|
role: "dialog",
|
|
8154
8358
|
"aria-label": this.t("commentBy", { name: comment.authorName })
|
|
8155
|
-
}, body,
|
|
8359
|
+
}, body, card.editing ? null : this.renderThread(comment));
|
|
8156
8360
|
}
|
|
8157
|
-
/**
|
|
8158
|
-
|
|
8361
|
+
/**
|
|
8362
|
+
* Emoji chips for one message and the picker to add one. Replies keep
|
|
8363
|
+
* their add button with their other tools, so `withAdd` is off for them.
|
|
8364
|
+
*/
|
|
8365
|
+
renderReactions(comment, targetId, withAdd = true) {
|
|
8159
8366
|
const card = this.card;
|
|
8160
8367
|
if (card?.kind !== "thread") return null;
|
|
8161
8368
|
const summaries = this.threadId === comment._id && this.thread ? this.thread.reactions.filter((r) => r.targetId === targetId) : [];
|
|
8162
8369
|
const open = card.picker === targetId;
|
|
8370
|
+
if (!withAdd && !summaries.length && !open) return null;
|
|
8163
8371
|
return h("div", { class: "reactions" }, ...summaries.map((r) => {
|
|
8164
8372
|
const mine = r.authorKeyHashes.includes(this.secretHash);
|
|
8165
8373
|
return h("button", {
|
|
@@ -8169,17 +8377,7 @@ var NuniWidget = class {
|
|
|
8169
8377
|
"aria-label": `${r.emoji} ${r.count}${mine ? ", including you" : ""}`,
|
|
8170
8378
|
onclick: () => this.toggleReaction(comment, targetId, r.emoji)
|
|
8171
8379
|
}, `${r.emoji} ${r.count}`);
|
|
8172
|
-
}), h("
|
|
8173
|
-
class: "reaction reaction-add",
|
|
8174
|
-
type: "button",
|
|
8175
|
-
"aria-label": this.t("addReaction"),
|
|
8176
|
-
"aria-expanded": String(open),
|
|
8177
|
-
title: this.t("addReaction"),
|
|
8178
|
-
onclick: () => {
|
|
8179
|
-
card.picker = open ? null : targetId;
|
|
8180
|
-
this.render();
|
|
8181
|
-
}
|
|
8182
|
-
}, icon(ICONS.smile)), open ? h("div", {
|
|
8380
|
+
}), withAdd ? this.reactionAdd(targetId, "reaction reaction-add") : null, open ? h("div", {
|
|
8183
8381
|
class: "reaction-picker",
|
|
8184
8382
|
role: "group",
|
|
8185
8383
|
"aria-label": this.t("reactions")
|
|
@@ -8194,6 +8392,22 @@ var NuniWidget = class {
|
|
|
8194
8392
|
}
|
|
8195
8393
|
}, emoji))) : null);
|
|
8196
8394
|
}
|
|
8395
|
+
reactionAdd(targetId, cls) {
|
|
8396
|
+
const card = this.card;
|
|
8397
|
+
if (card?.kind !== "thread") return null;
|
|
8398
|
+
const open = card.picker === targetId;
|
|
8399
|
+
return h("button", {
|
|
8400
|
+
class: cls,
|
|
8401
|
+
type: "button",
|
|
8402
|
+
"aria-label": this.t("addReaction"),
|
|
8403
|
+
"aria-expanded": String(open),
|
|
8404
|
+
title: this.t("addReaction"),
|
|
8405
|
+
onclick: () => {
|
|
8406
|
+
card.picker = open ? null : targetId;
|
|
8407
|
+
this.render();
|
|
8408
|
+
}
|
|
8409
|
+
}, icon(ICONS.smile));
|
|
8410
|
+
}
|
|
8197
8411
|
/** The replies under a comment and the box to add one. */
|
|
8198
8412
|
renderThread(comment) {
|
|
8199
8413
|
const card = this.card;
|
|
@@ -8226,13 +8440,10 @@ var NuniWidget = class {
|
|
|
8226
8440
|
}, this.t("save"))));
|
|
8227
8441
|
}
|
|
8228
8442
|
return h("div", {
|
|
8229
|
-
class: "reply",
|
|
8443
|
+
class: "reply msg",
|
|
8230
8444
|
"data-reply": reply._id
|
|
8231
|
-
}, h("div", { class: "card-head" }, h("span", {
|
|
8232
|
-
class: "
|
|
8233
|
-
style: `background:${colorFor(reply.authorName)}`
|
|
8234
|
-
}, initials(reply.authorName)), h("span", { class: "author" }, reply.authorName), 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" }), mine ? h("button", {
|
|
8235
|
-
class: "btn btn-ghost btn-icon btn-xs",
|
|
8445
|
+
}, h("div", { class: "card-head" }, avatar(reply.authorName), h("span", { class: "author" }, reply.authorName), 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", {
|
|
8446
|
+
class: "icon-btn",
|
|
8236
8447
|
type: "button",
|
|
8237
8448
|
"aria-label": this.t("editReply"),
|
|
8238
8449
|
title: this.t("edit"),
|
|
@@ -8241,18 +8452,18 @@ var NuniWidget = class {
|
|
|
8241
8452
|
this.render();
|
|
8242
8453
|
}
|
|
8243
8454
|
}, icon(ICONS.edit)) : null, mine || owner ? h("button", {
|
|
8244
|
-
class: "btn
|
|
8455
|
+
class: "icon-btn icon-btn-danger",
|
|
8245
8456
|
type: "button",
|
|
8246
8457
|
"aria-label": this.t("deleteReply"),
|
|
8247
8458
|
title: this.t("delete"),
|
|
8248
8459
|
"data-focus-key": `delete-${reply._id}`,
|
|
8249
8460
|
disabled: Boolean(card.busy),
|
|
8250
8461
|
onclick: () => void this.deleteReply(comment, reply)
|
|
8251
|
-
}, icon(ICONS.trash)) : null), h("div", { class: "comment-body" }, reply.body), this.renderReactions(comment, reply._id));
|
|
8462
|
+
}, icon(ICONS.trash)) : null)), h("div", { class: "msg-main" }, h("div", { class: "comment-body" }, reply.body), this.renderReactions(comment, reply._id, false)));
|
|
8252
8463
|
});
|
|
8253
8464
|
const needsName = !owner && !this.name;
|
|
8254
8465
|
const nameInput = h("input", {
|
|
8255
|
-
class: "
|
|
8466
|
+
class: "reply-name",
|
|
8256
8467
|
placeholder: this.t("yourName"),
|
|
8257
8468
|
value: this.name,
|
|
8258
8469
|
maxlength: LIMITS.nameMaxLength,
|
|
@@ -8263,14 +8474,31 @@ var NuniWidget = class {
|
|
|
8263
8474
|
const prevName = this.uiLayer.querySelector("[data-focus-key=\"reply-name\"]");
|
|
8264
8475
|
if (prevName) nameInput.value = prevName.value;
|
|
8265
8476
|
const box = h("textarea", {
|
|
8266
|
-
class: "
|
|
8477
|
+
class: "reply-text",
|
|
8267
8478
|
placeholder: replies.length ? this.t("reply") : this.t("replyFirst"),
|
|
8268
8479
|
maxlength: LIMITS.bodyMaxLength,
|
|
8480
|
+
rows: 1,
|
|
8269
8481
|
"data-focus-key": "reply",
|
|
8270
8482
|
"aria-label": this.t("reply")
|
|
8271
8483
|
});
|
|
8272
8484
|
const prev = this.uiLayer.querySelector("[data-focus-key=\"reply\"]");
|
|
8273
8485
|
if (prev) box.value = prev.value;
|
|
8486
|
+
const sendButton = h("button", {
|
|
8487
|
+
class: "reply-send",
|
|
8488
|
+
type: "submit",
|
|
8489
|
+
"aria-label": this.t("sendReply"),
|
|
8490
|
+
title: this.t("sendReply"),
|
|
8491
|
+
disabled: Boolean(card.sendingReply) || !box.value.trim()
|
|
8492
|
+
}, icon(ICONS.arrowUp));
|
|
8493
|
+
const grow = () => {
|
|
8494
|
+
sendButton.disabled = Boolean(card.sendingReply) || !box.value.trim();
|
|
8495
|
+
box.style.height = "auto";
|
|
8496
|
+
box.style.height = `${box.scrollHeight}px`;
|
|
8497
|
+
};
|
|
8498
|
+
box.addEventListener("input", grow);
|
|
8499
|
+
requestAnimationFrame(() => {
|
|
8500
|
+
if (box.isConnected) grow();
|
|
8501
|
+
});
|
|
8274
8502
|
const send = () => void this.sendReply(comment, box.value, needsName ? nameInput.value : this.name);
|
|
8275
8503
|
box.addEventListener("keydown", (e) => {
|
|
8276
8504
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
@@ -8291,13 +8519,7 @@ var NuniWidget = class {
|
|
|
8291
8519
|
e.preventDefault();
|
|
8292
8520
|
send();
|
|
8293
8521
|
}
|
|
8294
|
-
}, needsName ? nameInput : null,
|
|
8295
|
-
class: "btn btn-primary btn-icon",
|
|
8296
|
-
type: "submit",
|
|
8297
|
-
"aria-label": this.t("sendReply"),
|
|
8298
|
-
title: this.t("sendReply"),
|
|
8299
|
-
disabled: Boolean(card.sendingReply)
|
|
8300
|
-
}, icon(ICONS.send))));
|
|
8522
|
+
}, needsName ? nameInput : null, h("div", { class: "reply-row" }, box, sendButton)));
|
|
8301
8523
|
}
|
|
8302
8524
|
positionCard() {
|
|
8303
8525
|
const el = this.uiLayer.querySelector("[data-card]");
|