@youasked/react 0.5.0 → 0.6.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/YouAsked.d.ts +8 -1
- package/dist/client.d.ts +2 -0
- package/dist/context.d.ts +4 -1
- package/dist/icons.d.ts +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +492 -347
- package/dist/nudge.d.ts +31 -0
- package/dist/styles.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/YouAsked.tsx
|
|
4
|
-
import { useCallback as
|
|
4
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4, useSyncExternalStore } from "react";
|
|
5
5
|
import { createPortal } from "react-dom";
|
|
6
6
|
|
|
7
7
|
// src/client.ts
|
|
@@ -120,7 +120,7 @@ var DAY = 24 * 60 * MIN;
|
|
|
120
120
|
var uploads = /* @__PURE__ */ new Map();
|
|
121
121
|
var wait = (ms = 380) => new Promise((r) => setTimeout(r, ms + Math.random() * ms * 0.5));
|
|
122
122
|
var WORDS = (s) => new Set(s.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length > 2));
|
|
123
|
-
function createDemoClient(appName = "
|
|
123
|
+
function createDemoClient(appName = "this app") {
|
|
124
124
|
const t0 = Date.now();
|
|
125
125
|
let seq = 100;
|
|
126
126
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -147,31 +147,31 @@ function createDemoClient(appName = "Acme") {
|
|
|
147
147
|
});
|
|
148
148
|
const team = (id, body, ago2) => ({ id, body, team: true, author: null, mine: false, createdAt: t0 - ago2 });
|
|
149
149
|
const store = [
|
|
150
|
-
seed(12, "
|
|
150
|
+
seed(12, "Dark mode", "Easier on the eyes at night, and it'd match the rest of my phone.", 14, "planned", {
|
|
151
151
|
comments_: [
|
|
152
|
-
{ id: "c1", body: "Yes
|
|
153
|
-
team("c2", "On the list for December. Would
|
|
152
|
+
{ id: "c1", body: "Yes please. I use it every night.", team: false, author: "Raj", mine: false, createdAt: t0 - 3 * DAY },
|
|
153
|
+
team("c2", "On the list for December. Would following your phone's setting be enough to start?", 2 * DAY)
|
|
154
154
|
]
|
|
155
155
|
}),
|
|
156
|
-
seed(13, "
|
|
157
|
-
seed(7, "
|
|
158
|
-
shipNote: "
|
|
156
|
+
seed(13, "Export to CSV", "So I can open everything in a spreadsheet.", 11, "in_progress"),
|
|
157
|
+
seed(7, "Keyboard shortcuts", "", 8, "shipped", {
|
|
158
|
+
shipNote: "Press ? anywhere to see them all.",
|
|
159
159
|
shippedAt: t0 - 2 * DAY,
|
|
160
160
|
creditName: "Sam"
|
|
161
161
|
}),
|
|
162
|
-
seed(14, "
|
|
163
|
-
seed(15, "
|
|
164
|
-
seed(16, "Widget for the home screen", "Just today's
|
|
165
|
-
seed(9, "
|
|
166
|
-
shipNote: "
|
|
162
|
+
seed(14, "Offline mode", "I use it on the train and keep losing signal.", 6, "open"),
|
|
163
|
+
seed(15, "Share a link with a friend", "", 4, "open"),
|
|
164
|
+
seed(16, "Widget for the home screen", "Just today's number would be enough.", 3, "open"),
|
|
165
|
+
seed(9, "Sign in with Apple", "", 5, "shipped", {
|
|
166
|
+
shipNote: "You can now sign in with your Apple ID.",
|
|
167
167
|
shippedAt: t0 - 4 * 60 * MIN,
|
|
168
168
|
mine: true,
|
|
169
169
|
voted: true
|
|
170
170
|
}),
|
|
171
|
-
seed(17, "
|
|
171
|
+
seed(17, "A reminder the day before", "A nudge the day before something is due would do.", 2, "open", {
|
|
172
172
|
mine: true,
|
|
173
173
|
voted: true,
|
|
174
|
-
comments_: [team("c3", "Good one. Would a
|
|
174
|
+
comments_: [team("c3", "Good one. Would a push notification work, or would you rather get an email?", 3 * 60 * MIN)]
|
|
175
175
|
})
|
|
176
176
|
];
|
|
177
177
|
const find = (id) => store.find((r) => r.id === id);
|
|
@@ -344,11 +344,120 @@ var IconSpark = () => /* @__PURE__ */ jsxs("svg", { ...base, children: [
|
|
|
344
344
|
/* @__PURE__ */ jsx("path", { d: "m12 3 1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9Z" }),
|
|
345
345
|
/* @__PURE__ */ jsx("path", { d: "M19 16v4M17 18h4" })
|
|
346
346
|
] });
|
|
347
|
-
var IconIdea = () => /* @__PURE__ */ jsxs("svg", {
|
|
348
|
-
/* @__PURE__ */ jsx("path", { d: "
|
|
349
|
-
/* @__PURE__ */ jsx("path", { d: "
|
|
347
|
+
var IconIdea = ({ ink = "var(--_bg)" }) => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: [
|
|
348
|
+
/* @__PURE__ */ jsx("path", { d: "M6 2.25h12a4.5 4.5 0 0 1 4.5 4.5V15a4.5 4.5 0 0 1-4.5 4.5h-6.75L6 23.25V19.5A4.5 4.5 0 0 1 1.5 15V6.75A4.5 4.5 0 0 1 6 2.25Z", fill: "currentColor" }),
|
|
349
|
+
/* @__PURE__ */ jsx("path", { d: "M7.9 13.9 12 9.8l4.1 4.1", fill: "none", stroke: ink, strokeWidth: 2.6, strokeLinecap: "round", strokeLinejoin: "round" })
|
|
350
350
|
] });
|
|
351
351
|
|
|
352
|
+
// src/nudge.tsx
|
|
353
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
354
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
355
|
+
var NUDGE_DEFAULTS = { everyDays: 7, activeSeconds: 30, skipVisits: 1, message: null, position: "bottom" };
|
|
356
|
+
var DAY2 = 24 * 60 * 60 * 1e3;
|
|
357
|
+
var VISIT_GAP = 30 * 60 * 1e3;
|
|
358
|
+
function resolveNudge(server, prop) {
|
|
359
|
+
if (prop === false) return null;
|
|
360
|
+
if (typeof prop === "object") return { ...NUDGE_DEFAULTS, ...server, ...prop };
|
|
361
|
+
if (prop === true) return server ?? NUDGE_DEFAULTS;
|
|
362
|
+
return server ?? null;
|
|
363
|
+
}
|
|
364
|
+
function load(key) {
|
|
365
|
+
const empty = { visits: 0, lastVisitAt: 0, lastShownAt: 0, lastEngagedAt: 0, dismissals: 0 };
|
|
366
|
+
if (!key) return empty;
|
|
367
|
+
try {
|
|
368
|
+
return { ...empty, ...JSON.parse(localStorage.getItem(key) ?? "{}") };
|
|
369
|
+
} catch {
|
|
370
|
+
return empty;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function save(key, m) {
|
|
374
|
+
if (!key) return;
|
|
375
|
+
try {
|
|
376
|
+
localStorage.setItem(key, JSON.stringify(m));
|
|
377
|
+
} catch {
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function useNudge(settings, storageKey, blocked) {
|
|
381
|
+
const memory = useRef(null);
|
|
382
|
+
const [show, setShow] = useState(false);
|
|
383
|
+
useEffect(() => {
|
|
384
|
+
if (!settings || memory.current) return;
|
|
385
|
+
const m = load(storageKey);
|
|
386
|
+
const now = Date.now();
|
|
387
|
+
if (now - m.lastVisitAt > VISIT_GAP) m.visits += 1;
|
|
388
|
+
m.lastVisitAt = now;
|
|
389
|
+
memory.current = m;
|
|
390
|
+
save(storageKey, m);
|
|
391
|
+
}, [settings, storageKey]);
|
|
392
|
+
useEffect(() => {
|
|
393
|
+
if (!settings || show) return;
|
|
394
|
+
let active = 0;
|
|
395
|
+
const timer = window.setInterval(() => {
|
|
396
|
+
if (document.visibilityState !== "visible" || blocked) return;
|
|
397
|
+
active += 1;
|
|
398
|
+
if (active < settings.activeSeconds) return;
|
|
399
|
+
window.clearInterval(timer);
|
|
400
|
+
const m = memory.current;
|
|
401
|
+
if (!m) return;
|
|
402
|
+
const now = Date.now();
|
|
403
|
+
const wait2 = settings.everyDays * DAY2 * 2 ** Math.min(m.dismissals, 3);
|
|
404
|
+
const due = !storageKey || m.visits > settings.skipVisits && now - m.lastShownAt >= wait2 && now - m.lastEngagedAt >= wait2;
|
|
405
|
+
if (!due) return;
|
|
406
|
+
m.lastShownAt = now;
|
|
407
|
+
save(storageKey, m);
|
|
408
|
+
setShow(true);
|
|
409
|
+
}, 1e3);
|
|
410
|
+
return () => window.clearInterval(timer);
|
|
411
|
+
}, [settings, storageKey, blocked, show]);
|
|
412
|
+
const engaged = useCallback(() => {
|
|
413
|
+
const m = memory.current;
|
|
414
|
+
if (m) {
|
|
415
|
+
m.lastEngagedAt = Date.now();
|
|
416
|
+
m.dismissals = 0;
|
|
417
|
+
save(storageKey, m);
|
|
418
|
+
}
|
|
419
|
+
setShow(false);
|
|
420
|
+
}, [storageKey]);
|
|
421
|
+
const dismiss = useCallback(() => {
|
|
422
|
+
const m = memory.current;
|
|
423
|
+
if (m) {
|
|
424
|
+
m.dismissals += 1;
|
|
425
|
+
save(storageKey, m);
|
|
426
|
+
}
|
|
427
|
+
setShow(false);
|
|
428
|
+
}, [storageKey]);
|
|
429
|
+
return { show, engaged, dismiss };
|
|
430
|
+
}
|
|
431
|
+
function NudgeToast({
|
|
432
|
+
settings,
|
|
433
|
+
appName,
|
|
434
|
+
position,
|
|
435
|
+
trigger,
|
|
436
|
+
onOpen,
|
|
437
|
+
onDismiss
|
|
438
|
+
}) {
|
|
439
|
+
return /* @__PURE__ */ jsxs2("div", { className: "ya-toast ya-nudge", role: "status", "data-pos": position, "data-trigger": trigger, "data-place": settings.position, children: [
|
|
440
|
+
/* @__PURE__ */ jsxs2("div", { className: "ya-toast-top", children: [
|
|
441
|
+
/* @__PURE__ */ jsxs2("p", { className: "ya-toast-kicker", children: [
|
|
442
|
+
"Help shape ",
|
|
443
|
+
appName
|
|
444
|
+
] }),
|
|
445
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: "ya-icon-btn", onClick: onDismiss, "aria-label": "Dismiss", children: /* @__PURE__ */ jsx2(IconClose, {}) })
|
|
446
|
+
] }),
|
|
447
|
+
/* @__PURE__ */ jsxs2("div", { className: "ya-nudge-body", children: [
|
|
448
|
+
/* @__PURE__ */ jsx2("span", { className: "ya-card-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(IconIdea, {}) }),
|
|
449
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
450
|
+
/* @__PURE__ */ jsx2("p", { className: "ya-toast-title", children: settings.message ?? `Got an idea for ${appName}?` }),
|
|
451
|
+
/* @__PURE__ */ jsx2("p", { className: "ya-toast-note", children: "Ask for a feature or vote on what others want." })
|
|
452
|
+
] })
|
|
453
|
+
] }),
|
|
454
|
+
/* @__PURE__ */ jsxs2("div", { className: "ya-toast-actions", children: [
|
|
455
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: "ya-btn ya-btn-sm", onClick: onOpen, children: "Share an idea" }),
|
|
456
|
+
/* @__PURE__ */ jsx2("button", { type: "button", className: "ya-btn ya-btn-sm ya-btn-ghost", onClick: onDismiss, children: "Not now" })
|
|
457
|
+
] })
|
|
458
|
+
] });
|
|
459
|
+
}
|
|
460
|
+
|
|
352
461
|
// src/styles.ts
|
|
353
462
|
var css = `
|
|
354
463
|
.ya-scope{--_bg:var(--ya-bg);--_fg:var(--ya-fg);--_accent:var(--ya-accent);--_accent-fg:var(--ya-accent-fg);
|
|
@@ -579,6 +688,10 @@ box-shadow:0 0 0 1px var(--_border),0 24px 70px rgba(0,0,0,.22);padding-bottom:0
|
|
|
579
688
|
.ya-toast .ya-live{margin-top:8px}
|
|
580
689
|
.ya-live svg{width:15px;height:15px}
|
|
581
690
|
.ya-toast-note{font-size:13.5px;color:var(--_muted);margin-top:6px;overflow-wrap:anywhere}
|
|
691
|
+
.ya-toast[data-place=top]{top:calc(16px + env(safe-area-inset-top));bottom:auto}
|
|
692
|
+
.ya-nudge-body{display:flex;gap:12px;align-items:flex-start;margin-top:6px}
|
|
693
|
+
.ya-nudge-body .ya-card-icon{flex:none;margin-top:2px}
|
|
694
|
+
.ya-nudge-body .ya-toast-title{margin-top:0}
|
|
582
695
|
.ya-toast-actions{display:flex;gap:8px;margin-top:12px}
|
|
583
696
|
.ya-toast-quote{color:var(--_fg);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
|
|
584
697
|
.ya-toast .ya-icon-btn{width:30px;height:30px;margin:-6px -6px 0 0;background:none}
|
|
@@ -764,13 +877,13 @@ function tokenStyle(t) {
|
|
|
764
877
|
}
|
|
765
878
|
|
|
766
879
|
// src/shared.tsx
|
|
767
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
768
|
-
import { jsx as
|
|
880
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
881
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
769
882
|
function useVote(client, initial) {
|
|
770
|
-
const [state, setState] =
|
|
771
|
-
const busy =
|
|
772
|
-
|
|
773
|
-
const toggle =
|
|
883
|
+
const [state, setState] = useState2({ voted: initial.voted, votes: initial.votes });
|
|
884
|
+
const busy = useRef2(false);
|
|
885
|
+
useEffect2(() => setState({ voted: initial.voted, votes: initial.votes }), [initial.voted, initial.votes]);
|
|
886
|
+
const toggle = useCallback2(async () => {
|
|
774
887
|
if (busy.current) return;
|
|
775
888
|
busy.current = true;
|
|
776
889
|
const before = state;
|
|
@@ -787,7 +900,7 @@ function useVote(client, initial) {
|
|
|
787
900
|
}
|
|
788
901
|
function VoteButton({ client, request, compact }) {
|
|
789
902
|
const { voted, votes, toggle } = useVote(client, request);
|
|
790
|
-
return /* @__PURE__ */
|
|
903
|
+
return /* @__PURE__ */ jsxs3(
|
|
791
904
|
"button",
|
|
792
905
|
{
|
|
793
906
|
type: "button",
|
|
@@ -799,7 +912,7 @@ function VoteButton({ client, request, compact }) {
|
|
|
799
912
|
toggle();
|
|
800
913
|
},
|
|
801
914
|
children: [
|
|
802
|
-
/* @__PURE__ */
|
|
915
|
+
/* @__PURE__ */ jsx3(IconUp, {}),
|
|
803
916
|
votes
|
|
804
917
|
]
|
|
805
918
|
}
|
|
@@ -811,9 +924,9 @@ function BigVote({
|
|
|
811
924
|
onChange
|
|
812
925
|
}) {
|
|
813
926
|
const { voted, votes, toggle } = useVote(client, request);
|
|
814
|
-
|
|
815
|
-
return /* @__PURE__ */
|
|
816
|
-
/* @__PURE__ */
|
|
927
|
+
useEffect2(() => onChange?.(voted), [voted, onChange]);
|
|
928
|
+
return /* @__PURE__ */ jsxs3("button", { type: "button", className: "ya-bigvote", "aria-pressed": voted, onClick: toggle, children: [
|
|
929
|
+
/* @__PURE__ */ jsx3(IconUp, {}),
|
|
817
930
|
voted ? "Voted" : "Upvote",
|
|
818
931
|
" \xB7 ",
|
|
819
932
|
votes
|
|
@@ -828,8 +941,8 @@ var STATUS_LABEL = {
|
|
|
828
941
|
pending: "Awaiting approval"
|
|
829
942
|
};
|
|
830
943
|
function StatusPill({ status }) {
|
|
831
|
-
return /* @__PURE__ */
|
|
832
|
-
status === "shipped" && /* @__PURE__ */
|
|
944
|
+
return /* @__PURE__ */ jsxs3("span", { className: "ya-pill", "data-s": status, children: [
|
|
945
|
+
status === "shipped" && /* @__PURE__ */ jsx3(IconCheck, {}),
|
|
833
946
|
STATUS_LABEL[status]
|
|
834
947
|
] });
|
|
835
948
|
}
|
|
@@ -839,32 +952,32 @@ function RequestRow({
|
|
|
839
952
|
onOpen,
|
|
840
953
|
compact
|
|
841
954
|
}) {
|
|
842
|
-
return /* @__PURE__ */
|
|
843
|
-
/* @__PURE__ */
|
|
844
|
-
/* @__PURE__ */
|
|
845
|
-
/* @__PURE__ */
|
|
846
|
-
(request.status !== "open" || request.comments > 0 || request.mine) && /* @__PURE__ */
|
|
847
|
-
request.status !== "open" && /* @__PURE__ */
|
|
848
|
-
request.comments > 0 && /* @__PURE__ */
|
|
849
|
-
/* @__PURE__ */
|
|
955
|
+
return /* @__PURE__ */ jsxs3("li", { className: compact ? "ya-row ya-row-sm" : "ya-row", children: [
|
|
956
|
+
/* @__PURE__ */ jsx3(VoteButton, { client, request, compact }),
|
|
957
|
+
/* @__PURE__ */ jsxs3("button", { type: "button", className: "ya-row-main", onClick: onOpen, children: [
|
|
958
|
+
/* @__PURE__ */ jsx3("span", { className: "ya-row-title", children: request.title }),
|
|
959
|
+
(request.status !== "open" || request.comments > 0 || request.mine) && /* @__PURE__ */ jsxs3("span", { className: "ya-meta", children: [
|
|
960
|
+
request.status !== "open" && /* @__PURE__ */ jsx3(StatusPill, { status: request.status }),
|
|
961
|
+
request.comments > 0 && /* @__PURE__ */ jsxs3("span", { children: [
|
|
962
|
+
/* @__PURE__ */ jsx3(IconChat, {}),
|
|
850
963
|
request.comments
|
|
851
964
|
] }),
|
|
852
|
-
request.mine && /* @__PURE__ */
|
|
965
|
+
request.mine && /* @__PURE__ */ jsx3("span", { children: "You asked" })
|
|
853
966
|
] })
|
|
854
967
|
] })
|
|
855
968
|
] });
|
|
856
969
|
}
|
|
857
970
|
function Skeleton({ rows = 3 }) {
|
|
858
|
-
return /* @__PURE__ */
|
|
971
|
+
return /* @__PURE__ */ jsx3("div", { className: "ya-list", "aria-label": "Loading", role: "status", children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx3("div", { className: "ya-skel" }, i)) });
|
|
859
972
|
}
|
|
860
|
-
function useLoad(
|
|
861
|
-
const [data, setData] =
|
|
862
|
-
const [error, setError] =
|
|
863
|
-
|
|
973
|
+
function useLoad(load2, deps) {
|
|
974
|
+
const [data, setData] = useState2(null);
|
|
975
|
+
const [error, setError] = useState2(null);
|
|
976
|
+
useEffect2(() => {
|
|
864
977
|
let alive = true;
|
|
865
978
|
setData(null);
|
|
866
979
|
setError(null);
|
|
867
|
-
|
|
980
|
+
load2().then((d) => alive && setData(d)).catch((e) => alive && setError(e instanceof YouAskedError ? e.code : "network"));
|
|
868
981
|
return () => {
|
|
869
982
|
alive = false;
|
|
870
983
|
};
|
|
@@ -904,9 +1017,9 @@ function ago(t) {
|
|
|
904
1017
|
return new Date(t).toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
905
1018
|
}
|
|
906
1019
|
function AppAvatar({ icon, size = 36 }) {
|
|
907
|
-
const [failed, setFailed] =
|
|
1020
|
+
const [failed, setFailed] = useState2(false);
|
|
908
1021
|
if (!icon || failed) return null;
|
|
909
|
-
return /* @__PURE__ */
|
|
1022
|
+
return /* @__PURE__ */ jsx3(
|
|
910
1023
|
"img",
|
|
911
1024
|
{
|
|
912
1025
|
className: "ya-avatar",
|
|
@@ -927,31 +1040,31 @@ function Header({
|
|
|
927
1040
|
onClose,
|
|
928
1041
|
right
|
|
929
1042
|
}) {
|
|
930
|
-
return /* @__PURE__ */
|
|
931
|
-
onBack && /* @__PURE__ */
|
|
1043
|
+
return /* @__PURE__ */ jsxs3("div", { className: onBack ? "ya-head ya-head-back" : "ya-head", children: [
|
|
1044
|
+
onBack && /* @__PURE__ */ jsx3("button", { type: "button", className: "ya-icon-btn", onClick: onBack, "aria-label": "Back", children: /* @__PURE__ */ jsx3(IconBack, {}) }),
|
|
932
1045
|
leading,
|
|
933
|
-
/* @__PURE__ */
|
|
934
|
-
/* @__PURE__ */
|
|
935
|
-
subtitle && /* @__PURE__ */
|
|
1046
|
+
/* @__PURE__ */ jsxs3("div", { className: "ya-head-text", children: [
|
|
1047
|
+
/* @__PURE__ */ jsx3("h2", { className: "ya-h", children: title }),
|
|
1048
|
+
subtitle && /* @__PURE__ */ jsx3("p", { className: "ya-sub", children: subtitle })
|
|
936
1049
|
] }),
|
|
937
1050
|
right,
|
|
938
|
-
onClose && /* @__PURE__ */
|
|
1051
|
+
onClose && /* @__PURE__ */ jsx3("button", { type: "button", className: "ya-icon-btn", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx3(IconClose, {}) })
|
|
939
1052
|
] });
|
|
940
1053
|
}
|
|
941
1054
|
|
|
942
1055
|
// src/views.tsx
|
|
943
|
-
import { useEffect as
|
|
944
|
-
import { Fragment, jsx as
|
|
1056
|
+
import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
1057
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
945
1058
|
function Navigator({ route, setRoute, onClose }) {
|
|
946
1059
|
switch (route.view) {
|
|
947
1060
|
case "home":
|
|
948
|
-
return /* @__PURE__ */
|
|
1061
|
+
return /* @__PURE__ */ jsx4(Home, { route, setRoute, onClose }, `${route.draft ?? ""}${route.focus ? "f" : ""}${route.topic ?? ""}`);
|
|
949
1062
|
case "board":
|
|
950
|
-
return /* @__PURE__ */
|
|
1063
|
+
return /* @__PURE__ */ jsx4(Board, { initialTab: route.tab, setRoute, onClose });
|
|
951
1064
|
case "detail":
|
|
952
|
-
return /* @__PURE__ */
|
|
1065
|
+
return /* @__PURE__ */ jsx4(Detail, { id: route.id, from: route.from, setRoute, onClose }, route.id);
|
|
953
1066
|
case "mine":
|
|
954
|
-
return /* @__PURE__ */
|
|
1067
|
+
return /* @__PURE__ */ jsx4(Mine, { setRoute, onClose });
|
|
955
1068
|
}
|
|
956
1069
|
}
|
|
957
1070
|
function splitMessage(text) {
|
|
@@ -963,23 +1076,23 @@ function splitMessage(text) {
|
|
|
963
1076
|
return { title, body: t };
|
|
964
1077
|
}
|
|
965
1078
|
function ReplyBubble({ notice, appName, onOpen }) {
|
|
966
|
-
return /* @__PURE__ */
|
|
967
|
-
/* @__PURE__ */
|
|
1079
|
+
return /* @__PURE__ */ jsxs4("div", { className: "ya-bubble ya-bubble-in", children: [
|
|
1080
|
+
/* @__PURE__ */ jsxs4("span", { className: "ya-bubble-kicker", children: [
|
|
968
1081
|
appName,
|
|
969
1082
|
" replied about ",
|
|
970
1083
|
notice.title
|
|
971
1084
|
] }),
|
|
972
|
-
/* @__PURE__ */
|
|
973
|
-
/* @__PURE__ */
|
|
1085
|
+
/* @__PURE__ */ jsx4("span", { children: notice.reply }),
|
|
1086
|
+
/* @__PURE__ */ jsx4("button", { type: "button", className: "ya-bubble-link", onClick: onOpen, children: "Reply" })
|
|
974
1087
|
] });
|
|
975
1088
|
}
|
|
976
1089
|
var MAX_SHOTS = 3;
|
|
977
1090
|
function Confetti() {
|
|
978
1091
|
const colors = ["var(--_accent)", "var(--_green)", "var(--_amber)", "#ff7eb3"];
|
|
979
|
-
return /* @__PURE__ */
|
|
1092
|
+
return /* @__PURE__ */ jsx4("span", { className: "ya-confetti", "aria-hidden": "true", children: Array.from({ length: 14 }, (_, i) => {
|
|
980
1093
|
const angle = Math.PI * (0.15 + i / 13 * 0.7) % Math.PI;
|
|
981
1094
|
const dist = 38 + i % 4 * 14;
|
|
982
|
-
return /* @__PURE__ */
|
|
1095
|
+
return /* @__PURE__ */ jsx4(
|
|
983
1096
|
"i",
|
|
984
1097
|
{
|
|
985
1098
|
style: {
|
|
@@ -998,33 +1111,33 @@ function Home({ route, setRoute, onClose }) {
|
|
|
998
1111
|
const { client, config, appName, appIcon, greeting, markSeen, whatsNew, dismissWhatsNew, pointAtIt } = useInternal();
|
|
999
1112
|
const top = useLoad(() => client.list("top", "active"), [client]);
|
|
1000
1113
|
const shipped = useLoad(() => client.list("new", "shipped"), [client]);
|
|
1001
|
-
const [text, setText] =
|
|
1002
|
-
const [thread, setThread] =
|
|
1003
|
-
const [similar, setSimilar] =
|
|
1004
|
-
const [notices] =
|
|
1005
|
-
const [news] =
|
|
1006
|
-
const [shots, setShots] =
|
|
1007
|
-
const [shotError, setShotError] =
|
|
1008
|
-
const [credit, setCredit] =
|
|
1009
|
-
const urls =
|
|
1010
|
-
const inputRef =
|
|
1011
|
-
const bodyRef =
|
|
1114
|
+
const [text, setText] = useState3(route.draft ?? "");
|
|
1115
|
+
const [thread, setThread] = useState3([]);
|
|
1116
|
+
const [similar, setSimilar] = useState3([]);
|
|
1117
|
+
const [notices] = useState3(() => config?.unseen ?? []);
|
|
1118
|
+
const [news] = useState3(() => whatsNew);
|
|
1119
|
+
const [shots, setShots] = useState3([]);
|
|
1120
|
+
const [shotError, setShotError] = useState3(null);
|
|
1121
|
+
const [credit, setCredit] = useState3(false);
|
|
1122
|
+
const urls = useRef3([]);
|
|
1123
|
+
const inputRef = useRef3(null);
|
|
1124
|
+
const bodyRef = useRef3(null);
|
|
1012
1125
|
const sending = thread.some((t) => t.kind === "typing");
|
|
1013
|
-
|
|
1126
|
+
useEffect3(() => {
|
|
1014
1127
|
if (notices.length) markSeen(notices.map((n) => n.id));
|
|
1015
1128
|
}, [notices, markSeen]);
|
|
1016
|
-
|
|
1129
|
+
useEffect3(() => {
|
|
1017
1130
|
if (news) dismissWhatsNew();
|
|
1018
1131
|
}, [news, dismissWhatsNew]);
|
|
1019
1132
|
const arrived = config?.unseen.filter((n) => n.kind === "reply" && !notices.some((o) => o.id === n.id)) ?? [];
|
|
1020
1133
|
const arrivedKey = arrived.map((n) => n.id).join(",");
|
|
1021
|
-
|
|
1134
|
+
useEffect3(() => {
|
|
1022
1135
|
if (!arrived.length) return;
|
|
1023
1136
|
setThread((th) => [...th, ...arrived.map((notice) => ({ kind: "reply", notice }))]);
|
|
1024
1137
|
markSeen(arrived.map((n) => n.id));
|
|
1025
1138
|
}, [arrivedKey]);
|
|
1026
|
-
|
|
1027
|
-
|
|
1139
|
+
useEffect3(() => () => urls.current.forEach((u) => URL.revokeObjectURL(u)), []);
|
|
1140
|
+
useEffect3(() => {
|
|
1028
1141
|
if (!route.focus) return;
|
|
1029
1142
|
const t = setTimeout(() => {
|
|
1030
1143
|
const el = inputRef.current;
|
|
@@ -1034,16 +1147,16 @@ function Home({ route, setRoute, onClose }) {
|
|
|
1034
1147
|
}, 60);
|
|
1035
1148
|
return () => clearTimeout(t);
|
|
1036
1149
|
}, [route.focus]);
|
|
1037
|
-
|
|
1150
|
+
useEffect3(() => {
|
|
1038
1151
|
const el = inputRef.current;
|
|
1039
1152
|
if (!el) return;
|
|
1040
1153
|
el.style.height = "";
|
|
1041
1154
|
if (text.includes("\n") || el.scrollHeight > el.clientHeight + 2) el.style.height = `${Math.min(el.scrollHeight, 132)}px`;
|
|
1042
1155
|
}, [text]);
|
|
1043
|
-
|
|
1156
|
+
useEffect3(() => {
|
|
1044
1157
|
if (thread.length) bodyRef.current?.scrollTo({ top: bodyRef.current.scrollHeight, behavior: "smooth" });
|
|
1045
1158
|
}, [thread]);
|
|
1046
|
-
|
|
1159
|
+
useEffect3(() => {
|
|
1047
1160
|
const q = text.trim();
|
|
1048
1161
|
if (q.length < 4) {
|
|
1049
1162
|
setSimilar([]);
|
|
@@ -1104,106 +1217,106 @@ function Home({ route, setRoute, onClose }) {
|
|
|
1104
1217
|
}
|
|
1105
1218
|
};
|
|
1106
1219
|
const chatting = thread.length > 0;
|
|
1107
|
-
const openRequest = (id) => setRoute({ view: "detail", id });
|
|
1220
|
+
const openRequest = (id) => setRoute({ view: "detail", id, from: "home" });
|
|
1108
1221
|
const asking = route.topic && route.placeholder ? route.topic : null;
|
|
1109
1222
|
const placeholder = route.placeholder ?? "Ask for a feature\u2026";
|
|
1110
1223
|
const yours = news?.items.find((i) => i.mine);
|
|
1111
1224
|
const listed = new Set(news?.items.map((i) => i.id));
|
|
1112
1225
|
const shownNotices = notices.filter((n) => !(n.kind === "shipped" && listed.has(n.requestId)));
|
|
1113
|
-
return /* @__PURE__ */
|
|
1114
|
-
/* @__PURE__ */
|
|
1226
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1227
|
+
/* @__PURE__ */ jsx4(
|
|
1115
1228
|
Header,
|
|
1116
1229
|
{
|
|
1117
|
-
leading: /* @__PURE__ */
|
|
1230
|
+
leading: /* @__PURE__ */ jsx4(AppAvatar, { icon: appIcon }),
|
|
1118
1231
|
title: appName,
|
|
1119
1232
|
subtitle: "Ideas, votes and what's new",
|
|
1120
1233
|
onClose
|
|
1121
1234
|
}
|
|
1122
1235
|
),
|
|
1123
|
-
/* @__PURE__ */
|
|
1124
|
-
/* @__PURE__ */
|
|
1125
|
-
news && /* @__PURE__ */
|
|
1126
|
-
yours && /* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1128
|
-
/* @__PURE__ */
|
|
1129
|
-
/* @__PURE__ */
|
|
1130
|
-
/* @__PURE__ */
|
|
1131
|
-
/* @__PURE__ */
|
|
1132
|
-
i.mine && /* @__PURE__ */
|
|
1236
|
+
/* @__PURE__ */ jsxs4("div", { className: "ya-body ya-chat", ref: bodyRef, children: [
|
|
1237
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-bubble ya-bubble-in", children: asking ? `Let's talk about ${asking}. What's missing, or what bugs you?` : greeting ?? `Hey! What would make ${appName} better for you?` }),
|
|
1238
|
+
news && /* @__PURE__ */ jsxs4("div", { className: yours ? "ya-bubble ya-bubble-in ya-bubble-win ya-bubble-news" : "ya-bubble ya-bubble-in ya-bubble-news", children: [
|
|
1239
|
+
yours && /* @__PURE__ */ jsx4(Confetti, {}),
|
|
1240
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-bubble-kicker", children: whatsNewHeading(news.total) }),
|
|
1241
|
+
/* @__PURE__ */ jsx4("ul", { className: "ya-news", children: news.items.map((i) => /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsxs4("button", { type: "button", onClick: () => openRequest(i.id), children: [
|
|
1242
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-shipped-dot", children: /* @__PURE__ */ jsx4(IconCheck, {}) }),
|
|
1243
|
+
/* @__PURE__ */ jsxs4("span", { className: "ya-news-text", children: [
|
|
1244
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-news-title", children: i.title }),
|
|
1245
|
+
i.mine && /* @__PURE__ */ jsx4("span", { className: "ya-news-you", children: "You asked for this" })
|
|
1133
1246
|
] }),
|
|
1134
|
-
/* @__PURE__ */
|
|
1247
|
+
/* @__PURE__ */ jsx4(IconChevron, {})
|
|
1135
1248
|
] }) }, i.id)) }),
|
|
1136
|
-
yours && /* @__PURE__ */
|
|
1137
|
-
news.total > news.items.length && /* @__PURE__ */
|
|
1249
|
+
yours && /* @__PURE__ */ jsx4("span", { children: "That one was yours. Thanks for asking." }),
|
|
1250
|
+
news.total > news.items.length && /* @__PURE__ */ jsxs4("button", { type: "button", className: "ya-bubble-link", onClick: () => setRoute({ view: "board", tab: "shipped" }), children: [
|
|
1138
1251
|
"See all ",
|
|
1139
1252
|
news.total
|
|
1140
1253
|
] })
|
|
1141
1254
|
] }),
|
|
1142
1255
|
shownNotices.map(
|
|
1143
|
-
(n) => n.kind === "reply" ? /* @__PURE__ */
|
|
1144
|
-
/* @__PURE__ */
|
|
1145
|
-
/* @__PURE__ */
|
|
1256
|
+
(n) => n.kind === "reply" ? /* @__PURE__ */ jsx4(ReplyBubble, { notice: n, appName, onOpen: () => openRequest(n.requestId) }, n.id) : /* @__PURE__ */ jsxs4("div", { className: "ya-bubble ya-bubble-in ya-bubble-win", children: [
|
|
1257
|
+
/* @__PURE__ */ jsxs4("span", { className: "ya-live", children: [
|
|
1258
|
+
/* @__PURE__ */ jsx4(IconCheck, {}),
|
|
1146
1259
|
"It's live"
|
|
1147
1260
|
] }),
|
|
1148
|
-
/* @__PURE__ */
|
|
1261
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1149
1262
|
"You asked for ",
|
|
1150
|
-
/* @__PURE__ */
|
|
1263
|
+
/* @__PURE__ */ jsx4("b", { children: n.title }),
|
|
1151
1264
|
". ",
|
|
1152
1265
|
n.shipNote ?? "Thanks for asking."
|
|
1153
1266
|
] }),
|
|
1154
|
-
/* @__PURE__ */
|
|
1267
|
+
/* @__PURE__ */ jsx4("button", { type: "button", className: "ya-bubble-link", onClick: () => openRequest(n.requestId), children: "See it" })
|
|
1155
1268
|
] }, n.id)
|
|
1156
1269
|
),
|
|
1157
|
-
!chatting && /* @__PURE__ */
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
shipped.data && shipped.data.length > 0 && /* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1161
|
-
/* @__PURE__ */
|
|
1162
|
-
/* @__PURE__ */
|
|
1270
|
+
!chatting && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1271
|
+
/* @__PURE__ */ jsx4(Section, { title: "Popular right now", action: "See all", onAction: () => setRoute({ view: "board" }), children: top.error ? /* @__PURE__ */ jsx4("p", { className: "ya-note", children: errorText(top.error) }) : !top.data ? /* @__PURE__ */ jsx4(Skeleton, { rows: 2 }) : top.data.length === 0 ? /* @__PURE__ */ jsx4("p", { className: "ya-note", children: "No requests yet. Yours could be the first." }) : /* @__PURE__ */ jsx4("ul", { className: "ya-list", children: top.data.slice(0, 3).map((r) => /* @__PURE__ */ jsx4(RequestRow, { client, request: r, compact: true, onOpen: () => openRequest(r.id) }, r.id)) }) }),
|
|
1272
|
+
shipped.data && shipped.data.length > 0 && /* @__PURE__ */ jsx4(Section, { title: "Recently shipped", action: "All", onAction: () => setRoute({ view: "board", tab: "shipped" }), children: /* @__PURE__ */ jsx4("ul", { className: "ya-shipped", children: shipped.data.slice(0, 3).map((r) => /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsxs4("button", { type: "button", onClick: () => openRequest(r.id), children: [
|
|
1273
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-shipped-dot", children: /* @__PURE__ */ jsx4(IconCheck, {}) }),
|
|
1274
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-shipped-title", children: r.title }),
|
|
1275
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-shipped-when", children: r.shippedAt ? ago(r.shippedAt) : "" })
|
|
1163
1276
|
] }) }, r.id)) }) })
|
|
1164
1277
|
] }),
|
|
1165
1278
|
thread.map(
|
|
1166
|
-
(t, i) => t.kind === "out" ? /* @__PURE__ */
|
|
1167
|
-
t.images?.map((src) => /* @__PURE__ */
|
|
1279
|
+
(t, i) => t.kind === "out" ? /* @__PURE__ */ jsxs4("div", { className: "ya-bubble ya-bubble-out", children: [
|
|
1280
|
+
t.images?.map((src) => /* @__PURE__ */ jsx4("img", { className: "ya-bubble-img", src, alt: "Your screenshot" }, src)),
|
|
1168
1281
|
t.text
|
|
1169
|
-
] }, i) : t.kind === "typing" ? /* @__PURE__ */
|
|
1170
|
-
/* @__PURE__ */
|
|
1171
|
-
/* @__PURE__ */
|
|
1172
|
-
/* @__PURE__ */
|
|
1173
|
-
] }, i) : t.kind === "reply" ? /* @__PURE__ */
|
|
1174
|
-
/* @__PURE__ */
|
|
1282
|
+
] }, i) : t.kind === "typing" ? /* @__PURE__ */ jsxs4("div", { className: "ya-bubble ya-bubble-in ya-typing", "aria-label": "Posting", children: [
|
|
1283
|
+
/* @__PURE__ */ jsx4("span", {}),
|
|
1284
|
+
/* @__PURE__ */ jsx4("span", {}),
|
|
1285
|
+
/* @__PURE__ */ jsx4("span", {})
|
|
1286
|
+
] }, i) : t.kind === "reply" ? /* @__PURE__ */ jsx4(ReplyBubble, { notice: t.notice, appName, onOpen: () => openRequest(t.notice.requestId) }, i) : t.kind === "posted" ? /* @__PURE__ */ jsxs4("div", { className: "ya-bubble ya-bubble-in", children: [
|
|
1287
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1175
1288
|
"Got it. ",
|
|
1176
|
-
/* @__PURE__ */
|
|
1289
|
+
/* @__PURE__ */ jsx4("b", { children: t.request.title }),
|
|
1177
1290
|
" is on the board, and we'll tell you right here when it ships."
|
|
1178
1291
|
] }),
|
|
1179
|
-
/* @__PURE__ */
|
|
1180
|
-
] }, i) : /* @__PURE__ */
|
|
1292
|
+
/* @__PURE__ */ jsx4("button", { type: "button", className: "ya-bubble-link", onClick: () => openRequest(t.request.id), children: "View request" })
|
|
1293
|
+
] }, i) : /* @__PURE__ */ jsx4("div", { className: "ya-bubble ya-bubble-in ya-bubble-error", role: "alert", children: t.text }, i)
|
|
1181
1294
|
),
|
|
1182
|
-
chatting && !sending && /* @__PURE__ */
|
|
1295
|
+
chatting && !sending && /* @__PURE__ */ jsx4("button", { type: "button", className: "ya-chip", onClick: () => setRoute({ view: "board" }), children: "See what others asked for" })
|
|
1183
1296
|
] }),
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
similar.length > 0 && /* @__PURE__ */
|
|
1186
|
-
/* @__PURE__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
1297
|
+
/* @__PURE__ */ jsxs4("div", { className: "ya-composer-wrap", children: [
|
|
1298
|
+
similar.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "ya-tray", "aria-live": "polite", children: [
|
|
1299
|
+
/* @__PURE__ */ jsx4("p", { className: "ya-tray-h", children: "Sounds like one of these. Vote instead?" }),
|
|
1300
|
+
/* @__PURE__ */ jsx4("ul", { className: "ya-list", children: similar.map((r) => /* @__PURE__ */ jsx4(RequestRow, { client, request: r, compact: true, onOpen: () => openRequest(r.id) }, r.id)) })
|
|
1188
1301
|
] }),
|
|
1189
|
-
shots.length > 0 && /* @__PURE__ */
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1302
|
+
shots.length > 0 && /* @__PURE__ */ jsx4("ul", { className: "ya-shots", "aria-label": "Screenshots", children: shots.map((s, i) => /* @__PURE__ */ jsxs4("li", { className: "ya-shot", children: [
|
|
1303
|
+
/* @__PURE__ */ jsx4("img", { src: s.url, alt: "" }),
|
|
1304
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1192
1305
|
"Screenshot",
|
|
1193
1306
|
shots.length > 1 ? ` ${i + 1}` : ""
|
|
1194
1307
|
] }),
|
|
1195
|
-
/* @__PURE__ */
|
|
1308
|
+
/* @__PURE__ */ jsx4(
|
|
1196
1309
|
"button",
|
|
1197
1310
|
{
|
|
1198
1311
|
type: "button",
|
|
1199
1312
|
className: "ya-shot-x",
|
|
1200
1313
|
"aria-label": `Remove screenshot${shots.length > 1 ? ` ${i + 1}` : ""}`,
|
|
1201
1314
|
onClick: () => setShots((all) => all.filter((x) => x !== s)),
|
|
1202
|
-
children: /* @__PURE__ */
|
|
1315
|
+
children: /* @__PURE__ */ jsx4(IconClose, {})
|
|
1203
1316
|
}
|
|
1204
1317
|
)
|
|
1205
1318
|
] }, s.url)) }),
|
|
1206
|
-
/* @__PURE__ */
|
|
1319
|
+
/* @__PURE__ */ jsxs4(
|
|
1207
1320
|
"form",
|
|
1208
1321
|
{
|
|
1209
1322
|
className: "ya-composer",
|
|
@@ -1212,7 +1325,7 @@ function Home({ route, setRoute, onClose }) {
|
|
|
1212
1325
|
send();
|
|
1213
1326
|
},
|
|
1214
1327
|
children: [
|
|
1215
|
-
/* @__PURE__ */
|
|
1328
|
+
/* @__PURE__ */ jsx4(
|
|
1216
1329
|
"textarea",
|
|
1217
1330
|
{
|
|
1218
1331
|
ref: inputRef,
|
|
@@ -1231,12 +1344,12 @@ function Home({ route, setRoute, onClose }) {
|
|
|
1231
1344
|
}
|
|
1232
1345
|
}
|
|
1233
1346
|
),
|
|
1234
|
-
/* @__PURE__ */
|
|
1347
|
+
/* @__PURE__ */ jsx4("button", { type: "submit", className: "ya-send", disabled: text.trim().length < 3 || sending, "aria-label": "Send", children: /* @__PURE__ */ jsx4(IconSend, {}) })
|
|
1235
1348
|
]
|
|
1236
1349
|
}
|
|
1237
1350
|
),
|
|
1238
|
-
/* @__PURE__ */
|
|
1239
|
-
/* @__PURE__ */
|
|
1351
|
+
/* @__PURE__ */ jsxs4("div", { className: "ya-tools", children: [
|
|
1352
|
+
/* @__PURE__ */ jsxs4(
|
|
1240
1353
|
"button",
|
|
1241
1354
|
{
|
|
1242
1355
|
type: "button",
|
|
@@ -1246,18 +1359,18 @@ function Home({ route, setRoute, onClose }) {
|
|
|
1246
1359
|
onFocus: () => void import("./capture-FYZGL54F.js"),
|
|
1247
1360
|
disabled: sending || shots.length >= MAX_SHOTS,
|
|
1248
1361
|
children: [
|
|
1249
|
-
/* @__PURE__ */
|
|
1362
|
+
/* @__PURE__ */ jsx4(IconFrame, {}),
|
|
1250
1363
|
"Show us"
|
|
1251
1364
|
]
|
|
1252
1365
|
}
|
|
1253
1366
|
),
|
|
1254
|
-
config?.canCredit && text.trim().length > 0 && /* @__PURE__ */
|
|
1367
|
+
config?.canCredit && text.trim().length > 0 && /* @__PURE__ */ jsxs4("button", { type: "button", className: "ya-switch-row", role: "switch", "aria-checked": credit, onClick: () => setCredit((c) => !c), children: [
|
|
1255
1368
|
"Credit me when it ships",
|
|
1256
|
-
/* @__PURE__ */
|
|
1369
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-switch", "aria-hidden": "true" })
|
|
1257
1370
|
] })
|
|
1258
1371
|
] }),
|
|
1259
|
-
shotError && /* @__PURE__ */
|
|
1260
|
-
config?.watermark && /* @__PURE__ */
|
|
1372
|
+
shotError && /* @__PURE__ */ jsx4("p", { className: "ya-note", role: "alert", children: shotError }),
|
|
1373
|
+
config?.watermark && /* @__PURE__ */ jsx4("p", { className: "ya-mark", children: "Feedback by YouAsked" })
|
|
1261
1374
|
] })
|
|
1262
1375
|
] });
|
|
1263
1376
|
}
|
|
@@ -1267,12 +1380,12 @@ function Section({
|
|
|
1267
1380
|
onAction,
|
|
1268
1381
|
children
|
|
1269
1382
|
}) {
|
|
1270
|
-
return /* @__PURE__ */
|
|
1271
|
-
/* @__PURE__ */
|
|
1272
|
-
/* @__PURE__ */
|
|
1273
|
-
action && /* @__PURE__ */
|
|
1383
|
+
return /* @__PURE__ */ jsxs4("section", { className: "ya-section", children: [
|
|
1384
|
+
/* @__PURE__ */ jsxs4("div", { className: "ya-section-head", children: [
|
|
1385
|
+
/* @__PURE__ */ jsx4("h3", { children: title }),
|
|
1386
|
+
action && /* @__PURE__ */ jsxs4("button", { type: "button", className: "ya-link", onClick: onAction, children: [
|
|
1274
1387
|
action,
|
|
1275
|
-
/* @__PURE__ */
|
|
1388
|
+
/* @__PURE__ */ jsx4(IconChevron, {})
|
|
1276
1389
|
] })
|
|
1277
1390
|
] }),
|
|
1278
1391
|
children
|
|
@@ -1289,36 +1402,36 @@ function Board({
|
|
|
1289
1402
|
onClose
|
|
1290
1403
|
}) {
|
|
1291
1404
|
const { client, title } = useInternal();
|
|
1292
|
-
const [tab, setTab] =
|
|
1405
|
+
const [tab, setTab] = useState3(TABS.find((t) => t.key === initialTab) ?? TABS[0]);
|
|
1293
1406
|
const { data, error } = useLoad(() => client.list(tab.sort, tab.status), [client, tab.key]);
|
|
1294
|
-
return /* @__PURE__ */
|
|
1295
|
-
/* @__PURE__ */
|
|
1407
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1408
|
+
/* @__PURE__ */ jsx4(
|
|
1296
1409
|
Header,
|
|
1297
1410
|
{
|
|
1298
1411
|
title,
|
|
1299
1412
|
onBack: () => setRoute({ view: "home" }),
|
|
1300
1413
|
onClose,
|
|
1301
|
-
right: /* @__PURE__ */
|
|
1414
|
+
right: /* @__PURE__ */ jsx4("button", { type: "button", className: "ya-link", onClick: () => setRoute({ view: "mine" }), children: "Yours" })
|
|
1302
1415
|
}
|
|
1303
1416
|
),
|
|
1304
|
-
/* @__PURE__ */
|
|
1305
|
-
/* @__PURE__ */
|
|
1306
|
-
/* @__PURE__ */
|
|
1417
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-tabs", role: "tablist", "aria-label": "Sort requests", children: TABS.map((t) => /* @__PURE__ */ jsx4("button", { type: "button", role: "tab", className: "ya-tab", "aria-selected": tab.key === t.key, onClick: () => setTab(t), children: t.label }, t.key)) }),
|
|
1418
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-body", children: error ? /* @__PURE__ */ jsx4("p", { className: "ya-empty", children: errorText(error) }) : !data ? /* @__PURE__ */ jsx4(Skeleton, {}) : data.length === 0 ? /* @__PURE__ */ jsxs4("div", { className: "ya-empty", children: [
|
|
1419
|
+
/* @__PURE__ */ jsx4("b", { children: tab.key === "shipped" ? "Nothing shipped yet" : "No requests yet" }),
|
|
1307
1420
|
tab.key === "shipped" ? "Requests show up here once they're live." : "Tell us what you'd like next. Others can vote on it."
|
|
1308
|
-
] }) : /* @__PURE__ */
|
|
1309
|
-
/* @__PURE__ */
|
|
1310
|
-
/* @__PURE__ */
|
|
1421
|
+
] }) : /* @__PURE__ */ jsx4("ul", { className: "ya-list", children: data.map((r) => /* @__PURE__ */ jsx4(RequestRow, { client, request: r, onOpen: () => setRoute({ view: "detail", id: r.id, from: "board" }) }, r.id)) }) }),
|
|
1422
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-foot", children: /* @__PURE__ */ jsxs4("button", { type: "button", className: "ya-btn", onClick: () => setRoute({ view: "home", focus: true }), children: [
|
|
1423
|
+
/* @__PURE__ */ jsx4(IconPlus, {}),
|
|
1311
1424
|
"Request a feature"
|
|
1312
1425
|
] }) })
|
|
1313
1426
|
] });
|
|
1314
1427
|
}
|
|
1315
|
-
function Detail({ id, setRoute, onClose }) {
|
|
1428
|
+
function Detail({ id, from, setRoute, onClose }) {
|
|
1316
1429
|
const { client, config, markSeen, appName, appIcon } = useInternal();
|
|
1317
1430
|
const { data, error, setData } = useLoad(() => client.get(id), [client, id]);
|
|
1318
1431
|
const unseenHere = config?.unseen.filter((n) => n.requestId === id).map((n) => n.id).join(",") ?? "";
|
|
1319
|
-
const loaded =
|
|
1432
|
+
const loaded = useRef3(false);
|
|
1320
1433
|
loaded.current = Boolean(data);
|
|
1321
|
-
|
|
1434
|
+
useEffect3(() => {
|
|
1322
1435
|
if (!unseenHere) return;
|
|
1323
1436
|
markSeen(unseenHere.split(","));
|
|
1324
1437
|
if (loaded.current) {
|
|
@@ -1326,15 +1439,15 @@ function Detail({ id, setRoute, onClose }) {
|
|
|
1326
1439
|
});
|
|
1327
1440
|
}
|
|
1328
1441
|
}, [unseenHere, markSeen]);
|
|
1329
|
-
const [reply, setReply] =
|
|
1330
|
-
const [sending, setSending] =
|
|
1331
|
-
const [replyError, setReplyError] =
|
|
1332
|
-
const [voted, setVoted] =
|
|
1333
|
-
const [early, setEarly] =
|
|
1334
|
-
|
|
1335
|
-
const [confirmDelete, setConfirmDelete] =
|
|
1336
|
-
const [deleting, setDeleting] =
|
|
1337
|
-
const [deleteError, setDeleteError] =
|
|
1442
|
+
const [reply, setReply] = useState3("");
|
|
1443
|
+
const [sending, setSending] = useState3(false);
|
|
1444
|
+
const [replyError, setReplyError] = useState3(null);
|
|
1445
|
+
const [voted, setVoted] = useState3(null);
|
|
1446
|
+
const [early, setEarly] = useState3(false);
|
|
1447
|
+
useEffect3(() => setEarly(Boolean(data?.earlyAccess)), [data?.earlyAccess]);
|
|
1448
|
+
const [confirmDelete, setConfirmDelete] = useState3(false);
|
|
1449
|
+
const [deleting, setDeleting] = useState3(false);
|
|
1450
|
+
const [deleteError, setDeleteError] = useState3(null);
|
|
1338
1451
|
const remove = async () => {
|
|
1339
1452
|
if (!data?.request || deleting) return;
|
|
1340
1453
|
setDeleting(true);
|
|
@@ -1357,7 +1470,7 @@ function Detail({ id, setRoute, onClose }) {
|
|
|
1357
1470
|
setEarly(before);
|
|
1358
1471
|
}
|
|
1359
1472
|
};
|
|
1360
|
-
|
|
1473
|
+
useEffect3(() => {
|
|
1361
1474
|
if (data?.redirect) setRoute({ view: "detail", id: data.redirect });
|
|
1362
1475
|
}, [data?.redirect, setRoute]);
|
|
1363
1476
|
const request = data?.request;
|
|
@@ -1377,58 +1490,58 @@ function Detail({ id, setRoute, onClose }) {
|
|
|
1377
1490
|
setSending(false);
|
|
1378
1491
|
}
|
|
1379
1492
|
};
|
|
1380
|
-
return /* @__PURE__ */
|
|
1381
|
-
/* @__PURE__ */
|
|
1382
|
-
/* @__PURE__ */
|
|
1383
|
-
/* @__PURE__ */
|
|
1384
|
-
request.status !== "open" && /* @__PURE__ */
|
|
1385
|
-
/* @__PURE__ */
|
|
1493
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1494
|
+
/* @__PURE__ */ jsx4(Header, { title: "", onBack: () => setRoute({ view: from ?? "board" }), onClose }),
|
|
1495
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-body", children: error ? /* @__PURE__ */ jsx4("p", { className: "ya-empty", children: error === "not_found" ? "This request was removed." : errorText(error) }) : !request ? /* @__PURE__ */ jsx4(Skeleton, {}) : /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1496
|
+
/* @__PURE__ */ jsxs4("div", { className: "ya-detail-meta", children: [
|
|
1497
|
+
request.status !== "open" && /* @__PURE__ */ jsx4(StatusPill, { status: request.status }),
|
|
1498
|
+
/* @__PURE__ */ jsxs4("span", { className: "ya-ref", children: [
|
|
1386
1499
|
"YA-",
|
|
1387
1500
|
request.number
|
|
1388
1501
|
] })
|
|
1389
1502
|
] }),
|
|
1390
|
-
/* @__PURE__ */
|
|
1391
|
-
request.body && request.body !== request.title && /* @__PURE__ */
|
|
1392
|
-
data?.attachments && data.attachments.length > 0 && /* @__PURE__ */
|
|
1393
|
-
/* @__PURE__ */
|
|
1394
|
-
(request.status === "planned" || request.status === "in_progress") && (voted ?? request.voted) && /* @__PURE__ */
|
|
1395
|
-
/* @__PURE__ */
|
|
1396
|
-
/* @__PURE__ */
|
|
1397
|
-
/* @__PURE__ */
|
|
1398
|
-
/* @__PURE__ */
|
|
1503
|
+
/* @__PURE__ */ jsx4("h3", { className: "ya-detail-title", children: request.title }),
|
|
1504
|
+
request.body && request.body !== request.title && /* @__PURE__ */ jsx4("p", { className: "ya-text", children: request.body }),
|
|
1505
|
+
data?.attachments && data.attachments.length > 0 && /* @__PURE__ */ jsx4("div", { className: "ya-attachments", children: data.attachments.map((a) => /* @__PURE__ */ jsx4("a", { href: a.url, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsx4("img", { src: a.url, alt: "Screenshot attached to this request", loading: "lazy" }) }, a.id)) }),
|
|
1506
|
+
/* @__PURE__ */ jsx4(BigVote, { client, request, onChange: setVoted }),
|
|
1507
|
+
(request.status === "planned" || request.status === "in_progress") && (voted ?? request.voted) && /* @__PURE__ */ jsxs4("button", { type: "button", className: "ya-early", role: "switch", "aria-checked": early, onClick: toggleEarly, children: [
|
|
1508
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-card-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(IconSpark, {}) }),
|
|
1509
|
+
/* @__PURE__ */ jsxs4("span", { className: "ya-menurow-text", children: [
|
|
1510
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-menurow-label", children: "Try it early" }),
|
|
1511
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-menurow-sub", children: early ? "You're on the list. We'll let you in first." : "Get access before everyone else" })
|
|
1399
1512
|
] }),
|
|
1400
|
-
/* @__PURE__ */
|
|
1513
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-switch", "aria-hidden": "true" })
|
|
1401
1514
|
] }),
|
|
1402
|
-
request.source && /* @__PURE__ */
|
|
1515
|
+
request.source && /* @__PURE__ */ jsxs4("p", { className: "ya-note", children: [
|
|
1403
1516
|
"Also asked",
|
|
1404
1517
|
" ",
|
|
1405
|
-
request.sourceUrl ? /* @__PURE__ */
|
|
1518
|
+
request.sourceUrl ? /* @__PURE__ */ jsx4("a", { href: request.sourceUrl, target: "_blank", rel: "noopener noreferrer", children: request.source === "reddit" ? "on Reddit" : "in App Store reviews" }) : request.source === "reddit" ? "on Reddit" : "in App Store reviews",
|
|
1406
1519
|
"."
|
|
1407
1520
|
] }),
|
|
1408
|
-
request.mine && request.status !== "shipped" && /* @__PURE__ */
|
|
1409
|
-
data?.canDelete && (confirmDelete ? /* @__PURE__ */
|
|
1521
|
+
request.mine && request.status !== "shipped" && /* @__PURE__ */ jsx4("p", { className: "ya-note", children: "You asked for this. We'll tell you here when it ships." }),
|
|
1522
|
+
data?.canDelete && (confirmDelete ? /* @__PURE__ */ jsxs4("p", { className: "ya-note ya-delete-row", children: [
|
|
1410
1523
|
"Delete this request? This can't be undone.",
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
1413
|
-
] }) : /* @__PURE__ */
|
|
1414
|
-
deleteError && /* @__PURE__ */
|
|
1415
|
-
request.status === "shipped" && /* @__PURE__ */
|
|
1416
|
-
/* @__PURE__ */
|
|
1417
|
-
/* @__PURE__ */
|
|
1418
|
-
/* @__PURE__ */
|
|
1524
|
+
/* @__PURE__ */ jsx4("button", { type: "button", className: "ya-link ya-link-danger", onClick: remove, disabled: deleting, children: deleting ? "Deleting\u2026" : "Delete" }),
|
|
1525
|
+
/* @__PURE__ */ jsx4("button", { type: "button", className: "ya-link", onClick: () => setConfirmDelete(false), disabled: deleting, children: "Keep it" })
|
|
1526
|
+
] }) : /* @__PURE__ */ jsx4("p", { className: "ya-note ya-delete-row", children: /* @__PURE__ */ jsx4("button", { type: "button", className: "ya-link ya-link-quiet", onClick: () => setConfirmDelete(true), children: "Delete my request" }) })),
|
|
1527
|
+
deleteError && /* @__PURE__ */ jsx4("p", { className: "ya-note", role: "alert", children: deleteError }),
|
|
1528
|
+
request.status === "shipped" && /* @__PURE__ */ jsxs4("div", { className: "ya-callout", "data-tone": "success", children: [
|
|
1529
|
+
/* @__PURE__ */ jsx4(IconCheck, {}),
|
|
1530
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1531
|
+
/* @__PURE__ */ jsx4("b", { children: "It's live." }),
|
|
1419
1532
|
request.shipNote ? ` ${request.shipNote}` : " Thanks for asking.",
|
|
1420
|
-
request.creditName && /* @__PURE__ */
|
|
1533
|
+
request.creditName && /* @__PURE__ */ jsxs4("span", { className: "ya-credit", children: [
|
|
1421
1534
|
"Thanks to ",
|
|
1422
1535
|
request.creditName,
|
|
1423
1536
|
" for asking."
|
|
1424
1537
|
] })
|
|
1425
1538
|
] })
|
|
1426
1539
|
] }),
|
|
1427
|
-
/* @__PURE__ */
|
|
1428
|
-
comments.length === 0 ? /* @__PURE__ */
|
|
1540
|
+
/* @__PURE__ */ jsx4("p", { className: "ya-section-h", children: "Conversation" }),
|
|
1541
|
+
comments.length === 0 ? /* @__PURE__ */ jsx4("p", { className: "ya-text ya-text-muted", children: "No messages yet. Add details or ask a question below." }) : /* @__PURE__ */ jsx4("div", { className: "ya-thread", children: comments.map((c) => /* @__PURE__ */ jsx4(Message, { comment: c, appName, appIcon }, c.id)) })
|
|
1429
1542
|
] }) }),
|
|
1430
|
-
request && /* @__PURE__ */
|
|
1431
|
-
/* @__PURE__ */
|
|
1543
|
+
request && /* @__PURE__ */ jsxs4("form", { className: "ya-composer ya-composer-bar", onSubmit: send, children: [
|
|
1544
|
+
/* @__PURE__ */ jsx4(
|
|
1432
1545
|
"textarea",
|
|
1433
1546
|
{
|
|
1434
1547
|
className: "ya-composer-input",
|
|
@@ -1446,49 +1559,49 @@ function Detail({ id, setRoute, onClose }) {
|
|
|
1446
1559
|
}
|
|
1447
1560
|
}
|
|
1448
1561
|
),
|
|
1449
|
-
/* @__PURE__ */
|
|
1450
|
-
replyError && /* @__PURE__ */
|
|
1562
|
+
/* @__PURE__ */ jsx4("button", { type: "submit", className: "ya-send", disabled: !reply.trim() || sending, "aria-label": "Send comment", children: /* @__PURE__ */ jsx4(IconSend, {}) }),
|
|
1563
|
+
replyError && /* @__PURE__ */ jsx4("span", { className: "ya-sr", role: "alert", children: replyError })
|
|
1451
1564
|
] })
|
|
1452
1565
|
] });
|
|
1453
1566
|
}
|
|
1454
1567
|
function Message({ comment, appName, appIcon }) {
|
|
1455
|
-
const when = /* @__PURE__ */
|
|
1568
|
+
const when = /* @__PURE__ */ jsx4("time", { dateTime: new Date(comment.createdAt).toISOString(), children: ago(comment.createdAt) });
|
|
1456
1569
|
if (comment.mine) {
|
|
1457
|
-
return /* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1459
|
-
/* @__PURE__ */
|
|
1570
|
+
return /* @__PURE__ */ jsxs4("div", { className: "ya-msg ya-msg-out", children: [
|
|
1571
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-bubble ya-bubble-out", children: comment.body }),
|
|
1572
|
+
/* @__PURE__ */ jsx4("span", { className: "ya-msg-meta", children: when })
|
|
1460
1573
|
] });
|
|
1461
1574
|
}
|
|
1462
|
-
return /* @__PURE__ */
|
|
1463
|
-
comment.team && appIcon ? /* @__PURE__ */
|
|
1464
|
-
/* @__PURE__ */
|
|
1465
|
-
/* @__PURE__ */
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
comment.team && /* @__PURE__ */
|
|
1575
|
+
return /* @__PURE__ */ jsxs4("div", { className: "ya-msg", children: [
|
|
1576
|
+
comment.team && appIcon ? /* @__PURE__ */ jsx4(AppAvatar, { icon: appIcon, size: 26 }) : null,
|
|
1577
|
+
/* @__PURE__ */ jsxs4("div", { className: "ya-msg-body", children: [
|
|
1578
|
+
/* @__PURE__ */ jsxs4("span", { className: "ya-msg-meta", children: [
|
|
1579
|
+
/* @__PURE__ */ jsx4("b", { children: comment.team ? appName : comment.author || "Someone" }),
|
|
1580
|
+
comment.team && /* @__PURE__ */ jsx4("span", { className: "ya-team", children: "Team" }),
|
|
1468
1581
|
when
|
|
1469
1582
|
] }),
|
|
1470
|
-
/* @__PURE__ */
|
|
1583
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-bubble ya-bubble-in", children: comment.body })
|
|
1471
1584
|
] })
|
|
1472
1585
|
] });
|
|
1473
1586
|
}
|
|
1474
1587
|
function Mine({ setRoute, onClose }) {
|
|
1475
1588
|
const { client } = useInternal();
|
|
1476
1589
|
const { data, error } = useLoad(() => client.mine(), [client]);
|
|
1477
|
-
return /* @__PURE__ */
|
|
1478
|
-
/* @__PURE__ */
|
|
1479
|
-
/* @__PURE__ */
|
|
1480
|
-
/* @__PURE__ */
|
|
1590
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1591
|
+
/* @__PURE__ */ jsx4(Header, { title: "Your requests", onBack: () => setRoute({ view: "board" }), onClose }),
|
|
1592
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-body", children: error ? /* @__PURE__ */ jsx4("p", { className: "ya-empty", children: errorText(error) }) : !data ? /* @__PURE__ */ jsx4(Skeleton, {}) : data.length === 0 ? /* @__PURE__ */ jsxs4("div", { className: "ya-empty", children: [
|
|
1593
|
+
/* @__PURE__ */ jsx4("b", { children: "Nothing yet" }),
|
|
1481
1594
|
"Requests you post or vote on show up here, with their status."
|
|
1482
|
-
] }) : /* @__PURE__ */
|
|
1483
|
-
/* @__PURE__ */
|
|
1484
|
-
/* @__PURE__ */
|
|
1595
|
+
] }) : /* @__PURE__ */ jsx4("ul", { className: "ya-list", children: data.map((r) => /* @__PURE__ */ jsx4(RequestRow, { client, request: r, onOpen: () => setRoute({ view: "detail", id: r.id, from: "mine" }) }, r.id)) }) }),
|
|
1596
|
+
/* @__PURE__ */ jsx4("div", { className: "ya-foot", children: /* @__PURE__ */ jsxs4("button", { type: "button", className: "ya-btn", onClick: () => setRoute({ view: "home", focus: true }), children: [
|
|
1597
|
+
/* @__PURE__ */ jsx4(IconPlus, {}),
|
|
1485
1598
|
"Request a feature"
|
|
1486
1599
|
] }) })
|
|
1487
1600
|
] });
|
|
1488
1601
|
}
|
|
1489
1602
|
|
|
1490
1603
|
// src/YouAsked.tsx
|
|
1491
|
-
import { Fragment as Fragment2, jsx as
|
|
1604
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1492
1605
|
var warnedTestMode = false;
|
|
1493
1606
|
var DEFAULT_API_URL = "https://api.youasked.dev";
|
|
1494
1607
|
function lastWhatsNew(key) {
|
|
@@ -1505,6 +1618,7 @@ function YouAsked({
|
|
|
1505
1618
|
appKey = "",
|
|
1506
1619
|
demo = false,
|
|
1507
1620
|
cards = true,
|
|
1621
|
+
nudge: nudgeProp,
|
|
1508
1622
|
user,
|
|
1509
1623
|
signature,
|
|
1510
1624
|
ready = true,
|
|
@@ -1528,26 +1642,36 @@ function YouAsked({
|
|
|
1528
1642
|
[demo, appName, appKey, apiUrl, userId, userEmail, userName, signature]
|
|
1529
1643
|
);
|
|
1530
1644
|
const whatsNewKey = demo ? null : `youasked:whats-new:${appKey}:${userId ?? "anon"}`;
|
|
1531
|
-
const [mounted, setMounted] =
|
|
1532
|
-
const [route, setRoute] =
|
|
1533
|
-
const [config, setConfig] =
|
|
1534
|
-
const [testMode, setTestMode] =
|
|
1535
|
-
const [whatsNew, setWhatsNew] =
|
|
1536
|
-
const [whatsNewToast, setWhatsNewToast] =
|
|
1537
|
-
const [capture, setCapture] =
|
|
1645
|
+
const [mounted, setMounted] = useState4(false);
|
|
1646
|
+
const [route, setRoute] = useState4(null);
|
|
1647
|
+
const [config, setConfig] = useState4(null);
|
|
1648
|
+
const [testMode, setTestMode] = useState4(false);
|
|
1649
|
+
const [whatsNew, setWhatsNew] = useState4(null);
|
|
1650
|
+
const [whatsNewToast, setWhatsNewToast] = useState4(false);
|
|
1651
|
+
const [capture, setCapture] = useState4(null);
|
|
1538
1652
|
const tokens = useTokens(appearance, mounted);
|
|
1539
|
-
const openerRef =
|
|
1540
|
-
const [detectedIcon, setDetectedIcon] =
|
|
1541
|
-
|
|
1653
|
+
const openerRef = useRef4(null);
|
|
1654
|
+
const [detectedIcon, setDetectedIcon] = useState4(null);
|
|
1655
|
+
useEffect4(() => {
|
|
1542
1656
|
if (appIcon === void 0) setDetectedIcon(findPageIcon());
|
|
1543
1657
|
}, [appIcon]);
|
|
1544
|
-
|
|
1658
|
+
useEffect4(() => {
|
|
1545
1659
|
injectStyles();
|
|
1546
1660
|
setMounted(true);
|
|
1547
1661
|
}, []);
|
|
1548
|
-
|
|
1662
|
+
const [refresh, setRefresh] = useState4(0);
|
|
1663
|
+
const lastLoad = useRef4(0);
|
|
1664
|
+
useEffect4(() => {
|
|
1665
|
+
const onVisible = () => {
|
|
1666
|
+
if (document.visibilityState === "visible" && Date.now() - lastLoad.current > 6e4) setRefresh((n) => n + 1);
|
|
1667
|
+
};
|
|
1668
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
1669
|
+
return () => document.removeEventListener("visibilitychange", onVisible);
|
|
1670
|
+
}, []);
|
|
1671
|
+
useEffect4(() => {
|
|
1549
1672
|
if (!ready) return;
|
|
1550
1673
|
let alive = true;
|
|
1674
|
+
lastLoad.current = Date.now();
|
|
1551
1675
|
client.config().then((c) => {
|
|
1552
1676
|
if (!alive) return;
|
|
1553
1677
|
const seenAt = lastWhatsNew(whatsNewKey);
|
|
@@ -1567,14 +1691,14 @@ function YouAsked({
|
|
|
1567
1691
|
return () => {
|
|
1568
1692
|
alive = false;
|
|
1569
1693
|
};
|
|
1570
|
-
}, [client, ready]);
|
|
1571
|
-
|
|
1694
|
+
}, [client, ready, refresh]);
|
|
1695
|
+
useEffect4(() => {
|
|
1572
1696
|
if (!("onNotice" in client)) return;
|
|
1573
1697
|
return client.onNotice(
|
|
1574
1698
|
(n) => setConfig((c) => c ? { ...c, unseen: [...c.unseen, n] } : c)
|
|
1575
1699
|
);
|
|
1576
1700
|
}, [client]);
|
|
1577
|
-
const dismissWhatsNew =
|
|
1701
|
+
const dismissWhatsNew = useCallback3(() => {
|
|
1578
1702
|
setWhatsNew(null);
|
|
1579
1703
|
setWhatsNewToast(false);
|
|
1580
1704
|
try {
|
|
@@ -1584,7 +1708,7 @@ function YouAsked({
|
|
|
1584
1708
|
client.whatsNewSeen().catch(() => {
|
|
1585
1709
|
});
|
|
1586
1710
|
}, [client, whatsNewKey]);
|
|
1587
|
-
const pointAtIt =
|
|
1711
|
+
const pointAtIt = useCallback3(
|
|
1588
1712
|
() => new Promise((resolve, reject) => {
|
|
1589
1713
|
import("./capture-FYZGL54F.js").then(
|
|
1590
1714
|
(m) => setCapture({ Layer: m.default, resolve }),
|
|
@@ -1593,20 +1717,20 @@ function YouAsked({
|
|
|
1593
1717
|
}),
|
|
1594
1718
|
[]
|
|
1595
1719
|
);
|
|
1596
|
-
const open =
|
|
1720
|
+
const open = useCallback3((options) => {
|
|
1597
1721
|
openerRef.current = document.activeElement;
|
|
1598
1722
|
setRoute(toRoute(options));
|
|
1599
1723
|
}, []);
|
|
1600
|
-
const close =
|
|
1724
|
+
const close = useCallback3(() => {
|
|
1601
1725
|
setRoute(null);
|
|
1602
1726
|
openerRef.current?.focus?.({ preventScroll: true });
|
|
1603
1727
|
}, []);
|
|
1604
|
-
|
|
1728
|
+
useEffect4(() => {
|
|
1605
1729
|
const onOpen = (e) => open(e.detail);
|
|
1606
1730
|
window.addEventListener("youasked:open", onOpen);
|
|
1607
1731
|
return () => window.removeEventListener("youasked:open", onOpen);
|
|
1608
1732
|
}, [open]);
|
|
1609
|
-
const markSeen =
|
|
1733
|
+
const markSeen = useCallback3(
|
|
1610
1734
|
(ids) => {
|
|
1611
1735
|
if (!ids.length) return;
|
|
1612
1736
|
setConfig((c) => c ? { ...c, unseen: c.unseen.filter((n) => !ids.includes(n.id)) } : c);
|
|
@@ -1645,12 +1769,22 @@ function YouAsked({
|
|
|
1645
1769
|
);
|
|
1646
1770
|
const standing = unseen.filter((n) => !coveredBy(whatsNew, n));
|
|
1647
1771
|
const notice = standing.find((n) => n.kind === "shipped") ?? standing.find((n) => n.kind === "reply");
|
|
1648
|
-
|
|
1649
|
-
|
|
1772
|
+
const nudgeSettings = useMemo(
|
|
1773
|
+
() => config && cards && !testMode ? resolveNudge(config.nudge, nudgeProp) : null,
|
|
1774
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1775
|
+
[Boolean(config), JSON.stringify(config?.nudge ?? null), cards, testMode, typeof nudgeProp === "object" ? JSON.stringify(nudgeProp) : nudgeProp]
|
|
1776
|
+
);
|
|
1777
|
+
const busy = route !== null || Boolean(notice) || whatsNewToast && Boolean(whatsNew);
|
|
1778
|
+
const nudge = useNudge(nudgeSettings, demo ? null : `youasked:nudge:${appKey}:${userId ?? "anon"}`, busy);
|
|
1779
|
+
useEffect4(() => {
|
|
1780
|
+
if (route !== null) nudge.engaged();
|
|
1781
|
+
}, [route, nudge.engaged]);
|
|
1782
|
+
if (testMode) return /* @__PURE__ */ jsx5(YouAskedContext.Provider, { value, children });
|
|
1783
|
+
return /* @__PURE__ */ jsxs5(YouAskedContext.Provider, { value, children: [
|
|
1650
1784
|
children,
|
|
1651
1785
|
mounted && createPortal(
|
|
1652
|
-
/* @__PURE__ */
|
|
1653
|
-
trigger === "floating" && !capture && /* @__PURE__ */
|
|
1786
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-scope", "data-ya-mode": tokens?.mode, "data-ya-skip": "", style: scopeStyle, children: [
|
|
1787
|
+
trigger === "floating" && !capture && /* @__PURE__ */ jsx5(
|
|
1654
1788
|
Launcher,
|
|
1655
1789
|
{
|
|
1656
1790
|
position,
|
|
@@ -1660,7 +1794,7 @@ function YouAsked({
|
|
|
1660
1794
|
onClick: () => route ? close() : open()
|
|
1661
1795
|
}
|
|
1662
1796
|
),
|
|
1663
|
-
cards && !notice && whatsNewToast && whatsNew && route === null && /* @__PURE__ */
|
|
1797
|
+
cards && !notice && whatsNewToast && whatsNew && route === null && /* @__PURE__ */ jsx5(
|
|
1664
1798
|
WhatsNewToast,
|
|
1665
1799
|
{
|
|
1666
1800
|
news: whatsNew,
|
|
@@ -1670,7 +1804,18 @@ function YouAsked({
|
|
|
1670
1804
|
onDismiss: dismissWhatsNew
|
|
1671
1805
|
}
|
|
1672
1806
|
),
|
|
1673
|
-
|
|
1807
|
+
nudgeSettings && nudge.show && !busy && /* @__PURE__ */ jsx5(
|
|
1808
|
+
NudgeToast,
|
|
1809
|
+
{
|
|
1810
|
+
settings: nudgeSettings,
|
|
1811
|
+
appName: appName ?? config?.app.name ?? "us",
|
|
1812
|
+
position,
|
|
1813
|
+
trigger,
|
|
1814
|
+
onOpen: () => open({ view: "new" }),
|
|
1815
|
+
onDismiss: nudge.dismiss
|
|
1816
|
+
}
|
|
1817
|
+
),
|
|
1818
|
+
cards && notice && route === null && /* @__PURE__ */ jsx5(
|
|
1674
1819
|
ShippedToast,
|
|
1675
1820
|
{
|
|
1676
1821
|
notice,
|
|
@@ -1683,7 +1828,7 @@ function YouAsked({
|
|
|
1683
1828
|
onDismiss: () => markSeen([notice.id])
|
|
1684
1829
|
}
|
|
1685
1830
|
),
|
|
1686
|
-
route && /* @__PURE__ */
|
|
1831
|
+
route && /* @__PURE__ */ jsx5(
|
|
1687
1832
|
Panel,
|
|
1688
1833
|
{
|
|
1689
1834
|
route,
|
|
@@ -1694,7 +1839,7 @@ function YouAsked({
|
|
|
1694
1839
|
hidden: capture !== null
|
|
1695
1840
|
}
|
|
1696
1841
|
),
|
|
1697
|
-
capture && /* @__PURE__ */
|
|
1842
|
+
capture && /* @__PURE__ */ jsx5(
|
|
1698
1843
|
capture.Layer,
|
|
1699
1844
|
{
|
|
1700
1845
|
onDone: (image) => {
|
|
@@ -1721,8 +1866,8 @@ function findPageIcon() {
|
|
|
1721
1866
|
}
|
|
1722
1867
|
function useTokens(appearance, mounted) {
|
|
1723
1868
|
const key = JSON.stringify(appearance ?? {});
|
|
1724
|
-
const [tokens, setTokens] =
|
|
1725
|
-
|
|
1869
|
+
const [tokens, setTokens] = useState4(null);
|
|
1870
|
+
useEffect4(() => {
|
|
1726
1871
|
if (!mounted) return;
|
|
1727
1872
|
const parsed = JSON.parse(key);
|
|
1728
1873
|
const update = () => setTokens(resolveTokens(parsed));
|
|
@@ -1757,20 +1902,20 @@ function Panel({
|
|
|
1757
1902
|
hasLauncher,
|
|
1758
1903
|
hidden
|
|
1759
1904
|
}) {
|
|
1760
|
-
const panelRef =
|
|
1761
|
-
const backdropRef =
|
|
1762
|
-
const [closing, setClosing] =
|
|
1905
|
+
const panelRef = useRef4(null);
|
|
1906
|
+
const backdropRef = useRef4(null);
|
|
1907
|
+
const [closing, setClosing] = useState4(false);
|
|
1763
1908
|
const isSheet = useMedia("(max-width: 639px)");
|
|
1764
1909
|
const reduceMotion = useMedia("(prefers-reduced-motion: reduce)");
|
|
1765
|
-
const hiddenRef =
|
|
1910
|
+
const hiddenRef = useRef4(hidden);
|
|
1766
1911
|
hiddenRef.current = hidden;
|
|
1767
|
-
const drag =
|
|
1768
|
-
const requestClose =
|
|
1912
|
+
const drag = useRef4(null);
|
|
1913
|
+
const requestClose = useCallback3(() => {
|
|
1769
1914
|
if (reduceMotion) return onClose();
|
|
1770
1915
|
setClosing(true);
|
|
1771
1916
|
setTimeout(onClose, 200);
|
|
1772
1917
|
}, [onClose, reduceMotion]);
|
|
1773
|
-
|
|
1918
|
+
useEffect4(() => {
|
|
1774
1919
|
if (!isSheet) return;
|
|
1775
1920
|
const html = document.documentElement;
|
|
1776
1921
|
const previous = html.style.overflow;
|
|
@@ -1779,10 +1924,10 @@ function Panel({
|
|
|
1779
1924
|
html.style.overflow = previous;
|
|
1780
1925
|
};
|
|
1781
1926
|
}, [isSheet]);
|
|
1782
|
-
|
|
1927
|
+
useEffect4(() => {
|
|
1783
1928
|
panelRef.current?.focus({ preventScroll: true });
|
|
1784
1929
|
}, []);
|
|
1785
|
-
|
|
1930
|
+
useEffect4(() => {
|
|
1786
1931
|
const onKey = (e) => {
|
|
1787
1932
|
if (hiddenRef.current) return;
|
|
1788
1933
|
if (e.key === "Escape") {
|
|
@@ -1836,7 +1981,7 @@ function Panel({
|
|
|
1836
1981
|
if (backdrop) backdrop.style.opacity = "";
|
|
1837
1982
|
}
|
|
1838
1983
|
};
|
|
1839
|
-
return /* @__PURE__ */
|
|
1984
|
+
return /* @__PURE__ */ jsxs5(
|
|
1840
1985
|
"div",
|
|
1841
1986
|
{
|
|
1842
1987
|
className: "ya-overlay",
|
|
@@ -1845,8 +1990,8 @@ function Panel({
|
|
|
1845
1990
|
"data-closing": closing || void 0,
|
|
1846
1991
|
hidden,
|
|
1847
1992
|
children: [
|
|
1848
|
-
/* @__PURE__ */
|
|
1849
|
-
/* @__PURE__ */
|
|
1993
|
+
/* @__PURE__ */ jsx5("div", { className: "ya-backdrop", ref: backdropRef, onClick: requestClose, "aria-hidden": "true" }),
|
|
1994
|
+
/* @__PURE__ */ jsxs5(
|
|
1850
1995
|
"div",
|
|
1851
1996
|
{
|
|
1852
1997
|
className: "ya-panel",
|
|
@@ -1860,8 +2005,8 @@ function Panel({
|
|
|
1860
2005
|
onPointerUp,
|
|
1861
2006
|
onPointerCancel: onPointerUp,
|
|
1862
2007
|
children: [
|
|
1863
|
-
/* @__PURE__ */
|
|
1864
|
-
/* @__PURE__ */
|
|
2008
|
+
/* @__PURE__ */ jsx5("div", { className: "ya-grab-zone", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("div", { className: "ya-grab" }) }),
|
|
2009
|
+
/* @__PURE__ */ jsx5(Navigator, { route, setRoute, onClose: requestClose })
|
|
1865
2010
|
]
|
|
1866
2011
|
}
|
|
1867
2012
|
)
|
|
@@ -1891,7 +2036,7 @@ function Launcher({
|
|
|
1891
2036
|
badge,
|
|
1892
2037
|
onClick
|
|
1893
2038
|
}) {
|
|
1894
|
-
return /* @__PURE__ */
|
|
2039
|
+
return /* @__PURE__ */ jsxs5(
|
|
1895
2040
|
"button",
|
|
1896
2041
|
{
|
|
1897
2042
|
type: "button",
|
|
@@ -1902,9 +2047,9 @@ function Launcher({
|
|
|
1902
2047
|
"aria-label": isOpen ? "Close feature requests" : label || "Feature requests",
|
|
1903
2048
|
"aria-expanded": isOpen,
|
|
1904
2049
|
children: [
|
|
1905
|
-
/* @__PURE__ */
|
|
1906
|
-
label && !isOpen && /* @__PURE__ */
|
|
1907
|
-
badge && !isOpen && /* @__PURE__ */
|
|
2050
|
+
/* @__PURE__ */ jsx5("span", { className: "ya-fab-icon", children: isOpen ? /* @__PURE__ */ jsx5(IconClose, {}) : /* @__PURE__ */ jsx5(IconIdea, { ink: "var(--_accent)" }) }),
|
|
2051
|
+
label && !isOpen && /* @__PURE__ */ jsx5("span", { children: label }),
|
|
2052
|
+
badge && !isOpen && /* @__PURE__ */ jsx5("span", { className: "ya-dot", "aria-hidden": "true" })
|
|
1908
2053
|
]
|
|
1909
2054
|
}
|
|
1910
2055
|
);
|
|
@@ -1916,18 +2061,18 @@ function ShippedToast({
|
|
|
1916
2061
|
onOpen,
|
|
1917
2062
|
onDismiss
|
|
1918
2063
|
}) {
|
|
1919
|
-
return /* @__PURE__ */
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
1922
|
-
/* @__PURE__ */
|
|
2064
|
+
return /* @__PURE__ */ jsx5("div", { className: "ya-toast", role: "status", "data-pos": position, "data-trigger": trigger, children: notice.kind === "reply" ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2065
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-toast-top", children: [
|
|
2066
|
+
/* @__PURE__ */ jsx5("p", { className: "ya-toast-kicker", children: "New reply about" }),
|
|
2067
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-icon-btn", onClick: onDismiss, "aria-label": "Dismiss", children: /* @__PURE__ */ jsx5(IconClose, {}) })
|
|
1923
2068
|
] }),
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
/* @__PURE__ */
|
|
1926
|
-
/* @__PURE__ */
|
|
1927
|
-
/* @__PURE__ */
|
|
1928
|
-
/* @__PURE__ */
|
|
2069
|
+
/* @__PURE__ */ jsx5("p", { className: "ya-toast-title", children: notice.title }),
|
|
2070
|
+
/* @__PURE__ */ jsx5("p", { className: "ya-toast-note ya-toast-quote", children: notice.reply }),
|
|
2071
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-toast-actions", children: [
|
|
2072
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-btn ya-btn-sm", onClick: onOpen, children: "Reply" }),
|
|
2073
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-btn ya-btn-sm ya-btn-ghost", onClick: onDismiss, children: "Later" })
|
|
1929
2074
|
] })
|
|
1930
|
-
] }) : /* @__PURE__ */
|
|
2075
|
+
] }) : /* @__PURE__ */ jsx5(ShippedBody, { notice, onOpen, onDismiss }) });
|
|
1931
2076
|
}
|
|
1932
2077
|
function WhatsNewToast({
|
|
1933
2078
|
news,
|
|
@@ -1937,44 +2082,44 @@ function WhatsNewToast({
|
|
|
1937
2082
|
onDismiss
|
|
1938
2083
|
}) {
|
|
1939
2084
|
const mine = news.items.some((i) => i.mine);
|
|
1940
|
-
return /* @__PURE__ */
|
|
1941
|
-
/* @__PURE__ */
|
|
1942
|
-
/* @__PURE__ */
|
|
1943
|
-
/* @__PURE__ */
|
|
2085
|
+
return /* @__PURE__ */ jsxs5("div", { className: "ya-toast", role: "status", "data-pos": position, "data-trigger": trigger, children: [
|
|
2086
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-toast-top", children: [
|
|
2087
|
+
/* @__PURE__ */ jsx5("p", { className: "ya-toast-kicker", children: "What's new" }),
|
|
2088
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-icon-btn", onClick: onDismiss, "aria-label": "Dismiss", children: /* @__PURE__ */ jsx5(IconClose, {}) })
|
|
1944
2089
|
] }),
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
mine && /* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
2090
|
+
/* @__PURE__ */ jsx5("p", { className: "ya-toast-title", children: whatsNewHeading(news.total) }),
|
|
2091
|
+
mine && /* @__PURE__ */ jsxs5("div", { className: "ya-live", children: [
|
|
2092
|
+
/* @__PURE__ */ jsx5(IconCheck, {}),
|
|
1948
2093
|
"Including something you asked for"
|
|
1949
2094
|
] }),
|
|
1950
|
-
/* @__PURE__ */
|
|
1951
|
-
/* @__PURE__ */
|
|
1952
|
-
/* @__PURE__ */
|
|
2095
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-toast-actions", children: [
|
|
2096
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-btn ya-btn-sm", onClick: onOpen, children: "See what's new" }),
|
|
2097
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-btn ya-btn-sm ya-btn-ghost", onClick: onDismiss, children: "Not now" })
|
|
1953
2098
|
] })
|
|
1954
2099
|
] });
|
|
1955
2100
|
}
|
|
1956
2101
|
function ShippedBody({ notice, onOpen, onDismiss }) {
|
|
1957
|
-
return /* @__PURE__ */
|
|
1958
|
-
/* @__PURE__ */
|
|
1959
|
-
/* @__PURE__ */
|
|
1960
|
-
/* @__PURE__ */
|
|
2102
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
2103
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-toast-top", children: [
|
|
2104
|
+
/* @__PURE__ */ jsx5("p", { className: "ya-toast-kicker", children: "You asked for" }),
|
|
2105
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-icon-btn", onClick: onDismiss, "aria-label": "Dismiss", children: /* @__PURE__ */ jsx5(IconClose, {}) })
|
|
1961
2106
|
] }),
|
|
1962
|
-
/* @__PURE__ */
|
|
1963
|
-
/* @__PURE__ */
|
|
1964
|
-
/* @__PURE__ */
|
|
2107
|
+
/* @__PURE__ */ jsx5("p", { className: "ya-toast-title", children: notice.title }),
|
|
2108
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-live", children: [
|
|
2109
|
+
/* @__PURE__ */ jsx5(IconCheck, {}),
|
|
1965
2110
|
"It's live"
|
|
1966
2111
|
] }),
|
|
1967
|
-
notice.shipNote && /* @__PURE__ */
|
|
1968
|
-
/* @__PURE__ */
|
|
1969
|
-
/* @__PURE__ */
|
|
1970
|
-
/* @__PURE__ */
|
|
2112
|
+
notice.shipNote && /* @__PURE__ */ jsx5("p", { className: "ya-toast-note", children: notice.shipNote }),
|
|
2113
|
+
/* @__PURE__ */ jsxs5("div", { className: "ya-toast-actions", children: [
|
|
2114
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-btn ya-btn-sm", onClick: onOpen, children: "See it" }),
|
|
2115
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: "ya-btn ya-btn-sm ya-btn-ghost", onClick: onDismiss, children: "Nice" })
|
|
1971
2116
|
] })
|
|
1972
2117
|
] });
|
|
1973
2118
|
}
|
|
1974
2119
|
|
|
1975
2120
|
// src/entries.tsx
|
|
1976
|
-
import { useState as
|
|
1977
|
-
import { jsx as
|
|
2121
|
+
import { useState as useState5 } from "react";
|
|
2122
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1978
2123
|
function useScope(className, style) {
|
|
1979
2124
|
const { scope } = useInternal();
|
|
1980
2125
|
return {
|
|
@@ -1985,11 +2130,11 @@ function useScope(className, style) {
|
|
|
1985
2130
|
}
|
|
1986
2131
|
function AskBar({ placeholder = "Ask for a feature\u2026", className, style }) {
|
|
1987
2132
|
const { open, appIcon, unseenCount } = useInternal();
|
|
1988
|
-
return /* @__PURE__ */
|
|
1989
|
-
appIcon ? /* @__PURE__ */
|
|
1990
|
-
/* @__PURE__ */
|
|
1991
|
-
unseenCount > 0 && /* @__PURE__ */
|
|
1992
|
-
/* @__PURE__ */
|
|
2133
|
+
return /* @__PURE__ */ jsx6("div", { ...useScope(className, style), children: /* @__PURE__ */ jsxs6("button", { type: "button", className: "ya-askbar", onClick: () => open({ view: "new" }), children: [
|
|
2134
|
+
appIcon ? /* @__PURE__ */ jsx6(AppAvatar, { icon: appIcon, size: 30 }) : /* @__PURE__ */ jsx6("span", { className: "ya-askbar-glyph", "aria-hidden": "true", children: /* @__PURE__ */ jsx6(IconIdea, {}) }),
|
|
2135
|
+
/* @__PURE__ */ jsx6("span", { className: "ya-askbar-text", children: placeholder }),
|
|
2136
|
+
unseenCount > 0 && /* @__PURE__ */ jsx6("span", { className: "ya-badge", children: unseenCount }),
|
|
2137
|
+
/* @__PURE__ */ jsx6("span", { className: "ya-askbar-send", "aria-hidden": "true", children: /* @__PURE__ */ jsx6(IconSend, {}) })
|
|
1993
2138
|
] }) });
|
|
1994
2139
|
}
|
|
1995
2140
|
function FeatureCard({
|
|
@@ -2002,15 +2147,15 @@ function FeatureCard({
|
|
|
2002
2147
|
const { client, open, config, markSeen } = useInternal();
|
|
2003
2148
|
const { data } = useLoad(() => client.list("top", "active"), [client]);
|
|
2004
2149
|
const notice = config?.unseen.find((n) => n.kind === "shipped");
|
|
2005
|
-
return /* @__PURE__ */
|
|
2006
|
-
/* @__PURE__ */
|
|
2007
|
-
/* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2009
|
-
/* @__PURE__ */
|
|
2010
|
-
/* @__PURE__ */
|
|
2150
|
+
return /* @__PURE__ */ jsx6("div", { ...useScope(className, style), children: /* @__PURE__ */ jsxs6("section", { className: "ya-card", children: [
|
|
2151
|
+
/* @__PURE__ */ jsxs6("div", { className: "ya-card-head", children: [
|
|
2152
|
+
/* @__PURE__ */ jsx6("span", { className: "ya-card-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx6(IconIdea, {}) }),
|
|
2153
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2154
|
+
/* @__PURE__ */ jsx6("h3", { className: "ya-card-title", children: heading }),
|
|
2155
|
+
/* @__PURE__ */ jsx6("p", { className: "ya-card-sub", children: description })
|
|
2011
2156
|
] })
|
|
2012
2157
|
] }),
|
|
2013
|
-
notice && /* @__PURE__ */
|
|
2158
|
+
notice && /* @__PURE__ */ jsxs6(
|
|
2014
2159
|
"button",
|
|
2015
2160
|
{
|
|
2016
2161
|
type: "button",
|
|
@@ -2020,20 +2165,20 @@ function FeatureCard({
|
|
|
2020
2165
|
open({ requestId: notice.requestId });
|
|
2021
2166
|
},
|
|
2022
2167
|
children: [
|
|
2023
|
-
/* @__PURE__ */
|
|
2024
|
-
/* @__PURE__ */
|
|
2168
|
+
/* @__PURE__ */ jsx6("span", { className: "ya-shipped-dot", children: /* @__PURE__ */ jsx6(IconCheck, {}) }),
|
|
2169
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
2025
2170
|
"You asked for ",
|
|
2026
|
-
/* @__PURE__ */
|
|
2171
|
+
/* @__PURE__ */ jsx6("b", { children: notice.title }),
|
|
2027
2172
|
". It's live."
|
|
2028
2173
|
] }),
|
|
2029
|
-
/* @__PURE__ */
|
|
2174
|
+
/* @__PURE__ */ jsx6(IconChevron, {})
|
|
2030
2175
|
]
|
|
2031
2176
|
}
|
|
2032
2177
|
),
|
|
2033
|
-
!data ? /* @__PURE__ */
|
|
2034
|
-
/* @__PURE__ */
|
|
2035
|
-
/* @__PURE__ */
|
|
2036
|
-
data && data.length > limit && /* @__PURE__ */
|
|
2178
|
+
!data ? /* @__PURE__ */ jsx6(Skeleton, { rows: 2 }) : data.length > 0 ? /* @__PURE__ */ jsx6("ul", { className: "ya-list", children: data.slice(0, limit).map((r) => /* @__PURE__ */ jsx6(RequestRow, { client, request: r, compact: true, onOpen: () => open({ requestId: r.id }) }, r.id)) }) : null,
|
|
2179
|
+
/* @__PURE__ */ jsxs6("div", { className: "ya-card-actions", children: [
|
|
2180
|
+
/* @__PURE__ */ jsx6("button", { type: "button", className: "ya-btn ya-btn-sm", onClick: () => open({ view: "new" }), children: "Suggest an idea" }),
|
|
2181
|
+
data && data.length > limit && /* @__PURE__ */ jsxs6("button", { type: "button", className: "ya-btn ya-btn-sm ya-btn-ghost", onClick: () => open({ view: "board" }), children: [
|
|
2037
2182
|
"See all ",
|
|
2038
2183
|
data.length
|
|
2039
2184
|
] })
|
|
@@ -2049,26 +2194,26 @@ function RequestButton({
|
|
|
2049
2194
|
}) {
|
|
2050
2195
|
const { open, unseenCount } = useInternal();
|
|
2051
2196
|
const scope = useScope(className, style);
|
|
2052
|
-
const badge = unseenCount > 0 && (variant === "icon" ? /* @__PURE__ */
|
|
2197
|
+
const badge = unseenCount > 0 && (variant === "icon" ? /* @__PURE__ */ jsx6("span", { className: "ya-dot", "aria-hidden": "true" }) : /* @__PURE__ */ jsx6("span", { className: "ya-badge", children: unseenCount }));
|
|
2053
2198
|
if (variant === "icon") {
|
|
2054
|
-
return /* @__PURE__ */
|
|
2055
|
-
/* @__PURE__ */
|
|
2199
|
+
return /* @__PURE__ */ jsx6("span", { ...scope, children: /* @__PURE__ */ jsxs6("button", { type: "button", className: "ya-iconbtn", onClick: () => open(), "aria-label": label, children: [
|
|
2200
|
+
/* @__PURE__ */ jsx6(IconIdea, {}),
|
|
2056
2201
|
badge
|
|
2057
2202
|
] }) });
|
|
2058
2203
|
}
|
|
2059
2204
|
if (variant === "row") {
|
|
2060
|
-
return /* @__PURE__ */
|
|
2061
|
-
/* @__PURE__ */
|
|
2062
|
-
/* @__PURE__ */
|
|
2063
|
-
/* @__PURE__ */
|
|
2064
|
-
sublabel && /* @__PURE__ */
|
|
2205
|
+
return /* @__PURE__ */ jsx6("div", { ...scope, children: /* @__PURE__ */ jsxs6("button", { type: "button", className: "ya-menurow", onClick: () => open(), children: [
|
|
2206
|
+
/* @__PURE__ */ jsx6("span", { className: "ya-card-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx6(IconIdea, {}) }),
|
|
2207
|
+
/* @__PURE__ */ jsxs6("span", { className: "ya-menurow-text", children: [
|
|
2208
|
+
/* @__PURE__ */ jsx6("span", { className: "ya-menurow-label", children: label }),
|
|
2209
|
+
sublabel && /* @__PURE__ */ jsx6("span", { className: "ya-menurow-sub", children: sublabel })
|
|
2065
2210
|
] }),
|
|
2066
2211
|
badge,
|
|
2067
|
-
/* @__PURE__ */
|
|
2212
|
+
/* @__PURE__ */ jsx6(IconChevron, {})
|
|
2068
2213
|
] }) });
|
|
2069
2214
|
}
|
|
2070
|
-
return /* @__PURE__ */
|
|
2071
|
-
/* @__PURE__ */
|
|
2215
|
+
return /* @__PURE__ */ jsx6("span", { ...scope, children: /* @__PURE__ */ jsxs6("button", { type: "button", className: "ya-pillbtn", onClick: () => open(), children: [
|
|
2216
|
+
/* @__PURE__ */ jsx6(IconIdea, {}),
|
|
2072
2217
|
label,
|
|
2073
2218
|
badge
|
|
2074
2219
|
] }) });
|
|
@@ -2080,8 +2225,8 @@ function AskAbout({
|
|
|
2080
2225
|
style
|
|
2081
2226
|
}) {
|
|
2082
2227
|
const { open } = useInternal();
|
|
2083
|
-
return /* @__PURE__ */
|
|
2084
|
-
/* @__PURE__ */
|
|
2228
|
+
return /* @__PURE__ */ jsx6("span", { ...useScope(className, style), children: /* @__PURE__ */ jsxs6("button", { type: "button", className: "ya-askabout", onClick: () => open({ view: "new", topic }), children: [
|
|
2229
|
+
/* @__PURE__ */ jsx6(IconIdea, {}),
|
|
2085
2230
|
prompt ?? `Want more from ${topic}?`
|
|
2086
2231
|
] }) });
|
|
2087
2232
|
}
|
|
@@ -2089,11 +2234,11 @@ function AskForIt({ query, className, style }) {
|
|
|
2089
2234
|
const { open } = useInternal();
|
|
2090
2235
|
const q = query.trim();
|
|
2091
2236
|
const shown = q.length > 40 ? `${q.slice(0, 39).trimEnd()}\u2026` : q;
|
|
2092
|
-
return /* @__PURE__ */
|
|
2093
|
-
/* @__PURE__ */
|
|
2094
|
-
/* @__PURE__ */
|
|
2237
|
+
return /* @__PURE__ */ jsx6("span", { ...useScope(className, style), children: /* @__PURE__ */ jsxs6("button", { type: "button", className: "ya-askforit", onClick: () => open({ view: "new", draft: q, topic: "search" }), children: [
|
|
2238
|
+
/* @__PURE__ */ jsx6("span", { children: shown ? `Can't find \u201C${shown}\u201D?` : "Can't find it?" }),
|
|
2239
|
+
/* @__PURE__ */ jsxs6("b", { children: [
|
|
2095
2240
|
"Ask for it",
|
|
2096
|
-
/* @__PURE__ */
|
|
2241
|
+
/* @__PURE__ */ jsx6(IconChevron, {})
|
|
2097
2242
|
] })
|
|
2098
2243
|
] }) });
|
|
2099
2244
|
}
|
|
@@ -2103,8 +2248,8 @@ function FeatureBoard({
|
|
|
2103
2248
|
className,
|
|
2104
2249
|
style
|
|
2105
2250
|
}) {
|
|
2106
|
-
const [route, setRoute] =
|
|
2107
|
-
return /* @__PURE__ */
|
|
2251
|
+
const [route, setRoute] = useState5(start === "board" ? { view: "board" } : { view: "home" });
|
|
2252
|
+
return /* @__PURE__ */ jsx6("div", { ...useScope(className, style), children: /* @__PURE__ */ jsx6("div", { className: "ya-embed", style: { height }, children: /* @__PURE__ */ jsx6(Navigator, { route, setRoute }) }) });
|
|
2108
2253
|
}
|
|
2109
2254
|
export {
|
|
2110
2255
|
AskAbout,
|