@flytedan/flytebot-design-system 0.19.0 → 0.20.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 +892 -698
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -1
- package/dist/index.d.ts +54 -1
- package/dist/index.js +891 -698
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -146,6 +146,7 @@ __export(index_exports, {
|
|
|
146
146
|
SessionKit: () => SessionKit,
|
|
147
147
|
SessionProvider: () => SessionProvider,
|
|
148
148
|
SidebarNav: () => SidebarNav,
|
|
149
|
+
SignInPage: () => SignInPage,
|
|
149
150
|
Skeleton: () => Skeleton,
|
|
150
151
|
SkeletonText: () => SkeletonText,
|
|
151
152
|
Slider: () => Slider,
|
|
@@ -6608,11 +6609,203 @@ function ProfilePage({
|
|
|
6608
6609
|
] });
|
|
6609
6610
|
}
|
|
6610
6611
|
|
|
6612
|
+
// src/components/platform/SignInPage.tsx
|
|
6613
|
+
var React42 = __toESM(require("react"), 1);
|
|
6614
|
+
var import_jsx_runtime68 = require("react/jsx-runtime");
|
|
6615
|
+
function SignInPage({ productName, onSignIn, continueAs }) {
|
|
6616
|
+
const [signingIn, setSigningIn] = React42.useState(false);
|
|
6617
|
+
const [resuming, setResuming] = React42.useState(false);
|
|
6618
|
+
function handleSignIn() {
|
|
6619
|
+
setSigningIn(true);
|
|
6620
|
+
onSignIn();
|
|
6621
|
+
}
|
|
6622
|
+
function handleContinue() {
|
|
6623
|
+
setResuming(true);
|
|
6624
|
+
continueAs.onContinue().finally(() => setResuming(false));
|
|
6625
|
+
}
|
|
6626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6627
|
+
"div",
|
|
6628
|
+
{
|
|
6629
|
+
style: {
|
|
6630
|
+
position: "relative",
|
|
6631
|
+
display: "grid",
|
|
6632
|
+
placeItems: "center",
|
|
6633
|
+
minHeight: "100vh",
|
|
6634
|
+
padding: "24px 16px",
|
|
6635
|
+
boxSizing: "border-box",
|
|
6636
|
+
overflow: "hidden",
|
|
6637
|
+
background: "radial-gradient(circle at 15% 15%, var(--blue-700) 0%, transparent 45%), radial-gradient(circle at 85% 85%, var(--blue-600) 0%, transparent 40%), linear-gradient(160deg, var(--navy) 0%, var(--blue-950) 55%, var(--blue-900) 100%)"
|
|
6638
|
+
},
|
|
6639
|
+
children: [
|
|
6640
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6641
|
+
"div",
|
|
6642
|
+
{
|
|
6643
|
+
"aria-hidden": true,
|
|
6644
|
+
style: {
|
|
6645
|
+
position: "absolute",
|
|
6646
|
+
inset: 0,
|
|
6647
|
+
backgroundImage: "linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px)",
|
|
6648
|
+
backgroundSize: "48px 48px",
|
|
6649
|
+
maskImage: "radial-gradient(circle at 50% 40%, black, transparent 70%)"
|
|
6650
|
+
}
|
|
6651
|
+
}
|
|
6652
|
+
),
|
|
6653
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6654
|
+
"div",
|
|
6655
|
+
{
|
|
6656
|
+
style: {
|
|
6657
|
+
position: "relative",
|
|
6658
|
+
width: "100%",
|
|
6659
|
+
maxWidth: 408,
|
|
6660
|
+
display: "flex",
|
|
6661
|
+
flexDirection: "column",
|
|
6662
|
+
alignItems: "center"
|
|
6663
|
+
},
|
|
6664
|
+
children: [
|
|
6665
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { style: { marginBottom: "var(--s-32)" }, "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(FlytedeskMark, { size: "lg" }) }),
|
|
6666
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6667
|
+
"div",
|
|
6668
|
+
{
|
|
6669
|
+
style: {
|
|
6670
|
+
width: "100%",
|
|
6671
|
+
borderRadius: "var(--r-2xl)",
|
|
6672
|
+
overflow: "hidden",
|
|
6673
|
+
boxShadow: "0 24px 64px -12px rgba(2, 8, 20, 0.55), 0 2px 8px rgba(2, 8, 20, 0.3)"
|
|
6674
|
+
},
|
|
6675
|
+
children: [
|
|
6676
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6677
|
+
"div",
|
|
6678
|
+
{
|
|
6679
|
+
style: {
|
|
6680
|
+
height: 4,
|
|
6681
|
+
background: "linear-gradient(90deg, var(--blue-400), var(--blue-600), var(--navy))"
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
),
|
|
6685
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6686
|
+
"div",
|
|
6687
|
+
{
|
|
6688
|
+
style: {
|
|
6689
|
+
display: "flex",
|
|
6690
|
+
flexDirection: "column",
|
|
6691
|
+
gap: "var(--s-20)",
|
|
6692
|
+
alignItems: "center",
|
|
6693
|
+
textAlign: "center",
|
|
6694
|
+
padding: "var(--s-8) 0"
|
|
6695
|
+
},
|
|
6696
|
+
children: [
|
|
6697
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { children: [
|
|
6698
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("h1", { className: "fd-h3", style: { color: "var(--navy)" }, children: productName }),
|
|
6699
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-muted", style: { marginTop: "var(--s-4)" }, children: continueAs ? "Your session timed out, but you're likely still signed in" : "Sign in with your flytedesk workspace account" })
|
|
6700
|
+
] }),
|
|
6701
|
+
continueAs ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
|
|
6702
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6703
|
+
Button,
|
|
6704
|
+
{
|
|
6705
|
+
variant: "primary",
|
|
6706
|
+
style: { width: "100%" },
|
|
6707
|
+
loading: resuming,
|
|
6708
|
+
disabled: resuming,
|
|
6709
|
+
onClick: handleContinue,
|
|
6710
|
+
children: resuming ? "Resuming\u2026" : `Continue as ${continueAs.name}`
|
|
6711
|
+
}
|
|
6712
|
+
),
|
|
6713
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6714
|
+
"button",
|
|
6715
|
+
{
|
|
6716
|
+
type: "button",
|
|
6717
|
+
className: "fd-body-sm fd-muted",
|
|
6718
|
+
style: {
|
|
6719
|
+
background: "none",
|
|
6720
|
+
border: "none",
|
|
6721
|
+
cursor: "pointer",
|
|
6722
|
+
textDecoration: "underline",
|
|
6723
|
+
padding: 0
|
|
6724
|
+
},
|
|
6725
|
+
disabled: resuming,
|
|
6726
|
+
onClick: continueAs.onDecline,
|
|
6727
|
+
children: "Not you? Sign in with flytedesk ID"
|
|
6728
|
+
}
|
|
6729
|
+
)
|
|
6730
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6731
|
+
Button,
|
|
6732
|
+
{
|
|
6733
|
+
variant: "primary",
|
|
6734
|
+
style: { width: "100%" },
|
|
6735
|
+
loading: signingIn,
|
|
6736
|
+
disabled: signingIn,
|
|
6737
|
+
onClick: handleSignIn,
|
|
6738
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6739
|
+
"span",
|
|
6740
|
+
{
|
|
6741
|
+
style: {
|
|
6742
|
+
display: "flex",
|
|
6743
|
+
flexDirection: "row",
|
|
6744
|
+
alignItems: "center",
|
|
6745
|
+
justifyContent: "center",
|
|
6746
|
+
gap: "var(--s-8)",
|
|
6747
|
+
flexWrap: "nowrap"
|
|
6748
|
+
},
|
|
6749
|
+
children: [
|
|
6750
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(GoogleGlyph, {}),
|
|
6751
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { children: signingIn ? "Signing in\u2026" : "Sign in with flytedesk ID" })
|
|
6752
|
+
]
|
|
6753
|
+
}
|
|
6754
|
+
)
|
|
6755
|
+
}
|
|
6756
|
+
),
|
|
6757
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-muted", style: { fontSize: "12px" }, children: "One account, every flytedesk app." })
|
|
6758
|
+
]
|
|
6759
|
+
}
|
|
6760
|
+
) })
|
|
6761
|
+
]
|
|
6762
|
+
}
|
|
6763
|
+
)
|
|
6764
|
+
]
|
|
6765
|
+
}
|
|
6766
|
+
)
|
|
6767
|
+
]
|
|
6768
|
+
}
|
|
6769
|
+
);
|
|
6770
|
+
}
|
|
6771
|
+
function GoogleGlyph() {
|
|
6772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", "aria-hidden": true, children: [
|
|
6773
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6774
|
+
"path",
|
|
6775
|
+
{
|
|
6776
|
+
fill: "#4285F4",
|
|
6777
|
+
d: "M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.87 2.68-6.62Z"
|
|
6778
|
+
}
|
|
6779
|
+
),
|
|
6780
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6781
|
+
"path",
|
|
6782
|
+
{
|
|
6783
|
+
fill: "#34A853",
|
|
6784
|
+
d: "M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.81.54-1.84.87-3.04.87-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18Z"
|
|
6785
|
+
}
|
|
6786
|
+
),
|
|
6787
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6788
|
+
"path",
|
|
6789
|
+
{
|
|
6790
|
+
fill: "#FBBC05",
|
|
6791
|
+
d: "M3.97 10.73A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.19.29-1.73V4.94H.96A9 9 0 0 0 0 9c0 1.45.35 2.83.96 4.06l3.01-2.33Z"
|
|
6792
|
+
}
|
|
6793
|
+
),
|
|
6794
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6795
|
+
"path",
|
|
6796
|
+
{
|
|
6797
|
+
fill: "#EA4335",
|
|
6798
|
+
d: "M9 3.58c1.32 0 2.51.45 3.44 1.35l2.59-2.59C13.46.89 11.43 0 9 0A9 9 0 0 0 .96 4.94l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58Z"
|
|
6799
|
+
}
|
|
6800
|
+
)
|
|
6801
|
+
] });
|
|
6802
|
+
}
|
|
6803
|
+
|
|
6611
6804
|
// src/components/platform/RoadmapTimeline.tsx
|
|
6612
|
-
var
|
|
6805
|
+
var React45 = __toESM(require("react"), 1);
|
|
6613
6806
|
|
|
6614
6807
|
// src/kits/session.ts
|
|
6615
|
-
var
|
|
6808
|
+
var React43 = __toESM(require("react"), 1);
|
|
6616
6809
|
var PERMISSION_CATALOG = [
|
|
6617
6810
|
{ group: "Plans", items: [
|
|
6618
6811
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -8179,8 +8372,8 @@ function roadmap(overrides) {
|
|
|
8179
8372
|
};
|
|
8180
8373
|
}
|
|
8181
8374
|
function useSession() {
|
|
8182
|
-
const [s, setS] =
|
|
8183
|
-
|
|
8375
|
+
const [s, setS] = React43.useState(getSession);
|
|
8376
|
+
React43.useEffect(() => subscribe(setS), []);
|
|
8184
8377
|
return s;
|
|
8185
8378
|
}
|
|
8186
8379
|
var SessionKit = {
|
|
@@ -8213,7 +8406,7 @@ var SessionKit = {
|
|
|
8213
8406
|
};
|
|
8214
8407
|
function DemoSessionProvider({ children }) {
|
|
8215
8408
|
const session = useSession();
|
|
8216
|
-
const value =
|
|
8409
|
+
const value = React43.useMemo(
|
|
8217
8410
|
() => ({
|
|
8218
8411
|
user: session.user,
|
|
8219
8412
|
roles: session.roles,
|
|
@@ -8229,11 +8422,11 @@ function DemoSessionProvider({ children }) {
|
|
|
8229
8422
|
}),
|
|
8230
8423
|
[session]
|
|
8231
8424
|
);
|
|
8232
|
-
return
|
|
8425
|
+
return React43.createElement(SessionProvider, { value }, children);
|
|
8233
8426
|
}
|
|
8234
8427
|
|
|
8235
8428
|
// src/kits/runtime.ts
|
|
8236
|
-
var
|
|
8429
|
+
var React44 = __toESM(require("react"), 1);
|
|
8237
8430
|
var WIRED_ENDPOINTS = [
|
|
8238
8431
|
// Nothing yet. Every id below would come from a real service:
|
|
8239
8432
|
// "plan.get", "placements.list", …
|
|
@@ -8404,8 +8597,8 @@ var RuntimeKit = {
|
|
|
8404
8597
|
};
|
|
8405
8598
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
8406
8599
|
function useRuntimeMode() {
|
|
8407
|
-
const [m, setM] =
|
|
8408
|
-
|
|
8600
|
+
const [m, setM] = React44.useState(RuntimeKit.getMode());
|
|
8601
|
+
React44.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
8409
8602
|
return m;
|
|
8410
8603
|
}
|
|
8411
8604
|
function useFeatureStatus(key) {
|
|
@@ -8424,7 +8617,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
8424
8617
|
var UseFeatureStatus = useFeatureStatus;
|
|
8425
8618
|
|
|
8426
8619
|
// src/components/platform/RoadmapTimeline.tsx
|
|
8427
|
-
var
|
|
8620
|
+
var import_jsx_runtime69 = require("react/jsx-runtime");
|
|
8428
8621
|
var STATUS = {
|
|
8429
8622
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
8430
8623
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -8439,45 +8632,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
8439
8632
|
const s = STATUS[item.status] || STATUS.planned;
|
|
8440
8633
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
8441
8634
|
const blocking = deps.filter((d) => !d.implemented);
|
|
8442
|
-
return /* @__PURE__ */ (0,
|
|
8443
|
-
/* @__PURE__ */ (0,
|
|
8444
|
-
/* @__PURE__ */ (0,
|
|
8445
|
-
/* @__PURE__ */ (0,
|
|
8446
|
-
/* @__PURE__ */ (0,
|
|
8635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8636
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
8637
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
|
|
8638
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
|
|
8639
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
|
|
8447
8640
|
] }),
|
|
8448
|
-
/* @__PURE__ */ (0,
|
|
8449
|
-
item.backend ? /* @__PURE__ */ (0,
|
|
8450
|
-
/* @__PURE__ */ (0,
|
|
8451
|
-
/* @__PURE__ */ (0,
|
|
8641
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
|
|
8642
|
+
item.backend ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
|
|
8643
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
|
|
8644
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
|
|
8452
8645
|
] }) : null,
|
|
8453
|
-
/* @__PURE__ */ (0,
|
|
8454
|
-
item.effort ? /* @__PURE__ */ (0,
|
|
8455
|
-
/* @__PURE__ */ (0,
|
|
8646
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8647
|
+
item.effort ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
8648
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-hourglass-medium" }),
|
|
8456
8649
|
" ",
|
|
8457
8650
|
item.effort
|
|
8458
8651
|
] }) : null,
|
|
8459
|
-
/* @__PURE__ */ (0,
|
|
8460
|
-
/* @__PURE__ */ (0,
|
|
8652
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
8653
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-user" }),
|
|
8461
8654
|
" ",
|
|
8462
8655
|
item.owner
|
|
8463
8656
|
] }),
|
|
8464
|
-
item.screen ? /* @__PURE__ */ (0,
|
|
8465
|
-
/* @__PURE__ */ (0,
|
|
8466
|
-
/* @__PURE__ */ (0,
|
|
8657
|
+
item.screen ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
8658
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { flex: 1 } }),
|
|
8659
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
8467
8660
|
"button",
|
|
8468
8661
|
{
|
|
8469
8662
|
type: "button",
|
|
8470
8663
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
8471
8664
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
8472
|
-
children: /* @__PURE__ */ (0,
|
|
8665
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
8473
8666
|
}
|
|
8474
8667
|
)
|
|
8475
8668
|
] }),
|
|
8476
|
-
deps.length ? /* @__PURE__ */ (0,
|
|
8477
|
-
/* @__PURE__ */ (0,
|
|
8478
|
-
deps.map((d) => /* @__PURE__ */ (0,
|
|
8669
|
+
deps.length ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
|
|
8670
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
|
|
8671
|
+
deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
|
|
8479
8672
|
] }) : null,
|
|
8480
|
-
blocking.length && !item.implemented ? /* @__PURE__ */ (0,
|
|
8673
|
+
blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
8481
8674
|
"Blocked until ",
|
|
8482
8675
|
blocking.map((d) => d.label).join(" and "),
|
|
8483
8676
|
" ",
|
|
@@ -8488,12 +8681,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
8488
8681
|
}
|
|
8489
8682
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
8490
8683
|
const session = SessionKit.useSession();
|
|
8491
|
-
const [project, setProject] =
|
|
8492
|
-
const [q, setQ] =
|
|
8493
|
-
const scrollRef =
|
|
8494
|
-
const nowRef =
|
|
8495
|
-
const rm =
|
|
8496
|
-
const byKey =
|
|
8684
|
+
const [project, setProject] = React45.useState("");
|
|
8685
|
+
const [q, setQ] = React45.useState("");
|
|
8686
|
+
const scrollRef = React45.useRef(null);
|
|
8687
|
+
const nowRef = React45.useRef(null);
|
|
8688
|
+
const rm = React45.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
8689
|
+
const byKey = React45.useMemo(() => {
|
|
8497
8690
|
const m = {};
|
|
8498
8691
|
rm.items.forEach((i) => {
|
|
8499
8692
|
m[i.key] = i;
|
|
@@ -8502,7 +8695,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8502
8695
|
}, [rm]);
|
|
8503
8696
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
8504
8697
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
8505
|
-
|
|
8698
|
+
React45.useEffect(() => {
|
|
8506
8699
|
let raf1 = 0, raf2 = 0;
|
|
8507
8700
|
const place = () => {
|
|
8508
8701
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -8530,23 +8723,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8530
8723
|
}, 0);
|
|
8531
8724
|
const nextPhase = items.find((i) => !i.implemented);
|
|
8532
8725
|
let lastPhase = null;
|
|
8533
|
-
return /* @__PURE__ */ (0,
|
|
8534
|
-
/* @__PURE__ */ (0,
|
|
8535
|
-
/* @__PURE__ */ (0,
|
|
8536
|
-
/* @__PURE__ */ (0,
|
|
8537
|
-
/* @__PURE__ */ (0,
|
|
8726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
|
|
8727
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8728
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
|
|
8729
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
8730
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
|
|
8538
8731
|
] }),
|
|
8539
|
-
/* @__PURE__ */ (0,
|
|
8540
|
-
/* @__PURE__ */ (0,
|
|
8541
|
-
/* @__PURE__ */ (0,
|
|
8542
|
-
/* @__PURE__ */ (0,
|
|
8543
|
-
/* @__PURE__ */ (0,
|
|
8732
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
|
|
8733
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
|
|
8734
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
|
|
8735
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
|
|
8736
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
|
|
8544
8737
|
] }),
|
|
8545
|
-
/* @__PURE__ */ (0,
|
|
8546
|
-
/* @__PURE__ */ (0,
|
|
8547
|
-
/* @__PURE__ */ (0,
|
|
8548
|
-
/* @__PURE__ */ (0,
|
|
8549
|
-
/* @__PURE__ */ (0,
|
|
8738
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
8739
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
|
|
8740
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
|
|
8741
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { flex: 1 } }),
|
|
8742
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
8550
8743
|
Button,
|
|
8551
8744
|
{
|
|
8552
8745
|
size: "sm",
|
|
@@ -8560,7 +8753,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8560
8753
|
}
|
|
8561
8754
|
)
|
|
8562
8755
|
] }),
|
|
8563
|
-
/* @__PURE__ */ (0,
|
|
8756
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
8564
8757
|
Flag,
|
|
8565
8758
|
{
|
|
8566
8759
|
tone: "info",
|
|
@@ -8569,60 +8762,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8569
8762
|
actions: null
|
|
8570
8763
|
}
|
|
8571
8764
|
),
|
|
8572
|
-
/* @__PURE__ */ (0,
|
|
8573
|
-
/* @__PURE__ */ (0,
|
|
8765
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-track", children: [
|
|
8766
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
|
|
8574
8767
|
items.map((item, n) => {
|
|
8575
8768
|
const showPhase = item.phase !== lastPhase;
|
|
8576
8769
|
lastPhase = item.phase;
|
|
8577
8770
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
8578
8771
|
const isBoundary = n === firstPending;
|
|
8579
|
-
return /* @__PURE__ */ (0,
|
|
8580
|
-
showPhase ? /* @__PURE__ */ (0,
|
|
8581
|
-
/* @__PURE__ */ (0,
|
|
8582
|
-
/* @__PURE__ */ (0,
|
|
8583
|
-
item.phase === 0 ? null : /* @__PURE__ */ (0,
|
|
8772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(React45.Fragment, { children: [
|
|
8773
|
+
showPhase ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-era", children: [
|
|
8774
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
8775
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
8776
|
+
item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
8584
8777
|
fmtDate(item.phaseStart),
|
|
8585
8778
|
" \u2013 ",
|
|
8586
8779
|
fmtDate(item.date)
|
|
8587
8780
|
] }),
|
|
8588
|
-
/* @__PURE__ */ (0,
|
|
8781
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
8589
8782
|
"\xB7 ",
|
|
8590
8783
|
inPhase,
|
|
8591
8784
|
" feature",
|
|
8592
8785
|
inPhase === 1 ? "" : "s"
|
|
8593
8786
|
] })
|
|
8594
8787
|
] }),
|
|
8595
|
-
item.phaseWhy ? /* @__PURE__ */ (0,
|
|
8788
|
+
item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
8596
8789
|
] }) : null,
|
|
8597
|
-
isBoundary ? /* @__PURE__ */ (0,
|
|
8598
|
-
/* @__PURE__ */ (0,
|
|
8790
|
+
isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-rm-now-pill", children: [
|
|
8791
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-map-pin" }),
|
|
8599
8792
|
" You are here \u2014 everything above is wired"
|
|
8600
8793
|
] }) }) : null,
|
|
8601
|
-
/* @__PURE__ */ (0,
|
|
8602
|
-
/* @__PURE__ */ (0,
|
|
8603
|
-
/* @__PURE__ */ (0,
|
|
8794
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-row", children: [
|
|
8795
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
|
|
8796
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-date", children: [
|
|
8604
8797
|
fmtDate(item.date),
|
|
8605
|
-
/* @__PURE__ */ (0,
|
|
8606
|
-
/* @__PURE__ */ (0,
|
|
8798
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("br", {}),
|
|
8799
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
8607
8800
|
] }),
|
|
8608
|
-
/* @__PURE__ */ (0,
|
|
8801
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
|
|
8609
8802
|
] })
|
|
8610
8803
|
] }, item.key);
|
|
8611
8804
|
}),
|
|
8612
|
-
!items.length ? /* @__PURE__ */ (0,
|
|
8805
|
+
!items.length ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
8613
8806
|
] }) }) }),
|
|
8614
|
-
/* @__PURE__ */ (0,
|
|
8807
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
8615
8808
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
8616
|
-
/* @__PURE__ */ (0,
|
|
8809
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("code", { className: "fd-mono", children: "implemented" }),
|
|
8617
8810
|
" field, so this page cannot drift from what the apps actually do."
|
|
8618
8811
|
] })
|
|
8619
8812
|
] });
|
|
8620
8813
|
}
|
|
8621
8814
|
|
|
8622
8815
|
// src/components/platform/ComingSoon.tsx
|
|
8623
|
-
var
|
|
8816
|
+
var React46 = __toESM(require("react"), 1);
|
|
8624
8817
|
var import_react_dom6 = require("react-dom");
|
|
8625
|
-
var
|
|
8818
|
+
var import_jsx_runtime70 = require("react/jsx-runtime");
|
|
8626
8819
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
8627
8820
|
function readBypassed() {
|
|
8628
8821
|
try {
|
|
@@ -8638,8 +8831,8 @@ function writeBypassed(list) {
|
|
|
8638
8831
|
}
|
|
8639
8832
|
}
|
|
8640
8833
|
function useBypass(key) {
|
|
8641
|
-
const [on, setOn] =
|
|
8642
|
-
|
|
8834
|
+
const [on, setOn] = React46.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
8835
|
+
React46.useEffect(() => {
|
|
8643
8836
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
8644
8837
|
}, [key]);
|
|
8645
8838
|
const set = (next) => {
|
|
@@ -8652,43 +8845,43 @@ function useBypass(key) {
|
|
|
8652
8845
|
return [on, set];
|
|
8653
8846
|
}
|
|
8654
8847
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
8655
|
-
return /* @__PURE__ */ (0,
|
|
8656
|
-
/* @__PURE__ */ (0,
|
|
8657
|
-
/* @__PURE__ */ (0,
|
|
8848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(import_jsx_runtime70.Fragment, { children: [
|
|
8849
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-badge", children: [
|
|
8850
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
8658
8851
|
label
|
|
8659
8852
|
] }),
|
|
8660
|
-
detail ? /* @__PURE__ */ (0,
|
|
8661
|
-
backend ? /* @__PURE__ */ (0,
|
|
8662
|
-
/* @__PURE__ */ (0,
|
|
8853
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
|
|
8854
|
+
backend ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-backend", children: [
|
|
8855
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-overline", children: "Needs" }),
|
|
8663
8856
|
" ",
|
|
8664
8857
|
backend
|
|
8665
8858
|
] }) : null,
|
|
8666
|
-
eta || effort || onRoadmap ? /* @__PURE__ */ (0,
|
|
8667
|
-
eta ? /* @__PURE__ */ (0,
|
|
8668
|
-
/* @__PURE__ */ (0,
|
|
8859
|
+
eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-meta", children: [
|
|
8860
|
+
eta ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
|
|
8861
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
|
|
8669
8862
|
" ",
|
|
8670
8863
|
eta
|
|
8671
8864
|
] }) : null,
|
|
8672
|
-
effort ? /* @__PURE__ */ (0,
|
|
8673
|
-
/* @__PURE__ */ (0,
|
|
8865
|
+
effort ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
|
|
8866
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
8674
8867
|
" ",
|
|
8675
8868
|
effort
|
|
8676
8869
|
] }) : null,
|
|
8677
|
-
onRoadmap ? /* @__PURE__ */ (0,
|
|
8870
|
+
onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
8678
8871
|
"See the roadmap ",
|
|
8679
|
-
/* @__PURE__ */ (0,
|
|
8872
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
8680
8873
|
] }) : null
|
|
8681
8874
|
] }) : null,
|
|
8682
|
-
allowed ? /* @__PURE__ */ (0,
|
|
8683
|
-
/* @__PURE__ */ (0,
|
|
8875
|
+
allowed ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
|
|
8876
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
|
|
8684
8877
|
" View and use it anyway"
|
|
8685
8878
|
] }) : null
|
|
8686
8879
|
] });
|
|
8687
8880
|
}
|
|
8688
8881
|
function useHoverCard(open) {
|
|
8689
|
-
const anchor =
|
|
8690
|
-
const [pos, setPos] =
|
|
8691
|
-
|
|
8882
|
+
const anchor = React46.useRef(null);
|
|
8883
|
+
const [pos, setPos] = React46.useState(null);
|
|
8884
|
+
React46.useLayoutEffect(() => {
|
|
8692
8885
|
if (!open || !anchor.current) {
|
|
8693
8886
|
setPos(null);
|
|
8694
8887
|
return;
|
|
@@ -8740,9 +8933,9 @@ function ComingSoon({
|
|
|
8740
8933
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
8741
8934
|
if (inline) {
|
|
8742
8935
|
if (allowed && bypassed) {
|
|
8743
|
-
return /* @__PURE__ */ (0,
|
|
8936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
8744
8937
|
children,
|
|
8745
|
-
/* @__PURE__ */ (0,
|
|
8938
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8746
8939
|
"button",
|
|
8747
8940
|
{
|
|
8748
8941
|
type: "button",
|
|
@@ -8750,12 +8943,12 @@ function ComingSoon({
|
|
|
8750
8943
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
8751
8944
|
onClick: () => setBypassed(false),
|
|
8752
8945
|
"aria-label": "Re-blur this unwired feature",
|
|
8753
|
-
children: /* @__PURE__ */ (0,
|
|
8946
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
8754
8947
|
}
|
|
8755
8948
|
)
|
|
8756
8949
|
] });
|
|
8757
8950
|
}
|
|
8758
|
-
return /* @__PURE__ */ (0,
|
|
8951
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8759
8952
|
InlineSoon,
|
|
8760
8953
|
{
|
|
8761
8954
|
label,
|
|
@@ -8775,20 +8968,20 @@ function ComingSoon({
|
|
|
8775
8968
|
);
|
|
8776
8969
|
}
|
|
8777
8970
|
if (allowed && bypassed) {
|
|
8778
|
-
return /* @__PURE__ */ (0,
|
|
8779
|
-
/* @__PURE__ */ (0,
|
|
8780
|
-
/* @__PURE__ */ (0,
|
|
8781
|
-
/* @__PURE__ */ (0,
|
|
8971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
|
|
8972
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
|
|
8973
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-badge", children: [
|
|
8974
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
8782
8975
|
"Unwired feature \u2014 you are using it anyway"
|
|
8783
8976
|
] }),
|
|
8784
|
-
/* @__PURE__ */ (0,
|
|
8785
|
-
/* @__PURE__ */ (0,
|
|
8786
|
-
onRoadmap ? /* @__PURE__ */ (0,
|
|
8977
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
|
|
8978
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-bar-actions", children: [
|
|
8979
|
+
onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
8787
8980
|
"Roadmap ",
|
|
8788
|
-
/* @__PURE__ */ (0,
|
|
8981
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
8789
8982
|
] }) : null,
|
|
8790
|
-
/* @__PURE__ */ (0,
|
|
8791
|
-
/* @__PURE__ */ (0,
|
|
8983
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
|
|
8984
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
|
|
8792
8985
|
" Re-blur"
|
|
8793
8986
|
] })
|
|
8794
8987
|
] })
|
|
@@ -8796,10 +8989,10 @@ function ComingSoon({
|
|
|
8796
8989
|
children
|
|
8797
8990
|
] });
|
|
8798
8991
|
}
|
|
8799
|
-
return /* @__PURE__ */ (0,
|
|
8800
|
-
/* @__PURE__ */ (0,
|
|
8801
|
-
/* @__PURE__ */ (0,
|
|
8802
|
-
/* @__PURE__ */ (0,
|
|
8992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
|
|
8993
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
8994
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-veil" }),
|
|
8995
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8803
8996
|
SoonCard,
|
|
8804
8997
|
{
|
|
8805
8998
|
label,
|
|
@@ -8815,10 +9008,10 @@ function ComingSoon({
|
|
|
8815
9008
|
] });
|
|
8816
9009
|
}
|
|
8817
9010
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
8818
|
-
const [open, setOpen] =
|
|
9011
|
+
const [open, setOpen] = React46.useState(false);
|
|
8819
9012
|
const [anchor, pos] = useHoverCard(open);
|
|
8820
9013
|
const zIndex = useOverlayLayer(open);
|
|
8821
|
-
const close =
|
|
9014
|
+
const close = React46.useRef(null);
|
|
8822
9015
|
const show = () => {
|
|
8823
9016
|
if (close.current) {
|
|
8824
9017
|
clearTimeout(close.current);
|
|
@@ -8834,10 +9027,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8834
9027
|
setOpen(false);
|
|
8835
9028
|
}, 140);
|
|
8836
9029
|
};
|
|
8837
|
-
|
|
9030
|
+
React46.useEffect(() => () => {
|
|
8838
9031
|
if (close.current) clearTimeout(close.current);
|
|
8839
9032
|
}, []);
|
|
8840
|
-
return /* @__PURE__ */ (0,
|
|
9033
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
|
|
8841
9034
|
"span",
|
|
8842
9035
|
{
|
|
8843
9036
|
ref: anchor,
|
|
@@ -8848,8 +9041,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8848
9041
|
onBlur: hide,
|
|
8849
9042
|
...rest,
|
|
8850
9043
|
children: [
|
|
8851
|
-
/* @__PURE__ */ (0,
|
|
8852
|
-
/* @__PURE__ */ (0,
|
|
9044
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
9045
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8853
9046
|
"button",
|
|
8854
9047
|
{
|
|
8855
9048
|
type: "button",
|
|
@@ -8860,11 +9053,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8860
9053
|
onFocus: show,
|
|
8861
9054
|
onBlur: hide,
|
|
8862
9055
|
onClick: () => open ? setOpen(false) : show(),
|
|
8863
|
-
children: /* @__PURE__ */ (0,
|
|
9056
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
8864
9057
|
}
|
|
8865
9058
|
),
|
|
8866
9059
|
open && pos ? (0, import_react_dom6.createPortal)(
|
|
8867
|
-
/* @__PURE__ */ (0,
|
|
9060
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8868
9061
|
"div",
|
|
8869
9062
|
{
|
|
8870
9063
|
className: "fd-soon-note fd-soon-hovercard",
|
|
@@ -8872,7 +9065,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8872
9065
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
|
|
8873
9066
|
onMouseEnter: show,
|
|
8874
9067
|
onMouseLeave: hide,
|
|
8875
|
-
children: /* @__PURE__ */ (0,
|
|
9068
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8876
9069
|
SoonCard,
|
|
8877
9070
|
{
|
|
8878
9071
|
label,
|
|
@@ -8902,10 +9095,10 @@ function formatEta(iso2) {
|
|
|
8902
9095
|
var FormatEta = formatEta;
|
|
8903
9096
|
|
|
8904
9097
|
// src/components/platform/Gate.tsx
|
|
8905
|
-
var
|
|
9098
|
+
var import_jsx_runtime71 = require("react/jsx-runtime");
|
|
8906
9099
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
8907
9100
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
8908
|
-
return /* @__PURE__ */ (0,
|
|
9101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
|
|
8909
9102
|
"div",
|
|
8910
9103
|
{
|
|
8911
9104
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -8921,14 +9114,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
8921
9114
|
},
|
|
8922
9115
|
...rest,
|
|
8923
9116
|
children: [
|
|
8924
|
-
/* @__PURE__ */ (0,
|
|
8925
|
-
/* @__PURE__ */ (0,
|
|
8926
|
-
/* @__PURE__ */ (0,
|
|
9117
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
9118
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
9119
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
|
|
8927
9120
|
] }),
|
|
8928
|
-
/* @__PURE__ */ (0,
|
|
8929
|
-
need.length ? /* @__PURE__ */ (0,
|
|
8930
|
-
/* @__PURE__ */ (0,
|
|
8931
|
-
need.map((p) => /* @__PURE__ */ (0,
|
|
9121
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
|
|
9122
|
+
need.length ? /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
|
|
9123
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
|
|
9124
|
+
need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("code", { className: "fd-mono", style: {
|
|
8932
9125
|
fontSize: 11.5,
|
|
8933
9126
|
padding: "2px 7px",
|
|
8934
9127
|
borderRadius: 5,
|
|
@@ -8949,7 +9142,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
|
|
|
8949
9142
|
if (ok) return children;
|
|
8950
9143
|
if (fallback !== void 0) return fallback;
|
|
8951
9144
|
if (silent) return null;
|
|
8952
|
-
return /* @__PURE__ */ (0,
|
|
9145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
8953
9146
|
}
|
|
8954
9147
|
function FeatureGate({
|
|
8955
9148
|
flag,
|
|
@@ -8972,7 +9165,7 @@ function FeatureGate({
|
|
|
8972
9165
|
const f = SessionKit.findFlag(flag) || {};
|
|
8973
9166
|
const missing = rt.missing || [];
|
|
8974
9167
|
const canBypass = bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
8975
|
-
return /* @__PURE__ */ (0,
|
|
9168
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
|
|
8976
9169
|
ComingSoon,
|
|
8977
9170
|
{
|
|
8978
9171
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -8993,26 +9186,26 @@ function FeatureGate({
|
|
|
8993
9186
|
function PermissionHint({ perm, children }) {
|
|
8994
9187
|
const { can: can2 } = useSessionContext();
|
|
8995
9188
|
if (can2(perm)) return children;
|
|
8996
|
-
return /* @__PURE__ */ (0,
|
|
9189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
|
|
8997
9190
|
"span",
|
|
8998
9191
|
{
|
|
8999
9192
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
9000
9193
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
9001
9194
|
"aria-disabled": "true",
|
|
9002
|
-
children: /* @__PURE__ */ (0,
|
|
9195
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { style: { pointerEvents: "none" }, children })
|
|
9003
9196
|
}
|
|
9004
9197
|
);
|
|
9005
9198
|
}
|
|
9006
9199
|
|
|
9007
9200
|
// src/components/platform/ModeSwitch.tsx
|
|
9008
|
-
var
|
|
9009
|
-
var
|
|
9201
|
+
var React47 = __toESM(require("react"), 1);
|
|
9202
|
+
var import_jsx_runtime72 = require("react/jsx-runtime");
|
|
9010
9203
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
9011
9204
|
const mode2 = useRuntimeMode();
|
|
9012
|
-
const [open, setOpen] =
|
|
9205
|
+
const [open, setOpen] = React47.useState(false);
|
|
9013
9206
|
const zIndex = useOverlayLayer(open);
|
|
9014
|
-
const ref =
|
|
9015
|
-
|
|
9207
|
+
const ref = React47.useRef(null);
|
|
9208
|
+
React47.useEffect(() => {
|
|
9016
9209
|
if (!open) return;
|
|
9017
9210
|
const away = (e) => {
|
|
9018
9211
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -9034,8 +9227,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
9034
9227
|
RuntimeKit.setMode(next);
|
|
9035
9228
|
setOpen(false);
|
|
9036
9229
|
};
|
|
9037
|
-
return /* @__PURE__ */ (0,
|
|
9038
|
-
/* @__PURE__ */ (0,
|
|
9230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
|
|
9231
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
|
|
9039
9232
|
"button",
|
|
9040
9233
|
{
|
|
9041
9234
|
type: "button",
|
|
@@ -9045,29 +9238,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
9045
9238
|
title: test ? "Test mode \u2014 every response is simulated. Click to inspect requests or return to live mode." : "Live mode \u2014 incomplete features are shown under construction. Click for test mode.",
|
|
9046
9239
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
|
|
9047
9240
|
children: [
|
|
9048
|
-
/* @__PURE__ */ (0,
|
|
9049
|
-
test && requestCount ? /* @__PURE__ */ (0,
|
|
9241
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
|
|
9242
|
+
test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
|
|
9050
9243
|
]
|
|
9051
9244
|
}
|
|
9052
9245
|
),
|
|
9053
|
-
open ? /* @__PURE__ */ (0,
|
|
9054
|
-
/* @__PURE__ */ (0,
|
|
9055
|
-
/* @__PURE__ */ (0,
|
|
9056
|
-
/* @__PURE__ */ (0,
|
|
9246
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-view-enter fd-mode-pop", style: { zIndex }, children: [
|
|
9247
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
9248
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
|
|
9249
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
|
|
9057
9250
|
test ? "Test mode" : "Live mode"
|
|
9058
9251
|
] }),
|
|
9059
|
-
test ? /* @__PURE__ */ (0,
|
|
9252
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
9060
9253
|
requestCount,
|
|
9061
9254
|
" simulated request",
|
|
9062
9255
|
requestCount === 1 ? "" : "s"
|
|
9063
9256
|
] }) : null,
|
|
9064
|
-
/* @__PURE__ */ (0,
|
|
9065
|
-
test && onClearLog ? /* @__PURE__ */ (0,
|
|
9257
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { flex: 1 } }),
|
|
9258
|
+
test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
|
|
9066
9259
|
] }),
|
|
9067
|
-
/* @__PURE__ */ (0,
|
|
9068
|
-
/* @__PURE__ */ (0,
|
|
9069
|
-
/* @__PURE__ */ (0,
|
|
9070
|
-
/* @__PURE__ */ (0,
|
|
9260
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
9261
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
|
|
9262
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
|
|
9263
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
9071
9264
|
s.endpointsWired,
|
|
9072
9265
|
" endpoint",
|
|
9073
9266
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -9077,58 +9270,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
9077
9270
|
s.total,
|
|
9078
9271
|
" features complete"
|
|
9079
9272
|
] }),
|
|
9080
|
-
onOpenSpec ? /* @__PURE__ */ (0,
|
|
9081
|
-
/* @__PURE__ */ (0,
|
|
9082
|
-
/* @__PURE__ */ (0,
|
|
9273
|
+
onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(import_jsx_runtime72.Fragment, { children: [
|
|
9274
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { flex: 1 } }),
|
|
9275
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
9083
9276
|
setOpen(false);
|
|
9084
9277
|
onOpenSpec();
|
|
9085
9278
|
}, children: [
|
|
9086
9279
|
"API spec ",
|
|
9087
|
-
/* @__PURE__ */ (0,
|
|
9280
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
9088
9281
|
] })
|
|
9089
9282
|
] }) : null
|
|
9090
9283
|
] })
|
|
9091
9284
|
] }),
|
|
9092
|
-
/* @__PURE__ */ (0,
|
|
9093
|
-
/* @__PURE__ */ (0,
|
|
9094
|
-
/* @__PURE__ */ (0,
|
|
9095
|
-
/* @__PURE__ */ (0,
|
|
9096
|
-
/* @__PURE__ */ (0,
|
|
9097
|
-
/* @__PURE__ */ (0,
|
|
9285
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-choice", children: [
|
|
9286
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
|
|
9287
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
9288
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-opt-text", children: [
|
|
9289
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
|
|
9290
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
|
|
9098
9291
|
] }),
|
|
9099
|
-
!test ? /* @__PURE__ */ (0,
|
|
9292
|
+
!test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
9100
9293
|
] }),
|
|
9101
|
-
/* @__PURE__ */ (0,
|
|
9102
|
-
/* @__PURE__ */ (0,
|
|
9103
|
-
/* @__PURE__ */ (0,
|
|
9104
|
-
/* @__PURE__ */ (0,
|
|
9105
|
-
/* @__PURE__ */ (0,
|
|
9294
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
|
|
9295
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
9296
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-opt-text", children: [
|
|
9297
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
|
|
9298
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
|
|
9106
9299
|
] }),
|
|
9107
|
-
test ? /* @__PURE__ */ (0,
|
|
9300
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
9108
9301
|
] })
|
|
9109
9302
|
] }),
|
|
9110
|
-
test && renderLog ? /* @__PURE__ */ (0,
|
|
9303
|
+
test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
9111
9304
|
] }) }) : null
|
|
9112
9305
|
] });
|
|
9113
9306
|
}
|
|
9114
9307
|
function TestModeBar({ onExit }) {
|
|
9115
9308
|
const mode2 = useRuntimeMode();
|
|
9116
9309
|
if (mode2 !== "test") return null;
|
|
9117
|
-
return /* @__PURE__ */ (0,
|
|
9118
|
-
/* @__PURE__ */ (0,
|
|
9119
|
-
/* @__PURE__ */ (0,
|
|
9310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fd-testbar", role: "status", children: [
|
|
9311
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
|
|
9312
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
9120
9313
|
"Test mode"
|
|
9121
9314
|
] }),
|
|
9122
|
-
/* @__PURE__ */ (0,
|
|
9123
|
-
/* @__PURE__ */ (0,
|
|
9124
|
-
/* @__PURE__ */ (0,
|
|
9315
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
|
|
9316
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
|
|
9317
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
9125
9318
|
" Back to live mode"
|
|
9126
9319
|
] })
|
|
9127
9320
|
] });
|
|
9128
9321
|
}
|
|
9129
9322
|
|
|
9130
9323
|
// src/components/planner/ChannelMeta.tsx
|
|
9131
|
-
var
|
|
9324
|
+
var import_jsx_runtime73 = require("react/jsx-runtime");
|
|
9132
9325
|
var CHANNEL_WEIGHTS = {
|
|
9133
9326
|
"OOH": 50,
|
|
9134
9327
|
"DOOH": 50,
|
|
@@ -9181,9 +9374,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
9181
9374
|
const m = ChannelMeta(channel);
|
|
9182
9375
|
const wt = channelWeightOf(channel || "");
|
|
9183
9376
|
if (dot) {
|
|
9184
|
-
return /* @__PURE__ */ (0,
|
|
9377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
9185
9378
|
}
|
|
9186
|
-
return /* @__PURE__ */ (0,
|
|
9379
|
+
return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(
|
|
9187
9380
|
"span",
|
|
9188
9381
|
{
|
|
9189
9382
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -9191,16 +9384,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
9191
9384
|
style: { "--chan": m.color },
|
|
9192
9385
|
...rest,
|
|
9193
9386
|
children: [
|
|
9194
|
-
/* @__PURE__ */ (0,
|
|
9195
|
-
showLabel ? /* @__PURE__ */ (0,
|
|
9196
|
-
weight ? /* @__PURE__ */ (0,
|
|
9387
|
+
/* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
|
|
9388
|
+
showLabel ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
|
|
9389
|
+
weight ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
|
|
9197
9390
|
]
|
|
9198
9391
|
}
|
|
9199
9392
|
);
|
|
9200
9393
|
}
|
|
9201
9394
|
|
|
9202
9395
|
// src/components/planner/SaturationDistribution.tsx
|
|
9203
|
-
var
|
|
9396
|
+
var import_jsx_runtime74 = require("react/jsx-runtime");
|
|
9204
9397
|
var BANDS2 = [
|
|
9205
9398
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
9206
9399
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -9211,24 +9404,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9211
9404
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
9212
9405
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
9213
9406
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
9214
|
-
return /* @__PURE__ */ (0,
|
|
9215
|
-
/* @__PURE__ */ (0,
|
|
9407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
9408
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
|
|
9216
9409
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
9217
9410
|
const active = selectedBand === g.key;
|
|
9218
|
-
return /* @__PURE__ */ (0,
|
|
9411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(
|
|
9219
9412
|
"button",
|
|
9220
9413
|
{
|
|
9221
9414
|
type: "button",
|
|
9222
9415
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
9223
9416
|
style: { display: "flex", flexDirection: "column", justifyContent: "flex-end", gap: 10, padding: 12, border: "1px solid " + (active ? "var(--border-strong)" : "var(--border)"), borderRadius: "var(--r-lg)", background: active ? "var(--surface-2)" : "var(--surface)", cursor: onSelectBand ? "pointer" : "default", textAlign: "left", minHeight: 190, minWidth: 0, transition: "background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)" },
|
|
9224
9417
|
children: [
|
|
9225
|
-
/* @__PURE__ */ (0,
|
|
9418
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
|
|
9226
9419
|
// `overflow: hidden` + `white-space: nowrap` only clips once the span
|
|
9227
9420
|
// actually HAS a bounded width to clip against (see the grid/flex
|
|
9228
9421
|
// `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
|
|
9229
9422
|
// that clip readable instead of a hard cut mid-letter; the full name
|
|
9230
9423
|
// is still one hover away via `title`.
|
|
9231
|
-
/* @__PURE__ */ (0,
|
|
9424
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
|
|
9232
9425
|
"span",
|
|
9233
9426
|
{
|
|
9234
9427
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -9238,13 +9431,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9238
9431
|
c.name
|
|
9239
9432
|
)
|
|
9240
9433
|
)) }),
|
|
9241
|
-
/* @__PURE__ */ (0,
|
|
9242
|
-
/* @__PURE__ */ (0,
|
|
9243
|
-
/* @__PURE__ */ (0,
|
|
9434
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
|
|
9435
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
|
|
9436
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
|
|
9244
9437
|
] }),
|
|
9245
|
-
/* @__PURE__ */ (0,
|
|
9246
|
-
/* @__PURE__ */ (0,
|
|
9247
|
-
/* @__PURE__ */ (0,
|
|
9438
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
|
|
9439
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-label-lg", children: g.label }),
|
|
9440
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
|
|
9248
9441
|
"CRP ",
|
|
9249
9442
|
g.range
|
|
9250
9443
|
] })
|
|
@@ -9254,10 +9447,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9254
9447
|
g.key
|
|
9255
9448
|
);
|
|
9256
9449
|
}) }),
|
|
9257
|
-
floorBand ? /* @__PURE__ */ (0,
|
|
9258
|
-
/* @__PURE__ */ (0,
|
|
9259
|
-
/* @__PURE__ */ (0,
|
|
9260
|
-
/* @__PURE__ */ (0,
|
|
9450
|
+
floorBand ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
9451
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
|
|
9452
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
|
|
9453
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("strong", { style: { color: "var(--text)" }, children: [
|
|
9261
9454
|
"Plan floor ",
|
|
9262
9455
|
floorScore
|
|
9263
9456
|
] }),
|
|
@@ -9268,8 +9461,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9268
9461
|
}
|
|
9269
9462
|
|
|
9270
9463
|
// src/components/planner/MixGap.tsx
|
|
9271
|
-
var
|
|
9272
|
-
var
|
|
9464
|
+
var React48 = __toESM(require("react"), 1);
|
|
9465
|
+
var import_jsx_runtime75 = require("react/jsx-runtime");
|
|
9273
9466
|
var MIX_GAP_LAYOUT = {
|
|
9274
9467
|
trackHeight: 30,
|
|
9275
9468
|
barHeight: 20,
|
|
@@ -9283,19 +9476,19 @@ function mixGapOffset(value, max) {
|
|
|
9283
9476
|
}
|
|
9284
9477
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
9285
9478
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
9286
|
-
const [hover, setHover] =
|
|
9479
|
+
const [hover, setHover] = React48.useState(null);
|
|
9287
9480
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
9288
9481
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
9289
9482
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
9290
9483
|
const barTop = (trackHeight - barHeight) / 2;
|
|
9291
|
-
return /* @__PURE__ */ (0,
|
|
9292
|
-
/* @__PURE__ */ (0,
|
|
9293
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0,
|
|
9294
|
-
/* @__PURE__ */ (0,
|
|
9484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
9485
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
|
|
9486
|
+
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
9487
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
|
|
9295
9488
|
l
|
|
9296
9489
|
] }, l)),
|
|
9297
|
-
/* @__PURE__ */ (0,
|
|
9298
|
-
/* @__PURE__ */ (0,
|
|
9490
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
9491
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
|
|
9299
9492
|
"Target"
|
|
9300
9493
|
] })
|
|
9301
9494
|
] }),
|
|
@@ -9304,7 +9497,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9304
9497
|
const tone = toneOf(gap);
|
|
9305
9498
|
const tip = "Realized " + r.realized + "% vs " + r.target + "% target" + (gap < -1 ? " \xB7 " + Math.abs(gap).toFixed(0) + " pts short" : gap > 1 ? " \xB7 " + gap.toFixed(0) + " pts over" : " \xB7 on target") + (r.note ? " \u2014 " + r.note : "");
|
|
9306
9499
|
const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
|
|
9307
|
-
return /* @__PURE__ */ (0,
|
|
9500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(
|
|
9308
9501
|
"div",
|
|
9309
9502
|
{
|
|
9310
9503
|
className: "fd-row",
|
|
@@ -9312,15 +9505,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9312
9505
|
onMouseEnter: () => setHover(r.channel),
|
|
9313
9506
|
onMouseLeave: () => setHover(null),
|
|
9314
9507
|
children: [
|
|
9315
|
-
/* @__PURE__ */ (0,
|
|
9316
|
-
/* @__PURE__ */ (0,
|
|
9317
|
-
/* @__PURE__ */ (0,
|
|
9318
|
-
/* @__PURE__ */ (0,
|
|
9319
|
-
/* @__PURE__ */ (0,
|
|
9508
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
9509
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(import_jsx_runtime75.Fragment, { children: [
|
|
9510
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
|
|
9511
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
|
|
9512
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
|
|
9320
9513
|
r.realized,
|
|
9321
9514
|
"%"
|
|
9322
9515
|
] }),
|
|
9323
|
-
hover === r.channel ? /* @__PURE__ */ (0,
|
|
9516
|
+
hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
|
|
9324
9517
|
] }) })
|
|
9325
9518
|
]
|
|
9326
9519
|
},
|
|
@@ -9331,7 +9524,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9331
9524
|
}
|
|
9332
9525
|
|
|
9333
9526
|
// src/components/planner/ChannelContribution.tsx
|
|
9334
|
-
var
|
|
9527
|
+
var import_jsx_runtime76 = require("react/jsx-runtime");
|
|
9335
9528
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
9336
9529
|
function ChannelContribution({
|
|
9337
9530
|
channels = [],
|
|
@@ -9347,9 +9540,9 @@ function ChannelContribution({
|
|
|
9347
9540
|
const grand = total !== void 0 ? total : base + bonus;
|
|
9348
9541
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
9349
9542
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
9350
|
-
return /* @__PURE__ */ (0,
|
|
9351
|
-
loading ? /* @__PURE__ */ (0,
|
|
9352
|
-
channels.map((c) => /* @__PURE__ */ (0,
|
|
9543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
9544
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
|
|
9545
|
+
channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9353
9546
|
"span",
|
|
9354
9547
|
{
|
|
9355
9548
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -9358,7 +9551,7 @@ function ChannelContribution({
|
|
|
9358
9551
|
},
|
|
9359
9552
|
c.name
|
|
9360
9553
|
)),
|
|
9361
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
9554
|
+
bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9362
9555
|
"span",
|
|
9363
9556
|
{
|
|
9364
9557
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -9367,18 +9560,18 @@ function ChannelContribution({
|
|
|
9367
9560
|
}
|
|
9368
9561
|
) : null
|
|
9369
9562
|
] }),
|
|
9370
|
-
showTable ? /* @__PURE__ */ (0,
|
|
9371
|
-
/* @__PURE__ */ (0,
|
|
9372
|
-
/* @__PURE__ */ (0,
|
|
9373
|
-
/* @__PURE__ */ (0,
|
|
9374
|
-
/* @__PURE__ */ (0,
|
|
9375
|
-
/* @__PURE__ */ (0,
|
|
9376
|
-
/* @__PURE__ */ (0,
|
|
9563
|
+
showTable ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
|
|
9564
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
|
|
9565
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
|
|
9566
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
|
|
9567
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
|
|
9568
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
|
|
9569
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
|
|
9377
9570
|
] }) }),
|
|
9378
|
-
/* @__PURE__ */ (0,
|
|
9379
|
-
channels.map((c) => /* @__PURE__ */ (0,
|
|
9380
|
-
/* @__PURE__ */ (0,
|
|
9381
|
-
/* @__PURE__ */ (0,
|
|
9571
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tbody", { children: [
|
|
9572
|
+
channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
|
|
9573
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
|
|
9574
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9382
9575
|
"span",
|
|
9383
9576
|
{
|
|
9384
9577
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -9387,38 +9580,38 @@ function ChannelContribution({
|
|
|
9387
9580
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
9388
9581
|
}
|
|
9389
9582
|
) }),
|
|
9390
|
-
/* @__PURE__ */ (0,
|
|
9391
|
-
/* @__PURE__ */ (0,
|
|
9392
|
-
/* @__PURE__ */ (0,
|
|
9583
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: c.spend }),
|
|
9584
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
|
|
9585
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("td", { className: "is-num", children: [
|
|
9393
9586
|
pct(c.crp).toFixed(0),
|
|
9394
9587
|
"%"
|
|
9395
9588
|
] })
|
|
9396
9589
|
] }, c.name)),
|
|
9397
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
9398
|
-
/* @__PURE__ */ (0,
|
|
9399
|
-
/* @__PURE__ */ (0,
|
|
9590
|
+
bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
|
|
9591
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
|
|
9592
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
|
|
9400
9593
|
"Surround-sound bonus"
|
|
9401
9594
|
] }) }),
|
|
9402
|
-
/* @__PURE__ */ (0,
|
|
9595
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
9403
9596
|
"+",
|
|
9404
9597
|
bonusPct,
|
|
9405
9598
|
"% of +",
|
|
9406
9599
|
bonusMax,
|
|
9407
9600
|
"%"
|
|
9408
9601
|
] }) }),
|
|
9409
|
-
/* @__PURE__ */ (0,
|
|
9410
|
-
/* @__PURE__ */ (0,
|
|
9411
|
-
/* @__PURE__ */ (0,
|
|
9602
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
|
|
9603
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
|
|
9604
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("td", { className: "is-num", children: [
|
|
9412
9605
|
pct(bonus).toFixed(0),
|
|
9413
9606
|
"%"
|
|
9414
9607
|
] })
|
|
9415
9608
|
] }) : null,
|
|
9416
|
-
/* @__PURE__ */ (0,
|
|
9417
|
-
/* @__PURE__ */ (0,
|
|
9418
|
-
/* @__PURE__ */ (0,
|
|
9419
|
-
/* @__PURE__ */ (0,
|
|
9420
|
-
/* @__PURE__ */ (0,
|
|
9421
|
-
/* @__PURE__ */ (0,
|
|
9609
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
|
|
9610
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
|
|
9611
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", {}),
|
|
9612
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
|
|
9613
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
|
|
9614
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
|
|
9422
9615
|
] })
|
|
9423
9616
|
] })
|
|
9424
9617
|
] }) : null
|
|
@@ -9426,8 +9619,8 @@ function ChannelContribution({
|
|
|
9426
9619
|
}
|
|
9427
9620
|
|
|
9428
9621
|
// src/components/planner/BudgetReallocator.tsx
|
|
9429
|
-
var
|
|
9430
|
-
var
|
|
9622
|
+
var React49 = __toESM(require("react"), 1);
|
|
9623
|
+
var import_jsx_runtime77 = require("react/jsx-runtime");
|
|
9431
9624
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
9432
9625
|
function BudgetReallocator({
|
|
9433
9626
|
campus,
|
|
@@ -9442,8 +9635,8 @@ function BudgetReallocator({
|
|
|
9442
9635
|
onCancel,
|
|
9443
9636
|
className = ""
|
|
9444
9637
|
}) {
|
|
9445
|
-
const [draft, setDraft] =
|
|
9446
|
-
|
|
9638
|
+
const [draft, setDraft] = React49.useState(spend);
|
|
9639
|
+
React49.useEffect(() => setDraft(spend), [spend]);
|
|
9447
9640
|
const dirty = draft !== spend;
|
|
9448
9641
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
9449
9642
|
const nextBand = bandFor(nextCrp);
|
|
@@ -9458,10 +9651,10 @@ function BudgetReallocator({
|
|
|
9458
9651
|
setDraft(spend);
|
|
9459
9652
|
if (onCancel) onCancel();
|
|
9460
9653
|
};
|
|
9461
|
-
const trackRef =
|
|
9462
|
-
const chipRef =
|
|
9463
|
-
const [chipLeft, setChipLeft] =
|
|
9464
|
-
|
|
9654
|
+
const trackRef = React49.useRef(null);
|
|
9655
|
+
const chipRef = React49.useRef(null);
|
|
9656
|
+
const [chipLeft, setChipLeft] = React49.useState(null);
|
|
9657
|
+
React49.useLayoutEffect(() => {
|
|
9465
9658
|
const track = trackRef.current;
|
|
9466
9659
|
if (!dirty || !track) {
|
|
9467
9660
|
setChipLeft(null);
|
|
@@ -9482,23 +9675,23 @@ function BudgetReallocator({
|
|
|
9482
9675
|
ro.observe(track);
|
|
9483
9676
|
return () => ro.disconnect();
|
|
9484
9677
|
}, [dirty, pct]);
|
|
9485
|
-
return /* @__PURE__ */ (0,
|
|
9678
|
+
return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
|
|
9486
9679
|
"div",
|
|
9487
9680
|
{
|
|
9488
9681
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
9489
9682
|
style: { gap: 14, padding: 18, border: "1px solid " + (dirty ? "var(--border-brand)" : "var(--border)"), borderRadius: "var(--r-lg)", background: dirty ? "var(--surface-brand)" : "var(--surface)", color: "var(--text)", transition: "background var(--dur-base) var(--ease),border-color var(--dur-base) var(--ease)" },
|
|
9490
9683
|
children: [
|
|
9491
|
-
/* @__PURE__ */ (0,
|
|
9492
|
-
/* @__PURE__ */ (0,
|
|
9493
|
-
/* @__PURE__ */ (0,
|
|
9494
|
-
dirty ? /* @__PURE__ */ (0,
|
|
9495
|
-
/* @__PURE__ */ (0,
|
|
9496
|
-
/* @__PURE__ */ (0,
|
|
9684
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
9685
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
9686
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
9687
|
+
dirty ? /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(import_jsx_runtime77.Fragment, { children: [
|
|
9688
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
9689
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
9497
9690
|
] }) : null
|
|
9498
9691
|
] }),
|
|
9499
|
-
/* @__PURE__ */ (0,
|
|
9500
|
-
/* @__PURE__ */ (0,
|
|
9501
|
-
dirty ? /* @__PURE__ */ (0,
|
|
9692
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
|
|
9693
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
9694
|
+
dirty ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
9502
9695
|
"span",
|
|
9503
9696
|
{
|
|
9504
9697
|
ref: chipRef,
|
|
@@ -9510,7 +9703,7 @@ function BudgetReallocator({
|
|
|
9510
9703
|
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
9511
9704
|
}
|
|
9512
9705
|
) : null,
|
|
9513
|
-
/* @__PURE__ */ (0,
|
|
9706
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
9514
9707
|
"input",
|
|
9515
9708
|
{
|
|
9516
9709
|
type: "range",
|
|
@@ -9526,13 +9719,13 @@ function BudgetReallocator({
|
|
|
9526
9719
|
}
|
|
9527
9720
|
)
|
|
9528
9721
|
] }),
|
|
9529
|
-
/* @__PURE__ */ (0,
|
|
9530
|
-
/* @__PURE__ */ (0,
|
|
9531
|
-
/* @__PURE__ */ (0,
|
|
9532
|
-
/* @__PURE__ */ (0,
|
|
9722
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
9723
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
|
|
9724
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
|
|
9725
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
|
|
9533
9726
|
] }),
|
|
9534
|
-
/* @__PURE__ */ (0,
|
|
9535
|
-
/* @__PURE__ */ (0,
|
|
9727
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
9728
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
9536
9729
|
"button",
|
|
9537
9730
|
{
|
|
9538
9731
|
type: "button",
|
|
@@ -9551,7 +9744,7 @@ function BudgetReallocator({
|
|
|
9551
9744
|
}
|
|
9552
9745
|
|
|
9553
9746
|
// src/components/planner/SurroundSound.tsx
|
|
9554
|
-
var
|
|
9747
|
+
var import_jsx_runtime78 = require("react/jsx-runtime");
|
|
9555
9748
|
var CATEGORIES = [
|
|
9556
9749
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
9557
9750
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -9563,26 +9756,26 @@ var CATEGORIES = [
|
|
|
9563
9756
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
9564
9757
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
9565
9758
|
const single = present.length <= 2;
|
|
9566
|
-
return /* @__PURE__ */ (0,
|
|
9567
|
-
/* @__PURE__ */ (0,
|
|
9759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
|
|
9760
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
|
|
9568
9761
|
const on = present.includes(c.key);
|
|
9569
|
-
return /* @__PURE__ */ (0,
|
|
9762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)(
|
|
9570
9763
|
"span",
|
|
9571
9764
|
{
|
|
9572
9765
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
9573
9766
|
style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 5, width: 62, padding: "10px 0", borderRadius: "var(--r-md)", border: "1px solid " + (on ? "var(--csi-2-edge)" : "var(--border)"), background: on ? "var(--csi-2-fill)" : "var(--surface-2)", color: on ? "var(--csi-2-text)" : "var(--text-disabled)" },
|
|
9574
9767
|
children: [
|
|
9575
|
-
/* @__PURE__ */ (0,
|
|
9576
|
-
/* @__PURE__ */ (0,
|
|
9768
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
9769
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
|
|
9577
9770
|
]
|
|
9578
9771
|
},
|
|
9579
9772
|
c.key
|
|
9580
9773
|
);
|
|
9581
9774
|
}) }),
|
|
9582
|
-
/* @__PURE__ */ (0,
|
|
9583
|
-
/* @__PURE__ */ (0,
|
|
9584
|
-
/* @__PURE__ */ (0,
|
|
9585
|
-
/* @__PURE__ */ (0,
|
|
9775
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
9776
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
9777
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
|
|
9778
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
|
|
9586
9779
|
"+",
|
|
9587
9780
|
bonusPct,
|
|
9588
9781
|
"% of +",
|
|
@@ -9590,8 +9783,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
9590
9783
|
"%"
|
|
9591
9784
|
] })
|
|
9592
9785
|
] }),
|
|
9593
|
-
/* @__PURE__ */ (0,
|
|
9594
|
-
/* @__PURE__ */ (0,
|
|
9786
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
|
|
9787
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
|
|
9595
9788
|
present.length,
|
|
9596
9789
|
" of 6 channel categories present.",
|
|
9597
9790
|
" ",
|
|
@@ -9603,7 +9796,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
9603
9796
|
}
|
|
9604
9797
|
|
|
9605
9798
|
// src/components/planner/Importance.tsx
|
|
9606
|
-
var
|
|
9799
|
+
var import_jsx_runtime79 = require("react/jsx-runtime");
|
|
9607
9800
|
var IMPORTANCE_LEVELS = [
|
|
9608
9801
|
{ id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
|
|
9609
9802
|
{ id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
|
|
@@ -9633,23 +9826,23 @@ function importanceTokens(id) {
|
|
|
9633
9826
|
function ImportanceTag({ level, showLabel = true, size = "sm", className = "" }) {
|
|
9634
9827
|
const lvl = importanceLevel(level);
|
|
9635
9828
|
const t = importanceTokens(level);
|
|
9636
|
-
return /* @__PURE__ */ (0,
|
|
9829
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
|
|
9637
9830
|
"span",
|
|
9638
9831
|
{
|
|
9639
9832
|
className: ["fd-imp-tag", size === "md" ? "is-md" : "", className].filter(Boolean).join(" "),
|
|
9640
9833
|
style: { background: t.fill, borderColor: t.edge, color: t.text },
|
|
9641
9834
|
title: lvl.label + " \u2014 " + lvl.description,
|
|
9642
9835
|
children: [
|
|
9643
|
-
/* @__PURE__ */ (0,
|
|
9644
|
-
showLabel ? lvl.label : /* @__PURE__ */ (0,
|
|
9836
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
|
|
9837
|
+
showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-sr", children: lvl.label })
|
|
9645
9838
|
]
|
|
9646
9839
|
}
|
|
9647
9840
|
);
|
|
9648
9841
|
}
|
|
9649
9842
|
|
|
9650
9843
|
// src/components/planner/PreferenceMeter.tsx
|
|
9651
|
-
var
|
|
9652
|
-
var
|
|
9844
|
+
var React50 = __toESM(require("react"), 1);
|
|
9845
|
+
var import_jsx_runtime80 = require("react/jsx-runtime");
|
|
9653
9846
|
function preferenceScore(criteria) {
|
|
9654
9847
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
9655
9848
|
const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
|
|
@@ -9678,8 +9871,8 @@ function PreferenceMeter({
|
|
|
9678
9871
|
className = ""
|
|
9679
9872
|
}) {
|
|
9680
9873
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
9681
|
-
const segments =
|
|
9682
|
-
return /* @__PURE__ */ (0,
|
|
9874
|
+
const segments = React50.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
9875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
|
|
9683
9876
|
ScoreMeter,
|
|
9684
9877
|
{
|
|
9685
9878
|
score: value,
|
|
@@ -9691,22 +9884,22 @@ function PreferenceMeter({
|
|
|
9691
9884
|
placement,
|
|
9692
9885
|
className,
|
|
9693
9886
|
breakdownLabel: breakdownTitle,
|
|
9694
|
-
breakdown: /* @__PURE__ */ (0,
|
|
9695
|
-
/* @__PURE__ */ (0,
|
|
9696
|
-
/* @__PURE__ */ (0,
|
|
9697
|
-
/* @__PURE__ */ (0,
|
|
9887
|
+
breakdown: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-prefbreak", children: [
|
|
9888
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-prefbreak-head", children: [
|
|
9889
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
|
|
9890
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
|
|
9698
9891
|
] }),
|
|
9699
|
-
/* @__PURE__ */ (0,
|
|
9892
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
|
|
9700
9893
|
const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
|
|
9701
|
-
return /* @__PURE__ */ (0,
|
|
9702
|
-
/* @__PURE__ */ (0,
|
|
9703
|
-
/* @__PURE__ */ (0,
|
|
9704
|
-
/* @__PURE__ */ (0,
|
|
9705
|
-
c.note ? /* @__PURE__ */ (0,
|
|
9894
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
|
|
9895
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(ImportanceTag, { level: c.importance }),
|
|
9896
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-prefbreak-text", children: [
|
|
9897
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
|
|
9898
|
+
c.note ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
|
|
9706
9899
|
] }),
|
|
9707
|
-
/* @__PURE__ */ (0,
|
|
9900
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
|
|
9708
9901
|
Math.round(Number(c.earned) || 0),
|
|
9709
|
-
/* @__PURE__ */ (0,
|
|
9902
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
|
|
9710
9903
|
Math.round(c.weight)
|
|
9711
9904
|
] })
|
|
9712
9905
|
] }, c.id);
|
|
@@ -9717,10 +9910,10 @@ function PreferenceMeter({
|
|
|
9717
9910
|
}
|
|
9718
9911
|
|
|
9719
9912
|
// src/components/chat/AgentChatPanel.tsx
|
|
9720
|
-
var
|
|
9913
|
+
var React56 = __toESM(require("react"), 1);
|
|
9721
9914
|
|
|
9722
9915
|
// src/components/chat/chatEngine.ts
|
|
9723
|
-
var
|
|
9916
|
+
var React51 = __toESM(require("react"), 1);
|
|
9724
9917
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
9725
9918
|
var JOB_PENDING = ["queued", "running"];
|
|
9726
9919
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -9774,22 +9967,22 @@ function useChatEngine(opts) {
|
|
|
9774
9967
|
onClear,
|
|
9775
9968
|
onFeedback
|
|
9776
9969
|
} = opts || {};
|
|
9777
|
-
const [status, setStatus] =
|
|
9778
|
-
const [threadId, setThreadId] =
|
|
9779
|
-
const [messages, setMessages] =
|
|
9780
|
-
const [queue, setQueue] =
|
|
9781
|
-
const [fatal, setFatal] =
|
|
9782
|
-
const [busy, setBusy] =
|
|
9783
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
9784
|
-
const listRef =
|
|
9785
|
-
const queueRef =
|
|
9786
|
-
const busyRef =
|
|
9787
|
-
const stoppedRef =
|
|
9788
|
-
const abortRef =
|
|
9789
|
-
const serverCount =
|
|
9790
|
-
const threadRef =
|
|
9791
|
-
const mounted =
|
|
9792
|
-
|
|
9970
|
+
const [status, setStatus] = React51.useState("idle");
|
|
9971
|
+
const [threadId, setThreadId] = React51.useState(null);
|
|
9972
|
+
const [messages, setMessages] = React51.useState([]);
|
|
9973
|
+
const [queue, setQueue] = React51.useState([]);
|
|
9974
|
+
const [fatal, setFatal] = React51.useState(null);
|
|
9975
|
+
const [busy, setBusy] = React51.useState(false);
|
|
9976
|
+
const [turnStartedAt, setTurnStartedAt] = React51.useState(null);
|
|
9977
|
+
const listRef = React51.useRef([]);
|
|
9978
|
+
const queueRef = React51.useRef([]);
|
|
9979
|
+
const busyRef = React51.useRef(false);
|
|
9980
|
+
const stoppedRef = React51.useRef(false);
|
|
9981
|
+
const abortRef = React51.useRef(null);
|
|
9982
|
+
const serverCount = React51.useRef(0);
|
|
9983
|
+
const threadRef = React51.useRef(null);
|
|
9984
|
+
const mounted = React51.useRef(true);
|
|
9985
|
+
React51.useEffect(() => {
|
|
9793
9986
|
mounted.current = true;
|
|
9794
9987
|
return () => {
|
|
9795
9988
|
mounted.current = false;
|
|
@@ -9811,14 +10004,14 @@ function useChatEngine(opts) {
|
|
|
9811
10004
|
}
|
|
9812
10005
|
return false;
|
|
9813
10006
|
};
|
|
9814
|
-
const loadThread =
|
|
10007
|
+
const loadThread = React51.useCallback(async (id) => {
|
|
9815
10008
|
const data = await apiAdapter.getThread(id);
|
|
9816
10009
|
const list = [...data && data.messages || []];
|
|
9817
10010
|
serverCount.current = list.length;
|
|
9818
10011
|
commit(list);
|
|
9819
10012
|
return list;
|
|
9820
10013
|
}, [apiAdapter]);
|
|
9821
|
-
|
|
10014
|
+
React51.useEffect(() => {
|
|
9822
10015
|
if (!apiAdapter) {
|
|
9823
10016
|
setStatus("idle");
|
|
9824
10017
|
setFatal(null);
|
|
@@ -10031,7 +10224,7 @@ function useChatEngine(opts) {
|
|
|
10031
10224
|
await dispatchTurn(turn);
|
|
10032
10225
|
}
|
|
10033
10226
|
}
|
|
10034
|
-
const send =
|
|
10227
|
+
const send = React51.useCallback((text, attachments) => {
|
|
10035
10228
|
const body = (text || "").trim();
|
|
10036
10229
|
if (!body && !(attachments && attachments.length)) return;
|
|
10037
10230
|
if (status === "disconnected") return;
|
|
@@ -10041,7 +10234,7 @@ function useChatEngine(opts) {
|
|
|
10041
10234
|
stoppedRef.current = false;
|
|
10042
10235
|
drain();
|
|
10043
10236
|
}, [status]);
|
|
10044
|
-
const stop =
|
|
10237
|
+
const stop = React51.useCallback(() => {
|
|
10045
10238
|
stoppedRef.current = true;
|
|
10046
10239
|
const ac = abortRef.current;
|
|
10047
10240
|
if (ac) {
|
|
@@ -10060,11 +10253,11 @@ function useChatEngine(opts) {
|
|
|
10060
10253
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
10061
10254
|
}
|
|
10062
10255
|
}, [apiAdapter]);
|
|
10063
|
-
const removeQueued =
|
|
10256
|
+
const removeQueued = React51.useCallback((id) => {
|
|
10064
10257
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
10065
10258
|
setQueue(queueRef.current.slice());
|
|
10066
10259
|
}, []);
|
|
10067
|
-
const retry =
|
|
10260
|
+
const retry = React51.useCallback(() => {
|
|
10068
10261
|
const list = listRef.current;
|
|
10069
10262
|
let at = -1;
|
|
10070
10263
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -10080,19 +10273,19 @@ function useChatEngine(opts) {
|
|
|
10080
10273
|
setQueue(queueRef.current.slice());
|
|
10081
10274
|
drain();
|
|
10082
10275
|
}, []);
|
|
10083
|
-
const clear =
|
|
10276
|
+
const clear = React51.useCallback(() => {
|
|
10084
10277
|
commit([]);
|
|
10085
10278
|
serverCount.current = 0;
|
|
10086
10279
|
queueRef.current = [];
|
|
10087
10280
|
setQueue([]);
|
|
10088
10281
|
onClear && onClear();
|
|
10089
10282
|
}, [onClear]);
|
|
10090
|
-
const setFeedback =
|
|
10283
|
+
const setFeedback = React51.useCallback((id, value) => {
|
|
10091
10284
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
10092
10285
|
const msg = listRef.current.find((m) => m.id === id);
|
|
10093
10286
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
10094
10287
|
}, [onFeedback]);
|
|
10095
|
-
const reload =
|
|
10288
|
+
const reload = React51.useCallback(async () => {
|
|
10096
10289
|
if (!threadRef.current) return;
|
|
10097
10290
|
setStatus("loading");
|
|
10098
10291
|
try {
|
|
@@ -10130,11 +10323,11 @@ var ChatKit = {
|
|
|
10130
10323
|
};
|
|
10131
10324
|
|
|
10132
10325
|
// src/components/chat/ChatTranscript.tsx
|
|
10133
|
-
var
|
|
10326
|
+
var React53 = __toESM(require("react"), 1);
|
|
10134
10327
|
|
|
10135
10328
|
// src/components/chat/ChatTurn.tsx
|
|
10136
|
-
var
|
|
10137
|
-
var
|
|
10329
|
+
var React52 = __toESM(require("react"), 1);
|
|
10330
|
+
var import_jsx_runtime81 = require("react/jsx-runtime");
|
|
10138
10331
|
function JsonView({ value }) {
|
|
10139
10332
|
let text;
|
|
10140
10333
|
try {
|
|
@@ -10142,67 +10335,67 @@ function JsonView({ value }) {
|
|
|
10142
10335
|
} catch (e) {
|
|
10143
10336
|
text = String(value);
|
|
10144
10337
|
}
|
|
10145
|
-
return /* @__PURE__ */ (0,
|
|
10338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
10146
10339
|
}
|
|
10147
10340
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
10148
10341
|
if (!packet) return null;
|
|
10149
10342
|
const s = schema || {};
|
|
10150
10343
|
const invalid = packet.valid === false;
|
|
10151
10344
|
const title = s.heading || packet.type;
|
|
10152
|
-
return /* @__PURE__ */ (0,
|
|
10153
|
-
/* @__PURE__ */ (0,
|
|
10154
|
-
/* @__PURE__ */ (0,
|
|
10155
|
-
/* @__PURE__ */ (0,
|
|
10156
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
10157
|
-
invalid ? /* @__PURE__ */ (0,
|
|
10345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
|
|
10346
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("header", { className: "fdc-packet-head", children: [
|
|
10347
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
|
|
10348
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
|
|
10349
|
+
packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
|
|
10350
|
+
invalid ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
|
|
10158
10351
|
] }),
|
|
10159
|
-
invalid ? /* @__PURE__ */ (0,
|
|
10160
|
-
/* @__PURE__ */ (0,
|
|
10161
|
-
/* @__PURE__ */ (0,
|
|
10162
|
-
] }) : /* @__PURE__ */ (0,
|
|
10163
|
-
!invalid && onApply ? /* @__PURE__ */ (0,
|
|
10164
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
10165
|
-
/* @__PURE__ */ (0,
|
|
10166
|
-
/* @__PURE__ */ (0,
|
|
10352
|
+
invalid ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
|
|
10353
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10354
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
|
|
10355
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(JsonView, { value: packet.payload }) }),
|
|
10356
|
+
!invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("footer", { className: "fdc-packet-foot", children: [
|
|
10357
|
+
packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10358
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
|
|
10359
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
|
|
10167
10360
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
10168
10361
|
] })
|
|
10169
10362
|
] }) : null
|
|
10170
10363
|
] });
|
|
10171
10364
|
}
|
|
10172
10365
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
10173
|
-
const [open, setOpen] =
|
|
10366
|
+
const [open, setOpen] = React52.useState(defaultOpen);
|
|
10174
10367
|
if (!text) return null;
|
|
10175
|
-
return /* @__PURE__ */ (0,
|
|
10176
|
-
/* @__PURE__ */ (0,
|
|
10177
|
-
/* @__PURE__ */ (0,
|
|
10178
|
-
/* @__PURE__ */ (0,
|
|
10179
|
-
streaming ? /* @__PURE__ */ (0,
|
|
10180
|
-
/* @__PURE__ */ (0,
|
|
10181
|
-
/* @__PURE__ */ (0,
|
|
10182
|
-
/* @__PURE__ */ (0,
|
|
10368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
10369
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
10370
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
|
|
10371
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
|
|
10372
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
10373
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10374
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10375
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {})
|
|
10183
10376
|
] }) : null,
|
|
10184
|
-
/* @__PURE__ */ (0,
|
|
10377
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
10185
10378
|
] }),
|
|
10186
|
-
open ? /* @__PURE__ */ (0,
|
|
10379
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-think-body", children: text }) : null
|
|
10187
10380
|
] });
|
|
10188
10381
|
}
|
|
10189
10382
|
function Citations({ items = [], onOpen }) {
|
|
10190
|
-
const [open, setOpen] =
|
|
10383
|
+
const [open, setOpen] = React52.useState(false);
|
|
10191
10384
|
if (!items.length) return null;
|
|
10192
|
-
return /* @__PURE__ */ (0,
|
|
10193
|
-
/* @__PURE__ */ (0,
|
|
10194
|
-
/* @__PURE__ */ (0,
|
|
10195
|
-
/* @__PURE__ */ (0,
|
|
10385
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-cites", children: [
|
|
10386
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
10387
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
|
|
10388
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { children: [
|
|
10196
10389
|
items.length,
|
|
10197
10390
|
" source",
|
|
10198
10391
|
items.length === 1 ? "" : "s"
|
|
10199
10392
|
] }),
|
|
10200
|
-
/* @__PURE__ */ (0,
|
|
10393
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
10201
10394
|
] }),
|
|
10202
|
-
open ? /* @__PURE__ */ (0,
|
|
10203
|
-
/* @__PURE__ */ (0,
|
|
10204
|
-
c.url ? /* @__PURE__ */ (0,
|
|
10205
|
-
c.detail ? /* @__PURE__ */ (0,
|
|
10395
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("li", { children: [
|
|
10396
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
|
|
10397
|
+
c.url ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: c.title || "Source" }),
|
|
10398
|
+
c.detail ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
|
|
10206
10399
|
] }, c.id || i)) }) : null
|
|
10207
10400
|
] });
|
|
10208
10401
|
}
|
|
@@ -10213,29 +10406,29 @@ function clampText(text, max) {
|
|
|
10213
10406
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
10214
10407
|
}
|
|
10215
10408
|
function MessageBody({ message: m, ctx }) {
|
|
10216
|
-
const [expanded, setExpanded] =
|
|
10409
|
+
const [expanded, setExpanded] = React52.useState(false);
|
|
10217
10410
|
const isUser = m.role === "user";
|
|
10218
10411
|
const raw = m.text || "";
|
|
10219
10412
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
10220
10413
|
const body = clamped != null ? clamped : raw;
|
|
10221
10414
|
const showMd = ctx.markdown && !isUser;
|
|
10222
|
-
return /* @__PURE__ */ (0,
|
|
10223
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */ (0,
|
|
10224
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0,
|
|
10225
|
-
body ? /* @__PURE__ */ (0,
|
|
10226
|
-
showMd ? /* @__PURE__ */ (0,
|
|
10227
|
-
m.streaming ? /* @__PURE__ */ (0,
|
|
10415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-body", children: [
|
|
10416
|
+
m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
|
|
10417
|
+
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
|
|
10418
|
+
body ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
|
|
10419
|
+
showMd ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-plain", children: body }),
|
|
10420
|
+
m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
|
|
10228
10421
|
] }) : null,
|
|
10229
|
-
clamped != null ? /* @__PURE__ */ (0,
|
|
10230
|
-
/* @__PURE__ */ (0,
|
|
10422
|
+
clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
|
|
10423
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
|
|
10231
10424
|
"Show more",
|
|
10232
|
-
/* @__PURE__ */ (0,
|
|
10233
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0,
|
|
10234
|
-
/* @__PURE__ */ (0,
|
|
10425
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
|
|
10426
|
+
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
|
|
10427
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
|
|
10235
10428
|
"Show less"
|
|
10236
10429
|
] }) : null,
|
|
10237
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */ (0,
|
|
10238
|
-
m.packet ? /* @__PURE__ */ (0,
|
|
10430
|
+
m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
|
|
10431
|
+
m.packet ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
10239
10432
|
PacketCard,
|
|
10240
10433
|
{
|
|
10241
10434
|
packet: m.packet,
|
|
@@ -10245,44 +10438,44 @@ function MessageBody({ message: m, ctx }) {
|
|
|
10245
10438
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
10246
10439
|
}
|
|
10247
10440
|
) : null,
|
|
10248
|
-
m.citations && m.citations.length ? /* @__PURE__ */ (0,
|
|
10249
|
-
m.working ? /* @__PURE__ */ (0,
|
|
10250
|
-
/* @__PURE__ */ (0,
|
|
10251
|
-
/* @__PURE__ */ (0,
|
|
10252
|
-
/* @__PURE__ */ (0,
|
|
10253
|
-
/* @__PURE__ */ (0,
|
|
10441
|
+
m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
|
|
10442
|
+
m.working ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-working", role: "status", children: [
|
|
10443
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
10444
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10445
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10446
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {})
|
|
10254
10447
|
] }),
|
|
10255
|
-
/* @__PURE__ */ (0,
|
|
10448
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-label", children: [
|
|
10256
10449
|
m.resumed ? "Resuming" : "Working",
|
|
10257
|
-
m.job && m.job.status ? /* @__PURE__ */ (0,
|
|
10450
|
+
m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-job", children: [
|
|
10258
10451
|
" \xB7 ",
|
|
10259
10452
|
m.job.status
|
|
10260
10453
|
] }) : null,
|
|
10261
|
-
m.job && m.job.detail ? /* @__PURE__ */ (0,
|
|
10454
|
+
m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-job", children: [
|
|
10262
10455
|
" \xB7 ",
|
|
10263
10456
|
m.job.detail
|
|
10264
10457
|
] }) : null
|
|
10265
10458
|
] }),
|
|
10266
|
-
m.jobId ? /* @__PURE__ */ (0,
|
|
10459
|
+
m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
10267
10460
|
] }) : null,
|
|
10268
|
-
m.stopped ? /* @__PURE__ */ (0,
|
|
10269
|
-
/* @__PURE__ */ (0,
|
|
10461
|
+
m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-stopped", children: [
|
|
10462
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
10270
10463
|
"Stopped"
|
|
10271
10464
|
] }) : null,
|
|
10272
|
-
m.error ? /* @__PURE__ */ (0,
|
|
10273
|
-
/* @__PURE__ */ (0,
|
|
10274
|
-
/* @__PURE__ */ (0,
|
|
10275
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
10276
|
-
/* @__PURE__ */ (0,
|
|
10465
|
+
m.error ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-error", role: "alert", children: [
|
|
10466
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10467
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
|
|
10468
|
+
m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
|
|
10469
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
10277
10470
|
"Retry"
|
|
10278
10471
|
] }) : null
|
|
10279
10472
|
] }) : null
|
|
10280
10473
|
] });
|
|
10281
10474
|
}
|
|
10282
10475
|
function useCopyRun() {
|
|
10283
|
-
const [done, setDone] =
|
|
10284
|
-
const t =
|
|
10285
|
-
|
|
10476
|
+
const [done, setDone] = React52.useState(false);
|
|
10477
|
+
const t = React52.useRef(null);
|
|
10478
|
+
React52.useEffect(() => () => {
|
|
10286
10479
|
if (t.current) clearTimeout(t.current);
|
|
10287
10480
|
}, []);
|
|
10288
10481
|
return [done, (text) => {
|
|
@@ -10302,16 +10495,16 @@ function RunActions({ group, ctx }) {
|
|
|
10302
10495
|
const isAssistant = group.role === "assistant";
|
|
10303
10496
|
const fb = last.feedback;
|
|
10304
10497
|
if (!ctx.messageActions) return null;
|
|
10305
|
-
return /* @__PURE__ */ (0,
|
|
10306
|
-
/* @__PURE__ */ (0,
|
|
10307
|
-
/* @__PURE__ */ (0,
|
|
10308
|
-
/* @__PURE__ */ (0,
|
|
10498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
|
|
10499
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
|
|
10500
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
|
|
10501
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
|
|
10309
10502
|
] }),
|
|
10310
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
10311
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0,
|
|
10312
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0,
|
|
10313
|
-
/* @__PURE__ */ (0,
|
|
10314
|
-
/* @__PURE__ */ (0,
|
|
10503
|
+
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
10504
|
+
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
10505
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(React52.Fragment, { children: [
|
|
10506
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
10507
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
10315
10508
|
] }) : null,
|
|
10316
10509
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
10317
10510
|
] });
|
|
@@ -10321,22 +10514,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
10321
10514
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
10322
10515
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
10323
10516
|
const stamp = group.messages[0].timestamp;
|
|
10324
|
-
return /* @__PURE__ */ (0,
|
|
10325
|
-
/* @__PURE__ */ (0,
|
|
10326
|
-
ctx.showAvatars ? /* @__PURE__ */ (0,
|
|
10327
|
-
/* @__PURE__ */ (0,
|
|
10328
|
-
stamp ? /* @__PURE__ */ (0,
|
|
10329
|
-
group.messages.some((m) => m.model) ? /* @__PURE__ */ (0,
|
|
10517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
|
|
10518
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-turn-head", children: [
|
|
10519
|
+
ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
|
|
10520
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-who", children: name }),
|
|
10521
|
+
stamp ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
|
|
10522
|
+
group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
|
|
10330
10523
|
] }),
|
|
10331
|
-
/* @__PURE__ */ (0,
|
|
10332
|
-
group.messages.map((m) => /* @__PURE__ */ (0,
|
|
10333
|
-
/* @__PURE__ */ (0,
|
|
10524
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-turn-body", children: [
|
|
10525
|
+
group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
|
|
10526
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(RunActions, { group, ctx })
|
|
10334
10527
|
] })
|
|
10335
10528
|
] });
|
|
10336
10529
|
}
|
|
10337
10530
|
|
|
10338
10531
|
// src/components/chat/ChatTranscript.tsx
|
|
10339
|
-
var
|
|
10532
|
+
var import_jsx_runtime82 = require("react/jsx-runtime");
|
|
10340
10533
|
var GROUP_WINDOW = 6e4;
|
|
10341
10534
|
var STICK_PX = 100;
|
|
10342
10535
|
function groupMessages(list) {
|
|
@@ -10369,25 +10562,25 @@ function dayLabel(key) {
|
|
|
10369
10562
|
}
|
|
10370
10563
|
function Suggestions({ items = [], onPick }) {
|
|
10371
10564
|
if (!items.length) return null;
|
|
10372
|
-
return /* @__PURE__ */ (0,
|
|
10565
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
10373
10566
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
10374
|
-
return /* @__PURE__ */ (0,
|
|
10375
|
-
it.icon ? /* @__PURE__ */ (0,
|
|
10376
|
-
/* @__PURE__ */ (0,
|
|
10377
|
-
/* @__PURE__ */ (0,
|
|
10378
|
-
it.description ? /* @__PURE__ */ (0,
|
|
10567
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
|
|
10568
|
+
it.icon ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
|
|
10569
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fdc-suggest-text", children: [
|
|
10570
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
|
|
10571
|
+
it.description ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
|
|
10379
10572
|
] }),
|
|
10380
|
-
/* @__PURE__ */ (0,
|
|
10573
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
10381
10574
|
] }, it.id || i);
|
|
10382
10575
|
}) });
|
|
10383
10576
|
}
|
|
10384
10577
|
function LoadingTurns() {
|
|
10385
|
-
return /* @__PURE__ */ (0,
|
|
10386
|
-
/* @__PURE__ */ (0,
|
|
10387
|
-
/* @__PURE__ */ (0,
|
|
10388
|
-
/* @__PURE__ */ (0,
|
|
10389
|
-
/* @__PURE__ */ (0,
|
|
10390
|
-
/* @__PURE__ */ (0,
|
|
10578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-skel-turn", children: [
|
|
10579
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
|
|
10580
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-skel-lines", children: [
|
|
10581
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
|
|
10582
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
|
|
10583
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
|
|
10391
10584
|
] })
|
|
10392
10585
|
] }, i)) });
|
|
10393
10586
|
}
|
|
@@ -10404,10 +10597,10 @@ function ChatTranscript({
|
|
|
10404
10597
|
renderEmpty,
|
|
10405
10598
|
className = ""
|
|
10406
10599
|
}) {
|
|
10407
|
-
const scroller =
|
|
10408
|
-
const stick =
|
|
10409
|
-
const [pill, setPill] =
|
|
10410
|
-
const seen =
|
|
10600
|
+
const scroller = React53.useRef(null);
|
|
10601
|
+
const stick = React53.useRef(true);
|
|
10602
|
+
const [pill, setPill] = React53.useState(0);
|
|
10603
|
+
const seen = React53.useRef(0);
|
|
10411
10604
|
const toBottom = (smooth) => {
|
|
10412
10605
|
const el = scroller.current;
|
|
10413
10606
|
if (!el) return;
|
|
@@ -10426,7 +10619,7 @@ function ChatTranscript({
|
|
|
10426
10619
|
seen.current = messages.length;
|
|
10427
10620
|
}
|
|
10428
10621
|
};
|
|
10429
|
-
|
|
10622
|
+
React53.useLayoutEffect(() => {
|
|
10430
10623
|
const el = scroller.current;
|
|
10431
10624
|
if (!el) return;
|
|
10432
10625
|
if (stick.current) {
|
|
@@ -10434,7 +10627,7 @@ function ChatTranscript({
|
|
|
10434
10627
|
seen.current = messages.length;
|
|
10435
10628
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
10436
10629
|
}, [messages]);
|
|
10437
|
-
|
|
10630
|
+
React53.useEffect(() => {
|
|
10438
10631
|
const el = scroller.current;
|
|
10439
10632
|
const inner = el && el.firstChild;
|
|
10440
10633
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -10444,38 +10637,38 @@ function ChatTranscript({
|
|
|
10444
10637
|
ro.observe(inner);
|
|
10445
10638
|
return () => ro.disconnect();
|
|
10446
10639
|
}, []);
|
|
10447
|
-
const groups =
|
|
10640
|
+
const groups = React53.useMemo(() => groupMessages(messages), [messages]);
|
|
10448
10641
|
const empty = !messages.length && status === "ready";
|
|
10449
|
-
return /* @__PURE__ */ (0,
|
|
10450
|
-
/* @__PURE__ */ (0,
|
|
10451
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */ (0,
|
|
10452
|
-
status === "disconnected" ? /* @__PURE__ */ (0,
|
|
10453
|
-
/* @__PURE__ */ (0,
|
|
10454
|
-
/* @__PURE__ */ (0,
|
|
10455
|
-
/* @__PURE__ */ (0,
|
|
10456
|
-
ctx.onReconnect ? /* @__PURE__ */ (0,
|
|
10457
|
-
/* @__PURE__ */ (0,
|
|
10642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
10643
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
10644
|
+
status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(LoadingTurns, {}) : null,
|
|
10645
|
+
status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-dead", children: [
|
|
10646
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
|
|
10647
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
|
|
10648
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
|
|
10649
|
+
ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
|
|
10650
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
10458
10651
|
"Try again"
|
|
10459
10652
|
] }) : null
|
|
10460
10653
|
] }) : null,
|
|
10461
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0,
|
|
10462
|
-
/* @__PURE__ */ (0,
|
|
10463
|
-
/* @__PURE__ */ (0,
|
|
10464
|
-
emptyDescription ? /* @__PURE__ */ (0,
|
|
10465
|
-
/* @__PURE__ */ (0,
|
|
10654
|
+
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-empty", children: [
|
|
10655
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
|
|
10656
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
|
|
10657
|
+
emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
|
|
10658
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Suggestions, { items: suggestions, onPick })
|
|
10466
10659
|
] }) : null,
|
|
10467
10660
|
groups.map((g, i) => {
|
|
10468
10661
|
const prev = groups[i - 1];
|
|
10469
10662
|
const k = dayKey(g.messages[0].timestamp);
|
|
10470
10663
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
10471
|
-
return /* @__PURE__ */ (0,
|
|
10472
|
-
showDay ? /* @__PURE__ */ (0,
|
|
10473
|
-
/* @__PURE__ */ (0,
|
|
10664
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(React53.Fragment, { children: [
|
|
10665
|
+
showDay ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { children: dayLabel(k) }) }) : null,
|
|
10666
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(ChatTurn, { group: g, ctx })
|
|
10474
10667
|
] }, g.key || i);
|
|
10475
10668
|
})
|
|
10476
10669
|
] }),
|
|
10477
|
-
pill ? /* @__PURE__ */ (0,
|
|
10478
|
-
/* @__PURE__ */ (0,
|
|
10670
|
+
pill ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
|
|
10671
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
|
|
10479
10672
|
pill,
|
|
10480
10673
|
" new message",
|
|
10481
10674
|
pill === 1 ? "" : "s"
|
|
@@ -10485,8 +10678,8 @@ function ChatTranscript({
|
|
|
10485
10678
|
var TranscriptKit = { groupMessages };
|
|
10486
10679
|
|
|
10487
10680
|
// src/components/chat/ChatComposer.tsx
|
|
10488
|
-
var
|
|
10489
|
-
var
|
|
10681
|
+
var React54 = __toESM(require("react"), 1);
|
|
10682
|
+
var import_jsx_runtime83 = require("react/jsx-runtime");
|
|
10490
10683
|
function ChatComposer({
|
|
10491
10684
|
onSubmit,
|
|
10492
10685
|
onStop,
|
|
@@ -10513,17 +10706,17 @@ function ChatComposer({
|
|
|
10513
10706
|
onReject,
|
|
10514
10707
|
onOpenAttachment
|
|
10515
10708
|
}) {
|
|
10516
|
-
const [text, setText] =
|
|
10517
|
-
const [trigger, setTrigger] =
|
|
10518
|
-
const [mentionItems, setMentionItems] =
|
|
10519
|
-
const [listening, setListening] =
|
|
10520
|
-
const [notice, setNotice] =
|
|
10521
|
-
const editor =
|
|
10522
|
-
const wrap =
|
|
10523
|
-
const stopVoice =
|
|
10709
|
+
const [text, setText] = React54.useState(draft || "");
|
|
10710
|
+
const [trigger, setTrigger] = React54.useState(null);
|
|
10711
|
+
const [mentionItems, setMentionItems] = React54.useState([]);
|
|
10712
|
+
const [listening, setListening] = React54.useState(false);
|
|
10713
|
+
const [notice, setNotice] = React54.useState(null);
|
|
10714
|
+
const editor = React54.useRef(null);
|
|
10715
|
+
const wrap = React54.useRef(null);
|
|
10716
|
+
const stopVoice = React54.useRef(null);
|
|
10524
10717
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
10525
10718
|
} });
|
|
10526
|
-
|
|
10719
|
+
React54.useEffect(() => {
|
|
10527
10720
|
if (draft != null && draft !== text) setText(draft);
|
|
10528
10721
|
}, [draft]);
|
|
10529
10722
|
const change = (v) => {
|
|
@@ -10559,7 +10752,7 @@ function ChatComposer({
|
|
|
10559
10752
|
e.preventDefault();
|
|
10560
10753
|
staged.add(found.files);
|
|
10561
10754
|
};
|
|
10562
|
-
|
|
10755
|
+
React54.useEffect(() => {
|
|
10563
10756
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
10564
10757
|
setMentionItems([]);
|
|
10565
10758
|
return;
|
|
@@ -10577,7 +10770,7 @@ function ChatComposer({
|
|
|
10577
10770
|
const q = (trigger.query || "").toLowerCase();
|
|
10578
10771
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
10579
10772
|
}, [trigger, mentionSources]);
|
|
10580
|
-
const slashItems =
|
|
10773
|
+
const slashItems = React54.useMemo(() => {
|
|
10581
10774
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
10582
10775
|
const q = (trigger.query || "").toLowerCase();
|
|
10583
10776
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -10591,7 +10784,7 @@ function ChatComposer({
|
|
|
10591
10784
|
description: it.description,
|
|
10592
10785
|
icon: it.icon,
|
|
10593
10786
|
meta: mention.meta,
|
|
10594
|
-
shortcut: slash.shortcut ? /* @__PURE__ */ (0,
|
|
10787
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
10595
10788
|
onSelect: () => {
|
|
10596
10789
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
10597
10790
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -10654,14 +10847,14 @@ function ChatComposer({
|
|
|
10654
10847
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
10655
10848
|
};
|
|
10656
10849
|
};
|
|
10657
|
-
return /* @__PURE__ */ (0,
|
|
10658
|
-
queue.length ? /* @__PURE__ */ (0,
|
|
10659
|
-
/* @__PURE__ */ (0,
|
|
10660
|
-
/* @__PURE__ */ (0,
|
|
10661
|
-
onRemoveQueued ? /* @__PURE__ */ (0,
|
|
10850
|
+
return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
|
|
10851
|
+
queue.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-queue-row", children: [
|
|
10852
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
|
|
10853
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-queue-text", title: truncationTitle(q.text || (q.attachments ? q.attachments.length + " file(s)" : "")), children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
|
|
10854
|
+
onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
10662
10855
|
] }, q.id)) }) : null,
|
|
10663
10856
|
sessionBar,
|
|
10664
|
-
/* @__PURE__ */ (0,
|
|
10857
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10665
10858
|
Dropzone,
|
|
10666
10859
|
{
|
|
10667
10860
|
className: "fdc-field",
|
|
@@ -10675,9 +10868,9 @@ function ChatComposer({
|
|
|
10675
10868
|
disabled: !fileUploadHandler || disabled,
|
|
10676
10869
|
label: "Drop to attach",
|
|
10677
10870
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
10678
|
-
children: /* @__PURE__ */ (0,
|
|
10679
|
-
staged.items.length ? /* @__PURE__ */ (0,
|
|
10680
|
-
/* @__PURE__ */ (0,
|
|
10871
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
|
|
10872
|
+
staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
|
|
10873
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10681
10874
|
MarkdownEditor,
|
|
10682
10875
|
{
|
|
10683
10876
|
ref: editor,
|
|
@@ -10696,33 +10889,33 @@ function ChatComposer({
|
|
|
10696
10889
|
ariaLabel: "Message"
|
|
10697
10890
|
}
|
|
10698
10891
|
),
|
|
10699
|
-
/* @__PURE__ */ (0,
|
|
10700
|
-
fileUploadHandler ? /* @__PURE__ */ (0,
|
|
10701
|
-
voiceHandler ? /* @__PURE__ */ (0,
|
|
10892
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-tools", children: [
|
|
10893
|
+
fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
|
|
10894
|
+
voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
|
|
10702
10895
|
toolbarExtras,
|
|
10703
|
-
/* @__PURE__ */ (0,
|
|
10704
|
-
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0,
|
|
10896
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-tools-gap" }),
|
|
10897
|
+
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
|
|
10705
10898
|
text.length,
|
|
10706
10899
|
"/",
|
|
10707
10900
|
maxLength
|
|
10708
10901
|
] }) : null,
|
|
10709
|
-
busy ? /* @__PURE__ */ (0,
|
|
10710
|
-
/* @__PURE__ */ (0,
|
|
10711
|
-
/* @__PURE__ */ (0,
|
|
10712
|
-
] }) : /* @__PURE__ */ (0,
|
|
10713
|
-
/* @__PURE__ */ (0,
|
|
10714
|
-
/* @__PURE__ */ (0,
|
|
10902
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
|
|
10903
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
10904
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: "Stop" })
|
|
10905
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
|
|
10906
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
|
|
10907
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-send-label", children: "Send" })
|
|
10715
10908
|
] })
|
|
10716
10909
|
] })
|
|
10717
10910
|
] })
|
|
10718
10911
|
}
|
|
10719
10912
|
),
|
|
10720
|
-
notice ? /* @__PURE__ */ (0,
|
|
10721
|
-
/* @__PURE__ */ (0,
|
|
10913
|
+
notice ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-notice", role: "status", children: [
|
|
10914
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10722
10915
|
notice
|
|
10723
10916
|
] }) : null,
|
|
10724
|
-
hint && !notice ? /* @__PURE__ */ (0,
|
|
10725
|
-
/* @__PURE__ */ (0,
|
|
10917
|
+
hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-hint", children: hint }) : null,
|
|
10918
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10726
10919
|
Popover,
|
|
10727
10920
|
{
|
|
10728
10921
|
open: menuOpen,
|
|
@@ -10736,12 +10929,12 @@ function ChatComposer({
|
|
|
10736
10929
|
returnFocus: false,
|
|
10737
10930
|
closeOnOutside: true,
|
|
10738
10931
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
10739
|
-
children: /* @__PURE__ */ (0,
|
|
10932
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10740
10933
|
Menu,
|
|
10741
10934
|
{
|
|
10742
10935
|
items: menuItems,
|
|
10743
10936
|
autoFocus: false,
|
|
10744
|
-
header: /* @__PURE__ */ (0,
|
|
10937
|
+
header: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
10745
10938
|
onClose: () => setTrigger(null)
|
|
10746
10939
|
}
|
|
10747
10940
|
)
|
|
@@ -10751,12 +10944,12 @@ function ChatComposer({
|
|
|
10751
10944
|
}
|
|
10752
10945
|
|
|
10753
10946
|
// src/components/chat/ChatSessionBar.tsx
|
|
10754
|
-
var
|
|
10755
|
-
var
|
|
10947
|
+
var React55 = __toESM(require("react"), 1);
|
|
10948
|
+
var import_jsx_runtime84 = require("react/jsx-runtime");
|
|
10756
10949
|
var compact2 = meterFormats.compact;
|
|
10757
10950
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
10758
|
-
const [open, setOpen] =
|
|
10759
|
-
const anchor =
|
|
10951
|
+
const [open, setOpen] = React55.useState(false);
|
|
10952
|
+
const anchor = React55.useRef(null);
|
|
10760
10953
|
const stats = sessionStats || null;
|
|
10761
10954
|
const cu = contextUsage || null;
|
|
10762
10955
|
const limits = usageLimits || null;
|
|
@@ -10771,9 +10964,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10771
10964
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
10772
10965
|
if (cu) bits.push(pct + "% context");
|
|
10773
10966
|
const expandable = !!(cu || limits);
|
|
10774
|
-
return /* @__PURE__ */ (0,
|
|
10775
|
-
/* @__PURE__ */ (0,
|
|
10776
|
-
/* @__PURE__ */ (0,
|
|
10967
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(React55.Fragment, { children: [
|
|
10968
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fdc-bar", children: [
|
|
10969
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
|
|
10777
10970
|
"button",
|
|
10778
10971
|
{
|
|
10779
10972
|
type: "button",
|
|
@@ -10784,15 +10977,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10784
10977
|
"aria-expanded": expandable ? open : void 0,
|
|
10785
10978
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
10786
10979
|
children: [
|
|
10787
|
-
cu ? /* @__PURE__ */ (0,
|
|
10788
|
-
/* @__PURE__ */ (0,
|
|
10789
|
-
expandable ? /* @__PURE__ */ (0,
|
|
10980
|
+
cu ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
|
|
10981
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
|
|
10982
|
+
expandable ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
|
|
10790
10983
|
]
|
|
10791
10984
|
}
|
|
10792
10985
|
),
|
|
10793
10986
|
extras
|
|
10794
10987
|
] }),
|
|
10795
|
-
/* @__PURE__ */ (0,
|
|
10988
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10796
10989
|
Popover,
|
|
10797
10990
|
{
|
|
10798
10991
|
open,
|
|
@@ -10803,15 +10996,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10803
10996
|
maxHeight: 460,
|
|
10804
10997
|
padded: true,
|
|
10805
10998
|
label: "Usage",
|
|
10806
|
-
footer: onClear ? /* @__PURE__ */ (0,
|
|
10999
|
+
footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
10807
11000
|
setOpen(false);
|
|
10808
11001
|
onClear();
|
|
10809
11002
|
}, children: [
|
|
10810
|
-
/* @__PURE__ */ (0,
|
|
11003
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
10811
11004
|
"Clear conversation"
|
|
10812
11005
|
] }) : void 0,
|
|
10813
|
-
children: /* @__PURE__ */ (0,
|
|
10814
|
-
cu ? /* @__PURE__ */ (0,
|
|
11006
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fdc-usage", children: [
|
|
11007
|
+
cu ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10815
11008
|
SegmentedMeter,
|
|
10816
11009
|
{
|
|
10817
11010
|
total,
|
|
@@ -10823,9 +11016,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10823
11016
|
remainderLabel: "Free"
|
|
10824
11017
|
}
|
|
10825
11018
|
) }) : null,
|
|
10826
|
-
limits && limits.length ? /* @__PURE__ */ (0,
|
|
10827
|
-
/* @__PURE__ */ (0,
|
|
10828
|
-
/* @__PURE__ */ (0,
|
|
11019
|
+
limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { className: "fdc-usage-sec", children: [
|
|
11020
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
11021
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10829
11022
|
QuotaRow,
|
|
10830
11023
|
{
|
|
10831
11024
|
label: l.label,
|
|
@@ -10835,25 +11028,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10835
11028
|
l.id
|
|
10836
11029
|
)) })
|
|
10837
11030
|
] }) : null,
|
|
10838
|
-
stats ? /* @__PURE__ */ (0,
|
|
10839
|
-
stats.elapsedMs ? /* @__PURE__ */ (0,
|
|
10840
|
-
/* @__PURE__ */ (0,
|
|
10841
|
-
/* @__PURE__ */ (0,
|
|
11031
|
+
stats ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
11032
|
+
stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11033
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Session" }),
|
|
11034
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
10842
11035
|
] }) : null,
|
|
10843
|
-
stats.tokens ? /* @__PURE__ */ (0,
|
|
10844
|
-
/* @__PURE__ */ (0,
|
|
10845
|
-
/* @__PURE__ */ (0,
|
|
11036
|
+
stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11037
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Tokens" }),
|
|
11038
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
10846
11039
|
] }) : null,
|
|
10847
|
-
stats.costUsd != null ? /* @__PURE__ */ (0,
|
|
10848
|
-
/* @__PURE__ */ (0,
|
|
10849
|
-
/* @__PURE__ */ (0,
|
|
11040
|
+
stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11041
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Cost" }),
|
|
11042
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("b", { className: "fd-tabular", children: [
|
|
10850
11043
|
"$",
|
|
10851
11044
|
Number(stats.costUsd).toFixed(3)
|
|
10852
11045
|
] })
|
|
10853
11046
|
] }) : null,
|
|
10854
|
-
stats.turns ? /* @__PURE__ */ (0,
|
|
10855
|
-
/* @__PURE__ */ (0,
|
|
10856
|
-
/* @__PURE__ */ (0,
|
|
11047
|
+
stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11048
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Turns" }),
|
|
11049
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: stats.turns })
|
|
10857
11050
|
] }) : null
|
|
10858
11051
|
] }) : null
|
|
10859
11052
|
] })
|
|
@@ -10892,7 +11085,7 @@ function ModelControls({
|
|
|
10892
11085
|
disabled: m.disabled,
|
|
10893
11086
|
checked: m.id === (current2 && current2.id),
|
|
10894
11087
|
meta: m.meta,
|
|
10895
|
-
shortcut: m.shortcut ? /* @__PURE__ */ (0,
|
|
11088
|
+
shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
10896
11089
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
10897
11090
|
});
|
|
10898
11091
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -10905,15 +11098,15 @@ function ModelControls({
|
|
|
10905
11098
|
items.push({ kind: "section", label: "Fast mode" });
|
|
10906
11099
|
items.push({
|
|
10907
11100
|
kind: "custom",
|
|
10908
|
-
render: () => /* @__PURE__ */ (0,
|
|
10909
|
-
/* @__PURE__ */ (0,
|
|
10910
|
-
/* @__PURE__ */ (0,
|
|
10911
|
-
/* @__PURE__ */ (0,
|
|
11101
|
+
render: () => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("label", { className: "fdc-switchrow", children: [
|
|
11102
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: fastModeLabel }),
|
|
11103
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
|
|
11104
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-switch-thumb" }) })
|
|
10912
11105
|
] })
|
|
10913
11106
|
});
|
|
10914
11107
|
}
|
|
10915
|
-
return /* @__PURE__ */ (0,
|
|
10916
|
-
/* @__PURE__ */ (0,
|
|
11108
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(React55.Fragment, { children: [
|
|
11109
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10917
11110
|
MenuButton,
|
|
10918
11111
|
{
|
|
10919
11112
|
items,
|
|
@@ -10924,7 +11117,7 @@ function ModelControls({
|
|
|
10924
11117
|
title: "Choose a model"
|
|
10925
11118
|
}
|
|
10926
11119
|
),
|
|
10927
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */ (0,
|
|
11120
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10928
11121
|
MenuButton,
|
|
10929
11122
|
{
|
|
10930
11123
|
placement: "top-end",
|
|
@@ -10945,7 +11138,7 @@ function ModelControls({
|
|
|
10945
11138
|
}
|
|
10946
11139
|
|
|
10947
11140
|
// src/components/chat/AgentChatPanel.tsx
|
|
10948
|
-
var
|
|
11141
|
+
var import_jsx_runtime85 = require("react/jsx-runtime");
|
|
10949
11142
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
10950
11143
|
function AgentChatPanel({
|
|
10951
11144
|
/* required */
|
|
@@ -11029,11 +11222,11 @@ function AgentChatPanel({
|
|
|
11029
11222
|
onFeedback,
|
|
11030
11223
|
onEditMessage
|
|
11031
11224
|
}) {
|
|
11032
|
-
const [panelWidth, setPanelWidth] =
|
|
11033
|
-
const [applied, setApplied] =
|
|
11034
|
-
const [draft, setDraft] =
|
|
11035
|
-
const dragging =
|
|
11036
|
-
|
|
11225
|
+
const [panelWidth, setPanelWidth] = React56.useState(width);
|
|
11226
|
+
const [applied, setApplied] = React56.useState({});
|
|
11227
|
+
const [draft, setDraft] = React56.useState("");
|
|
11228
|
+
const dragging = React56.useRef(null);
|
|
11229
|
+
React56.useEffect(() => setPanelWidth(width), [width]);
|
|
11037
11230
|
const engine = useChatEngine({
|
|
11038
11231
|
contextType,
|
|
11039
11232
|
contextId,
|
|
@@ -11099,7 +11292,7 @@ function AgentChatPanel({
|
|
|
11099
11292
|
onReconnect: engine.reload,
|
|
11100
11293
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
11101
11294
|
};
|
|
11102
|
-
const sessionBar = /* @__PURE__ */ (0,
|
|
11295
|
+
const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11103
11296
|
ChatSessionBar,
|
|
11104
11297
|
{
|
|
11105
11298
|
sessionStats,
|
|
@@ -11108,7 +11301,7 @@ function AgentChatPanel({
|
|
|
11108
11301
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
11109
11302
|
}
|
|
11110
11303
|
);
|
|
11111
|
-
const modelControls = /* @__PURE__ */ (0,
|
|
11304
|
+
const modelControls = /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11112
11305
|
ModelControls,
|
|
11113
11306
|
{
|
|
11114
11307
|
models,
|
|
@@ -11123,7 +11316,7 @@ function AgentChatPanel({
|
|
|
11123
11316
|
narrow
|
|
11124
11317
|
}
|
|
11125
11318
|
);
|
|
11126
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0,
|
|
11319
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11127
11320
|
MenuButton,
|
|
11128
11321
|
{
|
|
11129
11322
|
variant: "ghost",
|
|
@@ -11150,7 +11343,7 @@ function AgentChatPanel({
|
|
|
11150
11343
|
})))
|
|
11151
11344
|
}
|
|
11152
11345
|
) : null;
|
|
11153
|
-
return /* @__PURE__ */ (0,
|
|
11346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
|
|
11154
11347
|
"aside",
|
|
11155
11348
|
{
|
|
11156
11349
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -11161,7 +11354,7 @@ function AgentChatPanel({
|
|
|
11161
11354
|
},
|
|
11162
11355
|
"aria-label": title,
|
|
11163
11356
|
children: [
|
|
11164
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */ (0,
|
|
11357
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11165
11358
|
"div",
|
|
11166
11359
|
{
|
|
11167
11360
|
className: "fdc-grip",
|
|
@@ -11176,20 +11369,20 @@ function AgentChatPanel({
|
|
|
11176
11369
|
}
|
|
11177
11370
|
}
|
|
11178
11371
|
) : null,
|
|
11179
|
-
showHeader ? /* @__PURE__ */ (0,
|
|
11180
|
-
/* @__PURE__ */ (0,
|
|
11181
|
-
/* @__PURE__ */ (0,
|
|
11182
|
-
/* @__PURE__ */ (0,
|
|
11183
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
11372
|
+
showHeader ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("header", { className: "fdc-head", children: [
|
|
11373
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
|
|
11374
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fdc-head-titles", children: [
|
|
11375
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
|
|
11376
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
|
|
11184
11377
|
] }),
|
|
11185
|
-
/* @__PURE__ */ (0,
|
|
11378
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fdc-head-acts", children: [
|
|
11186
11379
|
headerActions,
|
|
11187
11380
|
threadMenu,
|
|
11188
|
-
onNewThread ? /* @__PURE__ */ (0,
|
|
11189
|
-
onClose ? /* @__PURE__ */ (0,
|
|
11381
|
+
onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
|
|
11382
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
11190
11383
|
] })
|
|
11191
11384
|
] }) : null,
|
|
11192
|
-
/* @__PURE__ */ (0,
|
|
11385
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11193
11386
|
ChatTranscript,
|
|
11194
11387
|
{
|
|
11195
11388
|
messages: engine.visible,
|
|
@@ -11204,7 +11397,7 @@ function AgentChatPanel({
|
|
|
11204
11397
|
renderEmpty
|
|
11205
11398
|
}
|
|
11206
11399
|
),
|
|
11207
|
-
/* @__PURE__ */ (0,
|
|
11400
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11208
11401
|
ChatComposer,
|
|
11209
11402
|
{
|
|
11210
11403
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -11237,8 +11430,8 @@ function AgentChatPanel({
|
|
|
11237
11430
|
}
|
|
11238
11431
|
|
|
11239
11432
|
// src/components/files/FileViewer.tsx
|
|
11240
|
-
var
|
|
11241
|
-
var
|
|
11433
|
+
var React57 = __toESM(require("react"), 1);
|
|
11434
|
+
var import_jsx_runtime86 = require("react/jsx-runtime");
|
|
11242
11435
|
function previewKindOf(file) {
|
|
11243
11436
|
const mime = (file.mime || "").toLowerCase();
|
|
11244
11437
|
const ext = extensionOf(file.name || "");
|
|
@@ -11294,13 +11487,13 @@ function parseDelimited(text, delimiter) {
|
|
|
11294
11487
|
return rows;
|
|
11295
11488
|
}
|
|
11296
11489
|
function usePreview(file, kind, resolveUrl) {
|
|
11297
|
-
const [state, setState] =
|
|
11298
|
-
const [attempt, setAttempt] =
|
|
11299
|
-
const resolveRef =
|
|
11300
|
-
|
|
11490
|
+
const [state, setState] = React57.useState({ status: "loading" });
|
|
11491
|
+
const [attempt, setAttempt] = React57.useState(0);
|
|
11492
|
+
const resolveRef = React57.useRef(resolveUrl);
|
|
11493
|
+
React57.useEffect(() => {
|
|
11301
11494
|
resolveRef.current = resolveUrl;
|
|
11302
11495
|
}, [resolveUrl]);
|
|
11303
|
-
|
|
11496
|
+
React57.useEffect(() => {
|
|
11304
11497
|
if (kind === "none") {
|
|
11305
11498
|
setState({ status: "ready" });
|
|
11306
11499
|
return;
|
|
@@ -11330,19 +11523,19 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
11330
11523
|
if (ac) ac.abort();
|
|
11331
11524
|
};
|
|
11332
11525
|
}, [file.id, kind, attempt]);
|
|
11333
|
-
return { ...state, retry:
|
|
11526
|
+
return { ...state, retry: React57.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
11334
11527
|
}
|
|
11335
11528
|
function PreviewBody({ file, kind, state }) {
|
|
11336
|
-
if (kind === "image") return /* @__PURE__ */ (0,
|
|
11337
|
-
if (kind === "pdf") return /* @__PURE__ */ (0,
|
|
11338
|
-
if (kind === "markdown") return /* @__PURE__ */ (0,
|
|
11529
|
+
if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
11530
|
+
if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
|
|
11531
|
+
if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
|
|
11339
11532
|
if (kind === "json") {
|
|
11340
11533
|
let pretty = state.text || "";
|
|
11341
11534
|
try {
|
|
11342
11535
|
pretty = JSON.stringify(JSON.parse(pretty), null, 2);
|
|
11343
11536
|
} catch {
|
|
11344
11537
|
}
|
|
11345
|
-
return /* @__PURE__ */ (0,
|
|
11538
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CodeBlock, { code: pretty, language: "json" });
|
|
11346
11539
|
}
|
|
11347
11540
|
if (kind === "csv") {
|
|
11348
11541
|
const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
|
|
@@ -11350,12 +11543,12 @@ function PreviewBody({ file, kind, state }) {
|
|
|
11350
11543
|
const head = rows[0] || [];
|
|
11351
11544
|
const dataRows = rows.slice(1);
|
|
11352
11545
|
const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
|
|
11353
|
-
return /* @__PURE__ */ (0,
|
|
11354
|
-
/* @__PURE__ */ (0,
|
|
11355
|
-
/* @__PURE__ */ (0,
|
|
11356
|
-
/* @__PURE__ */ (0,
|
|
11546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-csv", children: [
|
|
11547
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("table", { className: "fd-fv-csv-table", children: [
|
|
11548
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("th", { children: c }, i)) }) }),
|
|
11549
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
|
|
11357
11550
|
] }),
|
|
11358
|
-
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0,
|
|
11551
|
+
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
|
|
11359
11552
|
"Showing the first ",
|
|
11360
11553
|
FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
|
|
11361
11554
|
" of ",
|
|
@@ -11364,24 +11557,24 @@ function PreviewBody({ file, kind, state }) {
|
|
|
11364
11557
|
] }) : null
|
|
11365
11558
|
] });
|
|
11366
11559
|
}
|
|
11367
|
-
if (kind === "text") return /* @__PURE__ */ (0,
|
|
11368
|
-
return /* @__PURE__ */ (0,
|
|
11369
|
-
/* @__PURE__ */ (0,
|
|
11370
|
-
/* @__PURE__ */ (0,
|
|
11371
|
-
/* @__PURE__ */ (0,
|
|
11560
|
+
if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
|
|
11561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-fallback", children: [
|
|
11562
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
11563
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
|
|
11564
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
|
|
11372
11565
|
file.mime || "Unknown type",
|
|
11373
11566
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
11374
11567
|
] })
|
|
11375
11568
|
] });
|
|
11376
11569
|
}
|
|
11377
11570
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
11378
|
-
const kind =
|
|
11571
|
+
const kind = React57.useMemo(() => previewKindOf(file), [file]);
|
|
11379
11572
|
const preview = usePreview(file, kind, resolveUrl);
|
|
11380
|
-
const [tab, setTab] =
|
|
11381
|
-
const [downloading, setDownloading] =
|
|
11382
|
-
const [downloadError, setDownloadError] =
|
|
11573
|
+
const [tab, setTab] = React57.useState("preview");
|
|
11574
|
+
const [downloading, setDownloading] = React57.useState(false);
|
|
11575
|
+
const [downloadError, setDownloadError] = React57.useState(null);
|
|
11383
11576
|
const hasSide = sidePanel != null;
|
|
11384
|
-
|
|
11577
|
+
React57.useEffect(() => {
|
|
11385
11578
|
setTab("preview");
|
|
11386
11579
|
}, [file.id]);
|
|
11387
11580
|
const download = () => {
|
|
@@ -11397,29 +11590,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11397
11590
|
a.remove();
|
|
11398
11591
|
}).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
|
|
11399
11592
|
};
|
|
11400
|
-
return /* @__PURE__ */ (0,
|
|
11593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
|
|
11401
11594
|
"section",
|
|
11402
11595
|
{
|
|
11403
11596
|
className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
|
|
11404
11597
|
"aria-label": file.name || "File",
|
|
11405
11598
|
children: [
|
|
11406
|
-
/* @__PURE__ */ (0,
|
|
11407
|
-
/* @__PURE__ */ (0,
|
|
11408
|
-
/* @__PURE__ */ (0,
|
|
11409
|
-
/* @__PURE__ */ (0,
|
|
11410
|
-
/* @__PURE__ */ (0,
|
|
11599
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("header", { className: "fd-fv-head", children: [
|
|
11600
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
11601
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-titles", children: [
|
|
11602
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
|
|
11603
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-meta", children: [
|
|
11411
11604
|
file.mime || "Unknown type",
|
|
11412
11605
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
11413
11606
|
] })
|
|
11414
11607
|
] }),
|
|
11415
|
-
/* @__PURE__ */ (0,
|
|
11608
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-actions", children: [
|
|
11416
11609
|
actions,
|
|
11417
|
-
/* @__PURE__ */ (0,
|
|
11418
|
-
onClose ? /* @__PURE__ */ (0,
|
|
11610
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
|
|
11611
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
|
|
11419
11612
|
] })
|
|
11420
11613
|
] }),
|
|
11421
|
-
downloadError ? /* @__PURE__ */ (0,
|
|
11422
|
-
hasSide ? /* @__PURE__ */ (0,
|
|
11614
|
+
downloadError ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
|
|
11615
|
+
hasSide ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
11423
11616
|
Tabs,
|
|
11424
11617
|
{
|
|
11425
11618
|
className: "fd-fv-tabs",
|
|
@@ -11428,19 +11621,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11428
11621
|
onChange: (v) => setTab(v)
|
|
11429
11622
|
}
|
|
11430
11623
|
) : null,
|
|
11431
|
-
/* @__PURE__ */ (0,
|
|
11432
|
-
/* @__PURE__ */ (0,
|
|
11624
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-body", children: [
|
|
11625
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
11433
11626
|
LoadingRegion,
|
|
11434
11627
|
{
|
|
11435
11628
|
state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
|
|
11436
11629
|
error: preview.error,
|
|
11437
11630
|
label: "Loading preview of " + (file.name || "file"),
|
|
11438
11631
|
onRetry: preview.status === "error" ? preview.retry : void 0,
|
|
11439
|
-
skeleton: /* @__PURE__ */ (0,
|
|
11440
|
-
children: /* @__PURE__ */ (0,
|
|
11632
|
+
skeleton: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Skeleton, { shape: "card", h: 220 }),
|
|
11633
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(PreviewBody, { file, kind, state: preview })
|
|
11441
11634
|
}
|
|
11442
11635
|
) }),
|
|
11443
|
-
hasSide ? /* @__PURE__ */ (0,
|
|
11636
|
+
hasSide ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
|
|
11444
11637
|
] })
|
|
11445
11638
|
]
|
|
11446
11639
|
}
|
|
@@ -11448,8 +11641,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11448
11641
|
}
|
|
11449
11642
|
|
|
11450
11643
|
// src/components/files/FileBrowser.tsx
|
|
11451
|
-
var
|
|
11452
|
-
var
|
|
11644
|
+
var React58 = __toESM(require("react"), 1);
|
|
11645
|
+
var import_jsx_runtime87 = require("react/jsx-runtime");
|
|
11453
11646
|
function childrenOf(folders, parentId) {
|
|
11454
11647
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
11455
11648
|
}
|
|
@@ -11519,10 +11712,10 @@ function FolderPickerMenu({
|
|
|
11519
11712
|
destinations,
|
|
11520
11713
|
onPick
|
|
11521
11714
|
}) {
|
|
11522
|
-
const [open, setOpen] =
|
|
11715
|
+
const [open, setOpen] = React58.useState(false);
|
|
11523
11716
|
const zIndex = useOverlayLayer(open);
|
|
11524
|
-
const ref =
|
|
11525
|
-
|
|
11717
|
+
const ref = React58.useRef(null);
|
|
11718
|
+
React58.useEffect(() => {
|
|
11526
11719
|
if (!open) return;
|
|
11527
11720
|
const away = (e) => {
|
|
11528
11721
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -11537,8 +11730,8 @@ function FolderPickerMenu({
|
|
|
11537
11730
|
document.removeEventListener("keydown", esc);
|
|
11538
11731
|
};
|
|
11539
11732
|
}, [open]);
|
|
11540
|
-
return /* @__PURE__ */ (0,
|
|
11541
|
-
/* @__PURE__ */ (0,
|
|
11733
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
|
|
11734
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11542
11735
|
IconButton,
|
|
11543
11736
|
{
|
|
11544
11737
|
icon: "arrows-out-cardinal",
|
|
@@ -11550,9 +11743,9 @@ function FolderPickerMenu({
|
|
|
11550
11743
|
onClick: () => setOpen((v) => !v)
|
|
11551
11744
|
}
|
|
11552
11745
|
),
|
|
11553
|
-
open ? /* @__PURE__ */ (0,
|
|
11554
|
-
/* @__PURE__ */ (0,
|
|
11555
|
-
destinations.map((d) => /* @__PURE__ */ (0,
|
|
11746
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-menu", role: "menu", "aria-label": label, style: { zIndex }, children: [
|
|
11747
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
|
|
11748
|
+
destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
11556
11749
|
"button",
|
|
11557
11750
|
{
|
|
11558
11751
|
type: "button",
|
|
@@ -11564,7 +11757,7 @@ function FolderPickerMenu({
|
|
|
11564
11757
|
setOpen(false);
|
|
11565
11758
|
},
|
|
11566
11759
|
children: [
|
|
11567
|
-
/* @__PURE__ */ (0,
|
|
11760
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
11568
11761
|
d.name
|
|
11569
11762
|
]
|
|
11570
11763
|
},
|
|
@@ -11574,8 +11767,8 @@ function FolderPickerMenu({
|
|
|
11574
11767
|
] });
|
|
11575
11768
|
}
|
|
11576
11769
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
11577
|
-
const [over, setOver] =
|
|
11578
|
-
const dragCounter =
|
|
11770
|
+
const [over, setOver] = React58.useState(false);
|
|
11771
|
+
const dragCounter = React58.useRef(0);
|
|
11579
11772
|
const dropHandlers = isDropTarget ? {
|
|
11580
11773
|
onDragEnter: (e) => {
|
|
11581
11774
|
if (!hasInternalPayload(e)) return;
|
|
@@ -11600,8 +11793,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
11600
11793
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
11601
11794
|
}
|
|
11602
11795
|
} : {};
|
|
11603
|
-
return /* @__PURE__ */ (0,
|
|
11604
|
-
/* @__PURE__ */ (0,
|
|
11796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
|
|
11797
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
11605
11798
|
"button",
|
|
11606
11799
|
{
|
|
11607
11800
|
type: "button",
|
|
@@ -11610,26 +11803,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
11610
11803
|
draggable: !!draggableId,
|
|
11611
11804
|
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
11612
11805
|
children: [
|
|
11613
|
-
/* @__PURE__ */ (0,
|
|
11614
|
-
/* @__PURE__ */ (0,
|
|
11615
|
-
/* @__PURE__ */ (0,
|
|
11616
|
-
meta ? /* @__PURE__ */ (0,
|
|
11806
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + icon }) }),
|
|
11807
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-row-text", children: [
|
|
11808
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
|
|
11809
|
+
meta ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
|
|
11617
11810
|
] })
|
|
11618
11811
|
]
|
|
11619
11812
|
}
|
|
11620
11813
|
),
|
|
11621
|
-
actions ? /* @__PURE__ */ (0,
|
|
11814
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
11622
11815
|
] });
|
|
11623
11816
|
}
|
|
11624
11817
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
11625
11818
|
const kids = childrenOf(folders, folder.id);
|
|
11626
|
-
const [expanded, setExpanded] =
|
|
11627
|
-
|
|
11819
|
+
const [expanded, setExpanded] = React58.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
11820
|
+
React58.useEffect(() => {
|
|
11628
11821
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
11629
11822
|
}, [currentFolderId, folder.id, folders]);
|
|
11630
11823
|
const isCurrent = folder.id === currentFolderId;
|
|
11631
|
-
return /* @__PURE__ */ (0,
|
|
11632
|
-
/* @__PURE__ */ (0,
|
|
11824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-tree-node", children: [
|
|
11825
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11633
11826
|
RowShell,
|
|
11634
11827
|
{
|
|
11635
11828
|
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
@@ -11639,7 +11832,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
11639
11832
|
isDropTarget: canMove,
|
|
11640
11833
|
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
11641
11834
|
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
11642
|
-
actions: kids.length ? /* @__PURE__ */ (0,
|
|
11835
|
+
actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11643
11836
|
IconButton,
|
|
11644
11837
|
{
|
|
11645
11838
|
icon: expanded ? "caret-down" : "caret-right",
|
|
@@ -11651,7 +11844,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
11651
11844
|
) : void 0
|
|
11652
11845
|
}
|
|
11653
11846
|
),
|
|
11654
|
-
expanded && kids.length ? /* @__PURE__ */ (0,
|
|
11847
|
+
expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11655
11848
|
TreeNode,
|
|
11656
11849
|
{
|
|
11657
11850
|
folder: k,
|
|
@@ -11690,15 +11883,15 @@ function FileBrowser({
|
|
|
11690
11883
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
11691
11884
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
11692
11885
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
11693
|
-
const [createOpen, setCreateOpen] =
|
|
11694
|
-
const [createName, setCreateName] =
|
|
11695
|
-
const [renameTarget, setRenameTarget] =
|
|
11696
|
-
const [renameValue, setRenameValue] =
|
|
11697
|
-
const [deleteTarget, setDeleteTarget] =
|
|
11698
|
-
const uploadInputRef =
|
|
11699
|
-
const crumbFolders =
|
|
11700
|
-
const subfolders =
|
|
11701
|
-
const currentFiles =
|
|
11886
|
+
const [createOpen, setCreateOpen] = React58.useState(false);
|
|
11887
|
+
const [createName, setCreateName] = React58.useState("");
|
|
11888
|
+
const [renameTarget, setRenameTarget] = React58.useState(null);
|
|
11889
|
+
const [renameValue, setRenameValue] = React58.useState("");
|
|
11890
|
+
const [deleteTarget, setDeleteTarget] = React58.useState(null);
|
|
11891
|
+
const uploadInputRef = React58.useRef(null);
|
|
11892
|
+
const crumbFolders = React58.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11893
|
+
const subfolders = React58.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11894
|
+
const currentFiles = React58.useMemo(
|
|
11702
11895
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
11703
11896
|
[files, currentFolderId]
|
|
11704
11897
|
);
|
|
@@ -11737,10 +11930,10 @@ function FileBrowser({
|
|
|
11737
11930
|
if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
|
|
11738
11931
|
setDeleteTarget(null);
|
|
11739
11932
|
};
|
|
11740
|
-
const content = /* @__PURE__ */ (0,
|
|
11741
|
-
/* @__PURE__ */ (0,
|
|
11742
|
-
/* @__PURE__ */ (0,
|
|
11743
|
-
/* @__PURE__ */ (0,
|
|
11933
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
11934
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-head", children: [
|
|
11935
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
11936
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11744
11937
|
BreadcrumbCrumb,
|
|
11745
11938
|
{
|
|
11746
11939
|
label: "Home",
|
|
@@ -11750,7 +11943,7 @@ function FileBrowser({
|
|
|
11750
11943
|
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
11751
11944
|
}
|
|
11752
11945
|
),
|
|
11753
|
-
crumbFolders.map((f, i) => /* @__PURE__ */ (0,
|
|
11946
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11754
11947
|
BreadcrumbCrumb,
|
|
11755
11948
|
{
|
|
11756
11949
|
label: f.name,
|
|
@@ -11762,11 +11955,11 @@ function FileBrowser({
|
|
|
11762
11955
|
f.id
|
|
11763
11956
|
))
|
|
11764
11957
|
] }),
|
|
11765
|
-
/* @__PURE__ */ (0,
|
|
11766
|
-
canCreateFolder ? /* @__PURE__ */ (0,
|
|
11767
|
-
canUpload ? /* @__PURE__ */ (0,
|
|
11768
|
-
/* @__PURE__ */ (0,
|
|
11769
|
-
/* @__PURE__ */ (0,
|
|
11958
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-actions", children: [
|
|
11959
|
+
canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
|
|
11960
|
+
canUpload ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
11961
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
|
|
11962
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11770
11963
|
"input",
|
|
11771
11964
|
{
|
|
11772
11965
|
ref: uploadInputRef,
|
|
@@ -11784,9 +11977,9 @@ function FileBrowser({
|
|
|
11784
11977
|
] }) : null
|
|
11785
11978
|
] })
|
|
11786
11979
|
] }),
|
|
11787
|
-
/* @__PURE__ */ (0,
|
|
11788
|
-
/* @__PURE__ */ (0,
|
|
11789
|
-
/* @__PURE__ */ (0,
|
|
11980
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-body", children: [
|
|
11981
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
|
|
11982
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11790
11983
|
RowShell,
|
|
11791
11984
|
{
|
|
11792
11985
|
icon: "house-simple",
|
|
@@ -11797,7 +11990,7 @@ function FileBrowser({
|
|
|
11797
11990
|
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
11798
11991
|
}
|
|
11799
11992
|
),
|
|
11800
|
-
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0,
|
|
11993
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11801
11994
|
TreeNode,
|
|
11802
11995
|
{
|
|
11803
11996
|
folder: f,
|
|
@@ -11811,18 +12004,18 @@ function FileBrowser({
|
|
|
11811
12004
|
f.id
|
|
11812
12005
|
))
|
|
11813
12006
|
] }),
|
|
11814
|
-
/* @__PURE__ */ (0,
|
|
12007
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11815
12008
|
LoadingRegion,
|
|
11816
12009
|
{
|
|
11817
12010
|
state: loading ? "loading" : "ready",
|
|
11818
12011
|
label: "Loading folder contents",
|
|
11819
|
-
skeleton: /* @__PURE__ */ (0,
|
|
11820
|
-
/* @__PURE__ */ (0,
|
|
11821
|
-
/* @__PURE__ */ (0,
|
|
11822
|
-
/* @__PURE__ */ (0,
|
|
12012
|
+
skeleton: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
|
|
12013
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
12014
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
12015
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" })
|
|
11823
12016
|
] }),
|
|
11824
|
-
children: isEmpty ? /* @__PURE__ */ (0,
|
|
11825
|
-
subfolders.map((f) => /* @__PURE__ */ (0,
|
|
12017
|
+
children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-list", children: [
|
|
12018
|
+
subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11826
12019
|
RowShell,
|
|
11827
12020
|
{
|
|
11828
12021
|
icon: "folder-simple",
|
|
@@ -11831,9 +12024,9 @@ function FileBrowser({
|
|
|
11831
12024
|
draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
|
|
11832
12025
|
isDropTarget: canMove,
|
|
11833
12026
|
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
11834
|
-
actions: /* @__PURE__ */ (0,
|
|
11835
|
-
canRenameFolder ? /* @__PURE__ */ (0,
|
|
11836
|
-
canMove ? /* @__PURE__ */ (0,
|
|
12027
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12028
|
+
canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
|
|
12029
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11837
12030
|
FolderPickerMenu,
|
|
11838
12031
|
{
|
|
11839
12032
|
label: "Move " + f.name,
|
|
@@ -11841,12 +12034,12 @@ function FileBrowser({
|
|
|
11841
12034
|
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
11842
12035
|
}
|
|
11843
12036
|
) : null,
|
|
11844
|
-
canDeleteFolder ? /* @__PURE__ */ (0,
|
|
12037
|
+
canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
|
|
11845
12038
|
] })
|
|
11846
12039
|
},
|
|
11847
12040
|
f.id
|
|
11848
12041
|
)),
|
|
11849
|
-
currentFiles.map((file) => /* @__PURE__ */ (0,
|
|
12042
|
+
currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11850
12043
|
RowShell,
|
|
11851
12044
|
{
|
|
11852
12045
|
icon: iconForMime(file.mime, file.name),
|
|
@@ -11854,8 +12047,8 @@ function FileBrowser({
|
|
|
11854
12047
|
meta: file.size ? formatBytes(file.size) : void 0,
|
|
11855
12048
|
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
11856
12049
|
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
11857
|
-
actions: /* @__PURE__ */ (0,
|
|
11858
|
-
canMove ? /* @__PURE__ */ (0,
|
|
12050
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12051
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11859
12052
|
FolderPickerMenu,
|
|
11860
12053
|
{
|
|
11861
12054
|
label: "Move " + file.name,
|
|
@@ -11863,7 +12056,7 @@ function FileBrowser({
|
|
|
11863
12056
|
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
11864
12057
|
}
|
|
11865
12058
|
) : null,
|
|
11866
|
-
canRemoveFile ? /* @__PURE__ */ (0,
|
|
12059
|
+
canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
|
|
11867
12060
|
] })
|
|
11868
12061
|
},
|
|
11869
12062
|
file.id
|
|
@@ -11872,10 +12065,10 @@ function FileBrowser({
|
|
|
11872
12065
|
}
|
|
11873
12066
|
) })
|
|
11874
12067
|
] }),
|
|
11875
|
-
/* @__PURE__ */ (0,
|
|
11876
|
-
/* @__PURE__ */ (0,
|
|
11877
|
-
/* @__PURE__ */ (0,
|
|
11878
|
-
] }), children: /* @__PURE__ */ (0,
|
|
12068
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12069
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
|
|
12070
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
|
|
12071
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11879
12072
|
"input",
|
|
11880
12073
|
{
|
|
11881
12074
|
className: "fd-fb-input",
|
|
@@ -11889,10 +12082,10 @@ function FileBrowser({
|
|
|
11889
12082
|
autoFocus: true
|
|
11890
12083
|
}
|
|
11891
12084
|
) }),
|
|
11892
|
-
/* @__PURE__ */ (0,
|
|
11893
|
-
/* @__PURE__ */ (0,
|
|
11894
|
-
/* @__PURE__ */ (0,
|
|
11895
|
-
] }), children: /* @__PURE__ */ (0,
|
|
12085
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12086
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
|
|
12087
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
|
|
12088
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11896
12089
|
"input",
|
|
11897
12090
|
{
|
|
11898
12091
|
className: "fd-fb-input",
|
|
@@ -11906,22 +12099,22 @@ function FileBrowser({
|
|
|
11906
12099
|
autoFocus: true
|
|
11907
12100
|
}
|
|
11908
12101
|
) }),
|
|
11909
|
-
/* @__PURE__ */ (0,
|
|
12102
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11910
12103
|
Modal,
|
|
11911
12104
|
{
|
|
11912
12105
|
open: deleteTarget != null,
|
|
11913
12106
|
title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
|
|
11914
12107
|
description: "This can't be undone. The folder must be empty.",
|
|
11915
12108
|
onClose: () => setDeleteTarget(null),
|
|
11916
|
-
footer: /* @__PURE__ */ (0,
|
|
11917
|
-
/* @__PURE__ */ (0,
|
|
11918
|
-
/* @__PURE__ */ (0,
|
|
12109
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12110
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
12111
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
|
|
11919
12112
|
] })
|
|
11920
12113
|
}
|
|
11921
12114
|
)
|
|
11922
12115
|
] });
|
|
11923
12116
|
if (!canUpload) return content;
|
|
11924
|
-
return /* @__PURE__ */ (0,
|
|
12117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|
|
11925
12118
|
}
|
|
11926
12119
|
function BreadcrumbCrumb({
|
|
11927
12120
|
label,
|
|
@@ -11930,8 +12123,8 @@ function BreadcrumbCrumb({
|
|
|
11930
12123
|
isDropTarget,
|
|
11931
12124
|
onDropPayload
|
|
11932
12125
|
}) {
|
|
11933
|
-
const [over, setOver] =
|
|
11934
|
-
const dragCounter =
|
|
12126
|
+
const [over, setOver] = React58.useState(false);
|
|
12127
|
+
const dragCounter = React58.useRef(0);
|
|
11935
12128
|
const dropHandlers = isDropTarget ? {
|
|
11936
12129
|
onDragEnter: (e) => {
|
|
11937
12130
|
if (!hasInternalPayload(e)) return;
|
|
@@ -11956,11 +12149,11 @@ function BreadcrumbCrumb({
|
|
|
11956
12149
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
11957
12150
|
}
|
|
11958
12151
|
} : {};
|
|
11959
|
-
return /* @__PURE__ */ (0,
|
|
12152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
|
|
11960
12153
|
}
|
|
11961
12154
|
|
|
11962
12155
|
// src/kits/query.ts
|
|
11963
|
-
var
|
|
12156
|
+
var React59 = __toESM(require("react"), 1);
|
|
11964
12157
|
function eqFilter(get2) {
|
|
11965
12158
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
11966
12159
|
}
|
|
@@ -11992,22 +12185,22 @@ function compare(a, b, dir) {
|
|
|
11992
12185
|
var API = null;
|
|
11993
12186
|
var PREFS = null;
|
|
11994
12187
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
11995
|
-
const [query, setQuery] =
|
|
12188
|
+
const [query, setQuery] = React59.useState(() => {
|
|
11996
12189
|
const store = PREFS || window.PlannerPrefs;
|
|
11997
12190
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
11998
12191
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
11999
12192
|
});
|
|
12000
|
-
const savePref =
|
|
12193
|
+
const savePref = React59.useCallback((patch2) => {
|
|
12001
12194
|
const store = PREFS || window.PlannerPrefs;
|
|
12002
12195
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
12003
12196
|
}, [prefsKey]);
|
|
12004
|
-
const [res, setRes] =
|
|
12005
|
-
const [loading, setLoading] =
|
|
12006
|
-
const seq2 =
|
|
12197
|
+
const [res, setRes] = React59.useState(null);
|
|
12198
|
+
const [loading, setLoading] = React59.useState(true);
|
|
12199
|
+
const seq2 = React59.useRef(0);
|
|
12007
12200
|
const depKey = (deps || []).join("|");
|
|
12008
12201
|
const paramKey = JSON.stringify(params || {});
|
|
12009
12202
|
const queryKey = JSON.stringify(query);
|
|
12010
|
-
|
|
12203
|
+
React59.useEffect(() => {
|
|
12011
12204
|
const id = ++seq2.current;
|
|
12012
12205
|
setLoading(true);
|
|
12013
12206
|
const t = setTimeout(() => {
|
|
@@ -12306,12 +12499,12 @@ function createVersionStore(initialState, options) {
|
|
|
12306
12499
|
}
|
|
12307
12500
|
|
|
12308
12501
|
// src/kits/documentTitle.ts
|
|
12309
|
-
var
|
|
12502
|
+
var React60 = __toESM(require("react"), 1);
|
|
12310
12503
|
function formatDocumentTitle(routeTitle, appName) {
|
|
12311
12504
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
12312
12505
|
}
|
|
12313
12506
|
function useDocumentTitle(routeTitle, appName) {
|
|
12314
|
-
|
|
12507
|
+
React60.useEffect(() => {
|
|
12315
12508
|
if (typeof document === "undefined") return;
|
|
12316
12509
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
12317
12510
|
}, [routeTitle, appName]);
|
|
@@ -12434,6 +12627,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
12434
12627
|
SessionKit,
|
|
12435
12628
|
SessionProvider,
|
|
12436
12629
|
SidebarNav,
|
|
12630
|
+
SignInPage,
|
|
12437
12631
|
Skeleton,
|
|
12438
12632
|
SkeletonText,
|
|
12439
12633
|
Slider,
|