@mushi-mushi/web 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +339 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +339 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -553,23 +553,47 @@ function getWidgetStyles(theme) {
|
|
|
553
553
|
font-weight: 600;
|
|
554
554
|
color: ${ink};
|
|
555
555
|
}
|
|
556
|
-
.mushi-close
|
|
556
|
+
.mushi-close {
|
|
557
557
|
background: none;
|
|
558
558
|
border: none;
|
|
559
559
|
cursor: pointer;
|
|
560
|
-
padding: 4px;
|
|
560
|
+
padding: 2px 4px;
|
|
561
561
|
color: ${inkMuted};
|
|
562
562
|
font-family: ${fontBody};
|
|
563
|
-
font-size:
|
|
563
|
+
font-size: 16px;
|
|
564
564
|
line-height: 1;
|
|
565
|
-
border-radius:
|
|
565
|
+
border-radius: 0;
|
|
566
|
+
transition: color 150ms ${easeStamp};
|
|
567
|
+
}
|
|
568
|
+
.mushi-back {
|
|
569
|
+
align-self: flex-start;
|
|
570
|
+
background: none;
|
|
571
|
+
border: none;
|
|
572
|
+
cursor: pointer;
|
|
573
|
+
padding: 0;
|
|
574
|
+
margin: 0 0 2px;
|
|
575
|
+
color: ${inkMuted};
|
|
576
|
+
font-family: ${fontMono};
|
|
577
|
+
font-size: 10px;
|
|
578
|
+
font-weight: 500;
|
|
579
|
+
letter-spacing: 0.12em;
|
|
580
|
+
text-transform: uppercase;
|
|
581
|
+
line-height: 1.2;
|
|
582
|
+
border-radius: 0;
|
|
566
583
|
transition: color 150ms ${easeStamp};
|
|
567
584
|
}
|
|
568
|
-
.mushi-close:hover
|
|
569
|
-
.mushi-
|
|
585
|
+
.mushi-close:hover { color: ${widgetAccent}; }
|
|
586
|
+
.mushi-back:hover { color: ${ink}; }
|
|
587
|
+
.mushi-close:focus-visible {
|
|
570
588
|
outline: 1.5px solid ${widgetAccent};
|
|
571
589
|
outline-offset: 2px;
|
|
572
590
|
}
|
|
591
|
+
.mushi-back:focus-visible {
|
|
592
|
+
outline: none;
|
|
593
|
+
color: ${widgetAccent};
|
|
594
|
+
text-decoration: underline;
|
|
595
|
+
text-underline-offset: 3px;
|
|
596
|
+
}
|
|
573
597
|
|
|
574
598
|
/* \u2500\u2500 Body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
575
599
|
Generous left/right padding (22px) so type breathes. Vertical
|
|
@@ -658,39 +682,121 @@ function getWidgetStyles(theme) {
|
|
|
658
682
|
.mushi-report-row {
|
|
659
683
|
width: 100%;
|
|
660
684
|
display: grid;
|
|
661
|
-
grid-template-columns:
|
|
662
|
-
gap:
|
|
685
|
+
grid-template-columns: 1fr auto;
|
|
686
|
+
gap: 10px;
|
|
663
687
|
align-items: center;
|
|
664
|
-
padding:
|
|
688
|
+
padding: 12px 4px 12px 0;
|
|
665
689
|
border: 0;
|
|
666
690
|
border-bottom: 1px solid ${rule};
|
|
667
691
|
background: transparent;
|
|
668
692
|
color: ${ink};
|
|
669
693
|
cursor: pointer;
|
|
670
694
|
text-align: left;
|
|
695
|
+
transition: background 180ms ${easeStamp}, padding-left 180ms ${easeStamp};
|
|
696
|
+
}
|
|
697
|
+
.mushi-report-row:hover,
|
|
698
|
+
.mushi-report-row:focus-visible {
|
|
699
|
+
background: ${isDark ? "rgba(242,235,221,0.04)" : "rgba(14,13,11,0.03)"};
|
|
700
|
+
padding-left: 4px;
|
|
701
|
+
}
|
|
702
|
+
.mushi-report-main {
|
|
703
|
+
min-width: 0;
|
|
704
|
+
display: grid;
|
|
705
|
+
gap: 6px;
|
|
706
|
+
}
|
|
707
|
+
.mushi-report-title {
|
|
708
|
+
font-size: 13px;
|
|
709
|
+
line-height: 1.35;
|
|
710
|
+
display: -webkit-box;
|
|
711
|
+
-webkit-line-clamp: 2;
|
|
712
|
+
-webkit-box-orient: vertical;
|
|
713
|
+
overflow: hidden;
|
|
714
|
+
}
|
|
715
|
+
.mushi-report-meta {
|
|
716
|
+
display: flex;
|
|
717
|
+
flex-wrap: wrap;
|
|
718
|
+
align-items: center;
|
|
719
|
+
gap: 8px;
|
|
671
720
|
}
|
|
672
721
|
.mushi-report-status {
|
|
722
|
+
display: inline-flex;
|
|
723
|
+
align-items: center;
|
|
673
724
|
font-family: ${fontMono};
|
|
674
725
|
font-size: 10px;
|
|
675
|
-
|
|
726
|
+
font-weight: 600;
|
|
727
|
+
letter-spacing: 0.04em;
|
|
676
728
|
text-transform: uppercase;
|
|
729
|
+
padding: 2px 7px;
|
|
730
|
+
border-radius: 999px;
|
|
731
|
+
border: 1px solid transparent;
|
|
732
|
+
}
|
|
733
|
+
.mushi-status-sent {
|
|
734
|
+
color: ${isDark ? "#A8C4FF" : "#1E4A8C"};
|
|
735
|
+
background: ${isDark ? "rgba(120,160,255,0.12)" : "rgba(30,74,140,0.08)"};
|
|
736
|
+
border-color: ${isDark ? "rgba(120,160,255,0.22)" : "rgba(30,74,140,0.16)"};
|
|
737
|
+
}
|
|
738
|
+
.mushi-status-review {
|
|
739
|
+
color: ${isDark ? "#FFD27A" : "#8A5A00"};
|
|
740
|
+
background: ${isDark ? "rgba(255,190,90,0.12)" : "rgba(180,120,0,0.10)"};
|
|
741
|
+
border-color: ${isDark ? "rgba(255,190,90,0.22)" : "rgba(180,120,0,0.18)"};
|
|
742
|
+
}
|
|
743
|
+
.mushi-status-fixing {
|
|
744
|
+
color: ${isDark ? "#FFB899" : "#9A3D12"};
|
|
745
|
+
background: ${isDark ? "rgba(255,120,60,0.12)" : "rgba(224,60,44,0.10)"};
|
|
746
|
+
border-color: ${isDark ? "rgba(255,120,60,0.24)" : "rgba(224,60,44,0.18)"};
|
|
747
|
+
}
|
|
748
|
+
.mushi-status-fixed {
|
|
749
|
+
color: ${isDark ? "#8FE3B0" : "#1F6B3A"};
|
|
750
|
+
background: ${isDark ? "rgba(80,200,130,0.12)" : "rgba(31,107,58,0.10)"};
|
|
751
|
+
border-color: ${isDark ? "rgba(80,200,130,0.22)" : "rgba(31,107,58,0.18)"};
|
|
752
|
+
}
|
|
753
|
+
.mushi-status-closed,
|
|
754
|
+
.mushi-status-unknown {
|
|
755
|
+
color: ${inkMuted};
|
|
756
|
+
background: ${isDark ? "rgba(242,235,221,0.06)" : "rgba(14,13,11,0.05)"};
|
|
757
|
+
border-color: ${ruleStrong};
|
|
677
758
|
}
|
|
678
|
-
.mushi-report-
|
|
679
|
-
font-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
759
|
+
.mushi-report-when {
|
|
760
|
+
font-family: ${fontMono};
|
|
761
|
+
font-size: 10px;
|
|
762
|
+
color: ${inkFaint};
|
|
763
|
+
}
|
|
764
|
+
.mushi-unread-badge {
|
|
765
|
+
display: inline-flex;
|
|
766
|
+
align-items: center;
|
|
767
|
+
justify-content: center;
|
|
768
|
+
min-width: 18px;
|
|
769
|
+
height: 18px;
|
|
770
|
+
padding: 0 5px;
|
|
771
|
+
border-radius: 999px;
|
|
772
|
+
font-family: ${fontMono};
|
|
773
|
+
font-size: 10px;
|
|
774
|
+
font-weight: 700;
|
|
775
|
+
color: ${widgetAccentInk};
|
|
776
|
+
background: ${widgetAccent};
|
|
777
|
+
}
|
|
778
|
+
.mushi-report-chevron {
|
|
779
|
+
font-size: 18px;
|
|
780
|
+
line-height: 1;
|
|
781
|
+
color: ${inkFaint};
|
|
782
|
+
transition: color 180ms ${easeStamp}, transform 180ms ${easeStamp};
|
|
783
|
+
}
|
|
784
|
+
.mushi-report-row:hover .mushi-report-chevron,
|
|
785
|
+
.mushi-report-row:focus-visible .mushi-report-chevron {
|
|
786
|
+
color: ${widgetAccent};
|
|
787
|
+
transform: translateX(2px);
|
|
683
788
|
}
|
|
684
789
|
.mushi-thread-summary {
|
|
685
790
|
border-bottom: 1px solid ${rule};
|
|
686
791
|
padding-bottom: 10px;
|
|
687
792
|
margin-bottom: 10px;
|
|
688
793
|
}
|
|
689
|
-
.mushi-thread-summary
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
794
|
+
.mushi-thread-summary-meta {
|
|
795
|
+
display: flex;
|
|
796
|
+
flex-wrap: wrap;
|
|
797
|
+
align-items: center;
|
|
798
|
+
gap: 10px;
|
|
799
|
+
margin-bottom: 8px;
|
|
694
800
|
}
|
|
695
801
|
.mushi-thread {
|
|
696
802
|
display: grid;
|
|
@@ -1687,6 +1793,95 @@ var CATEGORY_ICONS = {
|
|
|
1687
1793
|
other: "\u{1F4DD}"
|
|
1688
1794
|
};
|
|
1689
1795
|
var FEATURE_REQUEST_INTENT = "Feature request";
|
|
1796
|
+
function reporterStatusShort(status) {
|
|
1797
|
+
switch (status) {
|
|
1798
|
+
case "new":
|
|
1799
|
+
case "queued":
|
|
1800
|
+
case "pending":
|
|
1801
|
+
case "submitted":
|
|
1802
|
+
return "Sent";
|
|
1803
|
+
case "classified":
|
|
1804
|
+
case "triaged":
|
|
1805
|
+
case "grouped":
|
|
1806
|
+
case "dispatched":
|
|
1807
|
+
return "Review";
|
|
1808
|
+
case "fixing":
|
|
1809
|
+
return "Fixing";
|
|
1810
|
+
case "fixed":
|
|
1811
|
+
case "resolved":
|
|
1812
|
+
case "completed":
|
|
1813
|
+
return "Fixed";
|
|
1814
|
+
case "dismissed":
|
|
1815
|
+
return "Closed";
|
|
1816
|
+
default:
|
|
1817
|
+
return status.replace(/_/g, " ").slice(0, 12);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
function reporterStatusLabel(status) {
|
|
1821
|
+
switch (status) {
|
|
1822
|
+
case "new":
|
|
1823
|
+
case "queued":
|
|
1824
|
+
case "pending":
|
|
1825
|
+
case "submitted":
|
|
1826
|
+
return "Submitted";
|
|
1827
|
+
case "classified":
|
|
1828
|
+
case "triaged":
|
|
1829
|
+
case "grouped":
|
|
1830
|
+
case "dispatched":
|
|
1831
|
+
return "In review";
|
|
1832
|
+
case "fixing":
|
|
1833
|
+
return "Fix in progress";
|
|
1834
|
+
case "fixed":
|
|
1835
|
+
case "resolved":
|
|
1836
|
+
case "completed":
|
|
1837
|
+
return "Fixed";
|
|
1838
|
+
case "dismissed":
|
|
1839
|
+
return "Closed";
|
|
1840
|
+
default:
|
|
1841
|
+
return status.replace(/_/g, " ");
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
function reporterStatusTone(status) {
|
|
1845
|
+
switch (status) {
|
|
1846
|
+
case "new":
|
|
1847
|
+
case "queued":
|
|
1848
|
+
case "pending":
|
|
1849
|
+
case "submitted":
|
|
1850
|
+
return "sent";
|
|
1851
|
+
case "classified":
|
|
1852
|
+
case "triaged":
|
|
1853
|
+
case "grouped":
|
|
1854
|
+
case "dispatched":
|
|
1855
|
+
return "review";
|
|
1856
|
+
case "fixing":
|
|
1857
|
+
return "fixing";
|
|
1858
|
+
case "fixed":
|
|
1859
|
+
case "resolved":
|
|
1860
|
+
case "completed":
|
|
1861
|
+
return "fixed";
|
|
1862
|
+
case "dismissed":
|
|
1863
|
+
return "closed";
|
|
1864
|
+
default:
|
|
1865
|
+
return "unknown";
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
function formatRelativeTime(iso) {
|
|
1869
|
+
const then = Date.parse(iso);
|
|
1870
|
+
if (Number.isNaN(then)) return "";
|
|
1871
|
+
const diffMs = Date.now() - then;
|
|
1872
|
+
if (diffMs < 0) return "just now";
|
|
1873
|
+
const sec = Math.floor(diffMs / 1e3);
|
|
1874
|
+
if (sec < 60) return "just now";
|
|
1875
|
+
const min = Math.floor(sec / 60);
|
|
1876
|
+
if (min < 60) return `${min}m ago`;
|
|
1877
|
+
const hr = Math.floor(min / 60);
|
|
1878
|
+
if (hr < 24) return `${hr}h ago`;
|
|
1879
|
+
const day = Math.floor(hr / 24);
|
|
1880
|
+
if (day < 7) return `${day}d ago`;
|
|
1881
|
+
const week = Math.floor(day / 7);
|
|
1882
|
+
if (week < 5) return `${week}w ago`;
|
|
1883
|
+
return new Date(then).toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
1884
|
+
}
|
|
1690
1885
|
function pad2(n) {
|
|
1691
1886
|
return n < 10 ? `0${n}` : String(n);
|
|
1692
1887
|
}
|
|
@@ -1801,6 +1996,8 @@ var MushiWidget = class _MushiWidget {
|
|
|
1801
1996
|
successTimer = null;
|
|
1802
1997
|
autoCloseTimer = null;
|
|
1803
1998
|
rewardsState = null;
|
|
1999
|
+
leaderboardEntries = null;
|
|
2000
|
+
leaderboardLoading = false;
|
|
1804
2001
|
/** Server-confirmed id for the just-submitted report. Surfaces in
|
|
1805
2002
|
* the success step as a copyable receipt + optional deep link to
|
|
1806
2003
|
* the Mushi console (when `dashboardUrl` is configured). Cleared
|
|
@@ -2073,6 +2270,11 @@ var MushiWidget = class _MushiWidget {
|
|
|
2073
2270
|
this.rewardsState = state;
|
|
2074
2271
|
if (this.isOpen) this.render();
|
|
2075
2272
|
}
|
|
2273
|
+
setLeaderboard(entries, loading = false) {
|
|
2274
|
+
this.leaderboardEntries = entries;
|
|
2275
|
+
this.leaderboardLoading = loading;
|
|
2276
|
+
if (this.isOpen && this.step === "leaderboard") this.render();
|
|
2277
|
+
}
|
|
2076
2278
|
destroy() {
|
|
2077
2279
|
if (this.successTimer !== null) {
|
|
2078
2280
|
clearTimeout(this.successTimer);
|
|
@@ -2493,6 +2695,8 @@ var MushiWidget = class _MushiWidget {
|
|
|
2493
2695
|
return this.renderReportsStep();
|
|
2494
2696
|
case "report-detail":
|
|
2495
2697
|
return this.renderReportDetailStep();
|
|
2698
|
+
case "leaderboard":
|
|
2699
|
+
return this.renderLeaderboardStep();
|
|
2496
2700
|
}
|
|
2497
2701
|
}
|
|
2498
2702
|
renderOutdatedBanner() {
|
|
@@ -2525,7 +2729,7 @@ var MushiWidget = class _MushiWidget {
|
|
|
2525
2729
|
renderHeader(opts) {
|
|
2526
2730
|
const t = this.locale;
|
|
2527
2731
|
const { title, showBack = false, step, eyebrow } = opts;
|
|
2528
|
-
const eyebrowHtml = showBack ? `<button type="button" class="mushi-back" data-action="back" aria-label="${t.widget.back}">\u2190
|
|
2732
|
+
const eyebrowHtml = showBack ? `<button type="button" class="mushi-back" data-action="back" aria-label="${t.widget.back}">\u2190</button>` : `<span class="mushi-header-eyebrow">${eyebrow ?? "Mushi \xB7 Report"}</span>`;
|
|
2529
2733
|
const counterHtml = step ? `<span class="mushi-step-counter" aria-label="Step ${step} of ${TOTAL_STEPS}"><b>${pad2(step)}</b> / ${pad2(TOTAL_STEPS)}</span>` : "";
|
|
2530
2734
|
return `
|
|
2531
2735
|
<div class="mushi-header">
|
|
@@ -2661,24 +2865,61 @@ var MushiWidget = class _MushiWidget {
|
|
|
2661
2865
|
`;
|
|
2662
2866
|
}
|
|
2663
2867
|
renderReportsStep() {
|
|
2664
|
-
const reports = this.reporterReports.map((report) =>
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2868
|
+
const reports = this.reporterReports.map((report) => {
|
|
2869
|
+
const title = report.summary ?? report.description ?? `Report ${report.id.slice(0, 8)}`;
|
|
2870
|
+
const tone = reporterStatusTone(report.status);
|
|
2871
|
+
const when = formatRelativeTime(report.created_at);
|
|
2872
|
+
const unread = report.unread_count && report.unread_count > 0 ? `<span class="mushi-unread-badge" aria-label="${report.unread_count} unread">${report.unread_count}</span>` : "";
|
|
2873
|
+
return `
|
|
2874
|
+
<button type="button" class="mushi-report-row" data-report-id="${escapeHtml(report.id)}" aria-label="View report: ${escapeHtml(title)}">
|
|
2875
|
+
<div class="mushi-report-main">
|
|
2876
|
+
<span class="mushi-report-title">${escapeHtml(title)}</span>
|
|
2877
|
+
<span class="mushi-report-meta">
|
|
2878
|
+
<span class="mushi-report-status mushi-status-${tone}">${escapeHtml(reporterStatusShort(report.status))}</span>
|
|
2879
|
+
${when ? `<span class="mushi-report-when">${escapeHtml(when)}</span>` : ""}
|
|
2880
|
+
${unread}
|
|
2881
|
+
</span>
|
|
2882
|
+
</div>
|
|
2883
|
+
<span class="mushi-report-chevron" aria-hidden="true">\u203A</span>
|
|
2884
|
+
</button>`;
|
|
2885
|
+
}).join("");
|
|
2886
|
+
const leaderboardBtn = this.rewardsState ? `<button type="button" class="mushi-leaderboard-link" data-action="open-leaderboard">\u{1F3C6} Leaderboard</button>` : "";
|
|
2671
2887
|
return `
|
|
2672
2888
|
${this.renderHeader({ title: "Your reports", showBack: true, eyebrow: "Mushi \xB7 Inbox" })}
|
|
2673
2889
|
<div class="mushi-body">
|
|
2674
2890
|
${this.reporterLoading ? '<p class="mushi-muted">Loading reports\u2026</p>' : ""}
|
|
2675
2891
|
${this.reporterError ? `<p class="mushi-error-inline">${escapeHtml(this.reporterError)}</p>` : ""}
|
|
2676
2892
|
${reports || (!this.reporterLoading ? '<p class="mushi-muted">No reports from this browser yet.</p>' : "")}
|
|
2893
|
+
${leaderboardBtn}
|
|
2894
|
+
</div>
|
|
2895
|
+
`;
|
|
2896
|
+
}
|
|
2897
|
+
renderLeaderboardStep() {
|
|
2898
|
+
const myRank = this.rewardsState && this.leaderboardEntries ? this.leaderboardEntries.findIndex((e) => e.display_name === "You") + 1 : 0;
|
|
2899
|
+
const rows = (this.leaderboardEntries ?? []).map((e, i) => `
|
|
2900
|
+
<div class="mushi-lb-row ${i === 0 ? "mushi-lb-top" : ""}">
|
|
2901
|
+
<span class="mushi-lb-rank">#${i + 1}</span>
|
|
2902
|
+
<span class="mushi-lb-name">${escapeHtml(e.display_name)}</span>
|
|
2903
|
+
${e.tier_name ? `<span class="mushi-lb-tier">${escapeHtml(e.tier_name)}</span>` : ""}
|
|
2904
|
+
<span class="mushi-lb-pts">${e.total_points.toLocaleString()} pts</span>
|
|
2905
|
+
</div>
|
|
2906
|
+
`).join("");
|
|
2907
|
+
return `
|
|
2908
|
+
${this.renderHeader({ title: "\u{1F3C6} Leaderboard", showBack: true, eyebrow: "Mushi \xB7 Contributors" })}
|
|
2909
|
+
<div class="mushi-body">
|
|
2910
|
+
${this.leaderboardLoading ? '<p class="mushi-muted">Loading leaderboard\u2026</p>' : ""}
|
|
2911
|
+
${!this.leaderboardLoading && !this.leaderboardEntries?.length ? '<p class="mushi-muted">No contributors yet \u2014 be the first!</p>' : ""}
|
|
2912
|
+
<div class="mushi-lb-list">${rows}</div>
|
|
2913
|
+
${myRank > 0 ? `<p class="mushi-lb-myrank">You are ranked #${myRank}</p>` : ""}
|
|
2914
|
+
<p class="mushi-lb-note">Top contributors this month \xB7 Points refresh monthly</p>
|
|
2677
2915
|
</div>
|
|
2678
2916
|
`;
|
|
2679
2917
|
}
|
|
2680
2918
|
renderReportDetailStep() {
|
|
2681
2919
|
const report = this.reporterReports.find((r) => r.id === this.selectedReportId);
|
|
2920
|
+
const status = report?.status ?? "unknown";
|
|
2921
|
+
const tone = reporterStatusTone(status);
|
|
2922
|
+
const when = report?.created_at ? formatRelativeTime(report.created_at) : "";
|
|
2682
2923
|
const comments = this.reporterComments.map((comment) => `
|
|
2683
2924
|
<div class="mushi-thread-comment ${comment.author_kind}">
|
|
2684
2925
|
<strong>${escapeHtml(comment.author_kind === "reporter" ? "You" : comment.author_name ?? "Developer")}</strong>
|
|
@@ -2689,7 +2930,10 @@ var MushiWidget = class _MushiWidget {
|
|
|
2689
2930
|
${this.renderHeader({ title: "Report thread", showBack: true, eyebrow: "Mushi \xB7 Inbox" })}
|
|
2690
2931
|
<div class="mushi-body">
|
|
2691
2932
|
<div class="mushi-thread-summary">
|
|
2692
|
-
<
|
|
2933
|
+
<div class="mushi-thread-summary-meta">
|
|
2934
|
+
<span class="mushi-report-status mushi-status-${tone}">${escapeHtml(reporterStatusLabel(status))}</span>
|
|
2935
|
+
${when ? `<span class="mushi-report-when">Reported ${escapeHtml(when)}</span>` : ""}
|
|
2936
|
+
</div>
|
|
2693
2937
|
<p>${escapeHtml(report?.summary ?? report?.description ?? "Report details")}</p>
|
|
2694
2938
|
</div>
|
|
2695
2939
|
<div class="mushi-thread">
|
|
@@ -2997,6 +3241,8 @@ var MushiWidget = class _MushiWidget {
|
|
|
2997
3241
|
} else if (this.step === "report-detail") {
|
|
2998
3242
|
this.step = "reports";
|
|
2999
3243
|
this.selectedReportId = null;
|
|
3244
|
+
} else if (this.step === "leaderboard") {
|
|
3245
|
+
this.step = "reports";
|
|
3000
3246
|
}
|
|
3001
3247
|
this.render();
|
|
3002
3248
|
});
|
|
@@ -3016,6 +3262,11 @@ var MushiWidget = class _MushiWidget {
|
|
|
3016
3262
|
if (reportId) void this.loadReporterComments(reportId);
|
|
3017
3263
|
});
|
|
3018
3264
|
});
|
|
3265
|
+
panel.querySelector('[data-action="open-leaderboard"]')?.addEventListener("click", () => {
|
|
3266
|
+
this.step = "leaderboard";
|
|
3267
|
+
this.callbacks.onLeaderboardOpen?.();
|
|
3268
|
+
this.render();
|
|
3269
|
+
});
|
|
3019
3270
|
panel.querySelector('[data-action="reporter-reply"]')?.addEventListener("click", () => {
|
|
3020
3271
|
void this.submitReporterReply(panel);
|
|
3021
3272
|
});
|
|
@@ -3267,6 +3518,10 @@ var MushiWidget = class _MushiWidget {
|
|
|
3267
3518
|
const submit = this.shadow.querySelector('[data-action="submit"]');
|
|
3268
3519
|
submit?.click();
|
|
3269
3520
|
}
|
|
3521
|
+
recorderOpenMyReports() {
|
|
3522
|
+
if (!this.isOpen) this.open();
|
|
3523
|
+
void this.loadReporterReports();
|
|
3524
|
+
}
|
|
3270
3525
|
};
|
|
3271
3526
|
|
|
3272
3527
|
// src/marketing-recorder.ts
|
|
@@ -3289,7 +3544,8 @@ function exposeMarketingRecorder(widget) {
|
|
|
3289
3544
|
selectCategory: (category) => widget.recorderSelectCategory(category),
|
|
3290
3545
|
selectIntent: (label) => widget.recorderSelectIntent(label),
|
|
3291
3546
|
focusDescription: () => widget.recorderFocusDescription(),
|
|
3292
|
-
submit: () => widget.recorderSubmit()
|
|
3547
|
+
submit: () => widget.recorderSubmit(),
|
|
3548
|
+
openMyReports: () => widget.recorderOpenMyReports()
|
|
3293
3549
|
};
|
|
3294
3550
|
globalThis.__mushiRecorder = api;
|
|
3295
3551
|
}
|
|
@@ -3460,6 +3716,24 @@ async function fetchAndCacheTier(userId) {
|
|
|
3460
3716
|
noteRewardsApiFailure(res.error?.code);
|
|
3461
3717
|
return null;
|
|
3462
3718
|
}
|
|
3719
|
+
async function fetchLeaderboard(limit = 10) {
|
|
3720
|
+
if (!apiClient || isRewardsApiBackedOff()) return null;
|
|
3721
|
+
try {
|
|
3722
|
+
const res = await apiClient.getHallOfFame(limit);
|
|
3723
|
+
if (res.ok && res.data) {
|
|
3724
|
+
return (res.data.data ?? []).map((e) => ({
|
|
3725
|
+
display_name: e.display_name,
|
|
3726
|
+
tier_name: e.tier_name,
|
|
3727
|
+
total_points: e.total_points,
|
|
3728
|
+
points_30d: e.points_30d
|
|
3729
|
+
}));
|
|
3730
|
+
}
|
|
3731
|
+
noteRewardsApiFailure(res.error?.code);
|
|
3732
|
+
return null;
|
|
3733
|
+
} catch {
|
|
3734
|
+
return null;
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3463
3737
|
var routeObserver = null;
|
|
3464
3738
|
var clickHandler = null;
|
|
3465
3739
|
var origPushState = null;
|
|
@@ -5030,7 +5304,7 @@ function createProactiveManager(config = {}) {
|
|
|
5030
5304
|
|
|
5031
5305
|
// src/version.ts
|
|
5032
5306
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/web";
|
|
5033
|
-
var MUSHI_SDK_VERSION = "1.
|
|
5307
|
+
var MUSHI_SDK_VERSION = "1.10.0" ;
|
|
5034
5308
|
|
|
5035
5309
|
// src/mushi.ts
|
|
5036
5310
|
var instance = null;
|
|
@@ -5308,6 +5582,12 @@ function createInstance(config) {
|
|
|
5308
5582
|
async onReporterReply(reportId, body) {
|
|
5309
5583
|
const result = await apiClient2.replyToReporterReport(reportId, core.getReporterToken(), body);
|
|
5310
5584
|
if (!result.ok) throw new Error(result.error?.message ?? "Could not send reply");
|
|
5585
|
+
},
|
|
5586
|
+
onLeaderboardOpen() {
|
|
5587
|
+
widget.setLeaderboard(null, true);
|
|
5588
|
+
void fetchLeaderboard(10).then((entries) => {
|
|
5589
|
+
widget.setLeaderboard(entries, false);
|
|
5590
|
+
});
|
|
5311
5591
|
}
|
|
5312
5592
|
}, MUSHI_SDK_VERSION);
|
|
5313
5593
|
syncCaptureModules();
|
|
@@ -5564,7 +5844,7 @@ function createInstance(config) {
|
|
|
5564
5844
|
await offlineQueue.enqueue(finalReport);
|
|
5565
5845
|
log.info("Offline \u2014 report queued", { reportId: finalReport.id });
|
|
5566
5846
|
emit("report:queued", { reportId: finalReport.id });
|
|
5567
|
-
return;
|
|
5847
|
+
return { reportId: null, queuedOffline: true };
|
|
5568
5848
|
}
|
|
5569
5849
|
const result = await apiClient2.submitReport(finalReport);
|
|
5570
5850
|
if (result.ok) {
|
|
@@ -5862,6 +6142,28 @@ function createInstance(config) {
|
|
|
5862
6142
|
},
|
|
5863
6143
|
pulseTrigger() {
|
|
5864
6144
|
widget.pulseTrigger?.();
|
|
6145
|
+
},
|
|
6146
|
+
// ─── Reporter API (cross-platform) ────────────────────────────────
|
|
6147
|
+
async listMyReports() {
|
|
6148
|
+
const result = await apiClient2.listReporterReports(core.getReporterToken());
|
|
6149
|
+
if (!result.ok) return [];
|
|
6150
|
+
return result.data?.reports ?? [];
|
|
6151
|
+
},
|
|
6152
|
+
async listMyComments(reportId) {
|
|
6153
|
+
const result = await apiClient2.listReporterComments(reportId, core.getReporterToken());
|
|
6154
|
+
if (!result.ok) return [];
|
|
6155
|
+
return result.data?.comments ?? [];
|
|
6156
|
+
},
|
|
6157
|
+
async replyToReport(reportId, body) {
|
|
6158
|
+
const result = await apiClient2.replyToReporterReport(reportId, core.getReporterToken(), body);
|
|
6159
|
+
if (!result.ok) return null;
|
|
6160
|
+
return result.data?.comment ?? null;
|
|
6161
|
+
},
|
|
6162
|
+
async getHallOfFame(limit = 20) {
|
|
6163
|
+
const result = await apiClient2.getHallOfFame(limit);
|
|
6164
|
+
if (!result.ok) return [];
|
|
6165
|
+
const raw = result.data;
|
|
6166
|
+
return raw?.data ?? [];
|
|
5865
6167
|
}
|
|
5866
6168
|
};
|
|
5867
6169
|
if (typeof globalThis !== "undefined" && (bootstrapConfig.debug ?? false)) {
|
|
@@ -6179,7 +6481,11 @@ function createNoopInstance() {
|
|
|
6179
6481
|
recordActivity: () => {
|
|
6180
6482
|
},
|
|
6181
6483
|
pulseTrigger: () => {
|
|
6182
|
-
}
|
|
6484
|
+
},
|
|
6485
|
+
listMyReports: async () => [],
|
|
6486
|
+
listMyComments: async () => [],
|
|
6487
|
+
replyToReport: async () => null,
|
|
6488
|
+
getHallOfFame: async () => []
|
|
6183
6489
|
};
|
|
6184
6490
|
}
|
|
6185
6491
|
function installAutoBreadcrumbs(buffer) {
|