@flytedan/flytebot-design-system 0.6.0 → 0.7.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 +1293 -1034
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +225 -1
- package/dist/index.d.ts +225 -1
- package/dist/index.js +1287 -1034
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +6 -1
package/dist/index.js
CHANGED
|
@@ -205,7 +205,14 @@ function Popover({
|
|
|
205
205
|
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
206
206
|
width: matchWidth ? pos.width : width,
|
|
207
207
|
minWidth: minWidth || (matchWidth ? void 0 : 200),
|
|
208
|
-
|
|
208
|
+
// Size to content by default — cap only at real available room between the
|
|
209
|
+
// anchor and the viewport edge (pos.maxH, computed by usePopoverPosition).
|
|
210
|
+
// A caller-supplied `maxHeight` narrows that further (e.g. a long menu that
|
|
211
|
+
// should scroll well before it reaches the viewport edge); it must never
|
|
212
|
+
// widen past pos.maxH, which is why it's still Math.min'd against it. There
|
|
213
|
+
// is intentionally no arbitrary default here — an unrequested cap would clip
|
|
214
|
+
// ordinary content that simply happens to be taller than some fixed number.
|
|
215
|
+
maxHeight: maxHeight != null ? Math.min(maxHeight, pos.maxH) : pos.maxH,
|
|
209
216
|
transformOrigin: pos.side === "top" ? "bottom center" : "top center",
|
|
210
217
|
zIndex: 140,
|
|
211
218
|
...style
|
|
@@ -2421,56 +2428,140 @@ function StepList({
|
|
|
2421
2428
|
] });
|
|
2422
2429
|
}
|
|
2423
2430
|
|
|
2424
|
-
// src/components/
|
|
2431
|
+
// src/components/data/VirtualList.tsx
|
|
2425
2432
|
import * as React15 from "react";
|
|
2426
2433
|
import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2427
|
-
|
|
2428
|
-
|
|
2434
|
+
var VIRTUAL_LIST_BUFFER_ROWS = 20;
|
|
2435
|
+
function computeVirtualWindow(opts) {
|
|
2436
|
+
const { scrollTop, viewportHeight, itemHeight, itemCount, bufferRows = VIRTUAL_LIST_BUFFER_ROWS } = opts;
|
|
2437
|
+
if (itemCount <= 0 || itemHeight <= 0) {
|
|
2438
|
+
return { visibleStart: 0, visibleEnd: -1, startIndex: 0, endIndex: -1, totalHeight: 0, offsetY: 0 };
|
|
2439
|
+
}
|
|
2440
|
+
const lastPossible = itemCount - 1;
|
|
2441
|
+
const visibleStart = Math.min(lastPossible, Math.max(0, Math.floor(scrollTop / itemHeight)));
|
|
2442
|
+
const visibleRows = Math.max(1, Math.ceil(viewportHeight / itemHeight));
|
|
2443
|
+
const visibleEnd = Math.min(lastPossible, visibleStart + visibleRows - 1);
|
|
2444
|
+
const startIndex = Math.max(0, visibleStart - bufferRows);
|
|
2445
|
+
const endIndex = Math.min(lastPossible, visibleEnd + bufferRows);
|
|
2446
|
+
return {
|
|
2447
|
+
visibleStart,
|
|
2448
|
+
visibleEnd,
|
|
2449
|
+
startIndex,
|
|
2450
|
+
endIndex,
|
|
2451
|
+
totalHeight: itemCount * itemHeight,
|
|
2452
|
+
offsetY: startIndex * itemHeight
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
function computeNeedMore(win, itemCount, bufferRows = VIRTUAL_LIST_BUFFER_ROWS) {
|
|
2456
|
+
if (itemCount <= 0) return { start: true, end: true };
|
|
2457
|
+
return {
|
|
2458
|
+
start: win.visibleStart <= bufferRows,
|
|
2459
|
+
end: itemCount - 1 - win.visibleEnd <= bufferRows
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
function VirtualList({
|
|
2463
|
+
items,
|
|
2464
|
+
itemHeight,
|
|
2465
|
+
renderItem,
|
|
2466
|
+
onNeedMore,
|
|
2467
|
+
hasMore,
|
|
2468
|
+
loading = false,
|
|
2469
|
+
keyOf,
|
|
2470
|
+
height = 400,
|
|
2471
|
+
emptyState,
|
|
2472
|
+
className = "",
|
|
2473
|
+
style
|
|
2474
|
+
}) {
|
|
2475
|
+
const [scrollTop, setScrollTop] = React15.useState(0);
|
|
2476
|
+
const requested = React15.useRef({ start: null, end: null });
|
|
2477
|
+
const win = React15.useMemo(
|
|
2478
|
+
() => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: items.length }),
|
|
2479
|
+
[scrollTop, height, itemHeight, items.length]
|
|
2480
|
+
);
|
|
2481
|
+
const need = React15.useMemo(() => computeNeedMore(win, items.length), [win, items.length]);
|
|
2482
|
+
const wantStart = need.start && hasMore?.start !== false;
|
|
2483
|
+
const wantEnd = need.end && hasMore?.end !== false;
|
|
2429
2484
|
React15.useEffect(() => {
|
|
2430
|
-
if (
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
] })
|
|
2441
|
-
|
|
2485
|
+
if (loading || !wantStart || requested.current.start === items.length) return;
|
|
2486
|
+
requested.current.start = items.length;
|
|
2487
|
+
onNeedMore("start");
|
|
2488
|
+
}, [wantStart, loading, items.length, onNeedMore]);
|
|
2489
|
+
React15.useEffect(() => {
|
|
2490
|
+
if (loading || !wantEnd || requested.current.end === items.length) return;
|
|
2491
|
+
requested.current.end = items.length;
|
|
2492
|
+
onNeedMore("end");
|
|
2493
|
+
}, [wantEnd, loading, items.length, onNeedMore]);
|
|
2494
|
+
if (!items.length && !loading && emptyState) {
|
|
2495
|
+
return /* @__PURE__ */ jsx37("div", { className: ["fd-vlist", className].filter(Boolean).join(" "), style: { height, overflow: "auto", ...style }, children: emptyState });
|
|
2496
|
+
}
|
|
2497
|
+
const rows = [];
|
|
2498
|
+
for (let i = win.startIndex; i <= win.endIndex; i++) {
|
|
2499
|
+
const item = items[i];
|
|
2500
|
+
if (item === void 0) continue;
|
|
2501
|
+
rows.push(
|
|
2502
|
+
/* @__PURE__ */ jsx37("div", { style: { height: itemHeight, boxSizing: "border-box" }, children: renderItem(item, i) }, keyOf(item))
|
|
2503
|
+
);
|
|
2504
|
+
}
|
|
2505
|
+
return /* @__PURE__ */ jsxs33(
|
|
2506
|
+
"div",
|
|
2507
|
+
{
|
|
2508
|
+
className: ["fd-vlist", className].filter(Boolean).join(" "),
|
|
2509
|
+
style: { height, overflowY: "auto", overflowX: "hidden", position: "relative", ...style },
|
|
2510
|
+
onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
|
|
2511
|
+
children: [
|
|
2512
|
+
/* @__PURE__ */ jsx37("div", { style: { height: win.totalHeight, position: "relative" }, children: /* @__PURE__ */ jsx37("div", { style: { position: "absolute", top: win.offsetY, left: 0, right: 0 }, children: rows }) }),
|
|
2513
|
+
loading ? /* @__PURE__ */ jsx37("div", { style: { position: "sticky", bottom: 0, left: 0, right: 0, display: "grid", placeItems: "center", padding: "8px 0", background: "var(--surface)" }, children: /* @__PURE__ */ jsx37("span", { className: "fd-spinner", "aria-hidden": "true" }) }) : null
|
|
2514
|
+
]
|
|
2515
|
+
}
|
|
2516
|
+
);
|
|
2442
2517
|
}
|
|
2443
2518
|
|
|
2444
|
-
// src/components/
|
|
2519
|
+
// src/components/data/EntityRow.tsx
|
|
2445
2520
|
import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2446
|
-
function
|
|
2447
|
-
return /* @__PURE__ */ jsxs34(
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2521
|
+
function EntityRow({ title, meta, action, draggable = false, onDragStart, onDragEnd, style, className = "" }) {
|
|
2522
|
+
return /* @__PURE__ */ jsxs34(
|
|
2523
|
+
"div",
|
|
2524
|
+
{
|
|
2525
|
+
draggable,
|
|
2526
|
+
onDragStart,
|
|
2527
|
+
onDragEnd,
|
|
2528
|
+
className: ["fd-erow", className].filter(Boolean).join(" "),
|
|
2529
|
+
style: {
|
|
2530
|
+
display: "flex",
|
|
2531
|
+
alignItems: "center",
|
|
2532
|
+
gap: 8,
|
|
2533
|
+
height: "100%",
|
|
2534
|
+
padding: "0 8px",
|
|
2535
|
+
borderRadius: 6,
|
|
2536
|
+
cursor: draggable ? "grab" : void 0,
|
|
2537
|
+
...style
|
|
2538
|
+
},
|
|
2539
|
+
children: [
|
|
2540
|
+
draggable ? /* @__PURE__ */ jsx38("i", { className: "ph ph-dots-six-vertical", "aria-hidden": "true", style: { fontSize: 13, flex: "none", color: "var(--text-muted)" } }) : null,
|
|
2541
|
+
/* @__PURE__ */ jsxs34("span", { style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: 1 }, children: [
|
|
2542
|
+
/* @__PURE__ */ jsx38("span", { className: "fd-body-sm", style: { fontWeight: 600, color: "var(--text)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: title }),
|
|
2543
|
+
meta ? /* @__PURE__ */ jsx38("span", { style: { fontSize: "var(--overline-size)", color: "var(--text-muted)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: meta }) : null
|
|
2544
|
+
] }),
|
|
2545
|
+
action ? /* @__PURE__ */ jsx38(
|
|
2546
|
+
IconButton,
|
|
2547
|
+
{
|
|
2548
|
+
icon: action.icon,
|
|
2549
|
+
label: action.label,
|
|
2550
|
+
size: "sm",
|
|
2551
|
+
onClick: action.onClick,
|
|
2552
|
+
style: { color: action.tone === "add" ? "var(--ok-text)" : action.tone === "remove" ? "var(--danger-text)" : void 0 }
|
|
2553
|
+
}
|
|
2554
|
+
) : null
|
|
2555
|
+
]
|
|
2556
|
+
}
|
|
2557
|
+
);
|
|
2457
2558
|
}
|
|
2458
2559
|
|
|
2459
|
-
// src/components/
|
|
2460
|
-
import
|
|
2461
|
-
function Switch({ label, description, className = "", ...rest }) {
|
|
2462
|
-
return /* @__PURE__ */ jsxs35("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
|
|
2463
|
-
/* @__PURE__ */ jsx39("input", { type: "checkbox", role: "switch", ...rest }),
|
|
2464
|
-
/* @__PURE__ */ jsx39("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx39("span", { className: "fd-switch-thumb" }) }),
|
|
2465
|
-
label ? /* @__PURE__ */ jsxs35("span", { className: "fd-choice-text", children: [
|
|
2466
|
-
/* @__PURE__ */ jsx39("span", { className: "fd-switch-label", children: label }),
|
|
2467
|
-
description ? /* @__PURE__ */ jsx39("span", { className: "fd-choice-desc", children: description }) : null
|
|
2468
|
-
] }) : null
|
|
2469
|
-
] });
|
|
2470
|
-
}
|
|
2560
|
+
// src/components/data/TransferList.tsx
|
|
2561
|
+
import * as React16 from "react";
|
|
2471
2562
|
|
|
2472
2563
|
// src/components/forms/Input.tsx
|
|
2473
|
-
import { jsx as
|
|
2564
|
+
import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2474
2565
|
function Input({
|
|
2475
2566
|
label,
|
|
2476
2567
|
help,
|
|
@@ -2498,27 +2589,27 @@ function Input({
|
|
|
2498
2589
|
size === "lg" ? "fd-input-lg" : "",
|
|
2499
2590
|
className
|
|
2500
2591
|
].filter(Boolean).join(" ");
|
|
2501
|
-
return /* @__PURE__ */
|
|
2502
|
-
label ? /* @__PURE__ */
|
|
2592
|
+
return /* @__PURE__ */ jsxs35("div", { className: "fd-field", style, children: [
|
|
2593
|
+
label ? /* @__PURE__ */ jsxs35("label", { className: "fd-field-label", htmlFor: fieldId, children: [
|
|
2503
2594
|
label,
|
|
2504
|
-
required ? /* @__PURE__ */
|
|
2595
|
+
required ? /* @__PURE__ */ jsx39("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
|
|
2505
2596
|
] }) : null,
|
|
2506
|
-
/* @__PURE__ */
|
|
2507
|
-
icon ? /* @__PURE__ */
|
|
2508
|
-
prefix ? /* @__PURE__ */
|
|
2509
|
-
/* @__PURE__ */
|
|
2510
|
-
loading ? /* @__PURE__ */
|
|
2511
|
-
suffix && !loading ? /* @__PURE__ */
|
|
2597
|
+
/* @__PURE__ */ jsxs35("div", { className: box, children: [
|
|
2598
|
+
icon ? /* @__PURE__ */ jsx39("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx39("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
|
|
2599
|
+
prefix ? /* @__PURE__ */ jsx39("span", { className: "fd-input-affix", children: prefix }) : null,
|
|
2600
|
+
/* @__PURE__ */ jsx39("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
|
|
2601
|
+
loading ? /* @__PURE__ */ jsx39("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
|
|
2602
|
+
suffix && !loading ? /* @__PURE__ */ jsx39("span", { className: "fd-input-affix", children: suffix }) : null
|
|
2512
2603
|
] }),
|
|
2513
|
-
error ? /* @__PURE__ */
|
|
2514
|
-
/* @__PURE__ */
|
|
2604
|
+
error ? /* @__PURE__ */ jsxs35("span", { className: "fd-field-error", children: [
|
|
2605
|
+
/* @__PURE__ */ jsx39("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2515
2606
|
error
|
|
2516
|
-
] }) : help ? /* @__PURE__ */
|
|
2607
|
+
] }) : help ? /* @__PURE__ */ jsx39("span", { className: "fd-field-help", children: help }) : null
|
|
2517
2608
|
] });
|
|
2518
2609
|
}
|
|
2519
2610
|
|
|
2520
2611
|
// src/components/forms/SearchField.tsx
|
|
2521
|
-
import { jsx as
|
|
2612
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
2522
2613
|
function SearchField({
|
|
2523
2614
|
value,
|
|
2524
2615
|
onChange,
|
|
@@ -2533,7 +2624,7 @@ function SearchField({
|
|
|
2533
2624
|
...rest
|
|
2534
2625
|
}) {
|
|
2535
2626
|
const clear = onClear || (() => onChange(""));
|
|
2536
|
-
return /* @__PURE__ */
|
|
2627
|
+
return /* @__PURE__ */ jsx40(
|
|
2537
2628
|
Input,
|
|
2538
2629
|
{
|
|
2539
2630
|
id,
|
|
@@ -2546,14 +2637,14 @@ function SearchField({
|
|
|
2546
2637
|
style,
|
|
2547
2638
|
className,
|
|
2548
2639
|
onChange: (e) => onChange(e.target.value),
|
|
2549
|
-
suffix: value ? /* @__PURE__ */
|
|
2640
|
+
suffix: value ? /* @__PURE__ */ jsx40(
|
|
2550
2641
|
"button",
|
|
2551
2642
|
{
|
|
2552
2643
|
type: "button",
|
|
2553
2644
|
"aria-label": "Clear search",
|
|
2554
2645
|
onClick: clear,
|
|
2555
2646
|
style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
|
|
2556
|
-
children: /* @__PURE__ */
|
|
2647
|
+
children: /* @__PURE__ */ jsx40("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
|
|
2557
2648
|
}
|
|
2558
2649
|
) : void 0,
|
|
2559
2650
|
...rest
|
|
@@ -2561,27 +2652,183 @@ function SearchField({
|
|
|
2561
2652
|
);
|
|
2562
2653
|
}
|
|
2563
2654
|
|
|
2564
|
-
// src/components/
|
|
2655
|
+
// src/components/data/TransferList.tsx
|
|
2656
|
+
import { jsx as jsx41, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2657
|
+
var emptyHasMore = {};
|
|
2658
|
+
function TransferList({
|
|
2659
|
+
left,
|
|
2660
|
+
right,
|
|
2661
|
+
keyOf,
|
|
2662
|
+
renderLabel,
|
|
2663
|
+
renderMeta,
|
|
2664
|
+
onMove,
|
|
2665
|
+
itemHeight = 44,
|
|
2666
|
+
listHeight = 440,
|
|
2667
|
+
className = ""
|
|
2668
|
+
}) {
|
|
2669
|
+
const [dragging, setDragging] = React16.useState(null);
|
|
2670
|
+
const [dragOverSide, setDragOverSide] = React16.useState(null);
|
|
2671
|
+
const startDrag = (e, item, from) => {
|
|
2672
|
+
const key = keyOf(item);
|
|
2673
|
+
setDragging({ key, from });
|
|
2674
|
+
e.dataTransfer.effectAllowed = "move";
|
|
2675
|
+
e.dataTransfer.setData("text/plain", String(key));
|
|
2676
|
+
};
|
|
2677
|
+
const endDrag = () => {
|
|
2678
|
+
setDragging(null);
|
|
2679
|
+
setDragOverSide(null);
|
|
2680
|
+
};
|
|
2681
|
+
const findItem = (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key);
|
|
2682
|
+
const dropOnSide = (e, side) => {
|
|
2683
|
+
e.preventDefault();
|
|
2684
|
+
setDragOverSide(null);
|
|
2685
|
+
if (!dragging || dragging.from === side) return;
|
|
2686
|
+
const item = findItem(dragging.from, dragging.key);
|
|
2687
|
+
if (item !== void 0) onMove(item, dragging.from, side);
|
|
2688
|
+
setDragging(null);
|
|
2689
|
+
};
|
|
2690
|
+
const renderSide = (side, cfg, opposite) => /* @__PURE__ */ jsxs36(
|
|
2691
|
+
"div",
|
|
2692
|
+
{
|
|
2693
|
+
style: {
|
|
2694
|
+
flex: 1,
|
|
2695
|
+
minWidth: 0,
|
|
2696
|
+
display: "flex",
|
|
2697
|
+
flexDirection: "column",
|
|
2698
|
+
gap: 8,
|
|
2699
|
+
padding: 10,
|
|
2700
|
+
borderRadius: 10,
|
|
2701
|
+
border: "1px solid " + (dragOverSide === side ? "var(--brand)" : "var(--border)"),
|
|
2702
|
+
background: "var(--surface)"
|
|
2703
|
+
},
|
|
2704
|
+
onDragOver: (e) => {
|
|
2705
|
+
if (!dragging || dragging.from === side) return;
|
|
2706
|
+
e.preventDefault();
|
|
2707
|
+
e.dataTransfer.dropEffect = "move";
|
|
2708
|
+
if (dragOverSide !== side) setDragOverSide(side);
|
|
2709
|
+
},
|
|
2710
|
+
onDragLeave: (e) => {
|
|
2711
|
+
if (e.currentTarget.contains(e.relatedTarget)) return;
|
|
2712
|
+
setDragOverSide((s) => s === side ? null : s);
|
|
2713
|
+
},
|
|
2714
|
+
onDrop: (e) => dropOnSide(e, side),
|
|
2715
|
+
children: [
|
|
2716
|
+
cfg.label ? /* @__PURE__ */ jsxs36("span", { className: "fd-overline fd-muted", children: [
|
|
2717
|
+
cfg.label,
|
|
2718
|
+
cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
|
|
2719
|
+
] }) : null,
|
|
2720
|
+
/* @__PURE__ */ jsxs36("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
2721
|
+
/* @__PURE__ */ jsx41(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
|
|
2722
|
+
/* @__PURE__ */ jsx41(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort })
|
|
2723
|
+
] }),
|
|
2724
|
+
/* @__PURE__ */ jsx41(
|
|
2725
|
+
VirtualList,
|
|
2726
|
+
{
|
|
2727
|
+
items: cfg.items,
|
|
2728
|
+
itemHeight,
|
|
2729
|
+
height: listHeight,
|
|
2730
|
+
keyOf,
|
|
2731
|
+
loading: cfg.loading,
|
|
2732
|
+
hasMore: cfg.hasMore || emptyHasMore,
|
|
2733
|
+
onNeedMore: cfg.onNeedMore,
|
|
2734
|
+
emptyState: /* @__PURE__ */ jsx41(EmptyState, { icon: "tray", title: "Nothing here" }),
|
|
2735
|
+
renderItem: (item) => /* @__PURE__ */ jsx41(
|
|
2736
|
+
EntityRow,
|
|
2737
|
+
{
|
|
2738
|
+
title: renderLabel(item),
|
|
2739
|
+
meta: renderMeta ? renderMeta(item) : void 0,
|
|
2740
|
+
draggable: true,
|
|
2741
|
+
onDragStart: (e) => startDrag(e, item, side),
|
|
2742
|
+
onDragEnd: endDrag,
|
|
2743
|
+
style: { opacity: dragging && dragging.from === side && dragging.key === keyOf(item) ? 0.4 : 1 },
|
|
2744
|
+
action: {
|
|
2745
|
+
icon: side === "left" ? "plus" : "minus",
|
|
2746
|
+
label: (side === "left" ? "Move to " : "Move from ") + (side === "left" ? right.label || "the other list" : left.label || "the other list"),
|
|
2747
|
+
tone: side === "left" ? "add" : "remove",
|
|
2748
|
+
onClick: () => onMove(item, side, opposite)
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
)
|
|
2752
|
+
}
|
|
2753
|
+
)
|
|
2754
|
+
]
|
|
2755
|
+
}
|
|
2756
|
+
);
|
|
2757
|
+
return /* @__PURE__ */ jsxs36("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
|
|
2758
|
+
renderSide("left", left, "right"),
|
|
2759
|
+
renderSide("right", right, "left")
|
|
2760
|
+
] });
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
// src/components/forms/Checkbox.tsx
|
|
2764
|
+
import * as React17 from "react";
|
|
2565
2765
|
import { jsx as jsx42, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
2766
|
+
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
2767
|
+
const ref = React17.useRef(null);
|
|
2768
|
+
React17.useEffect(() => {
|
|
2769
|
+
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
2770
|
+
}, [indeterminate]);
|
|
2771
|
+
return /* @__PURE__ */ jsxs37("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
2772
|
+
/* @__PURE__ */ jsxs37("span", { className: "fd-choice-input", children: [
|
|
2773
|
+
/* @__PURE__ */ jsx42("input", { ref, type: "checkbox", ...rest }),
|
|
2774
|
+
/* @__PURE__ */ jsx42("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx42("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
|
|
2775
|
+
] }),
|
|
2776
|
+
/* @__PURE__ */ jsxs37("span", { className: "fd-choice-text", children: [
|
|
2777
|
+
/* @__PURE__ */ jsx42("span", { className: "fd-choice-title", children: label }),
|
|
2778
|
+
description ? /* @__PURE__ */ jsx42("span", { className: "fd-choice-desc", children: description }) : null
|
|
2779
|
+
] })
|
|
2780
|
+
] });
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
// src/components/forms/Radio.tsx
|
|
2784
|
+
import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
2785
|
+
function Radio({ label, description, card = false, className = "", ...rest }) {
|
|
2786
|
+
return /* @__PURE__ */ jsxs38("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
2787
|
+
/* @__PURE__ */ jsxs38("span", { className: "fd-choice-input", children: [
|
|
2788
|
+
/* @__PURE__ */ jsx43("input", { type: "radio", ...rest }),
|
|
2789
|
+
/* @__PURE__ */ jsx43("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx43("span", { className: "fd-choice-dot" }) })
|
|
2790
|
+
] }),
|
|
2791
|
+
/* @__PURE__ */ jsxs38("span", { className: "fd-choice-text", children: [
|
|
2792
|
+
/* @__PURE__ */ jsx43("span", { className: "fd-choice-title", children: label }),
|
|
2793
|
+
description ? /* @__PURE__ */ jsx43("span", { className: "fd-choice-desc", children: description }) : null
|
|
2794
|
+
] })
|
|
2795
|
+
] });
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
// src/components/forms/Switch.tsx
|
|
2799
|
+
import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
2800
|
+
function Switch({ label, description, className = "", ...rest }) {
|
|
2801
|
+
return /* @__PURE__ */ jsxs39("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
|
|
2802
|
+
/* @__PURE__ */ jsx44("input", { type: "checkbox", role: "switch", ...rest }),
|
|
2803
|
+
/* @__PURE__ */ jsx44("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx44("span", { className: "fd-switch-thumb" }) }),
|
|
2804
|
+
label ? /* @__PURE__ */ jsxs39("span", { className: "fd-choice-text", children: [
|
|
2805
|
+
/* @__PURE__ */ jsx44("span", { className: "fd-switch-label", children: label }),
|
|
2806
|
+
description ? /* @__PURE__ */ jsx44("span", { className: "fd-choice-desc", children: description }) : null
|
|
2807
|
+
] }) : null
|
|
2808
|
+
] });
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
// src/components/forms/Textarea.tsx
|
|
2812
|
+
import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
2566
2813
|
function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
|
|
2567
2814
|
const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
|
|
2568
2815
|
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : "", className].filter(Boolean).join(" ");
|
|
2569
|
-
return /* @__PURE__ */
|
|
2570
|
-
label ? /* @__PURE__ */
|
|
2816
|
+
return /* @__PURE__ */ jsxs40("div", { className: "fd-field", style, children: [
|
|
2817
|
+
label ? /* @__PURE__ */ jsxs40("label", { className: "fd-field-label", htmlFor: fieldId, children: [
|
|
2571
2818
|
label,
|
|
2572
|
-
required ? /* @__PURE__ */
|
|
2819
|
+
required ? /* @__PURE__ */ jsx45("span", { className: "fd-field-req", children: "*" }) : null
|
|
2573
2820
|
] }) : null,
|
|
2574
|
-
/* @__PURE__ */
|
|
2575
|
-
error ? /* @__PURE__ */
|
|
2576
|
-
/* @__PURE__ */
|
|
2821
|
+
/* @__PURE__ */ jsx45("div", { className: box, children: /* @__PURE__ */ jsx45("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
|
|
2822
|
+
error ? /* @__PURE__ */ jsxs40("span", { className: "fd-field-error", children: [
|
|
2823
|
+
/* @__PURE__ */ jsx45("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2577
2824
|
error
|
|
2578
|
-
] }) : help ? /* @__PURE__ */
|
|
2825
|
+
] }) : help ? /* @__PURE__ */ jsx45("span", { className: "fd-field-help", children: help }) : null
|
|
2579
2826
|
] });
|
|
2580
2827
|
}
|
|
2581
2828
|
|
|
2582
2829
|
// src/components/forms/NumberInput.tsx
|
|
2583
|
-
import * as
|
|
2584
|
-
import { jsx as
|
|
2830
|
+
import * as React18 from "react";
|
|
2831
|
+
import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
2585
2832
|
function NumberInput({
|
|
2586
2833
|
label,
|
|
2587
2834
|
help,
|
|
@@ -2605,10 +2852,10 @@ function NumberInput({
|
|
|
2605
2852
|
const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
|
|
2606
2853
|
return isNaN(n) ? null : n;
|
|
2607
2854
|
};
|
|
2608
|
-
const [text, setText] =
|
|
2609
|
-
const [editing, setEditing] =
|
|
2610
|
-
const timer =
|
|
2611
|
-
|
|
2855
|
+
const [text, setText] = React18.useState(value == null || value === "" ? "" : String(value));
|
|
2856
|
+
const [editing, setEditing] = React18.useState(false);
|
|
2857
|
+
const timer = React18.useRef(null);
|
|
2858
|
+
React18.useEffect(() => {
|
|
2612
2859
|
if (!editing) setText(value == null || value === "" ? "" : String(value));
|
|
2613
2860
|
}, [value, editing]);
|
|
2614
2861
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
@@ -2632,7 +2879,7 @@ function NumberInput({
|
|
|
2632
2879
|
const release = () => {
|
|
2633
2880
|
if (timer.current) clearTimeout(timer.current);
|
|
2634
2881
|
};
|
|
2635
|
-
|
|
2882
|
+
React18.useEffect(() => () => {
|
|
2636
2883
|
if (timer.current) clearTimeout(timer.current);
|
|
2637
2884
|
}, []);
|
|
2638
2885
|
const shown = editing ? text : (() => {
|
|
@@ -2640,14 +2887,14 @@ function NumberInput({
|
|
|
2640
2887
|
return n == null ? "" : format ? n.toLocaleString() : String(n);
|
|
2641
2888
|
})();
|
|
2642
2889
|
const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
2643
|
-
return /* @__PURE__ */
|
|
2644
|
-
label ? /* @__PURE__ */
|
|
2890
|
+
return /* @__PURE__ */ jsxs41("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
2891
|
+
label ? /* @__PURE__ */ jsxs41("label", { className: "fd-field-label", children: [
|
|
2645
2892
|
label,
|
|
2646
|
-
required ? /* @__PURE__ */
|
|
2893
|
+
required ? /* @__PURE__ */ jsx46("span", { className: "fd-field-req", children: "*" }) : null
|
|
2647
2894
|
] }) : null,
|
|
2648
|
-
/* @__PURE__ */
|
|
2649
|
-
prefix ? /* @__PURE__ */
|
|
2650
|
-
/* @__PURE__ */
|
|
2895
|
+
/* @__PURE__ */ jsxs41("div", { className: box, style: { gap: 8 }, children: [
|
|
2896
|
+
prefix ? /* @__PURE__ */ jsx46("span", { className: "fd-input-affix", children: prefix }) : null,
|
|
2897
|
+
/* @__PURE__ */ jsx46(
|
|
2651
2898
|
"input",
|
|
2652
2899
|
{
|
|
2653
2900
|
inputMode: "numeric",
|
|
@@ -2680,9 +2927,9 @@ function NumberInput({
|
|
|
2680
2927
|
}
|
|
2681
2928
|
}
|
|
2682
2929
|
),
|
|
2683
|
-
suffix ? /* @__PURE__ */
|
|
2684
|
-
/* @__PURE__ */
|
|
2685
|
-
/* @__PURE__ */
|
|
2930
|
+
suffix ? /* @__PURE__ */ jsx46("span", { className: "fd-input-affix", children: suffix }) : null,
|
|
2931
|
+
/* @__PURE__ */ jsxs41("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
|
|
2932
|
+
/* @__PURE__ */ jsx46(
|
|
2686
2933
|
"button",
|
|
2687
2934
|
{
|
|
2688
2935
|
type: "button",
|
|
@@ -2692,10 +2939,10 @@ function NumberInput({
|
|
|
2692
2939
|
onPointerDown: () => hold(-1),
|
|
2693
2940
|
onPointerUp: release,
|
|
2694
2941
|
onPointerLeave: release,
|
|
2695
|
-
children: /* @__PURE__ */
|
|
2942
|
+
children: /* @__PURE__ */ jsx46("i", { className: "ph ph-minus" })
|
|
2696
2943
|
}
|
|
2697
2944
|
),
|
|
2698
|
-
/* @__PURE__ */
|
|
2945
|
+
/* @__PURE__ */ jsx46(
|
|
2699
2946
|
"button",
|
|
2700
2947
|
{
|
|
2701
2948
|
type: "button",
|
|
@@ -2705,26 +2952,26 @@ function NumberInput({
|
|
|
2705
2952
|
onPointerDown: () => hold(1),
|
|
2706
2953
|
onPointerUp: release,
|
|
2707
2954
|
onPointerLeave: release,
|
|
2708
|
-
children: /* @__PURE__ */
|
|
2955
|
+
children: /* @__PURE__ */ jsx46("i", { className: "ph ph-plus" })
|
|
2709
2956
|
}
|
|
2710
2957
|
)
|
|
2711
2958
|
] })
|
|
2712
2959
|
] }),
|
|
2713
|
-
error ? /* @__PURE__ */
|
|
2714
|
-
/* @__PURE__ */
|
|
2960
|
+
error ? /* @__PURE__ */ jsxs41("span", { className: "fd-field-error", children: [
|
|
2961
|
+
/* @__PURE__ */ jsx46("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2715
2962
|
error
|
|
2716
|
-
] }) : help ? /* @__PURE__ */
|
|
2963
|
+
] }) : help ? /* @__PURE__ */ jsx46("span", { className: "fd-field-help", children: help }) : null
|
|
2717
2964
|
] });
|
|
2718
2965
|
}
|
|
2719
2966
|
|
|
2720
2967
|
// src/components/forms/Select.tsx
|
|
2721
|
-
import * as
|
|
2968
|
+
import * as React19 from "react";
|
|
2722
2969
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2723
|
-
import { jsx as
|
|
2970
|
+
import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
2724
2971
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
2725
2972
|
function usePopPos(open, ref, estH, estW) {
|
|
2726
|
-
const [pos, setPos] =
|
|
2727
|
-
|
|
2973
|
+
const [pos, setPos] = React19.useState(null);
|
|
2974
|
+
React19.useLayoutEffect(() => {
|
|
2728
2975
|
if (!open || !ref.current) {
|
|
2729
2976
|
setPos(null);
|
|
2730
2977
|
return;
|
|
@@ -2788,14 +3035,14 @@ function Select({
|
|
|
2788
3035
|
const vals = multiple ? Array.isArray(value) ? value : value ? [value] : [] : [];
|
|
2789
3036
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
2790
3037
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
2791
|
-
const [open, setOpen] =
|
|
2792
|
-
const [q, setQ] =
|
|
2793
|
-
const [active, setActive] =
|
|
2794
|
-
const rootRef =
|
|
2795
|
-
const boxRef =
|
|
2796
|
-
const popRef =
|
|
2797
|
-
const listRef =
|
|
2798
|
-
const typeBuf =
|
|
3038
|
+
const [open, setOpen] = React19.useState(false);
|
|
3039
|
+
const [q, setQ] = React19.useState("");
|
|
3040
|
+
const [active, setActive] = React19.useState(-1);
|
|
3041
|
+
const rootRef = React19.useRef(null);
|
|
3042
|
+
const boxRef = React19.useRef(null);
|
|
3043
|
+
const popRef = React19.useRef(null);
|
|
3044
|
+
const listRef = React19.useRef(null);
|
|
3045
|
+
const typeBuf = React19.useRef({ s: "", t: 0 });
|
|
2799
3046
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
2800
3047
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
2801
3048
|
const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
|
|
@@ -2821,7 +3068,7 @@ function Select({
|
|
|
2821
3068
|
}
|
|
2822
3069
|
setOpen(!open);
|
|
2823
3070
|
};
|
|
2824
|
-
|
|
3071
|
+
React19.useEffect(() => {
|
|
2825
3072
|
if (!open) return;
|
|
2826
3073
|
const away = (e) => {
|
|
2827
3074
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -2831,7 +3078,7 @@ function Select({
|
|
|
2831
3078
|
document.addEventListener("pointerdown", away);
|
|
2832
3079
|
return () => document.removeEventListener("pointerdown", away);
|
|
2833
3080
|
}, [open]);
|
|
2834
|
-
|
|
3081
|
+
React19.useEffect(() => {
|
|
2835
3082
|
if (!open || active < 0 || !listRef.current) return;
|
|
2836
3083
|
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
2837
3084
|
if (el) {
|
|
@@ -2885,13 +3132,13 @@ function Select({
|
|
|
2885
3132
|
});
|
|
2886
3133
|
const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
|
|
2887
3134
|
const box = ["fd-input", "fd-select", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
2888
|
-
return /* @__PURE__ */
|
|
2889
|
-
label ? /* @__PURE__ */
|
|
3135
|
+
return /* @__PURE__ */ jsxs42("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
|
|
3136
|
+
label ? /* @__PURE__ */ jsxs42("label", { className: "fd-field-label", htmlFor: fieldId, onClick: toggle, children: [
|
|
2890
3137
|
label,
|
|
2891
|
-
required ? /* @__PURE__ */
|
|
3138
|
+
required ? /* @__PURE__ */ jsx47("span", { className: "fd-field-req", children: "*" }) : null
|
|
2892
3139
|
] }) : null,
|
|
2893
|
-
/* @__PURE__ */
|
|
2894
|
-
/* @__PURE__ */
|
|
3140
|
+
/* @__PURE__ */ jsxs42("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
|
|
3141
|
+
/* @__PURE__ */ jsxs42(
|
|
2895
3142
|
"button",
|
|
2896
3143
|
{
|
|
2897
3144
|
type: "button",
|
|
@@ -2904,13 +3151,13 @@ function Select({
|
|
|
2904
3151
|
"aria-haspopup": "listbox",
|
|
2905
3152
|
style: { all: "unset", flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8, cursor: "inherit", overflow: "hidden" },
|
|
2906
3153
|
children: [
|
|
2907
|
-
selected && selected.icon ? /* @__PURE__ */
|
|
2908
|
-
/* @__PURE__ */
|
|
2909
|
-
multiple && chosen.length > 1 ? /* @__PURE__ */
|
|
3154
|
+
selected && selected.icon ? /* @__PURE__ */ jsx47("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
|
|
3155
|
+
/* @__PURE__ */ jsx47("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
|
|
3156
|
+
multiple && chosen.length > 1 ? /* @__PURE__ */ jsx47("span", { className: "fd-mono", style: { flex: "none", fontSize: 11, fontWeight: 700, padding: "1px 6px", borderRadius: 99, background: "var(--brand)", color: "#fff" }, children: chosen.length }) : null
|
|
2910
3157
|
]
|
|
2911
3158
|
}
|
|
2912
3159
|
),
|
|
2913
|
-
clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */
|
|
3160
|
+
clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx47(
|
|
2914
3161
|
"button",
|
|
2915
3162
|
{
|
|
2916
3163
|
type: "button",
|
|
@@ -2920,22 +3167,22 @@ function Select({
|
|
|
2920
3167
|
fire(multiple ? [] : "");
|
|
2921
3168
|
},
|
|
2922
3169
|
style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
|
|
2923
|
-
children: /* @__PURE__ */
|
|
3170
|
+
children: /* @__PURE__ */ jsx47("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
|
|
2924
3171
|
}
|
|
2925
3172
|
) : null,
|
|
2926
|
-
loading ? /* @__PURE__ */
|
|
3173
|
+
loading ? /* @__PURE__ */ jsx47("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx47("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx47("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
2927
3174
|
] }),
|
|
2928
3175
|
open && pos ? createPortal4(
|
|
2929
|
-
/* @__PURE__ */
|
|
3176
|
+
/* @__PURE__ */ jsxs42(
|
|
2930
3177
|
"div",
|
|
2931
3178
|
{
|
|
2932
3179
|
className: "fd-pop" + (pos.up ? " is-up" : ""),
|
|
2933
3180
|
ref: popRef,
|
|
2934
3181
|
style: popStyle(pos, { minWidth: Math.max(pos.width, 260), maxWidth: 380, zIndex: 130, overflowY: "hidden" }),
|
|
2935
3182
|
children: [
|
|
2936
|
-
hasSearch ? /* @__PURE__ */
|
|
2937
|
-
/* @__PURE__ */
|
|
2938
|
-
/* @__PURE__ */
|
|
3183
|
+
hasSearch ? /* @__PURE__ */ jsxs42("div", { className: "fd-pop-search", children: [
|
|
3184
|
+
/* @__PURE__ */ jsx47("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
|
|
3185
|
+
/* @__PURE__ */ jsx47(
|
|
2939
3186
|
"input",
|
|
2940
3187
|
{
|
|
2941
3188
|
autoFocus: true,
|
|
@@ -2948,15 +3195,15 @@ function Select({
|
|
|
2948
3195
|
}
|
|
2949
3196
|
}
|
|
2950
3197
|
),
|
|
2951
|
-
q ? /* @__PURE__ */
|
|
3198
|
+
q ? /* @__PURE__ */ jsx47("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
2952
3199
|
] }) : null,
|
|
2953
|
-
/* @__PURE__ */
|
|
3200
|
+
/* @__PURE__ */ jsx47("div", { className: "fd-pop-list", role: "listbox", "aria-multiselectable": multiple || void 0, ref: listRef, style: { maxHeight: Math.max(120, pos.maxH - (hasSearch ? 64 : 12) - (multiple ? 42 : 0)) }, children: visible.length === 0 ? /* @__PURE__ */ jsxs42("div", { className: "fd-pop-empty", children: [
|
|
2954
3201
|
'Nothing matches "',
|
|
2955
3202
|
q,
|
|
2956
3203
|
'".'
|
|
2957
|
-
] }) : groups.map((grp) => /* @__PURE__ */
|
|
2958
|
-
grp.g ? /* @__PURE__ */
|
|
2959
|
-
grp.items.map(({ o, i }) => /* @__PURE__ */
|
|
3204
|
+
] }) : groups.map((grp) => /* @__PURE__ */ jsxs42(React19.Fragment, { children: [
|
|
3205
|
+
grp.g ? /* @__PURE__ */ jsx47("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
3206
|
+
grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs42(
|
|
2960
3207
|
"button",
|
|
2961
3208
|
{
|
|
2962
3209
|
type: "button",
|
|
@@ -2968,21 +3215,21 @@ function Select({
|
|
|
2968
3215
|
onMouseEnter: () => setActive(i),
|
|
2969
3216
|
onClick: () => pick(o),
|
|
2970
3217
|
children: [
|
|
2971
|
-
multiple ? /* @__PURE__ */
|
|
2972
|
-
o.icon ? /* @__PURE__ */
|
|
2973
|
-
/* @__PURE__ */
|
|
2974
|
-
/* @__PURE__ */
|
|
2975
|
-
o.description ? /* @__PURE__ */
|
|
3218
|
+
multiple ? /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", style: { flex: "none", display: "grid", placeItems: "center", width: 16, height: 16, borderRadius: 4, border: "1.5px solid " + (isOn(o.value) ? "var(--brand)" : "var(--border-strong, var(--border))"), background: isOn(o.value) ? "var(--brand)" : "var(--surface)", color: "#fff" }, children: isOn(o.value) ? /* @__PURE__ */ jsx47("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
|
|
3219
|
+
o.icon ? /* @__PURE__ */ jsx47("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx47("i", { className: "ph ph-" + o.icon }) }) : null,
|
|
3220
|
+
/* @__PURE__ */ jsxs42("span", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3221
|
+
/* @__PURE__ */ jsx47("span", { className: "fd-opt-label", children: o.label }),
|
|
3222
|
+
o.description ? /* @__PURE__ */ jsx47("span", { className: "fd-opt-desc", children: o.description }) : null
|
|
2976
3223
|
] }),
|
|
2977
|
-
o.meta ? /* @__PURE__ */
|
|
2978
|
-
multiple ? null : /* @__PURE__ */
|
|
3224
|
+
o.meta ? /* @__PURE__ */ jsx47("span", { className: "fd-opt-meta", children: o.meta }) : null,
|
|
3225
|
+
multiple ? null : /* @__PURE__ */ jsx47("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx47("i", { className: "ph ph-check" }) : null })
|
|
2979
3226
|
]
|
|
2980
3227
|
},
|
|
2981
3228
|
String(o.value)
|
|
2982
3229
|
))
|
|
2983
3230
|
] }, grp.g || "_")) }),
|
|
2984
|
-
multiple ? /* @__PURE__ */
|
|
2985
|
-
/* @__PURE__ */
|
|
3231
|
+
multiple ? /* @__PURE__ */ jsxs42("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
|
|
3232
|
+
/* @__PURE__ */ jsx47(
|
|
2986
3233
|
"button",
|
|
2987
3234
|
{
|
|
2988
3235
|
type: "button",
|
|
@@ -2991,13 +3238,13 @@ function Select({
|
|
|
2991
3238
|
children: "Select all"
|
|
2992
3239
|
}
|
|
2993
3240
|
),
|
|
2994
|
-
/* @__PURE__ */
|
|
2995
|
-
/* @__PURE__ */
|
|
3241
|
+
/* @__PURE__ */ jsx47("span", { style: { flex: 1 } }),
|
|
3242
|
+
/* @__PURE__ */ jsxs42("span", { className: "fd-body-sm fd-muted", children: [
|
|
2996
3243
|
vals.length,
|
|
2997
3244
|
" of ",
|
|
2998
3245
|
opts.length
|
|
2999
3246
|
] }),
|
|
3000
|
-
/* @__PURE__ */
|
|
3247
|
+
/* @__PURE__ */ jsx47(
|
|
3001
3248
|
"button",
|
|
3002
3249
|
{
|
|
3003
3250
|
type: "button",
|
|
@@ -3013,17 +3260,17 @@ function Select({
|
|
|
3013
3260
|
),
|
|
3014
3261
|
document.body
|
|
3015
3262
|
) : null,
|
|
3016
|
-
error ? /* @__PURE__ */
|
|
3017
|
-
/* @__PURE__ */
|
|
3263
|
+
error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
|
|
3264
|
+
/* @__PURE__ */ jsx47("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3018
3265
|
error
|
|
3019
|
-
] }) : help ? /* @__PURE__ */
|
|
3266
|
+
] }) : help ? /* @__PURE__ */ jsx47("span", { className: "fd-field-help", children: help }) : null
|
|
3020
3267
|
] });
|
|
3021
3268
|
}
|
|
3022
3269
|
|
|
3023
3270
|
// src/components/forms/DatePicker.tsx
|
|
3024
|
-
import * as
|
|
3271
|
+
import * as React20 from "react";
|
|
3025
3272
|
import { createPortal as createPortal5 } from "react-dom";
|
|
3026
|
-
import { jsx as
|
|
3273
|
+
import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3027
3274
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3028
3275
|
var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
3029
3276
|
var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
|
|
@@ -3037,8 +3284,8 @@ var fmt = (s) => {
|
|
|
3037
3284
|
return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
|
|
3038
3285
|
};
|
|
3039
3286
|
function usePopPos2(open, ref, estH, estW) {
|
|
3040
|
-
const [pos, setPos] =
|
|
3041
|
-
|
|
3287
|
+
const [pos, setPos] = React20.useState(null);
|
|
3288
|
+
React20.useLayoutEffect(() => {
|
|
3042
3289
|
if (!open || !ref.current) {
|
|
3043
3290
|
setPos(null);
|
|
3044
3291
|
return;
|
|
@@ -3082,10 +3329,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3082
3329
|
const today = /* @__PURE__ */ new Date();
|
|
3083
3330
|
const sel = range ? value || {} : { start: value, end: value };
|
|
3084
3331
|
const anchor = parse(sel.start) || parse(initialMonth) || today;
|
|
3085
|
-
const [vy, setVy] =
|
|
3086
|
-
const [vm, setVm] =
|
|
3087
|
-
const [mode2, setMode] =
|
|
3088
|
-
const [hover, setHover] =
|
|
3332
|
+
const [vy, setVy] = React20.useState(anchor.getFullYear());
|
|
3333
|
+
const [vm, setVm] = React20.useState(anchor.getMonth());
|
|
3334
|
+
const [mode2, setMode] = React20.useState("days");
|
|
3335
|
+
const [hover, setHover] = React20.useState(null);
|
|
3089
3336
|
const s = parse(sel.start), e = parse(sel.end);
|
|
3090
3337
|
const hoverEnd = range && s && !e && hover ? parse(hover) : null;
|
|
3091
3338
|
const inRange = (d) => {
|
|
@@ -3122,9 +3369,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3122
3369
|
const startPad = new Date(y, m, 1).getDay();
|
|
3123
3370
|
const cells = [];
|
|
3124
3371
|
for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
|
|
3125
|
-
return /* @__PURE__ */
|
|
3126
|
-
DOW.map((d) => /* @__PURE__ */
|
|
3127
|
-
cells.map((d, i) => /* @__PURE__ */
|
|
3372
|
+
return /* @__PURE__ */ jsxs43("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
|
|
3373
|
+
DOW.map((d) => /* @__PURE__ */ jsx48("span", { className: "fd-cal-dow", children: d }, d)),
|
|
3374
|
+
cells.map((d, i) => /* @__PURE__ */ jsx48(
|
|
3128
3375
|
"button",
|
|
3129
3376
|
{
|
|
3130
3377
|
type: "button",
|
|
@@ -3138,20 +3385,20 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3138
3385
|
] });
|
|
3139
3386
|
};
|
|
3140
3387
|
const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
|
|
3141
|
-
return /* @__PURE__ */
|
|
3142
|
-
/* @__PURE__ */
|
|
3143
|
-
/* @__PURE__ */
|
|
3144
|
-
/* @__PURE__ */
|
|
3388
|
+
return /* @__PURE__ */ jsxs43("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
|
|
3389
|
+
/* @__PURE__ */ jsxs43("div", { className: "fd-cal-head", children: [
|
|
3390
|
+
/* @__PURE__ */ jsx48("button", { type: "button", className: "fd-btn-icon", "aria-label": "Previous", onClick: () => mode2 === "years" ? setVy(vy - 12) : mode2 === "months" ? setVy(vy - 1) : nav(-1), children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-left" }) }),
|
|
3391
|
+
/* @__PURE__ */ jsxs43("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
|
|
3145
3392
|
mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
|
|
3146
|
-
/* @__PURE__ */
|
|
3393
|
+
/* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
|
|
3147
3394
|
] }),
|
|
3148
|
-
months > 1 && mode2 === "days" ? /* @__PURE__ */
|
|
3149
|
-
/* @__PURE__ */
|
|
3395
|
+
months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx48("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
|
|
3396
|
+
/* @__PURE__ */ jsx48("button", { type: "button", className: "fd-btn-icon", "aria-label": "Next", onClick: () => mode2 === "years" ? setVy(vy + 12) : mode2 === "months" ? setVy(vy + 1) : nav(1), children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-right" }) })
|
|
3150
3397
|
] }),
|
|
3151
|
-
mode2 === "days" ? /* @__PURE__ */
|
|
3398
|
+
mode2 === "days" ? /* @__PURE__ */ jsxs43("div", { style: { display: "flex", gap: 18 }, children: [
|
|
3152
3399
|
monthGrid(vy, vm),
|
|
3153
3400
|
months > 1 ? monthGrid(nextY, nextM) : null
|
|
3154
|
-
] }) : mode2 === "months" ? /* @__PURE__ */
|
|
3401
|
+
] }) : mode2 === "months" ? /* @__PURE__ */ jsx48("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx48(
|
|
3155
3402
|
"button",
|
|
3156
3403
|
{
|
|
3157
3404
|
type: "button",
|
|
@@ -3163,7 +3410,7 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3163
3410
|
children: m.slice(0, 3)
|
|
3164
3411
|
},
|
|
3165
3412
|
m
|
|
3166
|
-
)) }) : /* @__PURE__ */
|
|
3413
|
+
)) }) : /* @__PURE__ */ jsx48("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx48(
|
|
3167
3414
|
"button",
|
|
3168
3415
|
{
|
|
3169
3416
|
type: "button",
|
|
@@ -3176,8 +3423,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3176
3423
|
},
|
|
3177
3424
|
y
|
|
3178
3425
|
)) }),
|
|
3179
|
-
/* @__PURE__ */
|
|
3180
|
-
/* @__PURE__ */
|
|
3426
|
+
/* @__PURE__ */ jsxs43("div", { className: "fd-cal-foot", children: [
|
|
3427
|
+
/* @__PURE__ */ jsx48(
|
|
3181
3428
|
"button",
|
|
3182
3429
|
{
|
|
3183
3430
|
type: "button",
|
|
@@ -3191,8 +3438,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3191
3438
|
children: "Today"
|
|
3192
3439
|
}
|
|
3193
3440
|
),
|
|
3194
|
-
/* @__PURE__ */
|
|
3195
|
-
range && sel.start ? /* @__PURE__ */
|
|
3441
|
+
/* @__PURE__ */ jsx48("span", { style: { flex: 1 } }),
|
|
3442
|
+
range && sel.start ? /* @__PURE__ */ jsxs43("span", { className: "fd-body-sm fd-muted", children: [
|
|
3196
3443
|
fmt(sel.start),
|
|
3197
3444
|
sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
|
|
3198
3445
|
] }) : null
|
|
@@ -3200,12 +3447,12 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3200
3447
|
] });
|
|
3201
3448
|
}
|
|
3202
3449
|
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, className = "", style, ...rest }) {
|
|
3203
|
-
const [open, setOpen] =
|
|
3204
|
-
const rootRef =
|
|
3205
|
-
const boxRef =
|
|
3206
|
-
const popRef =
|
|
3450
|
+
const [open, setOpen] = React20.useState(false);
|
|
3451
|
+
const rootRef = React20.useRef(null);
|
|
3452
|
+
const boxRef = React20.useRef(null);
|
|
3453
|
+
const popRef = React20.useRef(null);
|
|
3207
3454
|
const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
|
|
3208
|
-
|
|
3455
|
+
React20.useEffect(() => {
|
|
3209
3456
|
if (!open) return;
|
|
3210
3457
|
const away = (e) => {
|
|
3211
3458
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -3226,14 +3473,14 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3226
3473
|
const toggle = () => {
|
|
3227
3474
|
if (!disabled) setOpen(!open);
|
|
3228
3475
|
};
|
|
3229
|
-
return /* @__PURE__ */
|
|
3230
|
-
label ? /* @__PURE__ */
|
|
3476
|
+
return /* @__PURE__ */ jsxs43("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
|
|
3477
|
+
label ? /* @__PURE__ */ jsxs43("label", { className: "fd-field-label", onClick: toggle, children: [
|
|
3231
3478
|
label,
|
|
3232
|
-
required ? /* @__PURE__ */
|
|
3479
|
+
required ? /* @__PURE__ */ jsx48("span", { className: "fd-field-req", children: "*" }) : null
|
|
3233
3480
|
] }) : null,
|
|
3234
|
-
/* @__PURE__ */
|
|
3235
|
-
/* @__PURE__ */
|
|
3236
|
-
/* @__PURE__ */
|
|
3481
|
+
/* @__PURE__ */ jsxs43("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
|
|
3482
|
+
/* @__PURE__ */ jsx48("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
|
|
3483
|
+
/* @__PURE__ */ jsx48(
|
|
3237
3484
|
"button",
|
|
3238
3485
|
{
|
|
3239
3486
|
type: "button",
|
|
@@ -3249,10 +3496,10 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3249
3496
|
children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
|
|
3250
3497
|
}
|
|
3251
3498
|
),
|
|
3252
|
-
/* @__PURE__ */
|
|
3499
|
+
/* @__PURE__ */ jsx48("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3253
3500
|
] }),
|
|
3254
3501
|
open && pos ? createPortal5(
|
|
3255
|
-
/* @__PURE__ */
|
|
3502
|
+
/* @__PURE__ */ jsx48("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ jsx48(
|
|
3256
3503
|
Calendar,
|
|
3257
3504
|
{
|
|
3258
3505
|
range,
|
|
@@ -3266,21 +3513,21 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3266
3513
|
) }),
|
|
3267
3514
|
document.body
|
|
3268
3515
|
) : null,
|
|
3269
|
-
error ? /* @__PURE__ */
|
|
3270
|
-
/* @__PURE__ */
|
|
3516
|
+
error ? /* @__PURE__ */ jsxs43("span", { className: "fd-field-error", children: [
|
|
3517
|
+
/* @__PURE__ */ jsx48("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3271
3518
|
error
|
|
3272
|
-
] }) : help ? /* @__PURE__ */
|
|
3519
|
+
] }) : help ? /* @__PURE__ */ jsx48("span", { className: "fd-field-help", children: help }) : null
|
|
3273
3520
|
] });
|
|
3274
3521
|
}
|
|
3275
3522
|
|
|
3276
3523
|
// src/components/forms/TimePicker.tsx
|
|
3277
|
-
import * as
|
|
3524
|
+
import * as React21 from "react";
|
|
3278
3525
|
import { createPortal as createPortal6 } from "react-dom";
|
|
3279
|
-
import { jsx as
|
|
3526
|
+
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3280
3527
|
var pad = (n) => String(n).padStart(2, "0");
|
|
3281
3528
|
function usePopPos3(open, ref, estH, estW) {
|
|
3282
|
-
const [pos, setPos] =
|
|
3283
|
-
|
|
3529
|
+
const [pos, setPos] = React21.useState(null);
|
|
3530
|
+
React21.useLayoutEffect(() => {
|
|
3284
3531
|
if (!open || !ref.current) {
|
|
3285
3532
|
setPos(null);
|
|
3286
3533
|
return;
|
|
@@ -3326,9 +3573,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3326
3573
|
if (isNaN(m)) m = 0;
|
|
3327
3574
|
const pm = h24 >= 12;
|
|
3328
3575
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
3329
|
-
const [mode2, setMode] =
|
|
3330
|
-
const faceRef =
|
|
3331
|
-
const dragging =
|
|
3576
|
+
const [mode2, setMode] = React21.useState("h");
|
|
3577
|
+
const faceRef = React21.useRef(null);
|
|
3578
|
+
const dragging = React21.useRef(false);
|
|
3332
3579
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
3333
3580
|
const R = 108, NR = 80;
|
|
3334
3581
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -3363,12 +3610,12 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3363
3610
|
};
|
|
3364
3611
|
const handAngle = mode2 === "h" ? h12 % 12 * 30 : m * 6;
|
|
3365
3612
|
const minuteOff = mode2 === "m" && m % 5 !== 0;
|
|
3366
|
-
return /* @__PURE__ */
|
|
3367
|
-
/* @__PURE__ */
|
|
3368
|
-
/* @__PURE__ */
|
|
3369
|
-
/* @__PURE__ */
|
|
3370
|
-
/* @__PURE__ */
|
|
3371
|
-
/* @__PURE__ */
|
|
3613
|
+
return /* @__PURE__ */ jsxs44("div", { style: { padding: "4px 14px 14px" }, children: [
|
|
3614
|
+
/* @__PURE__ */ jsxs44("div", { className: "fd-clock-digits", children: [
|
|
3615
|
+
/* @__PURE__ */ jsx49("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
|
|
3616
|
+
/* @__PURE__ */ jsx49("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
|
|
3617
|
+
/* @__PURE__ */ jsx49("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
|
|
3618
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ jsx49(
|
|
3372
3619
|
"button",
|
|
3373
3620
|
{
|
|
3374
3621
|
type: "button",
|
|
@@ -3379,13 +3626,13 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3379
3626
|
ap
|
|
3380
3627
|
)) })
|
|
3381
3628
|
] }),
|
|
3382
|
-
/* @__PURE__ */
|
|
3383
|
-
/* @__PURE__ */
|
|
3384
|
-
/* @__PURE__ */
|
|
3385
|
-
minuteOff ? /* @__PURE__ */
|
|
3629
|
+
/* @__PURE__ */ jsxs44("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
|
|
3630
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
|
|
3631
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-clock-pivot" }),
|
|
3632
|
+
minuteOff ? /* @__PURE__ */ jsx49("span", { style: { position: "absolute", left: "50%", top: "50%", width: 10, height: 10, margin: -5, borderRadius: "50%", border: "2px solid var(--brand)", background: "var(--surface)", transform: "rotate(" + handAngle + "deg) translateY(-" + (NR - 6) + "px)", transformOrigin: "center", pointerEvents: "none" } }) : null,
|
|
3386
3633
|
nums.map((n) => {
|
|
3387
3634
|
const a = angleOf(n) * Math.PI / 180;
|
|
3388
|
-
return /* @__PURE__ */
|
|
3635
|
+
return /* @__PURE__ */ jsx49(
|
|
3389
3636
|
"span",
|
|
3390
3637
|
{
|
|
3391
3638
|
className: "fd-clock-num" + (n === selNum || mode2 === "m" && n === Math.round(m / 5) * 5 % 60 && m % 5 === 0 ? " is-sel" : ""),
|
|
@@ -3396,16 +3643,16 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3396
3643
|
);
|
|
3397
3644
|
})
|
|
3398
3645
|
] }),
|
|
3399
|
-
/* @__PURE__ */
|
|
3646
|
+
/* @__PURE__ */ jsx49("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
|
|
3400
3647
|
] });
|
|
3401
3648
|
}
|
|
3402
3649
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", className = "", style }) {
|
|
3403
|
-
const [open, setOpen] =
|
|
3404
|
-
const rootRef =
|
|
3405
|
-
const boxRef =
|
|
3406
|
-
const popRef =
|
|
3650
|
+
const [open, setOpen] = React21.useState(false);
|
|
3651
|
+
const rootRef = React21.useRef(null);
|
|
3652
|
+
const boxRef = React21.useRef(null);
|
|
3653
|
+
const popRef = React21.useRef(null);
|
|
3407
3654
|
const pos = usePopPos3(open, boxRef, 420, 262);
|
|
3408
|
-
|
|
3655
|
+
React21.useEffect(() => {
|
|
3409
3656
|
if (!open) return;
|
|
3410
3657
|
const away = (e) => {
|
|
3411
3658
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -3430,14 +3677,14 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3430
3677
|
const toggle = () => {
|
|
3431
3678
|
if (!disabled) setOpen(!open);
|
|
3432
3679
|
};
|
|
3433
|
-
return /* @__PURE__ */
|
|
3434
|
-
label ? /* @__PURE__ */
|
|
3680
|
+
return /* @__PURE__ */ jsxs44("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
|
|
3681
|
+
label ? /* @__PURE__ */ jsxs44("label", { className: "fd-field-label", onClick: toggle, children: [
|
|
3435
3682
|
label,
|
|
3436
|
-
required ? /* @__PURE__ */
|
|
3683
|
+
required ? /* @__PURE__ */ jsx49("span", { className: "fd-field-req", children: "*" }) : null
|
|
3437
3684
|
] }) : null,
|
|
3438
|
-
/* @__PURE__ */
|
|
3439
|
-
/* @__PURE__ */
|
|
3440
|
-
/* @__PURE__ */
|
|
3685
|
+
/* @__PURE__ */ jsxs44("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
|
|
3686
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
|
|
3687
|
+
/* @__PURE__ */ jsx49(
|
|
3441
3688
|
"button",
|
|
3442
3689
|
{
|
|
3443
3690
|
type: "button",
|
|
@@ -3452,13 +3699,13 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3452
3699
|
children: disp() || placeholder
|
|
3453
3700
|
}
|
|
3454
3701
|
),
|
|
3455
|
-
/* @__PURE__ */
|
|
3702
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3456
3703
|
] }),
|
|
3457
3704
|
open && pos ? createPortal6(
|
|
3458
|
-
/* @__PURE__ */
|
|
3459
|
-
/* @__PURE__ */
|
|
3460
|
-
/* @__PURE__ */
|
|
3461
|
-
/* @__PURE__ */
|
|
3705
|
+
/* @__PURE__ */ jsxs44("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
|
|
3706
|
+
/* @__PURE__ */ jsx49(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
|
|
3707
|
+
/* @__PURE__ */ jsxs44("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
|
|
3708
|
+
/* @__PURE__ */ jsx49(
|
|
3462
3709
|
"button",
|
|
3463
3710
|
{
|
|
3464
3711
|
type: "button",
|
|
@@ -3471,22 +3718,22 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3471
3718
|
children: "Now"
|
|
3472
3719
|
}
|
|
3473
3720
|
),
|
|
3474
|
-
/* @__PURE__ */
|
|
3475
|
-
/* @__PURE__ */
|
|
3721
|
+
/* @__PURE__ */ jsx49("span", { style: { flex: 1 } }),
|
|
3722
|
+
/* @__PURE__ */ jsx49("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
|
|
3476
3723
|
] })
|
|
3477
3724
|
] }),
|
|
3478
3725
|
document.body
|
|
3479
3726
|
) : null,
|
|
3480
|
-
error ? /* @__PURE__ */
|
|
3481
|
-
/* @__PURE__ */
|
|
3727
|
+
error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
|
|
3728
|
+
/* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3482
3729
|
error
|
|
3483
|
-
] }) : help ? /* @__PURE__ */
|
|
3730
|
+
] }) : help ? /* @__PURE__ */ jsx49("span", { className: "fd-field-help", children: help }) : null
|
|
3484
3731
|
] });
|
|
3485
3732
|
}
|
|
3486
3733
|
|
|
3487
3734
|
// src/components/forms/Slider.tsx
|
|
3488
|
-
import * as
|
|
3489
|
-
import { jsx as
|
|
3735
|
+
import * as React22 from "react";
|
|
3736
|
+
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3490
3737
|
function Slider({
|
|
3491
3738
|
label,
|
|
3492
3739
|
min = 0,
|
|
@@ -3500,18 +3747,18 @@ function Slider({
|
|
|
3500
3747
|
className = "",
|
|
3501
3748
|
...rest
|
|
3502
3749
|
}) {
|
|
3503
|
-
const [dragging, setDragging] =
|
|
3750
|
+
const [dragging, setDragging] = React22.useState(false);
|
|
3504
3751
|
const v = value === void 0 ? min : Number(value);
|
|
3505
3752
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
3506
|
-
return /* @__PURE__ */
|
|
3507
|
-
label ? /* @__PURE__ */
|
|
3508
|
-
/* @__PURE__ */
|
|
3509
|
-
/* @__PURE__ */
|
|
3753
|
+
return /* @__PURE__ */ jsxs45("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
3754
|
+
label ? /* @__PURE__ */ jsxs45("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
3755
|
+
/* @__PURE__ */ jsx50("span", { className: "fd-field-label", children: label }),
|
|
3756
|
+
/* @__PURE__ */ jsx50("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
|
|
3510
3757
|
] }) : null,
|
|
3511
|
-
/* @__PURE__ */
|
|
3512
|
-
/* @__PURE__ */
|
|
3513
|
-
showChip && dragging ? /* @__PURE__ */
|
|
3514
|
-
/* @__PURE__ */
|
|
3758
|
+
/* @__PURE__ */ jsxs45("div", { className: "fd-slider", children: [
|
|
3759
|
+
/* @__PURE__ */ jsx50("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
3760
|
+
showChip && dragging ? /* @__PURE__ */ jsx50("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
|
|
3761
|
+
/* @__PURE__ */ jsx50(
|
|
3515
3762
|
"input",
|
|
3516
3763
|
{
|
|
3517
3764
|
type: "range",
|
|
@@ -3528,13 +3775,13 @@ function Slider({
|
|
|
3528
3775
|
}
|
|
3529
3776
|
)
|
|
3530
3777
|
] }),
|
|
3531
|
-
help ? /* @__PURE__ */
|
|
3778
|
+
help ? /* @__PURE__ */ jsx50("span", { className: "fd-field-help", children: help }) : null
|
|
3532
3779
|
] });
|
|
3533
3780
|
}
|
|
3534
3781
|
|
|
3535
3782
|
// src/components/forms/RangeSlider.tsx
|
|
3536
|
-
import * as
|
|
3537
|
-
import { jsx as
|
|
3783
|
+
import * as React23 from "react";
|
|
3784
|
+
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3538
3785
|
function RangeSlider({
|
|
3539
3786
|
label,
|
|
3540
3787
|
min = 0,
|
|
@@ -3553,9 +3800,9 @@ function RangeSlider({
|
|
|
3553
3800
|
}) {
|
|
3554
3801
|
const fmt2 = format || ((v) => String(v));
|
|
3555
3802
|
const [a, b] = value || [min, max];
|
|
3556
|
-
const [drag, setDrag] =
|
|
3557
|
-
const [focus, setFocus] =
|
|
3558
|
-
const railRef =
|
|
3803
|
+
const [drag, setDrag] = React23.useState(null);
|
|
3804
|
+
const [focus, setFocus] = React23.useState(null);
|
|
3805
|
+
const railRef = React23.useRef(null);
|
|
3559
3806
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
3560
3807
|
const clampPair = (i, v) => {
|
|
3561
3808
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -3570,7 +3817,7 @@ function RangeSlider({
|
|
|
3570
3817
|
const r = railRef.current.getBoundingClientRect();
|
|
3571
3818
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
3572
3819
|
};
|
|
3573
|
-
|
|
3820
|
+
React23.useEffect(() => {
|
|
3574
3821
|
if (drag === null) return;
|
|
3575
3822
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
3576
3823
|
const upH = () => setDrag(null);
|
|
@@ -3591,7 +3838,7 @@ function RangeSlider({
|
|
|
3591
3838
|
};
|
|
3592
3839
|
const thin = S.length > 7 ? Math.ceil(S.length / 5) : 1;
|
|
3593
3840
|
const pair = value || [S[0].value, S[S.length - 1].value];
|
|
3594
|
-
return /* @__PURE__ */
|
|
3841
|
+
return /* @__PURE__ */ jsx51(
|
|
3595
3842
|
RangeSlider,
|
|
3596
3843
|
{
|
|
3597
3844
|
...rest,
|
|
@@ -3639,23 +3886,23 @@ function RangeSlider({
|
|
|
3639
3886
|
};
|
|
3640
3887
|
const showChip = (i) => drag === i || focus === i;
|
|
3641
3888
|
const hasLabels = marks.some((m) => m.label);
|
|
3642
|
-
return /* @__PURE__ */
|
|
3643
|
-
label ? /* @__PURE__ */
|
|
3644
|
-
/* @__PURE__ */
|
|
3645
|
-
/* @__PURE__ */
|
|
3889
|
+
return /* @__PURE__ */ jsxs46("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
|
|
3890
|
+
label ? /* @__PURE__ */ jsxs46("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
3891
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-field-label", children: label }),
|
|
3892
|
+
/* @__PURE__ */ jsxs46("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
|
|
3646
3893
|
fmt2(a),
|
|
3647
3894
|
" \u2013 ",
|
|
3648
3895
|
fmt2(b)
|
|
3649
3896
|
] })
|
|
3650
3897
|
] }) : null,
|
|
3651
|
-
/* @__PURE__ */
|
|
3652
|
-
/* @__PURE__ */
|
|
3653
|
-
/* @__PURE__ */
|
|
3654
|
-
marks.map((m) => /* @__PURE__ */
|
|
3655
|
-
/* @__PURE__ */
|
|
3656
|
-
m.label ? /* @__PURE__ */
|
|
3898
|
+
/* @__PURE__ */ jsxs46("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
3899
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-range-rail", ref: railRef }),
|
|
3900
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
3901
|
+
marks.map((m) => /* @__PURE__ */ jsxs46(React23.Fragment, { children: [
|
|
3902
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
3903
|
+
m.label ? /* @__PURE__ */ jsx51("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
3657
3904
|
] }, m.value)),
|
|
3658
|
-
[a, b].map((v, i) => /* @__PURE__ */
|
|
3905
|
+
[a, b].map((v, i) => /* @__PURE__ */ jsx51(
|
|
3659
3906
|
"span",
|
|
3660
3907
|
{
|
|
3661
3908
|
className: "fd-range-thumb" + (drag === i ? " is-drag" : ""),
|
|
@@ -3670,18 +3917,18 @@ function RangeSlider({
|
|
|
3670
3917
|
onKeyDown: key(i),
|
|
3671
3918
|
onFocus: () => setFocus(i),
|
|
3672
3919
|
onBlur: () => setFocus(null),
|
|
3673
|
-
children: /* @__PURE__ */
|
|
3920
|
+
children: /* @__PURE__ */ jsx51("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
|
|
3674
3921
|
},
|
|
3675
3922
|
i
|
|
3676
3923
|
))
|
|
3677
3924
|
] }),
|
|
3678
|
-
help ? /* @__PURE__ */
|
|
3925
|
+
help ? /* @__PURE__ */ jsx51("span", { className: "fd-field-help", children: help }) : null
|
|
3679
3926
|
] });
|
|
3680
3927
|
}
|
|
3681
3928
|
|
|
3682
3929
|
// src/components/forms/Dropzone.tsx
|
|
3683
|
-
import * as
|
|
3684
|
-
import { jsx as
|
|
3930
|
+
import * as React24 from "react";
|
|
3931
|
+
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
3685
3932
|
function Dropzone({
|
|
3686
3933
|
onFiles,
|
|
3687
3934
|
onReject,
|
|
@@ -3695,8 +3942,8 @@ function Dropzone({
|
|
|
3695
3942
|
className = "",
|
|
3696
3943
|
style
|
|
3697
3944
|
}) {
|
|
3698
|
-
const [over, setOver] =
|
|
3699
|
-
const depth =
|
|
3945
|
+
const [over, setOver] = React24.useState(false);
|
|
3946
|
+
const depth = React24.useRef(0);
|
|
3700
3947
|
const has = (e) => {
|
|
3701
3948
|
const dt = e.dataTransfer;
|
|
3702
3949
|
if (!dt) return false;
|
|
@@ -3726,7 +3973,7 @@ function Dropzone({
|
|
|
3726
3973
|
if (rejected.length && onReject) onReject(rejected);
|
|
3727
3974
|
if (accepted.length && onFiles) onFiles(accepted);
|
|
3728
3975
|
};
|
|
3729
|
-
return /* @__PURE__ */
|
|
3976
|
+
return /* @__PURE__ */ jsxs47(
|
|
3730
3977
|
"div",
|
|
3731
3978
|
{
|
|
3732
3979
|
className: ["fd-dropzone", over ? "is-over" : "", className].filter(Boolean).join(" "),
|
|
@@ -3737,10 +3984,10 @@ function Dropzone({
|
|
|
3737
3984
|
onDrop: drop,
|
|
3738
3985
|
children: [
|
|
3739
3986
|
children,
|
|
3740
|
-
over ? /* @__PURE__ */
|
|
3741
|
-
/* @__PURE__ */
|
|
3742
|
-
/* @__PURE__ */
|
|
3743
|
-
hint ? /* @__PURE__ */
|
|
3987
|
+
over ? /* @__PURE__ */ jsx52("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ jsxs47("div", { className: "fd-dropzone-card", children: [
|
|
3988
|
+
/* @__PURE__ */ jsx52("i", { className: "ph ph-tray-arrow-down" }),
|
|
3989
|
+
/* @__PURE__ */ jsx52("span", { className: "fd-dropzone-label", children: label }),
|
|
3990
|
+
hint ? /* @__PURE__ */ jsx52("span", { className: "fd-dropzone-hint", children: hint }) : null
|
|
3744
3991
|
] }) }) : null
|
|
3745
3992
|
]
|
|
3746
3993
|
}
|
|
@@ -3758,9 +4005,9 @@ function FilePickButton({
|
|
|
3758
4005
|
className = "",
|
|
3759
4006
|
children
|
|
3760
4007
|
}) {
|
|
3761
|
-
const ref =
|
|
3762
|
-
return /* @__PURE__ */
|
|
3763
|
-
/* @__PURE__ */
|
|
4008
|
+
const ref = React24.useRef(null);
|
|
4009
|
+
return /* @__PURE__ */ jsxs47(React24.Fragment, { children: [
|
|
4010
|
+
/* @__PURE__ */ jsx52(
|
|
3764
4011
|
"button",
|
|
3765
4012
|
{
|
|
3766
4013
|
type: "button",
|
|
@@ -3769,10 +4016,10 @@ function FilePickButton({
|
|
|
3769
4016
|
"aria-label": label,
|
|
3770
4017
|
title: label,
|
|
3771
4018
|
onClick: () => ref.current && ref.current.click(),
|
|
3772
|
-
children: children != null ? children : /* @__PURE__ */
|
|
4019
|
+
children: children != null ? children : /* @__PURE__ */ jsx52("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
|
|
3773
4020
|
}
|
|
3774
4021
|
),
|
|
3775
|
-
/* @__PURE__ */
|
|
4022
|
+
/* @__PURE__ */ jsx52(
|
|
3776
4023
|
"input",
|
|
3777
4024
|
{
|
|
3778
4025
|
ref,
|
|
@@ -3792,10 +4039,10 @@ function FilePickButton({
|
|
|
3792
4039
|
}
|
|
3793
4040
|
function useStagedFiles(upload, opts) {
|
|
3794
4041
|
const o = opts || {};
|
|
3795
|
-
const [items, setItems] =
|
|
3796
|
-
const controllers =
|
|
4042
|
+
const [items, setItems] = React24.useState([]);
|
|
4043
|
+
const controllers = React24.useRef({});
|
|
3797
4044
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
3798
|
-
const run =
|
|
4045
|
+
const run = React24.useCallback((att) => {
|
|
3799
4046
|
if (!upload) return;
|
|
3800
4047
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
3801
4048
|
controllers.current[att.id] = ac;
|
|
@@ -3812,14 +4059,14 @@ function useStagedFiles(upload, opts) {
|
|
|
3812
4059
|
delete controllers.current[att.id];
|
|
3813
4060
|
});
|
|
3814
4061
|
}, [upload]);
|
|
3815
|
-
const add =
|
|
4062
|
+
const add = React24.useCallback((files) => {
|
|
3816
4063
|
if (!upload) return [];
|
|
3817
4064
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
3818
4065
|
setItems((list) => list.concat(atts));
|
|
3819
4066
|
atts.forEach(run);
|
|
3820
4067
|
return atts;
|
|
3821
4068
|
}, [upload, run]);
|
|
3822
|
-
const remove =
|
|
4069
|
+
const remove = React24.useCallback((att) => {
|
|
3823
4070
|
const ac = controllers.current[att.id];
|
|
3824
4071
|
if (ac) {
|
|
3825
4072
|
try {
|
|
@@ -3830,10 +4077,10 @@ function useStagedFiles(upload, opts) {
|
|
|
3830
4077
|
}
|
|
3831
4078
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
3832
4079
|
}, []);
|
|
3833
|
-
const retry =
|
|
4080
|
+
const retry = React24.useCallback((att) => {
|
|
3834
4081
|
run(att);
|
|
3835
4082
|
}, [run]);
|
|
3836
|
-
const clear =
|
|
4083
|
+
const clear = React24.useCallback(() => {
|
|
3837
4084
|
Object.values(controllers.current).forEach((ac) => {
|
|
3838
4085
|
try {
|
|
3839
4086
|
ac && ac.abort();
|
|
@@ -3849,7 +4096,7 @@ function useStagedFiles(upload, opts) {
|
|
|
3849
4096
|
var DropzoneKit = { useStagedFiles };
|
|
3850
4097
|
|
|
3851
4098
|
// src/components/forms/FileGrid.tsx
|
|
3852
|
-
import { jsx as
|
|
4099
|
+
import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
3853
4100
|
var truncateMiddle = (name, max = 34) => {
|
|
3854
4101
|
if (!name || name.length <= max) return name;
|
|
3855
4102
|
const ext = /\.[A-Za-z0-9]+$/.exec(name);
|
|
@@ -3858,7 +4105,7 @@ var truncateMiddle = (name, max = 34) => {
|
|
|
3858
4105
|
return head + "\u2026" + tail;
|
|
3859
4106
|
};
|
|
3860
4107
|
function Progress({ value }) {
|
|
3861
|
-
return /* @__PURE__ */
|
|
4108
|
+
return /* @__PURE__ */ jsx53("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ jsx53("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
|
|
3862
4109
|
}
|
|
3863
4110
|
function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false, className = "" }) {
|
|
3864
4111
|
if (!file) return null;
|
|
@@ -3867,8 +4114,8 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
3867
4114
|
const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
|
|
3868
4115
|
const meta = file.meta || (file.size ? formatBytes(file.size) : "");
|
|
3869
4116
|
const clickable = !!onOpen && !uploading;
|
|
3870
|
-
return /* @__PURE__ */
|
|
3871
|
-
/* @__PURE__ */
|
|
4117
|
+
return /* @__PURE__ */ jsxs48("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
|
|
4118
|
+
/* @__PURE__ */ jsxs48(
|
|
3872
4119
|
"button",
|
|
3873
4120
|
{
|
|
3874
4121
|
type: "button",
|
|
@@ -3877,16 +4124,16 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
3877
4124
|
onClick: clickable ? () => onOpen(file) : void 0,
|
|
3878
4125
|
title: file.name + (meta ? " \xB7 " + meta : ""),
|
|
3879
4126
|
children: [
|
|
3880
|
-
/* @__PURE__ */
|
|
3881
|
-
thumb ? /* @__PURE__ */
|
|
3882
|
-
(file.mime || "").startsWith("video/") ? /* @__PURE__ */
|
|
4127
|
+
/* @__PURE__ */ jsxs48("span", { className: "fd-file-icon", children: [
|
|
4128
|
+
thumb ? /* @__PURE__ */ jsx53("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsx53("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
|
|
4129
|
+
(file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx53("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
|
|
3883
4130
|
] }),
|
|
3884
|
-
/* @__PURE__ */
|
|
3885
|
-
/* @__PURE__ */
|
|
3886
|
-
/* @__PURE__ */
|
|
3887
|
-
/* @__PURE__ */
|
|
4131
|
+
/* @__PURE__ */ jsxs48("span", { className: "fd-file-text", children: [
|
|
4132
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
|
|
4133
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ jsxs48("span", { className: "fd-file-err", children: [
|
|
4134
|
+
/* @__PURE__ */ jsx53("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3888
4135
|
file.error
|
|
3889
|
-
] }) : uploading ? /* @__PURE__ */
|
|
4136
|
+
] }) : uploading ? /* @__PURE__ */ jsxs48("span", { className: "fd-tabular", children: [
|
|
3890
4137
|
Math.round(file.progress),
|
|
3891
4138
|
"% uploaded"
|
|
3892
4139
|
] }) : meta })
|
|
@@ -3894,29 +4141,29 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
3894
4141
|
]
|
|
3895
4142
|
}
|
|
3896
4143
|
),
|
|
3897
|
-
uploading ? /* @__PURE__ */
|
|
3898
|
-
file.error && onRetry ? /* @__PURE__ */
|
|
3899
|
-
onRemove ? /* @__PURE__ */
|
|
4144
|
+
uploading ? /* @__PURE__ */ jsx53(Progress, { value: file.progress }) : null,
|
|
4145
|
+
file.error && onRetry ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
4146
|
+
onRemove ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
3900
4147
|
] });
|
|
3901
4148
|
}
|
|
3902
4149
|
function FileTile({ file, onOpen, onRemove, maxHeight = 200, className = "" }) {
|
|
3903
4150
|
if (!file) return null;
|
|
3904
4151
|
const src = file.thumb && file.thumb.url || file.blobUrl || file.url;
|
|
3905
4152
|
const uploading = file.progress != null && file.progress < 100 && !file.error;
|
|
3906
|
-
return /* @__PURE__ */
|
|
3907
|
-
/* @__PURE__ */
|
|
3908
|
-
uploading ? /* @__PURE__ */
|
|
3909
|
-
file.error ? /* @__PURE__ */
|
|
3910
|
-
/* @__PURE__ */
|
|
4153
|
+
return /* @__PURE__ */ jsxs48("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
|
|
4154
|
+
/* @__PURE__ */ jsx53("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ jsx53("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ jsx53("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ jsx53("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
|
|
4155
|
+
uploading ? /* @__PURE__ */ jsx53(Progress, { value: file.progress }) : null,
|
|
4156
|
+
file.error ? /* @__PURE__ */ jsxs48("figcaption", { className: "fd-tile-err", children: [
|
|
4157
|
+
/* @__PURE__ */ jsx53("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3911
4158
|
file.error
|
|
3912
4159
|
] }) : null,
|
|
3913
|
-
onRemove ? /* @__PURE__ */
|
|
4160
|
+
onRemove ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
3914
4161
|
] });
|
|
3915
4162
|
}
|
|
3916
4163
|
function FileStrip({ files = [], size = 68, onOpen, onRemove, onRetry, className = "" }) {
|
|
3917
4164
|
const list = files.filter(Boolean);
|
|
3918
4165
|
if (!list.length) return null;
|
|
3919
|
-
return /* @__PURE__ */
|
|
4166
|
+
return /* @__PURE__ */ jsx53("div", { className: ["fd-filestrip", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx53(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
|
|
3920
4167
|
}
|
|
3921
4168
|
var shortName = (name, keep = 5) => {
|
|
3922
4169
|
const s = String(name || "file");
|
|
@@ -3930,19 +4177,19 @@ function FileCell({ file, onOpen, onRemove, onRetry }) {
|
|
|
3930
4177
|
const image = isImage(file.mime, file.name);
|
|
3931
4178
|
const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
|
|
3932
4179
|
const label = file.name + (file.size ? " \xB7 " + formatBytes(file.size) : "");
|
|
3933
|
-
return /* @__PURE__ */
|
|
3934
|
-
/* @__PURE__ */
|
|
3935
|
-
thumb ? /* @__PURE__ */
|
|
3936
|
-
/* @__PURE__ */
|
|
3937
|
-
/* @__PURE__ */
|
|
3938
|
-
/* @__PURE__ */
|
|
4180
|
+
return /* @__PURE__ */ jsxs48("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
|
|
4181
|
+
/* @__PURE__ */ jsxs48("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
|
|
4182
|
+
thumb ? /* @__PURE__ */ jsx53("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsxs48("span", { className: "fd-cell-doc", children: [
|
|
4183
|
+
/* @__PURE__ */ jsx53("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
|
|
4184
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-cell-name", children: shortName(file.name) }),
|
|
4185
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
|
|
3939
4186
|
] }),
|
|
3940
|
-
(file.mime || "").startsWith("video/") ? /* @__PURE__ */
|
|
4187
|
+
(file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx53("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
|
|
3941
4188
|
] }),
|
|
3942
|
-
uploading ? /* @__PURE__ */
|
|
3943
|
-
file.error ? /* @__PURE__ */
|
|
3944
|
-
file.error && onRetry ? /* @__PURE__ */
|
|
3945
|
-
onRemove ? /* @__PURE__ */
|
|
4189
|
+
uploading ? /* @__PURE__ */ jsx53(Progress, { value: file.progress }) : null,
|
|
4190
|
+
file.error ? /* @__PURE__ */ jsx53("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ jsx53("i", { className: "ph ph-warning-circle" }) }) : null,
|
|
4191
|
+
file.error && onRetry ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
4192
|
+
onRemove ? /* @__PURE__ */ jsx53("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx53("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
3946
4193
|
] });
|
|
3947
4194
|
}
|
|
3948
4195
|
function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeight = 200, compact: compact3 = false, className = "" }) {
|
|
@@ -3950,15 +4197,15 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
3950
4197
|
if (!list.length) return null;
|
|
3951
4198
|
const pics = tiles ? list.filter((f) => isImage(f.mime, f.name)) : [];
|
|
3952
4199
|
const rest = list.filter((f) => pics.indexOf(f) === -1);
|
|
3953
|
-
return /* @__PURE__ */
|
|
3954
|
-
pics.length ? /* @__PURE__ */
|
|
3955
|
-
rest.length ? /* @__PURE__ */
|
|
4200
|
+
return /* @__PURE__ */ jsxs48("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
|
|
4201
|
+
pics.length ? /* @__PURE__ */ jsx53("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ jsx53(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
|
|
4202
|
+
rest.length ? /* @__PURE__ */ jsx53("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ jsx53(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
|
|
3956
4203
|
] });
|
|
3957
4204
|
}
|
|
3958
4205
|
|
|
3959
4206
|
// src/components/forms/MarkdownEditor.tsx
|
|
3960
|
-
import * as
|
|
3961
|
-
import { jsx as
|
|
4207
|
+
import * as React25 from "react";
|
|
4208
|
+
import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
3962
4209
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
3963
4210
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
3964
4211
|
function inlineParts(text) {
|
|
@@ -4171,7 +4418,7 @@ function syncDom(root, value) {
|
|
|
4171
4418
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
4172
4419
|
}
|
|
4173
4420
|
var LIST_CONT = RE_LI;
|
|
4174
|
-
var MarkdownEditor =
|
|
4421
|
+
var MarkdownEditor = React25.forwardRef(function MarkdownEditor2({
|
|
4175
4422
|
value = "",
|
|
4176
4423
|
onChange,
|
|
4177
4424
|
onSubmit,
|
|
@@ -4190,10 +4437,10 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4190
4437
|
className = "",
|
|
4191
4438
|
id
|
|
4192
4439
|
}, ref) {
|
|
4193
|
-
const boxRef =
|
|
4194
|
-
const composing =
|
|
4195
|
-
const pendingCaret =
|
|
4196
|
-
|
|
4440
|
+
const boxRef = React25.useRef(null);
|
|
4441
|
+
const composing = React25.useRef(false);
|
|
4442
|
+
const pendingCaret = React25.useRef(null);
|
|
4443
|
+
React25.useLayoutEffect(() => {
|
|
4197
4444
|
const root = boxRef.current;
|
|
4198
4445
|
if (!root || composing.current) return;
|
|
4199
4446
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -4202,7 +4449,7 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4202
4449
|
pendingCaret.current = null;
|
|
4203
4450
|
if (active && caret != null) placeCaret(root, caret);
|
|
4204
4451
|
}, [value]);
|
|
4205
|
-
|
|
4452
|
+
React25.useEffect(() => {
|
|
4206
4453
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
4207
4454
|
}, [autoFocus]);
|
|
4208
4455
|
const caretNow = () => {
|
|
@@ -4269,7 +4516,7 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4269
4516
|
api.replaceRange(from, to, next, from + next.length);
|
|
4270
4517
|
}
|
|
4271
4518
|
};
|
|
4272
|
-
|
|
4519
|
+
React25.useImperativeHandle(ref, () => api);
|
|
4273
4520
|
function detect(text, caret) {
|
|
4274
4521
|
if (!onTrigger) return;
|
|
4275
4522
|
const upto = text.slice(0, caret);
|
|
@@ -4382,8 +4629,8 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4382
4629
|
api.replaceRange(s.start, s.end, text.replace(/\r\n?/g, "\n"));
|
|
4383
4630
|
};
|
|
4384
4631
|
const lh = 1.55;
|
|
4385
|
-
return /* @__PURE__ */
|
|
4386
|
-
/* @__PURE__ */
|
|
4632
|
+
return /* @__PURE__ */ jsxs49("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
|
|
4633
|
+
/* @__PURE__ */ jsx54(
|
|
4387
4634
|
"div",
|
|
4388
4635
|
{
|
|
4389
4636
|
ref: boxRef,
|
|
@@ -4416,15 +4663,15 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4416
4663
|
}
|
|
4417
4664
|
}
|
|
4418
4665
|
),
|
|
4419
|
-
!value ? /* @__PURE__ */
|
|
4666
|
+
!value ? /* @__PURE__ */ jsx54("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
|
|
4420
4667
|
] });
|
|
4421
4668
|
});
|
|
4422
4669
|
|
|
4423
4670
|
// src/components/platform/AccountMenu.tsx
|
|
4424
|
-
import * as
|
|
4671
|
+
import * as React27 from "react";
|
|
4425
4672
|
|
|
4426
4673
|
// src/kits/session.ts
|
|
4427
|
-
import * as
|
|
4674
|
+
import * as React26 from "react";
|
|
4428
4675
|
var PERMISSION_CATALOG = [
|
|
4429
4676
|
{ group: "Plans", items: [
|
|
4430
4677
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -5991,8 +6238,8 @@ function roadmap(overrides) {
|
|
|
5991
6238
|
};
|
|
5992
6239
|
}
|
|
5993
6240
|
function useSession() {
|
|
5994
|
-
const [s, setS] =
|
|
5995
|
-
|
|
6241
|
+
const [s, setS] = React26.useState(getSession);
|
|
6242
|
+
React26.useEffect(() => subscribe(setS), []);
|
|
5996
6243
|
return s;
|
|
5997
6244
|
}
|
|
5998
6245
|
var SessionKit = {
|
|
@@ -6025,7 +6272,7 @@ var SessionKit = {
|
|
|
6025
6272
|
};
|
|
6026
6273
|
|
|
6027
6274
|
// src/components/platform/AccountMenu.tsx
|
|
6028
|
-
import { Fragment as Fragment11, jsx as
|
|
6275
|
+
import { Fragment as Fragment11, jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
6029
6276
|
var DEFAULT_LINKS = [
|
|
6030
6277
|
{ id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
|
|
6031
6278
|
{ id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
|
|
@@ -6036,7 +6283,7 @@ var DEFAULT_ADMIN_LINKS = [
|
|
|
6036
6283
|
{ id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
|
|
6037
6284
|
];
|
|
6038
6285
|
function Item({ item, onPick }) {
|
|
6039
|
-
return /* @__PURE__ */
|
|
6286
|
+
return /* @__PURE__ */ jsxs50(
|
|
6040
6287
|
"button",
|
|
6041
6288
|
{
|
|
6042
6289
|
type: "button",
|
|
@@ -6044,9 +6291,9 @@ function Item({ item, onPick }) {
|
|
|
6044
6291
|
className: "fd-acct-item",
|
|
6045
6292
|
onClick: () => onPick(item),
|
|
6046
6293
|
children: [
|
|
6047
|
-
/* @__PURE__ */
|
|
6048
|
-
/* @__PURE__ */
|
|
6049
|
-
item.badge ? /* @__PURE__ */
|
|
6294
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
|
|
6295
|
+
/* @__PURE__ */ jsx55("span", { style: { flex: 1 }, children: item.label }),
|
|
6296
|
+
item.badge ? /* @__PURE__ */ jsx55(Badge, { tone: "neutral", children: item.badge }) : null
|
|
6050
6297
|
]
|
|
6051
6298
|
}
|
|
6052
6299
|
);
|
|
@@ -6062,9 +6309,9 @@ function AccountMenu({
|
|
|
6062
6309
|
...rest
|
|
6063
6310
|
}) {
|
|
6064
6311
|
const session = SessionKit.useSession();
|
|
6065
|
-
const [open, setOpen] =
|
|
6066
|
-
const [switching, setSwitching] =
|
|
6067
|
-
const ref =
|
|
6312
|
+
const [open, setOpen] = React27.useState(false);
|
|
6313
|
+
const [switching, setSwitching] = React27.useState(false);
|
|
6314
|
+
const ref = React27.useRef(null);
|
|
6068
6315
|
const user = session.user;
|
|
6069
6316
|
const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
|
|
6070
6317
|
const pick = (item) => {
|
|
@@ -6078,8 +6325,8 @@ function AccountMenu({
|
|
|
6078
6325
|
if (onSignOut) return onSignOut();
|
|
6079
6326
|
window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
|
|
6080
6327
|
};
|
|
6081
|
-
return /* @__PURE__ */
|
|
6082
|
-
/* @__PURE__ */
|
|
6328
|
+
return /* @__PURE__ */ jsxs50(Fragment11, { children: [
|
|
6329
|
+
/* @__PURE__ */ jsxs50(
|
|
6083
6330
|
"button",
|
|
6084
6331
|
{
|
|
6085
6332
|
type: "button",
|
|
@@ -6091,32 +6338,32 @@ function AccountMenu({
|
|
|
6091
6338
|
onClick: () => setOpen((o) => !o),
|
|
6092
6339
|
...rest,
|
|
6093
6340
|
children: [
|
|
6094
|
-
/* @__PURE__ */
|
|
6095
|
-
/* @__PURE__ */
|
|
6341
|
+
/* @__PURE__ */ jsx55(Avatar, { name: user.name, size: "sm" }),
|
|
6342
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
|
|
6096
6343
|
]
|
|
6097
6344
|
}
|
|
6098
6345
|
),
|
|
6099
|
-
/* @__PURE__ */
|
|
6100
|
-
/* @__PURE__ */
|
|
6101
|
-
/* @__PURE__ */
|
|
6102
|
-
/* @__PURE__ */
|
|
6103
|
-
/* @__PURE__ */
|
|
6104
|
-
/* @__PURE__ */
|
|
6346
|
+
/* @__PURE__ */ jsx55(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ jsxs50("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
|
|
6347
|
+
/* @__PURE__ */ jsxs50("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
6348
|
+
/* @__PURE__ */ jsx55(Avatar, { name: user.name }),
|
|
6349
|
+
/* @__PURE__ */ jsxs50("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
|
|
6350
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
|
|
6351
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
|
|
6105
6352
|
] })
|
|
6106
6353
|
] }),
|
|
6107
|
-
showRoles && session.roles.length ? /* @__PURE__ */
|
|
6108
|
-
/* @__PURE__ */
|
|
6109
|
-
visibleAdmin.length ? /* @__PURE__ */
|
|
6110
|
-
/* @__PURE__ */
|
|
6111
|
-
visibleAdmin.map((l) => /* @__PURE__ */
|
|
6354
|
+
showRoles && session.roles.length ? /* @__PURE__ */ jsx55("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ jsx55(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
|
|
6355
|
+
/* @__PURE__ */ jsx55("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ jsx55(Item, { item: l, onPick: pick }, l.id)) }),
|
|
6356
|
+
visibleAdmin.length ? /* @__PURE__ */ jsxs50("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
|
|
6357
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
|
|
6358
|
+
visibleAdmin.map((l) => /* @__PURE__ */ jsx55(Item, { item: l, onPick: pick }, l.id))
|
|
6112
6359
|
] }) : null,
|
|
6113
|
-
allowUserSwitch ? /* @__PURE__ */
|
|
6114
|
-
/* @__PURE__ */
|
|
6115
|
-
/* @__PURE__ */
|
|
6116
|
-
/* @__PURE__ */
|
|
6117
|
-
/* @__PURE__ */
|
|
6360
|
+
allowUserSwitch ? /* @__PURE__ */ jsxs50("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
|
|
6361
|
+
/* @__PURE__ */ jsxs50("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
|
|
6362
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
|
|
6363
|
+
/* @__PURE__ */ jsx55("span", { style: { flex: 1 }, children: "View as another member" }),
|
|
6364
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
|
|
6118
6365
|
] }),
|
|
6119
|
-
switching ? /* @__PURE__ */
|
|
6366
|
+
switching ? /* @__PURE__ */ jsx55("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs50(
|
|
6120
6367
|
"button",
|
|
6121
6368
|
{
|
|
6122
6369
|
type: "button",
|
|
@@ -6128,34 +6375,34 @@ function AccountMenu({
|
|
|
6128
6375
|
setSwitching(false);
|
|
6129
6376
|
},
|
|
6130
6377
|
children: [
|
|
6131
|
-
/* @__PURE__ */
|
|
6132
|
-
/* @__PURE__ */
|
|
6133
|
-
/* @__PURE__ */
|
|
6134
|
-
/* @__PURE__ */
|
|
6378
|
+
/* @__PURE__ */ jsx55(Avatar, { name: u.name, size: "sm" }),
|
|
6379
|
+
/* @__PURE__ */ jsxs50("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
|
|
6380
|
+
/* @__PURE__ */ jsx55("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
|
|
6381
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
|
|
6135
6382
|
] }),
|
|
6136
|
-
u.id === user.id ? /* @__PURE__ */
|
|
6383
|
+
u.id === user.id ? /* @__PURE__ */ jsx55("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
|
|
6137
6384
|
]
|
|
6138
6385
|
},
|
|
6139
6386
|
u.id
|
|
6140
6387
|
)) }) : null
|
|
6141
6388
|
] }) : null,
|
|
6142
|
-
/* @__PURE__ */
|
|
6143
|
-
/* @__PURE__ */
|
|
6144
|
-
/* @__PURE__ */
|
|
6389
|
+
/* @__PURE__ */ jsx55("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ jsxs50("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
|
|
6390
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
|
|
6391
|
+
/* @__PURE__ */ jsx55("span", { style: { flex: 1 }, children: "Sign out" })
|
|
6145
6392
|
] }) })
|
|
6146
6393
|
] }) })
|
|
6147
6394
|
] });
|
|
6148
6395
|
}
|
|
6149
6396
|
|
|
6150
6397
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
6151
|
-
import * as
|
|
6152
|
-
import { jsx as
|
|
6398
|
+
import * as React28 from "react";
|
|
6399
|
+
import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
6153
6400
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
6154
6401
|
function Json({ obj }) {
|
|
6155
|
-
return /* @__PURE__ */
|
|
6402
|
+
return /* @__PURE__ */ jsx56("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
6156
6403
|
}
|
|
6157
6404
|
function Endpoint({ s, onRequest }) {
|
|
6158
|
-
const [tried, setTried] =
|
|
6405
|
+
const [tried, setTried] = React28.useState(null);
|
|
6159
6406
|
const run = async () => {
|
|
6160
6407
|
setTried("busy");
|
|
6161
6408
|
const t0 = (window.performance || Date).now();
|
|
@@ -6166,50 +6413,50 @@ function Endpoint({ s, onRequest }) {
|
|
|
6166
6413
|
setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
|
|
6167
6414
|
}
|
|
6168
6415
|
};
|
|
6169
|
-
return /* @__PURE__ */
|
|
6170
|
-
/* @__PURE__ */
|
|
6171
|
-
/* @__PURE__ */
|
|
6172
|
-
/* @__PURE__ */
|
|
6173
|
-
s.isList ? /* @__PURE__ */
|
|
6174
|
-
/* @__PURE__ */
|
|
6175
|
-
/* @__PURE__ */
|
|
6416
|
+
return /* @__PURE__ */ jsx56(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
6417
|
+
/* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
|
|
6418
|
+
/* @__PURE__ */ jsx56(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
|
|
6419
|
+
/* @__PURE__ */ jsx56("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
|
|
6420
|
+
s.isList ? /* @__PURE__ */ jsx56(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
|
|
6421
|
+
/* @__PURE__ */ jsx56("span", { style: { flex: 1 } }),
|
|
6422
|
+
/* @__PURE__ */ jsxs51("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
6176
6423
|
s.latency[0],
|
|
6177
6424
|
"\u2013",
|
|
6178
6425
|
s.latency[1],
|
|
6179
6426
|
"ms"
|
|
6180
6427
|
] }),
|
|
6181
|
-
/* @__PURE__ */
|
|
6428
|
+
/* @__PURE__ */ jsx56(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
|
|
6182
6429
|
] }),
|
|
6183
|
-
/* @__PURE__ */
|
|
6184
|
-
/* @__PURE__ */
|
|
6185
|
-
/* @__PURE__ */
|
|
6186
|
-
/* @__PURE__ */
|
|
6187
|
-
s.usedBy && s.usedBy.length ? /* @__PURE__ */
|
|
6430
|
+
/* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
|
|
6431
|
+
/* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6432
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
|
|
6433
|
+
/* @__PURE__ */ jsx56("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
|
|
6434
|
+
s.usedBy && s.usedBy.length ? /* @__PURE__ */ jsx56("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ jsx56(Tag, { children: u }, u)) }) : null
|
|
6188
6435
|
] }),
|
|
6189
|
-
/* @__PURE__ */
|
|
6190
|
-
s.request ? /* @__PURE__ */
|
|
6191
|
-
/* @__PURE__ */
|
|
6192
|
-
/* @__PURE__ */
|
|
6436
|
+
/* @__PURE__ */ jsxs51("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
|
|
6437
|
+
s.request ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6438
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Request body" }),
|
|
6439
|
+
/* @__PURE__ */ jsx56(Json, { obj: s.request })
|
|
6193
6440
|
] }) : null,
|
|
6194
|
-
s.query ? /* @__PURE__ */
|
|
6195
|
-
/* @__PURE__ */
|
|
6196
|
-
/* @__PURE__ */
|
|
6441
|
+
s.query ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6442
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Query" }),
|
|
6443
|
+
/* @__PURE__ */ jsx56(Json, { obj: s.query })
|
|
6197
6444
|
] }) : null,
|
|
6198
|
-
/* @__PURE__ */
|
|
6199
|
-
/* @__PURE__ */
|
|
6200
|
-
/* @__PURE__ */
|
|
6445
|
+
/* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6446
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Response 200" }),
|
|
6447
|
+
/* @__PURE__ */ jsx56(Json, { obj: s.response })
|
|
6201
6448
|
] })
|
|
6202
6449
|
] }),
|
|
6203
|
-
s.notes ? /* @__PURE__ */
|
|
6204
|
-
tried && tried !== "busy" ? /* @__PURE__ */
|
|
6205
|
-
/* @__PURE__ */
|
|
6206
|
-
/* @__PURE__ */
|
|
6207
|
-
/* @__PURE__ */
|
|
6450
|
+
s.notes ? /* @__PURE__ */ jsx56(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
|
|
6451
|
+
tried && tried !== "busy" ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6452
|
+
/* @__PURE__ */ jsxs51("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
6453
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
|
|
6454
|
+
/* @__PURE__ */ jsxs51(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
|
|
6208
6455
|
tried.ms,
|
|
6209
6456
|
"ms"
|
|
6210
6457
|
] })
|
|
6211
6458
|
] }),
|
|
6212
|
-
/* @__PURE__ */
|
|
6459
|
+
/* @__PURE__ */ jsx56(Json, { obj: tried.error ? { error: tried.error } : tried.data })
|
|
6213
6460
|
] }) : null
|
|
6214
6461
|
] })
|
|
6215
6462
|
] }) });
|
|
@@ -6228,58 +6475,58 @@ function ApiSpecBrowser({
|
|
|
6228
6475
|
className = "",
|
|
6229
6476
|
...rest
|
|
6230
6477
|
}) {
|
|
6231
|
-
const [q, setQ] =
|
|
6232
|
-
const [method, setMethod] =
|
|
6233
|
-
const [mod, setMod] =
|
|
6234
|
-
const [listOnly, setListOnly] =
|
|
6478
|
+
const [q, setQ] = React28.useState("");
|
|
6479
|
+
const [method, setMethod] = React28.useState(null);
|
|
6480
|
+
const [mod, setMod] = React28.useState(null);
|
|
6481
|
+
const [listOnly, setListOnly] = React28.useState(false);
|
|
6235
6482
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
6236
6483
|
const hits = spec.filter((s) => (!method || s.method === method) && (!listOnly || s.isList) && (!activeModule || activeModule.endpoints.indexOf(s.id) >= 0) && (!q || (s.path + " " + s.title + " " + s.purpose + " " + (s.usedBy || []).join(" ")).toLowerCase().includes(q.toLowerCase())));
|
|
6237
6484
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
6238
6485
|
const methods = [...new Set(spec.map((s) => s.method))];
|
|
6239
6486
|
const listCount = spec.filter((s) => s.isList).length;
|
|
6240
|
-
return /* @__PURE__ */
|
|
6241
|
-
/* @__PURE__ */
|
|
6242
|
-
kicker ? /* @__PURE__ */
|
|
6243
|
-
/* @__PURE__ */
|
|
6244
|
-
lede ? /* @__PURE__ */
|
|
6487
|
+
return /* @__PURE__ */ jsxs51("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
|
|
6488
|
+
/* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
6489
|
+
kicker ? /* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: kicker }) : null,
|
|
6490
|
+
/* @__PURE__ */ jsx56("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
6491
|
+
lede ? /* @__PURE__ */ jsx56("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
|
|
6245
6492
|
] }),
|
|
6246
|
-
modules && modules.length ? /* @__PURE__ */
|
|
6247
|
-
/* @__PURE__ */
|
|
6248
|
-
/* @__PURE__ */
|
|
6249
|
-
/* @__PURE__ */
|
|
6493
|
+
modules && modules.length ? /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
6494
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
|
|
6495
|
+
/* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
6496
|
+
/* @__PURE__ */ jsxs51(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
|
|
6250
6497
|
"All screens ",
|
|
6251
|
-
/* @__PURE__ */
|
|
6498
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: spec.length })
|
|
6252
6499
|
] }),
|
|
6253
|
-
modules.map((m) => /* @__PURE__ */
|
|
6500
|
+
modules.map((m) => /* @__PURE__ */ jsxs51(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
|
|
6254
6501
|
m.label,
|
|
6255
6502
|
" ",
|
|
6256
|
-
/* @__PURE__ */
|
|
6503
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: m.endpoints.length })
|
|
6257
6504
|
] }, m.id))
|
|
6258
6505
|
] }),
|
|
6259
|
-
activeModule ? /* @__PURE__ */
|
|
6506
|
+
activeModule ? /* @__PURE__ */ jsx56(
|
|
6260
6507
|
Flag,
|
|
6261
6508
|
{
|
|
6262
6509
|
tone: "info",
|
|
6263
6510
|
statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
|
|
6264
6511
|
cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
|
|
6265
|
-
actions: /* @__PURE__ */
|
|
6512
|
+
actions: /* @__PURE__ */ jsx56(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
|
|
6266
6513
|
}
|
|
6267
6514
|
) : null
|
|
6268
6515
|
] }) : null,
|
|
6269
|
-
sourceNote ? /* @__PURE__ */
|
|
6270
|
-
/* @__PURE__ */
|
|
6271
|
-
/* @__PURE__ */
|
|
6272
|
-
methods.map((m) => /* @__PURE__ */
|
|
6516
|
+
sourceNote ? /* @__PURE__ */ jsx56(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
|
|
6517
|
+
/* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
6518
|
+
/* @__PURE__ */ jsx56(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
|
|
6519
|
+
methods.map((m) => /* @__PURE__ */ jsxs51(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
|
|
6273
6520
|
m,
|
|
6274
6521
|
" ",
|
|
6275
|
-
/* @__PURE__ */
|
|
6522
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
|
|
6276
6523
|
] }, m)),
|
|
6277
|
-
listCount ? /* @__PURE__ */
|
|
6524
|
+
listCount ? /* @__PURE__ */ jsxs51(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
|
|
6278
6525
|
"Paged lists ",
|
|
6279
|
-
/* @__PURE__ */
|
|
6526
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: listCount })
|
|
6280
6527
|
] }) : null,
|
|
6281
|
-
/* @__PURE__ */
|
|
6282
|
-
/* @__PURE__ */
|
|
6528
|
+
/* @__PURE__ */ jsx56("span", { style: { flex: 1 } }),
|
|
6529
|
+
/* @__PURE__ */ jsxs51("span", { className: "fd-body-sm fd-muted", children: [
|
|
6283
6530
|
hits.length,
|
|
6284
6531
|
" of ",
|
|
6285
6532
|
spec.length,
|
|
@@ -6287,31 +6534,31 @@ function ApiSpecBrowser({
|
|
|
6287
6534
|
listCount ? " \xB7 " + listCount + " paged" : ""
|
|
6288
6535
|
] })
|
|
6289
6536
|
] }),
|
|
6290
|
-
hits.length === 0 ? /* @__PURE__ */
|
|
6537
|
+
hits.length === 0 ? /* @__PURE__ */ jsx56(Card, { elevation: "flat", children: /* @__PURE__ */ jsx56("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
|
|
6291
6538
|
const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
|
|
6292
6539
|
if (!items.length) return null;
|
|
6293
|
-
return /* @__PURE__ */
|
|
6294
|
-
/* @__PURE__ */
|
|
6295
|
-
items.map((s) => /* @__PURE__ */
|
|
6540
|
+
return /* @__PURE__ */ jsxs51("div", { className: "fd-stack", style: { gap: 12 }, children: [
|
|
6541
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-label-lg", children: g }),
|
|
6542
|
+
items.map((s) => /* @__PURE__ */ jsx56(Endpoint, { s, onRequest }, s.id))
|
|
6296
6543
|
] }, g);
|
|
6297
6544
|
}),
|
|
6298
|
-
conventions && conventions.length ? /* @__PURE__ */
|
|
6299
|
-
/* @__PURE__ */
|
|
6300
|
-
/* @__PURE__ */
|
|
6545
|
+
conventions && conventions.length ? /* @__PURE__ */ jsx56(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ jsx56("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
|
|
6546
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
|
|
6547
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
|
|
6301
6548
|
] }, k)) }) }) : null,
|
|
6302
|
-
openQuestions && openQuestions.length ? /* @__PURE__ */
|
|
6303
|
-
/* @__PURE__ */
|
|
6304
|
-
/* @__PURE__ */
|
|
6305
|
-
/* @__PURE__ */
|
|
6306
|
-
/* @__PURE__ */
|
|
6549
|
+
openQuestions && openQuestions.length ? /* @__PURE__ */ jsx56(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ jsx56("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ jsxs51("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
|
|
6550
|
+
/* @__PURE__ */ jsx56(Badge, { tone: "danger", children: id }),
|
|
6551
|
+
/* @__PURE__ */ jsxs51("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
|
|
6552
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
|
|
6553
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-body-sm fd-muted", children: why })
|
|
6307
6554
|
] })
|
|
6308
6555
|
] }, id)) }) }) : null
|
|
6309
6556
|
] });
|
|
6310
6557
|
}
|
|
6311
6558
|
|
|
6312
6559
|
// src/components/platform/ProfilePage.tsx
|
|
6313
|
-
import * as
|
|
6314
|
-
import { jsx as
|
|
6560
|
+
import * as React29 from "react";
|
|
6561
|
+
import { jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
6315
6562
|
var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
|
|
6316
6563
|
var NOTIFY = [
|
|
6317
6564
|
{ key: "planShared", label: "A plan is shared with me", detail: "Someone sends you a plan or a client link." },
|
|
@@ -6323,7 +6570,7 @@ var NOTIFY = [
|
|
|
6323
6570
|
function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
|
|
6324
6571
|
const session = SessionKit.useSession();
|
|
6325
6572
|
const user = userProp || session.user;
|
|
6326
|
-
const [draft, setDraft] =
|
|
6573
|
+
const [draft, setDraft] = React29.useState(() => ({
|
|
6327
6574
|
name: user.name || "",
|
|
6328
6575
|
title: user.title || "",
|
|
6329
6576
|
email: user.email || "",
|
|
@@ -6332,8 +6579,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6332
6579
|
bio: user.bio || "",
|
|
6333
6580
|
notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
|
|
6334
6581
|
}));
|
|
6335
|
-
const [saving, setSaving] =
|
|
6336
|
-
const [saved, setSaved] =
|
|
6582
|
+
const [saving, setSaving] = React29.useState(false);
|
|
6583
|
+
const [saved, setSaved] = React29.useState(false);
|
|
6337
6584
|
const set = (k, v) => {
|
|
6338
6585
|
setDraft((d) => Object.assign({}, d, { [k]: v }));
|
|
6339
6586
|
setSaved(false);
|
|
@@ -6355,43 +6602,43 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6355
6602
|
{ id: "s2", device: "iPhone 15 \xB7 Safari", where: "Denver, CO", when: "2 hours ago" },
|
|
6356
6603
|
{ id: "s3", device: "Windows \xB7 Edge", where: "Chicago, IL", when: "Aug 12" }
|
|
6357
6604
|
];
|
|
6358
|
-
return /* @__PURE__ */
|
|
6359
|
-
/* @__PURE__ */
|
|
6360
|
-
/* @__PURE__ */
|
|
6361
|
-
/* @__PURE__ */
|
|
6362
|
-
/* @__PURE__ */
|
|
6605
|
+
return /* @__PURE__ */ jsxs52("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
|
|
6606
|
+
/* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
6607
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", children: "Account" }),
|
|
6608
|
+
/* @__PURE__ */ jsx57("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
|
|
6609
|
+
/* @__PURE__ */ jsx57("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
|
|
6363
6610
|
] }),
|
|
6364
|
-
/* @__PURE__ */
|
|
6365
|
-
/* @__PURE__ */
|
|
6366
|
-
/* @__PURE__ */
|
|
6367
|
-
/* @__PURE__ */
|
|
6368
|
-
/* @__PURE__ */
|
|
6611
|
+
/* @__PURE__ */ jsx57(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
|
|
6612
|
+
/* @__PURE__ */ jsx57(Avatar, { name: draft.name || user.name, size: "lg" }),
|
|
6613
|
+
/* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
|
|
6614
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
|
|
6615
|
+
/* @__PURE__ */ jsxs52("span", { className: "fd-body-sm fd-muted", children: [
|
|
6369
6616
|
draft.title || "No title set",
|
|
6370
6617
|
" \xB7 ",
|
|
6371
6618
|
user.team || "No team"
|
|
6372
6619
|
] }),
|
|
6373
|
-
/* @__PURE__ */
|
|
6374
|
-
session.roles.map((r) => /* @__PURE__ */
|
|
6375
|
-
user.sso ? /* @__PURE__ */
|
|
6620
|
+
/* @__PURE__ */ jsxs52("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
|
|
6621
|
+
session.roles.map((r) => /* @__PURE__ */ jsx57(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
|
|
6622
|
+
user.sso ? /* @__PURE__ */ jsx57(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
|
|
6376
6623
|
] })
|
|
6377
6624
|
] }),
|
|
6378
|
-
/* @__PURE__ */
|
|
6625
|
+
/* @__PURE__ */ jsx57(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
|
|
6379
6626
|
] }) }),
|
|
6380
|
-
/* @__PURE__ */
|
|
6627
|
+
/* @__PURE__ */ jsx57(
|
|
6381
6628
|
Card,
|
|
6382
6629
|
{
|
|
6383
|
-
title: /* @__PURE__ */
|
|
6384
|
-
/* @__PURE__ */
|
|
6385
|
-
/* @__PURE__ */
|
|
6630
|
+
title: /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
6631
|
+
/* @__PURE__ */ jsx57("span", { children: "Identity" }),
|
|
6632
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
|
|
6386
6633
|
] }),
|
|
6387
6634
|
elevation: "flat",
|
|
6388
|
-
children: /* @__PURE__ */
|
|
6389
|
-
/* @__PURE__ */
|
|
6390
|
-
/* @__PURE__ */
|
|
6391
|
-
/* @__PURE__ */
|
|
6635
|
+
children: /* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 14 }, children: [
|
|
6636
|
+
/* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
|
|
6637
|
+
/* @__PURE__ */ jsx57(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
|
|
6638
|
+
/* @__PURE__ */ jsx57(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
|
|
6392
6639
|
] }),
|
|
6393
|
-
/* @__PURE__ */
|
|
6394
|
-
/* @__PURE__ */
|
|
6640
|
+
/* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
|
|
6641
|
+
/* @__PURE__ */ jsx57(
|
|
6395
6642
|
Input,
|
|
6396
6643
|
{
|
|
6397
6644
|
label: "Work email",
|
|
@@ -6401,9 +6648,9 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6401
6648
|
help: user.sso ? "Managed by your identity provider \u2014 change it there." : "Contact an administrator to change this."
|
|
6402
6649
|
}
|
|
6403
6650
|
),
|
|
6404
|
-
/* @__PURE__ */
|
|
6651
|
+
/* @__PURE__ */ jsx57(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
|
|
6405
6652
|
] }),
|
|
6406
|
-
/* @__PURE__ */
|
|
6653
|
+
/* @__PURE__ */ jsx57(
|
|
6407
6654
|
Textarea,
|
|
6408
6655
|
{
|
|
6409
6656
|
label: "Short bio",
|
|
@@ -6417,8 +6664,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6417
6664
|
] })
|
|
6418
6665
|
}
|
|
6419
6666
|
),
|
|
6420
|
-
/* @__PURE__ */
|
|
6421
|
-
/* @__PURE__ */
|
|
6667
|
+
/* @__PURE__ */ jsx57(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
|
|
6668
|
+
/* @__PURE__ */ jsx57(
|
|
6422
6669
|
Select,
|
|
6423
6670
|
{
|
|
6424
6671
|
label: "Time zone",
|
|
@@ -6428,28 +6675,28 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6428
6675
|
help: "Flight dates and schedules render in this zone."
|
|
6429
6676
|
}
|
|
6430
6677
|
),
|
|
6431
|
-
/* @__PURE__ */
|
|
6678
|
+
/* @__PURE__ */ jsx57(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
|
|
6432
6679
|
] }) }),
|
|
6433
|
-
/* @__PURE__ */
|
|
6680
|
+
/* @__PURE__ */ jsx57(
|
|
6434
6681
|
Card,
|
|
6435
6682
|
{
|
|
6436
|
-
title: /* @__PURE__ */
|
|
6437
|
-
/* @__PURE__ */
|
|
6438
|
-
/* @__PURE__ */
|
|
6683
|
+
title: /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
6684
|
+
/* @__PURE__ */ jsx57("span", { children: "Notifications" }),
|
|
6685
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
|
|
6439
6686
|
] }),
|
|
6440
6687
|
elevation: "flat",
|
|
6441
|
-
children: /* @__PURE__ */
|
|
6688
|
+
children: /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ jsx57(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
|
|
6442
6689
|
}
|
|
6443
6690
|
),
|
|
6444
|
-
/* @__PURE__ */
|
|
6691
|
+
/* @__PURE__ */ jsxs52(
|
|
6445
6692
|
Card,
|
|
6446
6693
|
{
|
|
6447
|
-
title: /* @__PURE__ */
|
|
6448
|
-
/* @__PURE__ */
|
|
6449
|
-
/* @__PURE__ */
|
|
6694
|
+
title: /* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
6695
|
+
/* @__PURE__ */ jsx57("span", { children: "Access" }),
|
|
6696
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
|
|
6450
6697
|
] }),
|
|
6451
6698
|
elevation: "flat",
|
|
6452
|
-
action: /* @__PURE__ */
|
|
6699
|
+
action: /* @__PURE__ */ jsx57(
|
|
6453
6700
|
Button,
|
|
6454
6701
|
{
|
|
6455
6702
|
size: "sm",
|
|
@@ -6460,39 +6707,39 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6460
6707
|
}
|
|
6461
6708
|
),
|
|
6462
6709
|
children: [
|
|
6463
|
-
/* @__PURE__ */
|
|
6464
|
-
/* @__PURE__ */
|
|
6465
|
-
/* @__PURE__ */
|
|
6710
|
+
/* @__PURE__ */ jsxs52("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
6711
|
+
/* @__PURE__ */ jsx57(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
|
|
6712
|
+
/* @__PURE__ */ jsxs52(CardRow, { label: "Permissions", children: [
|
|
6466
6713
|
session.permissions.length,
|
|
6467
6714
|
" granted"
|
|
6468
6715
|
] }),
|
|
6469
|
-
/* @__PURE__ */
|
|
6716
|
+
/* @__PURE__ */ jsx57(CardRow, { label: "Member since", children: user.joined || "\u2014" })
|
|
6470
6717
|
] }),
|
|
6471
|
-
/* @__PURE__ */
|
|
6718
|
+
/* @__PURE__ */ jsx57("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
|
|
6472
6719
|
]
|
|
6473
6720
|
}
|
|
6474
6721
|
),
|
|
6475
|
-
showSessions ? /* @__PURE__ */
|
|
6722
|
+
showSessions ? /* @__PURE__ */ jsx57(
|
|
6476
6723
|
Card,
|
|
6477
6724
|
{
|
|
6478
6725
|
title: "Signed-in devices",
|
|
6479
6726
|
elevation: "flat",
|
|
6480
|
-
action: /* @__PURE__ */
|
|
6481
|
-
children: /* @__PURE__ */
|
|
6482
|
-
/* @__PURE__ */
|
|
6483
|
-
/* @__PURE__ */
|
|
6484
|
-
/* @__PURE__ */
|
|
6485
|
-
/* @__PURE__ */
|
|
6727
|
+
action: /* @__PURE__ */ jsx57(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
|
|
6728
|
+
children: /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
6729
|
+
/* @__PURE__ */ jsx57("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
6730
|
+
/* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
|
|
6731
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
|
|
6732
|
+
/* @__PURE__ */ jsxs52("span", { className: "fd-body-sm fd-muted", children: [
|
|
6486
6733
|
s.where,
|
|
6487
6734
|
" \xB7 ",
|
|
6488
6735
|
s.when
|
|
6489
6736
|
] })
|
|
6490
6737
|
] }),
|
|
6491
|
-
s.current ? /* @__PURE__ */
|
|
6738
|
+
s.current ? /* @__PURE__ */ jsx57(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ jsx57(Button, { size: "sm", variant: "ghost", children: "Revoke" })
|
|
6492
6739
|
] }, s.id)) })
|
|
6493
6740
|
}
|
|
6494
6741
|
) : null,
|
|
6495
|
-
/* @__PURE__ */
|
|
6742
|
+
/* @__PURE__ */ jsxs52("div", { className: "fd-row", style: {
|
|
6496
6743
|
gap: 10,
|
|
6497
6744
|
flexWrap: "wrap",
|
|
6498
6745
|
position: "sticky",
|
|
@@ -6503,8 +6750,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6503
6750
|
border: "1px solid var(--border)",
|
|
6504
6751
|
boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
|
|
6505
6752
|
}, children: [
|
|
6506
|
-
/* @__PURE__ */
|
|
6507
|
-
/* @__PURE__ */
|
|
6753
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
|
|
6754
|
+
/* @__PURE__ */ jsx57(
|
|
6508
6755
|
Button,
|
|
6509
6756
|
{
|
|
6510
6757
|
size: "sm",
|
|
@@ -6517,16 +6764,16 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6517
6764
|
children: "Discard"
|
|
6518
6765
|
}
|
|
6519
6766
|
),
|
|
6520
|
-
/* @__PURE__ */
|
|
6767
|
+
/* @__PURE__ */ jsx57(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
|
|
6521
6768
|
] })
|
|
6522
6769
|
] });
|
|
6523
6770
|
}
|
|
6524
6771
|
|
|
6525
6772
|
// src/components/platform/RoadmapTimeline.tsx
|
|
6526
|
-
import * as
|
|
6773
|
+
import * as React31 from "react";
|
|
6527
6774
|
|
|
6528
6775
|
// src/kits/runtime.ts
|
|
6529
|
-
import * as
|
|
6776
|
+
import * as React30 from "react";
|
|
6530
6777
|
var WIRED_ENDPOINTS = [
|
|
6531
6778
|
// Nothing yet. Every id below would come from a real service:
|
|
6532
6779
|
// "plan.get", "placements.list", …
|
|
@@ -6697,8 +6944,8 @@ var RuntimeKit = {
|
|
|
6697
6944
|
};
|
|
6698
6945
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
6699
6946
|
function useRuntimeMode() {
|
|
6700
|
-
const [m, setM] =
|
|
6701
|
-
|
|
6947
|
+
const [m, setM] = React30.useState(RuntimeKit.getMode());
|
|
6948
|
+
React30.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
6702
6949
|
return m;
|
|
6703
6950
|
}
|
|
6704
6951
|
function useFeatureStatus(key) {
|
|
@@ -6717,7 +6964,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
6717
6964
|
var UseFeatureStatus = useFeatureStatus;
|
|
6718
6965
|
|
|
6719
6966
|
// src/components/platform/RoadmapTimeline.tsx
|
|
6720
|
-
import { jsx as
|
|
6967
|
+
import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
6721
6968
|
var STATUS = {
|
|
6722
6969
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
6723
6970
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -6732,45 +6979,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
6732
6979
|
const s = STATUS[item.status] || STATUS.planned;
|
|
6733
6980
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
6734
6981
|
const blocking = deps.filter((d) => !d.implemented);
|
|
6735
|
-
return /* @__PURE__ */
|
|
6736
|
-
/* @__PURE__ */
|
|
6737
|
-
/* @__PURE__ */
|
|
6738
|
-
/* @__PURE__ */
|
|
6739
|
-
/* @__PURE__ */
|
|
6982
|
+
return /* @__PURE__ */ jsx58(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
6983
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
6984
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
|
|
6985
|
+
/* @__PURE__ */ jsx58(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
|
|
6986
|
+
/* @__PURE__ */ jsx58(Badge, { tone: s.tone, icon: s.icon, children: s.label })
|
|
6740
6987
|
] }),
|
|
6741
|
-
/* @__PURE__ */
|
|
6742
|
-
item.backend ? /* @__PURE__ */
|
|
6743
|
-
/* @__PURE__ */
|
|
6744
|
-
/* @__PURE__ */
|
|
6988
|
+
/* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
|
|
6989
|
+
item.backend ? /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
|
|
6990
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
|
|
6991
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
|
|
6745
6992
|
] }) : null,
|
|
6746
|
-
/* @__PURE__ */
|
|
6747
|
-
item.effort ? /* @__PURE__ */
|
|
6748
|
-
/* @__PURE__ */
|
|
6993
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
6994
|
+
item.effort ? /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
|
|
6995
|
+
/* @__PURE__ */ jsx58("i", { className: "ph ph-hourglass-medium" }),
|
|
6749
6996
|
" ",
|
|
6750
6997
|
item.effort
|
|
6751
6998
|
] }) : null,
|
|
6752
|
-
/* @__PURE__ */
|
|
6753
|
-
/* @__PURE__ */
|
|
6999
|
+
/* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
|
|
7000
|
+
/* @__PURE__ */ jsx58("i", { className: "ph ph-user" }),
|
|
6754
7001
|
" ",
|
|
6755
7002
|
item.owner
|
|
6756
7003
|
] }),
|
|
6757
|
-
item.screen ? /* @__PURE__ */
|
|
6758
|
-
/* @__PURE__ */
|
|
6759
|
-
/* @__PURE__ */
|
|
7004
|
+
item.screen ? /* @__PURE__ */ jsx58(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
7005
|
+
/* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
|
|
7006
|
+
/* @__PURE__ */ jsx58(
|
|
6760
7007
|
"button",
|
|
6761
7008
|
{
|
|
6762
7009
|
type: "button",
|
|
6763
7010
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
6764
7011
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
6765
|
-
children: /* @__PURE__ */
|
|
7012
|
+
children: /* @__PURE__ */ jsx58("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
6766
7013
|
}
|
|
6767
7014
|
)
|
|
6768
7015
|
] }),
|
|
6769
|
-
deps.length ? /* @__PURE__ */
|
|
6770
|
-
/* @__PURE__ */
|
|
6771
|
-
deps.map((d) => /* @__PURE__ */
|
|
7016
|
+
deps.length ? /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
|
|
7017
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
|
|
7018
|
+
deps.map((d) => /* @__PURE__ */ jsx58(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
|
|
6772
7019
|
] }) : null,
|
|
6773
|
-
blocking.length && !item.implemented ? /* @__PURE__ */
|
|
7020
|
+
blocking.length && !item.implemented ? /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
6774
7021
|
"Blocked until ",
|
|
6775
7022
|
blocking.map((d) => d.label).join(" and "),
|
|
6776
7023
|
" ",
|
|
@@ -6781,12 +7028,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
6781
7028
|
}
|
|
6782
7029
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
6783
7030
|
const session = SessionKit.useSession();
|
|
6784
|
-
const [project, setProject] =
|
|
6785
|
-
const [q, setQ] =
|
|
6786
|
-
const scrollRef =
|
|
6787
|
-
const nowRef =
|
|
6788
|
-
const rm =
|
|
6789
|
-
const byKey =
|
|
7031
|
+
const [project, setProject] = React31.useState("");
|
|
7032
|
+
const [q, setQ] = React31.useState("");
|
|
7033
|
+
const scrollRef = React31.useRef(null);
|
|
7034
|
+
const nowRef = React31.useRef(null);
|
|
7035
|
+
const rm = React31.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
7036
|
+
const byKey = React31.useMemo(() => {
|
|
6790
7037
|
const m = {};
|
|
6791
7038
|
rm.items.forEach((i) => {
|
|
6792
7039
|
m[i.key] = i;
|
|
@@ -6795,7 +7042,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6795
7042
|
}, [rm]);
|
|
6796
7043
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
6797
7044
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
6798
|
-
|
|
7045
|
+
React31.useEffect(() => {
|
|
6799
7046
|
let raf1 = 0, raf2 = 0;
|
|
6800
7047
|
const place = () => {
|
|
6801
7048
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -6823,23 +7070,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6823
7070
|
}, 0);
|
|
6824
7071
|
const nextPhase = items.find((i) => !i.implemented);
|
|
6825
7072
|
let lastPhase = null;
|
|
6826
|
-
return /* @__PURE__ */
|
|
6827
|
-
/* @__PURE__ */
|
|
6828
|
-
/* @__PURE__ */
|
|
6829
|
-
/* @__PURE__ */
|
|
6830
|
-
/* @__PURE__ */
|
|
7073
|
+
return /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
|
|
7074
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
7075
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Architecture" }),
|
|
7076
|
+
/* @__PURE__ */ jsx58("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
7077
|
+
/* @__PURE__ */ jsx58("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." })
|
|
6831
7078
|
] }),
|
|
6832
|
-
/* @__PURE__ */
|
|
6833
|
-
/* @__PURE__ */
|
|
6834
|
-
/* @__PURE__ */
|
|
6835
|
-
/* @__PURE__ */
|
|
6836
|
-
/* @__PURE__ */
|
|
7079
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-grid-stats is-thin", children: [
|
|
7080
|
+
/* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
|
|
7081
|
+
/* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
|
|
7082
|
+
/* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
|
|
7083
|
+
/* @__PURE__ */ jsx58(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
|
|
6837
7084
|
] }),
|
|
6838
|
-
/* @__PURE__ */
|
|
6839
|
-
/* @__PURE__ */
|
|
6840
|
-
/* @__PURE__ */
|
|
6841
|
-
/* @__PURE__ */
|
|
6842
|
-
/* @__PURE__ */
|
|
7085
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
7086
|
+
/* @__PURE__ */ jsx58(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 } }),
|
|
7087
|
+
/* @__PURE__ */ jsx58(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
|
|
7088
|
+
/* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
|
|
7089
|
+
/* @__PURE__ */ jsx58(
|
|
6843
7090
|
Button,
|
|
6844
7091
|
{
|
|
6845
7092
|
size: "sm",
|
|
@@ -6853,7 +7100,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6853
7100
|
}
|
|
6854
7101
|
)
|
|
6855
7102
|
] }),
|
|
6856
|
-
/* @__PURE__ */
|
|
7103
|
+
/* @__PURE__ */ jsx58(
|
|
6857
7104
|
Flag,
|
|
6858
7105
|
{
|
|
6859
7106
|
tone: "info",
|
|
@@ -6862,60 +7109,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6862
7109
|
actions: null
|
|
6863
7110
|
}
|
|
6864
7111
|
),
|
|
6865
|
-
/* @__PURE__ */
|
|
6866
|
-
/* @__PURE__ */
|
|
7112
|
+
/* @__PURE__ */ jsx58("div", { className: "fd-rm", children: /* @__PURE__ */ jsx58("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs53("div", { className: "fd-rm-track", children: [
|
|
7113
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx58("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
|
|
6867
7114
|
items.map((item, n) => {
|
|
6868
7115
|
const showPhase = item.phase !== lastPhase;
|
|
6869
7116
|
lastPhase = item.phase;
|
|
6870
7117
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
6871
7118
|
const isBoundary = n === firstPending;
|
|
6872
|
-
return /* @__PURE__ */
|
|
6873
|
-
showPhase ? /* @__PURE__ */
|
|
6874
|
-
/* @__PURE__ */
|
|
6875
|
-
/* @__PURE__ */
|
|
6876
|
-
item.phase === 0 ? null : /* @__PURE__ */
|
|
7119
|
+
return /* @__PURE__ */ jsxs53(React31.Fragment, { children: [
|
|
7120
|
+
showPhase ? /* @__PURE__ */ jsxs53("div", { className: "fd-rm-era", children: [
|
|
7121
|
+
/* @__PURE__ */ jsxs53("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
7122
|
+
/* @__PURE__ */ jsx58("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
7123
|
+
item.phase === 0 ? null : /* @__PURE__ */ jsxs53("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
6877
7124
|
fmtDate(item.phaseStart),
|
|
6878
7125
|
" \u2013 ",
|
|
6879
7126
|
fmtDate(item.date)
|
|
6880
7127
|
] }),
|
|
6881
|
-
/* @__PURE__ */
|
|
7128
|
+
/* @__PURE__ */ jsxs53("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
6882
7129
|
"\xB7 ",
|
|
6883
7130
|
inPhase,
|
|
6884
7131
|
" feature",
|
|
6885
7132
|
inPhase === 1 ? "" : "s"
|
|
6886
7133
|
] })
|
|
6887
7134
|
] }),
|
|
6888
|
-
item.phaseWhy ? /* @__PURE__ */
|
|
7135
|
+
item.phaseWhy ? /* @__PURE__ */ jsx58("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
6889
7136
|
] }) : null,
|
|
6890
|
-
isBoundary ? /* @__PURE__ */
|
|
6891
|
-
/* @__PURE__ */
|
|
7137
|
+
isBoundary ? /* @__PURE__ */ jsx58("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs53("span", { className: "fd-rm-now-pill", children: [
|
|
7138
|
+
/* @__PURE__ */ jsx58("i", { className: "ph ph-map-pin" }),
|
|
6892
7139
|
" You are here \u2014 everything above is wired"
|
|
6893
7140
|
] }) }) : null,
|
|
6894
|
-
/* @__PURE__ */
|
|
6895
|
-
/* @__PURE__ */
|
|
6896
|
-
/* @__PURE__ */
|
|
7141
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-rm-row", children: [
|
|
7142
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
|
|
7143
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-rm-date", children: [
|
|
6897
7144
|
fmtDate(item.date),
|
|
6898
|
-
/* @__PURE__ */
|
|
6899
|
-
/* @__PURE__ */
|
|
7145
|
+
/* @__PURE__ */ jsx58("br", {}),
|
|
7146
|
+
/* @__PURE__ */ jsx58("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
6900
7147
|
] }),
|
|
6901
|
-
/* @__PURE__ */
|
|
7148
|
+
/* @__PURE__ */ jsx58(RoadmapCard, { item, byKey, onOpenFlag })
|
|
6902
7149
|
] })
|
|
6903
7150
|
] }, item.key);
|
|
6904
7151
|
}),
|
|
6905
|
-
!items.length ? /* @__PURE__ */
|
|
7152
|
+
!items.length ? /* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
6906
7153
|
] }) }) }),
|
|
6907
|
-
/* @__PURE__ */
|
|
7154
|
+
/* @__PURE__ */ jsxs53("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
6908
7155
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
6909
|
-
/* @__PURE__ */
|
|
7156
|
+
/* @__PURE__ */ jsx58("code", { className: "fd-mono", children: "implemented" }),
|
|
6910
7157
|
" field, so this page cannot drift from what the apps actually do."
|
|
6911
7158
|
] })
|
|
6912
7159
|
] });
|
|
6913
7160
|
}
|
|
6914
7161
|
|
|
6915
7162
|
// src/components/platform/ComingSoon.tsx
|
|
6916
|
-
import * as
|
|
7163
|
+
import * as React32 from "react";
|
|
6917
7164
|
import { createPortal as createPortal7 } from "react-dom";
|
|
6918
|
-
import { Fragment as Fragment13, jsx as
|
|
7165
|
+
import { Fragment as Fragment13, jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
6919
7166
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
6920
7167
|
function readBypassed() {
|
|
6921
7168
|
try {
|
|
@@ -6931,8 +7178,8 @@ function writeBypassed(list) {
|
|
|
6931
7178
|
}
|
|
6932
7179
|
}
|
|
6933
7180
|
function useBypass(key) {
|
|
6934
|
-
const [on, setOn] =
|
|
6935
|
-
|
|
7181
|
+
const [on, setOn] = React32.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
7182
|
+
React32.useEffect(() => {
|
|
6936
7183
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
6937
7184
|
}, [key]);
|
|
6938
7185
|
const set = (next) => {
|
|
@@ -6945,43 +7192,43 @@ function useBypass(key) {
|
|
|
6945
7192
|
return [on, set];
|
|
6946
7193
|
}
|
|
6947
7194
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
6948
|
-
return /* @__PURE__ */
|
|
6949
|
-
/* @__PURE__ */
|
|
6950
|
-
/* @__PURE__ */
|
|
7195
|
+
return /* @__PURE__ */ jsxs54(Fragment13, { children: [
|
|
7196
|
+
/* @__PURE__ */ jsxs54("span", { className: "fd-soon-badge", children: [
|
|
7197
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
6951
7198
|
label
|
|
6952
7199
|
] }),
|
|
6953
|
-
detail ? /* @__PURE__ */
|
|
6954
|
-
backend ? /* @__PURE__ */
|
|
6955
|
-
/* @__PURE__ */
|
|
7200
|
+
detail ? /* @__PURE__ */ jsx59("span", { className: "fd-soon-detail", children: detail }) : null,
|
|
7201
|
+
backend ? /* @__PURE__ */ jsxs54("span", { className: "fd-soon-backend", children: [
|
|
7202
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-overline", children: "Needs" }),
|
|
6956
7203
|
" ",
|
|
6957
7204
|
backend
|
|
6958
7205
|
] }) : null,
|
|
6959
|
-
eta || effort || onRoadmap ? /* @__PURE__ */
|
|
6960
|
-
eta ? /* @__PURE__ */
|
|
6961
|
-
/* @__PURE__ */
|
|
7206
|
+
eta || effort || onRoadmap ? /* @__PURE__ */ jsxs54("span", { className: "fd-soon-meta", children: [
|
|
7207
|
+
eta ? /* @__PURE__ */ jsxs54("span", { children: [
|
|
7208
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
|
|
6962
7209
|
" ",
|
|
6963
7210
|
eta
|
|
6964
7211
|
] }) : null,
|
|
6965
|
-
effort ? /* @__PURE__ */
|
|
6966
|
-
/* @__PURE__ */
|
|
7212
|
+
effort ? /* @__PURE__ */ jsxs54("span", { children: [
|
|
7213
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
6967
7214
|
" ",
|
|
6968
7215
|
effort
|
|
6969
7216
|
] }) : null,
|
|
6970
|
-
onRoadmap ? /* @__PURE__ */
|
|
7217
|
+
onRoadmap ? /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
6971
7218
|
"See the roadmap ",
|
|
6972
|
-
/* @__PURE__ */
|
|
7219
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
6973
7220
|
] }) : null
|
|
6974
7221
|
] }) : null,
|
|
6975
|
-
allowed ? /* @__PURE__ */
|
|
6976
|
-
/* @__PURE__ */
|
|
7222
|
+
allowed ? /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
|
|
7223
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-eye", "aria-hidden": "true" }),
|
|
6977
7224
|
" View and use it anyway"
|
|
6978
7225
|
] }) : null
|
|
6979
7226
|
] });
|
|
6980
7227
|
}
|
|
6981
7228
|
function useHoverCard(open) {
|
|
6982
|
-
const anchor =
|
|
6983
|
-
const [pos, setPos] =
|
|
6984
|
-
|
|
7229
|
+
const anchor = React32.useRef(null);
|
|
7230
|
+
const [pos, setPos] = React32.useState(null);
|
|
7231
|
+
React32.useLayoutEffect(() => {
|
|
6985
7232
|
if (!open || !anchor.current) {
|
|
6986
7233
|
setPos(null);
|
|
6987
7234
|
return;
|
|
@@ -7033,9 +7280,9 @@ function ComingSoon({
|
|
|
7033
7280
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
7034
7281
|
if (inline) {
|
|
7035
7282
|
if (allowed && bypassed) {
|
|
7036
|
-
return /* @__PURE__ */
|
|
7283
|
+
return /* @__PURE__ */ jsxs54("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
7037
7284
|
children,
|
|
7038
|
-
/* @__PURE__ */
|
|
7285
|
+
/* @__PURE__ */ jsx59(
|
|
7039
7286
|
"button",
|
|
7040
7287
|
{
|
|
7041
7288
|
type: "button",
|
|
@@ -7043,12 +7290,12 @@ function ComingSoon({
|
|
|
7043
7290
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
7044
7291
|
onClick: () => setBypassed(false),
|
|
7045
7292
|
"aria-label": "Re-blur this unwired feature",
|
|
7046
|
-
children: /* @__PURE__ */
|
|
7293
|
+
children: /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7047
7294
|
}
|
|
7048
7295
|
)
|
|
7049
7296
|
] });
|
|
7050
7297
|
}
|
|
7051
|
-
return /* @__PURE__ */
|
|
7298
|
+
return /* @__PURE__ */ jsx59(
|
|
7052
7299
|
InlineSoon,
|
|
7053
7300
|
{
|
|
7054
7301
|
label,
|
|
@@ -7068,20 +7315,20 @@ function ComingSoon({
|
|
|
7068
7315
|
);
|
|
7069
7316
|
}
|
|
7070
7317
|
if (allowed && bypassed) {
|
|
7071
|
-
return /* @__PURE__ */
|
|
7072
|
-
/* @__PURE__ */
|
|
7073
|
-
/* @__PURE__ */
|
|
7074
|
-
/* @__PURE__ */
|
|
7318
|
+
return /* @__PURE__ */ jsxs54("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
|
|
7319
|
+
/* @__PURE__ */ jsxs54("div", { className: "fd-soon-bar", role: "status", children: [
|
|
7320
|
+
/* @__PURE__ */ jsxs54("span", { className: "fd-soon-badge", children: [
|
|
7321
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
7075
7322
|
"Unwired feature \u2014 you are using it anyway"
|
|
7076
7323
|
] }),
|
|
7077
|
-
/* @__PURE__ */
|
|
7078
|
-
/* @__PURE__ */
|
|
7079
|
-
onRoadmap ? /* @__PURE__ */
|
|
7324
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
|
|
7325
|
+
/* @__PURE__ */ jsxs54("span", { className: "fd-soon-bar-actions", children: [
|
|
7326
|
+
onRoadmap ? /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
7080
7327
|
"Roadmap ",
|
|
7081
|
-
/* @__PURE__ */
|
|
7328
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
7082
7329
|
] }) : null,
|
|
7083
|
-
/* @__PURE__ */
|
|
7084
|
-
/* @__PURE__ */
|
|
7330
|
+
/* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
|
|
7331
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
|
|
7085
7332
|
" Re-blur"
|
|
7086
7333
|
] })
|
|
7087
7334
|
] })
|
|
@@ -7089,10 +7336,10 @@ function ComingSoon({
|
|
|
7089
7336
|
children
|
|
7090
7337
|
] });
|
|
7091
7338
|
}
|
|
7092
|
-
return /* @__PURE__ */
|
|
7093
|
-
/* @__PURE__ */
|
|
7094
|
-
/* @__PURE__ */
|
|
7095
|
-
/* @__PURE__ */
|
|
7339
|
+
return /* @__PURE__ */ jsxs54("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
|
|
7340
|
+
/* @__PURE__ */ jsx59("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
7341
|
+
/* @__PURE__ */ jsx59("div", { className: "fd-soon-veil" }),
|
|
7342
|
+
/* @__PURE__ */ jsx59("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx59(
|
|
7096
7343
|
SoonCard,
|
|
7097
7344
|
{
|
|
7098
7345
|
label,
|
|
@@ -7108,9 +7355,9 @@ function ComingSoon({
|
|
|
7108
7355
|
] });
|
|
7109
7356
|
}
|
|
7110
7357
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
7111
|
-
const [open, setOpen] =
|
|
7358
|
+
const [open, setOpen] = React32.useState(false);
|
|
7112
7359
|
const [anchor, pos] = useHoverCard(open);
|
|
7113
|
-
const close =
|
|
7360
|
+
const close = React32.useRef(null);
|
|
7114
7361
|
const show = () => {
|
|
7115
7362
|
if (close.current) {
|
|
7116
7363
|
clearTimeout(close.current);
|
|
@@ -7126,10 +7373,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7126
7373
|
setOpen(false);
|
|
7127
7374
|
}, 140);
|
|
7128
7375
|
};
|
|
7129
|
-
|
|
7376
|
+
React32.useEffect(() => () => {
|
|
7130
7377
|
if (close.current) clearTimeout(close.current);
|
|
7131
7378
|
}, []);
|
|
7132
|
-
return /* @__PURE__ */
|
|
7379
|
+
return /* @__PURE__ */ jsxs54(
|
|
7133
7380
|
"span",
|
|
7134
7381
|
{
|
|
7135
7382
|
ref: anchor,
|
|
@@ -7140,8 +7387,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7140
7387
|
onBlur: hide,
|
|
7141
7388
|
...rest,
|
|
7142
7389
|
children: [
|
|
7143
|
-
/* @__PURE__ */
|
|
7144
|
-
/* @__PURE__ */
|
|
7390
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
7391
|
+
/* @__PURE__ */ jsx59(
|
|
7145
7392
|
"button",
|
|
7146
7393
|
{
|
|
7147
7394
|
type: "button",
|
|
@@ -7152,11 +7399,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7152
7399
|
onFocus: show,
|
|
7153
7400
|
onBlur: hide,
|
|
7154
7401
|
onClick: () => open ? setOpen(false) : show(),
|
|
7155
|
-
children: /* @__PURE__ */
|
|
7402
|
+
children: /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7156
7403
|
}
|
|
7157
7404
|
),
|
|
7158
7405
|
open && pos ? createPortal7(
|
|
7159
|
-
/* @__PURE__ */
|
|
7406
|
+
/* @__PURE__ */ jsx59(
|
|
7160
7407
|
"div",
|
|
7161
7408
|
{
|
|
7162
7409
|
className: "fd-soon-note fd-soon-hovercard",
|
|
@@ -7164,7 +7411,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7164
7411
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width },
|
|
7165
7412
|
onMouseEnter: show,
|
|
7166
7413
|
onMouseLeave: hide,
|
|
7167
|
-
children: /* @__PURE__ */
|
|
7414
|
+
children: /* @__PURE__ */ jsx59(
|
|
7168
7415
|
SoonCard,
|
|
7169
7416
|
{
|
|
7170
7417
|
label,
|
|
@@ -7194,10 +7441,10 @@ function formatEta(iso2) {
|
|
|
7194
7441
|
var FormatEta = formatEta;
|
|
7195
7442
|
|
|
7196
7443
|
// src/components/platform/Gate.tsx
|
|
7197
|
-
import { jsx as
|
|
7444
|
+
import { jsx as jsx60, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
7198
7445
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
7199
7446
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
7200
|
-
return /* @__PURE__ */
|
|
7447
|
+
return /* @__PURE__ */ jsxs55(
|
|
7201
7448
|
"div",
|
|
7202
7449
|
{
|
|
7203
7450
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -7213,14 +7460,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
7213
7460
|
},
|
|
7214
7461
|
...rest,
|
|
7215
7462
|
children: [
|
|
7216
|
-
/* @__PURE__ */
|
|
7217
|
-
/* @__PURE__ */
|
|
7218
|
-
/* @__PURE__ */
|
|
7463
|
+
/* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
7464
|
+
/* @__PURE__ */ jsx60("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
7465
|
+
/* @__PURE__ */ jsx60("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
|
|
7219
7466
|
] }),
|
|
7220
|
-
/* @__PURE__ */
|
|
7221
|
-
need.length ? /* @__PURE__ */
|
|
7222
|
-
/* @__PURE__ */
|
|
7223
|
-
need.map((p) => /* @__PURE__ */
|
|
7467
|
+
/* @__PURE__ */ jsx60("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." }),
|
|
7468
|
+
need.length ? /* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
|
|
7469
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", children: "Requires" }),
|
|
7470
|
+
need.map((p) => /* @__PURE__ */ jsx60("code", { className: "fd-mono", style: {
|
|
7224
7471
|
fontSize: 11.5,
|
|
7225
7472
|
padding: "2px 7px",
|
|
7226
7473
|
borderRadius: 5,
|
|
@@ -7241,7 +7488,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
|
|
|
7241
7488
|
if (ok) return children;
|
|
7242
7489
|
if (fallback !== void 0) return fallback;
|
|
7243
7490
|
if (silent) return null;
|
|
7244
|
-
return /* @__PURE__ */
|
|
7491
|
+
return /* @__PURE__ */ jsx60(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
7245
7492
|
}
|
|
7246
7493
|
function FeatureGate({
|
|
7247
7494
|
flag,
|
|
@@ -7262,7 +7509,7 @@ function FeatureGate({
|
|
|
7262
7509
|
if (!preview) return fallback;
|
|
7263
7510
|
const f = SessionKit.findFlag(flag) || {};
|
|
7264
7511
|
const missing = rt.missing || [];
|
|
7265
|
-
return /* @__PURE__ */
|
|
7512
|
+
return /* @__PURE__ */ jsx60(
|
|
7266
7513
|
ComingSoon,
|
|
7267
7514
|
{
|
|
7268
7515
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -7283,25 +7530,25 @@ function FeatureGate({
|
|
|
7283
7530
|
function PermissionHint({ perm, children }) {
|
|
7284
7531
|
SessionKit.useSession();
|
|
7285
7532
|
if (SessionKit.can(perm)) return children;
|
|
7286
|
-
return /* @__PURE__ */
|
|
7533
|
+
return /* @__PURE__ */ jsx60(
|
|
7287
7534
|
"span",
|
|
7288
7535
|
{
|
|
7289
7536
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
7290
7537
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
7291
7538
|
"aria-disabled": "true",
|
|
7292
|
-
children: /* @__PURE__ */
|
|
7539
|
+
children: /* @__PURE__ */ jsx60("span", { style: { pointerEvents: "none" }, children })
|
|
7293
7540
|
}
|
|
7294
7541
|
);
|
|
7295
7542
|
}
|
|
7296
7543
|
|
|
7297
7544
|
// src/components/platform/ModeSwitch.tsx
|
|
7298
|
-
import * as
|
|
7299
|
-
import { Fragment as Fragment14, jsx as
|
|
7545
|
+
import * as React33 from "react";
|
|
7546
|
+
import { Fragment as Fragment14, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
7300
7547
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
7301
7548
|
const mode2 = useRuntimeMode();
|
|
7302
|
-
const [open, setOpen] =
|
|
7303
|
-
const ref =
|
|
7304
|
-
|
|
7549
|
+
const [open, setOpen] = React33.useState(false);
|
|
7550
|
+
const ref = React33.useRef(null);
|
|
7551
|
+
React33.useEffect(() => {
|
|
7305
7552
|
if (!open) return;
|
|
7306
7553
|
const away = (e) => {
|
|
7307
7554
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -7323,8 +7570,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7323
7570
|
RuntimeKit.setMode(next);
|
|
7324
7571
|
setOpen(false);
|
|
7325
7572
|
};
|
|
7326
|
-
return /* @__PURE__ */
|
|
7327
|
-
/* @__PURE__ */
|
|
7573
|
+
return /* @__PURE__ */ jsxs56("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
|
|
7574
|
+
/* @__PURE__ */ jsxs56(
|
|
7328
7575
|
"button",
|
|
7329
7576
|
{
|
|
7330
7577
|
type: "button",
|
|
@@ -7334,29 +7581,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7334
7581
|
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.",
|
|
7335
7582
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
|
|
7336
7583
|
children: [
|
|
7337
|
-
/* @__PURE__ */
|
|
7338
|
-
test && requestCount ? /* @__PURE__ */
|
|
7584
|
+
/* @__PURE__ */ jsx61("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
|
|
7585
|
+
test && requestCount ? /* @__PURE__ */ jsx61("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
|
|
7339
7586
|
]
|
|
7340
7587
|
}
|
|
7341
7588
|
),
|
|
7342
|
-
open ? /* @__PURE__ */
|
|
7343
|
-
/* @__PURE__ */
|
|
7344
|
-
/* @__PURE__ */
|
|
7345
|
-
/* @__PURE__ */
|
|
7589
|
+
open ? /* @__PURE__ */ jsxs56("span", { className: "fd-view-enter fd-mode-pop", children: [
|
|
7590
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
7591
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
|
|
7592
|
+
/* @__PURE__ */ jsx61("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
|
|
7346
7593
|
test ? "Test mode" : "Live mode"
|
|
7347
7594
|
] }),
|
|
7348
|
-
test ? /* @__PURE__ */
|
|
7595
|
+
test ? /* @__PURE__ */ jsxs56("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
7349
7596
|
requestCount,
|
|
7350
7597
|
" simulated request",
|
|
7351
7598
|
requestCount === 1 ? "" : "s"
|
|
7352
7599
|
] }) : null,
|
|
7353
|
-
/* @__PURE__ */
|
|
7354
|
-
test && onClearLog ? /* @__PURE__ */
|
|
7600
|
+
/* @__PURE__ */ jsx61("span", { style: { flex: 1 } }),
|
|
7601
|
+
test && onClearLog ? /* @__PURE__ */ jsx61("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
|
|
7355
7602
|
] }),
|
|
7356
|
-
/* @__PURE__ */
|
|
7357
|
-
/* @__PURE__ */
|
|
7358
|
-
/* @__PURE__ */
|
|
7359
|
-
/* @__PURE__ */
|
|
7603
|
+
/* @__PURE__ */ jsxs56("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
7604
|
+
/* @__PURE__ */ jsx61("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." }),
|
|
7605
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
|
|
7606
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
7360
7607
|
s.endpointsWired,
|
|
7361
7608
|
" endpoint",
|
|
7362
7609
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -7366,58 +7613,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7366
7613
|
s.total,
|
|
7367
7614
|
" features complete"
|
|
7368
7615
|
] }),
|
|
7369
|
-
onOpenSpec ? /* @__PURE__ */
|
|
7370
|
-
/* @__PURE__ */
|
|
7371
|
-
/* @__PURE__ */
|
|
7616
|
+
onOpenSpec ? /* @__PURE__ */ jsxs56(Fragment14, { children: [
|
|
7617
|
+
/* @__PURE__ */ jsx61("span", { style: { flex: 1 } }),
|
|
7618
|
+
/* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
7372
7619
|
setOpen(false);
|
|
7373
7620
|
onOpenSpec();
|
|
7374
7621
|
}, children: [
|
|
7375
7622
|
"API spec ",
|
|
7376
|
-
/* @__PURE__ */
|
|
7623
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
7377
7624
|
] })
|
|
7378
7625
|
] }) : null
|
|
7379
7626
|
] })
|
|
7380
7627
|
] }),
|
|
7381
|
-
/* @__PURE__ */
|
|
7382
|
-
/* @__PURE__ */
|
|
7383
|
-
/* @__PURE__ */
|
|
7384
|
-
/* @__PURE__ */
|
|
7385
|
-
/* @__PURE__ */
|
|
7386
|
-
/* @__PURE__ */
|
|
7628
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-mode-choice", children: [
|
|
7629
|
+
/* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
|
|
7630
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
7631
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-mode-opt-text", children: [
|
|
7632
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-title", children: "Live mode" }),
|
|
7633
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
|
|
7387
7634
|
] }),
|
|
7388
|
-
!test ? /* @__PURE__ */
|
|
7635
|
+
!test ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
7389
7636
|
] }),
|
|
7390
|
-
/* @__PURE__ */
|
|
7391
|
-
/* @__PURE__ */
|
|
7392
|
-
/* @__PURE__ */
|
|
7393
|
-
/* @__PURE__ */
|
|
7394
|
-
/* @__PURE__ */
|
|
7637
|
+
/* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
|
|
7638
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
7639
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-mode-opt-text", children: [
|
|
7640
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-title", children: "Test mode" }),
|
|
7641
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
|
|
7395
7642
|
] }),
|
|
7396
|
-
test ? /* @__PURE__ */
|
|
7643
|
+
test ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
7397
7644
|
] })
|
|
7398
7645
|
] }),
|
|
7399
|
-
test && renderLog ? /* @__PURE__ */
|
|
7646
|
+
test && renderLog ? /* @__PURE__ */ jsx61("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
7400
7647
|
] }) : null
|
|
7401
7648
|
] });
|
|
7402
7649
|
}
|
|
7403
7650
|
function TestModeBar({ onExit }) {
|
|
7404
7651
|
const mode2 = useRuntimeMode();
|
|
7405
7652
|
if (mode2 !== "test") return null;
|
|
7406
|
-
return /* @__PURE__ */
|
|
7407
|
-
/* @__PURE__ */
|
|
7408
|
-
/* @__PURE__ */
|
|
7653
|
+
return /* @__PURE__ */ jsxs56("div", { className: "fd-testbar", role: "status", children: [
|
|
7654
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-badge fd-badge-warning", children: [
|
|
7655
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
7409
7656
|
"Test mode"
|
|
7410
7657
|
] }),
|
|
7411
|
-
/* @__PURE__ */
|
|
7412
|
-
/* @__PURE__ */
|
|
7413
|
-
/* @__PURE__ */
|
|
7658
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
|
|
7659
|
+
/* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
|
|
7660
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
7414
7661
|
" Back to live mode"
|
|
7415
7662
|
] })
|
|
7416
7663
|
] });
|
|
7417
7664
|
}
|
|
7418
7665
|
|
|
7419
7666
|
// src/components/planner/ChannelMeta.tsx
|
|
7420
|
-
import { jsx as
|
|
7667
|
+
import { jsx as jsx62, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
7421
7668
|
var CHANNEL_WEIGHTS = {
|
|
7422
7669
|
"OOH": 50,
|
|
7423
7670
|
"DOOH": 50,
|
|
@@ -7470,9 +7717,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
7470
7717
|
const m = ChannelMeta(channel);
|
|
7471
7718
|
const wt = channelWeightOf(channel || "");
|
|
7472
7719
|
if (dot) {
|
|
7473
|
-
return /* @__PURE__ */
|
|
7720
|
+
return /* @__PURE__ */ jsx62("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
7474
7721
|
}
|
|
7475
|
-
return /* @__PURE__ */
|
|
7722
|
+
return /* @__PURE__ */ jsxs57(
|
|
7476
7723
|
"span",
|
|
7477
7724
|
{
|
|
7478
7725
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -7480,16 +7727,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
7480
7727
|
style: { "--chan": m.color },
|
|
7481
7728
|
...rest,
|
|
7482
7729
|
children: [
|
|
7483
|
-
/* @__PURE__ */
|
|
7484
|
-
showLabel ? /* @__PURE__ */
|
|
7485
|
-
weight ? /* @__PURE__ */
|
|
7730
|
+
/* @__PURE__ */ jsx62("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
|
|
7731
|
+
showLabel ? /* @__PURE__ */ jsx62("span", { className: "fd-chan-label", children: m.label }) : null,
|
|
7732
|
+
weight ? /* @__PURE__ */ jsx62("span", { className: "fd-chan-weight", children: wt || 0 }) : null
|
|
7486
7733
|
]
|
|
7487
7734
|
}
|
|
7488
7735
|
);
|
|
7489
7736
|
}
|
|
7490
7737
|
|
|
7491
7738
|
// src/components/planner/SaturationDistribution.tsx
|
|
7492
|
-
import { jsx as
|
|
7739
|
+
import { jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
7493
7740
|
var BANDS2 = [
|
|
7494
7741
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
7495
7742
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -7500,18 +7747,18 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7500
7747
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
7501
7748
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
7502
7749
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
7503
|
-
return /* @__PURE__ */
|
|
7504
|
-
/* @__PURE__ */
|
|
7750
|
+
return /* @__PURE__ */ jsxs58("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
7751
|
+
/* @__PURE__ */ jsx63("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
|
|
7505
7752
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
7506
7753
|
const active = selectedBand === g.key;
|
|
7507
|
-
return /* @__PURE__ */
|
|
7754
|
+
return /* @__PURE__ */ jsxs58(
|
|
7508
7755
|
"button",
|
|
7509
7756
|
{
|
|
7510
7757
|
type: "button",
|
|
7511
7758
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
7512
7759
|
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, transition: "background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)" },
|
|
7513
7760
|
children: [
|
|
7514
|
-
/* @__PURE__ */
|
|
7761
|
+
/* @__PURE__ */ jsx63("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx63("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ jsx63(
|
|
7515
7762
|
"span",
|
|
7516
7763
|
{
|
|
7517
7764
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -7520,13 +7767,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7520
7767
|
},
|
|
7521
7768
|
c.name
|
|
7522
7769
|
)) }),
|
|
7523
|
-
/* @__PURE__ */
|
|
7524
|
-
/* @__PURE__ */
|
|
7525
|
-
/* @__PURE__ */
|
|
7770
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
|
|
7771
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
|
|
7772
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx63("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
|
|
7526
7773
|
] }),
|
|
7527
|
-
/* @__PURE__ */
|
|
7528
|
-
/* @__PURE__ */
|
|
7529
|
-
/* @__PURE__ */
|
|
7774
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-stack", style: { gap: 1 }, children: [
|
|
7775
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-label-lg", children: g.label }),
|
|
7776
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
|
|
7530
7777
|
"CRP ",
|
|
7531
7778
|
g.range
|
|
7532
7779
|
] })
|
|
@@ -7536,10 +7783,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7536
7783
|
g.key
|
|
7537
7784
|
);
|
|
7538
7785
|
}) }),
|
|
7539
|
-
floorBand ? /* @__PURE__ */
|
|
7540
|
-
/* @__PURE__ */
|
|
7541
|
-
/* @__PURE__ */
|
|
7542
|
-
/* @__PURE__ */
|
|
7786
|
+
floorBand ? /* @__PURE__ */ jsxs58("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: [
|
|
7787
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx63("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
|
|
7788
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
|
|
7789
|
+
/* @__PURE__ */ jsxs58("strong", { style: { color: "var(--text)" }, children: [
|
|
7543
7790
|
"Plan floor ",
|
|
7544
7791
|
floorScore
|
|
7545
7792
|
] }),
|
|
@@ -7550,21 +7797,21 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7550
7797
|
}
|
|
7551
7798
|
|
|
7552
7799
|
// src/components/planner/MixGap.tsx
|
|
7553
|
-
import * as
|
|
7554
|
-
import { Fragment as Fragment15, jsx as
|
|
7800
|
+
import * as React34 from "react";
|
|
7801
|
+
import { Fragment as Fragment15, jsx as jsx64, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
7555
7802
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
7556
7803
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
7557
|
-
const [hover, setHover] =
|
|
7804
|
+
const [hover, setHover] = React34.useState(null);
|
|
7558
7805
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
7559
7806
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
7560
|
-
return /* @__PURE__ */
|
|
7561
|
-
/* @__PURE__ */
|
|
7562
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */
|
|
7563
|
-
/* @__PURE__ */
|
|
7807
|
+
return /* @__PURE__ */ jsxs59("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
7808
|
+
/* @__PURE__ */ jsxs59("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
|
|
7809
|
+
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs59("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
7810
|
+
/* @__PURE__ */ jsx64("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
|
|
7564
7811
|
l
|
|
7565
7812
|
] }, l)),
|
|
7566
|
-
/* @__PURE__ */
|
|
7567
|
-
/* @__PURE__ */
|
|
7813
|
+
/* @__PURE__ */ jsxs59("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
7814
|
+
/* @__PURE__ */ jsx64("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
|
|
7568
7815
|
"Target"
|
|
7569
7816
|
] })
|
|
7570
7817
|
] }),
|
|
@@ -7572,7 +7819,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
7572
7819
|
const gap = r.realized - r.target;
|
|
7573
7820
|
const tone = toneOf(gap);
|
|
7574
7821
|
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 : "");
|
|
7575
|
-
return /* @__PURE__ */
|
|
7822
|
+
return /* @__PURE__ */ jsxs59(
|
|
7576
7823
|
"div",
|
|
7577
7824
|
{
|
|
7578
7825
|
className: "fd-row",
|
|
@@ -7580,15 +7827,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
7580
7827
|
onMouseEnter: () => setHover(r.channel),
|
|
7581
7828
|
onMouseLeave: () => setHover(null),
|
|
7582
7829
|
children: [
|
|
7583
|
-
/* @__PURE__ */
|
|
7584
|
-
/* @__PURE__ */
|
|
7585
|
-
/* @__PURE__ */
|
|
7586
|
-
/* @__PURE__ */
|
|
7587
|
-
/* @__PURE__ */
|
|
7830
|
+
/* @__PURE__ */ jsx64("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx64(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
7831
|
+
/* @__PURE__ */ jsx64("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx64("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs59(Fragment15, { children: [
|
|
7832
|
+
/* @__PURE__ */ jsx64("span", { style: { position: "absolute", left: 0, top: 5, height: 12, width: r.realized / max * 100 + "%", background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
|
|
7833
|
+
/* @__PURE__ */ jsx64("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
|
|
7834
|
+
/* @__PURE__ */ jsxs59("span", { className: "fd-num", style: { position: "absolute", right: Math.max(r.realized, r.target) / max > 0.82 ? 0 : "auto", left: Math.max(r.realized, r.target) / max > 0.82 ? "auto" : "calc(" + Math.max(r.realized, r.target) / max * 100 + "% + 10px)", top: 2, fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap", background: Math.max(r.realized, r.target) / max > 0.82 ? "var(--surface)" : "none", paddingLeft: 3 }, children: [
|
|
7588
7835
|
r.realized,
|
|
7589
7836
|
"%"
|
|
7590
7837
|
] }),
|
|
7591
|
-
hover === r.channel ? /* @__PURE__ */
|
|
7838
|
+
hover === r.channel ? /* @__PURE__ */ jsx64("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: 26, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
|
|
7592
7839
|
] }) })
|
|
7593
7840
|
]
|
|
7594
7841
|
},
|
|
@@ -7599,7 +7846,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
7599
7846
|
}
|
|
7600
7847
|
|
|
7601
7848
|
// src/components/planner/ChannelContribution.tsx
|
|
7602
|
-
import { jsx as
|
|
7849
|
+
import { jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
7603
7850
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
7604
7851
|
function ChannelContribution({
|
|
7605
7852
|
channels = [],
|
|
@@ -7615,9 +7862,9 @@ function ChannelContribution({
|
|
|
7615
7862
|
const grand = total !== void 0 ? total : base + bonus;
|
|
7616
7863
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
7617
7864
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
7618
|
-
return /* @__PURE__ */
|
|
7619
|
-
loading ? /* @__PURE__ */
|
|
7620
|
-
channels.map((c) => /* @__PURE__ */
|
|
7865
|
+
return /* @__PURE__ */ jsxs60("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
7866
|
+
loading ? /* @__PURE__ */ jsx65("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs60("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
|
|
7867
|
+
channels.map((c) => /* @__PURE__ */ jsx65(
|
|
7621
7868
|
"span",
|
|
7622
7869
|
{
|
|
7623
7870
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -7626,7 +7873,7 @@ function ChannelContribution({
|
|
|
7626
7873
|
},
|
|
7627
7874
|
c.name
|
|
7628
7875
|
)),
|
|
7629
|
-
bonus > 0 ? /* @__PURE__ */
|
|
7876
|
+
bonus > 0 ? /* @__PURE__ */ jsx65(
|
|
7630
7877
|
"span",
|
|
7631
7878
|
{
|
|
7632
7879
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -7635,18 +7882,18 @@ function ChannelContribution({
|
|
|
7635
7882
|
}
|
|
7636
7883
|
) : null
|
|
7637
7884
|
] }),
|
|
7638
|
-
showTable ? /* @__PURE__ */
|
|
7639
|
-
/* @__PURE__ */
|
|
7640
|
-
/* @__PURE__ */
|
|
7641
|
-
/* @__PURE__ */
|
|
7642
|
-
/* @__PURE__ */
|
|
7643
|
-
/* @__PURE__ */
|
|
7644
|
-
/* @__PURE__ */
|
|
7885
|
+
showTable ? /* @__PURE__ */ jsxs60("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
|
|
7886
|
+
/* @__PURE__ */ jsx65("thead", { children: /* @__PURE__ */ jsxs60("tr", { children: [
|
|
7887
|
+
/* @__PURE__ */ jsx65("th", { style: { width: "34%" }, children: "Channel" }),
|
|
7888
|
+
/* @__PURE__ */ jsx65("th", { style: { width: "16%" }, children: "Weight" }),
|
|
7889
|
+
/* @__PURE__ */ jsx65("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
|
|
7890
|
+
/* @__PURE__ */ jsx65("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
|
|
7891
|
+
/* @__PURE__ */ jsx65("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
|
|
7645
7892
|
] }) }),
|
|
7646
|
-
/* @__PURE__ */
|
|
7647
|
-
channels.map((c) => /* @__PURE__ */
|
|
7648
|
-
/* @__PURE__ */
|
|
7649
|
-
/* @__PURE__ */
|
|
7893
|
+
/* @__PURE__ */ jsxs60("tbody", { children: [
|
|
7894
|
+
channels.map((c) => /* @__PURE__ */ jsxs60("tr", { children: [
|
|
7895
|
+
/* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsx65(ChannelTag, { channel: c.name, size: "sm" }) }),
|
|
7896
|
+
/* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsx65(
|
|
7650
7897
|
"span",
|
|
7651
7898
|
{
|
|
7652
7899
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -7655,38 +7902,38 @@ function ChannelContribution({
|
|
|
7655
7902
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
7656
7903
|
}
|
|
7657
7904
|
) }),
|
|
7658
|
-
/* @__PURE__ */
|
|
7659
|
-
/* @__PURE__ */
|
|
7660
|
-
/* @__PURE__ */
|
|
7905
|
+
/* @__PURE__ */ jsx65("td", { className: "is-num", children: c.spend }),
|
|
7906
|
+
/* @__PURE__ */ jsx65("td", { className: "is-num", children: c.crp.toFixed(1) }),
|
|
7907
|
+
/* @__PURE__ */ jsxs60("td", { className: "is-num", children: [
|
|
7661
7908
|
pct(c.crp).toFixed(0),
|
|
7662
7909
|
"%"
|
|
7663
7910
|
] })
|
|
7664
7911
|
] }, c.name)),
|
|
7665
|
-
bonus > 0 ? /* @__PURE__ */
|
|
7666
|
-
/* @__PURE__ */
|
|
7667
|
-
/* @__PURE__ */
|
|
7912
|
+
bonus > 0 ? /* @__PURE__ */ jsxs60("tr", { children: [
|
|
7913
|
+
/* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsxs60("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
|
|
7914
|
+
/* @__PURE__ */ jsx65("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" } }),
|
|
7668
7915
|
"Surround-sound bonus"
|
|
7669
7916
|
] }) }),
|
|
7670
|
-
/* @__PURE__ */
|
|
7917
|
+
/* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsxs60("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
7671
7918
|
"+",
|
|
7672
7919
|
bonusPct,
|
|
7673
7920
|
"% of +",
|
|
7674
7921
|
bonusMax,
|
|
7675
7922
|
"%"
|
|
7676
7923
|
] }) }),
|
|
7677
|
-
/* @__PURE__ */
|
|
7678
|
-
/* @__PURE__ */
|
|
7679
|
-
/* @__PURE__ */
|
|
7924
|
+
/* @__PURE__ */ jsx65("td", { className: "is-num fd-muted", children: "\u2014" }),
|
|
7925
|
+
/* @__PURE__ */ jsx65("td", { className: "is-num", children: bonus.toFixed(1) }),
|
|
7926
|
+
/* @__PURE__ */ jsxs60("td", { className: "is-num", children: [
|
|
7680
7927
|
pct(bonus).toFixed(0),
|
|
7681
7928
|
"%"
|
|
7682
7929
|
] })
|
|
7683
7930
|
] }) : null,
|
|
7684
|
-
/* @__PURE__ */
|
|
7685
|
-
/* @__PURE__ */
|
|
7686
|
-
/* @__PURE__ */
|
|
7687
|
-
/* @__PURE__ */
|
|
7688
|
-
/* @__PURE__ */
|
|
7689
|
-
/* @__PURE__ */
|
|
7931
|
+
/* @__PURE__ */ jsxs60("tr", { style: { background: "var(--surface-2)" }, children: [
|
|
7932
|
+
/* @__PURE__ */ jsx65("td", { style: { fontWeight: 700 }, children: "Campus total" }),
|
|
7933
|
+
/* @__PURE__ */ jsx65("td", {}),
|
|
7934
|
+
/* @__PURE__ */ jsx65("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
|
|
7935
|
+
/* @__PURE__ */ jsx65("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
|
|
7936
|
+
/* @__PURE__ */ jsx65("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
|
|
7690
7937
|
] })
|
|
7691
7938
|
] })
|
|
7692
7939
|
] }) : null
|
|
@@ -7694,8 +7941,8 @@ function ChannelContribution({
|
|
|
7694
7941
|
}
|
|
7695
7942
|
|
|
7696
7943
|
// src/components/planner/BudgetReallocator.tsx
|
|
7697
|
-
import * as
|
|
7698
|
-
import { Fragment as Fragment16, jsx as
|
|
7944
|
+
import * as React35 from "react";
|
|
7945
|
+
import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
7699
7946
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
7700
7947
|
function BudgetReallocator({
|
|
7701
7948
|
campus,
|
|
@@ -7710,8 +7957,8 @@ function BudgetReallocator({
|
|
|
7710
7957
|
onCancel,
|
|
7711
7958
|
className = ""
|
|
7712
7959
|
}) {
|
|
7713
|
-
const [draft, setDraft] =
|
|
7714
|
-
|
|
7960
|
+
const [draft, setDraft] = React35.useState(spend);
|
|
7961
|
+
React35.useEffect(() => setDraft(spend), [spend]);
|
|
7715
7962
|
const dirty = draft !== spend;
|
|
7716
7963
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
7717
7964
|
const nextBand = bandFor(nextCrp);
|
|
@@ -7726,24 +7973,24 @@ function BudgetReallocator({
|
|
|
7726
7973
|
setDraft(spend);
|
|
7727
7974
|
if (onCancel) onCancel();
|
|
7728
7975
|
};
|
|
7729
|
-
return /* @__PURE__ */
|
|
7976
|
+
return /* @__PURE__ */ jsxs61(
|
|
7730
7977
|
"div",
|
|
7731
7978
|
{
|
|
7732
7979
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
7733
7980
|
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)" },
|
|
7734
7981
|
children: [
|
|
7735
|
-
/* @__PURE__ */
|
|
7736
|
-
/* @__PURE__ */
|
|
7737
|
-
/* @__PURE__ */
|
|
7738
|
-
dirty ? /* @__PURE__ */
|
|
7739
|
-
/* @__PURE__ */
|
|
7740
|
-
/* @__PURE__ */
|
|
7982
|
+
/* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
7983
|
+
/* @__PURE__ */ jsx66("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
7984
|
+
/* @__PURE__ */ jsx66(CsiBadge, { band: nowBand, crp: Number(crp.toFixed(1)), size: "medium" }),
|
|
7985
|
+
dirty ? /* @__PURE__ */ jsxs61(Fragment16, { children: [
|
|
7986
|
+
/* @__PURE__ */ jsx66("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
7987
|
+
/* @__PURE__ */ jsx66(CsiBadge, { band: nextBand, crp: Number(nextCrp.toFixed(1)), size: "medium", preview: true })
|
|
7741
7988
|
] }) : null
|
|
7742
7989
|
] }),
|
|
7743
|
-
/* @__PURE__ */
|
|
7744
|
-
/* @__PURE__ */
|
|
7745
|
-
dirty ? /* @__PURE__ */
|
|
7746
|
-
/* @__PURE__ */
|
|
7990
|
+
/* @__PURE__ */ jsxs61("div", { className: "fd-slider", children: [
|
|
7991
|
+
/* @__PURE__ */ jsx66("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
7992
|
+
dirty ? /* @__PURE__ */ jsx66("span", { className: "fd-slider-chip", style: { left: pct + "%", background: delta < 0 ? "var(--danger-solid)" : "var(--ok-solid)" }, children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString() }) : null,
|
|
7993
|
+
/* @__PURE__ */ jsx66(
|
|
7747
7994
|
"input",
|
|
7748
7995
|
{
|
|
7749
7996
|
type: "range",
|
|
@@ -7759,13 +8006,13 @@ function BudgetReallocator({
|
|
|
7759
8006
|
}
|
|
7760
8007
|
)
|
|
7761
8008
|
] }),
|
|
7762
|
-
/* @__PURE__ */
|
|
7763
|
-
/* @__PURE__ */
|
|
7764
|
-
/* @__PURE__ */
|
|
7765
|
-
/* @__PURE__ */
|
|
8009
|
+
/* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8010
|
+
/* @__PURE__ */ jsxs61("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
|
|
8011
|
+
/* @__PURE__ */ jsx66("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
|
|
8012
|
+
/* @__PURE__ */ jsx66("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
|
|
7766
8013
|
] }),
|
|
7767
|
-
/* @__PURE__ */
|
|
7768
|
-
/* @__PURE__ */
|
|
8014
|
+
/* @__PURE__ */ jsx66("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
8015
|
+
/* @__PURE__ */ jsx66(
|
|
7769
8016
|
"button",
|
|
7770
8017
|
{
|
|
7771
8018
|
type: "button",
|
|
@@ -7784,7 +8031,7 @@ function BudgetReallocator({
|
|
|
7784
8031
|
}
|
|
7785
8032
|
|
|
7786
8033
|
// src/components/planner/SurroundSound.tsx
|
|
7787
|
-
import { jsx as
|
|
8034
|
+
import { jsx as jsx67, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
7788
8035
|
var CATEGORIES = [
|
|
7789
8036
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
7790
8037
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -7796,26 +8043,26 @@ var CATEGORIES = [
|
|
|
7796
8043
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
7797
8044
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
7798
8045
|
const single = present.length <= 2;
|
|
7799
|
-
return /* @__PURE__ */
|
|
7800
|
-
/* @__PURE__ */
|
|
8046
|
+
return /* @__PURE__ */ jsxs62("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
|
|
8047
|
+
/* @__PURE__ */ jsx67("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
|
|
7801
8048
|
const on = present.includes(c.key);
|
|
7802
|
-
return /* @__PURE__ */
|
|
8049
|
+
return /* @__PURE__ */ jsxs62(
|
|
7803
8050
|
"span",
|
|
7804
8051
|
{
|
|
7805
8052
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
7806
8053
|
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)" },
|
|
7807
8054
|
children: [
|
|
7808
|
-
/* @__PURE__ */
|
|
7809
|
-
/* @__PURE__ */
|
|
8055
|
+
/* @__PURE__ */ jsx67("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
8056
|
+
/* @__PURE__ */ jsx67("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
|
|
7810
8057
|
]
|
|
7811
8058
|
},
|
|
7812
8059
|
c.key
|
|
7813
8060
|
);
|
|
7814
8061
|
}) }),
|
|
7815
|
-
/* @__PURE__ */
|
|
7816
|
-
/* @__PURE__ */
|
|
7817
|
-
/* @__PURE__ */
|
|
7818
|
-
/* @__PURE__ */
|
|
8062
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
8063
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
8064
|
+
/* @__PURE__ */ jsx67("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
|
|
8065
|
+
/* @__PURE__ */ jsxs62("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
|
|
7819
8066
|
"+",
|
|
7820
8067
|
bonusPct,
|
|
7821
8068
|
"% of +",
|
|
@@ -7823,8 +8070,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
7823
8070
|
"%"
|
|
7824
8071
|
] })
|
|
7825
8072
|
] }),
|
|
7826
|
-
/* @__PURE__ */
|
|
7827
|
-
/* @__PURE__ */
|
|
8073
|
+
/* @__PURE__ */ jsx67("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx67("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
|
|
8074
|
+
/* @__PURE__ */ jsxs62("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
|
|
7828
8075
|
present.length,
|
|
7829
8076
|
" of 6 channel categories present.",
|
|
7830
8077
|
" ",
|
|
@@ -7836,10 +8083,10 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
7836
8083
|
}
|
|
7837
8084
|
|
|
7838
8085
|
// src/components/chat/AgentChatPanel.tsx
|
|
7839
|
-
import * as
|
|
8086
|
+
import * as React41 from "react";
|
|
7840
8087
|
|
|
7841
8088
|
// src/components/chat/chatEngine.ts
|
|
7842
|
-
import * as
|
|
8089
|
+
import * as React36 from "react";
|
|
7843
8090
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
7844
8091
|
var JOB_PENDING = ["queued", "running"];
|
|
7845
8092
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -7893,22 +8140,22 @@ function useChatEngine(opts) {
|
|
|
7893
8140
|
onClear,
|
|
7894
8141
|
onFeedback
|
|
7895
8142
|
} = opts || {};
|
|
7896
|
-
const [status, setStatus] =
|
|
7897
|
-
const [threadId, setThreadId] =
|
|
7898
|
-
const [messages, setMessages] =
|
|
7899
|
-
const [queue, setQueue] =
|
|
7900
|
-
const [fatal, setFatal] =
|
|
7901
|
-
const [busy, setBusy] =
|
|
7902
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
7903
|
-
const listRef =
|
|
7904
|
-
const queueRef =
|
|
7905
|
-
const busyRef =
|
|
7906
|
-
const stoppedRef =
|
|
7907
|
-
const abortRef =
|
|
7908
|
-
const serverCount =
|
|
7909
|
-
const threadRef =
|
|
7910
|
-
const mounted =
|
|
7911
|
-
|
|
8143
|
+
const [status, setStatus] = React36.useState("idle");
|
|
8144
|
+
const [threadId, setThreadId] = React36.useState(null);
|
|
8145
|
+
const [messages, setMessages] = React36.useState([]);
|
|
8146
|
+
const [queue, setQueue] = React36.useState([]);
|
|
8147
|
+
const [fatal, setFatal] = React36.useState(null);
|
|
8148
|
+
const [busy, setBusy] = React36.useState(false);
|
|
8149
|
+
const [turnStartedAt, setTurnStartedAt] = React36.useState(null);
|
|
8150
|
+
const listRef = React36.useRef([]);
|
|
8151
|
+
const queueRef = React36.useRef([]);
|
|
8152
|
+
const busyRef = React36.useRef(false);
|
|
8153
|
+
const stoppedRef = React36.useRef(false);
|
|
8154
|
+
const abortRef = React36.useRef(null);
|
|
8155
|
+
const serverCount = React36.useRef(0);
|
|
8156
|
+
const threadRef = React36.useRef(null);
|
|
8157
|
+
const mounted = React36.useRef(true);
|
|
8158
|
+
React36.useEffect(() => {
|
|
7912
8159
|
mounted.current = true;
|
|
7913
8160
|
return () => {
|
|
7914
8161
|
mounted.current = false;
|
|
@@ -7930,14 +8177,14 @@ function useChatEngine(opts) {
|
|
|
7930
8177
|
}
|
|
7931
8178
|
return false;
|
|
7932
8179
|
};
|
|
7933
|
-
const loadThread =
|
|
8180
|
+
const loadThread = React36.useCallback(async (id) => {
|
|
7934
8181
|
const data = await apiAdapter.getThread(id);
|
|
7935
8182
|
const list = [...data && data.messages || []];
|
|
7936
8183
|
serverCount.current = list.length;
|
|
7937
8184
|
commit(list);
|
|
7938
8185
|
return list;
|
|
7939
8186
|
}, [apiAdapter]);
|
|
7940
|
-
|
|
8187
|
+
React36.useEffect(() => {
|
|
7941
8188
|
if (!apiAdapter) {
|
|
7942
8189
|
setStatus("idle");
|
|
7943
8190
|
setFatal(null);
|
|
@@ -8150,7 +8397,7 @@ function useChatEngine(opts) {
|
|
|
8150
8397
|
await dispatchTurn(turn);
|
|
8151
8398
|
}
|
|
8152
8399
|
}
|
|
8153
|
-
const send =
|
|
8400
|
+
const send = React36.useCallback((text, attachments) => {
|
|
8154
8401
|
const body = (text || "").trim();
|
|
8155
8402
|
if (!body && !(attachments && attachments.length)) return;
|
|
8156
8403
|
if (status === "disconnected") return;
|
|
@@ -8160,7 +8407,7 @@ function useChatEngine(opts) {
|
|
|
8160
8407
|
stoppedRef.current = false;
|
|
8161
8408
|
drain();
|
|
8162
8409
|
}, [status]);
|
|
8163
|
-
const stop =
|
|
8410
|
+
const stop = React36.useCallback(() => {
|
|
8164
8411
|
stoppedRef.current = true;
|
|
8165
8412
|
const ac = abortRef.current;
|
|
8166
8413
|
if (ac) {
|
|
@@ -8179,11 +8426,11 @@ function useChatEngine(opts) {
|
|
|
8179
8426
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
8180
8427
|
}
|
|
8181
8428
|
}, [apiAdapter]);
|
|
8182
|
-
const removeQueued =
|
|
8429
|
+
const removeQueued = React36.useCallback((id) => {
|
|
8183
8430
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
8184
8431
|
setQueue(queueRef.current.slice());
|
|
8185
8432
|
}, []);
|
|
8186
|
-
const retry =
|
|
8433
|
+
const retry = React36.useCallback(() => {
|
|
8187
8434
|
const list = listRef.current;
|
|
8188
8435
|
let at = -1;
|
|
8189
8436
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -8199,19 +8446,19 @@ function useChatEngine(opts) {
|
|
|
8199
8446
|
setQueue(queueRef.current.slice());
|
|
8200
8447
|
drain();
|
|
8201
8448
|
}, []);
|
|
8202
|
-
const clear =
|
|
8449
|
+
const clear = React36.useCallback(() => {
|
|
8203
8450
|
commit([]);
|
|
8204
8451
|
serverCount.current = 0;
|
|
8205
8452
|
queueRef.current = [];
|
|
8206
8453
|
setQueue([]);
|
|
8207
8454
|
onClear && onClear();
|
|
8208
8455
|
}, [onClear]);
|
|
8209
|
-
const setFeedback =
|
|
8456
|
+
const setFeedback = React36.useCallback((id, value) => {
|
|
8210
8457
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
8211
8458
|
const msg = listRef.current.find((m) => m.id === id);
|
|
8212
8459
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
8213
8460
|
}, [onFeedback]);
|
|
8214
|
-
const reload =
|
|
8461
|
+
const reload = React36.useCallback(async () => {
|
|
8215
8462
|
if (!threadRef.current) return;
|
|
8216
8463
|
setStatus("loading");
|
|
8217
8464
|
try {
|
|
@@ -8249,11 +8496,11 @@ var ChatKit = {
|
|
|
8249
8496
|
};
|
|
8250
8497
|
|
|
8251
8498
|
// src/components/chat/ChatTranscript.tsx
|
|
8252
|
-
import * as
|
|
8499
|
+
import * as React38 from "react";
|
|
8253
8500
|
|
|
8254
8501
|
// src/components/chat/ChatTurn.tsx
|
|
8255
|
-
import * as
|
|
8256
|
-
import { jsx as
|
|
8502
|
+
import * as React37 from "react";
|
|
8503
|
+
import { jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
8257
8504
|
function JsonView({ value }) {
|
|
8258
8505
|
let text;
|
|
8259
8506
|
try {
|
|
@@ -8261,67 +8508,67 @@ function JsonView({ value }) {
|
|
|
8261
8508
|
} catch (e) {
|
|
8262
8509
|
text = String(value);
|
|
8263
8510
|
}
|
|
8264
|
-
return /* @__PURE__ */
|
|
8511
|
+
return /* @__PURE__ */ jsx68(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
8265
8512
|
}
|
|
8266
8513
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
8267
8514
|
if (!packet) return null;
|
|
8268
8515
|
const s = schema || {};
|
|
8269
8516
|
const invalid = packet.valid === false;
|
|
8270
8517
|
const title = s.heading || packet.type;
|
|
8271
|
-
return /* @__PURE__ */
|
|
8272
|
-
/* @__PURE__ */
|
|
8273
|
-
/* @__PURE__ */
|
|
8274
|
-
/* @__PURE__ */
|
|
8275
|
-
packet.repaired ? /* @__PURE__ */
|
|
8276
|
-
invalid ? /* @__PURE__ */
|
|
8518
|
+
return /* @__PURE__ */ jsxs63("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
|
|
8519
|
+
/* @__PURE__ */ jsxs63("header", { className: "fdc-packet-head", children: [
|
|
8520
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
|
|
8521
|
+
/* @__PURE__ */ jsx68("span", { className: "fdc-packet-title", children: title }),
|
|
8522
|
+
packet.repaired ? /* @__PURE__ */ jsx68("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
|
|
8523
|
+
invalid ? /* @__PURE__ */ jsx68("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
|
|
8277
8524
|
] }),
|
|
8278
|
-
invalid ? /* @__PURE__ */
|
|
8279
|
-
/* @__PURE__ */
|
|
8280
|
-
/* @__PURE__ */
|
|
8281
|
-
] }) : /* @__PURE__ */
|
|
8282
|
-
!invalid && onApply ? /* @__PURE__ */
|
|
8283
|
-
packet.repaired ? /* @__PURE__ */
|
|
8284
|
-
/* @__PURE__ */
|
|
8285
|
-
/* @__PURE__ */
|
|
8525
|
+
invalid ? /* @__PURE__ */ jsxs63("div", { className: "fdc-packet-alert", role: "alert", children: [
|
|
8526
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
8527
|
+
/* @__PURE__ */ jsx68("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
|
|
8528
|
+
] }) : /* @__PURE__ */ jsx68("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx68(JsonView, { value: packet.payload }) }),
|
|
8529
|
+
!invalid && onApply ? /* @__PURE__ */ jsxs63("footer", { className: "fdc-packet-foot", children: [
|
|
8530
|
+
packet.repaired ? /* @__PURE__ */ jsx68("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx68("span", {}),
|
|
8531
|
+
/* @__PURE__ */ jsxs63("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
|
|
8532
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
|
|
8286
8533
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
8287
8534
|
] })
|
|
8288
8535
|
] }) : null
|
|
8289
8536
|
] });
|
|
8290
8537
|
}
|
|
8291
8538
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
8292
|
-
const [open, setOpen] =
|
|
8539
|
+
const [open, setOpen] = React37.useState(defaultOpen);
|
|
8293
8540
|
if (!text) return null;
|
|
8294
|
-
return /* @__PURE__ */
|
|
8295
|
-
/* @__PURE__ */
|
|
8296
|
-
/* @__PURE__ */
|
|
8297
|
-
/* @__PURE__ */
|
|
8298
|
-
streaming ? /* @__PURE__ */
|
|
8299
|
-
/* @__PURE__ */
|
|
8300
|
-
/* @__PURE__ */
|
|
8301
|
-
/* @__PURE__ */
|
|
8541
|
+
return /* @__PURE__ */ jsxs63("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
8542
|
+
/* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
8543
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-brain", "aria-hidden": "true" }),
|
|
8544
|
+
/* @__PURE__ */ jsx68("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
|
|
8545
|
+
streaming ? /* @__PURE__ */ jsxs63("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
8546
|
+
/* @__PURE__ */ jsx68("span", {}),
|
|
8547
|
+
/* @__PURE__ */ jsx68("span", {}),
|
|
8548
|
+
/* @__PURE__ */ jsx68("span", {})
|
|
8302
8549
|
] }) : null,
|
|
8303
|
-
/* @__PURE__ */
|
|
8550
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
8304
8551
|
] }),
|
|
8305
|
-
open ? /* @__PURE__ */
|
|
8552
|
+
open ? /* @__PURE__ */ jsx68("div", { className: "fdc-think-body", children: text }) : null
|
|
8306
8553
|
] });
|
|
8307
8554
|
}
|
|
8308
8555
|
function Citations({ items = [], onOpen }) {
|
|
8309
|
-
const [open, setOpen] =
|
|
8556
|
+
const [open, setOpen] = React37.useState(false);
|
|
8310
8557
|
if (!items.length) return null;
|
|
8311
|
-
return /* @__PURE__ */
|
|
8312
|
-
/* @__PURE__ */
|
|
8313
|
-
/* @__PURE__ */
|
|
8314
|
-
/* @__PURE__ */
|
|
8558
|
+
return /* @__PURE__ */ jsxs63("div", { className: "fdc-cites", children: [
|
|
8559
|
+
/* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
8560
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
|
|
8561
|
+
/* @__PURE__ */ jsxs63("span", { children: [
|
|
8315
8562
|
items.length,
|
|
8316
8563
|
" source",
|
|
8317
8564
|
items.length === 1 ? "" : "s"
|
|
8318
8565
|
] }),
|
|
8319
|
-
/* @__PURE__ */
|
|
8566
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
8320
8567
|
] }),
|
|
8321
|
-
open ? /* @__PURE__ */
|
|
8322
|
-
/* @__PURE__ */
|
|
8323
|
-
c.url ? /* @__PURE__ */
|
|
8324
|
-
c.detail ? /* @__PURE__ */
|
|
8568
|
+
open ? /* @__PURE__ */ jsx68("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs63("li", { children: [
|
|
8569
|
+
/* @__PURE__ */ jsx68("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
|
|
8570
|
+
c.url ? /* @__PURE__ */ jsx68("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx68("span", { children: c.title || "Source" }),
|
|
8571
|
+
c.detail ? /* @__PURE__ */ jsx68("span", { className: "fdc-cite-detail", children: c.detail }) : null
|
|
8325
8572
|
] }, c.id || i)) }) : null
|
|
8326
8573
|
] });
|
|
8327
8574
|
}
|
|
@@ -8332,29 +8579,29 @@ function clampText(text, max) {
|
|
|
8332
8579
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
8333
8580
|
}
|
|
8334
8581
|
function MessageBody({ message: m, ctx }) {
|
|
8335
|
-
const [expanded, setExpanded] =
|
|
8582
|
+
const [expanded, setExpanded] = React37.useState(false);
|
|
8336
8583
|
const isUser = m.role === "user";
|
|
8337
8584
|
const raw = m.text || "";
|
|
8338
8585
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
8339
8586
|
const body = clamped != null ? clamped : raw;
|
|
8340
8587
|
const showMd = ctx.markdown && !isUser;
|
|
8341
|
-
return /* @__PURE__ */
|
|
8342
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */
|
|
8343
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */
|
|
8344
|
-
body ? /* @__PURE__ */
|
|
8345
|
-
showMd ? /* @__PURE__ */
|
|
8346
|
-
m.streaming ? /* @__PURE__ */
|
|
8588
|
+
return /* @__PURE__ */ jsxs63("div", { className: "fdc-body", children: [
|
|
8589
|
+
m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx68(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
|
|
8590
|
+
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx68(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
|
|
8591
|
+
body ? /* @__PURE__ */ jsxs63("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
|
|
8592
|
+
showMd ? /* @__PURE__ */ jsx68(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx68("div", { className: "fdc-plain", children: body }),
|
|
8593
|
+
m.streaming ? /* @__PURE__ */ jsx68("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
|
|
8347
8594
|
] }) : null,
|
|
8348
|
-
clamped != null ? /* @__PURE__ */
|
|
8349
|
-
/* @__PURE__ */
|
|
8595
|
+
clamped != null ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
|
|
8596
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
|
|
8350
8597
|
"Show more",
|
|
8351
|
-
/* @__PURE__ */
|
|
8352
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */
|
|
8353
|
-
/* @__PURE__ */
|
|
8598
|
+
/* @__PURE__ */ jsx68("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
|
|
8599
|
+
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
|
|
8600
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
|
|
8354
8601
|
"Show less"
|
|
8355
8602
|
] }) : null,
|
|
8356
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */
|
|
8357
|
-
m.packet ? /* @__PURE__ */
|
|
8603
|
+
m.attachments && m.attachments.length ? /* @__PURE__ */ jsx68(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
|
|
8604
|
+
m.packet ? /* @__PURE__ */ jsx68(
|
|
8358
8605
|
PacketCard,
|
|
8359
8606
|
{
|
|
8360
8607
|
packet: m.packet,
|
|
@@ -8364,44 +8611,44 @@ function MessageBody({ message: m, ctx }) {
|
|
|
8364
8611
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
8365
8612
|
}
|
|
8366
8613
|
) : null,
|
|
8367
|
-
m.citations && m.citations.length ? /* @__PURE__ */
|
|
8368
|
-
m.working ? /* @__PURE__ */
|
|
8369
|
-
/* @__PURE__ */
|
|
8370
|
-
/* @__PURE__ */
|
|
8371
|
-
/* @__PURE__ */
|
|
8372
|
-
/* @__PURE__ */
|
|
8614
|
+
m.citations && m.citations.length ? /* @__PURE__ */ jsx68(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
|
|
8615
|
+
m.working ? /* @__PURE__ */ jsxs63("div", { className: "fdc-working", role: "status", children: [
|
|
8616
|
+
/* @__PURE__ */ jsxs63("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
8617
|
+
/* @__PURE__ */ jsx68("span", {}),
|
|
8618
|
+
/* @__PURE__ */ jsx68("span", {}),
|
|
8619
|
+
/* @__PURE__ */ jsx68("span", {})
|
|
8373
8620
|
] }),
|
|
8374
|
-
/* @__PURE__ */
|
|
8621
|
+
/* @__PURE__ */ jsxs63("span", { className: "fdc-working-label", children: [
|
|
8375
8622
|
m.resumed ? "Resuming" : "Working",
|
|
8376
|
-
m.job && m.job.status ? /* @__PURE__ */
|
|
8623
|
+
m.job && m.job.status ? /* @__PURE__ */ jsxs63("span", { className: "fdc-working-job", children: [
|
|
8377
8624
|
" \xB7 ",
|
|
8378
8625
|
m.job.status
|
|
8379
8626
|
] }) : null,
|
|
8380
|
-
m.job && m.job.detail ? /* @__PURE__ */
|
|
8627
|
+
m.job && m.job.detail ? /* @__PURE__ */ jsxs63("span", { className: "fdc-working-job", children: [
|
|
8381
8628
|
" \xB7 ",
|
|
8382
8629
|
m.job.detail
|
|
8383
8630
|
] }) : null
|
|
8384
8631
|
] }),
|
|
8385
|
-
m.jobId ? /* @__PURE__ */
|
|
8632
|
+
m.jobId ? /* @__PURE__ */ jsx68("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
8386
8633
|
] }) : null,
|
|
8387
|
-
m.stopped ? /* @__PURE__ */
|
|
8388
|
-
/* @__PURE__ */
|
|
8634
|
+
m.stopped ? /* @__PURE__ */ jsxs63("div", { className: "fdc-stopped", children: [
|
|
8635
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
8389
8636
|
"Stopped"
|
|
8390
8637
|
] }) : null,
|
|
8391
|
-
m.error ? /* @__PURE__ */
|
|
8392
|
-
/* @__PURE__ */
|
|
8393
|
-
/* @__PURE__ */
|
|
8394
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */
|
|
8395
|
-
/* @__PURE__ */
|
|
8638
|
+
m.error ? /* @__PURE__ */ jsxs63("div", { className: "fdc-error", role: "alert", children: [
|
|
8639
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
8640
|
+
/* @__PURE__ */ jsx68("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
|
|
8641
|
+
m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
|
|
8642
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
8396
8643
|
"Retry"
|
|
8397
8644
|
] }) : null
|
|
8398
8645
|
] }) : null
|
|
8399
8646
|
] });
|
|
8400
8647
|
}
|
|
8401
8648
|
function useCopyRun() {
|
|
8402
|
-
const [done, setDone] =
|
|
8403
|
-
const t =
|
|
8404
|
-
|
|
8649
|
+
const [done, setDone] = React37.useState(false);
|
|
8650
|
+
const t = React37.useRef(null);
|
|
8651
|
+
React37.useEffect(() => () => {
|
|
8405
8652
|
if (t.current) clearTimeout(t.current);
|
|
8406
8653
|
}, []);
|
|
8407
8654
|
return [done, (text) => {
|
|
@@ -8421,16 +8668,16 @@ function RunActions({ group, ctx }) {
|
|
|
8421
8668
|
const isAssistant = group.role === "assistant";
|
|
8422
8669
|
const fb = last.feedback;
|
|
8423
8670
|
if (!ctx.messageActions) return null;
|
|
8424
|
-
return /* @__PURE__ */
|
|
8425
|
-
/* @__PURE__ */
|
|
8426
|
-
/* @__PURE__ */
|
|
8427
|
-
/* @__PURE__ */
|
|
8671
|
+
return /* @__PURE__ */ jsxs63("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
|
|
8672
|
+
/* @__PURE__ */ jsxs63("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
|
|
8673
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
|
|
8674
|
+
/* @__PURE__ */ jsx68("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
|
|
8428
8675
|
] }),
|
|
8429
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */
|
|
8430
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */
|
|
8431
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */
|
|
8432
|
-
/* @__PURE__ */
|
|
8433
|
-
/* @__PURE__ */
|
|
8676
|
+
isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx68("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
8677
|
+
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx68("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx68("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
8678
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs63(React37.Fragment, { children: [
|
|
8679
|
+
/* @__PURE__ */ jsx68("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__ */ jsx68("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
8680
|
+
/* @__PURE__ */ jsx68("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__ */ jsx68("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
8434
8681
|
] }) : null,
|
|
8435
8682
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
8436
8683
|
] });
|
|
@@ -8440,22 +8687,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
8440
8687
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
8441
8688
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
8442
8689
|
const stamp = group.messages[0].timestamp;
|
|
8443
|
-
return /* @__PURE__ */
|
|
8444
|
-
/* @__PURE__ */
|
|
8445
|
-
ctx.showAvatars ? /* @__PURE__ */
|
|
8446
|
-
/* @__PURE__ */
|
|
8447
|
-
stamp ? /* @__PURE__ */
|
|
8448
|
-
group.messages.some((m) => m.model) ? /* @__PURE__ */
|
|
8690
|
+
return /* @__PURE__ */ jsxs63("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
|
|
8691
|
+
/* @__PURE__ */ jsxs63("div", { className: "fdc-turn-head", children: [
|
|
8692
|
+
ctx.showAvatars ? /* @__PURE__ */ jsx68("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx68("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx68("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx68("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
|
|
8693
|
+
/* @__PURE__ */ jsx68("span", { className: "fdc-who", children: name }),
|
|
8694
|
+
stamp ? /* @__PURE__ */ jsx68(RelativeTime, { className: "fdc-when", value: stamp }) : null,
|
|
8695
|
+
group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx68("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
|
|
8449
8696
|
] }),
|
|
8450
|
-
/* @__PURE__ */
|
|
8451
|
-
group.messages.map((m) => /* @__PURE__ */
|
|
8452
|
-
/* @__PURE__ */
|
|
8697
|
+
/* @__PURE__ */ jsxs63("div", { className: "fdc-turn-body", children: [
|
|
8698
|
+
group.messages.map((m) => /* @__PURE__ */ jsx68("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx68(MessageBody, { message: m, ctx }) }, m.id)),
|
|
8699
|
+
/* @__PURE__ */ jsx68(RunActions, { group, ctx })
|
|
8453
8700
|
] })
|
|
8454
8701
|
] });
|
|
8455
8702
|
}
|
|
8456
8703
|
|
|
8457
8704
|
// src/components/chat/ChatTranscript.tsx
|
|
8458
|
-
import { jsx as
|
|
8705
|
+
import { jsx as jsx69, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
8459
8706
|
var GROUP_WINDOW = 6e4;
|
|
8460
8707
|
var STICK_PX = 100;
|
|
8461
8708
|
function groupMessages(list) {
|
|
@@ -8488,25 +8735,25 @@ function dayLabel(key) {
|
|
|
8488
8735
|
}
|
|
8489
8736
|
function Suggestions({ items = [], onPick }) {
|
|
8490
8737
|
if (!items.length) return null;
|
|
8491
|
-
return /* @__PURE__ */
|
|
8738
|
+
return /* @__PURE__ */ jsx69("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
8492
8739
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
8493
|
-
return /* @__PURE__ */
|
|
8494
|
-
it.icon ? /* @__PURE__ */
|
|
8495
|
-
/* @__PURE__ */
|
|
8496
|
-
/* @__PURE__ */
|
|
8497
|
-
it.description ? /* @__PURE__ */
|
|
8740
|
+
return /* @__PURE__ */ jsxs64("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
|
|
8741
|
+
it.icon ? /* @__PURE__ */ jsx69("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
|
|
8742
|
+
/* @__PURE__ */ jsxs64("span", { className: "fdc-suggest-text", children: [
|
|
8743
|
+
/* @__PURE__ */ jsx69("span", { className: "fdc-suggest-label", children: it.label }),
|
|
8744
|
+
it.description ? /* @__PURE__ */ jsx69("span", { className: "fdc-suggest-desc", children: it.description }) : null
|
|
8498
8745
|
] }),
|
|
8499
|
-
/* @__PURE__ */
|
|
8746
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
8500
8747
|
] }, it.id || i);
|
|
8501
8748
|
}) });
|
|
8502
8749
|
}
|
|
8503
8750
|
function LoadingTurns() {
|
|
8504
|
-
return /* @__PURE__ */
|
|
8505
|
-
/* @__PURE__ */
|
|
8506
|
-
/* @__PURE__ */
|
|
8507
|
-
/* @__PURE__ */
|
|
8508
|
-
/* @__PURE__ */
|
|
8509
|
-
/* @__PURE__ */
|
|
8751
|
+
return /* @__PURE__ */ jsx69("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs64("div", { className: "fdc-skel-turn", children: [
|
|
8752
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
|
|
8753
|
+
/* @__PURE__ */ jsxs64("div", { className: "fdc-skel-lines", children: [
|
|
8754
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
|
|
8755
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
|
|
8756
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
|
|
8510
8757
|
] })
|
|
8511
8758
|
] }, i)) });
|
|
8512
8759
|
}
|
|
@@ -8523,10 +8770,10 @@ function ChatTranscript({
|
|
|
8523
8770
|
renderEmpty,
|
|
8524
8771
|
className = ""
|
|
8525
8772
|
}) {
|
|
8526
|
-
const scroller =
|
|
8527
|
-
const stick =
|
|
8528
|
-
const [pill, setPill] =
|
|
8529
|
-
const seen =
|
|
8773
|
+
const scroller = React38.useRef(null);
|
|
8774
|
+
const stick = React38.useRef(true);
|
|
8775
|
+
const [pill, setPill] = React38.useState(0);
|
|
8776
|
+
const seen = React38.useRef(0);
|
|
8530
8777
|
const toBottom = (smooth) => {
|
|
8531
8778
|
const el = scroller.current;
|
|
8532
8779
|
if (!el) return;
|
|
@@ -8545,7 +8792,7 @@ function ChatTranscript({
|
|
|
8545
8792
|
seen.current = messages.length;
|
|
8546
8793
|
}
|
|
8547
8794
|
};
|
|
8548
|
-
|
|
8795
|
+
React38.useLayoutEffect(() => {
|
|
8549
8796
|
const el = scroller.current;
|
|
8550
8797
|
if (!el) return;
|
|
8551
8798
|
if (stick.current) {
|
|
@@ -8553,7 +8800,7 @@ function ChatTranscript({
|
|
|
8553
8800
|
seen.current = messages.length;
|
|
8554
8801
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
8555
8802
|
}, [messages]);
|
|
8556
|
-
|
|
8803
|
+
React38.useEffect(() => {
|
|
8557
8804
|
const el = scroller.current;
|
|
8558
8805
|
const inner = el && el.firstChild;
|
|
8559
8806
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -8563,38 +8810,38 @@ function ChatTranscript({
|
|
|
8563
8810
|
ro.observe(inner);
|
|
8564
8811
|
return () => ro.disconnect();
|
|
8565
8812
|
}, []);
|
|
8566
|
-
const groups =
|
|
8813
|
+
const groups = React38.useMemo(() => groupMessages(messages), [messages]);
|
|
8567
8814
|
const empty = !messages.length && status === "ready";
|
|
8568
|
-
return /* @__PURE__ */
|
|
8569
|
-
/* @__PURE__ */
|
|
8570
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */
|
|
8571
|
-
status === "disconnected" ? /* @__PURE__ */
|
|
8572
|
-
/* @__PURE__ */
|
|
8573
|
-
/* @__PURE__ */
|
|
8574
|
-
/* @__PURE__ */
|
|
8575
|
-
ctx.onReconnect ? /* @__PURE__ */
|
|
8576
|
-
/* @__PURE__ */
|
|
8815
|
+
return /* @__PURE__ */ jsxs64("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
8816
|
+
/* @__PURE__ */ jsxs64("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
8817
|
+
status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx69(LoadingTurns, {}) : null,
|
|
8818
|
+
status === "disconnected" ? /* @__PURE__ */ jsxs64("div", { className: "fdc-dead", children: [
|
|
8819
|
+
/* @__PURE__ */ jsx69("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx69("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
|
|
8820
|
+
/* @__PURE__ */ jsx69("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
|
|
8821
|
+
/* @__PURE__ */ jsx69("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." }),
|
|
8822
|
+
ctx.onReconnect ? /* @__PURE__ */ jsxs64("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
|
|
8823
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
8577
8824
|
"Try again"
|
|
8578
8825
|
] }) : null
|
|
8579
8826
|
] }) : null,
|
|
8580
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
8581
|
-
/* @__PURE__ */
|
|
8582
|
-
/* @__PURE__ */
|
|
8583
|
-
emptyDescription ? /* @__PURE__ */
|
|
8584
|
-
/* @__PURE__ */
|
|
8827
|
+
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs64("div", { className: "fdc-empty", children: [
|
|
8828
|
+
/* @__PURE__ */ jsx69("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx69("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
|
|
8829
|
+
/* @__PURE__ */ jsx69("h3", { className: "fdc-empty-title", children: emptyTitle }),
|
|
8830
|
+
emptyDescription ? /* @__PURE__ */ jsx69("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
|
|
8831
|
+
/* @__PURE__ */ jsx69(Suggestions, { items: suggestions, onPick })
|
|
8585
8832
|
] }) : null,
|
|
8586
8833
|
groups.map((g, i) => {
|
|
8587
8834
|
const prev = groups[i - 1];
|
|
8588
8835
|
const k = dayKey(g.messages[0].timestamp);
|
|
8589
8836
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
8590
|
-
return /* @__PURE__ */
|
|
8591
|
-
showDay ? /* @__PURE__ */
|
|
8592
|
-
/* @__PURE__ */
|
|
8837
|
+
return /* @__PURE__ */ jsxs64(React38.Fragment, { children: [
|
|
8838
|
+
showDay ? /* @__PURE__ */ jsx69("div", { className: "fdc-day", children: /* @__PURE__ */ jsx69("span", { children: dayLabel(k) }) }) : null,
|
|
8839
|
+
/* @__PURE__ */ jsx69(ChatTurn, { group: g, ctx })
|
|
8593
8840
|
] }, g.key || i);
|
|
8594
8841
|
})
|
|
8595
8842
|
] }),
|
|
8596
|
-
pill ? /* @__PURE__ */
|
|
8597
|
-
/* @__PURE__ */
|
|
8843
|
+
pill ? /* @__PURE__ */ jsxs64("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
|
|
8844
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
|
|
8598
8845
|
pill,
|
|
8599
8846
|
" new message",
|
|
8600
8847
|
pill === 1 ? "" : "s"
|
|
@@ -8604,8 +8851,8 @@ function ChatTranscript({
|
|
|
8604
8851
|
var TranscriptKit = { groupMessages };
|
|
8605
8852
|
|
|
8606
8853
|
// src/components/chat/ChatComposer.tsx
|
|
8607
|
-
import * as
|
|
8608
|
-
import { jsx as
|
|
8854
|
+
import * as React39 from "react";
|
|
8855
|
+
import { jsx as jsx70, jsxs as jsxs65 } from "react/jsx-runtime";
|
|
8609
8856
|
function ChatComposer({
|
|
8610
8857
|
onSubmit,
|
|
8611
8858
|
onStop,
|
|
@@ -8632,17 +8879,17 @@ function ChatComposer({
|
|
|
8632
8879
|
onReject,
|
|
8633
8880
|
onOpenAttachment
|
|
8634
8881
|
}) {
|
|
8635
|
-
const [text, setText] =
|
|
8636
|
-
const [trigger, setTrigger] =
|
|
8637
|
-
const [mentionItems, setMentionItems] =
|
|
8638
|
-
const [listening, setListening] =
|
|
8639
|
-
const [notice, setNotice] =
|
|
8640
|
-
const editor =
|
|
8641
|
-
const wrap =
|
|
8642
|
-
const stopVoice =
|
|
8882
|
+
const [text, setText] = React39.useState(draft || "");
|
|
8883
|
+
const [trigger, setTrigger] = React39.useState(null);
|
|
8884
|
+
const [mentionItems, setMentionItems] = React39.useState([]);
|
|
8885
|
+
const [listening, setListening] = React39.useState(false);
|
|
8886
|
+
const [notice, setNotice] = React39.useState(null);
|
|
8887
|
+
const editor = React39.useRef(null);
|
|
8888
|
+
const wrap = React39.useRef(null);
|
|
8889
|
+
const stopVoice = React39.useRef(null);
|
|
8643
8890
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
8644
8891
|
} });
|
|
8645
|
-
|
|
8892
|
+
React39.useEffect(() => {
|
|
8646
8893
|
if (draft != null && draft !== text) setText(draft);
|
|
8647
8894
|
}, [draft]);
|
|
8648
8895
|
const change = (v) => {
|
|
@@ -8676,7 +8923,7 @@ function ChatComposer({
|
|
|
8676
8923
|
e.preventDefault();
|
|
8677
8924
|
staged.add(found.files);
|
|
8678
8925
|
};
|
|
8679
|
-
|
|
8926
|
+
React39.useEffect(() => {
|
|
8680
8927
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
8681
8928
|
setMentionItems([]);
|
|
8682
8929
|
return;
|
|
@@ -8694,7 +8941,7 @@ function ChatComposer({
|
|
|
8694
8941
|
const q = (trigger.query || "").toLowerCase();
|
|
8695
8942
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
8696
8943
|
}, [trigger, mentionSources]);
|
|
8697
|
-
const slashItems =
|
|
8944
|
+
const slashItems = React39.useMemo(() => {
|
|
8698
8945
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
8699
8946
|
const q = (trigger.query || "").toLowerCase();
|
|
8700
8947
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -8708,7 +8955,7 @@ function ChatComposer({
|
|
|
8708
8955
|
description: it.description,
|
|
8709
8956
|
icon: it.icon,
|
|
8710
8957
|
meta: mention.meta,
|
|
8711
|
-
shortcut: slash.shortcut ? /* @__PURE__ */
|
|
8958
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ jsx70(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
8712
8959
|
onSelect: () => {
|
|
8713
8960
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
8714
8961
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -8771,14 +9018,14 @@ function ChatComposer({
|
|
|
8771
9018
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
8772
9019
|
};
|
|
8773
9020
|
};
|
|
8774
|
-
return /* @__PURE__ */
|
|
8775
|
-
queue.length ? /* @__PURE__ */
|
|
8776
|
-
/* @__PURE__ */
|
|
8777
|
-
/* @__PURE__ */
|
|
8778
|
-
onRemoveQueued ? /* @__PURE__ */
|
|
9021
|
+
return /* @__PURE__ */ jsxs65("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
|
|
9022
|
+
queue.length ? /* @__PURE__ */ jsx70("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs65("div", { className: "fdc-queue-row", children: [
|
|
9023
|
+
/* @__PURE__ */ jsx70("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
|
|
9024
|
+
/* @__PURE__ */ jsx70("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
|
|
9025
|
+
onRemoveQueued ? /* @__PURE__ */ jsx70("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx70("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
8779
9026
|
] }, q.id)) }) : null,
|
|
8780
9027
|
sessionBar,
|
|
8781
|
-
/* @__PURE__ */
|
|
9028
|
+
/* @__PURE__ */ jsx70(
|
|
8782
9029
|
Dropzone,
|
|
8783
9030
|
{
|
|
8784
9031
|
className: "fdc-field",
|
|
@@ -8792,9 +9039,9 @@ function ChatComposer({
|
|
|
8792
9039
|
disabled: !fileUploadHandler || disabled,
|
|
8793
9040
|
label: "Drop to attach",
|
|
8794
9041
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
8795
|
-
children: /* @__PURE__ */
|
|
8796
|
-
staged.items.length ? /* @__PURE__ */
|
|
8797
|
-
/* @__PURE__ */
|
|
9042
|
+
children: /* @__PURE__ */ jsxs65("div", { ref: wrap, className: "fdc-field-inner", children: [
|
|
9043
|
+
staged.items.length ? /* @__PURE__ */ jsx70("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx70(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
|
|
9044
|
+
/* @__PURE__ */ jsx70(
|
|
8798
9045
|
MarkdownEditor,
|
|
8799
9046
|
{
|
|
8800
9047
|
ref: editor,
|
|
@@ -8813,33 +9060,33 @@ function ChatComposer({
|
|
|
8813
9060
|
ariaLabel: "Message"
|
|
8814
9061
|
}
|
|
8815
9062
|
),
|
|
8816
|
-
/* @__PURE__ */
|
|
8817
|
-
fileUploadHandler ? /* @__PURE__ */
|
|
8818
|
-
voiceHandler ? /* @__PURE__ */
|
|
9063
|
+
/* @__PURE__ */ jsxs65("div", { className: "fdc-tools", children: [
|
|
9064
|
+
fileUploadHandler ? /* @__PURE__ */ jsx70(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
|
|
9065
|
+
voiceHandler ? /* @__PURE__ */ jsx70("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx70("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
|
|
8819
9066
|
toolbarExtras,
|
|
8820
|
-
/* @__PURE__ */
|
|
8821
|
-
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */
|
|
9067
|
+
/* @__PURE__ */ jsx70("span", { className: "fdc-tools-gap" }),
|
|
9068
|
+
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs65("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
|
|
8822
9069
|
text.length,
|
|
8823
9070
|
"/",
|
|
8824
9071
|
maxLength
|
|
8825
9072
|
] }) : null,
|
|
8826
|
-
busy ? /* @__PURE__ */
|
|
8827
|
-
/* @__PURE__ */
|
|
8828
|
-
/* @__PURE__ */
|
|
8829
|
-
] }) : /* @__PURE__ */
|
|
8830
|
-
/* @__PURE__ */
|
|
8831
|
-
/* @__PURE__ */
|
|
9073
|
+
busy ? /* @__PURE__ */ jsxs65("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
|
|
9074
|
+
/* @__PURE__ */ jsx70("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
9075
|
+
/* @__PURE__ */ jsx70("span", { children: "Stop" })
|
|
9076
|
+
] }) : /* @__PURE__ */ jsxs65("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
|
|
9077
|
+
/* @__PURE__ */ jsx70("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
|
|
9078
|
+
/* @__PURE__ */ jsx70("span", { className: "fdc-send-label", children: "Send" })
|
|
8832
9079
|
] })
|
|
8833
9080
|
] })
|
|
8834
9081
|
] })
|
|
8835
9082
|
}
|
|
8836
9083
|
),
|
|
8837
|
-
notice ? /* @__PURE__ */
|
|
8838
|
-
/* @__PURE__ */
|
|
9084
|
+
notice ? /* @__PURE__ */ jsxs65("div", { className: "fdc-notice", role: "status", children: [
|
|
9085
|
+
/* @__PURE__ */ jsx70("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
8839
9086
|
notice
|
|
8840
9087
|
] }) : null,
|
|
8841
|
-
hint && !notice ? /* @__PURE__ */
|
|
8842
|
-
/* @__PURE__ */
|
|
9088
|
+
hint && !notice ? /* @__PURE__ */ jsx70("div", { className: "fdc-hint", children: hint }) : null,
|
|
9089
|
+
/* @__PURE__ */ jsx70(
|
|
8843
9090
|
Popover,
|
|
8844
9091
|
{
|
|
8845
9092
|
open: menuOpen,
|
|
@@ -8853,12 +9100,12 @@ function ChatComposer({
|
|
|
8853
9100
|
returnFocus: false,
|
|
8854
9101
|
closeOnOutside: true,
|
|
8855
9102
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
8856
|
-
children: /* @__PURE__ */
|
|
9103
|
+
children: /* @__PURE__ */ jsx70(
|
|
8857
9104
|
Menu,
|
|
8858
9105
|
{
|
|
8859
9106
|
items: menuItems,
|
|
8860
9107
|
autoFocus: false,
|
|
8861
|
-
header: /* @__PURE__ */
|
|
9108
|
+
header: /* @__PURE__ */ jsx70("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
8862
9109
|
onClose: () => setTrigger(null)
|
|
8863
9110
|
}
|
|
8864
9111
|
)
|
|
@@ -8868,12 +9115,12 @@ function ChatComposer({
|
|
|
8868
9115
|
}
|
|
8869
9116
|
|
|
8870
9117
|
// src/components/chat/ChatSessionBar.tsx
|
|
8871
|
-
import * as
|
|
8872
|
-
import { jsx as
|
|
9118
|
+
import * as React40 from "react";
|
|
9119
|
+
import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
8873
9120
|
var compact2 = meterFormats.compact;
|
|
8874
9121
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
8875
|
-
const [open, setOpen] =
|
|
8876
|
-
const anchor =
|
|
9122
|
+
const [open, setOpen] = React40.useState(false);
|
|
9123
|
+
const anchor = React40.useRef(null);
|
|
8877
9124
|
const stats = sessionStats || null;
|
|
8878
9125
|
const cu = contextUsage || null;
|
|
8879
9126
|
const limits = usageLimits || null;
|
|
@@ -8888,9 +9135,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8888
9135
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
8889
9136
|
if (cu) bits.push(pct + "% context");
|
|
8890
9137
|
const expandable = !!(cu || limits);
|
|
8891
|
-
return /* @__PURE__ */
|
|
8892
|
-
/* @__PURE__ */
|
|
8893
|
-
/* @__PURE__ */
|
|
9138
|
+
return /* @__PURE__ */ jsxs66(React40.Fragment, { children: [
|
|
9139
|
+
/* @__PURE__ */ jsxs66("div", { className: "fdc-bar", children: [
|
|
9140
|
+
/* @__PURE__ */ jsxs66(
|
|
8894
9141
|
"button",
|
|
8895
9142
|
{
|
|
8896
9143
|
type: "button",
|
|
@@ -8901,16 +9148,16 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8901
9148
|
"aria-expanded": expandable ? open : void 0,
|
|
8902
9149
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
8903
9150
|
children: [
|
|
8904
|
-
cu ? /* @__PURE__ */
|
|
8905
|
-
/* @__PURE__ */
|
|
8906
|
-
expandable ? /* @__PURE__ */
|
|
9151
|
+
cu ? /* @__PURE__ */ jsx71("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx71(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
|
|
9152
|
+
/* @__PURE__ */ jsx71("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
|
|
9153
|
+
expandable ? /* @__PURE__ */ jsx71("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
|
|
8907
9154
|
]
|
|
8908
9155
|
}
|
|
8909
9156
|
),
|
|
8910
9157
|
extras
|
|
8911
9158
|
] }),
|
|
8912
|
-
/* @__PURE__ */
|
|
8913
|
-
cu ? /* @__PURE__ */
|
|
9159
|
+
/* @__PURE__ */ jsx71(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ jsxs66("div", { className: "fdc-usage", children: [
|
|
9160
|
+
cu ? /* @__PURE__ */ jsx71("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx71(
|
|
8914
9161
|
SegmentedMeter,
|
|
8915
9162
|
{
|
|
8916
9163
|
total,
|
|
@@ -8922,9 +9169,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8922
9169
|
remainderLabel: "Free"
|
|
8923
9170
|
}
|
|
8924
9171
|
) }) : null,
|
|
8925
|
-
limits && limits.length ? /* @__PURE__ */
|
|
8926
|
-
/* @__PURE__ */
|
|
8927
|
-
/* @__PURE__ */
|
|
9172
|
+
limits && limits.length ? /* @__PURE__ */ jsxs66("section", { className: "fdc-usage-sec", children: [
|
|
9173
|
+
/* @__PURE__ */ jsx71("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
9174
|
+
/* @__PURE__ */ jsx71("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx71(
|
|
8928
9175
|
QuotaRow,
|
|
8929
9176
|
{
|
|
8930
9177
|
label: l.label,
|
|
@@ -8934,32 +9181,32 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8934
9181
|
l.id
|
|
8935
9182
|
)) })
|
|
8936
9183
|
] }) : null,
|
|
8937
|
-
stats ? /* @__PURE__ */
|
|
8938
|
-
stats.elapsedMs ? /* @__PURE__ */
|
|
8939
|
-
/* @__PURE__ */
|
|
8940
|
-
/* @__PURE__ */
|
|
9184
|
+
stats ? /* @__PURE__ */ jsxs66("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
9185
|
+
stats.elapsedMs ? /* @__PURE__ */ jsxs66("div", { children: [
|
|
9186
|
+
/* @__PURE__ */ jsx71("span", { children: "Session" }),
|
|
9187
|
+
/* @__PURE__ */ jsx71("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
8941
9188
|
] }) : null,
|
|
8942
|
-
stats.tokens ? /* @__PURE__ */
|
|
8943
|
-
/* @__PURE__ */
|
|
8944
|
-
/* @__PURE__ */
|
|
9189
|
+
stats.tokens ? /* @__PURE__ */ jsxs66("div", { children: [
|
|
9190
|
+
/* @__PURE__ */ jsx71("span", { children: "Tokens" }),
|
|
9191
|
+
/* @__PURE__ */ jsx71("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
8945
9192
|
] }) : null,
|
|
8946
|
-
stats.costUsd != null ? /* @__PURE__ */
|
|
8947
|
-
/* @__PURE__ */
|
|
8948
|
-
/* @__PURE__ */
|
|
9193
|
+
stats.costUsd != null ? /* @__PURE__ */ jsxs66("div", { children: [
|
|
9194
|
+
/* @__PURE__ */ jsx71("span", { children: "Cost" }),
|
|
9195
|
+
/* @__PURE__ */ jsxs66("b", { className: "fd-tabular", children: [
|
|
8949
9196
|
"$",
|
|
8950
9197
|
Number(stats.costUsd).toFixed(3)
|
|
8951
9198
|
] })
|
|
8952
9199
|
] }) : null,
|
|
8953
|
-
stats.turns ? /* @__PURE__ */
|
|
8954
|
-
/* @__PURE__ */
|
|
8955
|
-
/* @__PURE__ */
|
|
9200
|
+
stats.turns ? /* @__PURE__ */ jsxs66("div", { children: [
|
|
9201
|
+
/* @__PURE__ */ jsx71("span", { children: "Turns" }),
|
|
9202
|
+
/* @__PURE__ */ jsx71("b", { className: "fd-tabular", children: stats.turns })
|
|
8956
9203
|
] }) : null
|
|
8957
9204
|
] }) : null,
|
|
8958
|
-
onClear ? /* @__PURE__ */
|
|
9205
|
+
onClear ? /* @__PURE__ */ jsx71("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
8959
9206
|
setOpen(false);
|
|
8960
9207
|
onClear();
|
|
8961
9208
|
}, children: [
|
|
8962
|
-
/* @__PURE__ */
|
|
9209
|
+
/* @__PURE__ */ jsx71("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
8963
9210
|
"Clear conversation"
|
|
8964
9211
|
] }) }) : null
|
|
8965
9212
|
] }) })
|
|
@@ -8996,7 +9243,7 @@ function ModelControls({
|
|
|
8996
9243
|
disabled: m.disabled,
|
|
8997
9244
|
checked: m.id === (current2 && current2.id),
|
|
8998
9245
|
meta: m.meta,
|
|
8999
|
-
shortcut: m.shortcut ? /* @__PURE__ */
|
|
9246
|
+
shortcut: m.shortcut ? /* @__PURE__ */ jsx71(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
9000
9247
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
9001
9248
|
});
|
|
9002
9249
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -9009,15 +9256,15 @@ function ModelControls({
|
|
|
9009
9256
|
items.push({ kind: "section", label: "Fast mode" });
|
|
9010
9257
|
items.push({
|
|
9011
9258
|
kind: "custom",
|
|
9012
|
-
render: () => /* @__PURE__ */
|
|
9013
|
-
/* @__PURE__ */
|
|
9014
|
-
/* @__PURE__ */
|
|
9015
|
-
/* @__PURE__ */
|
|
9259
|
+
render: () => /* @__PURE__ */ jsxs66("label", { className: "fdc-switchrow", children: [
|
|
9260
|
+
/* @__PURE__ */ jsx71("span", { children: fastModeLabel }),
|
|
9261
|
+
/* @__PURE__ */ jsx71("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
|
|
9262
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx71("span", { className: "fd-switch-thumb" }) })
|
|
9016
9263
|
] })
|
|
9017
9264
|
});
|
|
9018
9265
|
}
|
|
9019
|
-
return /* @__PURE__ */
|
|
9020
|
-
/* @__PURE__ */
|
|
9266
|
+
return /* @__PURE__ */ jsxs66(React40.Fragment, { children: [
|
|
9267
|
+
/* @__PURE__ */ jsx71(
|
|
9021
9268
|
MenuButton,
|
|
9022
9269
|
{
|
|
9023
9270
|
items,
|
|
@@ -9028,7 +9275,7 @@ function ModelControls({
|
|
|
9028
9275
|
title: "Choose a model"
|
|
9029
9276
|
}
|
|
9030
9277
|
),
|
|
9031
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */
|
|
9278
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ jsx71(
|
|
9032
9279
|
MenuButton,
|
|
9033
9280
|
{
|
|
9034
9281
|
placement: "top-end",
|
|
@@ -9049,7 +9296,7 @@ function ModelControls({
|
|
|
9049
9296
|
}
|
|
9050
9297
|
|
|
9051
9298
|
// src/components/chat/AgentChatPanel.tsx
|
|
9052
|
-
import { jsx as
|
|
9299
|
+
import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
9053
9300
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
9054
9301
|
function AgentChatPanel({
|
|
9055
9302
|
/* required */
|
|
@@ -9133,11 +9380,11 @@ function AgentChatPanel({
|
|
|
9133
9380
|
onFeedback,
|
|
9134
9381
|
onEditMessage
|
|
9135
9382
|
}) {
|
|
9136
|
-
const [panelWidth, setPanelWidth] =
|
|
9137
|
-
const [applied, setApplied] =
|
|
9138
|
-
const [draft, setDraft] =
|
|
9139
|
-
const dragging =
|
|
9140
|
-
|
|
9383
|
+
const [panelWidth, setPanelWidth] = React41.useState(width);
|
|
9384
|
+
const [applied, setApplied] = React41.useState({});
|
|
9385
|
+
const [draft, setDraft] = React41.useState("");
|
|
9386
|
+
const dragging = React41.useRef(null);
|
|
9387
|
+
React41.useEffect(() => setPanelWidth(width), [width]);
|
|
9141
9388
|
const engine = useChatEngine({
|
|
9142
9389
|
contextType,
|
|
9143
9390
|
contextId,
|
|
@@ -9203,7 +9450,7 @@ function AgentChatPanel({
|
|
|
9203
9450
|
onReconnect: engine.reload,
|
|
9204
9451
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
9205
9452
|
};
|
|
9206
|
-
const sessionBar = /* @__PURE__ */
|
|
9453
|
+
const sessionBar = /* @__PURE__ */ jsx72(
|
|
9207
9454
|
ChatSessionBar,
|
|
9208
9455
|
{
|
|
9209
9456
|
sessionStats,
|
|
@@ -9212,7 +9459,7 @@ function AgentChatPanel({
|
|
|
9212
9459
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
9213
9460
|
}
|
|
9214
9461
|
);
|
|
9215
|
-
const modelControls = /* @__PURE__ */
|
|
9462
|
+
const modelControls = /* @__PURE__ */ jsx72(
|
|
9216
9463
|
ModelControls,
|
|
9217
9464
|
{
|
|
9218
9465
|
models,
|
|
@@ -9227,7 +9474,7 @@ function AgentChatPanel({
|
|
|
9227
9474
|
narrow
|
|
9228
9475
|
}
|
|
9229
9476
|
);
|
|
9230
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */
|
|
9477
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx72(
|
|
9231
9478
|
MenuButton,
|
|
9232
9479
|
{
|
|
9233
9480
|
variant: "ghost",
|
|
@@ -9254,7 +9501,7 @@ function AgentChatPanel({
|
|
|
9254
9501
|
})))
|
|
9255
9502
|
}
|
|
9256
9503
|
) : null;
|
|
9257
|
-
return /* @__PURE__ */
|
|
9504
|
+
return /* @__PURE__ */ jsxs67(
|
|
9258
9505
|
"aside",
|
|
9259
9506
|
{
|
|
9260
9507
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -9265,7 +9512,7 @@ function AgentChatPanel({
|
|
|
9265
9512
|
},
|
|
9266
9513
|
"aria-label": title,
|
|
9267
9514
|
children: [
|
|
9268
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */
|
|
9515
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ jsx72(
|
|
9269
9516
|
"div",
|
|
9270
9517
|
{
|
|
9271
9518
|
className: "fdc-grip",
|
|
@@ -9280,20 +9527,20 @@ function AgentChatPanel({
|
|
|
9280
9527
|
}
|
|
9281
9528
|
}
|
|
9282
9529
|
) : null,
|
|
9283
|
-
showHeader ? /* @__PURE__ */
|
|
9284
|
-
/* @__PURE__ */
|
|
9285
|
-
/* @__PURE__ */
|
|
9286
|
-
/* @__PURE__ */
|
|
9287
|
-
subtitle ? /* @__PURE__ */
|
|
9530
|
+
showHeader ? /* @__PURE__ */ jsxs67("header", { className: "fdc-head", children: [
|
|
9531
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-" + assistantIcon }) }),
|
|
9532
|
+
/* @__PURE__ */ jsxs67("span", { className: "fdc-head-titles", children: [
|
|
9533
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-head-title", children: title }),
|
|
9534
|
+
subtitle ? /* @__PURE__ */ jsx72("span", { className: "fdc-head-sub", children: subtitle }) : null
|
|
9288
9535
|
] }),
|
|
9289
|
-
/* @__PURE__ */
|
|
9536
|
+
/* @__PURE__ */ jsxs67("span", { className: "fdc-head-acts", children: [
|
|
9290
9537
|
headerActions,
|
|
9291
9538
|
threadMenu,
|
|
9292
|
-
onNewThread ? /* @__PURE__ */
|
|
9293
|
-
onClose ? /* @__PURE__ */
|
|
9539
|
+
onNewThread ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
|
|
9540
|
+
onClose ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
9294
9541
|
] })
|
|
9295
9542
|
] }) : null,
|
|
9296
|
-
/* @__PURE__ */
|
|
9543
|
+
/* @__PURE__ */ jsx72(
|
|
9297
9544
|
ChatTranscript,
|
|
9298
9545
|
{
|
|
9299
9546
|
messages: engine.visible,
|
|
@@ -9308,7 +9555,7 @@ function AgentChatPanel({
|
|
|
9308
9555
|
renderEmpty
|
|
9309
9556
|
}
|
|
9310
9557
|
),
|
|
9311
|
-
/* @__PURE__ */
|
|
9558
|
+
/* @__PURE__ */ jsx72(
|
|
9312
9559
|
ChatComposer,
|
|
9313
9560
|
{
|
|
9314
9561
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -9341,7 +9588,7 @@ function AgentChatPanel({
|
|
|
9341
9588
|
}
|
|
9342
9589
|
|
|
9343
9590
|
// src/kits/query.ts
|
|
9344
|
-
import * as
|
|
9591
|
+
import * as React42 from "react";
|
|
9345
9592
|
function eqFilter(get2) {
|
|
9346
9593
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
9347
9594
|
}
|
|
@@ -9373,22 +9620,22 @@ function compare(a, b, dir) {
|
|
|
9373
9620
|
var API = null;
|
|
9374
9621
|
var PREFS = null;
|
|
9375
9622
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
9376
|
-
const [query, setQuery] =
|
|
9623
|
+
const [query, setQuery] = React42.useState(() => {
|
|
9377
9624
|
const store = PREFS || window.PlannerPrefs;
|
|
9378
9625
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
9379
9626
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
9380
9627
|
});
|
|
9381
|
-
const savePref =
|
|
9628
|
+
const savePref = React42.useCallback((patch2) => {
|
|
9382
9629
|
const store = PREFS || window.PlannerPrefs;
|
|
9383
9630
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
9384
9631
|
}, [prefsKey]);
|
|
9385
|
-
const [res, setRes] =
|
|
9386
|
-
const [loading, setLoading] =
|
|
9387
|
-
const seq2 =
|
|
9632
|
+
const [res, setRes] = React42.useState(null);
|
|
9633
|
+
const [loading, setLoading] = React42.useState(true);
|
|
9634
|
+
const seq2 = React42.useRef(0);
|
|
9388
9635
|
const depKey = (deps || []).join("|");
|
|
9389
9636
|
const paramKey = JSON.stringify(params || {});
|
|
9390
9637
|
const queryKey = JSON.stringify(query);
|
|
9391
|
-
|
|
9638
|
+
React42.useEffect(() => {
|
|
9392
9639
|
const id = ++seq2.current;
|
|
9393
9640
|
setLoading(true);
|
|
9394
9641
|
const t = setTimeout(() => {
|
|
@@ -9726,6 +9973,7 @@ export {
|
|
|
9726
9973
|
Dropzone,
|
|
9727
9974
|
DropzoneKit,
|
|
9728
9975
|
EmptyState,
|
|
9976
|
+
EntityRow,
|
|
9729
9977
|
FeatureGate,
|
|
9730
9978
|
FileChip,
|
|
9731
9979
|
FileGrid,
|
|
@@ -9798,11 +10046,16 @@ export {
|
|
|
9798
10046
|
Tooltip,
|
|
9799
10047
|
Topbar,
|
|
9800
10048
|
TranscriptKit,
|
|
10049
|
+
TransferList,
|
|
9801
10050
|
UseFeatureStatus,
|
|
9802
10051
|
UseRuntimeMode,
|
|
10052
|
+
VIRTUAL_LIST_BUFFER_ROWS,
|
|
10053
|
+
VirtualList,
|
|
9803
10054
|
acceptMatches,
|
|
9804
10055
|
anyOfFilter,
|
|
9805
10056
|
channelWeightOf,
|
|
10057
|
+
computeNeedMore,
|
|
10058
|
+
computeVirtualWindow,
|
|
9806
10059
|
createVersionStore,
|
|
9807
10060
|
eqFilter,
|
|
9808
10061
|
extensionOf,
|