@flytedan/flytebot-design-system 0.6.1 → 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 +1285 -1033
- 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 +1279 -1033
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2428,56 +2428,140 @@ function StepList({
|
|
|
2428
2428
|
] });
|
|
2429
2429
|
}
|
|
2430
2430
|
|
|
2431
|
-
// src/components/
|
|
2431
|
+
// src/components/data/VirtualList.tsx
|
|
2432
2432
|
import * as React15 from "react";
|
|
2433
2433
|
import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2434
|
-
|
|
2435
|
-
|
|
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;
|
|
2436
2484
|
React15.useEffect(() => {
|
|
2437
|
-
if (
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
] })
|
|
2448
|
-
|
|
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
|
+
);
|
|
2449
2517
|
}
|
|
2450
2518
|
|
|
2451
|
-
// src/components/
|
|
2519
|
+
// src/components/data/EntityRow.tsx
|
|
2452
2520
|
import { jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2453
|
-
function
|
|
2454
|
-
return /* @__PURE__ */ jsxs34(
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
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
|
+
);
|
|
2464
2558
|
}
|
|
2465
2559
|
|
|
2466
|
-
// src/components/
|
|
2467
|
-
import
|
|
2468
|
-
function Switch({ label, description, className = "", ...rest }) {
|
|
2469
|
-
return /* @__PURE__ */ jsxs35("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
|
|
2470
|
-
/* @__PURE__ */ jsx39("input", { type: "checkbox", role: "switch", ...rest }),
|
|
2471
|
-
/* @__PURE__ */ jsx39("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx39("span", { className: "fd-switch-thumb" }) }),
|
|
2472
|
-
label ? /* @__PURE__ */ jsxs35("span", { className: "fd-choice-text", children: [
|
|
2473
|
-
/* @__PURE__ */ jsx39("span", { className: "fd-switch-label", children: label }),
|
|
2474
|
-
description ? /* @__PURE__ */ jsx39("span", { className: "fd-choice-desc", children: description }) : null
|
|
2475
|
-
] }) : null
|
|
2476
|
-
] });
|
|
2477
|
-
}
|
|
2560
|
+
// src/components/data/TransferList.tsx
|
|
2561
|
+
import * as React16 from "react";
|
|
2478
2562
|
|
|
2479
2563
|
// src/components/forms/Input.tsx
|
|
2480
|
-
import { jsx as
|
|
2564
|
+
import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2481
2565
|
function Input({
|
|
2482
2566
|
label,
|
|
2483
2567
|
help,
|
|
@@ -2505,27 +2589,27 @@ function Input({
|
|
|
2505
2589
|
size === "lg" ? "fd-input-lg" : "",
|
|
2506
2590
|
className
|
|
2507
2591
|
].filter(Boolean).join(" ");
|
|
2508
|
-
return /* @__PURE__ */
|
|
2509
|
-
label ? /* @__PURE__ */
|
|
2592
|
+
return /* @__PURE__ */ jsxs35("div", { className: "fd-field", style, children: [
|
|
2593
|
+
label ? /* @__PURE__ */ jsxs35("label", { className: "fd-field-label", htmlFor: fieldId, children: [
|
|
2510
2594
|
label,
|
|
2511
|
-
required ? /* @__PURE__ */
|
|
2595
|
+
required ? /* @__PURE__ */ jsx39("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
|
|
2512
2596
|
] }) : null,
|
|
2513
|
-
/* @__PURE__ */
|
|
2514
|
-
icon ? /* @__PURE__ */
|
|
2515
|
-
prefix ? /* @__PURE__ */
|
|
2516
|
-
/* @__PURE__ */
|
|
2517
|
-
loading ? /* @__PURE__ */
|
|
2518
|
-
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
|
|
2519
2603
|
] }),
|
|
2520
|
-
error ? /* @__PURE__ */
|
|
2521
|
-
/* @__PURE__ */
|
|
2604
|
+
error ? /* @__PURE__ */ jsxs35("span", { className: "fd-field-error", children: [
|
|
2605
|
+
/* @__PURE__ */ jsx39("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2522
2606
|
error
|
|
2523
|
-
] }) : help ? /* @__PURE__ */
|
|
2607
|
+
] }) : help ? /* @__PURE__ */ jsx39("span", { className: "fd-field-help", children: help }) : null
|
|
2524
2608
|
] });
|
|
2525
2609
|
}
|
|
2526
2610
|
|
|
2527
2611
|
// src/components/forms/SearchField.tsx
|
|
2528
|
-
import { jsx as
|
|
2612
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
2529
2613
|
function SearchField({
|
|
2530
2614
|
value,
|
|
2531
2615
|
onChange,
|
|
@@ -2540,7 +2624,7 @@ function SearchField({
|
|
|
2540
2624
|
...rest
|
|
2541
2625
|
}) {
|
|
2542
2626
|
const clear = onClear || (() => onChange(""));
|
|
2543
|
-
return /* @__PURE__ */
|
|
2627
|
+
return /* @__PURE__ */ jsx40(
|
|
2544
2628
|
Input,
|
|
2545
2629
|
{
|
|
2546
2630
|
id,
|
|
@@ -2553,14 +2637,14 @@ function SearchField({
|
|
|
2553
2637
|
style,
|
|
2554
2638
|
className,
|
|
2555
2639
|
onChange: (e) => onChange(e.target.value),
|
|
2556
|
-
suffix: value ? /* @__PURE__ */
|
|
2640
|
+
suffix: value ? /* @__PURE__ */ jsx40(
|
|
2557
2641
|
"button",
|
|
2558
2642
|
{
|
|
2559
2643
|
type: "button",
|
|
2560
2644
|
"aria-label": "Clear search",
|
|
2561
2645
|
onClick: clear,
|
|
2562
2646
|
style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
|
|
2563
|
-
children: /* @__PURE__ */
|
|
2647
|
+
children: /* @__PURE__ */ jsx40("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
|
|
2564
2648
|
}
|
|
2565
2649
|
) : void 0,
|
|
2566
2650
|
...rest
|
|
@@ -2568,27 +2652,183 @@ function SearchField({
|
|
|
2568
2652
|
);
|
|
2569
2653
|
}
|
|
2570
2654
|
|
|
2571
|
-
// 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";
|
|
2572
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";
|
|
2573
2813
|
function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
|
|
2574
2814
|
const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
|
|
2575
2815
|
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : "", className].filter(Boolean).join(" ");
|
|
2576
|
-
return /* @__PURE__ */
|
|
2577
|
-
label ? /* @__PURE__ */
|
|
2816
|
+
return /* @__PURE__ */ jsxs40("div", { className: "fd-field", style, children: [
|
|
2817
|
+
label ? /* @__PURE__ */ jsxs40("label", { className: "fd-field-label", htmlFor: fieldId, children: [
|
|
2578
2818
|
label,
|
|
2579
|
-
required ? /* @__PURE__ */
|
|
2819
|
+
required ? /* @__PURE__ */ jsx45("span", { className: "fd-field-req", children: "*" }) : null
|
|
2580
2820
|
] }) : null,
|
|
2581
|
-
/* @__PURE__ */
|
|
2582
|
-
error ? /* @__PURE__ */
|
|
2583
|
-
/* @__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" }),
|
|
2584
2824
|
error
|
|
2585
|
-
] }) : help ? /* @__PURE__ */
|
|
2825
|
+
] }) : help ? /* @__PURE__ */ jsx45("span", { className: "fd-field-help", children: help }) : null
|
|
2586
2826
|
] });
|
|
2587
2827
|
}
|
|
2588
2828
|
|
|
2589
2829
|
// src/components/forms/NumberInput.tsx
|
|
2590
|
-
import * as
|
|
2591
|
-
import { jsx as
|
|
2830
|
+
import * as React18 from "react";
|
|
2831
|
+
import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
2592
2832
|
function NumberInput({
|
|
2593
2833
|
label,
|
|
2594
2834
|
help,
|
|
@@ -2612,10 +2852,10 @@ function NumberInput({
|
|
|
2612
2852
|
const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
|
|
2613
2853
|
return isNaN(n) ? null : n;
|
|
2614
2854
|
};
|
|
2615
|
-
const [text, setText] =
|
|
2616
|
-
const [editing, setEditing] =
|
|
2617
|
-
const timer =
|
|
2618
|
-
|
|
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(() => {
|
|
2619
2859
|
if (!editing) setText(value == null || value === "" ? "" : String(value));
|
|
2620
2860
|
}, [value, editing]);
|
|
2621
2861
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
@@ -2639,7 +2879,7 @@ function NumberInput({
|
|
|
2639
2879
|
const release = () => {
|
|
2640
2880
|
if (timer.current) clearTimeout(timer.current);
|
|
2641
2881
|
};
|
|
2642
|
-
|
|
2882
|
+
React18.useEffect(() => () => {
|
|
2643
2883
|
if (timer.current) clearTimeout(timer.current);
|
|
2644
2884
|
}, []);
|
|
2645
2885
|
const shown = editing ? text : (() => {
|
|
@@ -2647,14 +2887,14 @@ function NumberInput({
|
|
|
2647
2887
|
return n == null ? "" : format ? n.toLocaleString() : String(n);
|
|
2648
2888
|
})();
|
|
2649
2889
|
const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
2650
|
-
return /* @__PURE__ */
|
|
2651
|
-
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: [
|
|
2652
2892
|
label,
|
|
2653
|
-
required ? /* @__PURE__ */
|
|
2893
|
+
required ? /* @__PURE__ */ jsx46("span", { className: "fd-field-req", children: "*" }) : null
|
|
2654
2894
|
] }) : null,
|
|
2655
|
-
/* @__PURE__ */
|
|
2656
|
-
prefix ? /* @__PURE__ */
|
|
2657
|
-
/* @__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(
|
|
2658
2898
|
"input",
|
|
2659
2899
|
{
|
|
2660
2900
|
inputMode: "numeric",
|
|
@@ -2687,9 +2927,9 @@ function NumberInput({
|
|
|
2687
2927
|
}
|
|
2688
2928
|
}
|
|
2689
2929
|
),
|
|
2690
|
-
suffix ? /* @__PURE__ */
|
|
2691
|
-
/* @__PURE__ */
|
|
2692
|
-
/* @__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(
|
|
2693
2933
|
"button",
|
|
2694
2934
|
{
|
|
2695
2935
|
type: "button",
|
|
@@ -2699,10 +2939,10 @@ function NumberInput({
|
|
|
2699
2939
|
onPointerDown: () => hold(-1),
|
|
2700
2940
|
onPointerUp: release,
|
|
2701
2941
|
onPointerLeave: release,
|
|
2702
|
-
children: /* @__PURE__ */
|
|
2942
|
+
children: /* @__PURE__ */ jsx46("i", { className: "ph ph-minus" })
|
|
2703
2943
|
}
|
|
2704
2944
|
),
|
|
2705
|
-
/* @__PURE__ */
|
|
2945
|
+
/* @__PURE__ */ jsx46(
|
|
2706
2946
|
"button",
|
|
2707
2947
|
{
|
|
2708
2948
|
type: "button",
|
|
@@ -2712,26 +2952,26 @@ function NumberInput({
|
|
|
2712
2952
|
onPointerDown: () => hold(1),
|
|
2713
2953
|
onPointerUp: release,
|
|
2714
2954
|
onPointerLeave: release,
|
|
2715
|
-
children: /* @__PURE__ */
|
|
2955
|
+
children: /* @__PURE__ */ jsx46("i", { className: "ph ph-plus" })
|
|
2716
2956
|
}
|
|
2717
2957
|
)
|
|
2718
2958
|
] })
|
|
2719
2959
|
] }),
|
|
2720
|
-
error ? /* @__PURE__ */
|
|
2721
|
-
/* @__PURE__ */
|
|
2960
|
+
error ? /* @__PURE__ */ jsxs41("span", { className: "fd-field-error", children: [
|
|
2961
|
+
/* @__PURE__ */ jsx46("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2722
2962
|
error
|
|
2723
|
-
] }) : help ? /* @__PURE__ */
|
|
2963
|
+
] }) : help ? /* @__PURE__ */ jsx46("span", { className: "fd-field-help", children: help }) : null
|
|
2724
2964
|
] });
|
|
2725
2965
|
}
|
|
2726
2966
|
|
|
2727
2967
|
// src/components/forms/Select.tsx
|
|
2728
|
-
import * as
|
|
2968
|
+
import * as React19 from "react";
|
|
2729
2969
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2730
|
-
import { jsx as
|
|
2970
|
+
import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
2731
2971
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
2732
2972
|
function usePopPos(open, ref, estH, estW) {
|
|
2733
|
-
const [pos, setPos] =
|
|
2734
|
-
|
|
2973
|
+
const [pos, setPos] = React19.useState(null);
|
|
2974
|
+
React19.useLayoutEffect(() => {
|
|
2735
2975
|
if (!open || !ref.current) {
|
|
2736
2976
|
setPos(null);
|
|
2737
2977
|
return;
|
|
@@ -2795,14 +3035,14 @@ function Select({
|
|
|
2795
3035
|
const vals = multiple ? Array.isArray(value) ? value : value ? [value] : [] : [];
|
|
2796
3036
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
2797
3037
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
2798
|
-
const [open, setOpen] =
|
|
2799
|
-
const [q, setQ] =
|
|
2800
|
-
const [active, setActive] =
|
|
2801
|
-
const rootRef =
|
|
2802
|
-
const boxRef =
|
|
2803
|
-
const popRef =
|
|
2804
|
-
const listRef =
|
|
2805
|
-
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 });
|
|
2806
3046
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
2807
3047
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
2808
3048
|
const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
|
|
@@ -2828,7 +3068,7 @@ function Select({
|
|
|
2828
3068
|
}
|
|
2829
3069
|
setOpen(!open);
|
|
2830
3070
|
};
|
|
2831
|
-
|
|
3071
|
+
React19.useEffect(() => {
|
|
2832
3072
|
if (!open) return;
|
|
2833
3073
|
const away = (e) => {
|
|
2834
3074
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -2838,7 +3078,7 @@ function Select({
|
|
|
2838
3078
|
document.addEventListener("pointerdown", away);
|
|
2839
3079
|
return () => document.removeEventListener("pointerdown", away);
|
|
2840
3080
|
}, [open]);
|
|
2841
|
-
|
|
3081
|
+
React19.useEffect(() => {
|
|
2842
3082
|
if (!open || active < 0 || !listRef.current) return;
|
|
2843
3083
|
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
2844
3084
|
if (el) {
|
|
@@ -2892,13 +3132,13 @@ function Select({
|
|
|
2892
3132
|
});
|
|
2893
3133
|
const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
|
|
2894
3134
|
const box = ["fd-input", "fd-select", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
2895
|
-
return /* @__PURE__ */
|
|
2896
|
-
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: [
|
|
2897
3137
|
label,
|
|
2898
|
-
required ? /* @__PURE__ */
|
|
3138
|
+
required ? /* @__PURE__ */ jsx47("span", { className: "fd-field-req", children: "*" }) : null
|
|
2899
3139
|
] }) : null,
|
|
2900
|
-
/* @__PURE__ */
|
|
2901
|
-
/* @__PURE__ */
|
|
3140
|
+
/* @__PURE__ */ jsxs42("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
|
|
3141
|
+
/* @__PURE__ */ jsxs42(
|
|
2902
3142
|
"button",
|
|
2903
3143
|
{
|
|
2904
3144
|
type: "button",
|
|
@@ -2911,13 +3151,13 @@ function Select({
|
|
|
2911
3151
|
"aria-haspopup": "listbox",
|
|
2912
3152
|
style: { all: "unset", flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8, cursor: "inherit", overflow: "hidden" },
|
|
2913
3153
|
children: [
|
|
2914
|
-
selected && selected.icon ? /* @__PURE__ */
|
|
2915
|
-
/* @__PURE__ */
|
|
2916
|
-
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
|
|
2917
3157
|
]
|
|
2918
3158
|
}
|
|
2919
3159
|
),
|
|
2920
|
-
clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */
|
|
3160
|
+
clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx47(
|
|
2921
3161
|
"button",
|
|
2922
3162
|
{
|
|
2923
3163
|
type: "button",
|
|
@@ -2927,22 +3167,22 @@ function Select({
|
|
|
2927
3167
|
fire(multiple ? [] : "");
|
|
2928
3168
|
},
|
|
2929
3169
|
style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
|
|
2930
|
-
children: /* @__PURE__ */
|
|
3170
|
+
children: /* @__PURE__ */ jsx47("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
|
|
2931
3171
|
}
|
|
2932
3172
|
) : null,
|
|
2933
|
-
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" }) })
|
|
2934
3174
|
] }),
|
|
2935
3175
|
open && pos ? createPortal4(
|
|
2936
|
-
/* @__PURE__ */
|
|
3176
|
+
/* @__PURE__ */ jsxs42(
|
|
2937
3177
|
"div",
|
|
2938
3178
|
{
|
|
2939
3179
|
className: "fd-pop" + (pos.up ? " is-up" : ""),
|
|
2940
3180
|
ref: popRef,
|
|
2941
3181
|
style: popStyle(pos, { minWidth: Math.max(pos.width, 260), maxWidth: 380, zIndex: 130, overflowY: "hidden" }),
|
|
2942
3182
|
children: [
|
|
2943
|
-
hasSearch ? /* @__PURE__ */
|
|
2944
|
-
/* @__PURE__ */
|
|
2945
|
-
/* @__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(
|
|
2946
3186
|
"input",
|
|
2947
3187
|
{
|
|
2948
3188
|
autoFocus: true,
|
|
@@ -2955,15 +3195,15 @@ function Select({
|
|
|
2955
3195
|
}
|
|
2956
3196
|
}
|
|
2957
3197
|
),
|
|
2958
|
-
q ? /* @__PURE__ */
|
|
3198
|
+
q ? /* @__PURE__ */ jsx47("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
2959
3199
|
] }) : null,
|
|
2960
|
-
/* @__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: [
|
|
2961
3201
|
'Nothing matches "',
|
|
2962
3202
|
q,
|
|
2963
3203
|
'".'
|
|
2964
|
-
] }) : groups.map((grp) => /* @__PURE__ */
|
|
2965
|
-
grp.g ? /* @__PURE__ */
|
|
2966
|
-
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(
|
|
2967
3207
|
"button",
|
|
2968
3208
|
{
|
|
2969
3209
|
type: "button",
|
|
@@ -2975,21 +3215,21 @@ function Select({
|
|
|
2975
3215
|
onMouseEnter: () => setActive(i),
|
|
2976
3216
|
onClick: () => pick(o),
|
|
2977
3217
|
children: [
|
|
2978
|
-
multiple ? /* @__PURE__ */
|
|
2979
|
-
o.icon ? /* @__PURE__ */
|
|
2980
|
-
/* @__PURE__ */
|
|
2981
|
-
/* @__PURE__ */
|
|
2982
|
-
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
|
|
2983
3223
|
] }),
|
|
2984
|
-
o.meta ? /* @__PURE__ */
|
|
2985
|
-
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 })
|
|
2986
3226
|
]
|
|
2987
3227
|
},
|
|
2988
3228
|
String(o.value)
|
|
2989
3229
|
))
|
|
2990
3230
|
] }, grp.g || "_")) }),
|
|
2991
|
-
multiple ? /* @__PURE__ */
|
|
2992
|
-
/* @__PURE__ */
|
|
3231
|
+
multiple ? /* @__PURE__ */ jsxs42("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
|
|
3232
|
+
/* @__PURE__ */ jsx47(
|
|
2993
3233
|
"button",
|
|
2994
3234
|
{
|
|
2995
3235
|
type: "button",
|
|
@@ -2998,13 +3238,13 @@ function Select({
|
|
|
2998
3238
|
children: "Select all"
|
|
2999
3239
|
}
|
|
3000
3240
|
),
|
|
3001
|
-
/* @__PURE__ */
|
|
3002
|
-
/* @__PURE__ */
|
|
3241
|
+
/* @__PURE__ */ jsx47("span", { style: { flex: 1 } }),
|
|
3242
|
+
/* @__PURE__ */ jsxs42("span", { className: "fd-body-sm fd-muted", children: [
|
|
3003
3243
|
vals.length,
|
|
3004
3244
|
" of ",
|
|
3005
3245
|
opts.length
|
|
3006
3246
|
] }),
|
|
3007
|
-
/* @__PURE__ */
|
|
3247
|
+
/* @__PURE__ */ jsx47(
|
|
3008
3248
|
"button",
|
|
3009
3249
|
{
|
|
3010
3250
|
type: "button",
|
|
@@ -3020,17 +3260,17 @@ function Select({
|
|
|
3020
3260
|
),
|
|
3021
3261
|
document.body
|
|
3022
3262
|
) : null,
|
|
3023
|
-
error ? /* @__PURE__ */
|
|
3024
|
-
/* @__PURE__ */
|
|
3263
|
+
error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
|
|
3264
|
+
/* @__PURE__ */ jsx47("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3025
3265
|
error
|
|
3026
|
-
] }) : help ? /* @__PURE__ */
|
|
3266
|
+
] }) : help ? /* @__PURE__ */ jsx47("span", { className: "fd-field-help", children: help }) : null
|
|
3027
3267
|
] });
|
|
3028
3268
|
}
|
|
3029
3269
|
|
|
3030
3270
|
// src/components/forms/DatePicker.tsx
|
|
3031
|
-
import * as
|
|
3271
|
+
import * as React20 from "react";
|
|
3032
3272
|
import { createPortal as createPortal5 } from "react-dom";
|
|
3033
|
-
import { jsx as
|
|
3273
|
+
import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3034
3274
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3035
3275
|
var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
3036
3276
|
var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
|
|
@@ -3044,8 +3284,8 @@ var fmt = (s) => {
|
|
|
3044
3284
|
return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
|
|
3045
3285
|
};
|
|
3046
3286
|
function usePopPos2(open, ref, estH, estW) {
|
|
3047
|
-
const [pos, setPos] =
|
|
3048
|
-
|
|
3287
|
+
const [pos, setPos] = React20.useState(null);
|
|
3288
|
+
React20.useLayoutEffect(() => {
|
|
3049
3289
|
if (!open || !ref.current) {
|
|
3050
3290
|
setPos(null);
|
|
3051
3291
|
return;
|
|
@@ -3089,10 +3329,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3089
3329
|
const today = /* @__PURE__ */ new Date();
|
|
3090
3330
|
const sel = range ? value || {} : { start: value, end: value };
|
|
3091
3331
|
const anchor = parse(sel.start) || parse(initialMonth) || today;
|
|
3092
|
-
const [vy, setVy] =
|
|
3093
|
-
const [vm, setVm] =
|
|
3094
|
-
const [mode2, setMode] =
|
|
3095
|
-
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);
|
|
3096
3336
|
const s = parse(sel.start), e = parse(sel.end);
|
|
3097
3337
|
const hoverEnd = range && s && !e && hover ? parse(hover) : null;
|
|
3098
3338
|
const inRange = (d) => {
|
|
@@ -3129,9 +3369,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3129
3369
|
const startPad = new Date(y, m, 1).getDay();
|
|
3130
3370
|
const cells = [];
|
|
3131
3371
|
for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
|
|
3132
|
-
return /* @__PURE__ */
|
|
3133
|
-
DOW.map((d) => /* @__PURE__ */
|
|
3134
|
-
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(
|
|
3135
3375
|
"button",
|
|
3136
3376
|
{
|
|
3137
3377
|
type: "button",
|
|
@@ -3145,20 +3385,20 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3145
3385
|
] });
|
|
3146
3386
|
};
|
|
3147
3387
|
const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
|
|
3148
|
-
return /* @__PURE__ */
|
|
3149
|
-
/* @__PURE__ */
|
|
3150
|
-
/* @__PURE__ */
|
|
3151
|
-
/* @__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: [
|
|
3152
3392
|
mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
|
|
3153
|
-
/* @__PURE__ */
|
|
3393
|
+
/* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
|
|
3154
3394
|
] }),
|
|
3155
|
-
months > 1 && mode2 === "days" ? /* @__PURE__ */
|
|
3156
|
-
/* @__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" }) })
|
|
3157
3397
|
] }),
|
|
3158
|
-
mode2 === "days" ? /* @__PURE__ */
|
|
3398
|
+
mode2 === "days" ? /* @__PURE__ */ jsxs43("div", { style: { display: "flex", gap: 18 }, children: [
|
|
3159
3399
|
monthGrid(vy, vm),
|
|
3160
3400
|
months > 1 ? monthGrid(nextY, nextM) : null
|
|
3161
|
-
] }) : mode2 === "months" ? /* @__PURE__ */
|
|
3401
|
+
] }) : mode2 === "months" ? /* @__PURE__ */ jsx48("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx48(
|
|
3162
3402
|
"button",
|
|
3163
3403
|
{
|
|
3164
3404
|
type: "button",
|
|
@@ -3170,7 +3410,7 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3170
3410
|
children: m.slice(0, 3)
|
|
3171
3411
|
},
|
|
3172
3412
|
m
|
|
3173
|
-
)) }) : /* @__PURE__ */
|
|
3413
|
+
)) }) : /* @__PURE__ */ jsx48("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx48(
|
|
3174
3414
|
"button",
|
|
3175
3415
|
{
|
|
3176
3416
|
type: "button",
|
|
@@ -3183,8 +3423,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3183
3423
|
},
|
|
3184
3424
|
y
|
|
3185
3425
|
)) }),
|
|
3186
|
-
/* @__PURE__ */
|
|
3187
|
-
/* @__PURE__ */
|
|
3426
|
+
/* @__PURE__ */ jsxs43("div", { className: "fd-cal-foot", children: [
|
|
3427
|
+
/* @__PURE__ */ jsx48(
|
|
3188
3428
|
"button",
|
|
3189
3429
|
{
|
|
3190
3430
|
type: "button",
|
|
@@ -3198,8 +3438,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3198
3438
|
children: "Today"
|
|
3199
3439
|
}
|
|
3200
3440
|
),
|
|
3201
|
-
/* @__PURE__ */
|
|
3202
|
-
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: [
|
|
3203
3443
|
fmt(sel.start),
|
|
3204
3444
|
sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
|
|
3205
3445
|
] }) : null
|
|
@@ -3207,12 +3447,12 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3207
3447
|
] });
|
|
3208
3448
|
}
|
|
3209
3449
|
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, className = "", style, ...rest }) {
|
|
3210
|
-
const [open, setOpen] =
|
|
3211
|
-
const rootRef =
|
|
3212
|
-
const boxRef =
|
|
3213
|
-
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);
|
|
3214
3454
|
const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
|
|
3215
|
-
|
|
3455
|
+
React20.useEffect(() => {
|
|
3216
3456
|
if (!open) return;
|
|
3217
3457
|
const away = (e) => {
|
|
3218
3458
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -3233,14 +3473,14 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3233
3473
|
const toggle = () => {
|
|
3234
3474
|
if (!disabled) setOpen(!open);
|
|
3235
3475
|
};
|
|
3236
|
-
return /* @__PURE__ */
|
|
3237
|
-
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: [
|
|
3238
3478
|
label,
|
|
3239
|
-
required ? /* @__PURE__ */
|
|
3479
|
+
required ? /* @__PURE__ */ jsx48("span", { className: "fd-field-req", children: "*" }) : null
|
|
3240
3480
|
] }) : null,
|
|
3241
|
-
/* @__PURE__ */
|
|
3242
|
-
/* @__PURE__ */
|
|
3243
|
-
/* @__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(
|
|
3244
3484
|
"button",
|
|
3245
3485
|
{
|
|
3246
3486
|
type: "button",
|
|
@@ -3256,10 +3496,10 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3256
3496
|
children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
|
|
3257
3497
|
}
|
|
3258
3498
|
),
|
|
3259
|
-
/* @__PURE__ */
|
|
3499
|
+
/* @__PURE__ */ jsx48("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3260
3500
|
] }),
|
|
3261
3501
|
open && pos ? createPortal5(
|
|
3262
|
-
/* @__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(
|
|
3263
3503
|
Calendar,
|
|
3264
3504
|
{
|
|
3265
3505
|
range,
|
|
@@ -3273,21 +3513,21 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3273
3513
|
) }),
|
|
3274
3514
|
document.body
|
|
3275
3515
|
) : null,
|
|
3276
|
-
error ? /* @__PURE__ */
|
|
3277
|
-
/* @__PURE__ */
|
|
3516
|
+
error ? /* @__PURE__ */ jsxs43("span", { className: "fd-field-error", children: [
|
|
3517
|
+
/* @__PURE__ */ jsx48("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3278
3518
|
error
|
|
3279
|
-
] }) : help ? /* @__PURE__ */
|
|
3519
|
+
] }) : help ? /* @__PURE__ */ jsx48("span", { className: "fd-field-help", children: help }) : null
|
|
3280
3520
|
] });
|
|
3281
3521
|
}
|
|
3282
3522
|
|
|
3283
3523
|
// src/components/forms/TimePicker.tsx
|
|
3284
|
-
import * as
|
|
3524
|
+
import * as React21 from "react";
|
|
3285
3525
|
import { createPortal as createPortal6 } from "react-dom";
|
|
3286
|
-
import { jsx as
|
|
3526
|
+
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3287
3527
|
var pad = (n) => String(n).padStart(2, "0");
|
|
3288
3528
|
function usePopPos3(open, ref, estH, estW) {
|
|
3289
|
-
const [pos, setPos] =
|
|
3290
|
-
|
|
3529
|
+
const [pos, setPos] = React21.useState(null);
|
|
3530
|
+
React21.useLayoutEffect(() => {
|
|
3291
3531
|
if (!open || !ref.current) {
|
|
3292
3532
|
setPos(null);
|
|
3293
3533
|
return;
|
|
@@ -3333,9 +3573,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3333
3573
|
if (isNaN(m)) m = 0;
|
|
3334
3574
|
const pm = h24 >= 12;
|
|
3335
3575
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
3336
|
-
const [mode2, setMode] =
|
|
3337
|
-
const faceRef =
|
|
3338
|
-
const dragging =
|
|
3576
|
+
const [mode2, setMode] = React21.useState("h");
|
|
3577
|
+
const faceRef = React21.useRef(null);
|
|
3578
|
+
const dragging = React21.useRef(false);
|
|
3339
3579
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
3340
3580
|
const R = 108, NR = 80;
|
|
3341
3581
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -3370,12 +3610,12 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3370
3610
|
};
|
|
3371
3611
|
const handAngle = mode2 === "h" ? h12 % 12 * 30 : m * 6;
|
|
3372
3612
|
const minuteOff = mode2 === "m" && m % 5 !== 0;
|
|
3373
|
-
return /* @__PURE__ */
|
|
3374
|
-
/* @__PURE__ */
|
|
3375
|
-
/* @__PURE__ */
|
|
3376
|
-
/* @__PURE__ */
|
|
3377
|
-
/* @__PURE__ */
|
|
3378
|
-
/* @__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(
|
|
3379
3619
|
"button",
|
|
3380
3620
|
{
|
|
3381
3621
|
type: "button",
|
|
@@ -3386,13 +3626,13 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3386
3626
|
ap
|
|
3387
3627
|
)) })
|
|
3388
3628
|
] }),
|
|
3389
|
-
/* @__PURE__ */
|
|
3390
|
-
/* @__PURE__ */
|
|
3391
|
-
/* @__PURE__ */
|
|
3392
|
-
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,
|
|
3393
3633
|
nums.map((n) => {
|
|
3394
3634
|
const a = angleOf(n) * Math.PI / 180;
|
|
3395
|
-
return /* @__PURE__ */
|
|
3635
|
+
return /* @__PURE__ */ jsx49(
|
|
3396
3636
|
"span",
|
|
3397
3637
|
{
|
|
3398
3638
|
className: "fd-clock-num" + (n === selNum || mode2 === "m" && n === Math.round(m / 5) * 5 % 60 && m % 5 === 0 ? " is-sel" : ""),
|
|
@@ -3403,16 +3643,16 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3403
3643
|
);
|
|
3404
3644
|
})
|
|
3405
3645
|
] }),
|
|
3406
|
-
/* @__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" }) })
|
|
3407
3647
|
] });
|
|
3408
3648
|
}
|
|
3409
3649
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", className = "", style }) {
|
|
3410
|
-
const [open, setOpen] =
|
|
3411
|
-
const rootRef =
|
|
3412
|
-
const boxRef =
|
|
3413
|
-
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);
|
|
3414
3654
|
const pos = usePopPos3(open, boxRef, 420, 262);
|
|
3415
|
-
|
|
3655
|
+
React21.useEffect(() => {
|
|
3416
3656
|
if (!open) return;
|
|
3417
3657
|
const away = (e) => {
|
|
3418
3658
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -3437,14 +3677,14 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3437
3677
|
const toggle = () => {
|
|
3438
3678
|
if (!disabled) setOpen(!open);
|
|
3439
3679
|
};
|
|
3440
|
-
return /* @__PURE__ */
|
|
3441
|
-
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: [
|
|
3442
3682
|
label,
|
|
3443
|
-
required ? /* @__PURE__ */
|
|
3683
|
+
required ? /* @__PURE__ */ jsx49("span", { className: "fd-field-req", children: "*" }) : null
|
|
3444
3684
|
] }) : null,
|
|
3445
|
-
/* @__PURE__ */
|
|
3446
|
-
/* @__PURE__ */
|
|
3447
|
-
/* @__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(
|
|
3448
3688
|
"button",
|
|
3449
3689
|
{
|
|
3450
3690
|
type: "button",
|
|
@@ -3459,13 +3699,13 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3459
3699
|
children: disp() || placeholder
|
|
3460
3700
|
}
|
|
3461
3701
|
),
|
|
3462
|
-
/* @__PURE__ */
|
|
3702
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3463
3703
|
] }),
|
|
3464
3704
|
open && pos ? createPortal6(
|
|
3465
|
-
/* @__PURE__ */
|
|
3466
|
-
/* @__PURE__ */
|
|
3467
|
-
/* @__PURE__ */
|
|
3468
|
-
/* @__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(
|
|
3469
3709
|
"button",
|
|
3470
3710
|
{
|
|
3471
3711
|
type: "button",
|
|
@@ -3478,22 +3718,22 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3478
3718
|
children: "Now"
|
|
3479
3719
|
}
|
|
3480
3720
|
),
|
|
3481
|
-
/* @__PURE__ */
|
|
3482
|
-
/* @__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" })
|
|
3483
3723
|
] })
|
|
3484
3724
|
] }),
|
|
3485
3725
|
document.body
|
|
3486
3726
|
) : null,
|
|
3487
|
-
error ? /* @__PURE__ */
|
|
3488
|
-
/* @__PURE__ */
|
|
3727
|
+
error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
|
|
3728
|
+
/* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3489
3729
|
error
|
|
3490
|
-
] }) : help ? /* @__PURE__ */
|
|
3730
|
+
] }) : help ? /* @__PURE__ */ jsx49("span", { className: "fd-field-help", children: help }) : null
|
|
3491
3731
|
] });
|
|
3492
3732
|
}
|
|
3493
3733
|
|
|
3494
3734
|
// src/components/forms/Slider.tsx
|
|
3495
|
-
import * as
|
|
3496
|
-
import { jsx as
|
|
3735
|
+
import * as React22 from "react";
|
|
3736
|
+
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3497
3737
|
function Slider({
|
|
3498
3738
|
label,
|
|
3499
3739
|
min = 0,
|
|
@@ -3507,18 +3747,18 @@ function Slider({
|
|
|
3507
3747
|
className = "",
|
|
3508
3748
|
...rest
|
|
3509
3749
|
}) {
|
|
3510
|
-
const [dragging, setDragging] =
|
|
3750
|
+
const [dragging, setDragging] = React22.useState(false);
|
|
3511
3751
|
const v = value === void 0 ? min : Number(value);
|
|
3512
3752
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
3513
|
-
return /* @__PURE__ */
|
|
3514
|
-
label ? /* @__PURE__ */
|
|
3515
|
-
/* @__PURE__ */
|
|
3516
|
-
/* @__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) })
|
|
3517
3757
|
] }) : null,
|
|
3518
|
-
/* @__PURE__ */
|
|
3519
|
-
/* @__PURE__ */
|
|
3520
|
-
showChip && dragging ? /* @__PURE__ */
|
|
3521
|
-
/* @__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(
|
|
3522
3762
|
"input",
|
|
3523
3763
|
{
|
|
3524
3764
|
type: "range",
|
|
@@ -3535,13 +3775,13 @@ function Slider({
|
|
|
3535
3775
|
}
|
|
3536
3776
|
)
|
|
3537
3777
|
] }),
|
|
3538
|
-
help ? /* @__PURE__ */
|
|
3778
|
+
help ? /* @__PURE__ */ jsx50("span", { className: "fd-field-help", children: help }) : null
|
|
3539
3779
|
] });
|
|
3540
3780
|
}
|
|
3541
3781
|
|
|
3542
3782
|
// src/components/forms/RangeSlider.tsx
|
|
3543
|
-
import * as
|
|
3544
|
-
import { jsx as
|
|
3783
|
+
import * as React23 from "react";
|
|
3784
|
+
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3545
3785
|
function RangeSlider({
|
|
3546
3786
|
label,
|
|
3547
3787
|
min = 0,
|
|
@@ -3560,9 +3800,9 @@ function RangeSlider({
|
|
|
3560
3800
|
}) {
|
|
3561
3801
|
const fmt2 = format || ((v) => String(v));
|
|
3562
3802
|
const [a, b] = value || [min, max];
|
|
3563
|
-
const [drag, setDrag] =
|
|
3564
|
-
const [focus, setFocus] =
|
|
3565
|
-
const railRef =
|
|
3803
|
+
const [drag, setDrag] = React23.useState(null);
|
|
3804
|
+
const [focus, setFocus] = React23.useState(null);
|
|
3805
|
+
const railRef = React23.useRef(null);
|
|
3566
3806
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
3567
3807
|
const clampPair = (i, v) => {
|
|
3568
3808
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -3577,7 +3817,7 @@ function RangeSlider({
|
|
|
3577
3817
|
const r = railRef.current.getBoundingClientRect();
|
|
3578
3818
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
3579
3819
|
};
|
|
3580
|
-
|
|
3820
|
+
React23.useEffect(() => {
|
|
3581
3821
|
if (drag === null) return;
|
|
3582
3822
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
3583
3823
|
const upH = () => setDrag(null);
|
|
@@ -3598,7 +3838,7 @@ function RangeSlider({
|
|
|
3598
3838
|
};
|
|
3599
3839
|
const thin = S.length > 7 ? Math.ceil(S.length / 5) : 1;
|
|
3600
3840
|
const pair = value || [S[0].value, S[S.length - 1].value];
|
|
3601
|
-
return /* @__PURE__ */
|
|
3841
|
+
return /* @__PURE__ */ jsx51(
|
|
3602
3842
|
RangeSlider,
|
|
3603
3843
|
{
|
|
3604
3844
|
...rest,
|
|
@@ -3646,23 +3886,23 @@ function RangeSlider({
|
|
|
3646
3886
|
};
|
|
3647
3887
|
const showChip = (i) => drag === i || focus === i;
|
|
3648
3888
|
const hasLabels = marks.some((m) => m.label);
|
|
3649
|
-
return /* @__PURE__ */
|
|
3650
|
-
label ? /* @__PURE__ */
|
|
3651
|
-
/* @__PURE__ */
|
|
3652
|
-
/* @__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: [
|
|
3653
3893
|
fmt2(a),
|
|
3654
3894
|
" \u2013 ",
|
|
3655
3895
|
fmt2(b)
|
|
3656
3896
|
] })
|
|
3657
3897
|
] }) : null,
|
|
3658
|
-
/* @__PURE__ */
|
|
3659
|
-
/* @__PURE__ */
|
|
3660
|
-
/* @__PURE__ */
|
|
3661
|
-
marks.map((m) => /* @__PURE__ */
|
|
3662
|
-
/* @__PURE__ */
|
|
3663
|
-
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
|
|
3664
3904
|
] }, m.value)),
|
|
3665
|
-
[a, b].map((v, i) => /* @__PURE__ */
|
|
3905
|
+
[a, b].map((v, i) => /* @__PURE__ */ jsx51(
|
|
3666
3906
|
"span",
|
|
3667
3907
|
{
|
|
3668
3908
|
className: "fd-range-thumb" + (drag === i ? " is-drag" : ""),
|
|
@@ -3677,18 +3917,18 @@ function RangeSlider({
|
|
|
3677
3917
|
onKeyDown: key(i),
|
|
3678
3918
|
onFocus: () => setFocus(i),
|
|
3679
3919
|
onBlur: () => setFocus(null),
|
|
3680
|
-
children: /* @__PURE__ */
|
|
3920
|
+
children: /* @__PURE__ */ jsx51("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
|
|
3681
3921
|
},
|
|
3682
3922
|
i
|
|
3683
3923
|
))
|
|
3684
3924
|
] }),
|
|
3685
|
-
help ? /* @__PURE__ */
|
|
3925
|
+
help ? /* @__PURE__ */ jsx51("span", { className: "fd-field-help", children: help }) : null
|
|
3686
3926
|
] });
|
|
3687
3927
|
}
|
|
3688
3928
|
|
|
3689
3929
|
// src/components/forms/Dropzone.tsx
|
|
3690
|
-
import * as
|
|
3691
|
-
import { jsx as
|
|
3930
|
+
import * as React24 from "react";
|
|
3931
|
+
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
3692
3932
|
function Dropzone({
|
|
3693
3933
|
onFiles,
|
|
3694
3934
|
onReject,
|
|
@@ -3702,8 +3942,8 @@ function Dropzone({
|
|
|
3702
3942
|
className = "",
|
|
3703
3943
|
style
|
|
3704
3944
|
}) {
|
|
3705
|
-
const [over, setOver] =
|
|
3706
|
-
const depth =
|
|
3945
|
+
const [over, setOver] = React24.useState(false);
|
|
3946
|
+
const depth = React24.useRef(0);
|
|
3707
3947
|
const has = (e) => {
|
|
3708
3948
|
const dt = e.dataTransfer;
|
|
3709
3949
|
if (!dt) return false;
|
|
@@ -3733,7 +3973,7 @@ function Dropzone({
|
|
|
3733
3973
|
if (rejected.length && onReject) onReject(rejected);
|
|
3734
3974
|
if (accepted.length && onFiles) onFiles(accepted);
|
|
3735
3975
|
};
|
|
3736
|
-
return /* @__PURE__ */
|
|
3976
|
+
return /* @__PURE__ */ jsxs47(
|
|
3737
3977
|
"div",
|
|
3738
3978
|
{
|
|
3739
3979
|
className: ["fd-dropzone", over ? "is-over" : "", className].filter(Boolean).join(" "),
|
|
@@ -3744,10 +3984,10 @@ function Dropzone({
|
|
|
3744
3984
|
onDrop: drop,
|
|
3745
3985
|
children: [
|
|
3746
3986
|
children,
|
|
3747
|
-
over ? /* @__PURE__ */
|
|
3748
|
-
/* @__PURE__ */
|
|
3749
|
-
/* @__PURE__ */
|
|
3750
|
-
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
|
|
3751
3991
|
] }) }) : null
|
|
3752
3992
|
]
|
|
3753
3993
|
}
|
|
@@ -3765,9 +4005,9 @@ function FilePickButton({
|
|
|
3765
4005
|
className = "",
|
|
3766
4006
|
children
|
|
3767
4007
|
}) {
|
|
3768
|
-
const ref =
|
|
3769
|
-
return /* @__PURE__ */
|
|
3770
|
-
/* @__PURE__ */
|
|
4008
|
+
const ref = React24.useRef(null);
|
|
4009
|
+
return /* @__PURE__ */ jsxs47(React24.Fragment, { children: [
|
|
4010
|
+
/* @__PURE__ */ jsx52(
|
|
3771
4011
|
"button",
|
|
3772
4012
|
{
|
|
3773
4013
|
type: "button",
|
|
@@ -3776,10 +4016,10 @@ function FilePickButton({
|
|
|
3776
4016
|
"aria-label": label,
|
|
3777
4017
|
title: label,
|
|
3778
4018
|
onClick: () => ref.current && ref.current.click(),
|
|
3779
|
-
children: children != null ? children : /* @__PURE__ */
|
|
4019
|
+
children: children != null ? children : /* @__PURE__ */ jsx52("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
|
|
3780
4020
|
}
|
|
3781
4021
|
),
|
|
3782
|
-
/* @__PURE__ */
|
|
4022
|
+
/* @__PURE__ */ jsx52(
|
|
3783
4023
|
"input",
|
|
3784
4024
|
{
|
|
3785
4025
|
ref,
|
|
@@ -3799,10 +4039,10 @@ function FilePickButton({
|
|
|
3799
4039
|
}
|
|
3800
4040
|
function useStagedFiles(upload, opts) {
|
|
3801
4041
|
const o = opts || {};
|
|
3802
|
-
const [items, setItems] =
|
|
3803
|
-
const controllers =
|
|
4042
|
+
const [items, setItems] = React24.useState([]);
|
|
4043
|
+
const controllers = React24.useRef({});
|
|
3804
4044
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
3805
|
-
const run =
|
|
4045
|
+
const run = React24.useCallback((att) => {
|
|
3806
4046
|
if (!upload) return;
|
|
3807
4047
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
3808
4048
|
controllers.current[att.id] = ac;
|
|
@@ -3819,14 +4059,14 @@ function useStagedFiles(upload, opts) {
|
|
|
3819
4059
|
delete controllers.current[att.id];
|
|
3820
4060
|
});
|
|
3821
4061
|
}, [upload]);
|
|
3822
|
-
const add =
|
|
4062
|
+
const add = React24.useCallback((files) => {
|
|
3823
4063
|
if (!upload) return [];
|
|
3824
4064
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
3825
4065
|
setItems((list) => list.concat(atts));
|
|
3826
4066
|
atts.forEach(run);
|
|
3827
4067
|
return atts;
|
|
3828
4068
|
}, [upload, run]);
|
|
3829
|
-
const remove =
|
|
4069
|
+
const remove = React24.useCallback((att) => {
|
|
3830
4070
|
const ac = controllers.current[att.id];
|
|
3831
4071
|
if (ac) {
|
|
3832
4072
|
try {
|
|
@@ -3837,10 +4077,10 @@ function useStagedFiles(upload, opts) {
|
|
|
3837
4077
|
}
|
|
3838
4078
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
3839
4079
|
}, []);
|
|
3840
|
-
const retry =
|
|
4080
|
+
const retry = React24.useCallback((att) => {
|
|
3841
4081
|
run(att);
|
|
3842
4082
|
}, [run]);
|
|
3843
|
-
const clear =
|
|
4083
|
+
const clear = React24.useCallback(() => {
|
|
3844
4084
|
Object.values(controllers.current).forEach((ac) => {
|
|
3845
4085
|
try {
|
|
3846
4086
|
ac && ac.abort();
|
|
@@ -3856,7 +4096,7 @@ function useStagedFiles(upload, opts) {
|
|
|
3856
4096
|
var DropzoneKit = { useStagedFiles };
|
|
3857
4097
|
|
|
3858
4098
|
// src/components/forms/FileGrid.tsx
|
|
3859
|
-
import { jsx as
|
|
4099
|
+
import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
3860
4100
|
var truncateMiddle = (name, max = 34) => {
|
|
3861
4101
|
if (!name || name.length <= max) return name;
|
|
3862
4102
|
const ext = /\.[A-Za-z0-9]+$/.exec(name);
|
|
@@ -3865,7 +4105,7 @@ var truncateMiddle = (name, max = 34) => {
|
|
|
3865
4105
|
return head + "\u2026" + tail;
|
|
3866
4106
|
};
|
|
3867
4107
|
function Progress({ value }) {
|
|
3868
|
-
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)) + "%" } }) });
|
|
3869
4109
|
}
|
|
3870
4110
|
function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false, className = "" }) {
|
|
3871
4111
|
if (!file) return null;
|
|
@@ -3874,8 +4114,8 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
3874
4114
|
const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
|
|
3875
4115
|
const meta = file.meta || (file.size ? formatBytes(file.size) : "");
|
|
3876
4116
|
const clickable = !!onOpen && !uploading;
|
|
3877
|
-
return /* @__PURE__ */
|
|
3878
|
-
/* @__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(
|
|
3879
4119
|
"button",
|
|
3880
4120
|
{
|
|
3881
4121
|
type: "button",
|
|
@@ -3884,16 +4124,16 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
3884
4124
|
onClick: clickable ? () => onOpen(file) : void 0,
|
|
3885
4125
|
title: file.name + (meta ? " \xB7 " + meta : ""),
|
|
3886
4126
|
children: [
|
|
3887
|
-
/* @__PURE__ */
|
|
3888
|
-
thumb ? /* @__PURE__ */
|
|
3889
|
-
(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
|
|
3890
4130
|
] }),
|
|
3891
|
-
/* @__PURE__ */
|
|
3892
|
-
/* @__PURE__ */
|
|
3893
|
-
/* @__PURE__ */
|
|
3894
|
-
/* @__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" }),
|
|
3895
4135
|
file.error
|
|
3896
|
-
] }) : uploading ? /* @__PURE__ */
|
|
4136
|
+
] }) : uploading ? /* @__PURE__ */ jsxs48("span", { className: "fd-tabular", children: [
|
|
3897
4137
|
Math.round(file.progress),
|
|
3898
4138
|
"% uploaded"
|
|
3899
4139
|
] }) : meta })
|
|
@@ -3901,29 +4141,29 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
3901
4141
|
]
|
|
3902
4142
|
}
|
|
3903
4143
|
),
|
|
3904
|
-
uploading ? /* @__PURE__ */
|
|
3905
|
-
file.error && onRetry ? /* @__PURE__ */
|
|
3906
|
-
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
|
|
3907
4147
|
] });
|
|
3908
4148
|
}
|
|
3909
4149
|
function FileTile({ file, onOpen, onRemove, maxHeight = 200, className = "" }) {
|
|
3910
4150
|
if (!file) return null;
|
|
3911
4151
|
const src = file.thumb && file.thumb.url || file.blobUrl || file.url;
|
|
3912
4152
|
const uploading = file.progress != null && file.progress < 100 && !file.error;
|
|
3913
|
-
return /* @__PURE__ */
|
|
3914
|
-
/* @__PURE__ */
|
|
3915
|
-
uploading ? /* @__PURE__ */
|
|
3916
|
-
file.error ? /* @__PURE__ */
|
|
3917
|
-
/* @__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" }),
|
|
3918
4158
|
file.error
|
|
3919
4159
|
] }) : null,
|
|
3920
|
-
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
|
|
3921
4161
|
] });
|
|
3922
4162
|
}
|
|
3923
4163
|
function FileStrip({ files = [], size = 68, onOpen, onRemove, onRetry, className = "" }) {
|
|
3924
4164
|
const list = files.filter(Boolean);
|
|
3925
4165
|
if (!list.length) return null;
|
|
3926
|
-
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)) });
|
|
3927
4167
|
}
|
|
3928
4168
|
var shortName = (name, keep = 5) => {
|
|
3929
4169
|
const s = String(name || "file");
|
|
@@ -3937,19 +4177,19 @@ function FileCell({ file, onOpen, onRemove, onRetry }) {
|
|
|
3937
4177
|
const image = isImage(file.mime, file.name);
|
|
3938
4178
|
const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
|
|
3939
4179
|
const label = file.name + (file.size ? " \xB7 " + formatBytes(file.size) : "");
|
|
3940
|
-
return /* @__PURE__ */
|
|
3941
|
-
/* @__PURE__ */
|
|
3942
|
-
thumb ? /* @__PURE__ */
|
|
3943
|
-
/* @__PURE__ */
|
|
3944
|
-
/* @__PURE__ */
|
|
3945
|
-
/* @__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) })
|
|
3946
4186
|
] }),
|
|
3947
|
-
(file.mime || "").startsWith("video/") ? /* @__PURE__ */
|
|
4187
|
+
(file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx53("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
|
|
3948
4188
|
] }),
|
|
3949
|
-
uploading ? /* @__PURE__ */
|
|
3950
|
-
file.error ? /* @__PURE__ */
|
|
3951
|
-
file.error && onRetry ? /* @__PURE__ */
|
|
3952
|
-
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
|
|
3953
4193
|
] });
|
|
3954
4194
|
}
|
|
3955
4195
|
function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeight = 200, compact: compact3 = false, className = "" }) {
|
|
@@ -3957,15 +4197,15 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
3957
4197
|
if (!list.length) return null;
|
|
3958
4198
|
const pics = tiles ? list.filter((f) => isImage(f.mime, f.name)) : [];
|
|
3959
4199
|
const rest = list.filter((f) => pics.indexOf(f) === -1);
|
|
3960
|
-
return /* @__PURE__ */
|
|
3961
|
-
pics.length ? /* @__PURE__ */
|
|
3962
|
-
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
|
|
3963
4203
|
] });
|
|
3964
4204
|
}
|
|
3965
4205
|
|
|
3966
4206
|
// src/components/forms/MarkdownEditor.tsx
|
|
3967
|
-
import * as
|
|
3968
|
-
import { jsx as
|
|
4207
|
+
import * as React25 from "react";
|
|
4208
|
+
import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
3969
4209
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
3970
4210
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
3971
4211
|
function inlineParts(text) {
|
|
@@ -4178,7 +4418,7 @@ function syncDom(root, value) {
|
|
|
4178
4418
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
4179
4419
|
}
|
|
4180
4420
|
var LIST_CONT = RE_LI;
|
|
4181
|
-
var MarkdownEditor =
|
|
4421
|
+
var MarkdownEditor = React25.forwardRef(function MarkdownEditor2({
|
|
4182
4422
|
value = "",
|
|
4183
4423
|
onChange,
|
|
4184
4424
|
onSubmit,
|
|
@@ -4197,10 +4437,10 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4197
4437
|
className = "",
|
|
4198
4438
|
id
|
|
4199
4439
|
}, ref) {
|
|
4200
|
-
const boxRef =
|
|
4201
|
-
const composing =
|
|
4202
|
-
const pendingCaret =
|
|
4203
|
-
|
|
4440
|
+
const boxRef = React25.useRef(null);
|
|
4441
|
+
const composing = React25.useRef(false);
|
|
4442
|
+
const pendingCaret = React25.useRef(null);
|
|
4443
|
+
React25.useLayoutEffect(() => {
|
|
4204
4444
|
const root = boxRef.current;
|
|
4205
4445
|
if (!root || composing.current) return;
|
|
4206
4446
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -4209,7 +4449,7 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4209
4449
|
pendingCaret.current = null;
|
|
4210
4450
|
if (active && caret != null) placeCaret(root, caret);
|
|
4211
4451
|
}, [value]);
|
|
4212
|
-
|
|
4452
|
+
React25.useEffect(() => {
|
|
4213
4453
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
4214
4454
|
}, [autoFocus]);
|
|
4215
4455
|
const caretNow = () => {
|
|
@@ -4276,7 +4516,7 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4276
4516
|
api.replaceRange(from, to, next, from + next.length);
|
|
4277
4517
|
}
|
|
4278
4518
|
};
|
|
4279
|
-
|
|
4519
|
+
React25.useImperativeHandle(ref, () => api);
|
|
4280
4520
|
function detect(text, caret) {
|
|
4281
4521
|
if (!onTrigger) return;
|
|
4282
4522
|
const upto = text.slice(0, caret);
|
|
@@ -4389,8 +4629,8 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4389
4629
|
api.replaceRange(s.start, s.end, text.replace(/\r\n?/g, "\n"));
|
|
4390
4630
|
};
|
|
4391
4631
|
const lh = 1.55;
|
|
4392
|
-
return /* @__PURE__ */
|
|
4393
|
-
/* @__PURE__ */
|
|
4632
|
+
return /* @__PURE__ */ jsxs49("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
|
|
4633
|
+
/* @__PURE__ */ jsx54(
|
|
4394
4634
|
"div",
|
|
4395
4635
|
{
|
|
4396
4636
|
ref: boxRef,
|
|
@@ -4423,15 +4663,15 @@ var MarkdownEditor = React23.forwardRef(function MarkdownEditor2({
|
|
|
4423
4663
|
}
|
|
4424
4664
|
}
|
|
4425
4665
|
),
|
|
4426
|
-
!value ? /* @__PURE__ */
|
|
4666
|
+
!value ? /* @__PURE__ */ jsx54("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
|
|
4427
4667
|
] });
|
|
4428
4668
|
});
|
|
4429
4669
|
|
|
4430
4670
|
// src/components/platform/AccountMenu.tsx
|
|
4431
|
-
import * as
|
|
4671
|
+
import * as React27 from "react";
|
|
4432
4672
|
|
|
4433
4673
|
// src/kits/session.ts
|
|
4434
|
-
import * as
|
|
4674
|
+
import * as React26 from "react";
|
|
4435
4675
|
var PERMISSION_CATALOG = [
|
|
4436
4676
|
{ group: "Plans", items: [
|
|
4437
4677
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -5998,8 +6238,8 @@ function roadmap(overrides) {
|
|
|
5998
6238
|
};
|
|
5999
6239
|
}
|
|
6000
6240
|
function useSession() {
|
|
6001
|
-
const [s, setS] =
|
|
6002
|
-
|
|
6241
|
+
const [s, setS] = React26.useState(getSession);
|
|
6242
|
+
React26.useEffect(() => subscribe(setS), []);
|
|
6003
6243
|
return s;
|
|
6004
6244
|
}
|
|
6005
6245
|
var SessionKit = {
|
|
@@ -6032,7 +6272,7 @@ var SessionKit = {
|
|
|
6032
6272
|
};
|
|
6033
6273
|
|
|
6034
6274
|
// src/components/platform/AccountMenu.tsx
|
|
6035
|
-
import { Fragment as Fragment11, jsx as
|
|
6275
|
+
import { Fragment as Fragment11, jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
6036
6276
|
var DEFAULT_LINKS = [
|
|
6037
6277
|
{ id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
|
|
6038
6278
|
{ id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
|
|
@@ -6043,7 +6283,7 @@ var DEFAULT_ADMIN_LINKS = [
|
|
|
6043
6283
|
{ id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
|
|
6044
6284
|
];
|
|
6045
6285
|
function Item({ item, onPick }) {
|
|
6046
|
-
return /* @__PURE__ */
|
|
6286
|
+
return /* @__PURE__ */ jsxs50(
|
|
6047
6287
|
"button",
|
|
6048
6288
|
{
|
|
6049
6289
|
type: "button",
|
|
@@ -6051,9 +6291,9 @@ function Item({ item, onPick }) {
|
|
|
6051
6291
|
className: "fd-acct-item",
|
|
6052
6292
|
onClick: () => onPick(item),
|
|
6053
6293
|
children: [
|
|
6054
|
-
/* @__PURE__ */
|
|
6055
|
-
/* @__PURE__ */
|
|
6056
|
-
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
|
|
6057
6297
|
]
|
|
6058
6298
|
}
|
|
6059
6299
|
);
|
|
@@ -6069,9 +6309,9 @@ function AccountMenu({
|
|
|
6069
6309
|
...rest
|
|
6070
6310
|
}) {
|
|
6071
6311
|
const session = SessionKit.useSession();
|
|
6072
|
-
const [open, setOpen] =
|
|
6073
|
-
const [switching, setSwitching] =
|
|
6074
|
-
const ref =
|
|
6312
|
+
const [open, setOpen] = React27.useState(false);
|
|
6313
|
+
const [switching, setSwitching] = React27.useState(false);
|
|
6314
|
+
const ref = React27.useRef(null);
|
|
6075
6315
|
const user = session.user;
|
|
6076
6316
|
const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
|
|
6077
6317
|
const pick = (item) => {
|
|
@@ -6085,8 +6325,8 @@ function AccountMenu({
|
|
|
6085
6325
|
if (onSignOut) return onSignOut();
|
|
6086
6326
|
window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
|
|
6087
6327
|
};
|
|
6088
|
-
return /* @__PURE__ */
|
|
6089
|
-
/* @__PURE__ */
|
|
6328
|
+
return /* @__PURE__ */ jsxs50(Fragment11, { children: [
|
|
6329
|
+
/* @__PURE__ */ jsxs50(
|
|
6090
6330
|
"button",
|
|
6091
6331
|
{
|
|
6092
6332
|
type: "button",
|
|
@@ -6098,32 +6338,32 @@ function AccountMenu({
|
|
|
6098
6338
|
onClick: () => setOpen((o) => !o),
|
|
6099
6339
|
...rest,
|
|
6100
6340
|
children: [
|
|
6101
|
-
/* @__PURE__ */
|
|
6102
|
-
/* @__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)" } })
|
|
6103
6343
|
]
|
|
6104
6344
|
}
|
|
6105
6345
|
),
|
|
6106
|
-
/* @__PURE__ */
|
|
6107
|
-
/* @__PURE__ */
|
|
6108
|
-
/* @__PURE__ */
|
|
6109
|
-
/* @__PURE__ */
|
|
6110
|
-
/* @__PURE__ */
|
|
6111
|
-
/* @__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 })
|
|
6112
6352
|
] })
|
|
6113
6353
|
] }),
|
|
6114
|
-
showRoles && session.roles.length ? /* @__PURE__ */
|
|
6115
|
-
/* @__PURE__ */
|
|
6116
|
-
visibleAdmin.length ? /* @__PURE__ */
|
|
6117
|
-
/* @__PURE__ */
|
|
6118
|
-
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))
|
|
6119
6359
|
] }) : null,
|
|
6120
|
-
allowUserSwitch ? /* @__PURE__ */
|
|
6121
|
-
/* @__PURE__ */
|
|
6122
|
-
/* @__PURE__ */
|
|
6123
|
-
/* @__PURE__ */
|
|
6124
|
-
/* @__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 } })
|
|
6125
6365
|
] }),
|
|
6126
|
-
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(
|
|
6127
6367
|
"button",
|
|
6128
6368
|
{
|
|
6129
6369
|
type: "button",
|
|
@@ -6135,34 +6375,34 @@ function AccountMenu({
|
|
|
6135
6375
|
setSwitching(false);
|
|
6136
6376
|
},
|
|
6137
6377
|
children: [
|
|
6138
|
-
/* @__PURE__ */
|
|
6139
|
-
/* @__PURE__ */
|
|
6140
|
-
/* @__PURE__ */
|
|
6141
|
-
/* @__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(", ") })
|
|
6142
6382
|
] }),
|
|
6143
|
-
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
|
|
6144
6384
|
]
|
|
6145
6385
|
},
|
|
6146
6386
|
u.id
|
|
6147
6387
|
)) }) : null
|
|
6148
6388
|
] }) : null,
|
|
6149
|
-
/* @__PURE__ */
|
|
6150
|
-
/* @__PURE__ */
|
|
6151
|
-
/* @__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" })
|
|
6152
6392
|
] }) })
|
|
6153
6393
|
] }) })
|
|
6154
6394
|
] });
|
|
6155
6395
|
}
|
|
6156
6396
|
|
|
6157
6397
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
6158
|
-
import * as
|
|
6159
|
-
import { jsx as
|
|
6398
|
+
import * as React28 from "react";
|
|
6399
|
+
import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
6160
6400
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
6161
6401
|
function Json({ obj }) {
|
|
6162
|
-
return /* @__PURE__ */
|
|
6402
|
+
return /* @__PURE__ */ jsx56("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
6163
6403
|
}
|
|
6164
6404
|
function Endpoint({ s, onRequest }) {
|
|
6165
|
-
const [tried, setTried] =
|
|
6405
|
+
const [tried, setTried] = React28.useState(null);
|
|
6166
6406
|
const run = async () => {
|
|
6167
6407
|
setTried("busy");
|
|
6168
6408
|
const t0 = (window.performance || Date).now();
|
|
@@ -6173,50 +6413,50 @@ function Endpoint({ s, onRequest }) {
|
|
|
6173
6413
|
setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
|
|
6174
6414
|
}
|
|
6175
6415
|
};
|
|
6176
|
-
return /* @__PURE__ */
|
|
6177
|
-
/* @__PURE__ */
|
|
6178
|
-
/* @__PURE__ */
|
|
6179
|
-
/* @__PURE__ */
|
|
6180
|
-
s.isList ? /* @__PURE__ */
|
|
6181
|
-
/* @__PURE__ */
|
|
6182
|
-
/* @__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: [
|
|
6183
6423
|
s.latency[0],
|
|
6184
6424
|
"\u2013",
|
|
6185
6425
|
s.latency[1],
|
|
6186
6426
|
"ms"
|
|
6187
6427
|
] }),
|
|
6188
|
-
/* @__PURE__ */
|
|
6428
|
+
/* @__PURE__ */ jsx56(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
|
|
6189
6429
|
] }),
|
|
6190
|
-
/* @__PURE__ */
|
|
6191
|
-
/* @__PURE__ */
|
|
6192
|
-
/* @__PURE__ */
|
|
6193
|
-
/* @__PURE__ */
|
|
6194
|
-
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
|
|
6195
6435
|
] }),
|
|
6196
|
-
/* @__PURE__ */
|
|
6197
|
-
s.request ? /* @__PURE__ */
|
|
6198
|
-
/* @__PURE__ */
|
|
6199
|
-
/* @__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 })
|
|
6200
6440
|
] }) : null,
|
|
6201
|
-
s.query ? /* @__PURE__ */
|
|
6202
|
-
/* @__PURE__ */
|
|
6203
|
-
/* @__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 })
|
|
6204
6444
|
] }) : null,
|
|
6205
|
-
/* @__PURE__ */
|
|
6206
|
-
/* @__PURE__ */
|
|
6207
|
-
/* @__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 })
|
|
6208
6448
|
] })
|
|
6209
6449
|
] }),
|
|
6210
|
-
s.notes ? /* @__PURE__ */
|
|
6211
|
-
tried && tried !== "busy" ? /* @__PURE__ */
|
|
6212
|
-
/* @__PURE__ */
|
|
6213
|
-
/* @__PURE__ */
|
|
6214
|
-
/* @__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: [
|
|
6215
6455
|
tried.ms,
|
|
6216
6456
|
"ms"
|
|
6217
6457
|
] })
|
|
6218
6458
|
] }),
|
|
6219
|
-
/* @__PURE__ */
|
|
6459
|
+
/* @__PURE__ */ jsx56(Json, { obj: tried.error ? { error: tried.error } : tried.data })
|
|
6220
6460
|
] }) : null
|
|
6221
6461
|
] })
|
|
6222
6462
|
] }) });
|
|
@@ -6235,58 +6475,58 @@ function ApiSpecBrowser({
|
|
|
6235
6475
|
className = "",
|
|
6236
6476
|
...rest
|
|
6237
6477
|
}) {
|
|
6238
|
-
const [q, setQ] =
|
|
6239
|
-
const [method, setMethod] =
|
|
6240
|
-
const [mod, setMod] =
|
|
6241
|
-
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);
|
|
6242
6482
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
6243
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())));
|
|
6244
6484
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
6245
6485
|
const methods = [...new Set(spec.map((s) => s.method))];
|
|
6246
6486
|
const listCount = spec.filter((s) => s.isList).length;
|
|
6247
|
-
return /* @__PURE__ */
|
|
6248
|
-
/* @__PURE__ */
|
|
6249
|
-
kicker ? /* @__PURE__ */
|
|
6250
|
-
/* @__PURE__ */
|
|
6251
|
-
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
|
|
6252
6492
|
] }),
|
|
6253
|
-
modules && modules.length ? /* @__PURE__ */
|
|
6254
|
-
/* @__PURE__ */
|
|
6255
|
-
/* @__PURE__ */
|
|
6256
|
-
/* @__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: [
|
|
6257
6497
|
"All screens ",
|
|
6258
|
-
/* @__PURE__ */
|
|
6498
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: spec.length })
|
|
6259
6499
|
] }),
|
|
6260
|
-
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: [
|
|
6261
6501
|
m.label,
|
|
6262
6502
|
" ",
|
|
6263
|
-
/* @__PURE__ */
|
|
6503
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: m.endpoints.length })
|
|
6264
6504
|
] }, m.id))
|
|
6265
6505
|
] }),
|
|
6266
|
-
activeModule ? /* @__PURE__ */
|
|
6506
|
+
activeModule ? /* @__PURE__ */ jsx56(
|
|
6267
6507
|
Flag,
|
|
6268
6508
|
{
|
|
6269
6509
|
tone: "info",
|
|
6270
6510
|
statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
|
|
6271
6511
|
cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
|
|
6272
|
-
actions: /* @__PURE__ */
|
|
6512
|
+
actions: /* @__PURE__ */ jsx56(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
|
|
6273
6513
|
}
|
|
6274
6514
|
) : null
|
|
6275
6515
|
] }) : null,
|
|
6276
|
-
sourceNote ? /* @__PURE__ */
|
|
6277
|
-
/* @__PURE__ */
|
|
6278
|
-
/* @__PURE__ */
|
|
6279
|
-
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: [
|
|
6280
6520
|
m,
|
|
6281
6521
|
" ",
|
|
6282
|
-
/* @__PURE__ */
|
|
6522
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
|
|
6283
6523
|
] }, m)),
|
|
6284
|
-
listCount ? /* @__PURE__ */
|
|
6524
|
+
listCount ? /* @__PURE__ */ jsxs51(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
|
|
6285
6525
|
"Paged lists ",
|
|
6286
|
-
/* @__PURE__ */
|
|
6526
|
+
/* @__PURE__ */ jsx56("span", { className: "fd-mono", children: listCount })
|
|
6287
6527
|
] }) : null,
|
|
6288
|
-
/* @__PURE__ */
|
|
6289
|
-
/* @__PURE__ */
|
|
6528
|
+
/* @__PURE__ */ jsx56("span", { style: { flex: 1 } }),
|
|
6529
|
+
/* @__PURE__ */ jsxs51("span", { className: "fd-body-sm fd-muted", children: [
|
|
6290
6530
|
hits.length,
|
|
6291
6531
|
" of ",
|
|
6292
6532
|
spec.length,
|
|
@@ -6294,31 +6534,31 @@ function ApiSpecBrowser({
|
|
|
6294
6534
|
listCount ? " \xB7 " + listCount + " paged" : ""
|
|
6295
6535
|
] })
|
|
6296
6536
|
] }),
|
|
6297
|
-
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]) => {
|
|
6298
6538
|
const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
|
|
6299
6539
|
if (!items.length) return null;
|
|
6300
|
-
return /* @__PURE__ */
|
|
6301
|
-
/* @__PURE__ */
|
|
6302
|
-
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))
|
|
6303
6543
|
] }, g);
|
|
6304
6544
|
}),
|
|
6305
|
-
conventions && conventions.length ? /* @__PURE__ */
|
|
6306
|
-
/* @__PURE__ */
|
|
6307
|
-
/* @__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 })
|
|
6308
6548
|
] }, k)) }) }) : null,
|
|
6309
|
-
openQuestions && openQuestions.length ? /* @__PURE__ */
|
|
6310
|
-
/* @__PURE__ */
|
|
6311
|
-
/* @__PURE__ */
|
|
6312
|
-
/* @__PURE__ */
|
|
6313
|
-
/* @__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 })
|
|
6314
6554
|
] })
|
|
6315
6555
|
] }, id)) }) }) : null
|
|
6316
6556
|
] });
|
|
6317
6557
|
}
|
|
6318
6558
|
|
|
6319
6559
|
// src/components/platform/ProfilePage.tsx
|
|
6320
|
-
import * as
|
|
6321
|
-
import { jsx as
|
|
6560
|
+
import * as React29 from "react";
|
|
6561
|
+
import { jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
6322
6562
|
var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
|
|
6323
6563
|
var NOTIFY = [
|
|
6324
6564
|
{ key: "planShared", label: "A plan is shared with me", detail: "Someone sends you a plan or a client link." },
|
|
@@ -6330,7 +6570,7 @@ var NOTIFY = [
|
|
|
6330
6570
|
function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
|
|
6331
6571
|
const session = SessionKit.useSession();
|
|
6332
6572
|
const user = userProp || session.user;
|
|
6333
|
-
const [draft, setDraft] =
|
|
6573
|
+
const [draft, setDraft] = React29.useState(() => ({
|
|
6334
6574
|
name: user.name || "",
|
|
6335
6575
|
title: user.title || "",
|
|
6336
6576
|
email: user.email || "",
|
|
@@ -6339,8 +6579,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6339
6579
|
bio: user.bio || "",
|
|
6340
6580
|
notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
|
|
6341
6581
|
}));
|
|
6342
|
-
const [saving, setSaving] =
|
|
6343
|
-
const [saved, setSaved] =
|
|
6582
|
+
const [saving, setSaving] = React29.useState(false);
|
|
6583
|
+
const [saved, setSaved] = React29.useState(false);
|
|
6344
6584
|
const set = (k, v) => {
|
|
6345
6585
|
setDraft((d) => Object.assign({}, d, { [k]: v }));
|
|
6346
6586
|
setSaved(false);
|
|
@@ -6362,43 +6602,43 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6362
6602
|
{ id: "s2", device: "iPhone 15 \xB7 Safari", where: "Denver, CO", when: "2 hours ago" },
|
|
6363
6603
|
{ id: "s3", device: "Windows \xB7 Edge", where: "Chicago, IL", when: "Aug 12" }
|
|
6364
6604
|
];
|
|
6365
|
-
return /* @__PURE__ */
|
|
6366
|
-
/* @__PURE__ */
|
|
6367
|
-
/* @__PURE__ */
|
|
6368
|
-
/* @__PURE__ */
|
|
6369
|
-
/* @__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." })
|
|
6370
6610
|
] }),
|
|
6371
|
-
/* @__PURE__ */
|
|
6372
|
-
/* @__PURE__ */
|
|
6373
|
-
/* @__PURE__ */
|
|
6374
|
-
/* @__PURE__ */
|
|
6375
|
-
/* @__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: [
|
|
6376
6616
|
draft.title || "No title set",
|
|
6377
6617
|
" \xB7 ",
|
|
6378
6618
|
user.team || "No team"
|
|
6379
6619
|
] }),
|
|
6380
|
-
/* @__PURE__ */
|
|
6381
|
-
session.roles.map((r) => /* @__PURE__ */
|
|
6382
|
-
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
|
|
6383
6623
|
] })
|
|
6384
6624
|
] }),
|
|
6385
|
-
/* @__PURE__ */
|
|
6625
|
+
/* @__PURE__ */ jsx57(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
|
|
6386
6626
|
] }) }),
|
|
6387
|
-
/* @__PURE__ */
|
|
6627
|
+
/* @__PURE__ */ jsx57(
|
|
6388
6628
|
Card,
|
|
6389
6629
|
{
|
|
6390
|
-
title: /* @__PURE__ */
|
|
6391
|
-
/* @__PURE__ */
|
|
6392
|
-
/* @__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" })
|
|
6393
6633
|
] }),
|
|
6394
6634
|
elevation: "flat",
|
|
6395
|
-
children: /* @__PURE__ */
|
|
6396
|
-
/* @__PURE__ */
|
|
6397
|
-
/* @__PURE__ */
|
|
6398
|
-
/* @__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" })
|
|
6399
6639
|
] }),
|
|
6400
|
-
/* @__PURE__ */
|
|
6401
|
-
/* @__PURE__ */
|
|
6640
|
+
/* @__PURE__ */ jsxs52("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
|
|
6641
|
+
/* @__PURE__ */ jsx57(
|
|
6402
6642
|
Input,
|
|
6403
6643
|
{
|
|
6404
6644
|
label: "Work email",
|
|
@@ -6408,9 +6648,9 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6408
6648
|
help: user.sso ? "Managed by your identity provider \u2014 change it there." : "Contact an administrator to change this."
|
|
6409
6649
|
}
|
|
6410
6650
|
),
|
|
6411
|
-
/* @__PURE__ */
|
|
6651
|
+
/* @__PURE__ */ jsx57(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
|
|
6412
6652
|
] }),
|
|
6413
|
-
/* @__PURE__ */
|
|
6653
|
+
/* @__PURE__ */ jsx57(
|
|
6414
6654
|
Textarea,
|
|
6415
6655
|
{
|
|
6416
6656
|
label: "Short bio",
|
|
@@ -6424,8 +6664,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6424
6664
|
] })
|
|
6425
6665
|
}
|
|
6426
6666
|
),
|
|
6427
|
-
/* @__PURE__ */
|
|
6428
|
-
/* @__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(
|
|
6429
6669
|
Select,
|
|
6430
6670
|
{
|
|
6431
6671
|
label: "Time zone",
|
|
@@ -6435,28 +6675,28 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6435
6675
|
help: "Flight dates and schedules render in this zone."
|
|
6436
6676
|
}
|
|
6437
6677
|
),
|
|
6438
|
-
/* @__PURE__ */
|
|
6678
|
+
/* @__PURE__ */ jsx57(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
|
|
6439
6679
|
] }) }),
|
|
6440
|
-
/* @__PURE__ */
|
|
6680
|
+
/* @__PURE__ */ jsx57(
|
|
6441
6681
|
Card,
|
|
6442
6682
|
{
|
|
6443
|
-
title: /* @__PURE__ */
|
|
6444
|
-
/* @__PURE__ */
|
|
6445
|
-
/* @__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" })
|
|
6446
6686
|
] }),
|
|
6447
6687
|
elevation: "flat",
|
|
6448
|
-
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)) })
|
|
6449
6689
|
}
|
|
6450
6690
|
),
|
|
6451
|
-
/* @__PURE__ */
|
|
6691
|
+
/* @__PURE__ */ jsxs52(
|
|
6452
6692
|
Card,
|
|
6453
6693
|
{
|
|
6454
|
-
title: /* @__PURE__ */
|
|
6455
|
-
/* @__PURE__ */
|
|
6456
|
-
/* @__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" })
|
|
6457
6697
|
] }),
|
|
6458
6698
|
elevation: "flat",
|
|
6459
|
-
action: /* @__PURE__ */
|
|
6699
|
+
action: /* @__PURE__ */ jsx57(
|
|
6460
6700
|
Button,
|
|
6461
6701
|
{
|
|
6462
6702
|
size: "sm",
|
|
@@ -6467,39 +6707,39 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6467
6707
|
}
|
|
6468
6708
|
),
|
|
6469
6709
|
children: [
|
|
6470
|
-
/* @__PURE__ */
|
|
6471
|
-
/* @__PURE__ */
|
|
6472
|
-
/* @__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: [
|
|
6473
6713
|
session.permissions.length,
|
|
6474
6714
|
" granted"
|
|
6475
6715
|
] }),
|
|
6476
|
-
/* @__PURE__ */
|
|
6716
|
+
/* @__PURE__ */ jsx57(CardRow, { label: "Member since", children: user.joined || "\u2014" })
|
|
6477
6717
|
] }),
|
|
6478
|
-
/* @__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." })
|
|
6479
6719
|
]
|
|
6480
6720
|
}
|
|
6481
6721
|
),
|
|
6482
|
-
showSessions ? /* @__PURE__ */
|
|
6722
|
+
showSessions ? /* @__PURE__ */ jsx57(
|
|
6483
6723
|
Card,
|
|
6484
6724
|
{
|
|
6485
6725
|
title: "Signed-in devices",
|
|
6486
6726
|
elevation: "flat",
|
|
6487
|
-
action: /* @__PURE__ */
|
|
6488
|
-
children: /* @__PURE__ */
|
|
6489
|
-
/* @__PURE__ */
|
|
6490
|
-
/* @__PURE__ */
|
|
6491
|
-
/* @__PURE__ */
|
|
6492
|
-
/* @__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: [
|
|
6493
6733
|
s.where,
|
|
6494
6734
|
" \xB7 ",
|
|
6495
6735
|
s.when
|
|
6496
6736
|
] })
|
|
6497
6737
|
] }),
|
|
6498
|
-
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" })
|
|
6499
6739
|
] }, s.id)) })
|
|
6500
6740
|
}
|
|
6501
6741
|
) : null,
|
|
6502
|
-
/* @__PURE__ */
|
|
6742
|
+
/* @__PURE__ */ jsxs52("div", { className: "fd-row", style: {
|
|
6503
6743
|
gap: 10,
|
|
6504
6744
|
flexWrap: "wrap",
|
|
6505
6745
|
position: "sticky",
|
|
@@ -6510,8 +6750,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6510
6750
|
border: "1px solid var(--border)",
|
|
6511
6751
|
boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
|
|
6512
6752
|
}, children: [
|
|
6513
|
-
/* @__PURE__ */
|
|
6514
|
-
/* @__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(
|
|
6515
6755
|
Button,
|
|
6516
6756
|
{
|
|
6517
6757
|
size: "sm",
|
|
@@ -6524,16 +6764,16 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6524
6764
|
children: "Discard"
|
|
6525
6765
|
}
|
|
6526
6766
|
),
|
|
6527
|
-
/* @__PURE__ */
|
|
6767
|
+
/* @__PURE__ */ jsx57(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
|
|
6528
6768
|
] })
|
|
6529
6769
|
] });
|
|
6530
6770
|
}
|
|
6531
6771
|
|
|
6532
6772
|
// src/components/platform/RoadmapTimeline.tsx
|
|
6533
|
-
import * as
|
|
6773
|
+
import * as React31 from "react";
|
|
6534
6774
|
|
|
6535
6775
|
// src/kits/runtime.ts
|
|
6536
|
-
import * as
|
|
6776
|
+
import * as React30 from "react";
|
|
6537
6777
|
var WIRED_ENDPOINTS = [
|
|
6538
6778
|
// Nothing yet. Every id below would come from a real service:
|
|
6539
6779
|
// "plan.get", "placements.list", …
|
|
@@ -6704,8 +6944,8 @@ var RuntimeKit = {
|
|
|
6704
6944
|
};
|
|
6705
6945
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
6706
6946
|
function useRuntimeMode() {
|
|
6707
|
-
const [m, setM] =
|
|
6708
|
-
|
|
6947
|
+
const [m, setM] = React30.useState(RuntimeKit.getMode());
|
|
6948
|
+
React30.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
6709
6949
|
return m;
|
|
6710
6950
|
}
|
|
6711
6951
|
function useFeatureStatus(key) {
|
|
@@ -6724,7 +6964,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
6724
6964
|
var UseFeatureStatus = useFeatureStatus;
|
|
6725
6965
|
|
|
6726
6966
|
// src/components/platform/RoadmapTimeline.tsx
|
|
6727
|
-
import { jsx as
|
|
6967
|
+
import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
6728
6968
|
var STATUS = {
|
|
6729
6969
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
6730
6970
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -6739,45 +6979,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
6739
6979
|
const s = STATUS[item.status] || STATUS.planned;
|
|
6740
6980
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
6741
6981
|
const blocking = deps.filter((d) => !d.implemented);
|
|
6742
|
-
return /* @__PURE__ */
|
|
6743
|
-
/* @__PURE__ */
|
|
6744
|
-
/* @__PURE__ */
|
|
6745
|
-
/* @__PURE__ */
|
|
6746
|
-
/* @__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 })
|
|
6747
6987
|
] }),
|
|
6748
|
-
/* @__PURE__ */
|
|
6749
|
-
item.backend ? /* @__PURE__ */
|
|
6750
|
-
/* @__PURE__ */
|
|
6751
|
-
/* @__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 })
|
|
6752
6992
|
] }) : null,
|
|
6753
|
-
/* @__PURE__ */
|
|
6754
|
-
item.effort ? /* @__PURE__ */
|
|
6755
|
-
/* @__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" }),
|
|
6756
6996
|
" ",
|
|
6757
6997
|
item.effort
|
|
6758
6998
|
] }) : null,
|
|
6759
|
-
/* @__PURE__ */
|
|
6760
|
-
/* @__PURE__ */
|
|
6999
|
+
/* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
|
|
7000
|
+
/* @__PURE__ */ jsx58("i", { className: "ph ph-user" }),
|
|
6761
7001
|
" ",
|
|
6762
7002
|
item.owner
|
|
6763
7003
|
] }),
|
|
6764
|
-
item.screen ? /* @__PURE__ */
|
|
6765
|
-
/* @__PURE__ */
|
|
6766
|
-
/* @__PURE__ */
|
|
7004
|
+
item.screen ? /* @__PURE__ */ jsx58(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
7005
|
+
/* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
|
|
7006
|
+
/* @__PURE__ */ jsx58(
|
|
6767
7007
|
"button",
|
|
6768
7008
|
{
|
|
6769
7009
|
type: "button",
|
|
6770
7010
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
6771
7011
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
6772
|
-
children: /* @__PURE__ */
|
|
7012
|
+
children: /* @__PURE__ */ jsx58("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
6773
7013
|
}
|
|
6774
7014
|
)
|
|
6775
7015
|
] }),
|
|
6776
|
-
deps.length ? /* @__PURE__ */
|
|
6777
|
-
/* @__PURE__ */
|
|
6778
|
-
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))
|
|
6779
7019
|
] }) : null,
|
|
6780
|
-
blocking.length && !item.implemented ? /* @__PURE__ */
|
|
7020
|
+
blocking.length && !item.implemented ? /* @__PURE__ */ jsxs53("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
6781
7021
|
"Blocked until ",
|
|
6782
7022
|
blocking.map((d) => d.label).join(" and "),
|
|
6783
7023
|
" ",
|
|
@@ -6788,12 +7028,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
6788
7028
|
}
|
|
6789
7029
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
6790
7030
|
const session = SessionKit.useSession();
|
|
6791
|
-
const [project, setProject] =
|
|
6792
|
-
const [q, setQ] =
|
|
6793
|
-
const scrollRef =
|
|
6794
|
-
const nowRef =
|
|
6795
|
-
const rm =
|
|
6796
|
-
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(() => {
|
|
6797
7037
|
const m = {};
|
|
6798
7038
|
rm.items.forEach((i) => {
|
|
6799
7039
|
m[i.key] = i;
|
|
@@ -6802,7 +7042,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6802
7042
|
}, [rm]);
|
|
6803
7043
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
6804
7044
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
6805
|
-
|
|
7045
|
+
React31.useEffect(() => {
|
|
6806
7046
|
let raf1 = 0, raf2 = 0;
|
|
6807
7047
|
const place = () => {
|
|
6808
7048
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -6830,23 +7070,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6830
7070
|
}, 0);
|
|
6831
7071
|
const nextPhase = items.find((i) => !i.implemented);
|
|
6832
7072
|
let lastPhase = null;
|
|
6833
|
-
return /* @__PURE__ */
|
|
6834
|
-
/* @__PURE__ */
|
|
6835
|
-
/* @__PURE__ */
|
|
6836
|
-
/* @__PURE__ */
|
|
6837
|
-
/* @__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." })
|
|
6838
7078
|
] }),
|
|
6839
|
-
/* @__PURE__ */
|
|
6840
|
-
/* @__PURE__ */
|
|
6841
|
-
/* @__PURE__ */
|
|
6842
|
-
/* @__PURE__ */
|
|
6843
|
-
/* @__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" })
|
|
6844
7084
|
] }),
|
|
6845
|
-
/* @__PURE__ */
|
|
6846
|
-
/* @__PURE__ */
|
|
6847
|
-
/* @__PURE__ */
|
|
6848
|
-
/* @__PURE__ */
|
|
6849
|
-
/* @__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(
|
|
6850
7090
|
Button,
|
|
6851
7091
|
{
|
|
6852
7092
|
size: "sm",
|
|
@@ -6860,7 +7100,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6860
7100
|
}
|
|
6861
7101
|
)
|
|
6862
7102
|
] }),
|
|
6863
|
-
/* @__PURE__ */
|
|
7103
|
+
/* @__PURE__ */ jsx58(
|
|
6864
7104
|
Flag,
|
|
6865
7105
|
{
|
|
6866
7106
|
tone: "info",
|
|
@@ -6869,60 +7109,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
6869
7109
|
actions: null
|
|
6870
7110
|
}
|
|
6871
7111
|
),
|
|
6872
|
-
/* @__PURE__ */
|
|
6873
|
-
/* @__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%" } }) }),
|
|
6874
7114
|
items.map((item, n) => {
|
|
6875
7115
|
const showPhase = item.phase !== lastPhase;
|
|
6876
7116
|
lastPhase = item.phase;
|
|
6877
7117
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
6878
7118
|
const isBoundary = n === firstPending;
|
|
6879
|
-
return /* @__PURE__ */
|
|
6880
|
-
showPhase ? /* @__PURE__ */
|
|
6881
|
-
/* @__PURE__ */
|
|
6882
|
-
/* @__PURE__ */
|
|
6883
|
-
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: [
|
|
6884
7124
|
fmtDate(item.phaseStart),
|
|
6885
7125
|
" \u2013 ",
|
|
6886
7126
|
fmtDate(item.date)
|
|
6887
7127
|
] }),
|
|
6888
|
-
/* @__PURE__ */
|
|
7128
|
+
/* @__PURE__ */ jsxs53("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
6889
7129
|
"\xB7 ",
|
|
6890
7130
|
inPhase,
|
|
6891
7131
|
" feature",
|
|
6892
7132
|
inPhase === 1 ? "" : "s"
|
|
6893
7133
|
] })
|
|
6894
7134
|
] }),
|
|
6895
|
-
item.phaseWhy ? /* @__PURE__ */
|
|
7135
|
+
item.phaseWhy ? /* @__PURE__ */ jsx58("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
6896
7136
|
] }) : null,
|
|
6897
|
-
isBoundary ? /* @__PURE__ */
|
|
6898
|
-
/* @__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" }),
|
|
6899
7139
|
" You are here \u2014 everything above is wired"
|
|
6900
7140
|
] }) }) : null,
|
|
6901
|
-
/* @__PURE__ */
|
|
6902
|
-
/* @__PURE__ */
|
|
6903
|
-
/* @__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: [
|
|
6904
7144
|
fmtDate(item.date),
|
|
6905
|
-
/* @__PURE__ */
|
|
6906
|
-
/* @__PURE__ */
|
|
7145
|
+
/* @__PURE__ */ jsx58("br", {}),
|
|
7146
|
+
/* @__PURE__ */ jsx58("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
6907
7147
|
] }),
|
|
6908
|
-
/* @__PURE__ */
|
|
7148
|
+
/* @__PURE__ */ jsx58(RoadmapCard, { item, byKey, onOpenFlag })
|
|
6909
7149
|
] })
|
|
6910
7150
|
] }, item.key);
|
|
6911
7151
|
}),
|
|
6912
|
-
!items.length ? /* @__PURE__ */
|
|
7152
|
+
!items.length ? /* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
6913
7153
|
] }) }) }),
|
|
6914
|
-
/* @__PURE__ */
|
|
7154
|
+
/* @__PURE__ */ jsxs53("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
6915
7155
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
6916
|
-
/* @__PURE__ */
|
|
7156
|
+
/* @__PURE__ */ jsx58("code", { className: "fd-mono", children: "implemented" }),
|
|
6917
7157
|
" field, so this page cannot drift from what the apps actually do."
|
|
6918
7158
|
] })
|
|
6919
7159
|
] });
|
|
6920
7160
|
}
|
|
6921
7161
|
|
|
6922
7162
|
// src/components/platform/ComingSoon.tsx
|
|
6923
|
-
import * as
|
|
7163
|
+
import * as React32 from "react";
|
|
6924
7164
|
import { createPortal as createPortal7 } from "react-dom";
|
|
6925
|
-
import { Fragment as Fragment13, jsx as
|
|
7165
|
+
import { Fragment as Fragment13, jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
6926
7166
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
6927
7167
|
function readBypassed() {
|
|
6928
7168
|
try {
|
|
@@ -6938,8 +7178,8 @@ function writeBypassed(list) {
|
|
|
6938
7178
|
}
|
|
6939
7179
|
}
|
|
6940
7180
|
function useBypass(key) {
|
|
6941
|
-
const [on, setOn] =
|
|
6942
|
-
|
|
7181
|
+
const [on, setOn] = React32.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
7182
|
+
React32.useEffect(() => {
|
|
6943
7183
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
6944
7184
|
}, [key]);
|
|
6945
7185
|
const set = (next) => {
|
|
@@ -6952,43 +7192,43 @@ function useBypass(key) {
|
|
|
6952
7192
|
return [on, set];
|
|
6953
7193
|
}
|
|
6954
7194
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
6955
|
-
return /* @__PURE__ */
|
|
6956
|
-
/* @__PURE__ */
|
|
6957
|
-
/* @__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" }),
|
|
6958
7198
|
label
|
|
6959
7199
|
] }),
|
|
6960
|
-
detail ? /* @__PURE__ */
|
|
6961
|
-
backend ? /* @__PURE__ */
|
|
6962
|
-
/* @__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" }),
|
|
6963
7203
|
" ",
|
|
6964
7204
|
backend
|
|
6965
7205
|
] }) : null,
|
|
6966
|
-
eta || effort || onRoadmap ? /* @__PURE__ */
|
|
6967
|
-
eta ? /* @__PURE__ */
|
|
6968
|
-
/* @__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" }),
|
|
6969
7209
|
" ",
|
|
6970
7210
|
eta
|
|
6971
7211
|
] }) : null,
|
|
6972
|
-
effort ? /* @__PURE__ */
|
|
6973
|
-
/* @__PURE__ */
|
|
7212
|
+
effort ? /* @__PURE__ */ jsxs54("span", { children: [
|
|
7213
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
6974
7214
|
" ",
|
|
6975
7215
|
effort
|
|
6976
7216
|
] }) : null,
|
|
6977
|
-
onRoadmap ? /* @__PURE__ */
|
|
7217
|
+
onRoadmap ? /* @__PURE__ */ jsxs54("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
6978
7218
|
"See the roadmap ",
|
|
6979
|
-
/* @__PURE__ */
|
|
7219
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
6980
7220
|
] }) : null
|
|
6981
7221
|
] }) : null,
|
|
6982
|
-
allowed ? /* @__PURE__ */
|
|
6983
|
-
/* @__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" }),
|
|
6984
7224
|
" View and use it anyway"
|
|
6985
7225
|
] }) : null
|
|
6986
7226
|
] });
|
|
6987
7227
|
}
|
|
6988
7228
|
function useHoverCard(open) {
|
|
6989
|
-
const anchor =
|
|
6990
|
-
const [pos, setPos] =
|
|
6991
|
-
|
|
7229
|
+
const anchor = React32.useRef(null);
|
|
7230
|
+
const [pos, setPos] = React32.useState(null);
|
|
7231
|
+
React32.useLayoutEffect(() => {
|
|
6992
7232
|
if (!open || !anchor.current) {
|
|
6993
7233
|
setPos(null);
|
|
6994
7234
|
return;
|
|
@@ -7040,9 +7280,9 @@ function ComingSoon({
|
|
|
7040
7280
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
7041
7281
|
if (inline) {
|
|
7042
7282
|
if (allowed && bypassed) {
|
|
7043
|
-
return /* @__PURE__ */
|
|
7283
|
+
return /* @__PURE__ */ jsxs54("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
7044
7284
|
children,
|
|
7045
|
-
/* @__PURE__ */
|
|
7285
|
+
/* @__PURE__ */ jsx59(
|
|
7046
7286
|
"button",
|
|
7047
7287
|
{
|
|
7048
7288
|
type: "button",
|
|
@@ -7050,12 +7290,12 @@ function ComingSoon({
|
|
|
7050
7290
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
7051
7291
|
onClick: () => setBypassed(false),
|
|
7052
7292
|
"aria-label": "Re-blur this unwired feature",
|
|
7053
|
-
children: /* @__PURE__ */
|
|
7293
|
+
children: /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7054
7294
|
}
|
|
7055
7295
|
)
|
|
7056
7296
|
] });
|
|
7057
7297
|
}
|
|
7058
|
-
return /* @__PURE__ */
|
|
7298
|
+
return /* @__PURE__ */ jsx59(
|
|
7059
7299
|
InlineSoon,
|
|
7060
7300
|
{
|
|
7061
7301
|
label,
|
|
@@ -7075,20 +7315,20 @@ function ComingSoon({
|
|
|
7075
7315
|
);
|
|
7076
7316
|
}
|
|
7077
7317
|
if (allowed && bypassed) {
|
|
7078
|
-
return /* @__PURE__ */
|
|
7079
|
-
/* @__PURE__ */
|
|
7080
|
-
/* @__PURE__ */
|
|
7081
|
-
/* @__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" }),
|
|
7082
7322
|
"Unwired feature \u2014 you are using it anyway"
|
|
7083
7323
|
] }),
|
|
7084
|
-
/* @__PURE__ */
|
|
7085
|
-
/* @__PURE__ */
|
|
7086
|
-
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: [
|
|
7087
7327
|
"Roadmap ",
|
|
7088
|
-
/* @__PURE__ */
|
|
7328
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
7089
7329
|
] }) : null,
|
|
7090
|
-
/* @__PURE__ */
|
|
7091
|
-
/* @__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" }),
|
|
7092
7332
|
" Re-blur"
|
|
7093
7333
|
] })
|
|
7094
7334
|
] })
|
|
@@ -7096,10 +7336,10 @@ function ComingSoon({
|
|
|
7096
7336
|
children
|
|
7097
7337
|
] });
|
|
7098
7338
|
}
|
|
7099
|
-
return /* @__PURE__ */
|
|
7100
|
-
/* @__PURE__ */
|
|
7101
|
-
/* @__PURE__ */
|
|
7102
|
-
/* @__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(
|
|
7103
7343
|
SoonCard,
|
|
7104
7344
|
{
|
|
7105
7345
|
label,
|
|
@@ -7115,9 +7355,9 @@ function ComingSoon({
|
|
|
7115
7355
|
] });
|
|
7116
7356
|
}
|
|
7117
7357
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
7118
|
-
const [open, setOpen] =
|
|
7358
|
+
const [open, setOpen] = React32.useState(false);
|
|
7119
7359
|
const [anchor, pos] = useHoverCard(open);
|
|
7120
|
-
const close =
|
|
7360
|
+
const close = React32.useRef(null);
|
|
7121
7361
|
const show = () => {
|
|
7122
7362
|
if (close.current) {
|
|
7123
7363
|
clearTimeout(close.current);
|
|
@@ -7133,10 +7373,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7133
7373
|
setOpen(false);
|
|
7134
7374
|
}, 140);
|
|
7135
7375
|
};
|
|
7136
|
-
|
|
7376
|
+
React32.useEffect(() => () => {
|
|
7137
7377
|
if (close.current) clearTimeout(close.current);
|
|
7138
7378
|
}, []);
|
|
7139
|
-
return /* @__PURE__ */
|
|
7379
|
+
return /* @__PURE__ */ jsxs54(
|
|
7140
7380
|
"span",
|
|
7141
7381
|
{
|
|
7142
7382
|
ref: anchor,
|
|
@@ -7147,8 +7387,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7147
7387
|
onBlur: hide,
|
|
7148
7388
|
...rest,
|
|
7149
7389
|
children: [
|
|
7150
|
-
/* @__PURE__ */
|
|
7151
|
-
/* @__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(
|
|
7152
7392
|
"button",
|
|
7153
7393
|
{
|
|
7154
7394
|
type: "button",
|
|
@@ -7159,11 +7399,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7159
7399
|
onFocus: show,
|
|
7160
7400
|
onBlur: hide,
|
|
7161
7401
|
onClick: () => open ? setOpen(false) : show(),
|
|
7162
|
-
children: /* @__PURE__ */
|
|
7402
|
+
children: /* @__PURE__ */ jsx59("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7163
7403
|
}
|
|
7164
7404
|
),
|
|
7165
7405
|
open && pos ? createPortal7(
|
|
7166
|
-
/* @__PURE__ */
|
|
7406
|
+
/* @__PURE__ */ jsx59(
|
|
7167
7407
|
"div",
|
|
7168
7408
|
{
|
|
7169
7409
|
className: "fd-soon-note fd-soon-hovercard",
|
|
@@ -7171,7 +7411,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7171
7411
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width },
|
|
7172
7412
|
onMouseEnter: show,
|
|
7173
7413
|
onMouseLeave: hide,
|
|
7174
|
-
children: /* @__PURE__ */
|
|
7414
|
+
children: /* @__PURE__ */ jsx59(
|
|
7175
7415
|
SoonCard,
|
|
7176
7416
|
{
|
|
7177
7417
|
label,
|
|
@@ -7201,10 +7441,10 @@ function formatEta(iso2) {
|
|
|
7201
7441
|
var FormatEta = formatEta;
|
|
7202
7442
|
|
|
7203
7443
|
// src/components/platform/Gate.tsx
|
|
7204
|
-
import { jsx as
|
|
7444
|
+
import { jsx as jsx60, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
7205
7445
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
7206
7446
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
7207
|
-
return /* @__PURE__ */
|
|
7447
|
+
return /* @__PURE__ */ jsxs55(
|
|
7208
7448
|
"div",
|
|
7209
7449
|
{
|
|
7210
7450
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -7220,14 +7460,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
7220
7460
|
},
|
|
7221
7461
|
...rest,
|
|
7222
7462
|
children: [
|
|
7223
|
-
/* @__PURE__ */
|
|
7224
|
-
/* @__PURE__ */
|
|
7225
|
-
/* @__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" })
|
|
7226
7466
|
] }),
|
|
7227
|
-
/* @__PURE__ */
|
|
7228
|
-
need.length ? /* @__PURE__ */
|
|
7229
|
-
/* @__PURE__ */
|
|
7230
|
-
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: {
|
|
7231
7471
|
fontSize: 11.5,
|
|
7232
7472
|
padding: "2px 7px",
|
|
7233
7473
|
borderRadius: 5,
|
|
@@ -7248,7 +7488,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
|
|
|
7248
7488
|
if (ok) return children;
|
|
7249
7489
|
if (fallback !== void 0) return fallback;
|
|
7250
7490
|
if (silent) return null;
|
|
7251
|
-
return /* @__PURE__ */
|
|
7491
|
+
return /* @__PURE__ */ jsx60(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
7252
7492
|
}
|
|
7253
7493
|
function FeatureGate({
|
|
7254
7494
|
flag,
|
|
@@ -7269,7 +7509,7 @@ function FeatureGate({
|
|
|
7269
7509
|
if (!preview) return fallback;
|
|
7270
7510
|
const f = SessionKit.findFlag(flag) || {};
|
|
7271
7511
|
const missing = rt.missing || [];
|
|
7272
|
-
return /* @__PURE__ */
|
|
7512
|
+
return /* @__PURE__ */ jsx60(
|
|
7273
7513
|
ComingSoon,
|
|
7274
7514
|
{
|
|
7275
7515
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -7290,25 +7530,25 @@ function FeatureGate({
|
|
|
7290
7530
|
function PermissionHint({ perm, children }) {
|
|
7291
7531
|
SessionKit.useSession();
|
|
7292
7532
|
if (SessionKit.can(perm)) return children;
|
|
7293
|
-
return /* @__PURE__ */
|
|
7533
|
+
return /* @__PURE__ */ jsx60(
|
|
7294
7534
|
"span",
|
|
7295
7535
|
{
|
|
7296
7536
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
7297
7537
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
7298
7538
|
"aria-disabled": "true",
|
|
7299
|
-
children: /* @__PURE__ */
|
|
7539
|
+
children: /* @__PURE__ */ jsx60("span", { style: { pointerEvents: "none" }, children })
|
|
7300
7540
|
}
|
|
7301
7541
|
);
|
|
7302
7542
|
}
|
|
7303
7543
|
|
|
7304
7544
|
// src/components/platform/ModeSwitch.tsx
|
|
7305
|
-
import * as
|
|
7306
|
-
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";
|
|
7307
7547
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
7308
7548
|
const mode2 = useRuntimeMode();
|
|
7309
|
-
const [open, setOpen] =
|
|
7310
|
-
const ref =
|
|
7311
|
-
|
|
7549
|
+
const [open, setOpen] = React33.useState(false);
|
|
7550
|
+
const ref = React33.useRef(null);
|
|
7551
|
+
React33.useEffect(() => {
|
|
7312
7552
|
if (!open) return;
|
|
7313
7553
|
const away = (e) => {
|
|
7314
7554
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -7330,8 +7570,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7330
7570
|
RuntimeKit.setMode(next);
|
|
7331
7571
|
setOpen(false);
|
|
7332
7572
|
};
|
|
7333
|
-
return /* @__PURE__ */
|
|
7334
|
-
/* @__PURE__ */
|
|
7573
|
+
return /* @__PURE__ */ jsxs56("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
|
|
7574
|
+
/* @__PURE__ */ jsxs56(
|
|
7335
7575
|
"button",
|
|
7336
7576
|
{
|
|
7337
7577
|
type: "button",
|
|
@@ -7341,29 +7581,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7341
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.",
|
|
7342
7582
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
|
|
7343
7583
|
children: [
|
|
7344
|
-
/* @__PURE__ */
|
|
7345
|
-
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
|
|
7346
7586
|
]
|
|
7347
7587
|
}
|
|
7348
7588
|
),
|
|
7349
|
-
open ? /* @__PURE__ */
|
|
7350
|
-
/* @__PURE__ */
|
|
7351
|
-
/* @__PURE__ */
|
|
7352
|
-
/* @__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" }),
|
|
7353
7593
|
test ? "Test mode" : "Live mode"
|
|
7354
7594
|
] }),
|
|
7355
|
-
test ? /* @__PURE__ */
|
|
7595
|
+
test ? /* @__PURE__ */ jsxs56("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
7356
7596
|
requestCount,
|
|
7357
7597
|
" simulated request",
|
|
7358
7598
|
requestCount === 1 ? "" : "s"
|
|
7359
7599
|
] }) : null,
|
|
7360
|
-
/* @__PURE__ */
|
|
7361
|
-
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
|
|
7362
7602
|
] }),
|
|
7363
|
-
/* @__PURE__ */
|
|
7364
|
-
/* @__PURE__ */
|
|
7365
|
-
/* @__PURE__ */
|
|
7366
|
-
/* @__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: [
|
|
7367
7607
|
s.endpointsWired,
|
|
7368
7608
|
" endpoint",
|
|
7369
7609
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -7373,58 +7613,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7373
7613
|
s.total,
|
|
7374
7614
|
" features complete"
|
|
7375
7615
|
] }),
|
|
7376
|
-
onOpenSpec ? /* @__PURE__ */
|
|
7377
|
-
/* @__PURE__ */
|
|
7378
|
-
/* @__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: () => {
|
|
7379
7619
|
setOpen(false);
|
|
7380
7620
|
onOpenSpec();
|
|
7381
7621
|
}, children: [
|
|
7382
7622
|
"API spec ",
|
|
7383
|
-
/* @__PURE__ */
|
|
7623
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
7384
7624
|
] })
|
|
7385
7625
|
] }) : null
|
|
7386
7626
|
] })
|
|
7387
7627
|
] }),
|
|
7388
|
-
/* @__PURE__ */
|
|
7389
|
-
/* @__PURE__ */
|
|
7390
|
-
/* @__PURE__ */
|
|
7391
|
-
/* @__PURE__ */
|
|
7392
|
-
/* @__PURE__ */
|
|
7393
|
-
/* @__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" })
|
|
7394
7634
|
] }),
|
|
7395
|
-
!test ? /* @__PURE__ */
|
|
7635
|
+
!test ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
7396
7636
|
] }),
|
|
7397
|
-
/* @__PURE__ */
|
|
7398
|
-
/* @__PURE__ */
|
|
7399
|
-
/* @__PURE__ */
|
|
7400
|
-
/* @__PURE__ */
|
|
7401
|
-
/* @__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" })
|
|
7402
7642
|
] }),
|
|
7403
|
-
test ? /* @__PURE__ */
|
|
7643
|
+
test ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
7404
7644
|
] })
|
|
7405
7645
|
] }),
|
|
7406
|
-
test && renderLog ? /* @__PURE__ */
|
|
7646
|
+
test && renderLog ? /* @__PURE__ */ jsx61("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
7407
7647
|
] }) : null
|
|
7408
7648
|
] });
|
|
7409
7649
|
}
|
|
7410
7650
|
function TestModeBar({ onExit }) {
|
|
7411
7651
|
const mode2 = useRuntimeMode();
|
|
7412
7652
|
if (mode2 !== "test") return null;
|
|
7413
|
-
return /* @__PURE__ */
|
|
7414
|
-
/* @__PURE__ */
|
|
7415
|
-
/* @__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" }),
|
|
7416
7656
|
"Test mode"
|
|
7417
7657
|
] }),
|
|
7418
|
-
/* @__PURE__ */
|
|
7419
|
-
/* @__PURE__ */
|
|
7420
|
-
/* @__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" }),
|
|
7421
7661
|
" Back to live mode"
|
|
7422
7662
|
] })
|
|
7423
7663
|
] });
|
|
7424
7664
|
}
|
|
7425
7665
|
|
|
7426
7666
|
// src/components/planner/ChannelMeta.tsx
|
|
7427
|
-
import { jsx as
|
|
7667
|
+
import { jsx as jsx62, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
7428
7668
|
var CHANNEL_WEIGHTS = {
|
|
7429
7669
|
"OOH": 50,
|
|
7430
7670
|
"DOOH": 50,
|
|
@@ -7477,9 +7717,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
7477
7717
|
const m = ChannelMeta(channel);
|
|
7478
7718
|
const wt = channelWeightOf(channel || "");
|
|
7479
7719
|
if (dot) {
|
|
7480
|
-
return /* @__PURE__ */
|
|
7720
|
+
return /* @__PURE__ */ jsx62("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
7481
7721
|
}
|
|
7482
|
-
return /* @__PURE__ */
|
|
7722
|
+
return /* @__PURE__ */ jsxs57(
|
|
7483
7723
|
"span",
|
|
7484
7724
|
{
|
|
7485
7725
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -7487,16 +7727,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
7487
7727
|
style: { "--chan": m.color },
|
|
7488
7728
|
...rest,
|
|
7489
7729
|
children: [
|
|
7490
|
-
/* @__PURE__ */
|
|
7491
|
-
showLabel ? /* @__PURE__ */
|
|
7492
|
-
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
|
|
7493
7733
|
]
|
|
7494
7734
|
}
|
|
7495
7735
|
);
|
|
7496
7736
|
}
|
|
7497
7737
|
|
|
7498
7738
|
// src/components/planner/SaturationDistribution.tsx
|
|
7499
|
-
import { jsx as
|
|
7739
|
+
import { jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
7500
7740
|
var BANDS2 = [
|
|
7501
7741
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
7502
7742
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -7507,18 +7747,18 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7507
7747
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
7508
7748
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
7509
7749
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
7510
|
-
return /* @__PURE__ */
|
|
7511
|
-
/* @__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) => {
|
|
7512
7752
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
7513
7753
|
const active = selectedBand === g.key;
|
|
7514
|
-
return /* @__PURE__ */
|
|
7754
|
+
return /* @__PURE__ */ jsxs58(
|
|
7515
7755
|
"button",
|
|
7516
7756
|
{
|
|
7517
7757
|
type: "button",
|
|
7518
7758
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
7519
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)" },
|
|
7520
7760
|
children: [
|
|
7521
|
-
/* @__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(
|
|
7522
7762
|
"span",
|
|
7523
7763
|
{
|
|
7524
7764
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -7527,13 +7767,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7527
7767
|
},
|
|
7528
7768
|
c.name
|
|
7529
7769
|
)) }),
|
|
7530
|
-
/* @__PURE__ */
|
|
7531
|
-
/* @__PURE__ */
|
|
7532
|
-
/* @__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)) })
|
|
7533
7773
|
] }),
|
|
7534
|
-
/* @__PURE__ */
|
|
7535
|
-
/* @__PURE__ */
|
|
7536
|
-
/* @__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: [
|
|
7537
7777
|
"CRP ",
|
|
7538
7778
|
g.range
|
|
7539
7779
|
] })
|
|
@@ -7543,10 +7783,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7543
7783
|
g.key
|
|
7544
7784
|
);
|
|
7545
7785
|
}) }),
|
|
7546
|
-
floorBand ? /* @__PURE__ */
|
|
7547
|
-
/* @__PURE__ */
|
|
7548
|
-
/* @__PURE__ */
|
|
7549
|
-
/* @__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: [
|
|
7550
7790
|
"Plan floor ",
|
|
7551
7791
|
floorScore
|
|
7552
7792
|
] }),
|
|
@@ -7557,21 +7797,21 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
7557
7797
|
}
|
|
7558
7798
|
|
|
7559
7799
|
// src/components/planner/MixGap.tsx
|
|
7560
|
-
import * as
|
|
7561
|
-
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";
|
|
7562
7802
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
7563
7803
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
7564
|
-
const [hover, setHover] =
|
|
7804
|
+
const [hover, setHover] = React34.useState(null);
|
|
7565
7805
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
7566
7806
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
7567
|
-
return /* @__PURE__ */
|
|
7568
|
-
/* @__PURE__ */
|
|
7569
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */
|
|
7570
|
-
/* @__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 } }),
|
|
7571
7811
|
l
|
|
7572
7812
|
] }, l)),
|
|
7573
|
-
/* @__PURE__ */
|
|
7574
|
-
/* @__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)" } }),
|
|
7575
7815
|
"Target"
|
|
7576
7816
|
] })
|
|
7577
7817
|
] }),
|
|
@@ -7579,7 +7819,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
7579
7819
|
const gap = r.realized - r.target;
|
|
7580
7820
|
const tone = toneOf(gap);
|
|
7581
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 : "");
|
|
7582
|
-
return /* @__PURE__ */
|
|
7822
|
+
return /* @__PURE__ */ jsxs59(
|
|
7583
7823
|
"div",
|
|
7584
7824
|
{
|
|
7585
7825
|
className: "fd-row",
|
|
@@ -7587,15 +7827,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
7587
7827
|
onMouseEnter: () => setHover(r.channel),
|
|
7588
7828
|
onMouseLeave: () => setHover(null),
|
|
7589
7829
|
children: [
|
|
7590
|
-
/* @__PURE__ */
|
|
7591
|
-
/* @__PURE__ */
|
|
7592
|
-
/* @__PURE__ */
|
|
7593
|
-
/* @__PURE__ */
|
|
7594
|
-
/* @__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: [
|
|
7595
7835
|
r.realized,
|
|
7596
7836
|
"%"
|
|
7597
7837
|
] }),
|
|
7598
|
-
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
|
|
7599
7839
|
] }) })
|
|
7600
7840
|
]
|
|
7601
7841
|
},
|
|
@@ -7606,7 +7846,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
7606
7846
|
}
|
|
7607
7847
|
|
|
7608
7848
|
// src/components/planner/ChannelContribution.tsx
|
|
7609
|
-
import { jsx as
|
|
7849
|
+
import { jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
7610
7850
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
7611
7851
|
function ChannelContribution({
|
|
7612
7852
|
channels = [],
|
|
@@ -7622,9 +7862,9 @@ function ChannelContribution({
|
|
|
7622
7862
|
const grand = total !== void 0 ? total : base + bonus;
|
|
7623
7863
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
7624
7864
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
7625
|
-
return /* @__PURE__ */
|
|
7626
|
-
loading ? /* @__PURE__ */
|
|
7627
|
-
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(
|
|
7628
7868
|
"span",
|
|
7629
7869
|
{
|
|
7630
7870
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -7633,7 +7873,7 @@ function ChannelContribution({
|
|
|
7633
7873
|
},
|
|
7634
7874
|
c.name
|
|
7635
7875
|
)),
|
|
7636
|
-
bonus > 0 ? /* @__PURE__ */
|
|
7876
|
+
bonus > 0 ? /* @__PURE__ */ jsx65(
|
|
7637
7877
|
"span",
|
|
7638
7878
|
{
|
|
7639
7879
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -7642,18 +7882,18 @@ function ChannelContribution({
|
|
|
7642
7882
|
}
|
|
7643
7883
|
) : null
|
|
7644
7884
|
] }),
|
|
7645
|
-
showTable ? /* @__PURE__ */
|
|
7646
|
-
/* @__PURE__ */
|
|
7647
|
-
/* @__PURE__ */
|
|
7648
|
-
/* @__PURE__ */
|
|
7649
|
-
/* @__PURE__ */
|
|
7650
|
-
/* @__PURE__ */
|
|
7651
|
-
/* @__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" })
|
|
7652
7892
|
] }) }),
|
|
7653
|
-
/* @__PURE__ */
|
|
7654
|
-
channels.map((c) => /* @__PURE__ */
|
|
7655
|
-
/* @__PURE__ */
|
|
7656
|
-
/* @__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(
|
|
7657
7897
|
"span",
|
|
7658
7898
|
{
|
|
7659
7899
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -7662,38 +7902,38 @@ function ChannelContribution({
|
|
|
7662
7902
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
7663
7903
|
}
|
|
7664
7904
|
) }),
|
|
7665
|
-
/* @__PURE__ */
|
|
7666
|
-
/* @__PURE__ */
|
|
7667
|
-
/* @__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: [
|
|
7668
7908
|
pct(c.crp).toFixed(0),
|
|
7669
7909
|
"%"
|
|
7670
7910
|
] })
|
|
7671
7911
|
] }, c.name)),
|
|
7672
|
-
bonus > 0 ? /* @__PURE__ */
|
|
7673
|
-
/* @__PURE__ */
|
|
7674
|
-
/* @__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" } }),
|
|
7675
7915
|
"Surround-sound bonus"
|
|
7676
7916
|
] }) }),
|
|
7677
|
-
/* @__PURE__ */
|
|
7917
|
+
/* @__PURE__ */ jsx65("td", { children: /* @__PURE__ */ jsxs60("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
7678
7918
|
"+",
|
|
7679
7919
|
bonusPct,
|
|
7680
7920
|
"% of +",
|
|
7681
7921
|
bonusMax,
|
|
7682
7922
|
"%"
|
|
7683
7923
|
] }) }),
|
|
7684
|
-
/* @__PURE__ */
|
|
7685
|
-
/* @__PURE__ */
|
|
7686
|
-
/* @__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: [
|
|
7687
7927
|
pct(bonus).toFixed(0),
|
|
7688
7928
|
"%"
|
|
7689
7929
|
] })
|
|
7690
7930
|
] }) : null,
|
|
7691
|
-
/* @__PURE__ */
|
|
7692
|
-
/* @__PURE__ */
|
|
7693
|
-
/* @__PURE__ */
|
|
7694
|
-
/* @__PURE__ */
|
|
7695
|
-
/* @__PURE__ */
|
|
7696
|
-
/* @__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%" })
|
|
7697
7937
|
] })
|
|
7698
7938
|
] })
|
|
7699
7939
|
] }) : null
|
|
@@ -7701,8 +7941,8 @@ function ChannelContribution({
|
|
|
7701
7941
|
}
|
|
7702
7942
|
|
|
7703
7943
|
// src/components/planner/BudgetReallocator.tsx
|
|
7704
|
-
import * as
|
|
7705
|
-
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";
|
|
7706
7946
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
7707
7947
|
function BudgetReallocator({
|
|
7708
7948
|
campus,
|
|
@@ -7717,8 +7957,8 @@ function BudgetReallocator({
|
|
|
7717
7957
|
onCancel,
|
|
7718
7958
|
className = ""
|
|
7719
7959
|
}) {
|
|
7720
|
-
const [draft, setDraft] =
|
|
7721
|
-
|
|
7960
|
+
const [draft, setDraft] = React35.useState(spend);
|
|
7961
|
+
React35.useEffect(() => setDraft(spend), [spend]);
|
|
7722
7962
|
const dirty = draft !== spend;
|
|
7723
7963
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
7724
7964
|
const nextBand = bandFor(nextCrp);
|
|
@@ -7733,24 +7973,24 @@ function BudgetReallocator({
|
|
|
7733
7973
|
setDraft(spend);
|
|
7734
7974
|
if (onCancel) onCancel();
|
|
7735
7975
|
};
|
|
7736
|
-
return /* @__PURE__ */
|
|
7976
|
+
return /* @__PURE__ */ jsxs61(
|
|
7737
7977
|
"div",
|
|
7738
7978
|
{
|
|
7739
7979
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
7740
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)" },
|
|
7741
7981
|
children: [
|
|
7742
|
-
/* @__PURE__ */
|
|
7743
|
-
/* @__PURE__ */
|
|
7744
|
-
/* @__PURE__ */
|
|
7745
|
-
dirty ? /* @__PURE__ */
|
|
7746
|
-
/* @__PURE__ */
|
|
7747
|
-
/* @__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 })
|
|
7748
7988
|
] }) : null
|
|
7749
7989
|
] }),
|
|
7750
|
-
/* @__PURE__ */
|
|
7751
|
-
/* @__PURE__ */
|
|
7752
|
-
dirty ? /* @__PURE__ */
|
|
7753
|
-
/* @__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(
|
|
7754
7994
|
"input",
|
|
7755
7995
|
{
|
|
7756
7996
|
type: "range",
|
|
@@ -7766,13 +8006,13 @@ function BudgetReallocator({
|
|
|
7766
8006
|
}
|
|
7767
8007
|
)
|
|
7768
8008
|
] }),
|
|
7769
|
-
/* @__PURE__ */
|
|
7770
|
-
/* @__PURE__ */
|
|
7771
|
-
/* @__PURE__ */
|
|
7772
|
-
/* @__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." })
|
|
7773
8013
|
] }),
|
|
7774
|
-
/* @__PURE__ */
|
|
7775
|
-
/* @__PURE__ */
|
|
8014
|
+
/* @__PURE__ */ jsx66("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
8015
|
+
/* @__PURE__ */ jsx66(
|
|
7776
8016
|
"button",
|
|
7777
8017
|
{
|
|
7778
8018
|
type: "button",
|
|
@@ -7791,7 +8031,7 @@ function BudgetReallocator({
|
|
|
7791
8031
|
}
|
|
7792
8032
|
|
|
7793
8033
|
// src/components/planner/SurroundSound.tsx
|
|
7794
|
-
import { jsx as
|
|
8034
|
+
import { jsx as jsx67, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
7795
8035
|
var CATEGORIES = [
|
|
7796
8036
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
7797
8037
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -7803,26 +8043,26 @@ var CATEGORIES = [
|
|
|
7803
8043
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
7804
8044
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
7805
8045
|
const single = present.length <= 2;
|
|
7806
|
-
return /* @__PURE__ */
|
|
7807
|
-
/* @__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) => {
|
|
7808
8048
|
const on = present.includes(c.key);
|
|
7809
|
-
return /* @__PURE__ */
|
|
8049
|
+
return /* @__PURE__ */ jsxs62(
|
|
7810
8050
|
"span",
|
|
7811
8051
|
{
|
|
7812
8052
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
7813
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)" },
|
|
7814
8054
|
children: [
|
|
7815
|
-
/* @__PURE__ */
|
|
7816
|
-
/* @__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 })
|
|
7817
8057
|
]
|
|
7818
8058
|
},
|
|
7819
8059
|
c.key
|
|
7820
8060
|
);
|
|
7821
8061
|
}) }),
|
|
7822
|
-
/* @__PURE__ */
|
|
7823
|
-
/* @__PURE__ */
|
|
7824
|
-
/* @__PURE__ */
|
|
7825
|
-
/* @__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: [
|
|
7826
8066
|
"+",
|
|
7827
8067
|
bonusPct,
|
|
7828
8068
|
"% of +",
|
|
@@ -7830,8 +8070,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
7830
8070
|
"%"
|
|
7831
8071
|
] })
|
|
7832
8072
|
] }),
|
|
7833
|
-
/* @__PURE__ */
|
|
7834
|
-
/* @__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: [
|
|
7835
8075
|
present.length,
|
|
7836
8076
|
" of 6 channel categories present.",
|
|
7837
8077
|
" ",
|
|
@@ -7843,10 +8083,10 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
7843
8083
|
}
|
|
7844
8084
|
|
|
7845
8085
|
// src/components/chat/AgentChatPanel.tsx
|
|
7846
|
-
import * as
|
|
8086
|
+
import * as React41 from "react";
|
|
7847
8087
|
|
|
7848
8088
|
// src/components/chat/chatEngine.ts
|
|
7849
|
-
import * as
|
|
8089
|
+
import * as React36 from "react";
|
|
7850
8090
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
7851
8091
|
var JOB_PENDING = ["queued", "running"];
|
|
7852
8092
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -7900,22 +8140,22 @@ function useChatEngine(opts) {
|
|
|
7900
8140
|
onClear,
|
|
7901
8141
|
onFeedback
|
|
7902
8142
|
} = opts || {};
|
|
7903
|
-
const [status, setStatus] =
|
|
7904
|
-
const [threadId, setThreadId] =
|
|
7905
|
-
const [messages, setMessages] =
|
|
7906
|
-
const [queue, setQueue] =
|
|
7907
|
-
const [fatal, setFatal] =
|
|
7908
|
-
const [busy, setBusy] =
|
|
7909
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
7910
|
-
const listRef =
|
|
7911
|
-
const queueRef =
|
|
7912
|
-
const busyRef =
|
|
7913
|
-
const stoppedRef =
|
|
7914
|
-
const abortRef =
|
|
7915
|
-
const serverCount =
|
|
7916
|
-
const threadRef =
|
|
7917
|
-
const mounted =
|
|
7918
|
-
|
|
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(() => {
|
|
7919
8159
|
mounted.current = true;
|
|
7920
8160
|
return () => {
|
|
7921
8161
|
mounted.current = false;
|
|
@@ -7937,14 +8177,14 @@ function useChatEngine(opts) {
|
|
|
7937
8177
|
}
|
|
7938
8178
|
return false;
|
|
7939
8179
|
};
|
|
7940
|
-
const loadThread =
|
|
8180
|
+
const loadThread = React36.useCallback(async (id) => {
|
|
7941
8181
|
const data = await apiAdapter.getThread(id);
|
|
7942
8182
|
const list = [...data && data.messages || []];
|
|
7943
8183
|
serverCount.current = list.length;
|
|
7944
8184
|
commit(list);
|
|
7945
8185
|
return list;
|
|
7946
8186
|
}, [apiAdapter]);
|
|
7947
|
-
|
|
8187
|
+
React36.useEffect(() => {
|
|
7948
8188
|
if (!apiAdapter) {
|
|
7949
8189
|
setStatus("idle");
|
|
7950
8190
|
setFatal(null);
|
|
@@ -8157,7 +8397,7 @@ function useChatEngine(opts) {
|
|
|
8157
8397
|
await dispatchTurn(turn);
|
|
8158
8398
|
}
|
|
8159
8399
|
}
|
|
8160
|
-
const send =
|
|
8400
|
+
const send = React36.useCallback((text, attachments) => {
|
|
8161
8401
|
const body = (text || "").trim();
|
|
8162
8402
|
if (!body && !(attachments && attachments.length)) return;
|
|
8163
8403
|
if (status === "disconnected") return;
|
|
@@ -8167,7 +8407,7 @@ function useChatEngine(opts) {
|
|
|
8167
8407
|
stoppedRef.current = false;
|
|
8168
8408
|
drain();
|
|
8169
8409
|
}, [status]);
|
|
8170
|
-
const stop =
|
|
8410
|
+
const stop = React36.useCallback(() => {
|
|
8171
8411
|
stoppedRef.current = true;
|
|
8172
8412
|
const ac = abortRef.current;
|
|
8173
8413
|
if (ac) {
|
|
@@ -8186,11 +8426,11 @@ function useChatEngine(opts) {
|
|
|
8186
8426
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
8187
8427
|
}
|
|
8188
8428
|
}, [apiAdapter]);
|
|
8189
|
-
const removeQueued =
|
|
8429
|
+
const removeQueued = React36.useCallback((id) => {
|
|
8190
8430
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
8191
8431
|
setQueue(queueRef.current.slice());
|
|
8192
8432
|
}, []);
|
|
8193
|
-
const retry =
|
|
8433
|
+
const retry = React36.useCallback(() => {
|
|
8194
8434
|
const list = listRef.current;
|
|
8195
8435
|
let at = -1;
|
|
8196
8436
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -8206,19 +8446,19 @@ function useChatEngine(opts) {
|
|
|
8206
8446
|
setQueue(queueRef.current.slice());
|
|
8207
8447
|
drain();
|
|
8208
8448
|
}, []);
|
|
8209
|
-
const clear =
|
|
8449
|
+
const clear = React36.useCallback(() => {
|
|
8210
8450
|
commit([]);
|
|
8211
8451
|
serverCount.current = 0;
|
|
8212
8452
|
queueRef.current = [];
|
|
8213
8453
|
setQueue([]);
|
|
8214
8454
|
onClear && onClear();
|
|
8215
8455
|
}, [onClear]);
|
|
8216
|
-
const setFeedback =
|
|
8456
|
+
const setFeedback = React36.useCallback((id, value) => {
|
|
8217
8457
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
8218
8458
|
const msg = listRef.current.find((m) => m.id === id);
|
|
8219
8459
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
8220
8460
|
}, [onFeedback]);
|
|
8221
|
-
const reload =
|
|
8461
|
+
const reload = React36.useCallback(async () => {
|
|
8222
8462
|
if (!threadRef.current) return;
|
|
8223
8463
|
setStatus("loading");
|
|
8224
8464
|
try {
|
|
@@ -8256,11 +8496,11 @@ var ChatKit = {
|
|
|
8256
8496
|
};
|
|
8257
8497
|
|
|
8258
8498
|
// src/components/chat/ChatTranscript.tsx
|
|
8259
|
-
import * as
|
|
8499
|
+
import * as React38 from "react";
|
|
8260
8500
|
|
|
8261
8501
|
// src/components/chat/ChatTurn.tsx
|
|
8262
|
-
import * as
|
|
8263
|
-
import { jsx as
|
|
8502
|
+
import * as React37 from "react";
|
|
8503
|
+
import { jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
8264
8504
|
function JsonView({ value }) {
|
|
8265
8505
|
let text;
|
|
8266
8506
|
try {
|
|
@@ -8268,67 +8508,67 @@ function JsonView({ value }) {
|
|
|
8268
8508
|
} catch (e) {
|
|
8269
8509
|
text = String(value);
|
|
8270
8510
|
}
|
|
8271
|
-
return /* @__PURE__ */
|
|
8511
|
+
return /* @__PURE__ */ jsx68(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
8272
8512
|
}
|
|
8273
8513
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
8274
8514
|
if (!packet) return null;
|
|
8275
8515
|
const s = schema || {};
|
|
8276
8516
|
const invalid = packet.valid === false;
|
|
8277
8517
|
const title = s.heading || packet.type;
|
|
8278
|
-
return /* @__PURE__ */
|
|
8279
|
-
/* @__PURE__ */
|
|
8280
|
-
/* @__PURE__ */
|
|
8281
|
-
/* @__PURE__ */
|
|
8282
|
-
packet.repaired ? /* @__PURE__ */
|
|
8283
|
-
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
|
|
8284
8524
|
] }),
|
|
8285
|
-
invalid ? /* @__PURE__ */
|
|
8286
|
-
/* @__PURE__ */
|
|
8287
|
-
/* @__PURE__ */
|
|
8288
|
-
] }) : /* @__PURE__ */
|
|
8289
|
-
!invalid && onApply ? /* @__PURE__ */
|
|
8290
|
-
packet.repaired ? /* @__PURE__ */
|
|
8291
|
-
/* @__PURE__ */
|
|
8292
|
-
/* @__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" }),
|
|
8293
8533
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
8294
8534
|
] })
|
|
8295
8535
|
] }) : null
|
|
8296
8536
|
] });
|
|
8297
8537
|
}
|
|
8298
8538
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
8299
|
-
const [open, setOpen] =
|
|
8539
|
+
const [open, setOpen] = React37.useState(defaultOpen);
|
|
8300
8540
|
if (!text) return null;
|
|
8301
|
-
return /* @__PURE__ */
|
|
8302
|
-
/* @__PURE__ */
|
|
8303
|
-
/* @__PURE__ */
|
|
8304
|
-
/* @__PURE__ */
|
|
8305
|
-
streaming ? /* @__PURE__ */
|
|
8306
|
-
/* @__PURE__ */
|
|
8307
|
-
/* @__PURE__ */
|
|
8308
|
-
/* @__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", {})
|
|
8309
8549
|
] }) : null,
|
|
8310
|
-
/* @__PURE__ */
|
|
8550
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
8311
8551
|
] }),
|
|
8312
|
-
open ? /* @__PURE__ */
|
|
8552
|
+
open ? /* @__PURE__ */ jsx68("div", { className: "fdc-think-body", children: text }) : null
|
|
8313
8553
|
] });
|
|
8314
8554
|
}
|
|
8315
8555
|
function Citations({ items = [], onOpen }) {
|
|
8316
|
-
const [open, setOpen] =
|
|
8556
|
+
const [open, setOpen] = React37.useState(false);
|
|
8317
8557
|
if (!items.length) return null;
|
|
8318
|
-
return /* @__PURE__ */
|
|
8319
|
-
/* @__PURE__ */
|
|
8320
|
-
/* @__PURE__ */
|
|
8321
|
-
/* @__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: [
|
|
8322
8562
|
items.length,
|
|
8323
8563
|
" source",
|
|
8324
8564
|
items.length === 1 ? "" : "s"
|
|
8325
8565
|
] }),
|
|
8326
|
-
/* @__PURE__ */
|
|
8566
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
8327
8567
|
] }),
|
|
8328
|
-
open ? /* @__PURE__ */
|
|
8329
|
-
/* @__PURE__ */
|
|
8330
|
-
c.url ? /* @__PURE__ */
|
|
8331
|
-
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
|
|
8332
8572
|
] }, c.id || i)) }) : null
|
|
8333
8573
|
] });
|
|
8334
8574
|
}
|
|
@@ -8339,29 +8579,29 @@ function clampText(text, max) {
|
|
|
8339
8579
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
8340
8580
|
}
|
|
8341
8581
|
function MessageBody({ message: m, ctx }) {
|
|
8342
|
-
const [expanded, setExpanded] =
|
|
8582
|
+
const [expanded, setExpanded] = React37.useState(false);
|
|
8343
8583
|
const isUser = m.role === "user";
|
|
8344
8584
|
const raw = m.text || "";
|
|
8345
8585
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
8346
8586
|
const body = clamped != null ? clamped : raw;
|
|
8347
8587
|
const showMd = ctx.markdown && !isUser;
|
|
8348
|
-
return /* @__PURE__ */
|
|
8349
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */
|
|
8350
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */
|
|
8351
|
-
body ? /* @__PURE__ */
|
|
8352
|
-
showMd ? /* @__PURE__ */
|
|
8353
|
-
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
|
|
8354
8594
|
] }) : null,
|
|
8355
|
-
clamped != null ? /* @__PURE__ */
|
|
8356
|
-
/* @__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" }),
|
|
8357
8597
|
"Show more",
|
|
8358
|
-
/* @__PURE__ */
|
|
8359
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */
|
|
8360
|
-
/* @__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" }),
|
|
8361
8601
|
"Show less"
|
|
8362
8602
|
] }) : null,
|
|
8363
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */
|
|
8364
|
-
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(
|
|
8365
8605
|
PacketCard,
|
|
8366
8606
|
{
|
|
8367
8607
|
packet: m.packet,
|
|
@@ -8371,44 +8611,44 @@ function MessageBody({ message: m, ctx }) {
|
|
|
8371
8611
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
8372
8612
|
}
|
|
8373
8613
|
) : null,
|
|
8374
|
-
m.citations && m.citations.length ? /* @__PURE__ */
|
|
8375
|
-
m.working ? /* @__PURE__ */
|
|
8376
|
-
/* @__PURE__ */
|
|
8377
|
-
/* @__PURE__ */
|
|
8378
|
-
/* @__PURE__ */
|
|
8379
|
-
/* @__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", {})
|
|
8380
8620
|
] }),
|
|
8381
|
-
/* @__PURE__ */
|
|
8621
|
+
/* @__PURE__ */ jsxs63("span", { className: "fdc-working-label", children: [
|
|
8382
8622
|
m.resumed ? "Resuming" : "Working",
|
|
8383
|
-
m.job && m.job.status ? /* @__PURE__ */
|
|
8623
|
+
m.job && m.job.status ? /* @__PURE__ */ jsxs63("span", { className: "fdc-working-job", children: [
|
|
8384
8624
|
" \xB7 ",
|
|
8385
8625
|
m.job.status
|
|
8386
8626
|
] }) : null,
|
|
8387
|
-
m.job && m.job.detail ? /* @__PURE__ */
|
|
8627
|
+
m.job && m.job.detail ? /* @__PURE__ */ jsxs63("span", { className: "fdc-working-job", children: [
|
|
8388
8628
|
" \xB7 ",
|
|
8389
8629
|
m.job.detail
|
|
8390
8630
|
] }) : null
|
|
8391
8631
|
] }),
|
|
8392
|
-
m.jobId ? /* @__PURE__ */
|
|
8632
|
+
m.jobId ? /* @__PURE__ */ jsx68("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
8393
8633
|
] }) : null,
|
|
8394
|
-
m.stopped ? /* @__PURE__ */
|
|
8395
|
-
/* @__PURE__ */
|
|
8634
|
+
m.stopped ? /* @__PURE__ */ jsxs63("div", { className: "fdc-stopped", children: [
|
|
8635
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
8396
8636
|
"Stopped"
|
|
8397
8637
|
] }) : null,
|
|
8398
|
-
m.error ? /* @__PURE__ */
|
|
8399
|
-
/* @__PURE__ */
|
|
8400
|
-
/* @__PURE__ */
|
|
8401
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */
|
|
8402
|
-
/* @__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" }),
|
|
8403
8643
|
"Retry"
|
|
8404
8644
|
] }) : null
|
|
8405
8645
|
] }) : null
|
|
8406
8646
|
] });
|
|
8407
8647
|
}
|
|
8408
8648
|
function useCopyRun() {
|
|
8409
|
-
const [done, setDone] =
|
|
8410
|
-
const t =
|
|
8411
|
-
|
|
8649
|
+
const [done, setDone] = React37.useState(false);
|
|
8650
|
+
const t = React37.useRef(null);
|
|
8651
|
+
React37.useEffect(() => () => {
|
|
8412
8652
|
if (t.current) clearTimeout(t.current);
|
|
8413
8653
|
}, []);
|
|
8414
8654
|
return [done, (text) => {
|
|
@@ -8428,16 +8668,16 @@ function RunActions({ group, ctx }) {
|
|
|
8428
8668
|
const isAssistant = group.role === "assistant";
|
|
8429
8669
|
const fb = last.feedback;
|
|
8430
8670
|
if (!ctx.messageActions) return null;
|
|
8431
|
-
return /* @__PURE__ */
|
|
8432
|
-
/* @__PURE__ */
|
|
8433
|
-
/* @__PURE__ */
|
|
8434
|
-
/* @__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" })
|
|
8435
8675
|
] }),
|
|
8436
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */
|
|
8437
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */
|
|
8438
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */
|
|
8439
|
-
/* @__PURE__ */
|
|
8440
|
-
/* @__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" }) })
|
|
8441
8681
|
] }) : null,
|
|
8442
8682
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
8443
8683
|
] });
|
|
@@ -8447,22 +8687,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
8447
8687
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
8448
8688
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
8449
8689
|
const stamp = group.messages[0].timestamp;
|
|
8450
|
-
return /* @__PURE__ */
|
|
8451
|
-
/* @__PURE__ */
|
|
8452
|
-
ctx.showAvatars ? /* @__PURE__ */
|
|
8453
|
-
/* @__PURE__ */
|
|
8454
|
-
stamp ? /* @__PURE__ */
|
|
8455
|
-
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
|
|
8456
8696
|
] }),
|
|
8457
|
-
/* @__PURE__ */
|
|
8458
|
-
group.messages.map((m) => /* @__PURE__ */
|
|
8459
|
-
/* @__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 })
|
|
8460
8700
|
] })
|
|
8461
8701
|
] });
|
|
8462
8702
|
}
|
|
8463
8703
|
|
|
8464
8704
|
// src/components/chat/ChatTranscript.tsx
|
|
8465
|
-
import { jsx as
|
|
8705
|
+
import { jsx as jsx69, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
8466
8706
|
var GROUP_WINDOW = 6e4;
|
|
8467
8707
|
var STICK_PX = 100;
|
|
8468
8708
|
function groupMessages(list) {
|
|
@@ -8495,25 +8735,25 @@ function dayLabel(key) {
|
|
|
8495
8735
|
}
|
|
8496
8736
|
function Suggestions({ items = [], onPick }) {
|
|
8497
8737
|
if (!items.length) return null;
|
|
8498
|
-
return /* @__PURE__ */
|
|
8738
|
+
return /* @__PURE__ */ jsx69("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
8499
8739
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
8500
|
-
return /* @__PURE__ */
|
|
8501
|
-
it.icon ? /* @__PURE__ */
|
|
8502
|
-
/* @__PURE__ */
|
|
8503
|
-
/* @__PURE__ */
|
|
8504
|
-
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
|
|
8505
8745
|
] }),
|
|
8506
|
-
/* @__PURE__ */
|
|
8746
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
8507
8747
|
] }, it.id || i);
|
|
8508
8748
|
}) });
|
|
8509
8749
|
}
|
|
8510
8750
|
function LoadingTurns() {
|
|
8511
|
-
return /* @__PURE__ */
|
|
8512
|
-
/* @__PURE__ */
|
|
8513
|
-
/* @__PURE__ */
|
|
8514
|
-
/* @__PURE__ */
|
|
8515
|
-
/* @__PURE__ */
|
|
8516
|
-
/* @__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 } })
|
|
8517
8757
|
] })
|
|
8518
8758
|
] }, i)) });
|
|
8519
8759
|
}
|
|
@@ -8530,10 +8770,10 @@ function ChatTranscript({
|
|
|
8530
8770
|
renderEmpty,
|
|
8531
8771
|
className = ""
|
|
8532
8772
|
}) {
|
|
8533
|
-
const scroller =
|
|
8534
|
-
const stick =
|
|
8535
|
-
const [pill, setPill] =
|
|
8536
|
-
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);
|
|
8537
8777
|
const toBottom = (smooth) => {
|
|
8538
8778
|
const el = scroller.current;
|
|
8539
8779
|
if (!el) return;
|
|
@@ -8552,7 +8792,7 @@ function ChatTranscript({
|
|
|
8552
8792
|
seen.current = messages.length;
|
|
8553
8793
|
}
|
|
8554
8794
|
};
|
|
8555
|
-
|
|
8795
|
+
React38.useLayoutEffect(() => {
|
|
8556
8796
|
const el = scroller.current;
|
|
8557
8797
|
if (!el) return;
|
|
8558
8798
|
if (stick.current) {
|
|
@@ -8560,7 +8800,7 @@ function ChatTranscript({
|
|
|
8560
8800
|
seen.current = messages.length;
|
|
8561
8801
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
8562
8802
|
}, [messages]);
|
|
8563
|
-
|
|
8803
|
+
React38.useEffect(() => {
|
|
8564
8804
|
const el = scroller.current;
|
|
8565
8805
|
const inner = el && el.firstChild;
|
|
8566
8806
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -8570,38 +8810,38 @@ function ChatTranscript({
|
|
|
8570
8810
|
ro.observe(inner);
|
|
8571
8811
|
return () => ro.disconnect();
|
|
8572
8812
|
}, []);
|
|
8573
|
-
const groups =
|
|
8813
|
+
const groups = React38.useMemo(() => groupMessages(messages), [messages]);
|
|
8574
8814
|
const empty = !messages.length && status === "ready";
|
|
8575
|
-
return /* @__PURE__ */
|
|
8576
|
-
/* @__PURE__ */
|
|
8577
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */
|
|
8578
|
-
status === "disconnected" ? /* @__PURE__ */
|
|
8579
|
-
/* @__PURE__ */
|
|
8580
|
-
/* @__PURE__ */
|
|
8581
|
-
/* @__PURE__ */
|
|
8582
|
-
ctx.onReconnect ? /* @__PURE__ */
|
|
8583
|
-
/* @__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" }),
|
|
8584
8824
|
"Try again"
|
|
8585
8825
|
] }) : null
|
|
8586
8826
|
] }) : null,
|
|
8587
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
8588
|
-
/* @__PURE__ */
|
|
8589
|
-
/* @__PURE__ */
|
|
8590
|
-
emptyDescription ? /* @__PURE__ */
|
|
8591
|
-
/* @__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 })
|
|
8592
8832
|
] }) : null,
|
|
8593
8833
|
groups.map((g, i) => {
|
|
8594
8834
|
const prev = groups[i - 1];
|
|
8595
8835
|
const k = dayKey(g.messages[0].timestamp);
|
|
8596
8836
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
8597
|
-
return /* @__PURE__ */
|
|
8598
|
-
showDay ? /* @__PURE__ */
|
|
8599
|
-
/* @__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 })
|
|
8600
8840
|
] }, g.key || i);
|
|
8601
8841
|
})
|
|
8602
8842
|
] }),
|
|
8603
|
-
pill ? /* @__PURE__ */
|
|
8604
|
-
/* @__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" }),
|
|
8605
8845
|
pill,
|
|
8606
8846
|
" new message",
|
|
8607
8847
|
pill === 1 ? "" : "s"
|
|
@@ -8611,8 +8851,8 @@ function ChatTranscript({
|
|
|
8611
8851
|
var TranscriptKit = { groupMessages };
|
|
8612
8852
|
|
|
8613
8853
|
// src/components/chat/ChatComposer.tsx
|
|
8614
|
-
import * as
|
|
8615
|
-
import { jsx as
|
|
8854
|
+
import * as React39 from "react";
|
|
8855
|
+
import { jsx as jsx70, jsxs as jsxs65 } from "react/jsx-runtime";
|
|
8616
8856
|
function ChatComposer({
|
|
8617
8857
|
onSubmit,
|
|
8618
8858
|
onStop,
|
|
@@ -8639,17 +8879,17 @@ function ChatComposer({
|
|
|
8639
8879
|
onReject,
|
|
8640
8880
|
onOpenAttachment
|
|
8641
8881
|
}) {
|
|
8642
|
-
const [text, setText] =
|
|
8643
|
-
const [trigger, setTrigger] =
|
|
8644
|
-
const [mentionItems, setMentionItems] =
|
|
8645
|
-
const [listening, setListening] =
|
|
8646
|
-
const [notice, setNotice] =
|
|
8647
|
-
const editor =
|
|
8648
|
-
const wrap =
|
|
8649
|
-
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);
|
|
8650
8890
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
8651
8891
|
} });
|
|
8652
|
-
|
|
8892
|
+
React39.useEffect(() => {
|
|
8653
8893
|
if (draft != null && draft !== text) setText(draft);
|
|
8654
8894
|
}, [draft]);
|
|
8655
8895
|
const change = (v) => {
|
|
@@ -8683,7 +8923,7 @@ function ChatComposer({
|
|
|
8683
8923
|
e.preventDefault();
|
|
8684
8924
|
staged.add(found.files);
|
|
8685
8925
|
};
|
|
8686
|
-
|
|
8926
|
+
React39.useEffect(() => {
|
|
8687
8927
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
8688
8928
|
setMentionItems([]);
|
|
8689
8929
|
return;
|
|
@@ -8701,7 +8941,7 @@ function ChatComposer({
|
|
|
8701
8941
|
const q = (trigger.query || "").toLowerCase();
|
|
8702
8942
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
8703
8943
|
}, [trigger, mentionSources]);
|
|
8704
|
-
const slashItems =
|
|
8944
|
+
const slashItems = React39.useMemo(() => {
|
|
8705
8945
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
8706
8946
|
const q = (trigger.query || "").toLowerCase();
|
|
8707
8947
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -8715,7 +8955,7 @@ function ChatComposer({
|
|
|
8715
8955
|
description: it.description,
|
|
8716
8956
|
icon: it.icon,
|
|
8717
8957
|
meta: mention.meta,
|
|
8718
|
-
shortcut: slash.shortcut ? /* @__PURE__ */
|
|
8958
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ jsx70(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
8719
8959
|
onSelect: () => {
|
|
8720
8960
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
8721
8961
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -8778,14 +9018,14 @@ function ChatComposer({
|
|
|
8778
9018
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
8779
9019
|
};
|
|
8780
9020
|
};
|
|
8781
|
-
return /* @__PURE__ */
|
|
8782
|
-
queue.length ? /* @__PURE__ */
|
|
8783
|
-
/* @__PURE__ */
|
|
8784
|
-
/* @__PURE__ */
|
|
8785
|
-
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
|
|
8786
9026
|
] }, q.id)) }) : null,
|
|
8787
9027
|
sessionBar,
|
|
8788
|
-
/* @__PURE__ */
|
|
9028
|
+
/* @__PURE__ */ jsx70(
|
|
8789
9029
|
Dropzone,
|
|
8790
9030
|
{
|
|
8791
9031
|
className: "fdc-field",
|
|
@@ -8799,9 +9039,9 @@ function ChatComposer({
|
|
|
8799
9039
|
disabled: !fileUploadHandler || disabled,
|
|
8800
9040
|
label: "Drop to attach",
|
|
8801
9041
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
8802
|
-
children: /* @__PURE__ */
|
|
8803
|
-
staged.items.length ? /* @__PURE__ */
|
|
8804
|
-
/* @__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(
|
|
8805
9045
|
MarkdownEditor,
|
|
8806
9046
|
{
|
|
8807
9047
|
ref: editor,
|
|
@@ -8820,33 +9060,33 @@ function ChatComposer({
|
|
|
8820
9060
|
ariaLabel: "Message"
|
|
8821
9061
|
}
|
|
8822
9062
|
),
|
|
8823
|
-
/* @__PURE__ */
|
|
8824
|
-
fileUploadHandler ? /* @__PURE__ */
|
|
8825
|
-
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,
|
|
8826
9066
|
toolbarExtras,
|
|
8827
|
-
/* @__PURE__ */
|
|
8828
|
-
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: [
|
|
8829
9069
|
text.length,
|
|
8830
9070
|
"/",
|
|
8831
9071
|
maxLength
|
|
8832
9072
|
] }) : null,
|
|
8833
|
-
busy ? /* @__PURE__ */
|
|
8834
|
-
/* @__PURE__ */
|
|
8835
|
-
/* @__PURE__ */
|
|
8836
|
-
] }) : /* @__PURE__ */
|
|
8837
|
-
/* @__PURE__ */
|
|
8838
|
-
/* @__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" })
|
|
8839
9079
|
] })
|
|
8840
9080
|
] })
|
|
8841
9081
|
] })
|
|
8842
9082
|
}
|
|
8843
9083
|
),
|
|
8844
|
-
notice ? /* @__PURE__ */
|
|
8845
|
-
/* @__PURE__ */
|
|
9084
|
+
notice ? /* @__PURE__ */ jsxs65("div", { className: "fdc-notice", role: "status", children: [
|
|
9085
|
+
/* @__PURE__ */ jsx70("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
8846
9086
|
notice
|
|
8847
9087
|
] }) : null,
|
|
8848
|
-
hint && !notice ? /* @__PURE__ */
|
|
8849
|
-
/* @__PURE__ */
|
|
9088
|
+
hint && !notice ? /* @__PURE__ */ jsx70("div", { className: "fdc-hint", children: hint }) : null,
|
|
9089
|
+
/* @__PURE__ */ jsx70(
|
|
8850
9090
|
Popover,
|
|
8851
9091
|
{
|
|
8852
9092
|
open: menuOpen,
|
|
@@ -8860,12 +9100,12 @@ function ChatComposer({
|
|
|
8860
9100
|
returnFocus: false,
|
|
8861
9101
|
closeOnOutside: true,
|
|
8862
9102
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
8863
|
-
children: /* @__PURE__ */
|
|
9103
|
+
children: /* @__PURE__ */ jsx70(
|
|
8864
9104
|
Menu,
|
|
8865
9105
|
{
|
|
8866
9106
|
items: menuItems,
|
|
8867
9107
|
autoFocus: false,
|
|
8868
|
-
header: /* @__PURE__ */
|
|
9108
|
+
header: /* @__PURE__ */ jsx70("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
8869
9109
|
onClose: () => setTrigger(null)
|
|
8870
9110
|
}
|
|
8871
9111
|
)
|
|
@@ -8875,12 +9115,12 @@ function ChatComposer({
|
|
|
8875
9115
|
}
|
|
8876
9116
|
|
|
8877
9117
|
// src/components/chat/ChatSessionBar.tsx
|
|
8878
|
-
import * as
|
|
8879
|
-
import { jsx as
|
|
9118
|
+
import * as React40 from "react";
|
|
9119
|
+
import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
8880
9120
|
var compact2 = meterFormats.compact;
|
|
8881
9121
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
8882
|
-
const [open, setOpen] =
|
|
8883
|
-
const anchor =
|
|
9122
|
+
const [open, setOpen] = React40.useState(false);
|
|
9123
|
+
const anchor = React40.useRef(null);
|
|
8884
9124
|
const stats = sessionStats || null;
|
|
8885
9125
|
const cu = contextUsage || null;
|
|
8886
9126
|
const limits = usageLimits || null;
|
|
@@ -8895,9 +9135,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8895
9135
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
8896
9136
|
if (cu) bits.push(pct + "% context");
|
|
8897
9137
|
const expandable = !!(cu || limits);
|
|
8898
|
-
return /* @__PURE__ */
|
|
8899
|
-
/* @__PURE__ */
|
|
8900
|
-
/* @__PURE__ */
|
|
9138
|
+
return /* @__PURE__ */ jsxs66(React40.Fragment, { children: [
|
|
9139
|
+
/* @__PURE__ */ jsxs66("div", { className: "fdc-bar", children: [
|
|
9140
|
+
/* @__PURE__ */ jsxs66(
|
|
8901
9141
|
"button",
|
|
8902
9142
|
{
|
|
8903
9143
|
type: "button",
|
|
@@ -8908,16 +9148,16 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8908
9148
|
"aria-expanded": expandable ? open : void 0,
|
|
8909
9149
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
8910
9150
|
children: [
|
|
8911
|
-
cu ? /* @__PURE__ */
|
|
8912
|
-
/* @__PURE__ */
|
|
8913
|
-
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
|
|
8914
9154
|
]
|
|
8915
9155
|
}
|
|
8916
9156
|
),
|
|
8917
9157
|
extras
|
|
8918
9158
|
] }),
|
|
8919
|
-
/* @__PURE__ */
|
|
8920
|
-
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(
|
|
8921
9161
|
SegmentedMeter,
|
|
8922
9162
|
{
|
|
8923
9163
|
total,
|
|
@@ -8929,9 +9169,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8929
9169
|
remainderLabel: "Free"
|
|
8930
9170
|
}
|
|
8931
9171
|
) }) : null,
|
|
8932
|
-
limits && limits.length ? /* @__PURE__ */
|
|
8933
|
-
/* @__PURE__ */
|
|
8934
|
-
/* @__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(
|
|
8935
9175
|
QuotaRow,
|
|
8936
9176
|
{
|
|
8937
9177
|
label: l.label,
|
|
@@ -8941,32 +9181,32 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
8941
9181
|
l.id
|
|
8942
9182
|
)) })
|
|
8943
9183
|
] }) : null,
|
|
8944
|
-
stats ? /* @__PURE__ */
|
|
8945
|
-
stats.elapsedMs ? /* @__PURE__ */
|
|
8946
|
-
/* @__PURE__ */
|
|
8947
|
-
/* @__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) })
|
|
8948
9188
|
] }) : null,
|
|
8949
|
-
stats.tokens ? /* @__PURE__ */
|
|
8950
|
-
/* @__PURE__ */
|
|
8951
|
-
/* @__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() })
|
|
8952
9192
|
] }) : null,
|
|
8953
|
-
stats.costUsd != null ? /* @__PURE__ */
|
|
8954
|
-
/* @__PURE__ */
|
|
8955
|
-
/* @__PURE__ */
|
|
9193
|
+
stats.costUsd != null ? /* @__PURE__ */ jsxs66("div", { children: [
|
|
9194
|
+
/* @__PURE__ */ jsx71("span", { children: "Cost" }),
|
|
9195
|
+
/* @__PURE__ */ jsxs66("b", { className: "fd-tabular", children: [
|
|
8956
9196
|
"$",
|
|
8957
9197
|
Number(stats.costUsd).toFixed(3)
|
|
8958
9198
|
] })
|
|
8959
9199
|
] }) : null,
|
|
8960
|
-
stats.turns ? /* @__PURE__ */
|
|
8961
|
-
/* @__PURE__ */
|
|
8962
|
-
/* @__PURE__ */
|
|
9200
|
+
stats.turns ? /* @__PURE__ */ jsxs66("div", { children: [
|
|
9201
|
+
/* @__PURE__ */ jsx71("span", { children: "Turns" }),
|
|
9202
|
+
/* @__PURE__ */ jsx71("b", { className: "fd-tabular", children: stats.turns })
|
|
8963
9203
|
] }) : null
|
|
8964
9204
|
] }) : null,
|
|
8965
|
-
onClear ? /* @__PURE__ */
|
|
9205
|
+
onClear ? /* @__PURE__ */ jsx71("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ jsxs66("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
8966
9206
|
setOpen(false);
|
|
8967
9207
|
onClear();
|
|
8968
9208
|
}, children: [
|
|
8969
|
-
/* @__PURE__ */
|
|
9209
|
+
/* @__PURE__ */ jsx71("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
8970
9210
|
"Clear conversation"
|
|
8971
9211
|
] }) }) : null
|
|
8972
9212
|
] }) })
|
|
@@ -9003,7 +9243,7 @@ function ModelControls({
|
|
|
9003
9243
|
disabled: m.disabled,
|
|
9004
9244
|
checked: m.id === (current2 && current2.id),
|
|
9005
9245
|
meta: m.meta,
|
|
9006
|
-
shortcut: m.shortcut ? /* @__PURE__ */
|
|
9246
|
+
shortcut: m.shortcut ? /* @__PURE__ */ jsx71(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
9007
9247
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
9008
9248
|
});
|
|
9009
9249
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -9016,15 +9256,15 @@ function ModelControls({
|
|
|
9016
9256
|
items.push({ kind: "section", label: "Fast mode" });
|
|
9017
9257
|
items.push({
|
|
9018
9258
|
kind: "custom",
|
|
9019
|
-
render: () => /* @__PURE__ */
|
|
9020
|
-
/* @__PURE__ */
|
|
9021
|
-
/* @__PURE__ */
|
|
9022
|
-
/* @__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" }) })
|
|
9023
9263
|
] })
|
|
9024
9264
|
});
|
|
9025
9265
|
}
|
|
9026
|
-
return /* @__PURE__ */
|
|
9027
|
-
/* @__PURE__ */
|
|
9266
|
+
return /* @__PURE__ */ jsxs66(React40.Fragment, { children: [
|
|
9267
|
+
/* @__PURE__ */ jsx71(
|
|
9028
9268
|
MenuButton,
|
|
9029
9269
|
{
|
|
9030
9270
|
items,
|
|
@@ -9035,7 +9275,7 @@ function ModelControls({
|
|
|
9035
9275
|
title: "Choose a model"
|
|
9036
9276
|
}
|
|
9037
9277
|
),
|
|
9038
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */
|
|
9278
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ jsx71(
|
|
9039
9279
|
MenuButton,
|
|
9040
9280
|
{
|
|
9041
9281
|
placement: "top-end",
|
|
@@ -9056,7 +9296,7 @@ function ModelControls({
|
|
|
9056
9296
|
}
|
|
9057
9297
|
|
|
9058
9298
|
// src/components/chat/AgentChatPanel.tsx
|
|
9059
|
-
import { jsx as
|
|
9299
|
+
import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
9060
9300
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
9061
9301
|
function AgentChatPanel({
|
|
9062
9302
|
/* required */
|
|
@@ -9140,11 +9380,11 @@ function AgentChatPanel({
|
|
|
9140
9380
|
onFeedback,
|
|
9141
9381
|
onEditMessage
|
|
9142
9382
|
}) {
|
|
9143
|
-
const [panelWidth, setPanelWidth] =
|
|
9144
|
-
const [applied, setApplied] =
|
|
9145
|
-
const [draft, setDraft] =
|
|
9146
|
-
const dragging =
|
|
9147
|
-
|
|
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]);
|
|
9148
9388
|
const engine = useChatEngine({
|
|
9149
9389
|
contextType,
|
|
9150
9390
|
contextId,
|
|
@@ -9210,7 +9450,7 @@ function AgentChatPanel({
|
|
|
9210
9450
|
onReconnect: engine.reload,
|
|
9211
9451
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
9212
9452
|
};
|
|
9213
|
-
const sessionBar = /* @__PURE__ */
|
|
9453
|
+
const sessionBar = /* @__PURE__ */ jsx72(
|
|
9214
9454
|
ChatSessionBar,
|
|
9215
9455
|
{
|
|
9216
9456
|
sessionStats,
|
|
@@ -9219,7 +9459,7 @@ function AgentChatPanel({
|
|
|
9219
9459
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
9220
9460
|
}
|
|
9221
9461
|
);
|
|
9222
|
-
const modelControls = /* @__PURE__ */
|
|
9462
|
+
const modelControls = /* @__PURE__ */ jsx72(
|
|
9223
9463
|
ModelControls,
|
|
9224
9464
|
{
|
|
9225
9465
|
models,
|
|
@@ -9234,7 +9474,7 @@ function AgentChatPanel({
|
|
|
9234
9474
|
narrow
|
|
9235
9475
|
}
|
|
9236
9476
|
);
|
|
9237
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */
|
|
9477
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx72(
|
|
9238
9478
|
MenuButton,
|
|
9239
9479
|
{
|
|
9240
9480
|
variant: "ghost",
|
|
@@ -9261,7 +9501,7 @@ function AgentChatPanel({
|
|
|
9261
9501
|
})))
|
|
9262
9502
|
}
|
|
9263
9503
|
) : null;
|
|
9264
|
-
return /* @__PURE__ */
|
|
9504
|
+
return /* @__PURE__ */ jsxs67(
|
|
9265
9505
|
"aside",
|
|
9266
9506
|
{
|
|
9267
9507
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -9272,7 +9512,7 @@ function AgentChatPanel({
|
|
|
9272
9512
|
},
|
|
9273
9513
|
"aria-label": title,
|
|
9274
9514
|
children: [
|
|
9275
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */
|
|
9515
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ jsx72(
|
|
9276
9516
|
"div",
|
|
9277
9517
|
{
|
|
9278
9518
|
className: "fdc-grip",
|
|
@@ -9287,20 +9527,20 @@ function AgentChatPanel({
|
|
|
9287
9527
|
}
|
|
9288
9528
|
}
|
|
9289
9529
|
) : null,
|
|
9290
|
-
showHeader ? /* @__PURE__ */
|
|
9291
|
-
/* @__PURE__ */
|
|
9292
|
-
/* @__PURE__ */
|
|
9293
|
-
/* @__PURE__ */
|
|
9294
|
-
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
|
|
9295
9535
|
] }),
|
|
9296
|
-
/* @__PURE__ */
|
|
9536
|
+
/* @__PURE__ */ jsxs67("span", { className: "fdc-head-acts", children: [
|
|
9297
9537
|
headerActions,
|
|
9298
9538
|
threadMenu,
|
|
9299
|
-
onNewThread ? /* @__PURE__ */
|
|
9300
|
-
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
|
|
9301
9541
|
] })
|
|
9302
9542
|
] }) : null,
|
|
9303
|
-
/* @__PURE__ */
|
|
9543
|
+
/* @__PURE__ */ jsx72(
|
|
9304
9544
|
ChatTranscript,
|
|
9305
9545
|
{
|
|
9306
9546
|
messages: engine.visible,
|
|
@@ -9315,7 +9555,7 @@ function AgentChatPanel({
|
|
|
9315
9555
|
renderEmpty
|
|
9316
9556
|
}
|
|
9317
9557
|
),
|
|
9318
|
-
/* @__PURE__ */
|
|
9558
|
+
/* @__PURE__ */ jsx72(
|
|
9319
9559
|
ChatComposer,
|
|
9320
9560
|
{
|
|
9321
9561
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -9348,7 +9588,7 @@ function AgentChatPanel({
|
|
|
9348
9588
|
}
|
|
9349
9589
|
|
|
9350
9590
|
// src/kits/query.ts
|
|
9351
|
-
import * as
|
|
9591
|
+
import * as React42 from "react";
|
|
9352
9592
|
function eqFilter(get2) {
|
|
9353
9593
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
9354
9594
|
}
|
|
@@ -9380,22 +9620,22 @@ function compare(a, b, dir) {
|
|
|
9380
9620
|
var API = null;
|
|
9381
9621
|
var PREFS = null;
|
|
9382
9622
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
9383
|
-
const [query, setQuery] =
|
|
9623
|
+
const [query, setQuery] = React42.useState(() => {
|
|
9384
9624
|
const store = PREFS || window.PlannerPrefs;
|
|
9385
9625
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
9386
9626
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
9387
9627
|
});
|
|
9388
|
-
const savePref =
|
|
9628
|
+
const savePref = React42.useCallback((patch2) => {
|
|
9389
9629
|
const store = PREFS || window.PlannerPrefs;
|
|
9390
9630
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
9391
9631
|
}, [prefsKey]);
|
|
9392
|
-
const [res, setRes] =
|
|
9393
|
-
const [loading, setLoading] =
|
|
9394
|
-
const seq2 =
|
|
9632
|
+
const [res, setRes] = React42.useState(null);
|
|
9633
|
+
const [loading, setLoading] = React42.useState(true);
|
|
9634
|
+
const seq2 = React42.useRef(0);
|
|
9395
9635
|
const depKey = (deps || []).join("|");
|
|
9396
9636
|
const paramKey = JSON.stringify(params || {});
|
|
9397
9637
|
const queryKey = JSON.stringify(query);
|
|
9398
|
-
|
|
9638
|
+
React42.useEffect(() => {
|
|
9399
9639
|
const id = ++seq2.current;
|
|
9400
9640
|
setLoading(true);
|
|
9401
9641
|
const t = setTimeout(() => {
|
|
@@ -9733,6 +9973,7 @@ export {
|
|
|
9733
9973
|
Dropzone,
|
|
9734
9974
|
DropzoneKit,
|
|
9735
9975
|
EmptyState,
|
|
9976
|
+
EntityRow,
|
|
9736
9977
|
FeatureGate,
|
|
9737
9978
|
FileChip,
|
|
9738
9979
|
FileGrid,
|
|
@@ -9805,11 +10046,16 @@ export {
|
|
|
9805
10046
|
Tooltip,
|
|
9806
10047
|
Topbar,
|
|
9807
10048
|
TranscriptKit,
|
|
10049
|
+
TransferList,
|
|
9808
10050
|
UseFeatureStatus,
|
|
9809
10051
|
UseRuntimeMode,
|
|
10052
|
+
VIRTUAL_LIST_BUFFER_ROWS,
|
|
10053
|
+
VirtualList,
|
|
9810
10054
|
acceptMatches,
|
|
9811
10055
|
anyOfFilter,
|
|
9812
10056
|
channelWeightOf,
|
|
10057
|
+
computeNeedMore,
|
|
10058
|
+
computeVirtualWindow,
|
|
9813
10059
|
createVersionStore,
|
|
9814
10060
|
eqFilter,
|
|
9815
10061
|
extensionOf,
|