@loupekit/sdk 0.13.1 → 0.14.0-next.81
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.global.js +149 -31
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +149 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -390,11 +390,35 @@ var STYLES = (
|
|
|
390
390
|
.hfeed-p { font-weight: 700; }
|
|
391
391
|
.hfeed-p-critical { color: var(--pin); }
|
|
392
392
|
.hfeed-p-high { color: #e0a92c; }
|
|
393
|
+
.hfeed-a { display: flex; gap: 4px; margin-top: 3px; }
|
|
394
|
+
.hfeed-act {
|
|
395
|
+
font-size: 11px; padding: 3px 8px; border: 1px solid var(--line); border-radius: 6px;
|
|
396
|
+
background: var(--bg-3); color: var(--ink); cursor: pointer;
|
|
397
|
+
}
|
|
398
|
+
.hfeed-act:hover { border-color: var(--accent); }
|
|
399
|
+
.hfeed-act.danger:hover, .hfeed-act.danger[data-armed] { border-color: var(--pin); color: var(--pin); }
|
|
393
400
|
.hempty { padding: 14px; text-align: center; color: var(--muted); font-size: 12px; }
|
|
394
401
|
.hfoot { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--line); font-size: 11px; color: var(--muted); text-align: center; }
|
|
395
402
|
|
|
396
403
|
/* Timeline grouping (project scope) + the repo filter. */
|
|
397
|
-
.daylabel {
|
|
404
|
+
.daylabel {
|
|
405
|
+
display: flex; align-items: center; gap: 6px; width: 100%; margin: 8px 0 0; padding: 4px 2px;
|
|
406
|
+
border: 0; background: none; cursor: pointer; text-align: left;
|
|
407
|
+
font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 700;
|
|
408
|
+
}
|
|
409
|
+
.daylabel::before { content: "\u25BE"; font-size: 10px; width: 10px; }
|
|
410
|
+
.daylabel.shut::before { content: "\u25B8"; }
|
|
411
|
+
.daylabel::after {
|
|
412
|
+
content: attr(data-n); padding: 0 6px; border-radius: 999px; background: var(--bg-3);
|
|
413
|
+
font-size: 10px; letter-spacing: 0;
|
|
414
|
+
}
|
|
415
|
+
.daylabel:hover { color: var(--ink); }
|
|
416
|
+
.listfilters { display: flex; gap: 6px; margin: 6px 0 2px; }
|
|
417
|
+
.listfilters select {
|
|
418
|
+
flex: 1; min-width: 0; font-size: 12px; padding: 4px 6px; border: 1px solid var(--line); border-radius: 7px;
|
|
419
|
+
background: var(--bg-2); color: var(--ink); outline: none; cursor: pointer;
|
|
420
|
+
}
|
|
421
|
+
.listfilters select:focus { border-color: var(--accent); }
|
|
398
422
|
/* The page a comment belongs to, shown in the project scope (Settings \u2192 Page paths). */
|
|
399
423
|
.pathtag {
|
|
400
424
|
padding: 1px 6px; border-radius: 999px; background: var(--bg-3); color: var(--muted);
|
|
@@ -3946,7 +3970,7 @@ var HttpAdapter = class {
|
|
|
3946
3970
|
};
|
|
3947
3971
|
|
|
3948
3972
|
// src/app.ts
|
|
3949
|
-
var SDK_VERSION = true ? "0.
|
|
3973
|
+
var SDK_VERSION = true ? "0.14.0" : "dev";
|
|
3950
3974
|
var FAB_SIZE = 46;
|
|
3951
3975
|
var FAB_DRAG_THRESHOLD = 6;
|
|
3952
3976
|
var LAUNCHER_SHORTCUT = "Alt+Shift+L";
|
|
@@ -4101,6 +4125,11 @@ var LoupeApp = class {
|
|
|
4101
4125
|
this.allLoaded = false;
|
|
4102
4126
|
/** A clicked stat tile, which narrows the list. */
|
|
4103
4127
|
this.statFilter = "";
|
|
4128
|
+
/** One board stage to show, or "" for every stage. */
|
|
4129
|
+
this.statusFilter = "";
|
|
4130
|
+
this.sortOrder = "";
|
|
4131
|
+
/** Day groups the reader folded shut. Session only: "Today" means another day tomorrow. */
|
|
4132
|
+
this.collapsedDays = /* @__PURE__ */ new Set();
|
|
4104
4133
|
/** Accent preset id (see ACCENTS), applied as inline --accent / --accent-soft. */
|
|
4105
4134
|
this.accent = "indigo";
|
|
4106
4135
|
/** Collapsed to the one-line minimize bar. */
|
|
@@ -4794,6 +4823,27 @@ var LoupeApp = class {
|
|
|
4794
4823
|
this.renderList();
|
|
4795
4824
|
};
|
|
4796
4825
|
listHead.appendChild(search);
|
|
4826
|
+
const filters = el("div", "listfilters");
|
|
4827
|
+
this.statusSel = el("select", "lf-status");
|
|
4828
|
+
this.statusSel.setAttribute("aria-label", "Filter by status");
|
|
4829
|
+
this.statusSel.append(
|
|
4830
|
+
optionEl("All statuses", "", !this.statusFilter),
|
|
4831
|
+
...Object.keys(STAGE_LABELS).map((k) => optionEl(STAGE_LABELS[k], k, this.statusFilter === k))
|
|
4832
|
+
);
|
|
4833
|
+
this.statusSel.onchange = () => {
|
|
4834
|
+
this.statusFilter = this.statusSel.value;
|
|
4835
|
+
this.saveState();
|
|
4836
|
+
this.renderList();
|
|
4837
|
+
};
|
|
4838
|
+
this.sortSel = el("select", "lf-sort");
|
|
4839
|
+
this.sortSel.setAttribute("aria-label", "Order");
|
|
4840
|
+
this.sortSel.append(optionEl("Newest first", "newest", false), optionEl("Oldest first", "oldest", false), optionEl("Page order", "page", false));
|
|
4841
|
+
this.sortSel.onchange = () => {
|
|
4842
|
+
this.sortOrder = this.sortSel.value;
|
|
4843
|
+
this.saveState();
|
|
4844
|
+
this.renderList();
|
|
4845
|
+
};
|
|
4846
|
+
filters.append(this.statusSel, this.sortSel);
|
|
4797
4847
|
this.listEl = el("div", "list");
|
|
4798
4848
|
const homeView = el("div", "view home-view");
|
|
4799
4849
|
this.homeEl = homeView;
|
|
@@ -4801,7 +4851,7 @@ var LoupeApp = class {
|
|
|
4801
4851
|
this.commentsHint = el("div", "hint-slot");
|
|
4802
4852
|
this.reviewBar = el("div", "reviewbar");
|
|
4803
4853
|
this.reviewBar.style.display = "none";
|
|
4804
|
-
commentsView.append(this.commentsHint, tools, listHead, this.reviewBar, this.listEl, this.buildIntegrations());
|
|
4854
|
+
commentsView.append(this.commentsHint, tools, listHead, filters, this.reviewBar, this.listEl, this.buildIntegrations());
|
|
4805
4855
|
const activityView = el("div", "view activity-view");
|
|
4806
4856
|
this.activityEl = activityView;
|
|
4807
4857
|
const chatView = el("div", "view chat-view");
|
|
@@ -5463,17 +5513,49 @@ var LoupeApp = class {
|
|
|
5463
5513
|
feed.innerHTML = recent.length ? recent.map((c) => {
|
|
5464
5514
|
const stage = STAGE_LABELS[normalizeStatus(c.status)];
|
|
5465
5515
|
const prio = normalizePriority(c.priority);
|
|
5466
|
-
return `<
|
|
5516
|
+
return `<div class="hfeed-i" role="button" tabindex="0" data-id="${escapeAttr(c.id)}"><span class="hfeed-t">${escapeHtml(c.title || (c.body.split("\n")[0] ?? "").slice(0, 60))}</span><span class="hfeed-m">${escapeHtml(c.author?.name ?? "")} \xB7 <span title="${escapeAttr(this.fmtWhen(c.createdAt))}">${fmtAgo(c.createdAt)}</span> \xB7 <span class="hfeed-s hfeed-s-${normalizeStatus(c.status)}">${stage}</span><span class="hfeed-p hfeed-p-${prio}">${PRIORITY_LABELS[prio]}</span></span><span class="hfeed-a"><button class="hfeed-act" data-act="resolve">${isResolved(c) ? "Reopen" : "Resolve"}</button><button class="hfeed-act" data-act="open">Open</button><button class="hfeed-act danger" data-act="delete">Delete</button></span></div>`;
|
|
5467
5517
|
}).join("") : `<div class="hempty">Nothing here yet.</div>`;
|
|
5468
5518
|
feed.querySelectorAll(".hfeed-i").forEach((b) => {
|
|
5469
|
-
|
|
5470
|
-
|
|
5519
|
+
const id = b.dataset.id;
|
|
5520
|
+
const open = () => {
|
|
5471
5521
|
this.statFilter = "";
|
|
5522
|
+
this.statusFilter = "";
|
|
5472
5523
|
this.setTab("comments");
|
|
5473
5524
|
this.expanded.add(id);
|
|
5525
|
+
const c = recent.find((x) => x.id === id);
|
|
5526
|
+
if (c) void this.loadMessages(c);
|
|
5474
5527
|
this.renderList();
|
|
5475
5528
|
this.flash(id);
|
|
5476
5529
|
};
|
|
5530
|
+
b.onclick = open;
|
|
5531
|
+
b.onkeydown = (e) => {
|
|
5532
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
5533
|
+
e.preventDefault();
|
|
5534
|
+
open();
|
|
5535
|
+
}
|
|
5536
|
+
};
|
|
5537
|
+
b.querySelectorAll(".hfeed-act").forEach((btn) => {
|
|
5538
|
+
btn.onclick = (e) => {
|
|
5539
|
+
e.stopPropagation();
|
|
5540
|
+
const c = recent.find((x) => x.id === id);
|
|
5541
|
+
if (!c) return;
|
|
5542
|
+
if (btn.dataset.act === "open") open();
|
|
5543
|
+
else if (btn.dataset.act === "resolve") void this.toggleResolved(c);
|
|
5544
|
+
else if (btn.dataset.act === "delete") {
|
|
5545
|
+
if (btn.dataset.armed) void this.deleteComment(c);
|
|
5546
|
+
else {
|
|
5547
|
+
btn.dataset.armed = "1";
|
|
5548
|
+
btn.textContent = "Confirm delete";
|
|
5549
|
+
setTimeout(() => {
|
|
5550
|
+
if (btn.isConnected) {
|
|
5551
|
+
delete btn.dataset.armed;
|
|
5552
|
+
btn.textContent = "Delete";
|
|
5553
|
+
}
|
|
5554
|
+
}, 3e3);
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
};
|
|
5558
|
+
});
|
|
5477
5559
|
});
|
|
5478
5560
|
}
|
|
5479
5561
|
async loadNotifications() {
|
|
@@ -6582,6 +6664,8 @@ var LoupeApp = class {
|
|
|
6582
6664
|
if (typeof p?.tab === "string" && known.includes(p.tab)) this.tab = p.tab;
|
|
6583
6665
|
if (p?.scope === "page" || p?.scope === "all") this.scope = p.scope;
|
|
6584
6666
|
if (typeof p?.statFilter === "string") this.statFilter = p.statFilter;
|
|
6667
|
+
if (typeof p?.statusFilter === "string" && p.statusFilter in STAGE_LABELS) this.statusFilter = p.statusFilter;
|
|
6668
|
+
if (["newest", "oldest", "page"].includes(p?.sortOrder)) this.sortOrder = p.sortOrder;
|
|
6585
6669
|
if (p?.float && typeof p.float.w === "number") this.floatRect = { ...this.floatRect, ...p.float };
|
|
6586
6670
|
if (typeof p?.markersHidden === "boolean") this.markersHidden = p.markersHidden;
|
|
6587
6671
|
if (typeof p?.launcherHidden === "boolean") this.launcherHidden = p.launcherHidden;
|
|
@@ -6608,6 +6692,8 @@ var LoupeApp = class {
|
|
|
6608
6692
|
fab: this.fabPos,
|
|
6609
6693
|
scope: this.scope,
|
|
6610
6694
|
statFilter: this.statFilter,
|
|
6695
|
+
statusFilter: this.statusFilter,
|
|
6696
|
+
sortOrder: this.sortOrder,
|
|
6611
6697
|
accent: this.accent,
|
|
6612
6698
|
minimized: this.minimized,
|
|
6613
6699
|
hoverHints: this.hoverHints,
|
|
@@ -6690,25 +6776,43 @@ var LoupeApp = class {
|
|
|
6690
6776
|
if (this.statFilter === "needs_you" && !needsYou({ status: c.status }).needs) return false;
|
|
6691
6777
|
if (this.statFilter === "resolved" && stage !== "resolved") return false;
|
|
6692
6778
|
if (this.statFilter === "stale" && (stage === "resolved" || !(Date.parse(c.createdAt) < weekAgo))) return false;
|
|
6779
|
+
if (this.statusFilter && stage !== this.statusFilter) return false;
|
|
6693
6780
|
return !q || `${c.title ?? ""} ${c.body} ${c.author?.name ?? ""}`.toLowerCase().includes(q);
|
|
6694
6781
|
});
|
|
6695
|
-
|
|
6782
|
+
const order = this.sortOrder || (this.scope === "all" ? "newest" : "page");
|
|
6783
|
+
if (this.sortSel) this.sortSel.value = order;
|
|
6784
|
+
if (this.statusSel) this.statusSel.value = this.statusFilter;
|
|
6785
|
+
if (order === "newest") items = [...items].sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
6786
|
+
if (order === "oldest") items = [...items].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
6787
|
+
const grouped = order !== "page";
|
|
6788
|
+
const perDay = /* @__PURE__ */ new Map();
|
|
6789
|
+
if (grouped) for (const c of items) perDay.set(dayLabel(c.createdAt), (perDay.get(dayLabel(c.createdAt)) ?? 0) + 1);
|
|
6696
6790
|
this.renderReviewBar();
|
|
6697
6791
|
if (!items.length) {
|
|
6698
6792
|
this.listEl.appendChild(el(
|
|
6699
6793
|
"div",
|
|
6700
6794
|
"empty",
|
|
6701
|
-
this.statFilter ? "Nothing in this bucket." : q ? "No comments match your search." : this.scope === "all" ? "No feedback in this project yet." : "No comments yet. Use Inspect to pick an element, or Note to drop a comment anywhere on the page."
|
|
6795
|
+
this.statFilter ? "Nothing in this bucket." : this.statusFilter ? `Nothing in ${STAGE_LABELS[this.statusFilter]}.` : q ? "No comments match your search." : this.scope === "all" ? "No feedback in this project yet." : "No comments yet. Use Inspect to pick an element, or Note to drop a comment anywhere on the page."
|
|
6702
6796
|
));
|
|
6703
6797
|
}
|
|
6704
6798
|
let lastDay = "";
|
|
6705
6799
|
items.forEach((c, i) => {
|
|
6706
|
-
if (
|
|
6800
|
+
if (grouped) {
|
|
6707
6801
|
const day = dayLabel(c.createdAt);
|
|
6802
|
+
const shut = this.collapsedDays.has(day);
|
|
6708
6803
|
if (day !== lastDay) {
|
|
6709
|
-
|
|
6804
|
+
const head = el("button", "daylabel" + (shut ? " shut" : ""), day);
|
|
6805
|
+
head.dataset.n = String(perDay.get(day) ?? 0);
|
|
6806
|
+
head.setAttribute("aria-expanded", String(!shut));
|
|
6807
|
+
head.onclick = () => {
|
|
6808
|
+
if (shut) this.collapsedDays.delete(day);
|
|
6809
|
+
else this.collapsedDays.add(day);
|
|
6810
|
+
this.renderList();
|
|
6811
|
+
};
|
|
6812
|
+
this.listEl.appendChild(head);
|
|
6710
6813
|
lastDay = day;
|
|
6711
6814
|
}
|
|
6815
|
+
if (shut) return;
|
|
6712
6816
|
}
|
|
6713
6817
|
this.listEl.appendChild(this.itemView(c, i));
|
|
6714
6818
|
});
|
|
@@ -6855,31 +6959,14 @@ var LoupeApp = class {
|
|
|
6855
6959
|
}
|
|
6856
6960
|
const actions = el("div", "actions");
|
|
6857
6961
|
const doneBtn = el("button", "", isResolved(c) ? "Reopen" : "Resolve");
|
|
6858
|
-
doneBtn.onclick =
|
|
6962
|
+
doneBtn.onclick = (e) => {
|
|
6859
6963
|
e.stopPropagation();
|
|
6860
|
-
|
|
6861
|
-
c.status = status;
|
|
6862
|
-
await this.store.update(c.id, { status });
|
|
6863
|
-
this.renderPins();
|
|
6864
|
-
this.renderList();
|
|
6865
|
-
this.addActivity({
|
|
6866
|
-
kind: status === "resolved" ? "comment.resolve" : "comment.reopen",
|
|
6867
|
-
label: `${status === "resolved" ? "Resolved" : "Reopened"} \u201C${c.title || c.body.split("\n")[0] || "comment"}\u201D`
|
|
6868
|
-
});
|
|
6964
|
+
void this.toggleResolved(c);
|
|
6869
6965
|
};
|
|
6870
6966
|
const del = el("button", "", "Delete");
|
|
6871
|
-
del.onclick =
|
|
6967
|
+
del.onclick = (e) => {
|
|
6872
6968
|
e.stopPropagation();
|
|
6873
|
-
|
|
6874
|
-
this.comments = this.comments.filter((x) => x.id !== c.id);
|
|
6875
|
-
this.resolved.delete(c.id);
|
|
6876
|
-
this.renderPins();
|
|
6877
|
-
this.renderList();
|
|
6878
|
-
this.addActivity({
|
|
6879
|
-
kind: "comment.delete",
|
|
6880
|
-
label: `Deleted \u201C${c.title || c.body.split("\n")[0] || "comment"}\u201D`,
|
|
6881
|
-
level: "warn"
|
|
6882
|
-
});
|
|
6969
|
+
void this.deleteComment(c);
|
|
6883
6970
|
};
|
|
6884
6971
|
actions.append(doneBtn, del);
|
|
6885
6972
|
detail.appendChild(actions);
|
|
@@ -6896,6 +6983,37 @@ var LoupeApp = class {
|
|
|
6896
6983
|
};
|
|
6897
6984
|
return item;
|
|
6898
6985
|
}
|
|
6986
|
+
/**
|
|
6987
|
+
* Resolve or reopen a comment. Shared by the card and the Home feed. The page list
|
|
6988
|
+
* and the project list are separate reads, so the change is applied to both.
|
|
6989
|
+
*/
|
|
6990
|
+
async toggleResolved(c) {
|
|
6991
|
+
const status = isResolved(c) ? "queue" : "resolved";
|
|
6992
|
+
await this.store.update(c.id, { status });
|
|
6993
|
+
for (const x of [c, ...this.comments, ...this.allComments]) if (x.id === c.id) x.status = status;
|
|
6994
|
+
this.renderPins();
|
|
6995
|
+
this.renderList();
|
|
6996
|
+
this.renderHome();
|
|
6997
|
+
this.addActivity({
|
|
6998
|
+
kind: status === "resolved" ? "comment.resolve" : "comment.reopen",
|
|
6999
|
+
label: `${status === "resolved" ? "Resolved" : "Reopened"} \u201C${c.title || c.body.split("\n")[0] || "comment"}\u201D`
|
|
7000
|
+
});
|
|
7001
|
+
}
|
|
7002
|
+
/** Delete a comment, from the card or the Home feed. */
|
|
7003
|
+
async deleteComment(c) {
|
|
7004
|
+
await this.store.remove(c.id);
|
|
7005
|
+
this.comments = this.comments.filter((x) => x.id !== c.id);
|
|
7006
|
+
this.allComments = this.allComments.filter((x) => x.id !== c.id);
|
|
7007
|
+
this.resolved.delete(c.id);
|
|
7008
|
+
this.renderPins();
|
|
7009
|
+
this.renderList();
|
|
7010
|
+
this.renderHome();
|
|
7011
|
+
this.addActivity({
|
|
7012
|
+
kind: "comment.delete",
|
|
7013
|
+
label: `Deleted \u201C${c.title || c.body.split("\n")[0] || "comment"}\u201D`,
|
|
7014
|
+
level: "warn"
|
|
7015
|
+
});
|
|
7016
|
+
}
|
|
6899
7017
|
/**
|
|
6900
7018
|
* The review banner. This is the one place the panel asks a human to decide
|
|
6901
7019
|
* something, so it sits above everything else in the detail.
|