@flytedan/flytebot-design-system 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1109 -1091
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -7
- package/dist/index.d.ts +37 -7
- package/dist/index.js +1109 -1091
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +12 -3
package/dist/index.js
CHANGED
|
@@ -2744,11 +2744,30 @@ function EntityRow({
|
|
|
2744
2744
|
}
|
|
2745
2745
|
|
|
2746
2746
|
// src/components/data/TransferList.tsx
|
|
2747
|
-
import * as
|
|
2747
|
+
import * as React18 from "react";
|
|
2748
2748
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2749
2749
|
|
|
2750
|
-
// src/components/forms/
|
|
2750
|
+
// src/components/forms/field.tsx
|
|
2751
|
+
import * as React17 from "react";
|
|
2751
2752
|
import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2753
|
+
function useFieldId(id) {
|
|
2754
|
+
const generated = React17.useId();
|
|
2755
|
+
return id || generated;
|
|
2756
|
+
}
|
|
2757
|
+
function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
|
|
2758
|
+
return /* @__PURE__ */ jsxs36("label", { className: "fd-field-label", htmlFor, id, onClick, children: [
|
|
2759
|
+
children,
|
|
2760
|
+
required ? /* @__PURE__ */ jsx40("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
|
|
2761
|
+
] });
|
|
2762
|
+
}
|
|
2763
|
+
function useTriggerLabelling(label, id) {
|
|
2764
|
+
const fieldId = useFieldId(id);
|
|
2765
|
+
const labelId = fieldId + "-label";
|
|
2766
|
+
return { fieldId, labelId, ariaLabelledBy: label ? labelId + " " + fieldId : void 0 };
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
// src/components/forms/Input.tsx
|
|
2770
|
+
import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
2752
2771
|
function Input({
|
|
2753
2772
|
label,
|
|
2754
2773
|
help,
|
|
@@ -2767,7 +2786,7 @@ function Input({
|
|
|
2767
2786
|
inputStyle,
|
|
2768
2787
|
...rest
|
|
2769
2788
|
}) {
|
|
2770
|
-
const fieldId = id
|
|
2789
|
+
const fieldId = useFieldId(id);
|
|
2771
2790
|
const box = [
|
|
2772
2791
|
"fd-input",
|
|
2773
2792
|
numeric ? "fd-input-num" : "",
|
|
@@ -2776,27 +2795,24 @@ function Input({
|
|
|
2776
2795
|
size === "lg" ? "fd-input-lg" : "",
|
|
2777
2796
|
className
|
|
2778
2797
|
].filter(Boolean).join(" ");
|
|
2779
|
-
return /* @__PURE__ */
|
|
2780
|
-
label ? /* @__PURE__ */
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
/* @__PURE__ */ jsx40("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
|
|
2788
|
-
loading ? /* @__PURE__ */ jsx40("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
|
|
2789
|
-
suffix && !loading ? /* @__PURE__ */ jsx40("span", { className: "fd-input-affix", children: suffix }) : null
|
|
2798
|
+
return /* @__PURE__ */ jsxs37("div", { className: "fd-field", style, children: [
|
|
2799
|
+
label ? /* @__PURE__ */ jsx41(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
2800
|
+
/* @__PURE__ */ jsxs37("div", { className: box, children: [
|
|
2801
|
+
icon ? /* @__PURE__ */ jsx41("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx41("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
|
|
2802
|
+
prefix ? /* @__PURE__ */ jsx41("span", { className: "fd-input-affix", children: prefix }) : null,
|
|
2803
|
+
/* @__PURE__ */ jsx41("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
|
|
2804
|
+
loading ? /* @__PURE__ */ jsx41("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
|
|
2805
|
+
suffix && !loading ? /* @__PURE__ */ jsx41("span", { className: "fd-input-affix", children: suffix }) : null
|
|
2790
2806
|
] }),
|
|
2791
|
-
error ? /* @__PURE__ */
|
|
2792
|
-
/* @__PURE__ */
|
|
2807
|
+
error ? /* @__PURE__ */ jsxs37("span", { className: "fd-field-error", children: [
|
|
2808
|
+
/* @__PURE__ */ jsx41("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2793
2809
|
error
|
|
2794
|
-
] }) : help ? /* @__PURE__ */
|
|
2810
|
+
] }) : help ? /* @__PURE__ */ jsx41("span", { className: "fd-field-help", children: help }) : null
|
|
2795
2811
|
] });
|
|
2796
2812
|
}
|
|
2797
2813
|
|
|
2798
2814
|
// src/components/forms/SearchField.tsx
|
|
2799
|
-
import { jsx as
|
|
2815
|
+
import { jsx as jsx42 } from "react/jsx-runtime";
|
|
2800
2816
|
function SearchField({
|
|
2801
2817
|
value,
|
|
2802
2818
|
onChange,
|
|
@@ -2811,7 +2827,7 @@ function SearchField({
|
|
|
2811
2827
|
...rest
|
|
2812
2828
|
}) {
|
|
2813
2829
|
const clear = onClear || (() => onChange(""));
|
|
2814
|
-
return /* @__PURE__ */
|
|
2830
|
+
return /* @__PURE__ */ jsx42(
|
|
2815
2831
|
Input,
|
|
2816
2832
|
{
|
|
2817
2833
|
id,
|
|
@@ -2824,14 +2840,14 @@ function SearchField({
|
|
|
2824
2840
|
style,
|
|
2825
2841
|
className,
|
|
2826
2842
|
onChange: (e) => onChange(e.target.value),
|
|
2827
|
-
suffix: value ? /* @__PURE__ */
|
|
2843
|
+
suffix: value ? /* @__PURE__ */ jsx42(
|
|
2828
2844
|
"button",
|
|
2829
2845
|
{
|
|
2830
2846
|
type: "button",
|
|
2831
2847
|
"aria-label": "Clear search",
|
|
2832
2848
|
onClick: clear,
|
|
2833
2849
|
style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
|
|
2834
|
-
children: /* @__PURE__ */
|
|
2850
|
+
children: /* @__PURE__ */ jsx42("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
|
|
2835
2851
|
}
|
|
2836
2852
|
) : void 0,
|
|
2837
2853
|
...rest
|
|
@@ -2840,7 +2856,7 @@ function SearchField({
|
|
|
2840
2856
|
}
|
|
2841
2857
|
|
|
2842
2858
|
// src/components/data/TransferList.tsx
|
|
2843
|
-
import { jsx as
|
|
2859
|
+
import { jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
2844
2860
|
var emptyHasMore = {};
|
|
2845
2861
|
var DRAG_THRESHOLD_PX = 5;
|
|
2846
2862
|
function TransferList({
|
|
@@ -2854,12 +2870,12 @@ function TransferList({
|
|
|
2854
2870
|
listHeight = 440,
|
|
2855
2871
|
className = ""
|
|
2856
2872
|
}) {
|
|
2857
|
-
const [drag, setDrag] =
|
|
2858
|
-
const [dragOverSide, setDragOverSide] =
|
|
2859
|
-
const dragRef =
|
|
2860
|
-
const armedRef =
|
|
2861
|
-
const sideRefs =
|
|
2862
|
-
const hitTestSide =
|
|
2873
|
+
const [drag, setDrag] = React18.useState(null);
|
|
2874
|
+
const [dragOverSide, setDragOverSide] = React18.useState(null);
|
|
2875
|
+
const dragRef = React18.useRef(null);
|
|
2876
|
+
const armedRef = React18.useRef(null);
|
|
2877
|
+
const sideRefs = React18.useRef({ left: null, right: null });
|
|
2878
|
+
const hitTestSide = React18.useCallback((x, y) => {
|
|
2863
2879
|
for (const side of ["left", "right"]) {
|
|
2864
2880
|
const el = sideRefs.current[side];
|
|
2865
2881
|
if (!el) continue;
|
|
@@ -2868,7 +2884,7 @@ function TransferList({
|
|
|
2868
2884
|
}
|
|
2869
2885
|
return null;
|
|
2870
2886
|
}, []);
|
|
2871
|
-
const findItem =
|
|
2887
|
+
const findItem = React18.useCallback(
|
|
2872
2888
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
2873
2889
|
[left.items, right.items, keyOf]
|
|
2874
2890
|
);
|
|
@@ -2890,7 +2906,7 @@ function TransferList({
|
|
|
2890
2906
|
height: rect.height
|
|
2891
2907
|
};
|
|
2892
2908
|
};
|
|
2893
|
-
|
|
2909
|
+
React18.useEffect(() => {
|
|
2894
2910
|
const onMovePointer = (e) => {
|
|
2895
2911
|
const armed = armedRef.current;
|
|
2896
2912
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -2943,7 +2959,7 @@ function TransferList({
|
|
|
2943
2959
|
window.removeEventListener("pointercancel", endDrag);
|
|
2944
2960
|
};
|
|
2945
2961
|
}, [hitTestSide, findItem, onMove]);
|
|
2946
|
-
|
|
2962
|
+
React18.useEffect(() => {
|
|
2947
2963
|
if (!drag || typeof document === "undefined") return;
|
|
2948
2964
|
const prev = document.body.style.userSelect;
|
|
2949
2965
|
document.body.style.userSelect = "none";
|
|
@@ -2953,7 +2969,7 @@ function TransferList({
|
|
|
2953
2969
|
}, [drag]);
|
|
2954
2970
|
const renderSide = (side, cfg, opposite) => {
|
|
2955
2971
|
const showOverlay = drag != null && dragOverSide === side;
|
|
2956
|
-
return /* @__PURE__ */
|
|
2972
|
+
return /* @__PURE__ */ jsxs38(
|
|
2957
2973
|
"div",
|
|
2958
2974
|
{
|
|
2959
2975
|
ref: (el) => {
|
|
@@ -2972,16 +2988,16 @@ function TransferList({
|
|
|
2972
2988
|
position: "relative"
|
|
2973
2989
|
},
|
|
2974
2990
|
children: [
|
|
2975
|
-
cfg.label ? /* @__PURE__ */
|
|
2991
|
+
cfg.label ? /* @__PURE__ */ jsxs38("span", { className: "fd-overline fd-muted", children: [
|
|
2976
2992
|
cfg.label,
|
|
2977
2993
|
cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
|
|
2978
2994
|
] }) : null,
|
|
2979
|
-
cfg.header ? /* @__PURE__ */
|
|
2980
|
-
/* @__PURE__ */
|
|
2981
|
-
/* @__PURE__ */
|
|
2982
|
-
/* @__PURE__ */
|
|
2995
|
+
cfg.header ? /* @__PURE__ */ jsx43("div", { className: "fd-tlist-header", children: cfg.header }) : null,
|
|
2996
|
+
/* @__PURE__ */ jsxs38("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
2997
|
+
/* @__PURE__ */ jsx43(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
|
|
2998
|
+
/* @__PURE__ */ jsx43(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
|
|
2983
2999
|
] }),
|
|
2984
|
-
/* @__PURE__ */
|
|
3000
|
+
/* @__PURE__ */ jsx43(
|
|
2985
3001
|
VirtualList,
|
|
2986
3002
|
{
|
|
2987
3003
|
items: cfg.items,
|
|
@@ -2995,13 +3011,13 @@ function TransferList({
|
|
|
2995
3011
|
firstItemIndex: cfg.firstItemIndex,
|
|
2996
3012
|
totalCount: cfg.totalCount,
|
|
2997
3013
|
onNeedMore: cfg.onNeedMore,
|
|
2998
|
-
emptyState: /* @__PURE__ */
|
|
3014
|
+
emptyState: /* @__PURE__ */ jsx43(EmptyState, { icon: "tray", title: "Nothing here" }),
|
|
2999
3015
|
renderItem: (item) => {
|
|
3000
3016
|
const isBeingDragged = drag != null && drag.from === side && drag.key === keyOf(item);
|
|
3001
3017
|
if (isBeingDragged) {
|
|
3002
|
-
return /* @__PURE__ */
|
|
3018
|
+
return /* @__PURE__ */ jsx43("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
|
|
3003
3019
|
}
|
|
3004
|
-
return /* @__PURE__ */
|
|
3020
|
+
return /* @__PURE__ */ jsx43(
|
|
3005
3021
|
EntityRow,
|
|
3006
3022
|
{
|
|
3007
3023
|
...renderRow(item),
|
|
@@ -3018,20 +3034,20 @@ function TransferList({
|
|
|
3018
3034
|
}
|
|
3019
3035
|
}
|
|
3020
3036
|
),
|
|
3021
|
-
cfg.footer ? /* @__PURE__ */
|
|
3022
|
-
showOverlay ? /* @__PURE__ */
|
|
3023
|
-
/* @__PURE__ */
|
|
3024
|
-
/* @__PURE__ */
|
|
3037
|
+
cfg.footer ? /* @__PURE__ */ jsx43("div", { className: "fd-tlist-footer", children: cfg.footer }) : null,
|
|
3038
|
+
showOverlay ? /* @__PURE__ */ jsx43("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ jsxs38("span", { className: "fd-tlist-drop-card", children: [
|
|
3039
|
+
/* @__PURE__ */ jsx43("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
|
|
3040
|
+
/* @__PURE__ */ jsx43("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
|
|
3025
3041
|
] }) }) : null
|
|
3026
3042
|
]
|
|
3027
3043
|
}
|
|
3028
3044
|
);
|
|
3029
3045
|
};
|
|
3030
|
-
return /* @__PURE__ */
|
|
3046
|
+
return /* @__PURE__ */ jsxs38("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
|
|
3031
3047
|
renderSide("left", left, "right"),
|
|
3032
3048
|
renderSide("right", right, "left"),
|
|
3033
3049
|
drag ? createPortal4(
|
|
3034
|
-
/* @__PURE__ */
|
|
3050
|
+
/* @__PURE__ */ jsx43(
|
|
3035
3051
|
"div",
|
|
3036
3052
|
{
|
|
3037
3053
|
"aria-hidden": "true",
|
|
@@ -3046,7 +3062,7 @@ function TransferList({
|
|
|
3046
3062
|
pointerEvents: "none",
|
|
3047
3063
|
zIndex: 1e3
|
|
3048
3064
|
},
|
|
3049
|
-
children: /* @__PURE__ */
|
|
3065
|
+
children: /* @__PURE__ */ jsx43(EntityRow, { ...renderRow(drag.item), draggable: true, className: "fd-erow-dragging" })
|
|
3050
3066
|
}
|
|
3051
3067
|
),
|
|
3052
3068
|
document.body
|
|
@@ -3055,74 +3071,71 @@ function TransferList({
|
|
|
3055
3071
|
}
|
|
3056
3072
|
|
|
3057
3073
|
// src/components/forms/Checkbox.tsx
|
|
3058
|
-
import * as
|
|
3059
|
-
import { jsx as
|
|
3074
|
+
import * as React19 from "react";
|
|
3075
|
+
import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3060
3076
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
3061
|
-
const ref =
|
|
3062
|
-
|
|
3077
|
+
const ref = React19.useRef(null);
|
|
3078
|
+
React19.useEffect(() => {
|
|
3063
3079
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
3064
3080
|
}, [indeterminate]);
|
|
3065
|
-
return /* @__PURE__ */
|
|
3066
|
-
/* @__PURE__ */
|
|
3067
|
-
/* @__PURE__ */
|
|
3068
|
-
/* @__PURE__ */
|
|
3081
|
+
return /* @__PURE__ */ jsxs39("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
3082
|
+
/* @__PURE__ */ jsxs39("span", { className: "fd-choice-input", children: [
|
|
3083
|
+
/* @__PURE__ */ jsx44("input", { ref, type: "checkbox", ...rest }),
|
|
3084
|
+
/* @__PURE__ */ jsx44("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx44("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
|
|
3069
3085
|
] }),
|
|
3070
|
-
/* @__PURE__ */
|
|
3071
|
-
/* @__PURE__ */
|
|
3072
|
-
description ? /* @__PURE__ */
|
|
3086
|
+
/* @__PURE__ */ jsxs39("span", { className: "fd-choice-text", children: [
|
|
3087
|
+
/* @__PURE__ */ jsx44("span", { className: "fd-choice-title", children: label }),
|
|
3088
|
+
description ? /* @__PURE__ */ jsx44("span", { className: "fd-choice-desc", children: description }) : null
|
|
3073
3089
|
] })
|
|
3074
3090
|
] });
|
|
3075
3091
|
}
|
|
3076
3092
|
|
|
3077
3093
|
// src/components/forms/Radio.tsx
|
|
3078
|
-
import { jsx as
|
|
3094
|
+
import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3079
3095
|
function Radio({ label, description, card = false, className = "", ...rest }) {
|
|
3080
|
-
return /* @__PURE__ */
|
|
3081
|
-
/* @__PURE__ */
|
|
3082
|
-
/* @__PURE__ */
|
|
3083
|
-
/* @__PURE__ */
|
|
3096
|
+
return /* @__PURE__ */ jsxs40("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
3097
|
+
/* @__PURE__ */ jsxs40("span", { className: "fd-choice-input", children: [
|
|
3098
|
+
/* @__PURE__ */ jsx45("input", { type: "radio", ...rest }),
|
|
3099
|
+
/* @__PURE__ */ jsx45("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx45("span", { className: "fd-choice-dot" }) })
|
|
3084
3100
|
] }),
|
|
3085
|
-
/* @__PURE__ */
|
|
3086
|
-
/* @__PURE__ */
|
|
3087
|
-
description ? /* @__PURE__ */
|
|
3101
|
+
/* @__PURE__ */ jsxs40("span", { className: "fd-choice-text", children: [
|
|
3102
|
+
/* @__PURE__ */ jsx45("span", { className: "fd-choice-title", children: label }),
|
|
3103
|
+
description ? /* @__PURE__ */ jsx45("span", { className: "fd-choice-desc", children: description }) : null
|
|
3088
3104
|
] })
|
|
3089
3105
|
] });
|
|
3090
3106
|
}
|
|
3091
3107
|
|
|
3092
3108
|
// src/components/forms/Switch.tsx
|
|
3093
|
-
import { jsx as
|
|
3109
|
+
import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
3094
3110
|
function Switch({ label, description, className = "", ...rest }) {
|
|
3095
|
-
return /* @__PURE__ */
|
|
3096
|
-
/* @__PURE__ */
|
|
3097
|
-
/* @__PURE__ */
|
|
3098
|
-
label ? /* @__PURE__ */
|
|
3099
|
-
/* @__PURE__ */
|
|
3100
|
-
description ? /* @__PURE__ */
|
|
3111
|
+
return /* @__PURE__ */ jsxs41("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
|
|
3112
|
+
/* @__PURE__ */ jsx46("input", { type: "checkbox", role: "switch", ...rest }),
|
|
3113
|
+
/* @__PURE__ */ jsx46("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx46("span", { className: "fd-switch-thumb" }) }),
|
|
3114
|
+
label ? /* @__PURE__ */ jsxs41("span", { className: "fd-choice-text", children: [
|
|
3115
|
+
/* @__PURE__ */ jsx46("span", { className: "fd-switch-label", children: label }),
|
|
3116
|
+
description ? /* @__PURE__ */ jsx46("span", { className: "fd-choice-desc", children: description }) : null
|
|
3101
3117
|
] }) : null
|
|
3102
3118
|
] });
|
|
3103
3119
|
}
|
|
3104
3120
|
|
|
3105
3121
|
// src/components/forms/Textarea.tsx
|
|
3106
|
-
import { jsx as
|
|
3122
|
+
import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3107
3123
|
function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
|
|
3108
|
-
const fieldId = id
|
|
3124
|
+
const fieldId = useFieldId(id);
|
|
3109
3125
|
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : "", className].filter(Boolean).join(" ");
|
|
3110
|
-
return /* @__PURE__ */
|
|
3111
|
-
label ? /* @__PURE__ */
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
/* @__PURE__ */ jsx46("div", { className: box, children: /* @__PURE__ */ jsx46("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
|
|
3116
|
-
error ? /* @__PURE__ */ jsxs41("span", { className: "fd-field-error", children: [
|
|
3117
|
-
/* @__PURE__ */ jsx46("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3126
|
+
return /* @__PURE__ */ jsxs42("div", { className: "fd-field", style, children: [
|
|
3127
|
+
label ? /* @__PURE__ */ jsx47(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
3128
|
+
/* @__PURE__ */ jsx47("div", { className: box, children: /* @__PURE__ */ jsx47("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
|
|
3129
|
+
error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
|
|
3130
|
+
/* @__PURE__ */ jsx47("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3118
3131
|
error
|
|
3119
|
-
] }) : help ? /* @__PURE__ */
|
|
3132
|
+
] }) : help ? /* @__PURE__ */ jsx47("span", { className: "fd-field-help", children: help }) : null
|
|
3120
3133
|
] });
|
|
3121
3134
|
}
|
|
3122
3135
|
|
|
3123
3136
|
// src/components/forms/NumberInput.tsx
|
|
3124
|
-
import * as
|
|
3125
|
-
import { jsx as
|
|
3137
|
+
import * as React20 from "react";
|
|
3138
|
+
import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3126
3139
|
function NumberInput({
|
|
3127
3140
|
label,
|
|
3128
3141
|
help,
|
|
@@ -3140,16 +3153,19 @@ function NumberInput({
|
|
|
3140
3153
|
format = true,
|
|
3141
3154
|
className = "",
|
|
3142
3155
|
style,
|
|
3143
|
-
placeholder
|
|
3156
|
+
placeholder,
|
|
3157
|
+
id,
|
|
3158
|
+
"aria-label": ariaLabel
|
|
3144
3159
|
}) {
|
|
3160
|
+
const fieldId = useFieldId(id);
|
|
3145
3161
|
const num = (v) => {
|
|
3146
3162
|
const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
|
|
3147
3163
|
return isNaN(n) ? null : n;
|
|
3148
3164
|
};
|
|
3149
|
-
const [text, setText] =
|
|
3150
|
-
const [editing, setEditing] =
|
|
3151
|
-
const timer =
|
|
3152
|
-
|
|
3165
|
+
const [text, setText] = React20.useState(value == null || value === "" ? "" : String(value));
|
|
3166
|
+
const [editing, setEditing] = React20.useState(false);
|
|
3167
|
+
const timer = React20.useRef(null);
|
|
3168
|
+
React20.useEffect(() => {
|
|
3153
3169
|
if (!editing) setText(value == null || value === "" ? "" : String(value));
|
|
3154
3170
|
}, [value, editing]);
|
|
3155
3171
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
@@ -3173,7 +3189,7 @@ function NumberInput({
|
|
|
3173
3189
|
const release = () => {
|
|
3174
3190
|
if (timer.current) clearTimeout(timer.current);
|
|
3175
3191
|
};
|
|
3176
|
-
|
|
3192
|
+
React20.useEffect(() => () => {
|
|
3177
3193
|
if (timer.current) clearTimeout(timer.current);
|
|
3178
3194
|
}, []);
|
|
3179
3195
|
const shown = editing ? text : (() => {
|
|
@@ -3181,16 +3197,17 @@ function NumberInput({
|
|
|
3181
3197
|
return n == null ? "" : format ? n.toLocaleString() : String(n);
|
|
3182
3198
|
})();
|
|
3183
3199
|
const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
/* @__PURE__ */ jsx47(
|
|
3200
|
+
const fieldName = label || ariaLabel;
|
|
3201
|
+
const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
|
|
3202
|
+
return /* @__PURE__ */ jsxs43("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
3203
|
+
label ? /* @__PURE__ */ jsx48(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
3204
|
+
/* @__PURE__ */ jsxs43("div", { className: box, style: { gap: 8 }, children: [
|
|
3205
|
+
prefix ? /* @__PURE__ */ jsx48("span", { className: "fd-input-affix", children: prefix }) : null,
|
|
3206
|
+
/* @__PURE__ */ jsx48(
|
|
3192
3207
|
"input",
|
|
3193
3208
|
{
|
|
3209
|
+
id: fieldId,
|
|
3210
|
+
"aria-label": ariaLabel,
|
|
3194
3211
|
inputMode: "numeric",
|
|
3195
3212
|
disabled,
|
|
3196
3213
|
placeholder,
|
|
@@ -3221,51 +3238,51 @@ function NumberInput({
|
|
|
3221
3238
|
}
|
|
3222
3239
|
}
|
|
3223
3240
|
),
|
|
3224
|
-
suffix ? /* @__PURE__ */
|
|
3225
|
-
/* @__PURE__ */
|
|
3226
|
-
/* @__PURE__ */
|
|
3241
|
+
suffix ? /* @__PURE__ */ jsx48("span", { className: "fd-input-affix", children: suffix }) : null,
|
|
3242
|
+
/* @__PURE__ */ jsxs43("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
|
|
3243
|
+
/* @__PURE__ */ jsx48(
|
|
3227
3244
|
"button",
|
|
3228
3245
|
{
|
|
3229
3246
|
type: "button",
|
|
3230
3247
|
className: "fd-stepbtn",
|
|
3231
|
-
"aria-label": "Decrease",
|
|
3248
|
+
"aria-label": stepperName("Decrease"),
|
|
3232
3249
|
disabled: disabled || (num(text) ?? 0) <= min,
|
|
3233
3250
|
onPointerDown: () => hold(-1),
|
|
3234
3251
|
onPointerUp: release,
|
|
3235
3252
|
onPointerLeave: release,
|
|
3236
|
-
children: /* @__PURE__ */
|
|
3253
|
+
children: /* @__PURE__ */ jsx48("i", { className: "ph ph-minus" })
|
|
3237
3254
|
}
|
|
3238
3255
|
),
|
|
3239
|
-
/* @__PURE__ */
|
|
3256
|
+
/* @__PURE__ */ jsx48(
|
|
3240
3257
|
"button",
|
|
3241
3258
|
{
|
|
3242
3259
|
type: "button",
|
|
3243
3260
|
className: "fd-stepbtn",
|
|
3244
|
-
"aria-label": "Increase",
|
|
3261
|
+
"aria-label": stepperName("Increase"),
|
|
3245
3262
|
disabled: disabled || (num(text) ?? 0) >= max,
|
|
3246
3263
|
onPointerDown: () => hold(1),
|
|
3247
3264
|
onPointerUp: release,
|
|
3248
3265
|
onPointerLeave: release,
|
|
3249
|
-
children: /* @__PURE__ */
|
|
3266
|
+
children: /* @__PURE__ */ jsx48("i", { className: "ph ph-plus" })
|
|
3250
3267
|
}
|
|
3251
3268
|
)
|
|
3252
3269
|
] })
|
|
3253
3270
|
] }),
|
|
3254
|
-
error ? /* @__PURE__ */
|
|
3255
|
-
/* @__PURE__ */
|
|
3271
|
+
error ? /* @__PURE__ */ jsxs43("span", { className: "fd-field-error", children: [
|
|
3272
|
+
/* @__PURE__ */ jsx48("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3256
3273
|
error
|
|
3257
|
-
] }) : help ? /* @__PURE__ */
|
|
3274
|
+
] }) : help ? /* @__PURE__ */ jsx48("span", { className: "fd-field-help", children: help }) : null
|
|
3258
3275
|
] });
|
|
3259
3276
|
}
|
|
3260
3277
|
|
|
3261
3278
|
// src/components/forms/Select.tsx
|
|
3262
|
-
import * as
|
|
3279
|
+
import * as React21 from "react";
|
|
3263
3280
|
import { createPortal as createPortal5 } from "react-dom";
|
|
3264
|
-
import { jsx as
|
|
3281
|
+
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3265
3282
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
3266
3283
|
function usePopPos(open, ref, estH, estW) {
|
|
3267
|
-
const [pos, setPos] =
|
|
3268
|
-
|
|
3284
|
+
const [pos, setPos] = React21.useState(null);
|
|
3285
|
+
React21.useLayoutEffect(() => {
|
|
3269
3286
|
if (!open || !ref.current) {
|
|
3270
3287
|
setPos(null);
|
|
3271
3288
|
return;
|
|
@@ -3322,21 +3339,21 @@ function Select({
|
|
|
3322
3339
|
summary,
|
|
3323
3340
|
id,
|
|
3324
3341
|
className = "",
|
|
3325
|
-
style
|
|
3326
|
-
...rest
|
|
3342
|
+
style
|
|
3327
3343
|
}) {
|
|
3328
3344
|
const opts = options.map(norm);
|
|
3329
3345
|
const vals = multiple ? Array.isArray(value) ? value : value ? [value] : [] : [];
|
|
3330
3346
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
3331
3347
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
3332
|
-
const
|
|
3333
|
-
const [
|
|
3334
|
-
const [
|
|
3335
|
-
const
|
|
3336
|
-
const
|
|
3337
|
-
const
|
|
3338
|
-
const
|
|
3339
|
-
const
|
|
3348
|
+
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3349
|
+
const [open, setOpen] = React21.useState(false);
|
|
3350
|
+
const [q, setQ] = React21.useState("");
|
|
3351
|
+
const [active, setActive] = React21.useState(-1);
|
|
3352
|
+
const rootRef = React21.useRef(null);
|
|
3353
|
+
const boxRef = React21.useRef(null);
|
|
3354
|
+
const popRef = React21.useRef(null);
|
|
3355
|
+
const listRef = React21.useRef(null);
|
|
3356
|
+
const typeBuf = React21.useRef({ s: "", t: 0 });
|
|
3340
3357
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
3341
3358
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
3342
3359
|
const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
|
|
@@ -3362,7 +3379,7 @@ function Select({
|
|
|
3362
3379
|
}
|
|
3363
3380
|
setOpen(!open);
|
|
3364
3381
|
};
|
|
3365
|
-
|
|
3382
|
+
React21.useEffect(() => {
|
|
3366
3383
|
if (!open) return;
|
|
3367
3384
|
const away = (e) => {
|
|
3368
3385
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -3372,7 +3389,7 @@ function Select({
|
|
|
3372
3389
|
document.addEventListener("pointerdown", away);
|
|
3373
3390
|
return () => document.removeEventListener("pointerdown", away);
|
|
3374
3391
|
}, [open]);
|
|
3375
|
-
|
|
3392
|
+
React21.useEffect(() => {
|
|
3376
3393
|
if (!open || active < 0 || !listRef.current) return;
|
|
3377
3394
|
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
3378
3395
|
if (el) {
|
|
@@ -3424,15 +3441,11 @@ function Select({
|
|
|
3424
3441
|
if (!last || last.g !== g) groups.push({ g, items: [{ o, i }] });
|
|
3425
3442
|
else last.items.push({ o, i });
|
|
3426
3443
|
});
|
|
3427
|
-
const fieldId = id || (rest.name ? "fd-" + rest.name : void 0);
|
|
3428
3444
|
const box = ["fd-input", "fd-select", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
3429
|
-
return /* @__PURE__ */
|
|
3430
|
-
label ? /* @__PURE__ */
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
] }) : null,
|
|
3434
|
-
/* @__PURE__ */ jsxs43("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
|
|
3435
|
-
/* @__PURE__ */ jsxs43(
|
|
3445
|
+
return /* @__PURE__ */ jsxs44("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
|
|
3446
|
+
label ? /* @__PURE__ */ jsx49(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
|
|
3447
|
+
/* @__PURE__ */ jsxs44("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
|
|
3448
|
+
/* @__PURE__ */ jsxs44(
|
|
3436
3449
|
"button",
|
|
3437
3450
|
{
|
|
3438
3451
|
type: "button",
|
|
@@ -3443,15 +3456,16 @@ function Select({
|
|
|
3443
3456
|
role: "combobox",
|
|
3444
3457
|
"aria-expanded": open,
|
|
3445
3458
|
"aria-haspopup": "listbox",
|
|
3459
|
+
"aria-labelledby": ariaLabelledBy,
|
|
3446
3460
|
style: { all: "unset", flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8, cursor: "inherit", overflow: "hidden" },
|
|
3447
3461
|
children: [
|
|
3448
|
-
selected && selected.icon ? /* @__PURE__ */
|
|
3449
|
-
/* @__PURE__ */
|
|
3450
|
-
multiple && chosen.length > 1 ? /* @__PURE__ */
|
|
3462
|
+
selected && selected.icon ? /* @__PURE__ */ jsx49("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
|
|
3463
|
+
/* @__PURE__ */ jsx49("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
|
|
3464
|
+
multiple && chosen.length > 1 ? /* @__PURE__ */ jsx49("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
|
|
3451
3465
|
]
|
|
3452
3466
|
}
|
|
3453
3467
|
),
|
|
3454
|
-
clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */
|
|
3468
|
+
clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx49(
|
|
3455
3469
|
"button",
|
|
3456
3470
|
{
|
|
3457
3471
|
type: "button",
|
|
@@ -3461,22 +3475,22 @@ function Select({
|
|
|
3461
3475
|
fire(multiple ? [] : "");
|
|
3462
3476
|
},
|
|
3463
3477
|
style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
|
|
3464
|
-
children: /* @__PURE__ */
|
|
3478
|
+
children: /* @__PURE__ */ jsx49("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
|
|
3465
3479
|
}
|
|
3466
3480
|
) : null,
|
|
3467
|
-
loading ? /* @__PURE__ */
|
|
3481
|
+
loading ? /* @__PURE__ */ jsx49("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx49("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3468
3482
|
] }),
|
|
3469
3483
|
open && pos ? createPortal5(
|
|
3470
|
-
/* @__PURE__ */
|
|
3484
|
+
/* @__PURE__ */ jsxs44(
|
|
3471
3485
|
"div",
|
|
3472
3486
|
{
|
|
3473
3487
|
className: "fd-pop" + (pos.up ? " is-up" : ""),
|
|
3474
3488
|
ref: popRef,
|
|
3475
3489
|
style: popStyle(pos, { minWidth: Math.max(pos.width, 260), maxWidth: 380, zIndex: 130, overflowY: "hidden" }),
|
|
3476
3490
|
children: [
|
|
3477
|
-
hasSearch ? /* @__PURE__ */
|
|
3478
|
-
/* @__PURE__ */
|
|
3479
|
-
/* @__PURE__ */
|
|
3491
|
+
hasSearch ? /* @__PURE__ */ jsxs44("div", { className: "fd-pop-search", children: [
|
|
3492
|
+
/* @__PURE__ */ jsx49("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
|
|
3493
|
+
/* @__PURE__ */ jsx49(
|
|
3480
3494
|
"input",
|
|
3481
3495
|
{
|
|
3482
3496
|
autoFocus: true,
|
|
@@ -3489,15 +3503,15 @@ function Select({
|
|
|
3489
3503
|
}
|
|
3490
3504
|
}
|
|
3491
3505
|
),
|
|
3492
|
-
q ? /* @__PURE__ */
|
|
3506
|
+
q ? /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
3493
3507
|
] }) : null,
|
|
3494
|
-
/* @__PURE__ */
|
|
3508
|
+
/* @__PURE__ */ jsx49("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__ */ jsxs44("div", { className: "fd-pop-empty", children: [
|
|
3495
3509
|
'Nothing matches "',
|
|
3496
3510
|
q,
|
|
3497
3511
|
'".'
|
|
3498
|
-
] }) : groups.map((grp) => /* @__PURE__ */
|
|
3499
|
-
grp.g ? /* @__PURE__ */
|
|
3500
|
-
grp.items.map(({ o, i }) => /* @__PURE__ */
|
|
3512
|
+
] }) : groups.map((grp) => /* @__PURE__ */ jsxs44(React21.Fragment, { children: [
|
|
3513
|
+
grp.g ? /* @__PURE__ */ jsx49("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
3514
|
+
grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs44(
|
|
3501
3515
|
"button",
|
|
3502
3516
|
{
|
|
3503
3517
|
type: "button",
|
|
@@ -3509,21 +3523,21 @@ function Select({
|
|
|
3509
3523
|
onMouseEnter: () => setActive(i),
|
|
3510
3524
|
onClick: () => pick(o),
|
|
3511
3525
|
children: [
|
|
3512
|
-
multiple ? /* @__PURE__ */
|
|
3513
|
-
o.icon ? /* @__PURE__ */
|
|
3514
|
-
/* @__PURE__ */
|
|
3515
|
-
/* @__PURE__ */
|
|
3516
|
-
o.description ? /* @__PURE__ */
|
|
3526
|
+
multiple ? /* @__PURE__ */ jsx49("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__ */ jsx49("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
|
|
3527
|
+
o.icon ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-" + o.icon }) }) : null,
|
|
3528
|
+
/* @__PURE__ */ jsxs44("span", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3529
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-opt-label", children: o.label }),
|
|
3530
|
+
o.description ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-desc", children: o.description }) : null
|
|
3517
3531
|
] }),
|
|
3518
|
-
o.meta ? /* @__PURE__ */
|
|
3519
|
-
multiple ? null : /* @__PURE__ */
|
|
3532
|
+
o.meta ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-meta", children: o.meta }) : null,
|
|
3533
|
+
multiple ? null : /* @__PURE__ */ jsx49("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx49("i", { className: "ph ph-check" }) : null })
|
|
3520
3534
|
]
|
|
3521
3535
|
},
|
|
3522
3536
|
String(o.value)
|
|
3523
3537
|
))
|
|
3524
3538
|
] }, grp.g || "_")) }),
|
|
3525
|
-
multiple ? /* @__PURE__ */
|
|
3526
|
-
/* @__PURE__ */
|
|
3539
|
+
multiple ? /* @__PURE__ */ jsxs44("div", { className: "fd-row", style: { gap: 10, padding: "8px 12px", borderTop: "1px solid var(--border)" }, children: [
|
|
3540
|
+
/* @__PURE__ */ jsx49(
|
|
3527
3541
|
"button",
|
|
3528
3542
|
{
|
|
3529
3543
|
type: "button",
|
|
@@ -3532,13 +3546,13 @@ function Select({
|
|
|
3532
3546
|
children: "Select all"
|
|
3533
3547
|
}
|
|
3534
3548
|
),
|
|
3535
|
-
/* @__PURE__ */
|
|
3536
|
-
/* @__PURE__ */
|
|
3549
|
+
/* @__PURE__ */ jsx49("span", { style: { flex: 1 } }),
|
|
3550
|
+
/* @__PURE__ */ jsxs44("span", { className: "fd-body-sm fd-muted", children: [
|
|
3537
3551
|
vals.length,
|
|
3538
3552
|
" of ",
|
|
3539
3553
|
opts.length
|
|
3540
3554
|
] }),
|
|
3541
|
-
/* @__PURE__ */
|
|
3555
|
+
/* @__PURE__ */ jsx49(
|
|
3542
3556
|
"button",
|
|
3543
3557
|
{
|
|
3544
3558
|
type: "button",
|
|
@@ -3554,17 +3568,17 @@ function Select({
|
|
|
3554
3568
|
),
|
|
3555
3569
|
document.body
|
|
3556
3570
|
) : null,
|
|
3557
|
-
error ? /* @__PURE__ */
|
|
3558
|
-
/* @__PURE__ */
|
|
3571
|
+
error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
|
|
3572
|
+
/* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3559
3573
|
error
|
|
3560
|
-
] }) : help ? /* @__PURE__ */
|
|
3574
|
+
] }) : help ? /* @__PURE__ */ jsx49("span", { className: "fd-field-help", children: help }) : null
|
|
3561
3575
|
] });
|
|
3562
3576
|
}
|
|
3563
3577
|
|
|
3564
3578
|
// src/components/forms/DatePicker.tsx
|
|
3565
|
-
import * as
|
|
3579
|
+
import * as React22 from "react";
|
|
3566
3580
|
import { createPortal as createPortal6 } from "react-dom";
|
|
3567
|
-
import { jsx as
|
|
3581
|
+
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3568
3582
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3569
3583
|
var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
3570
3584
|
var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
|
|
@@ -3578,8 +3592,8 @@ var fmt = (s) => {
|
|
|
3578
3592
|
return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
|
|
3579
3593
|
};
|
|
3580
3594
|
function usePopPos2(open, ref, estH, estW) {
|
|
3581
|
-
const [pos, setPos] =
|
|
3582
|
-
|
|
3595
|
+
const [pos, setPos] = React22.useState(null);
|
|
3596
|
+
React22.useLayoutEffect(() => {
|
|
3583
3597
|
if (!open || !ref.current) {
|
|
3584
3598
|
setPos(null);
|
|
3585
3599
|
return;
|
|
@@ -3623,10 +3637,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3623
3637
|
const today = /* @__PURE__ */ new Date();
|
|
3624
3638
|
const sel = range ? value || {} : { start: value, end: value };
|
|
3625
3639
|
const anchor = parse(sel.start) || parse(initialMonth) || today;
|
|
3626
|
-
const [vy, setVy] =
|
|
3627
|
-
const [vm, setVm] =
|
|
3628
|
-
const [mode2, setMode] =
|
|
3629
|
-
const [hover, setHover] =
|
|
3640
|
+
const [vy, setVy] = React22.useState(anchor.getFullYear());
|
|
3641
|
+
const [vm, setVm] = React22.useState(anchor.getMonth());
|
|
3642
|
+
const [mode2, setMode] = React22.useState("days");
|
|
3643
|
+
const [hover, setHover] = React22.useState(null);
|
|
3630
3644
|
const s = parse(sel.start), e = parse(sel.end);
|
|
3631
3645
|
const hoverEnd = range && s && !e && hover ? parse(hover) : null;
|
|
3632
3646
|
const inRange = (d) => {
|
|
@@ -3663,9 +3677,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3663
3677
|
const startPad = new Date(y, m, 1).getDay();
|
|
3664
3678
|
const cells = [];
|
|
3665
3679
|
for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
|
|
3666
|
-
return /* @__PURE__ */
|
|
3667
|
-
DOW.map((d) => /* @__PURE__ */
|
|
3668
|
-
cells.map((d, i) => /* @__PURE__ */
|
|
3680
|
+
return /* @__PURE__ */ jsxs45("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
|
|
3681
|
+
DOW.map((d) => /* @__PURE__ */ jsx50("span", { className: "fd-cal-dow", children: d }, d)),
|
|
3682
|
+
cells.map((d, i) => /* @__PURE__ */ jsx50(
|
|
3669
3683
|
"button",
|
|
3670
3684
|
{
|
|
3671
3685
|
type: "button",
|
|
@@ -3679,20 +3693,20 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3679
3693
|
] });
|
|
3680
3694
|
};
|
|
3681
3695
|
const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
|
|
3682
|
-
return /* @__PURE__ */
|
|
3683
|
-
/* @__PURE__ */
|
|
3684
|
-
/* @__PURE__ */
|
|
3685
|
-
/* @__PURE__ */
|
|
3696
|
+
return /* @__PURE__ */ jsxs45("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
|
|
3697
|
+
/* @__PURE__ */ jsxs45("div", { className: "fd-cal-head", children: [
|
|
3698
|
+
/* @__PURE__ */ jsx50("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__ */ jsx50("i", { className: "ph ph-caret-left" }) }),
|
|
3699
|
+
/* @__PURE__ */ jsxs45("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
|
|
3686
3700
|
mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
|
|
3687
|
-
/* @__PURE__ */
|
|
3701
|
+
/* @__PURE__ */ jsx50("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
|
|
3688
3702
|
] }),
|
|
3689
|
-
months > 1 && mode2 === "days" ? /* @__PURE__ */
|
|
3690
|
-
/* @__PURE__ */
|
|
3703
|
+
months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx50("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
|
|
3704
|
+
/* @__PURE__ */ jsx50("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__ */ jsx50("i", { className: "ph ph-caret-right" }) })
|
|
3691
3705
|
] }),
|
|
3692
|
-
mode2 === "days" ? /* @__PURE__ */
|
|
3706
|
+
mode2 === "days" ? /* @__PURE__ */ jsxs45("div", { style: { display: "flex", gap: 18 }, children: [
|
|
3693
3707
|
monthGrid(vy, vm),
|
|
3694
3708
|
months > 1 ? monthGrid(nextY, nextM) : null
|
|
3695
|
-
] }) : mode2 === "months" ? /* @__PURE__ */
|
|
3709
|
+
] }) : mode2 === "months" ? /* @__PURE__ */ jsx50("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx50(
|
|
3696
3710
|
"button",
|
|
3697
3711
|
{
|
|
3698
3712
|
type: "button",
|
|
@@ -3704,7 +3718,7 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3704
3718
|
children: m.slice(0, 3)
|
|
3705
3719
|
},
|
|
3706
3720
|
m
|
|
3707
|
-
)) }) : /* @__PURE__ */
|
|
3721
|
+
)) }) : /* @__PURE__ */ jsx50("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx50(
|
|
3708
3722
|
"button",
|
|
3709
3723
|
{
|
|
3710
3724
|
type: "button",
|
|
@@ -3717,8 +3731,8 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3717
3731
|
},
|
|
3718
3732
|
y
|
|
3719
3733
|
)) }),
|
|
3720
|
-
/* @__PURE__ */
|
|
3721
|
-
/* @__PURE__ */
|
|
3734
|
+
/* @__PURE__ */ jsxs45("div", { className: "fd-cal-foot", children: [
|
|
3735
|
+
/* @__PURE__ */ jsx50(
|
|
3722
3736
|
"button",
|
|
3723
3737
|
{
|
|
3724
3738
|
type: "button",
|
|
@@ -3732,21 +3746,22 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3732
3746
|
children: "Today"
|
|
3733
3747
|
}
|
|
3734
3748
|
),
|
|
3735
|
-
/* @__PURE__ */
|
|
3736
|
-
range && sel.start ? /* @__PURE__ */
|
|
3749
|
+
/* @__PURE__ */ jsx50("span", { style: { flex: 1 } }),
|
|
3750
|
+
range && sel.start ? /* @__PURE__ */ jsxs45("span", { className: "fd-body-sm fd-muted", children: [
|
|
3737
3751
|
fmt(sel.start),
|
|
3738
3752
|
sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
|
|
3739
3753
|
] }) : null
|
|
3740
3754
|
] })
|
|
3741
3755
|
] });
|
|
3742
3756
|
}
|
|
3743
|
-
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, className = "", style, ...rest }) {
|
|
3744
|
-
const
|
|
3745
|
-
const
|
|
3746
|
-
const
|
|
3747
|
-
const
|
|
3757
|
+
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
|
|
3758
|
+
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3759
|
+
const [open, setOpen] = React22.useState(false);
|
|
3760
|
+
const rootRef = React22.useRef(null);
|
|
3761
|
+
const boxRef = React22.useRef(null);
|
|
3762
|
+
const popRef = React22.useRef(null);
|
|
3748
3763
|
const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
|
|
3749
|
-
|
|
3764
|
+
React22.useEffect(() => {
|
|
3750
3765
|
if (!open) return;
|
|
3751
3766
|
const away = (e) => {
|
|
3752
3767
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -3767,17 +3782,16 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3767
3782
|
const toggle = () => {
|
|
3768
3783
|
if (!disabled) setOpen(!open);
|
|
3769
3784
|
};
|
|
3770
|
-
return /* @__PURE__ */
|
|
3771
|
-
label ? /* @__PURE__ */
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
/* @__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: [
|
|
3776
|
-
/* @__PURE__ */ jsx49("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
|
|
3777
|
-
/* @__PURE__ */ jsx49(
|
|
3785
|
+
return /* @__PURE__ */ jsxs45("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
|
|
3786
|
+
label ? /* @__PURE__ */ jsx50(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
|
|
3787
|
+
/* @__PURE__ */ jsxs45("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: [
|
|
3788
|
+
/* @__PURE__ */ jsx50("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
|
|
3789
|
+
/* @__PURE__ */ jsx50(
|
|
3778
3790
|
"button",
|
|
3779
3791
|
{
|
|
3780
3792
|
type: "button",
|
|
3793
|
+
id: fieldId,
|
|
3794
|
+
"aria-labelledby": ariaLabelledBy,
|
|
3781
3795
|
disabled,
|
|
3782
3796
|
onKeyDown: (e) => {
|
|
3783
3797
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -3790,10 +3804,10 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3790
3804
|
children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
|
|
3791
3805
|
}
|
|
3792
3806
|
),
|
|
3793
|
-
/* @__PURE__ */
|
|
3807
|
+
/* @__PURE__ */ jsx50("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3794
3808
|
] }),
|
|
3795
3809
|
open && pos ? createPortal6(
|
|
3796
|
-
/* @__PURE__ */
|
|
3810
|
+
/* @__PURE__ */ jsx50("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle2(pos, { width: "max-content", minWidth: 0, zIndex: 130 }), children: /* @__PURE__ */ jsx50(
|
|
3797
3811
|
Calendar,
|
|
3798
3812
|
{
|
|
3799
3813
|
range,
|
|
@@ -3807,21 +3821,21 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3807
3821
|
) }),
|
|
3808
3822
|
document.body
|
|
3809
3823
|
) : null,
|
|
3810
|
-
error ? /* @__PURE__ */
|
|
3811
|
-
/* @__PURE__ */
|
|
3824
|
+
error ? /* @__PURE__ */ jsxs45("span", { className: "fd-field-error", children: [
|
|
3825
|
+
/* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3812
3826
|
error
|
|
3813
|
-
] }) : help ? /* @__PURE__ */
|
|
3827
|
+
] }) : help ? /* @__PURE__ */ jsx50("span", { className: "fd-field-help", children: help }) : null
|
|
3814
3828
|
] });
|
|
3815
3829
|
}
|
|
3816
3830
|
|
|
3817
3831
|
// src/components/forms/TimePicker.tsx
|
|
3818
|
-
import * as
|
|
3832
|
+
import * as React23 from "react";
|
|
3819
3833
|
import { createPortal as createPortal7 } from "react-dom";
|
|
3820
|
-
import { jsx as
|
|
3834
|
+
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3821
3835
|
var pad = (n) => String(n).padStart(2, "0");
|
|
3822
3836
|
function usePopPos3(open, ref, estH, estW) {
|
|
3823
|
-
const [pos, setPos] =
|
|
3824
|
-
|
|
3837
|
+
const [pos, setPos] = React23.useState(null);
|
|
3838
|
+
React23.useLayoutEffect(() => {
|
|
3825
3839
|
if (!open || !ref.current) {
|
|
3826
3840
|
setPos(null);
|
|
3827
3841
|
return;
|
|
@@ -3867,9 +3881,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3867
3881
|
if (isNaN(m)) m = 0;
|
|
3868
3882
|
const pm = h24 >= 12;
|
|
3869
3883
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
3870
|
-
const [mode2, setMode] =
|
|
3871
|
-
const faceRef =
|
|
3872
|
-
const dragging =
|
|
3884
|
+
const [mode2, setMode] = React23.useState("h");
|
|
3885
|
+
const faceRef = React23.useRef(null);
|
|
3886
|
+
const dragging = React23.useRef(false);
|
|
3873
3887
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
3874
3888
|
const R = 108, NR = 80;
|
|
3875
3889
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -3904,12 +3918,12 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3904
3918
|
};
|
|
3905
3919
|
const handAngle = mode2 === "h" ? h12 % 12 * 30 : m * 6;
|
|
3906
3920
|
const minuteOff = mode2 === "m" && m % 5 !== 0;
|
|
3907
|
-
return /* @__PURE__ */
|
|
3908
|
-
/* @__PURE__ */
|
|
3909
|
-
/* @__PURE__ */
|
|
3910
|
-
/* @__PURE__ */
|
|
3911
|
-
/* @__PURE__ */
|
|
3912
|
-
/* @__PURE__ */
|
|
3921
|
+
return /* @__PURE__ */ jsxs46("div", { style: { padding: "4px 14px 14px" }, children: [
|
|
3922
|
+
/* @__PURE__ */ jsxs46("div", { className: "fd-clock-digits", children: [
|
|
3923
|
+
/* @__PURE__ */ jsx51("button", { type: "button", className: "fd-clock-digit" + (mode2 === "h" ? " is-active" : ""), onClick: () => setMode("h"), children: pad(h12) }),
|
|
3924
|
+
/* @__PURE__ */ jsx51("span", { style: { fontSize: 24, fontWeight: 700, color: "var(--text-muted)" }, children: ":" }),
|
|
3925
|
+
/* @__PURE__ */ jsx51("button", { type: "button", className: "fd-clock-digit" + (mode2 === "m" ? " is-active" : ""), onClick: () => setMode("m"), children: pad(m) }),
|
|
3926
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-stack", style: { gap: 3, marginLeft: 8 }, children: ["AM", "PM"].map((ap) => /* @__PURE__ */ jsx51(
|
|
3913
3927
|
"button",
|
|
3914
3928
|
{
|
|
3915
3929
|
type: "button",
|
|
@@ -3920,13 +3934,13 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3920
3934
|
ap
|
|
3921
3935
|
)) })
|
|
3922
3936
|
] }),
|
|
3923
|
-
/* @__PURE__ */
|
|
3924
|
-
/* @__PURE__ */
|
|
3925
|
-
/* @__PURE__ */
|
|
3926
|
-
minuteOff ? /* @__PURE__ */
|
|
3937
|
+
/* @__PURE__ */ jsxs46("div", { className: "fd-clock", ref: faceRef, onPointerDown: down, onPointerMove: move, onPointerUp: upH, children: [
|
|
3938
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-clock-hand", style: { height: NR - (minuteOff ? 14 : 16), transform: "translateX(-50%) rotate(" + handAngle + "deg)", bottom: "50%" } }),
|
|
3939
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-clock-pivot" }),
|
|
3940
|
+
minuteOff ? /* @__PURE__ */ jsx51("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,
|
|
3927
3941
|
nums.map((n) => {
|
|
3928
3942
|
const a = angleOf(n) * Math.PI / 180;
|
|
3929
|
-
return /* @__PURE__ */
|
|
3943
|
+
return /* @__PURE__ */ jsx51(
|
|
3930
3944
|
"span",
|
|
3931
3945
|
{
|
|
3932
3946
|
className: "fd-clock-num" + (n === selNum || mode2 === "m" && n === Math.round(m / 5) * 5 % 60 && m % 5 === 0 ? " is-sel" : ""),
|
|
@@ -3937,16 +3951,17 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3937
3951
|
);
|
|
3938
3952
|
})
|
|
3939
3953
|
] }),
|
|
3940
|
-
/* @__PURE__ */
|
|
3954
|
+
/* @__PURE__ */ jsx51("div", { className: "fd-row", style: { justifyContent: "center", gap: 6 }, children: /* @__PURE__ */ jsx51("span", { className: "fd-body-sm fd-muted", children: mode2 === "h" ? "Pick the hour \u2014 drag or tap" : "Now the minutes" }) })
|
|
3941
3955
|
] });
|
|
3942
3956
|
}
|
|
3943
|
-
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", className = "", style }) {
|
|
3944
|
-
const
|
|
3945
|
-
const
|
|
3946
|
-
const
|
|
3947
|
-
const
|
|
3957
|
+
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
3958
|
+
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3959
|
+
const [open, setOpen] = React23.useState(false);
|
|
3960
|
+
const rootRef = React23.useRef(null);
|
|
3961
|
+
const boxRef = React23.useRef(null);
|
|
3962
|
+
const popRef = React23.useRef(null);
|
|
3948
3963
|
const pos = usePopPos3(open, boxRef, 420, 262);
|
|
3949
|
-
|
|
3964
|
+
React23.useEffect(() => {
|
|
3950
3965
|
if (!open) return;
|
|
3951
3966
|
const away = (e) => {
|
|
3952
3967
|
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
@@ -3971,17 +3986,16 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3971
3986
|
const toggle = () => {
|
|
3972
3987
|
if (!disabled) setOpen(!open);
|
|
3973
3988
|
};
|
|
3974
|
-
return /* @__PURE__ */
|
|
3975
|
-
label ? /* @__PURE__ */
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
/* @__PURE__ */ jsxs45("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: [
|
|
3980
|
-
/* @__PURE__ */ jsx50("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
|
|
3981
|
-
/* @__PURE__ */ jsx50(
|
|
3989
|
+
return /* @__PURE__ */ jsxs46("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
|
|
3990
|
+
label ? /* @__PURE__ */ jsx51(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
|
|
3991
|
+
/* @__PURE__ */ jsxs46("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: [
|
|
3992
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx51("i", { className: "ph ph-clock", "aria-hidden": "true" }) }),
|
|
3993
|
+
/* @__PURE__ */ jsx51(
|
|
3982
3994
|
"button",
|
|
3983
3995
|
{
|
|
3984
3996
|
type: "button",
|
|
3997
|
+
id: fieldId,
|
|
3998
|
+
"aria-labelledby": ariaLabelledBy,
|
|
3985
3999
|
disabled,
|
|
3986
4000
|
onKeyDown: (e) => {
|
|
3987
4001
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -3993,13 +4007,13 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
3993
4007
|
children: disp() || placeholder
|
|
3994
4008
|
}
|
|
3995
4009
|
),
|
|
3996
|
-
/* @__PURE__ */
|
|
4010
|
+
/* @__PURE__ */ jsx51("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx51("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3997
4011
|
] }),
|
|
3998
4012
|
open && pos ? createPortal7(
|
|
3999
|
-
/* @__PURE__ */
|
|
4000
|
-
/* @__PURE__ */
|
|
4001
|
-
/* @__PURE__ */
|
|
4002
|
-
/* @__PURE__ */
|
|
4013
|
+
/* @__PURE__ */ jsxs46("div", { className: "fd-pop" + (pos.up ? " is-up" : ""), ref: popRef, style: popStyle3(pos, { width: 262, minWidth: 0, zIndex: 130 }), children: [
|
|
4014
|
+
/* @__PURE__ */ jsx51(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) }),
|
|
4015
|
+
/* @__PURE__ */ jsxs46("div", { className: "fd-cal-foot", style: { margin: "0 14px 12px", paddingTop: 10 }, children: [
|
|
4016
|
+
/* @__PURE__ */ jsx51(
|
|
4003
4017
|
"button",
|
|
4004
4018
|
{
|
|
4005
4019
|
type: "button",
|
|
@@ -4012,22 +4026,22 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4012
4026
|
children: "Now"
|
|
4013
4027
|
}
|
|
4014
4028
|
),
|
|
4015
|
-
/* @__PURE__ */
|
|
4016
|
-
/* @__PURE__ */
|
|
4029
|
+
/* @__PURE__ */ jsx51("span", { style: { flex: 1 } }),
|
|
4030
|
+
/* @__PURE__ */ jsx51("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
|
|
4017
4031
|
] })
|
|
4018
4032
|
] }),
|
|
4019
4033
|
document.body
|
|
4020
4034
|
) : null,
|
|
4021
|
-
error ? /* @__PURE__ */
|
|
4022
|
-
/* @__PURE__ */
|
|
4035
|
+
error ? /* @__PURE__ */ jsxs46("span", { className: "fd-field-error", children: [
|
|
4036
|
+
/* @__PURE__ */ jsx51("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
4023
4037
|
error
|
|
4024
|
-
] }) : help ? /* @__PURE__ */
|
|
4038
|
+
] }) : help ? /* @__PURE__ */ jsx51("span", { className: "fd-field-help", children: help }) : null
|
|
4025
4039
|
] });
|
|
4026
4040
|
}
|
|
4027
4041
|
|
|
4028
4042
|
// src/components/forms/Slider.tsx
|
|
4029
|
-
import * as
|
|
4030
|
-
import { jsx as
|
|
4043
|
+
import * as React24 from "react";
|
|
4044
|
+
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
4031
4045
|
function Slider({
|
|
4032
4046
|
label,
|
|
4033
4047
|
min = 0,
|
|
@@ -4038,23 +4052,27 @@ function Slider({
|
|
|
4038
4052
|
format = (v) => String(v),
|
|
4039
4053
|
showChip = true,
|
|
4040
4054
|
help,
|
|
4055
|
+
id,
|
|
4056
|
+
"aria-label": ariaLabel,
|
|
4041
4057
|
className = "",
|
|
4042
4058
|
...rest
|
|
4043
4059
|
}) {
|
|
4044
|
-
const
|
|
4060
|
+
const fieldId = useFieldId(id);
|
|
4061
|
+
const [dragging, setDragging] = React24.useState(false);
|
|
4045
4062
|
const v = value === void 0 ? min : Number(value);
|
|
4046
4063
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4047
|
-
return /* @__PURE__ */
|
|
4048
|
-
label ? /* @__PURE__ */
|
|
4049
|
-
/* @__PURE__ */
|
|
4050
|
-
/* @__PURE__ */
|
|
4064
|
+
return /* @__PURE__ */ jsxs47("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
4065
|
+
label ? /* @__PURE__ */ jsxs47("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
4066
|
+
/* @__PURE__ */ jsx52(FieldLabel, { htmlFor: fieldId, children: label }),
|
|
4067
|
+
/* @__PURE__ */ jsx52("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: format(v) })
|
|
4051
4068
|
] }) : null,
|
|
4052
|
-
/* @__PURE__ */
|
|
4053
|
-
/* @__PURE__ */
|
|
4054
|
-
showChip && dragging ? /* @__PURE__ */
|
|
4055
|
-
/* @__PURE__ */
|
|
4069
|
+
/* @__PURE__ */ jsxs47("div", { className: "fd-slider", children: [
|
|
4070
|
+
/* @__PURE__ */ jsx52("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
4071
|
+
showChip && dragging ? /* @__PURE__ */ jsx52("span", { className: "fd-slider-chip", style: { left: pct + "%" }, children: format(v) }) : null,
|
|
4072
|
+
/* @__PURE__ */ jsx52(
|
|
4056
4073
|
"input",
|
|
4057
4074
|
{
|
|
4075
|
+
id: fieldId,
|
|
4058
4076
|
type: "range",
|
|
4059
4077
|
min,
|
|
4060
4078
|
max,
|
|
@@ -4064,18 +4082,18 @@ function Slider({
|
|
|
4064
4082
|
onPointerDown: () => setDragging(true),
|
|
4065
4083
|
onPointerUp: () => setDragging(false),
|
|
4066
4084
|
onBlur: () => setDragging(false),
|
|
4067
|
-
"aria-label":
|
|
4085
|
+
"aria-label": ariaLabel,
|
|
4068
4086
|
...rest
|
|
4069
4087
|
}
|
|
4070
4088
|
)
|
|
4071
4089
|
] }),
|
|
4072
|
-
help ? /* @__PURE__ */
|
|
4090
|
+
help ? /* @__PURE__ */ jsx52("span", { className: "fd-field-help", children: help }) : null
|
|
4073
4091
|
] });
|
|
4074
4092
|
}
|
|
4075
4093
|
|
|
4076
4094
|
// src/components/forms/RangeSlider.tsx
|
|
4077
|
-
import * as
|
|
4078
|
-
import { jsx as
|
|
4095
|
+
import * as React25 from "react";
|
|
4096
|
+
import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
4079
4097
|
function RangeSlider({
|
|
4080
4098
|
label,
|
|
4081
4099
|
min = 0,
|
|
@@ -4094,9 +4112,9 @@ function RangeSlider({
|
|
|
4094
4112
|
}) {
|
|
4095
4113
|
const fmt2 = format || ((v) => String(v));
|
|
4096
4114
|
const [a, b] = value || [min, max];
|
|
4097
|
-
const [drag, setDrag] =
|
|
4098
|
-
const [focus, setFocus] =
|
|
4099
|
-
const railRef =
|
|
4115
|
+
const [drag, setDrag] = React25.useState(null);
|
|
4116
|
+
const [focus, setFocus] = React25.useState(null);
|
|
4117
|
+
const railRef = React25.useRef(null);
|
|
4100
4118
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4101
4119
|
const clampPair = (i, v) => {
|
|
4102
4120
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -4111,7 +4129,7 @@ function RangeSlider({
|
|
|
4111
4129
|
const r = railRef.current.getBoundingClientRect();
|
|
4112
4130
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
4113
4131
|
};
|
|
4114
|
-
|
|
4132
|
+
React25.useEffect(() => {
|
|
4115
4133
|
if (drag === null) return;
|
|
4116
4134
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
4117
4135
|
const upH = () => setDrag(null);
|
|
@@ -4132,7 +4150,7 @@ function RangeSlider({
|
|
|
4132
4150
|
};
|
|
4133
4151
|
const thin = S.length > 7 ? Math.ceil(S.length / 5) : 1;
|
|
4134
4152
|
const pair = value || [S[0].value, S[S.length - 1].value];
|
|
4135
|
-
return /* @__PURE__ */
|
|
4153
|
+
return /* @__PURE__ */ jsx53(
|
|
4136
4154
|
RangeSlider,
|
|
4137
4155
|
{
|
|
4138
4156
|
...rest,
|
|
@@ -4180,23 +4198,23 @@ function RangeSlider({
|
|
|
4180
4198
|
};
|
|
4181
4199
|
const showChip = (i) => drag === i || focus === i;
|
|
4182
4200
|
const hasLabels = marks.some((m) => m.label);
|
|
4183
|
-
return /* @__PURE__ */
|
|
4184
|
-
label ? /* @__PURE__ */
|
|
4185
|
-
/* @__PURE__ */
|
|
4186
|
-
/* @__PURE__ */
|
|
4201
|
+
return /* @__PURE__ */ jsxs48("div", { className: ["fd-field", className].filter(Boolean).join(" "), ...rest, children: [
|
|
4202
|
+
label ? /* @__PURE__ */ jsxs48("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
4203
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-field-label", children: label }),
|
|
4204
|
+
/* @__PURE__ */ jsxs48("span", { className: "fd-num", style: { color: "var(--text-2)" }, children: [
|
|
4187
4205
|
fmt2(a),
|
|
4188
4206
|
" \u2013 ",
|
|
4189
4207
|
fmt2(b)
|
|
4190
4208
|
] })
|
|
4191
4209
|
] }) : null,
|
|
4192
|
-
/* @__PURE__ */
|
|
4193
|
-
/* @__PURE__ */
|
|
4194
|
-
/* @__PURE__ */
|
|
4195
|
-
marks.map((m) => /* @__PURE__ */
|
|
4196
|
-
/* @__PURE__ */
|
|
4197
|
-
m.label ? /* @__PURE__ */
|
|
4210
|
+
/* @__PURE__ */ jsxs48("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
4211
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-range-rail", ref: railRef }),
|
|
4212
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
4213
|
+
marks.map((m) => /* @__PURE__ */ jsxs48(React25.Fragment, { children: [
|
|
4214
|
+
/* @__PURE__ */ jsx53("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
4215
|
+
m.label ? /* @__PURE__ */ jsx53("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
4198
4216
|
] }, m.value)),
|
|
4199
|
-
[a, b].map((v, i) => /* @__PURE__ */
|
|
4217
|
+
[a, b].map((v, i) => /* @__PURE__ */ jsx53(
|
|
4200
4218
|
"span",
|
|
4201
4219
|
{
|
|
4202
4220
|
className: "fd-range-thumb" + (drag === i ? " is-drag" : ""),
|
|
@@ -4211,18 +4229,18 @@ function RangeSlider({
|
|
|
4211
4229
|
onKeyDown: key(i),
|
|
4212
4230
|
onFocus: () => setFocus(i),
|
|
4213
4231
|
onBlur: () => setFocus(null),
|
|
4214
|
-
children: /* @__PURE__ */
|
|
4232
|
+
children: /* @__PURE__ */ jsx53("span", { className: "fd-range-chip", style: { opacity: showChip(i) ? 1 : void 0 }, children: fmt2(v) })
|
|
4215
4233
|
},
|
|
4216
4234
|
i
|
|
4217
4235
|
))
|
|
4218
4236
|
] }),
|
|
4219
|
-
help ? /* @__PURE__ */
|
|
4237
|
+
help ? /* @__PURE__ */ jsx53("span", { className: "fd-field-help", children: help }) : null
|
|
4220
4238
|
] });
|
|
4221
4239
|
}
|
|
4222
4240
|
|
|
4223
4241
|
// src/components/forms/Dropzone.tsx
|
|
4224
|
-
import * as
|
|
4225
|
-
import { jsx as
|
|
4242
|
+
import * as React26 from "react";
|
|
4243
|
+
import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
4226
4244
|
function Dropzone({
|
|
4227
4245
|
onFiles,
|
|
4228
4246
|
onReject,
|
|
@@ -4236,8 +4254,8 @@ function Dropzone({
|
|
|
4236
4254
|
className = "",
|
|
4237
4255
|
style
|
|
4238
4256
|
}) {
|
|
4239
|
-
const [over, setOver] =
|
|
4240
|
-
const depth =
|
|
4257
|
+
const [over, setOver] = React26.useState(false);
|
|
4258
|
+
const depth = React26.useRef(0);
|
|
4241
4259
|
const has = (e) => {
|
|
4242
4260
|
const dt = e.dataTransfer;
|
|
4243
4261
|
if (!dt) return false;
|
|
@@ -4267,7 +4285,7 @@ function Dropzone({
|
|
|
4267
4285
|
if (rejected.length && onReject) onReject(rejected);
|
|
4268
4286
|
if (accepted.length && onFiles) onFiles(accepted);
|
|
4269
4287
|
};
|
|
4270
|
-
return /* @__PURE__ */
|
|
4288
|
+
return /* @__PURE__ */ jsxs49(
|
|
4271
4289
|
"div",
|
|
4272
4290
|
{
|
|
4273
4291
|
className: ["fd-dropzone", over ? "is-over" : "", className].filter(Boolean).join(" "),
|
|
@@ -4278,10 +4296,10 @@ function Dropzone({
|
|
|
4278
4296
|
onDrop: drop,
|
|
4279
4297
|
children: [
|
|
4280
4298
|
children,
|
|
4281
|
-
over ? /* @__PURE__ */
|
|
4282
|
-
/* @__PURE__ */
|
|
4283
|
-
/* @__PURE__ */
|
|
4284
|
-
hint ? /* @__PURE__ */
|
|
4299
|
+
over ? /* @__PURE__ */ jsx54("div", { className: "fd-dropzone-veil", "aria-hidden": "true", children: /* @__PURE__ */ jsxs49("div", { className: "fd-dropzone-card", children: [
|
|
4300
|
+
/* @__PURE__ */ jsx54("i", { className: "ph ph-tray-arrow-down" }),
|
|
4301
|
+
/* @__PURE__ */ jsx54("span", { className: "fd-dropzone-label", children: label }),
|
|
4302
|
+
hint ? /* @__PURE__ */ jsx54("span", { className: "fd-dropzone-hint", children: hint }) : null
|
|
4285
4303
|
] }) }) : null
|
|
4286
4304
|
]
|
|
4287
4305
|
}
|
|
@@ -4299,9 +4317,9 @@ function FilePickButton({
|
|
|
4299
4317
|
className = "",
|
|
4300
4318
|
children
|
|
4301
4319
|
}) {
|
|
4302
|
-
const ref =
|
|
4303
|
-
return /* @__PURE__ */
|
|
4304
|
-
/* @__PURE__ */
|
|
4320
|
+
const ref = React26.useRef(null);
|
|
4321
|
+
return /* @__PURE__ */ jsxs49(React26.Fragment, { children: [
|
|
4322
|
+
/* @__PURE__ */ jsx54(
|
|
4305
4323
|
"button",
|
|
4306
4324
|
{
|
|
4307
4325
|
type: "button",
|
|
@@ -4310,10 +4328,10 @@ function FilePickButton({
|
|
|
4310
4328
|
"aria-label": label,
|
|
4311
4329
|
title: label,
|
|
4312
4330
|
onClick: () => ref.current && ref.current.click(),
|
|
4313
|
-
children: children != null ? children : /* @__PURE__ */
|
|
4331
|
+
children: children != null ? children : /* @__PURE__ */ jsx54("i", { className: "ph ph-" + icon, "aria-hidden": "true" })
|
|
4314
4332
|
}
|
|
4315
4333
|
),
|
|
4316
|
-
/* @__PURE__ */
|
|
4334
|
+
/* @__PURE__ */ jsx54(
|
|
4317
4335
|
"input",
|
|
4318
4336
|
{
|
|
4319
4337
|
ref,
|
|
@@ -4333,10 +4351,10 @@ function FilePickButton({
|
|
|
4333
4351
|
}
|
|
4334
4352
|
function useStagedFiles(upload, opts) {
|
|
4335
4353
|
const o = opts || {};
|
|
4336
|
-
const [items, setItems] =
|
|
4337
|
-
const controllers =
|
|
4354
|
+
const [items, setItems] = React26.useState([]);
|
|
4355
|
+
const controllers = React26.useRef({});
|
|
4338
4356
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
4339
|
-
const run =
|
|
4357
|
+
const run = React26.useCallback((att) => {
|
|
4340
4358
|
if (!upload) return;
|
|
4341
4359
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
4342
4360
|
controllers.current[att.id] = ac;
|
|
@@ -4353,14 +4371,14 @@ function useStagedFiles(upload, opts) {
|
|
|
4353
4371
|
delete controllers.current[att.id];
|
|
4354
4372
|
});
|
|
4355
4373
|
}, [upload]);
|
|
4356
|
-
const add =
|
|
4374
|
+
const add = React26.useCallback((files) => {
|
|
4357
4375
|
if (!upload) return [];
|
|
4358
4376
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
4359
4377
|
setItems((list) => list.concat(atts));
|
|
4360
4378
|
atts.forEach(run);
|
|
4361
4379
|
return atts;
|
|
4362
4380
|
}, [upload, run]);
|
|
4363
|
-
const remove =
|
|
4381
|
+
const remove = React26.useCallback((att) => {
|
|
4364
4382
|
const ac = controllers.current[att.id];
|
|
4365
4383
|
if (ac) {
|
|
4366
4384
|
try {
|
|
@@ -4371,10 +4389,10 @@ function useStagedFiles(upload, opts) {
|
|
|
4371
4389
|
}
|
|
4372
4390
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
4373
4391
|
}, []);
|
|
4374
|
-
const retry =
|
|
4392
|
+
const retry = React26.useCallback((att) => {
|
|
4375
4393
|
run(att);
|
|
4376
4394
|
}, [run]);
|
|
4377
|
-
const clear =
|
|
4395
|
+
const clear = React26.useCallback(() => {
|
|
4378
4396
|
Object.values(controllers.current).forEach((ac) => {
|
|
4379
4397
|
try {
|
|
4380
4398
|
ac && ac.abort();
|
|
@@ -4390,7 +4408,7 @@ function useStagedFiles(upload, opts) {
|
|
|
4390
4408
|
var DropzoneKit = { useStagedFiles };
|
|
4391
4409
|
|
|
4392
4410
|
// src/components/forms/FileGrid.tsx
|
|
4393
|
-
import { jsx as
|
|
4411
|
+
import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
4394
4412
|
var truncateMiddle = (name, max = 34) => {
|
|
4395
4413
|
if (!name || name.length <= max) return name;
|
|
4396
4414
|
const ext = /\.[A-Za-z0-9]+$/.exec(name);
|
|
@@ -4399,7 +4417,7 @@ var truncateMiddle = (name, max = 34) => {
|
|
|
4399
4417
|
return head + "\u2026" + tail;
|
|
4400
4418
|
};
|
|
4401
4419
|
function Progress({ value }) {
|
|
4402
|
-
return /* @__PURE__ */
|
|
4420
|
+
return /* @__PURE__ */ jsx55("span", { className: "fd-file-prog", role: "progressbar", "aria-valuenow": Math.round(value), "aria-valuemin": 0, "aria-valuemax": 100, children: /* @__PURE__ */ jsx55("span", { className: "fd-file-prog-fill", style: { width: Math.max(4, Math.min(100, value)) + "%" } }) });
|
|
4403
4421
|
}
|
|
4404
4422
|
function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false, className = "" }) {
|
|
4405
4423
|
if (!file) return null;
|
|
@@ -4408,8 +4426,8 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
4408
4426
|
const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
|
|
4409
4427
|
const meta = file.meta || (file.size ? formatBytes(file.size) : "");
|
|
4410
4428
|
const clickable = !!onOpen && !uploading;
|
|
4411
|
-
return /* @__PURE__ */
|
|
4412
|
-
/* @__PURE__ */
|
|
4429
|
+
return /* @__PURE__ */ jsxs50("div", { className: ["fd-file", compact3 ? "is-compact" : "", file.error ? "is-error" : "", uploading ? "is-uploading" : "", className].filter(Boolean).join(" "), children: [
|
|
4430
|
+
/* @__PURE__ */ jsxs50(
|
|
4413
4431
|
"button",
|
|
4414
4432
|
{
|
|
4415
4433
|
type: "button",
|
|
@@ -4418,16 +4436,16 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
4418
4436
|
onClick: clickable ? () => onOpen(file) : void 0,
|
|
4419
4437
|
title: file.name + (meta ? " \xB7 " + meta : ""),
|
|
4420
4438
|
children: [
|
|
4421
|
-
/* @__PURE__ */
|
|
4422
|
-
thumb ? /* @__PURE__ */
|
|
4423
|
-
(file.mime || "").startsWith("video/") ? /* @__PURE__ */
|
|
4439
|
+
/* @__PURE__ */ jsxs50("span", { className: "fd-file-icon", children: [
|
|
4440
|
+
thumb ? /* @__PURE__ */ jsx55("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsx55("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
|
|
4441
|
+
(file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx55("i", { className: "ph ph-play fd-file-play", "aria-hidden": "true" }) : null
|
|
4424
4442
|
] }),
|
|
4425
|
-
/* @__PURE__ */
|
|
4426
|
-
/* @__PURE__ */
|
|
4427
|
-
/* @__PURE__ */
|
|
4428
|
-
/* @__PURE__ */
|
|
4443
|
+
/* @__PURE__ */ jsxs50("span", { className: "fd-file-text", children: [
|
|
4444
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-file-name", children: truncateMiddle(file.name, compact3 ? 26 : 40) }),
|
|
4445
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-file-meta", children: file.error ? /* @__PURE__ */ jsxs50("span", { className: "fd-file-err", children: [
|
|
4446
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
4429
4447
|
file.error
|
|
4430
|
-
] }) : uploading ? /* @__PURE__ */
|
|
4448
|
+
] }) : uploading ? /* @__PURE__ */ jsxs50("span", { className: "fd-tabular", children: [
|
|
4431
4449
|
Math.round(file.progress),
|
|
4432
4450
|
"% uploaded"
|
|
4433
4451
|
] }) : meta })
|
|
@@ -4435,29 +4453,29 @@ function FileChip({ file, onOpen, onRemove, onRetry, compact: compact3 = false,
|
|
|
4435
4453
|
]
|
|
4436
4454
|
}
|
|
4437
4455
|
),
|
|
4438
|
-
uploading ? /* @__PURE__ */
|
|
4439
|
-
file.error && onRetry ? /* @__PURE__ */
|
|
4440
|
-
onRemove ? /* @__PURE__ */
|
|
4456
|
+
uploading ? /* @__PURE__ */ jsx55(Progress, { value: file.progress }) : null,
|
|
4457
|
+
file.error && onRetry ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-file-act", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
4458
|
+
onRemove ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-file-act", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
4441
4459
|
] });
|
|
4442
4460
|
}
|
|
4443
4461
|
function FileTile({ file, onOpen, onRemove, maxHeight = 200, className = "" }) {
|
|
4444
4462
|
if (!file) return null;
|
|
4445
4463
|
const src = file.thumb && file.thumb.url || file.blobUrl || file.url;
|
|
4446
4464
|
const uploading = file.progress != null && file.progress < 100 && !file.error;
|
|
4447
|
-
return /* @__PURE__ */
|
|
4448
|
-
/* @__PURE__ */
|
|
4449
|
-
uploading ? /* @__PURE__ */
|
|
4450
|
-
file.error ? /* @__PURE__ */
|
|
4451
|
-
/* @__PURE__ */
|
|
4465
|
+
return /* @__PURE__ */ jsxs50("figure", { className: ["fd-tile", uploading ? "is-uploading" : "", file.error ? "is-error" : "", className].filter(Boolean).join(" "), children: [
|
|
4466
|
+
/* @__PURE__ */ jsx55("button", { type: "button", className: "fd-tile-btn", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen, children: src ? /* @__PURE__ */ jsx55("img", { src, alt: file.name || "", style: { maxHeight }, loading: "lazy" }) : /* @__PURE__ */ jsx55("span", { className: "fd-tile-fallback", children: /* @__PURE__ */ jsx55("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }) }) }),
|
|
4467
|
+
uploading ? /* @__PURE__ */ jsx55(Progress, { value: file.progress }) : null,
|
|
4468
|
+
file.error ? /* @__PURE__ */ jsxs50("figcaption", { className: "fd-tile-err", children: [
|
|
4469
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
4452
4470
|
file.error
|
|
4453
4471
|
] }) : null,
|
|
4454
|
-
onRemove ? /* @__PURE__ */
|
|
4472
|
+
onRemove ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-tile-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
4455
4473
|
] });
|
|
4456
4474
|
}
|
|
4457
4475
|
function FileStrip({ files = [], size = 68, onOpen, onRemove, onRetry, className = "" }) {
|
|
4458
4476
|
const list = files.filter(Boolean);
|
|
4459
4477
|
if (!list.length) return null;
|
|
4460
|
-
return /* @__PURE__ */
|
|
4478
|
+
return /* @__PURE__ */ jsx55("div", { className: ["fd-filestrip", "fd-scrollbar", className].filter(Boolean).join(" "), style: { "--fd-cell": size + "px" }, children: list.map((f) => /* @__PURE__ */ jsx55(FileCell, { file: f, onOpen, onRemove, onRetry }, f.id || f.name)) });
|
|
4461
4479
|
}
|
|
4462
4480
|
var shortName = (name, keep = 5) => {
|
|
4463
4481
|
const s = String(name || "file");
|
|
@@ -4471,19 +4489,19 @@ function FileCell({ file, onOpen, onRemove, onRetry }) {
|
|
|
4471
4489
|
const image = isImage(file.mime, file.name);
|
|
4472
4490
|
const thumb = file.thumb && file.thumb.url || (image ? file.blobUrl || file.url : null);
|
|
4473
4491
|
const label = file.name + (file.size ? " \xB7 " + formatBytes(file.size) : "");
|
|
4474
|
-
return /* @__PURE__ */
|
|
4475
|
-
/* @__PURE__ */
|
|
4476
|
-
thumb ? /* @__PURE__ */
|
|
4477
|
-
/* @__PURE__ */
|
|
4478
|
-
/* @__PURE__ */
|
|
4479
|
-
/* @__PURE__ */
|
|
4492
|
+
return /* @__PURE__ */ jsxs50("div", { className: ["fd-cell", file.error ? "is-error" : "", uploading ? "is-uploading" : ""].filter(Boolean).join(" "), title: file.error ? file.name + " \u2014 " + file.error : label, children: [
|
|
4493
|
+
/* @__PURE__ */ jsxs50("button", { type: "button", className: "fd-cell-main", onClick: onOpen ? () => onOpen(file) : void 0, disabled: !onOpen || uploading, "aria-label": "Open " + file.name, children: [
|
|
4494
|
+
thumb ? /* @__PURE__ */ jsx55("img", { src: thumb, alt: "" }) : /* @__PURE__ */ jsxs50("span", { className: "fd-cell-doc", children: [
|
|
4495
|
+
/* @__PURE__ */ jsx55("i", { className: "ph ph-" + iconForMime(file.mime, file.name), "aria-hidden": "true" }),
|
|
4496
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-cell-name", children: shortName(file.name) }),
|
|
4497
|
+
/* @__PURE__ */ jsx55("span", { className: "fd-cell-size", children: file.meta || formatBytes(file.size) })
|
|
4480
4498
|
] }),
|
|
4481
|
-
(file.mime || "").startsWith("video/") ? /* @__PURE__ */
|
|
4499
|
+
(file.mime || "").startsWith("video/") ? /* @__PURE__ */ jsx55("i", { className: "ph ph-play fd-cell-play", "aria-hidden": "true" }) : null
|
|
4482
4500
|
] }),
|
|
4483
|
-
uploading ? /* @__PURE__ */
|
|
4484
|
-
file.error ? /* @__PURE__ */
|
|
4485
|
-
file.error && onRetry ? /* @__PURE__ */
|
|
4486
|
-
onRemove ? /* @__PURE__ */
|
|
4501
|
+
uploading ? /* @__PURE__ */ jsx55(Progress, { value: file.progress }) : null,
|
|
4502
|
+
file.error ? /* @__PURE__ */ jsx55("span", { className: "fd-cell-err", "aria-hidden": "true", children: /* @__PURE__ */ jsx55("i", { className: "ph ph-warning-circle" }) }) : null,
|
|
4503
|
+
file.error && onRetry ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-cell-x is-retry", onClick: () => onRetry(file), "aria-label": "Retry upload of " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
4504
|
+
onRemove ? /* @__PURE__ */ jsx55("button", { type: "button", className: "fd-cell-x", onClick: () => onRemove(file), "aria-label": "Remove " + file.name, children: /* @__PURE__ */ jsx55("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
4487
4505
|
] });
|
|
4488
4506
|
}
|
|
4489
4507
|
function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeight = 200, compact: compact3 = false, className = "" }) {
|
|
@@ -4491,15 +4509,15 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
4491
4509
|
if (!list.length) return null;
|
|
4492
4510
|
const pics = tiles ? list.filter((f) => isImage(f.mime, f.name)) : [];
|
|
4493
4511
|
const rest = list.filter((f) => pics.indexOf(f) === -1);
|
|
4494
|
-
return /* @__PURE__ */
|
|
4495
|
-
pics.length ? /* @__PURE__ */
|
|
4496
|
-
rest.length ? /* @__PURE__ */
|
|
4512
|
+
return /* @__PURE__ */ jsxs50("div", { className: ["fd-filegrid", className].filter(Boolean).join(" "), children: [
|
|
4513
|
+
pics.length ? /* @__PURE__ */ jsx55("div", { className: "fd-filegrid-tiles", children: pics.map((f) => /* @__PURE__ */ jsx55(FileTile, { file: f, onOpen, onRemove, maxHeight }, f.id || f.name)) }) : null,
|
|
4514
|
+
rest.length ? /* @__PURE__ */ jsx55("div", { className: "fd-filegrid-chips", children: rest.map((f) => /* @__PURE__ */ jsx55(FileChip, { file: f, onOpen, onRemove, onRetry, compact: compact3 }, f.id || f.name)) }) : null
|
|
4497
4515
|
] });
|
|
4498
4516
|
}
|
|
4499
4517
|
|
|
4500
4518
|
// src/components/forms/MarkdownEditor.tsx
|
|
4501
|
-
import * as
|
|
4502
|
-
import { jsx as
|
|
4519
|
+
import * as React27 from "react";
|
|
4520
|
+
import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
4503
4521
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
4504
4522
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
4505
4523
|
function inlineParts(text) {
|
|
@@ -4712,7 +4730,7 @@ function syncDom(root, value) {
|
|
|
4712
4730
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
4713
4731
|
}
|
|
4714
4732
|
var LIST_CONT = RE_LI;
|
|
4715
|
-
var MarkdownEditor =
|
|
4733
|
+
var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
4716
4734
|
value = "",
|
|
4717
4735
|
onChange,
|
|
4718
4736
|
onSubmit,
|
|
@@ -4731,10 +4749,10 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
|
|
|
4731
4749
|
className = "",
|
|
4732
4750
|
id
|
|
4733
4751
|
}, ref) {
|
|
4734
|
-
const boxRef =
|
|
4735
|
-
const composing =
|
|
4736
|
-
const pendingCaret =
|
|
4737
|
-
|
|
4752
|
+
const boxRef = React27.useRef(null);
|
|
4753
|
+
const composing = React27.useRef(false);
|
|
4754
|
+
const pendingCaret = React27.useRef(null);
|
|
4755
|
+
React27.useLayoutEffect(() => {
|
|
4738
4756
|
const root = boxRef.current;
|
|
4739
4757
|
if (!root || composing.current) return;
|
|
4740
4758
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -4743,7 +4761,7 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
|
|
|
4743
4761
|
pendingCaret.current = null;
|
|
4744
4762
|
if (active && caret != null) placeCaret(root, caret);
|
|
4745
4763
|
}, [value]);
|
|
4746
|
-
|
|
4764
|
+
React27.useEffect(() => {
|
|
4747
4765
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
4748
4766
|
}, [autoFocus]);
|
|
4749
4767
|
const caretNow = () => {
|
|
@@ -4810,7 +4828,7 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
|
|
|
4810
4828
|
api.replaceRange(from, to, next, from + next.length);
|
|
4811
4829
|
}
|
|
4812
4830
|
};
|
|
4813
|
-
|
|
4831
|
+
React27.useImperativeHandle(ref, () => api);
|
|
4814
4832
|
function detect(text, caret) {
|
|
4815
4833
|
if (!onTrigger) return;
|
|
4816
4834
|
const upto = text.slice(0, caret);
|
|
@@ -4923,8 +4941,8 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
|
|
|
4923
4941
|
api.replaceRange(s.start, s.end, text.replace(/\r\n?/g, "\n"));
|
|
4924
4942
|
};
|
|
4925
4943
|
const lh = 1.55;
|
|
4926
|
-
return /* @__PURE__ */
|
|
4927
|
-
/* @__PURE__ */
|
|
4944
|
+
return /* @__PURE__ */ jsxs51("div", { className: ["fd-rme-wrap", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "), children: [
|
|
4945
|
+
/* @__PURE__ */ jsx56(
|
|
4928
4946
|
"div",
|
|
4929
4947
|
{
|
|
4930
4948
|
ref: boxRef,
|
|
@@ -4957,15 +4975,15 @@ var MarkdownEditor = React26.forwardRef(function MarkdownEditor2({
|
|
|
4957
4975
|
}
|
|
4958
4976
|
}
|
|
4959
4977
|
),
|
|
4960
|
-
!value ? /* @__PURE__ */
|
|
4978
|
+
!value ? /* @__PURE__ */ jsx56("span", { className: "fd-rme-ph", "aria-hidden": "true", children: placeholder }) : null
|
|
4961
4979
|
] });
|
|
4962
4980
|
});
|
|
4963
4981
|
|
|
4964
4982
|
// src/components/platform/AccountMenu.tsx
|
|
4965
|
-
import * as
|
|
4983
|
+
import * as React29 from "react";
|
|
4966
4984
|
|
|
4967
4985
|
// src/kits/session.ts
|
|
4968
|
-
import * as
|
|
4986
|
+
import * as React28 from "react";
|
|
4969
4987
|
var PERMISSION_CATALOG = [
|
|
4970
4988
|
{ group: "Plans", items: [
|
|
4971
4989
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -6532,8 +6550,8 @@ function roadmap(overrides) {
|
|
|
6532
6550
|
};
|
|
6533
6551
|
}
|
|
6534
6552
|
function useSession() {
|
|
6535
|
-
const [s, setS] =
|
|
6536
|
-
|
|
6553
|
+
const [s, setS] = React28.useState(getSession);
|
|
6554
|
+
React28.useEffect(() => subscribe(setS), []);
|
|
6537
6555
|
return s;
|
|
6538
6556
|
}
|
|
6539
6557
|
var SessionKit = {
|
|
@@ -6566,7 +6584,7 @@ var SessionKit = {
|
|
|
6566
6584
|
};
|
|
6567
6585
|
|
|
6568
6586
|
// src/components/platform/AccountMenu.tsx
|
|
6569
|
-
import { Fragment as Fragment12, jsx as
|
|
6587
|
+
import { Fragment as Fragment12, jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
6570
6588
|
var DEFAULT_LINKS = [
|
|
6571
6589
|
{ id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
|
|
6572
6590
|
{ id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
|
|
@@ -6577,7 +6595,7 @@ var DEFAULT_ADMIN_LINKS = [
|
|
|
6577
6595
|
{ id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
|
|
6578
6596
|
];
|
|
6579
6597
|
function Item({ item, onPick }) {
|
|
6580
|
-
return /* @__PURE__ */
|
|
6598
|
+
return /* @__PURE__ */ jsxs52(
|
|
6581
6599
|
"button",
|
|
6582
6600
|
{
|
|
6583
6601
|
type: "button",
|
|
@@ -6585,9 +6603,9 @@ function Item({ item, onPick }) {
|
|
|
6585
6603
|
className: "fd-acct-item",
|
|
6586
6604
|
onClick: () => onPick(item),
|
|
6587
6605
|
children: [
|
|
6588
|
-
/* @__PURE__ */
|
|
6589
|
-
/* @__PURE__ */
|
|
6590
|
-
item.badge ? /* @__PURE__ */
|
|
6606
|
+
/* @__PURE__ */ jsx57("i", { className: "ph ph-" + item.icon, "aria-hidden": "true" }),
|
|
6607
|
+
/* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: item.label }),
|
|
6608
|
+
item.badge ? /* @__PURE__ */ jsx57(Badge, { tone: "neutral", children: item.badge }) : null
|
|
6591
6609
|
]
|
|
6592
6610
|
}
|
|
6593
6611
|
);
|
|
@@ -6603,9 +6621,9 @@ function AccountMenu({
|
|
|
6603
6621
|
...rest
|
|
6604
6622
|
}) {
|
|
6605
6623
|
const session = SessionKit.useSession();
|
|
6606
|
-
const [open, setOpen] =
|
|
6607
|
-
const [switching, setSwitching] =
|
|
6608
|
-
const ref =
|
|
6624
|
+
const [open, setOpen] = React29.useState(false);
|
|
6625
|
+
const [switching, setSwitching] = React29.useState(false);
|
|
6626
|
+
const ref = React29.useRef(null);
|
|
6609
6627
|
const user = session.user;
|
|
6610
6628
|
const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
|
|
6611
6629
|
const pick = (item) => {
|
|
@@ -6619,8 +6637,8 @@ function AccountMenu({
|
|
|
6619
6637
|
if (onSignOut) return onSignOut();
|
|
6620
6638
|
window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
|
|
6621
6639
|
};
|
|
6622
|
-
return /* @__PURE__ */
|
|
6623
|
-
/* @__PURE__ */
|
|
6640
|
+
return /* @__PURE__ */ jsxs52(Fragment12, { children: [
|
|
6641
|
+
/* @__PURE__ */ jsxs52(
|
|
6624
6642
|
"button",
|
|
6625
6643
|
{
|
|
6626
6644
|
type: "button",
|
|
@@ -6632,32 +6650,32 @@ function AccountMenu({
|
|
|
6632
6650
|
onClick: () => setOpen((o) => !o),
|
|
6633
6651
|
...rest,
|
|
6634
6652
|
children: [
|
|
6635
|
-
/* @__PURE__ */
|
|
6636
|
-
/* @__PURE__ */
|
|
6653
|
+
/* @__PURE__ */ jsx57(Avatar, { name: user.name, size: "sm" }),
|
|
6654
|
+
/* @__PURE__ */ jsx57("i", { className: "ph ph-caret-down", "aria-hidden": "true", style: { fontSize: 11, color: "var(--text-muted)" } })
|
|
6637
6655
|
]
|
|
6638
6656
|
}
|
|
6639
6657
|
),
|
|
6640
|
-
/* @__PURE__ */
|
|
6641
|
-
/* @__PURE__ */
|
|
6642
|
-
/* @__PURE__ */
|
|
6643
|
-
/* @__PURE__ */
|
|
6644
|
-
/* @__PURE__ */
|
|
6645
|
-
/* @__PURE__ */
|
|
6658
|
+
/* @__PURE__ */ jsx57(Popover, { open, anchorRef: ref, onClose: () => setOpen(false), placement: "bottom-end", width: 272, children: /* @__PURE__ */ jsxs52("div", { role: "menu", className: "fd-stack", style: { gap: 0 }, children: [
|
|
6659
|
+
/* @__PURE__ */ jsxs52("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
6660
|
+
/* @__PURE__ */ jsx57(Avatar, { name: user.name }),
|
|
6661
|
+
/* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 1, minWidth: 0, flex: 1 }, children: [
|
|
6662
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: user.name }),
|
|
6663
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-body-sm fd-muted fd-table-trunc", children: user.email })
|
|
6646
6664
|
] })
|
|
6647
6665
|
] }),
|
|
6648
|
-
showRoles && session.roles.length ? /* @__PURE__ */
|
|
6649
|
-
/* @__PURE__ */
|
|
6650
|
-
visibleAdmin.length ? /* @__PURE__ */
|
|
6651
|
-
/* @__PURE__ */
|
|
6652
|
-
visibleAdmin.map((l) => /* @__PURE__ */
|
|
6666
|
+
showRoles && session.roles.length ? /* @__PURE__ */ jsx57("div", { className: "fd-row", style: { gap: 6, padding: "10px 14px", flexWrap: "wrap", borderBottom: "1px solid var(--border)" }, children: session.roles.map((r) => /* @__PURE__ */ jsx57(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)) }) : null,
|
|
6667
|
+
/* @__PURE__ */ jsx57("div", { className: "fd-acct-group", children: links.map((l) => /* @__PURE__ */ jsx57(Item, { item: l, onPick: pick }, l.id)) }),
|
|
6668
|
+
visibleAdmin.length ? /* @__PURE__ */ jsxs52("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
|
|
6669
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-overline fd-muted", style: { padding: "8px 14px 4px", display: "block" }, children: "Administration" }),
|
|
6670
|
+
visibleAdmin.map((l) => /* @__PURE__ */ jsx57(Item, { item: l, onPick: pick }, l.id))
|
|
6653
6671
|
] }) : null,
|
|
6654
|
-
allowUserSwitch ? /* @__PURE__ */
|
|
6655
|
-
/* @__PURE__ */
|
|
6656
|
-
/* @__PURE__ */
|
|
6657
|
-
/* @__PURE__ */
|
|
6658
|
-
/* @__PURE__ */
|
|
6672
|
+
allowUserSwitch ? /* @__PURE__ */ jsxs52("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: [
|
|
6673
|
+
/* @__PURE__ */ jsxs52("button", { type: "button", role: "menuitem", className: "fd-acct-item", onClick: () => setSwitching((s) => !s), children: [
|
|
6674
|
+
/* @__PURE__ */ jsx57("i", { className: "ph ph-user-switch", "aria-hidden": "true" }),
|
|
6675
|
+
/* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: "View as another member" }),
|
|
6676
|
+
/* @__PURE__ */ jsx57("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
|
|
6659
6677
|
] }),
|
|
6660
|
-
switching ? /* @__PURE__ */
|
|
6678
|
+
switching ? /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0, maxHeight: 208, overflowY: "auto" }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs52(
|
|
6661
6679
|
"button",
|
|
6662
6680
|
{
|
|
6663
6681
|
type: "button",
|
|
@@ -6669,34 +6687,34 @@ function AccountMenu({
|
|
|
6669
6687
|
setSwitching(false);
|
|
6670
6688
|
},
|
|
6671
6689
|
children: [
|
|
6672
|
-
/* @__PURE__ */
|
|
6673
|
-
/* @__PURE__ */
|
|
6674
|
-
/* @__PURE__ */
|
|
6675
|
-
/* @__PURE__ */
|
|
6690
|
+
/* @__PURE__ */ jsx57(Avatar, { name: u.name, size: "sm" }),
|
|
6691
|
+
/* @__PURE__ */ jsxs52("span", { className: "fd-stack", style: { gap: 0, flex: 1, minWidth: 0, alignItems: "flex-start" }, children: [
|
|
6692
|
+
/* @__PURE__ */ jsx57("span", { style: { fontWeight: u.id === user.id ? 700 : 500 }, children: u.name }),
|
|
6693
|
+
/* @__PURE__ */ jsx57("span", { className: "fd-muted", style: { fontSize: 11.5 }, children: u.roles.join(", ") })
|
|
6676
6694
|
] }),
|
|
6677
|
-
u.id === user.id ? /* @__PURE__ */
|
|
6695
|
+
u.id === user.id ? /* @__PURE__ */ jsx57("i", { className: "ph ph-check", "aria-hidden": "true", style: { color: "var(--ok-text)" } }) : null
|
|
6678
6696
|
]
|
|
6679
6697
|
},
|
|
6680
6698
|
u.id
|
|
6681
6699
|
)) }) : null
|
|
6682
6700
|
] }) : null,
|
|
6683
|
-
/* @__PURE__ */
|
|
6684
|
-
/* @__PURE__ */
|
|
6685
|
-
/* @__PURE__ */
|
|
6701
|
+
/* @__PURE__ */ jsx57("div", { className: "fd-acct-group", style: { borderTop: "1px solid var(--border)" }, children: /* @__PURE__ */ jsxs52("button", { type: "button", role: "menuitem", className: "fd-acct-item", "data-danger": "true", onClick: signOut, children: [
|
|
6702
|
+
/* @__PURE__ */ jsx57("i", { className: "ph ph-sign-out", "aria-hidden": "true" }),
|
|
6703
|
+
/* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: "Sign out" })
|
|
6686
6704
|
] }) })
|
|
6687
6705
|
] }) })
|
|
6688
6706
|
] });
|
|
6689
6707
|
}
|
|
6690
6708
|
|
|
6691
6709
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
6692
|
-
import * as
|
|
6693
|
-
import { jsx as
|
|
6710
|
+
import * as React30 from "react";
|
|
6711
|
+
import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
6694
6712
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
6695
6713
|
function Json({ obj }) {
|
|
6696
|
-
return /* @__PURE__ */
|
|
6714
|
+
return /* @__PURE__ */ jsx58("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
6697
6715
|
}
|
|
6698
6716
|
function Endpoint({ s, onRequest }) {
|
|
6699
|
-
const [tried, setTried] =
|
|
6717
|
+
const [tried, setTried] = React30.useState(null);
|
|
6700
6718
|
const run = async () => {
|
|
6701
6719
|
setTried("busy");
|
|
6702
6720
|
const t0 = (window.performance || Date).now();
|
|
@@ -6707,50 +6725,50 @@ function Endpoint({ s, onRequest }) {
|
|
|
6707
6725
|
setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
|
|
6708
6726
|
}
|
|
6709
6727
|
};
|
|
6710
|
-
return /* @__PURE__ */
|
|
6711
|
-
/* @__PURE__ */
|
|
6712
|
-
/* @__PURE__ */
|
|
6713
|
-
/* @__PURE__ */
|
|
6714
|
-
s.isList ? /* @__PURE__ */
|
|
6715
|
-
/* @__PURE__ */
|
|
6716
|
-
/* @__PURE__ */
|
|
6728
|
+
return /* @__PURE__ */ jsx58(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
6729
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
|
|
6730
|
+
/* @__PURE__ */ jsx58(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
|
|
6731
|
+
/* @__PURE__ */ jsx58("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
|
|
6732
|
+
s.isList ? /* @__PURE__ */ jsx58(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
|
|
6733
|
+
/* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
|
|
6734
|
+
/* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
6717
6735
|
s.latency[0],
|
|
6718
6736
|
"\u2013",
|
|
6719
6737
|
s.latency[1],
|
|
6720
6738
|
"ms"
|
|
6721
6739
|
] }),
|
|
6722
|
-
/* @__PURE__ */
|
|
6740
|
+
/* @__PURE__ */ jsx58(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
|
|
6723
6741
|
] }),
|
|
6724
|
-
/* @__PURE__ */
|
|
6725
|
-
/* @__PURE__ */
|
|
6726
|
-
/* @__PURE__ */
|
|
6727
|
-
/* @__PURE__ */
|
|
6728
|
-
s.usedBy && s.usedBy.length ? /* @__PURE__ */
|
|
6742
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
|
|
6743
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6744
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
|
|
6745
|
+
/* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
|
|
6746
|
+
s.usedBy && s.usedBy.length ? /* @__PURE__ */ jsx58("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ jsx58(Tag, { children: u }, u)) }) : null
|
|
6729
6747
|
] }),
|
|
6730
|
-
/* @__PURE__ */
|
|
6731
|
-
s.request ? /* @__PURE__ */
|
|
6732
|
-
/* @__PURE__ */
|
|
6733
|
-
/* @__PURE__ */
|
|
6748
|
+
/* @__PURE__ */ jsxs53("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
|
|
6749
|
+
s.request ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6750
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Request body" }),
|
|
6751
|
+
/* @__PURE__ */ jsx58(Json, { obj: s.request })
|
|
6734
6752
|
] }) : null,
|
|
6735
|
-
s.query ? /* @__PURE__ */
|
|
6736
|
-
/* @__PURE__ */
|
|
6737
|
-
/* @__PURE__ */
|
|
6753
|
+
s.query ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6754
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Query" }),
|
|
6755
|
+
/* @__PURE__ */ jsx58(Json, { obj: s.query })
|
|
6738
6756
|
] }) : null,
|
|
6739
|
-
/* @__PURE__ */
|
|
6740
|
-
/* @__PURE__ */
|
|
6741
|
-
/* @__PURE__ */
|
|
6757
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6758
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Response 200" }),
|
|
6759
|
+
/* @__PURE__ */ jsx58(Json, { obj: s.response })
|
|
6742
6760
|
] })
|
|
6743
6761
|
] }),
|
|
6744
|
-
s.notes ? /* @__PURE__ */
|
|
6745
|
-
tried && tried !== "busy" ? /* @__PURE__ */
|
|
6746
|
-
/* @__PURE__ */
|
|
6747
|
-
/* @__PURE__ */
|
|
6748
|
-
/* @__PURE__ */
|
|
6762
|
+
s.notes ? /* @__PURE__ */ jsx58(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
|
|
6763
|
+
tried && tried !== "busy" ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
6764
|
+
/* @__PURE__ */ jsxs53("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
6765
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
|
|
6766
|
+
/* @__PURE__ */ jsxs53(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
|
|
6749
6767
|
tried.ms,
|
|
6750
6768
|
"ms"
|
|
6751
6769
|
] })
|
|
6752
6770
|
] }),
|
|
6753
|
-
/* @__PURE__ */
|
|
6771
|
+
/* @__PURE__ */ jsx58(Json, { obj: tried.error ? { error: tried.error } : tried.data })
|
|
6754
6772
|
] }) : null
|
|
6755
6773
|
] })
|
|
6756
6774
|
] }) });
|
|
@@ -6769,58 +6787,58 @@ function ApiSpecBrowser({
|
|
|
6769
6787
|
className = "",
|
|
6770
6788
|
...rest
|
|
6771
6789
|
}) {
|
|
6772
|
-
const [q, setQ] =
|
|
6773
|
-
const [method, setMethod] =
|
|
6774
|
-
const [mod, setMod] =
|
|
6775
|
-
const [listOnly, setListOnly] =
|
|
6790
|
+
const [q, setQ] = React30.useState("");
|
|
6791
|
+
const [method, setMethod] = React30.useState(null);
|
|
6792
|
+
const [mod, setMod] = React30.useState(null);
|
|
6793
|
+
const [listOnly, setListOnly] = React30.useState(false);
|
|
6776
6794
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
6777
6795
|
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())));
|
|
6778
6796
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
6779
6797
|
const methods = [...new Set(spec.map((s) => s.method))];
|
|
6780
6798
|
const listCount = spec.filter((s) => s.isList).length;
|
|
6781
|
-
return /* @__PURE__ */
|
|
6782
|
-
/* @__PURE__ */
|
|
6783
|
-
kicker ? /* @__PURE__ */
|
|
6784
|
-
/* @__PURE__ */
|
|
6785
|
-
lede ? /* @__PURE__ */
|
|
6799
|
+
return /* @__PURE__ */ jsxs53("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
|
|
6800
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
6801
|
+
kicker ? /* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: kicker }) : null,
|
|
6802
|
+
/* @__PURE__ */ jsx58("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
6803
|
+
lede ? /* @__PURE__ */ jsx58("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
|
|
6786
6804
|
] }),
|
|
6787
|
-
modules && modules.length ? /* @__PURE__ */
|
|
6788
|
-
/* @__PURE__ */
|
|
6789
|
-
/* @__PURE__ */
|
|
6790
|
-
/* @__PURE__ */
|
|
6805
|
+
modules && modules.length ? /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
6806
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
|
|
6807
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
6808
|
+
/* @__PURE__ */ jsxs53(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
|
|
6791
6809
|
"All screens ",
|
|
6792
|
-
/* @__PURE__ */
|
|
6810
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-mono", children: spec.length })
|
|
6793
6811
|
] }),
|
|
6794
|
-
modules.map((m) => /* @__PURE__ */
|
|
6812
|
+
modules.map((m) => /* @__PURE__ */ jsxs53(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
|
|
6795
6813
|
m.label,
|
|
6796
6814
|
" ",
|
|
6797
|
-
/* @__PURE__ */
|
|
6815
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-mono", children: m.endpoints.length })
|
|
6798
6816
|
] }, m.id))
|
|
6799
6817
|
] }),
|
|
6800
|
-
activeModule ? /* @__PURE__ */
|
|
6818
|
+
activeModule ? /* @__PURE__ */ jsx58(
|
|
6801
6819
|
Flag,
|
|
6802
6820
|
{
|
|
6803
6821
|
tone: "info",
|
|
6804
6822
|
statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
|
|
6805
6823
|
cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
|
|
6806
|
-
actions: /* @__PURE__ */
|
|
6824
|
+
actions: /* @__PURE__ */ jsx58(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
|
|
6807
6825
|
}
|
|
6808
6826
|
) : null
|
|
6809
6827
|
] }) : null,
|
|
6810
|
-
sourceNote ? /* @__PURE__ */
|
|
6811
|
-
/* @__PURE__ */
|
|
6812
|
-
/* @__PURE__ */
|
|
6813
|
-
methods.map((m) => /* @__PURE__ */
|
|
6828
|
+
sourceNote ? /* @__PURE__ */ jsx58(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
|
|
6829
|
+
/* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
6830
|
+
/* @__PURE__ */ jsx58(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
|
|
6831
|
+
methods.map((m) => /* @__PURE__ */ jsxs53(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
|
|
6814
6832
|
m,
|
|
6815
6833
|
" ",
|
|
6816
|
-
/* @__PURE__ */
|
|
6834
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
|
|
6817
6835
|
] }, m)),
|
|
6818
|
-
listCount ? /* @__PURE__ */
|
|
6836
|
+
listCount ? /* @__PURE__ */ jsxs53(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
|
|
6819
6837
|
"Paged lists ",
|
|
6820
|
-
/* @__PURE__ */
|
|
6838
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-mono", children: listCount })
|
|
6821
6839
|
] }) : null,
|
|
6822
|
-
/* @__PURE__ */
|
|
6823
|
-
/* @__PURE__ */
|
|
6840
|
+
/* @__PURE__ */ jsx58("span", { style: { flex: 1 } }),
|
|
6841
|
+
/* @__PURE__ */ jsxs53("span", { className: "fd-body-sm fd-muted", children: [
|
|
6824
6842
|
hits.length,
|
|
6825
6843
|
" of ",
|
|
6826
6844
|
spec.length,
|
|
@@ -6828,31 +6846,31 @@ function ApiSpecBrowser({
|
|
|
6828
6846
|
listCount ? " \xB7 " + listCount + " paged" : ""
|
|
6829
6847
|
] })
|
|
6830
6848
|
] }),
|
|
6831
|
-
hits.length === 0 ? /* @__PURE__ */
|
|
6849
|
+
hits.length === 0 ? /* @__PURE__ */ jsx58(Card, { elevation: "flat", children: /* @__PURE__ */ jsx58("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
|
|
6832
6850
|
const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
|
|
6833
6851
|
if (!items.length) return null;
|
|
6834
|
-
return /* @__PURE__ */
|
|
6835
|
-
/* @__PURE__ */
|
|
6836
|
-
items.map((s) => /* @__PURE__ */
|
|
6852
|
+
return /* @__PURE__ */ jsxs53("div", { className: "fd-stack", style: { gap: 12 }, children: [
|
|
6853
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-label-lg", children: g }),
|
|
6854
|
+
items.map((s) => /* @__PURE__ */ jsx58(Endpoint, { s, onRequest }, s.id))
|
|
6837
6855
|
] }, g);
|
|
6838
6856
|
}),
|
|
6839
|
-
conventions && conventions.length ? /* @__PURE__ */
|
|
6840
|
-
/* @__PURE__ */
|
|
6841
|
-
/* @__PURE__ */
|
|
6857
|
+
conventions && conventions.length ? /* @__PURE__ */ jsx58(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ jsx58("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
|
|
6858
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
|
|
6859
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
|
|
6842
6860
|
] }, k)) }) }) : null,
|
|
6843
|
-
openQuestions && openQuestions.length ? /* @__PURE__ */
|
|
6844
|
-
/* @__PURE__ */
|
|
6845
|
-
/* @__PURE__ */
|
|
6846
|
-
/* @__PURE__ */
|
|
6847
|
-
/* @__PURE__ */
|
|
6861
|
+
openQuestions && openQuestions.length ? /* @__PURE__ */ jsx58(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ jsx58("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ jsxs53("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
|
|
6862
|
+
/* @__PURE__ */ jsx58(Badge, { tone: "danger", children: id }),
|
|
6863
|
+
/* @__PURE__ */ jsxs53("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
|
|
6864
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
|
|
6865
|
+
/* @__PURE__ */ jsx58("span", { className: "fd-body-sm fd-muted", children: why })
|
|
6848
6866
|
] })
|
|
6849
6867
|
] }, id)) }) }) : null
|
|
6850
6868
|
] });
|
|
6851
6869
|
}
|
|
6852
6870
|
|
|
6853
6871
|
// src/components/platform/ProfilePage.tsx
|
|
6854
|
-
import * as
|
|
6855
|
-
import { jsx as
|
|
6872
|
+
import * as React31 from "react";
|
|
6873
|
+
import { jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
6856
6874
|
var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
|
|
6857
6875
|
var NOTIFY = [
|
|
6858
6876
|
{ key: "planShared", label: "A plan is shared with me", detail: "Someone sends you a plan or a client link." },
|
|
@@ -6864,7 +6882,7 @@ var NOTIFY = [
|
|
|
6864
6882
|
function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
|
|
6865
6883
|
const session = SessionKit.useSession();
|
|
6866
6884
|
const user = userProp || session.user;
|
|
6867
|
-
const [draft, setDraft] =
|
|
6885
|
+
const [draft, setDraft] = React31.useState(() => ({
|
|
6868
6886
|
name: user.name || "",
|
|
6869
6887
|
title: user.title || "",
|
|
6870
6888
|
email: user.email || "",
|
|
@@ -6873,8 +6891,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6873
6891
|
bio: user.bio || "",
|
|
6874
6892
|
notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
|
|
6875
6893
|
}));
|
|
6876
|
-
const [saving, setSaving] =
|
|
6877
|
-
const [saved, setSaved] =
|
|
6894
|
+
const [saving, setSaving] = React31.useState(false);
|
|
6895
|
+
const [saved, setSaved] = React31.useState(false);
|
|
6878
6896
|
const set = (k, v) => {
|
|
6879
6897
|
setDraft((d) => Object.assign({}, d, { [k]: v }));
|
|
6880
6898
|
setSaved(false);
|
|
@@ -6896,43 +6914,43 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6896
6914
|
{ id: "s2", device: "iPhone 15 \xB7 Safari", where: "Denver, CO", when: "2 hours ago" },
|
|
6897
6915
|
{ id: "s3", device: "Windows \xB7 Edge", where: "Chicago, IL", when: "Aug 12" }
|
|
6898
6916
|
];
|
|
6899
|
-
return /* @__PURE__ */
|
|
6900
|
-
/* @__PURE__ */
|
|
6901
|
-
/* @__PURE__ */
|
|
6902
|
-
/* @__PURE__ */
|
|
6903
|
-
/* @__PURE__ */
|
|
6917
|
+
return /* @__PURE__ */ jsxs54("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, ...rest, children: [
|
|
6918
|
+
/* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
6919
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-overline fd-muted", children: "Account" }),
|
|
6920
|
+
/* @__PURE__ */ jsx59("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
|
|
6921
|
+
/* @__PURE__ */ jsx59("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." })
|
|
6904
6922
|
] }),
|
|
6905
|
-
/* @__PURE__ */
|
|
6906
|
-
/* @__PURE__ */
|
|
6907
|
-
/* @__PURE__ */
|
|
6908
|
-
/* @__PURE__ */
|
|
6909
|
-
/* @__PURE__ */
|
|
6923
|
+
/* @__PURE__ */ jsx59(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
|
|
6924
|
+
/* @__PURE__ */ jsx59(Avatar, { name: draft.name || user.name, size: "lg" }),
|
|
6925
|
+
/* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
|
|
6926
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-h3", style: { margin: 0 }, children: draft.name || user.name }),
|
|
6927
|
+
/* @__PURE__ */ jsxs54("span", { className: "fd-body-sm fd-muted", children: [
|
|
6910
6928
|
draft.title || "No title set",
|
|
6911
6929
|
" \xB7 ",
|
|
6912
6930
|
user.team || "No team"
|
|
6913
6931
|
] }),
|
|
6914
|
-
/* @__PURE__ */
|
|
6915
|
-
session.roles.map((r) => /* @__PURE__ */
|
|
6916
|
-
user.sso ? /* @__PURE__ */
|
|
6932
|
+
/* @__PURE__ */ jsxs54("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
|
|
6933
|
+
session.roles.map((r) => /* @__PURE__ */ jsx59(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
|
|
6934
|
+
user.sso ? /* @__PURE__ */ jsx59(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
|
|
6917
6935
|
] })
|
|
6918
6936
|
] }),
|
|
6919
|
-
/* @__PURE__ */
|
|
6937
|
+
/* @__PURE__ */ jsx59(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
|
|
6920
6938
|
] }) }),
|
|
6921
|
-
/* @__PURE__ */
|
|
6939
|
+
/* @__PURE__ */ jsx59(
|
|
6922
6940
|
Card,
|
|
6923
6941
|
{
|
|
6924
|
-
title: /* @__PURE__ */
|
|
6925
|
-
/* @__PURE__ */
|
|
6926
|
-
/* @__PURE__ */
|
|
6942
|
+
title: /* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
6943
|
+
/* @__PURE__ */ jsx59("span", { children: "Identity" }),
|
|
6944
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Name and title appear on plans you share" })
|
|
6927
6945
|
] }),
|
|
6928
6946
|
elevation: "flat",
|
|
6929
|
-
children: /* @__PURE__ */
|
|
6930
|
-
/* @__PURE__ */
|
|
6931
|
-
/* @__PURE__ */
|
|
6932
|
-
/* @__PURE__ */
|
|
6947
|
+
children: /* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 14 }, children: [
|
|
6948
|
+
/* @__PURE__ */ jsxs54("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
|
|
6949
|
+
/* @__PURE__ */ jsx59(Input, { label: "Full name", value: draft.name, onChange: (e) => set("name", e.target.value) }),
|
|
6950
|
+
/* @__PURE__ */ jsx59(Input, { label: "Job title", value: draft.title, onChange: (e) => set("title", e.target.value), placeholder: "e.g. Senior media planner" })
|
|
6933
6951
|
] }),
|
|
6934
|
-
/* @__PURE__ */
|
|
6935
|
-
/* @__PURE__ */
|
|
6952
|
+
/* @__PURE__ */ jsxs54("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
|
|
6953
|
+
/* @__PURE__ */ jsx59(
|
|
6936
6954
|
Input,
|
|
6937
6955
|
{
|
|
6938
6956
|
label: "Work email",
|
|
@@ -6942,9 +6960,9 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6942
6960
|
help: user.sso ? "Managed by your identity provider \u2014 change it there." : "Contact an administrator to change this."
|
|
6943
6961
|
}
|
|
6944
6962
|
),
|
|
6945
|
-
/* @__PURE__ */
|
|
6963
|
+
/* @__PURE__ */ jsx59(Input, { label: "Phone", value: draft.phone, onChange: (e) => set("phone", e.target.value), placeholder: "Optional" })
|
|
6946
6964
|
] }),
|
|
6947
|
-
/* @__PURE__ */
|
|
6965
|
+
/* @__PURE__ */ jsx59(
|
|
6948
6966
|
Textarea,
|
|
6949
6967
|
{
|
|
6950
6968
|
label: "Short bio",
|
|
@@ -6958,8 +6976,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6958
6976
|
] })
|
|
6959
6977
|
}
|
|
6960
6978
|
),
|
|
6961
|
-
/* @__PURE__ */
|
|
6962
|
-
/* @__PURE__ */
|
|
6979
|
+
/* @__PURE__ */ jsx59(Card, { title: "Working preferences", elevation: "flat", children: /* @__PURE__ */ jsxs54("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: [
|
|
6980
|
+
/* @__PURE__ */ jsx59(
|
|
6963
6981
|
Select,
|
|
6964
6982
|
{
|
|
6965
6983
|
label: "Time zone",
|
|
@@ -6969,28 +6987,28 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6969
6987
|
help: "Flight dates and schedules render in this zone."
|
|
6970
6988
|
}
|
|
6971
6989
|
),
|
|
6972
|
-
/* @__PURE__ */
|
|
6990
|
+
/* @__PURE__ */ jsx59(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
|
|
6973
6991
|
] }) }),
|
|
6974
|
-
/* @__PURE__ */
|
|
6992
|
+
/* @__PURE__ */ jsx59(
|
|
6975
6993
|
Card,
|
|
6976
6994
|
{
|
|
6977
|
-
title: /* @__PURE__ */
|
|
6978
|
-
/* @__PURE__ */
|
|
6979
|
-
/* @__PURE__ */
|
|
6995
|
+
title: /* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
6996
|
+
/* @__PURE__ */ jsx59("span", { children: "Notifications" }),
|
|
6997
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
|
|
6980
6998
|
] }),
|
|
6981
6999
|
elevation: "flat",
|
|
6982
|
-
children: /* @__PURE__ */
|
|
7000
|
+
children: /* @__PURE__ */ jsx59("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ jsx59(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
|
|
6983
7001
|
}
|
|
6984
7002
|
),
|
|
6985
|
-
/* @__PURE__ */
|
|
7003
|
+
/* @__PURE__ */ jsxs54(
|
|
6986
7004
|
Card,
|
|
6987
7005
|
{
|
|
6988
|
-
title: /* @__PURE__ */
|
|
6989
|
-
/* @__PURE__ */
|
|
6990
|
-
/* @__PURE__ */
|
|
7006
|
+
title: /* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
7007
|
+
/* @__PURE__ */ jsx59("span", { children: "Access" }),
|
|
7008
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
|
|
6991
7009
|
] }),
|
|
6992
7010
|
elevation: "flat",
|
|
6993
|
-
action: /* @__PURE__ */
|
|
7011
|
+
action: /* @__PURE__ */ jsx59(
|
|
6994
7012
|
Button,
|
|
6995
7013
|
{
|
|
6996
7014
|
size: "sm",
|
|
@@ -7001,39 +7019,39 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
7001
7019
|
}
|
|
7002
7020
|
),
|
|
7003
7021
|
children: [
|
|
7004
|
-
/* @__PURE__ */
|
|
7005
|
-
/* @__PURE__ */
|
|
7006
|
-
/* @__PURE__ */
|
|
7022
|
+
/* @__PURE__ */ jsxs54("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
7023
|
+
/* @__PURE__ */ jsx59(CardRow, { label: "Roles", children: session.roles.map((r) => r.name).join(", ") || "None" }),
|
|
7024
|
+
/* @__PURE__ */ jsxs54(CardRow, { label: "Permissions", children: [
|
|
7007
7025
|
session.permissions.length,
|
|
7008
7026
|
" granted"
|
|
7009
7027
|
] }),
|
|
7010
|
-
/* @__PURE__ */
|
|
7028
|
+
/* @__PURE__ */ jsx59(CardRow, { label: "Member since", children: user.joined || "\u2014" })
|
|
7011
7029
|
] }),
|
|
7012
|
-
/* @__PURE__ */
|
|
7030
|
+
/* @__PURE__ */ jsx59("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." })
|
|
7013
7031
|
]
|
|
7014
7032
|
}
|
|
7015
7033
|
),
|
|
7016
|
-
showSessions ? /* @__PURE__ */
|
|
7034
|
+
showSessions ? /* @__PURE__ */ jsx59(
|
|
7017
7035
|
Card,
|
|
7018
7036
|
{
|
|
7019
7037
|
title: "Signed-in devices",
|
|
7020
7038
|
elevation: "flat",
|
|
7021
|
-
action: /* @__PURE__ */
|
|
7022
|
-
children: /* @__PURE__ */
|
|
7023
|
-
/* @__PURE__ */
|
|
7024
|
-
/* @__PURE__ */
|
|
7025
|
-
/* @__PURE__ */
|
|
7026
|
-
/* @__PURE__ */
|
|
7039
|
+
action: /* @__PURE__ */ jsx59(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
|
|
7040
|
+
children: /* @__PURE__ */ jsx59("div", { className: "fd-stack", style: { gap: 0 }, children: liveSessions.map((s) => /* @__PURE__ */ jsxs54("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
7041
|
+
/* @__PURE__ */ jsx59("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
7042
|
+
/* @__PURE__ */ jsxs54("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
|
|
7043
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
|
|
7044
|
+
/* @__PURE__ */ jsxs54("span", { className: "fd-body-sm fd-muted", children: [
|
|
7027
7045
|
s.where,
|
|
7028
7046
|
" \xB7 ",
|
|
7029
7047
|
s.when
|
|
7030
7048
|
] })
|
|
7031
7049
|
] }),
|
|
7032
|
-
s.current ? /* @__PURE__ */
|
|
7050
|
+
s.current ? /* @__PURE__ */ jsx59(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ jsx59(Button, { size: "sm", variant: "ghost", children: "Revoke" })
|
|
7033
7051
|
] }, s.id)) })
|
|
7034
7052
|
}
|
|
7035
7053
|
) : null,
|
|
7036
|
-
/* @__PURE__ */
|
|
7054
|
+
/* @__PURE__ */ jsxs54("div", { className: "fd-row", style: {
|
|
7037
7055
|
gap: 10,
|
|
7038
7056
|
flexWrap: "wrap",
|
|
7039
7057
|
position: "sticky",
|
|
@@ -7044,8 +7062,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
7044
7062
|
border: "1px solid var(--border)",
|
|
7045
7063
|
boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
|
|
7046
7064
|
}, children: [
|
|
7047
|
-
/* @__PURE__ */
|
|
7048
|
-
/* @__PURE__ */
|
|
7065
|
+
/* @__PURE__ */ jsx59("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
|
|
7066
|
+
/* @__PURE__ */ jsx59(
|
|
7049
7067
|
Button,
|
|
7050
7068
|
{
|
|
7051
7069
|
size: "sm",
|
|
@@ -7058,16 +7076,16 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
7058
7076
|
children: "Discard"
|
|
7059
7077
|
}
|
|
7060
7078
|
),
|
|
7061
|
-
/* @__PURE__ */
|
|
7079
|
+
/* @__PURE__ */ jsx59(Button, { size: "sm", icon: "check", disabled: !dirty, loading: saving, onClick: save, children: "Save changes" })
|
|
7062
7080
|
] })
|
|
7063
7081
|
] });
|
|
7064
7082
|
}
|
|
7065
7083
|
|
|
7066
7084
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7067
|
-
import * as
|
|
7085
|
+
import * as React33 from "react";
|
|
7068
7086
|
|
|
7069
7087
|
// src/kits/runtime.ts
|
|
7070
|
-
import * as
|
|
7088
|
+
import * as React32 from "react";
|
|
7071
7089
|
var WIRED_ENDPOINTS = [
|
|
7072
7090
|
// Nothing yet. Every id below would come from a real service:
|
|
7073
7091
|
// "plan.get", "placements.list", …
|
|
@@ -7238,8 +7256,8 @@ var RuntimeKit = {
|
|
|
7238
7256
|
};
|
|
7239
7257
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
7240
7258
|
function useRuntimeMode() {
|
|
7241
|
-
const [m, setM] =
|
|
7242
|
-
|
|
7259
|
+
const [m, setM] = React32.useState(RuntimeKit.getMode());
|
|
7260
|
+
React32.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
7243
7261
|
return m;
|
|
7244
7262
|
}
|
|
7245
7263
|
function useFeatureStatus(key) {
|
|
@@ -7258,7 +7276,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
7258
7276
|
var UseFeatureStatus = useFeatureStatus;
|
|
7259
7277
|
|
|
7260
7278
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7261
|
-
import { jsx as
|
|
7279
|
+
import { jsx as jsx60, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
7262
7280
|
var STATUS = {
|
|
7263
7281
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
7264
7282
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -7273,45 +7291,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
7273
7291
|
const s = STATUS[item.status] || STATUS.planned;
|
|
7274
7292
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
7275
7293
|
const blocking = deps.filter((d) => !d.implemented);
|
|
7276
|
-
return /* @__PURE__ */
|
|
7277
|
-
/* @__PURE__ */
|
|
7278
|
-
/* @__PURE__ */
|
|
7279
|
-
/* @__PURE__ */
|
|
7280
|
-
/* @__PURE__ */
|
|
7294
|
+
return /* @__PURE__ */ jsx60(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs55("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
7295
|
+
/* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
7296
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
|
|
7297
|
+
/* @__PURE__ */ jsx60(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
|
|
7298
|
+
/* @__PURE__ */ jsx60(Badge, { tone: s.tone, icon: s.icon, children: s.label })
|
|
7281
7299
|
] }),
|
|
7282
|
-
/* @__PURE__ */
|
|
7283
|
-
item.backend ? /* @__PURE__ */
|
|
7284
|
-
/* @__PURE__ */
|
|
7285
|
-
/* @__PURE__ */
|
|
7300
|
+
/* @__PURE__ */ jsx60("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
|
|
7301
|
+
item.backend ? /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
|
|
7302
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
|
|
7303
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
|
|
7286
7304
|
] }) : null,
|
|
7287
|
-
/* @__PURE__ */
|
|
7288
|
-
item.effort ? /* @__PURE__ */
|
|
7289
|
-
/* @__PURE__ */
|
|
7305
|
+
/* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
7306
|
+
item.effort ? /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm fd-muted", children: [
|
|
7307
|
+
/* @__PURE__ */ jsx60("i", { className: "ph ph-hourglass-medium" }),
|
|
7290
7308
|
" ",
|
|
7291
7309
|
item.effort
|
|
7292
7310
|
] }) : null,
|
|
7293
|
-
/* @__PURE__ */
|
|
7294
|
-
/* @__PURE__ */
|
|
7311
|
+
/* @__PURE__ */ jsxs55("span", { className: "fd-body-sm fd-muted", children: [
|
|
7312
|
+
/* @__PURE__ */ jsx60("i", { className: "ph ph-user" }),
|
|
7295
7313
|
" ",
|
|
7296
7314
|
item.owner
|
|
7297
7315
|
] }),
|
|
7298
|
-
item.screen ? /* @__PURE__ */
|
|
7299
|
-
/* @__PURE__ */
|
|
7300
|
-
/* @__PURE__ */
|
|
7316
|
+
item.screen ? /* @__PURE__ */ jsx60(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
7317
|
+
/* @__PURE__ */ jsx60("span", { style: { flex: 1 } }),
|
|
7318
|
+
/* @__PURE__ */ jsx60(
|
|
7301
7319
|
"button",
|
|
7302
7320
|
{
|
|
7303
7321
|
type: "button",
|
|
7304
7322
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
7305
7323
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
7306
|
-
children: /* @__PURE__ */
|
|
7324
|
+
children: /* @__PURE__ */ jsx60("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
7307
7325
|
}
|
|
7308
7326
|
)
|
|
7309
7327
|
] }),
|
|
7310
|
-
deps.length ? /* @__PURE__ */
|
|
7311
|
-
/* @__PURE__ */
|
|
7312
|
-
deps.map((d) => /* @__PURE__ */
|
|
7328
|
+
deps.length ? /* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
|
|
7329
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
|
|
7330
|
+
deps.map((d) => /* @__PURE__ */ jsx60(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
|
|
7313
7331
|
] }) : null,
|
|
7314
|
-
blocking.length && !item.implemented ? /* @__PURE__ */
|
|
7332
|
+
blocking.length && !item.implemented ? /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
7315
7333
|
"Blocked until ",
|
|
7316
7334
|
blocking.map((d) => d.label).join(" and "),
|
|
7317
7335
|
" ",
|
|
@@ -7322,12 +7340,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
7322
7340
|
}
|
|
7323
7341
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
7324
7342
|
const session = SessionKit.useSession();
|
|
7325
|
-
const [project, setProject] =
|
|
7326
|
-
const [q, setQ] =
|
|
7327
|
-
const scrollRef =
|
|
7328
|
-
const nowRef =
|
|
7329
|
-
const rm =
|
|
7330
|
-
const byKey =
|
|
7343
|
+
const [project, setProject] = React33.useState("");
|
|
7344
|
+
const [q, setQ] = React33.useState("");
|
|
7345
|
+
const scrollRef = React33.useRef(null);
|
|
7346
|
+
const nowRef = React33.useRef(null);
|
|
7347
|
+
const rm = React33.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
7348
|
+
const byKey = React33.useMemo(() => {
|
|
7331
7349
|
const m = {};
|
|
7332
7350
|
rm.items.forEach((i) => {
|
|
7333
7351
|
m[i.key] = i;
|
|
@@ -7336,7 +7354,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7336
7354
|
}, [rm]);
|
|
7337
7355
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
7338
7356
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
7339
|
-
|
|
7357
|
+
React33.useEffect(() => {
|
|
7340
7358
|
let raf1 = 0, raf2 = 0;
|
|
7341
7359
|
const place = () => {
|
|
7342
7360
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -7364,23 +7382,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7364
7382
|
}, 0);
|
|
7365
7383
|
const nextPhase = items.find((i) => !i.implemented);
|
|
7366
7384
|
let lastPhase = null;
|
|
7367
|
-
return /* @__PURE__ */
|
|
7368
|
-
/* @__PURE__ */
|
|
7369
|
-
/* @__PURE__ */
|
|
7370
|
-
/* @__PURE__ */
|
|
7371
|
-
/* @__PURE__ */
|
|
7385
|
+
return /* @__PURE__ */ jsxs55("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
|
|
7386
|
+
/* @__PURE__ */ jsxs55("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
7387
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-overline fd-muted", children: "Architecture" }),
|
|
7388
|
+
/* @__PURE__ */ jsx60("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
7389
|
+
/* @__PURE__ */ jsx60("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." })
|
|
7372
7390
|
] }),
|
|
7373
|
-
/* @__PURE__ */
|
|
7374
|
-
/* @__PURE__ */
|
|
7375
|
-
/* @__PURE__ */
|
|
7376
|
-
/* @__PURE__ */
|
|
7377
|
-
/* @__PURE__ */
|
|
7391
|
+
/* @__PURE__ */ jsxs55("div", { className: "fd-grid-stats is-thin", children: [
|
|
7392
|
+
/* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
|
|
7393
|
+
/* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
|
|
7394
|
+
/* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
|
|
7395
|
+
/* @__PURE__ */ jsx60(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
|
|
7378
7396
|
] }),
|
|
7379
|
-
/* @__PURE__ */
|
|
7380
|
-
/* @__PURE__ */
|
|
7381
|
-
/* @__PURE__ */
|
|
7382
|
-
/* @__PURE__ */
|
|
7383
|
-
/* @__PURE__ */
|
|
7397
|
+
/* @__PURE__ */ jsxs55("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
7398
|
+
/* @__PURE__ */ jsx60(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 } }),
|
|
7399
|
+
/* @__PURE__ */ jsx60(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
|
|
7400
|
+
/* @__PURE__ */ jsx60("span", { style: { flex: 1 } }),
|
|
7401
|
+
/* @__PURE__ */ jsx60(
|
|
7384
7402
|
Button,
|
|
7385
7403
|
{
|
|
7386
7404
|
size: "sm",
|
|
@@ -7394,7 +7412,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7394
7412
|
}
|
|
7395
7413
|
)
|
|
7396
7414
|
] }),
|
|
7397
|
-
/* @__PURE__ */
|
|
7415
|
+
/* @__PURE__ */ jsx60(
|
|
7398
7416
|
Flag,
|
|
7399
7417
|
{
|
|
7400
7418
|
tone: "info",
|
|
@@ -7403,60 +7421,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7403
7421
|
actions: null
|
|
7404
7422
|
}
|
|
7405
7423
|
),
|
|
7406
|
-
/* @__PURE__ */
|
|
7407
|
-
/* @__PURE__ */
|
|
7424
|
+
/* @__PURE__ */ jsx60("div", { className: "fd-rm", children: /* @__PURE__ */ jsx60("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs55("div", { className: "fd-rm-track", children: [
|
|
7425
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx60("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
|
|
7408
7426
|
items.map((item, n) => {
|
|
7409
7427
|
const showPhase = item.phase !== lastPhase;
|
|
7410
7428
|
lastPhase = item.phase;
|
|
7411
7429
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
7412
7430
|
const isBoundary = n === firstPending;
|
|
7413
|
-
return /* @__PURE__ */
|
|
7414
|
-
showPhase ? /* @__PURE__ */
|
|
7415
|
-
/* @__PURE__ */
|
|
7416
|
-
/* @__PURE__ */
|
|
7417
|
-
item.phase === 0 ? null : /* @__PURE__ */
|
|
7431
|
+
return /* @__PURE__ */ jsxs55(React33.Fragment, { children: [
|
|
7432
|
+
showPhase ? /* @__PURE__ */ jsxs55("div", { className: "fd-rm-era", children: [
|
|
7433
|
+
/* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
7434
|
+
/* @__PURE__ */ jsx60("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
7435
|
+
item.phase === 0 ? null : /* @__PURE__ */ jsxs55("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
7418
7436
|
fmtDate(item.phaseStart),
|
|
7419
7437
|
" \u2013 ",
|
|
7420
7438
|
fmtDate(item.date)
|
|
7421
7439
|
] }),
|
|
7422
|
-
/* @__PURE__ */
|
|
7440
|
+
/* @__PURE__ */ jsxs55("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
7423
7441
|
"\xB7 ",
|
|
7424
7442
|
inPhase,
|
|
7425
7443
|
" feature",
|
|
7426
7444
|
inPhase === 1 ? "" : "s"
|
|
7427
7445
|
] })
|
|
7428
7446
|
] }),
|
|
7429
|
-
item.phaseWhy ? /* @__PURE__ */
|
|
7447
|
+
item.phaseWhy ? /* @__PURE__ */ jsx60("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
7430
7448
|
] }) : null,
|
|
7431
|
-
isBoundary ? /* @__PURE__ */
|
|
7432
|
-
/* @__PURE__ */
|
|
7449
|
+
isBoundary ? /* @__PURE__ */ jsx60("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs55("span", { className: "fd-rm-now-pill", children: [
|
|
7450
|
+
/* @__PURE__ */ jsx60("i", { className: "ph ph-map-pin" }),
|
|
7433
7451
|
" You are here \u2014 everything above is wired"
|
|
7434
7452
|
] }) }) : null,
|
|
7435
|
-
/* @__PURE__ */
|
|
7436
|
-
/* @__PURE__ */
|
|
7437
|
-
/* @__PURE__ */
|
|
7453
|
+
/* @__PURE__ */ jsxs55("div", { className: "fd-rm-row", children: [
|
|
7454
|
+
/* @__PURE__ */ jsx60("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
|
|
7455
|
+
/* @__PURE__ */ jsxs55("div", { className: "fd-rm-date", children: [
|
|
7438
7456
|
fmtDate(item.date),
|
|
7439
|
-
/* @__PURE__ */
|
|
7440
|
-
/* @__PURE__ */
|
|
7457
|
+
/* @__PURE__ */ jsx60("br", {}),
|
|
7458
|
+
/* @__PURE__ */ jsx60("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
7441
7459
|
] }),
|
|
7442
|
-
/* @__PURE__ */
|
|
7460
|
+
/* @__PURE__ */ jsx60(RoadmapCard, { item, byKey, onOpenFlag })
|
|
7443
7461
|
] })
|
|
7444
7462
|
] }, item.key);
|
|
7445
7463
|
}),
|
|
7446
|
-
!items.length ? /* @__PURE__ */
|
|
7464
|
+
!items.length ? /* @__PURE__ */ jsx60("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
7447
7465
|
] }) }) }),
|
|
7448
|
-
/* @__PURE__ */
|
|
7466
|
+
/* @__PURE__ */ jsxs55("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
7449
7467
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
7450
|
-
/* @__PURE__ */
|
|
7468
|
+
/* @__PURE__ */ jsx60("code", { className: "fd-mono", children: "implemented" }),
|
|
7451
7469
|
" field, so this page cannot drift from what the apps actually do."
|
|
7452
7470
|
] })
|
|
7453
7471
|
] });
|
|
7454
7472
|
}
|
|
7455
7473
|
|
|
7456
7474
|
// src/components/platform/ComingSoon.tsx
|
|
7457
|
-
import * as
|
|
7475
|
+
import * as React34 from "react";
|
|
7458
7476
|
import { createPortal as createPortal8 } from "react-dom";
|
|
7459
|
-
import { Fragment as Fragment14, jsx as
|
|
7477
|
+
import { Fragment as Fragment14, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
7460
7478
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
7461
7479
|
function readBypassed() {
|
|
7462
7480
|
try {
|
|
@@ -7472,8 +7490,8 @@ function writeBypassed(list) {
|
|
|
7472
7490
|
}
|
|
7473
7491
|
}
|
|
7474
7492
|
function useBypass(key) {
|
|
7475
|
-
const [on, setOn] =
|
|
7476
|
-
|
|
7493
|
+
const [on, setOn] = React34.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
7494
|
+
React34.useEffect(() => {
|
|
7477
7495
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
7478
7496
|
}, [key]);
|
|
7479
7497
|
const set = (next) => {
|
|
@@ -7486,43 +7504,43 @@ function useBypass(key) {
|
|
|
7486
7504
|
return [on, set];
|
|
7487
7505
|
}
|
|
7488
7506
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
7489
|
-
return /* @__PURE__ */
|
|
7490
|
-
/* @__PURE__ */
|
|
7491
|
-
/* @__PURE__ */
|
|
7507
|
+
return /* @__PURE__ */ jsxs56(Fragment14, { children: [
|
|
7508
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-soon-badge", children: [
|
|
7509
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
7492
7510
|
label
|
|
7493
7511
|
] }),
|
|
7494
|
-
detail ? /* @__PURE__ */
|
|
7495
|
-
backend ? /* @__PURE__ */
|
|
7496
|
-
/* @__PURE__ */
|
|
7512
|
+
detail ? /* @__PURE__ */ jsx61("span", { className: "fd-soon-detail", children: detail }) : null,
|
|
7513
|
+
backend ? /* @__PURE__ */ jsxs56("span", { className: "fd-soon-backend", children: [
|
|
7514
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-overline", children: "Needs" }),
|
|
7497
7515
|
" ",
|
|
7498
7516
|
backend
|
|
7499
7517
|
] }) : null,
|
|
7500
|
-
eta || effort || onRoadmap ? /* @__PURE__ */
|
|
7501
|
-
eta ? /* @__PURE__ */
|
|
7502
|
-
/* @__PURE__ */
|
|
7518
|
+
eta || effort || onRoadmap ? /* @__PURE__ */ jsxs56("span", { className: "fd-soon-meta", children: [
|
|
7519
|
+
eta ? /* @__PURE__ */ jsxs56("span", { children: [
|
|
7520
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
|
|
7503
7521
|
" ",
|
|
7504
7522
|
eta
|
|
7505
7523
|
] }) : null,
|
|
7506
|
-
effort ? /* @__PURE__ */
|
|
7507
|
-
/* @__PURE__ */
|
|
7524
|
+
effort ? /* @__PURE__ */ jsxs56("span", { children: [
|
|
7525
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
7508
7526
|
" ",
|
|
7509
7527
|
effort
|
|
7510
7528
|
] }) : null,
|
|
7511
|
-
onRoadmap ? /* @__PURE__ */
|
|
7529
|
+
onRoadmap ? /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
7512
7530
|
"See the roadmap ",
|
|
7513
|
-
/* @__PURE__ */
|
|
7531
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
7514
7532
|
] }) : null
|
|
7515
7533
|
] }) : null,
|
|
7516
|
-
allowed ? /* @__PURE__ */
|
|
7517
|
-
/* @__PURE__ */
|
|
7534
|
+
allowed ? /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
|
|
7535
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-eye", "aria-hidden": "true" }),
|
|
7518
7536
|
" View and use it anyway"
|
|
7519
7537
|
] }) : null
|
|
7520
7538
|
] });
|
|
7521
7539
|
}
|
|
7522
7540
|
function useHoverCard(open) {
|
|
7523
|
-
const anchor =
|
|
7524
|
-
const [pos, setPos] =
|
|
7525
|
-
|
|
7541
|
+
const anchor = React34.useRef(null);
|
|
7542
|
+
const [pos, setPos] = React34.useState(null);
|
|
7543
|
+
React34.useLayoutEffect(() => {
|
|
7526
7544
|
if (!open || !anchor.current) {
|
|
7527
7545
|
setPos(null);
|
|
7528
7546
|
return;
|
|
@@ -7574,9 +7592,9 @@ function ComingSoon({
|
|
|
7574
7592
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
7575
7593
|
if (inline) {
|
|
7576
7594
|
if (allowed && bypassed) {
|
|
7577
|
-
return /* @__PURE__ */
|
|
7595
|
+
return /* @__PURE__ */ jsxs56("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
7578
7596
|
children,
|
|
7579
|
-
/* @__PURE__ */
|
|
7597
|
+
/* @__PURE__ */ jsx61(
|
|
7580
7598
|
"button",
|
|
7581
7599
|
{
|
|
7582
7600
|
type: "button",
|
|
@@ -7584,12 +7602,12 @@ function ComingSoon({
|
|
|
7584
7602
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
7585
7603
|
onClick: () => setBypassed(false),
|
|
7586
7604
|
"aria-label": "Re-blur this unwired feature",
|
|
7587
|
-
children: /* @__PURE__ */
|
|
7605
|
+
children: /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7588
7606
|
}
|
|
7589
7607
|
)
|
|
7590
7608
|
] });
|
|
7591
7609
|
}
|
|
7592
|
-
return /* @__PURE__ */
|
|
7610
|
+
return /* @__PURE__ */ jsx61(
|
|
7593
7611
|
InlineSoon,
|
|
7594
7612
|
{
|
|
7595
7613
|
label,
|
|
@@ -7609,20 +7627,20 @@ function ComingSoon({
|
|
|
7609
7627
|
);
|
|
7610
7628
|
}
|
|
7611
7629
|
if (allowed && bypassed) {
|
|
7612
|
-
return /* @__PURE__ */
|
|
7613
|
-
/* @__PURE__ */
|
|
7614
|
-
/* @__PURE__ */
|
|
7615
|
-
/* @__PURE__ */
|
|
7630
|
+
return /* @__PURE__ */ jsxs56("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
|
|
7631
|
+
/* @__PURE__ */ jsxs56("div", { className: "fd-soon-bar", role: "status", children: [
|
|
7632
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-soon-badge", children: [
|
|
7633
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
7616
7634
|
"Unwired feature \u2014 you are using it anyway"
|
|
7617
7635
|
] }),
|
|
7618
|
-
/* @__PURE__ */
|
|
7619
|
-
/* @__PURE__ */
|
|
7620
|
-
onRoadmap ? /* @__PURE__ */
|
|
7636
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
|
|
7637
|
+
/* @__PURE__ */ jsxs56("span", { className: "fd-soon-bar-actions", children: [
|
|
7638
|
+
onRoadmap ? /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
7621
7639
|
"Roadmap ",
|
|
7622
|
-
/* @__PURE__ */
|
|
7640
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
7623
7641
|
] }) : null,
|
|
7624
|
-
/* @__PURE__ */
|
|
7625
|
-
/* @__PURE__ */
|
|
7642
|
+
/* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
|
|
7643
|
+
/* @__PURE__ */ jsx61("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
|
|
7626
7644
|
" Re-blur"
|
|
7627
7645
|
] })
|
|
7628
7646
|
] })
|
|
@@ -7630,10 +7648,10 @@ function ComingSoon({
|
|
|
7630
7648
|
children
|
|
7631
7649
|
] });
|
|
7632
7650
|
}
|
|
7633
|
-
return /* @__PURE__ */
|
|
7634
|
-
/* @__PURE__ */
|
|
7635
|
-
/* @__PURE__ */
|
|
7636
|
-
/* @__PURE__ */
|
|
7651
|
+
return /* @__PURE__ */ jsxs56("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
|
|
7652
|
+
/* @__PURE__ */ jsx61("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
7653
|
+
/* @__PURE__ */ jsx61("div", { className: "fd-soon-veil" }),
|
|
7654
|
+
/* @__PURE__ */ jsx61("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx61(
|
|
7637
7655
|
SoonCard,
|
|
7638
7656
|
{
|
|
7639
7657
|
label,
|
|
@@ -7649,9 +7667,9 @@ function ComingSoon({
|
|
|
7649
7667
|
] });
|
|
7650
7668
|
}
|
|
7651
7669
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
7652
|
-
const [open, setOpen] =
|
|
7670
|
+
const [open, setOpen] = React34.useState(false);
|
|
7653
7671
|
const [anchor, pos] = useHoverCard(open);
|
|
7654
|
-
const close =
|
|
7672
|
+
const close = React34.useRef(null);
|
|
7655
7673
|
const show = () => {
|
|
7656
7674
|
if (close.current) {
|
|
7657
7675
|
clearTimeout(close.current);
|
|
@@ -7667,10 +7685,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7667
7685
|
setOpen(false);
|
|
7668
7686
|
}, 140);
|
|
7669
7687
|
};
|
|
7670
|
-
|
|
7688
|
+
React34.useEffect(() => () => {
|
|
7671
7689
|
if (close.current) clearTimeout(close.current);
|
|
7672
7690
|
}, []);
|
|
7673
|
-
return /* @__PURE__ */
|
|
7691
|
+
return /* @__PURE__ */ jsxs56(
|
|
7674
7692
|
"span",
|
|
7675
7693
|
{
|
|
7676
7694
|
ref: anchor,
|
|
@@ -7681,8 +7699,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7681
7699
|
onBlur: hide,
|
|
7682
7700
|
...rest,
|
|
7683
7701
|
children: [
|
|
7684
|
-
/* @__PURE__ */
|
|
7685
|
-
/* @__PURE__ */
|
|
7702
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
7703
|
+
/* @__PURE__ */ jsx61(
|
|
7686
7704
|
"button",
|
|
7687
7705
|
{
|
|
7688
7706
|
type: "button",
|
|
@@ -7693,11 +7711,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7693
7711
|
onFocus: show,
|
|
7694
7712
|
onBlur: hide,
|
|
7695
7713
|
onClick: () => open ? setOpen(false) : show(),
|
|
7696
|
-
children: /* @__PURE__ */
|
|
7714
|
+
children: /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7697
7715
|
}
|
|
7698
7716
|
),
|
|
7699
7717
|
open && pos ? createPortal8(
|
|
7700
|
-
/* @__PURE__ */
|
|
7718
|
+
/* @__PURE__ */ jsx61(
|
|
7701
7719
|
"div",
|
|
7702
7720
|
{
|
|
7703
7721
|
className: "fd-soon-note fd-soon-hovercard",
|
|
@@ -7705,7 +7723,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7705
7723
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width },
|
|
7706
7724
|
onMouseEnter: show,
|
|
7707
7725
|
onMouseLeave: hide,
|
|
7708
|
-
children: /* @__PURE__ */
|
|
7726
|
+
children: /* @__PURE__ */ jsx61(
|
|
7709
7727
|
SoonCard,
|
|
7710
7728
|
{
|
|
7711
7729
|
label,
|
|
@@ -7735,10 +7753,10 @@ function formatEta(iso2) {
|
|
|
7735
7753
|
var FormatEta = formatEta;
|
|
7736
7754
|
|
|
7737
7755
|
// src/components/platform/Gate.tsx
|
|
7738
|
-
import { jsx as
|
|
7756
|
+
import { jsx as jsx62, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
7739
7757
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
7740
7758
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
7741
|
-
return /* @__PURE__ */
|
|
7759
|
+
return /* @__PURE__ */ jsxs57(
|
|
7742
7760
|
"div",
|
|
7743
7761
|
{
|
|
7744
7762
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -7754,14 +7772,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
7754
7772
|
},
|
|
7755
7773
|
...rest,
|
|
7756
7774
|
children: [
|
|
7757
|
-
/* @__PURE__ */
|
|
7758
|
-
/* @__PURE__ */
|
|
7759
|
-
/* @__PURE__ */
|
|
7775
|
+
/* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
7776
|
+
/* @__PURE__ */ jsx62("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
7777
|
+
/* @__PURE__ */ jsx62("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
|
|
7760
7778
|
] }),
|
|
7761
|
-
/* @__PURE__ */
|
|
7762
|
-
need.length ? /* @__PURE__ */
|
|
7763
|
-
/* @__PURE__ */
|
|
7764
|
-
need.map((p) => /* @__PURE__ */
|
|
7779
|
+
/* @__PURE__ */ jsx62("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." }),
|
|
7780
|
+
need.length ? /* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
|
|
7781
|
+
/* @__PURE__ */ jsx62("span", { className: "fd-overline fd-muted", children: "Requires" }),
|
|
7782
|
+
need.map((p) => /* @__PURE__ */ jsx62("code", { className: "fd-mono", style: {
|
|
7765
7783
|
fontSize: 11.5,
|
|
7766
7784
|
padding: "2px 7px",
|
|
7767
7785
|
borderRadius: 5,
|
|
@@ -7782,7 +7800,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
|
|
|
7782
7800
|
if (ok) return children;
|
|
7783
7801
|
if (fallback !== void 0) return fallback;
|
|
7784
7802
|
if (silent) return null;
|
|
7785
|
-
return /* @__PURE__ */
|
|
7803
|
+
return /* @__PURE__ */ jsx62(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
7786
7804
|
}
|
|
7787
7805
|
function FeatureGate({
|
|
7788
7806
|
flag,
|
|
@@ -7803,7 +7821,7 @@ function FeatureGate({
|
|
|
7803
7821
|
if (!preview) return fallback;
|
|
7804
7822
|
const f = SessionKit.findFlag(flag) || {};
|
|
7805
7823
|
const missing = rt.missing || [];
|
|
7806
|
-
return /* @__PURE__ */
|
|
7824
|
+
return /* @__PURE__ */ jsx62(
|
|
7807
7825
|
ComingSoon,
|
|
7808
7826
|
{
|
|
7809
7827
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -7824,25 +7842,25 @@ function FeatureGate({
|
|
|
7824
7842
|
function PermissionHint({ perm, children }) {
|
|
7825
7843
|
SessionKit.useSession();
|
|
7826
7844
|
if (SessionKit.can(perm)) return children;
|
|
7827
|
-
return /* @__PURE__ */
|
|
7845
|
+
return /* @__PURE__ */ jsx62(
|
|
7828
7846
|
"span",
|
|
7829
7847
|
{
|
|
7830
7848
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
7831
7849
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
7832
7850
|
"aria-disabled": "true",
|
|
7833
|
-
children: /* @__PURE__ */
|
|
7851
|
+
children: /* @__PURE__ */ jsx62("span", { style: { pointerEvents: "none" }, children })
|
|
7834
7852
|
}
|
|
7835
7853
|
);
|
|
7836
7854
|
}
|
|
7837
7855
|
|
|
7838
7856
|
// src/components/platform/ModeSwitch.tsx
|
|
7839
|
-
import * as
|
|
7840
|
-
import { Fragment as Fragment15, jsx as
|
|
7857
|
+
import * as React35 from "react";
|
|
7858
|
+
import { Fragment as Fragment15, jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
7841
7859
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
7842
7860
|
const mode2 = useRuntimeMode();
|
|
7843
|
-
const [open, setOpen] =
|
|
7844
|
-
const ref =
|
|
7845
|
-
|
|
7861
|
+
const [open, setOpen] = React35.useState(false);
|
|
7862
|
+
const ref = React35.useRef(null);
|
|
7863
|
+
React35.useEffect(() => {
|
|
7846
7864
|
if (!open) return;
|
|
7847
7865
|
const away = (e) => {
|
|
7848
7866
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -7864,8 +7882,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7864
7882
|
RuntimeKit.setMode(next);
|
|
7865
7883
|
setOpen(false);
|
|
7866
7884
|
};
|
|
7867
|
-
return /* @__PURE__ */
|
|
7868
|
-
/* @__PURE__ */
|
|
7885
|
+
return /* @__PURE__ */ jsxs58("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
|
|
7886
|
+
/* @__PURE__ */ jsxs58(
|
|
7869
7887
|
"button",
|
|
7870
7888
|
{
|
|
7871
7889
|
type: "button",
|
|
@@ -7875,29 +7893,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7875
7893
|
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.",
|
|
7876
7894
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
|
|
7877
7895
|
children: [
|
|
7878
|
-
/* @__PURE__ */
|
|
7879
|
-
test && requestCount ? /* @__PURE__ */
|
|
7896
|
+
/* @__PURE__ */ jsx63("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
|
|
7897
|
+
test && requestCount ? /* @__PURE__ */ jsx63("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
|
|
7880
7898
|
]
|
|
7881
7899
|
}
|
|
7882
7900
|
),
|
|
7883
|
-
open ? /* @__PURE__ */
|
|
7884
|
-
/* @__PURE__ */
|
|
7885
|
-
/* @__PURE__ */
|
|
7886
|
-
/* @__PURE__ */
|
|
7901
|
+
open ? /* @__PURE__ */ jsxs58("span", { className: "fd-view-enter fd-mode-pop", children: [
|
|
7902
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
7903
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
|
|
7904
|
+
/* @__PURE__ */ jsx63("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
|
|
7887
7905
|
test ? "Test mode" : "Live mode"
|
|
7888
7906
|
] }),
|
|
7889
|
-
test ? /* @__PURE__ */
|
|
7907
|
+
test ? /* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
7890
7908
|
requestCount,
|
|
7891
7909
|
" simulated request",
|
|
7892
7910
|
requestCount === 1 ? "" : "s"
|
|
7893
7911
|
] }) : null,
|
|
7894
|
-
/* @__PURE__ */
|
|
7895
|
-
test && onClearLog ? /* @__PURE__ */
|
|
7912
|
+
/* @__PURE__ */ jsx63("span", { style: { flex: 1 } }),
|
|
7913
|
+
test && onClearLog ? /* @__PURE__ */ jsx63("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
|
|
7896
7914
|
] }),
|
|
7897
|
-
/* @__PURE__ */
|
|
7898
|
-
/* @__PURE__ */
|
|
7899
|
-
/* @__PURE__ */
|
|
7900
|
-
/* @__PURE__ */
|
|
7915
|
+
/* @__PURE__ */ jsxs58("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
7916
|
+
/* @__PURE__ */ jsx63("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." }),
|
|
7917
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
|
|
7918
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
7901
7919
|
s.endpointsWired,
|
|
7902
7920
|
" endpoint",
|
|
7903
7921
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -7907,58 +7925,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7907
7925
|
s.total,
|
|
7908
7926
|
" features complete"
|
|
7909
7927
|
] }),
|
|
7910
|
-
onOpenSpec ? /* @__PURE__ */
|
|
7911
|
-
/* @__PURE__ */
|
|
7912
|
-
/* @__PURE__ */
|
|
7928
|
+
onOpenSpec ? /* @__PURE__ */ jsxs58(Fragment15, { children: [
|
|
7929
|
+
/* @__PURE__ */ jsx63("span", { style: { flex: 1 } }),
|
|
7930
|
+
/* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
7913
7931
|
setOpen(false);
|
|
7914
7932
|
onOpenSpec();
|
|
7915
7933
|
}, children: [
|
|
7916
7934
|
"API spec ",
|
|
7917
|
-
/* @__PURE__ */
|
|
7935
|
+
/* @__PURE__ */ jsx63("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
7918
7936
|
] })
|
|
7919
7937
|
] }) : null
|
|
7920
7938
|
] })
|
|
7921
7939
|
] }),
|
|
7922
|
-
/* @__PURE__ */
|
|
7923
|
-
/* @__PURE__ */
|
|
7924
|
-
/* @__PURE__ */
|
|
7925
|
-
/* @__PURE__ */
|
|
7926
|
-
/* @__PURE__ */
|
|
7927
|
-
/* @__PURE__ */
|
|
7940
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-mode-choice", children: [
|
|
7941
|
+
/* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
|
|
7942
|
+
/* @__PURE__ */ jsx63("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
7943
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-mode-opt-text", children: [
|
|
7944
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-title", children: "Live mode" }),
|
|
7945
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
|
|
7928
7946
|
] }),
|
|
7929
|
-
!test ? /* @__PURE__ */
|
|
7947
|
+
!test ? /* @__PURE__ */ jsx63("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
7930
7948
|
] }),
|
|
7931
|
-
/* @__PURE__ */
|
|
7932
|
-
/* @__PURE__ */
|
|
7933
|
-
/* @__PURE__ */
|
|
7934
|
-
/* @__PURE__ */
|
|
7935
|
-
/* @__PURE__ */
|
|
7949
|
+
/* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
|
|
7950
|
+
/* @__PURE__ */ jsx63("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
7951
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-mode-opt-text", children: [
|
|
7952
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-title", children: "Test mode" }),
|
|
7953
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
|
|
7936
7954
|
] }),
|
|
7937
|
-
test ? /* @__PURE__ */
|
|
7955
|
+
test ? /* @__PURE__ */ jsx63("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
7938
7956
|
] })
|
|
7939
7957
|
] }),
|
|
7940
|
-
test && renderLog ? /* @__PURE__ */
|
|
7958
|
+
test && renderLog ? /* @__PURE__ */ jsx63("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
7941
7959
|
] }) : null
|
|
7942
7960
|
] });
|
|
7943
7961
|
}
|
|
7944
7962
|
function TestModeBar({ onExit }) {
|
|
7945
7963
|
const mode2 = useRuntimeMode();
|
|
7946
7964
|
if (mode2 !== "test") return null;
|
|
7947
|
-
return /* @__PURE__ */
|
|
7948
|
-
/* @__PURE__ */
|
|
7949
|
-
/* @__PURE__ */
|
|
7965
|
+
return /* @__PURE__ */ jsxs58("div", { className: "fd-testbar", role: "status", children: [
|
|
7966
|
+
/* @__PURE__ */ jsxs58("span", { className: "fd-badge fd-badge-warning", children: [
|
|
7967
|
+
/* @__PURE__ */ jsx63("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
7950
7968
|
"Test mode"
|
|
7951
7969
|
] }),
|
|
7952
|
-
/* @__PURE__ */
|
|
7953
|
-
/* @__PURE__ */
|
|
7954
|
-
/* @__PURE__ */
|
|
7970
|
+
/* @__PURE__ */ jsx63("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
|
|
7971
|
+
/* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
|
|
7972
|
+
/* @__PURE__ */ jsx63("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
7955
7973
|
" Back to live mode"
|
|
7956
7974
|
] })
|
|
7957
7975
|
] });
|
|
7958
7976
|
}
|
|
7959
7977
|
|
|
7960
7978
|
// src/components/planner/ChannelMeta.tsx
|
|
7961
|
-
import { jsx as
|
|
7979
|
+
import { jsx as jsx64, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
7962
7980
|
var CHANNEL_WEIGHTS = {
|
|
7963
7981
|
"OOH": 50,
|
|
7964
7982
|
"DOOH": 50,
|
|
@@ -8011,9 +8029,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
8011
8029
|
const m = ChannelMeta(channel);
|
|
8012
8030
|
const wt = channelWeightOf(channel || "");
|
|
8013
8031
|
if (dot) {
|
|
8014
|
-
return /* @__PURE__ */
|
|
8032
|
+
return /* @__PURE__ */ jsx64("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
8015
8033
|
}
|
|
8016
|
-
return /* @__PURE__ */
|
|
8034
|
+
return /* @__PURE__ */ jsxs59(
|
|
8017
8035
|
"span",
|
|
8018
8036
|
{
|
|
8019
8037
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -8021,16 +8039,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
8021
8039
|
style: { "--chan": m.color },
|
|
8022
8040
|
...rest,
|
|
8023
8041
|
children: [
|
|
8024
|
-
/* @__PURE__ */
|
|
8025
|
-
showLabel ? /* @__PURE__ */
|
|
8026
|
-
weight ? /* @__PURE__ */
|
|
8042
|
+
/* @__PURE__ */ jsx64("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
|
|
8043
|
+
showLabel ? /* @__PURE__ */ jsx64("span", { className: "fd-chan-label", children: m.label }) : null,
|
|
8044
|
+
weight ? /* @__PURE__ */ jsx64("span", { className: "fd-chan-weight", children: wt || 0 }) : null
|
|
8027
8045
|
]
|
|
8028
8046
|
}
|
|
8029
8047
|
);
|
|
8030
8048
|
}
|
|
8031
8049
|
|
|
8032
8050
|
// src/components/planner/SaturationDistribution.tsx
|
|
8033
|
-
import { jsx as
|
|
8051
|
+
import { jsx as jsx65, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
8034
8052
|
var BANDS2 = [
|
|
8035
8053
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
8036
8054
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -8041,18 +8059,18 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8041
8059
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
8042
8060
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
8043
8061
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
8044
|
-
return /* @__PURE__ */
|
|
8045
|
-
/* @__PURE__ */
|
|
8062
|
+
return /* @__PURE__ */ jsxs60("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
8063
|
+
/* @__PURE__ */ jsx65("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
|
|
8046
8064
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
8047
8065
|
const active = selectedBand === g.key;
|
|
8048
|
-
return /* @__PURE__ */
|
|
8066
|
+
return /* @__PURE__ */ jsxs60(
|
|
8049
8067
|
"button",
|
|
8050
8068
|
{
|
|
8051
8069
|
type: "button",
|
|
8052
8070
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
8053
8071
|
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)" },
|
|
8054
8072
|
children: [
|
|
8055
|
-
/* @__PURE__ */
|
|
8073
|
+
/* @__PURE__ */ jsx65("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx65("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => /* @__PURE__ */ jsx65(
|
|
8056
8074
|
"span",
|
|
8057
8075
|
{
|
|
8058
8076
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -8061,13 +8079,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8061
8079
|
},
|
|
8062
8080
|
c.name
|
|
8063
8081
|
)) }),
|
|
8064
|
-
/* @__PURE__ */
|
|
8065
|
-
/* @__PURE__ */
|
|
8066
|
-
/* @__PURE__ */
|
|
8082
|
+
/* @__PURE__ */ jsxs60("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
|
|
8083
|
+
/* @__PURE__ */ jsx65("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
|
|
8084
|
+
/* @__PURE__ */ jsx65("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx65("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
|
|
8067
8085
|
] }),
|
|
8068
|
-
/* @__PURE__ */
|
|
8069
|
-
/* @__PURE__ */
|
|
8070
|
-
/* @__PURE__ */
|
|
8086
|
+
/* @__PURE__ */ jsxs60("span", { className: "fd-stack", style: { gap: 1 }, children: [
|
|
8087
|
+
/* @__PURE__ */ jsx65("span", { className: "fd-label-lg", children: g.label }),
|
|
8088
|
+
/* @__PURE__ */ jsxs60("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
|
|
8071
8089
|
"CRP ",
|
|
8072
8090
|
g.range
|
|
8073
8091
|
] })
|
|
@@ -8077,10 +8095,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8077
8095
|
g.key
|
|
8078
8096
|
);
|
|
8079
8097
|
}) }),
|
|
8080
|
-
floorBand ? /* @__PURE__ */
|
|
8081
|
-
/* @__PURE__ */
|
|
8082
|
-
/* @__PURE__ */
|
|
8083
|
-
/* @__PURE__ */
|
|
8098
|
+
floorBand ? /* @__PURE__ */ jsxs60("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: [
|
|
8099
|
+
/* @__PURE__ */ jsx65("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx65("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
|
|
8100
|
+
/* @__PURE__ */ jsxs60("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
|
|
8101
|
+
/* @__PURE__ */ jsxs60("strong", { style: { color: "var(--text)" }, children: [
|
|
8084
8102
|
"Plan floor ",
|
|
8085
8103
|
floorScore
|
|
8086
8104
|
] }),
|
|
@@ -8091,21 +8109,21 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8091
8109
|
}
|
|
8092
8110
|
|
|
8093
8111
|
// src/components/planner/MixGap.tsx
|
|
8094
|
-
import * as
|
|
8095
|
-
import { Fragment as Fragment16, jsx as
|
|
8112
|
+
import * as React36 from "react";
|
|
8113
|
+
import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
8096
8114
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
8097
8115
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
8098
|
-
const [hover, setHover] =
|
|
8116
|
+
const [hover, setHover] = React36.useState(null);
|
|
8099
8117
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
8100
8118
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
8101
|
-
return /* @__PURE__ */
|
|
8102
|
-
/* @__PURE__ */
|
|
8103
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */
|
|
8104
|
-
/* @__PURE__ */
|
|
8119
|
+
return /* @__PURE__ */ jsxs61("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
8120
|
+
/* @__PURE__ */ jsxs61("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
|
|
8121
|
+
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs61("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
8122
|
+
/* @__PURE__ */ jsx66("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
|
|
8105
8123
|
l
|
|
8106
8124
|
] }, l)),
|
|
8107
|
-
/* @__PURE__ */
|
|
8108
|
-
/* @__PURE__ */
|
|
8125
|
+
/* @__PURE__ */ jsxs61("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
8126
|
+
/* @__PURE__ */ jsx66("span", { style: { width: 3, height: 14, background: "var(--n-500)" } }),
|
|
8109
8127
|
"Target"
|
|
8110
8128
|
] })
|
|
8111
8129
|
] }),
|
|
@@ -8113,7 +8131,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
8113
8131
|
const gap = r.realized - r.target;
|
|
8114
8132
|
const tone = toneOf(gap);
|
|
8115
8133
|
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 : "");
|
|
8116
|
-
return /* @__PURE__ */
|
|
8134
|
+
return /* @__PURE__ */ jsxs61(
|
|
8117
8135
|
"div",
|
|
8118
8136
|
{
|
|
8119
8137
|
className: "fd-row",
|
|
@@ -8121,15 +8139,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
8121
8139
|
onMouseEnter: () => setHover(r.channel),
|
|
8122
8140
|
onMouseLeave: () => setHover(null),
|
|
8123
8141
|
children: [
|
|
8124
|
-
/* @__PURE__ */
|
|
8125
|
-
/* @__PURE__ */
|
|
8126
|
-
/* @__PURE__ */
|
|
8127
|
-
/* @__PURE__ */
|
|
8128
|
-
/* @__PURE__ */
|
|
8142
|
+
/* @__PURE__ */ jsx66("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx66(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
8143
|
+
/* @__PURE__ */ jsx66("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx66("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs61(Fragment16, { children: [
|
|
8144
|
+
/* @__PURE__ */ jsx66("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)" } }),
|
|
8145
|
+
/* @__PURE__ */ jsx66("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
|
|
8146
|
+
/* @__PURE__ */ jsxs61("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: [
|
|
8129
8147
|
r.realized,
|
|
8130
8148
|
"%"
|
|
8131
8149
|
] }),
|
|
8132
|
-
hover === r.channel ? /* @__PURE__ */
|
|
8150
|
+
hover === r.channel ? /* @__PURE__ */ jsx66("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
|
|
8133
8151
|
] }) })
|
|
8134
8152
|
]
|
|
8135
8153
|
},
|
|
@@ -8140,7 +8158,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
8140
8158
|
}
|
|
8141
8159
|
|
|
8142
8160
|
// src/components/planner/ChannelContribution.tsx
|
|
8143
|
-
import { jsx as
|
|
8161
|
+
import { jsx as jsx67, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
8144
8162
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
8145
8163
|
function ChannelContribution({
|
|
8146
8164
|
channels = [],
|
|
@@ -8156,9 +8174,9 @@ function ChannelContribution({
|
|
|
8156
8174
|
const grand = total !== void 0 ? total : base + bonus;
|
|
8157
8175
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
8158
8176
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
8159
|
-
return /* @__PURE__ */
|
|
8160
|
-
loading ? /* @__PURE__ */
|
|
8161
|
-
channels.map((c) => /* @__PURE__ */
|
|
8177
|
+
return /* @__PURE__ */ jsxs62("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
8178
|
+
loading ? /* @__PURE__ */ jsx67("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
|
|
8179
|
+
channels.map((c) => /* @__PURE__ */ jsx67(
|
|
8162
8180
|
"span",
|
|
8163
8181
|
{
|
|
8164
8182
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -8167,7 +8185,7 @@ function ChannelContribution({
|
|
|
8167
8185
|
},
|
|
8168
8186
|
c.name
|
|
8169
8187
|
)),
|
|
8170
|
-
bonus > 0 ? /* @__PURE__ */
|
|
8188
|
+
bonus > 0 ? /* @__PURE__ */ jsx67(
|
|
8171
8189
|
"span",
|
|
8172
8190
|
{
|
|
8173
8191
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -8176,18 +8194,18 @@ function ChannelContribution({
|
|
|
8176
8194
|
}
|
|
8177
8195
|
) : null
|
|
8178
8196
|
] }),
|
|
8179
|
-
showTable ? /* @__PURE__ */
|
|
8180
|
-
/* @__PURE__ */
|
|
8181
|
-
/* @__PURE__ */
|
|
8182
|
-
/* @__PURE__ */
|
|
8183
|
-
/* @__PURE__ */
|
|
8184
|
-
/* @__PURE__ */
|
|
8185
|
-
/* @__PURE__ */
|
|
8197
|
+
showTable ? /* @__PURE__ */ jsxs62("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
|
|
8198
|
+
/* @__PURE__ */ jsx67("thead", { children: /* @__PURE__ */ jsxs62("tr", { children: [
|
|
8199
|
+
/* @__PURE__ */ jsx67("th", { style: { width: "34%" }, children: "Channel" }),
|
|
8200
|
+
/* @__PURE__ */ jsx67("th", { style: { width: "16%" }, children: "Weight" }),
|
|
8201
|
+
/* @__PURE__ */ jsx67("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
|
|
8202
|
+
/* @__PURE__ */ jsx67("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
|
|
8203
|
+
/* @__PURE__ */ jsx67("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
|
|
8186
8204
|
] }) }),
|
|
8187
|
-
/* @__PURE__ */
|
|
8188
|
-
channels.map((c) => /* @__PURE__ */
|
|
8189
|
-
/* @__PURE__ */
|
|
8190
|
-
/* @__PURE__ */
|
|
8205
|
+
/* @__PURE__ */ jsxs62("tbody", { children: [
|
|
8206
|
+
channels.map((c) => /* @__PURE__ */ jsxs62("tr", { children: [
|
|
8207
|
+
/* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsx67(ChannelTag, { channel: c.name, size: "sm" }) }),
|
|
8208
|
+
/* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsx67(
|
|
8191
8209
|
"span",
|
|
8192
8210
|
{
|
|
8193
8211
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -8196,38 +8214,38 @@ function ChannelContribution({
|
|
|
8196
8214
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
8197
8215
|
}
|
|
8198
8216
|
) }),
|
|
8199
|
-
/* @__PURE__ */
|
|
8200
|
-
/* @__PURE__ */
|
|
8201
|
-
/* @__PURE__ */
|
|
8217
|
+
/* @__PURE__ */ jsx67("td", { className: "is-num", children: c.spend }),
|
|
8218
|
+
/* @__PURE__ */ jsx67("td", { className: "is-num", children: c.crp.toFixed(1) }),
|
|
8219
|
+
/* @__PURE__ */ jsxs62("td", { className: "is-num", children: [
|
|
8202
8220
|
pct(c.crp).toFixed(0),
|
|
8203
8221
|
"%"
|
|
8204
8222
|
] })
|
|
8205
8223
|
] }, c.name)),
|
|
8206
|
-
bonus > 0 ? /* @__PURE__ */
|
|
8207
|
-
/* @__PURE__ */
|
|
8208
|
-
/* @__PURE__ */
|
|
8224
|
+
bonus > 0 ? /* @__PURE__ */ jsxs62("tr", { children: [
|
|
8225
|
+
/* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsxs62("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
|
|
8226
|
+
/* @__PURE__ */ jsx67("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" } }),
|
|
8209
8227
|
"Surround-sound bonus"
|
|
8210
8228
|
] }) }),
|
|
8211
|
-
/* @__PURE__ */
|
|
8229
|
+
/* @__PURE__ */ jsx67("td", { children: /* @__PURE__ */ jsxs62("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
8212
8230
|
"+",
|
|
8213
8231
|
bonusPct,
|
|
8214
8232
|
"% of +",
|
|
8215
8233
|
bonusMax,
|
|
8216
8234
|
"%"
|
|
8217
8235
|
] }) }),
|
|
8218
|
-
/* @__PURE__ */
|
|
8219
|
-
/* @__PURE__ */
|
|
8220
|
-
/* @__PURE__ */
|
|
8236
|
+
/* @__PURE__ */ jsx67("td", { className: "is-num fd-muted", children: "\u2014" }),
|
|
8237
|
+
/* @__PURE__ */ jsx67("td", { className: "is-num", children: bonus.toFixed(1) }),
|
|
8238
|
+
/* @__PURE__ */ jsxs62("td", { className: "is-num", children: [
|
|
8221
8239
|
pct(bonus).toFixed(0),
|
|
8222
8240
|
"%"
|
|
8223
8241
|
] })
|
|
8224
8242
|
] }) : null,
|
|
8225
|
-
/* @__PURE__ */
|
|
8226
|
-
/* @__PURE__ */
|
|
8227
|
-
/* @__PURE__ */
|
|
8228
|
-
/* @__PURE__ */
|
|
8229
|
-
/* @__PURE__ */
|
|
8230
|
-
/* @__PURE__ */
|
|
8243
|
+
/* @__PURE__ */ jsxs62("tr", { style: { background: "var(--surface-2)" }, children: [
|
|
8244
|
+
/* @__PURE__ */ jsx67("td", { style: { fontWeight: 700 }, children: "Campus total" }),
|
|
8245
|
+
/* @__PURE__ */ jsx67("td", {}),
|
|
8246
|
+
/* @__PURE__ */ jsx67("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
|
|
8247
|
+
/* @__PURE__ */ jsx67("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
|
|
8248
|
+
/* @__PURE__ */ jsx67("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
|
|
8231
8249
|
] })
|
|
8232
8250
|
] })
|
|
8233
8251
|
] }) : null
|
|
@@ -8235,8 +8253,8 @@ function ChannelContribution({
|
|
|
8235
8253
|
}
|
|
8236
8254
|
|
|
8237
8255
|
// src/components/planner/BudgetReallocator.tsx
|
|
8238
|
-
import * as
|
|
8239
|
-
import { Fragment as Fragment17, jsx as
|
|
8256
|
+
import * as React37 from "react";
|
|
8257
|
+
import { Fragment as Fragment17, jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
8240
8258
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
8241
8259
|
function BudgetReallocator({
|
|
8242
8260
|
campus,
|
|
@@ -8251,8 +8269,8 @@ function BudgetReallocator({
|
|
|
8251
8269
|
onCancel,
|
|
8252
8270
|
className = ""
|
|
8253
8271
|
}) {
|
|
8254
|
-
const [draft, setDraft] =
|
|
8255
|
-
|
|
8272
|
+
const [draft, setDraft] = React37.useState(spend);
|
|
8273
|
+
React37.useEffect(() => setDraft(spend), [spend]);
|
|
8256
8274
|
const dirty = draft !== spend;
|
|
8257
8275
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
8258
8276
|
const nextBand = bandFor(nextCrp);
|
|
@@ -8267,24 +8285,24 @@ function BudgetReallocator({
|
|
|
8267
8285
|
setDraft(spend);
|
|
8268
8286
|
if (onCancel) onCancel();
|
|
8269
8287
|
};
|
|
8270
|
-
return /* @__PURE__ */
|
|
8288
|
+
return /* @__PURE__ */ jsxs63(
|
|
8271
8289
|
"div",
|
|
8272
8290
|
{
|
|
8273
8291
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
8274
8292
|
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)" },
|
|
8275
8293
|
children: [
|
|
8276
|
-
/* @__PURE__ */
|
|
8277
|
-
/* @__PURE__ */
|
|
8278
|
-
/* @__PURE__ */
|
|
8279
|
-
dirty ? /* @__PURE__ */
|
|
8280
|
-
/* @__PURE__ */
|
|
8281
|
-
/* @__PURE__ */
|
|
8294
|
+
/* @__PURE__ */ jsxs63("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8295
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
8296
|
+
/* @__PURE__ */ jsx68(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
8297
|
+
dirty ? /* @__PURE__ */ jsxs63(Fragment17, { children: [
|
|
8298
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
8299
|
+
/* @__PURE__ */ jsx68(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
8282
8300
|
] }) : null
|
|
8283
8301
|
] }),
|
|
8284
|
-
/* @__PURE__ */
|
|
8285
|
-
/* @__PURE__ */
|
|
8286
|
-
dirty ? /* @__PURE__ */
|
|
8287
|
-
/* @__PURE__ */
|
|
8302
|
+
/* @__PURE__ */ jsxs63("div", { className: "fd-slider", children: [
|
|
8303
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
8304
|
+
dirty ? /* @__PURE__ */ jsx68("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,
|
|
8305
|
+
/* @__PURE__ */ jsx68(
|
|
8288
8306
|
"input",
|
|
8289
8307
|
{
|
|
8290
8308
|
type: "range",
|
|
@@ -8300,13 +8318,13 @@ function BudgetReallocator({
|
|
|
8300
8318
|
}
|
|
8301
8319
|
)
|
|
8302
8320
|
] }),
|
|
8303
|
-
/* @__PURE__ */
|
|
8304
|
-
/* @__PURE__ */
|
|
8305
|
-
/* @__PURE__ */
|
|
8306
|
-
/* @__PURE__ */
|
|
8321
|
+
/* @__PURE__ */ jsxs63("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8322
|
+
/* @__PURE__ */ jsxs63("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
|
|
8323
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
|
|
8324
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
|
|
8307
8325
|
] }),
|
|
8308
|
-
/* @__PURE__ */
|
|
8309
|
-
/* @__PURE__ */
|
|
8326
|
+
/* @__PURE__ */ jsx68("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
8327
|
+
/* @__PURE__ */ jsx68(
|
|
8310
8328
|
"button",
|
|
8311
8329
|
{
|
|
8312
8330
|
type: "button",
|
|
@@ -8325,7 +8343,7 @@ function BudgetReallocator({
|
|
|
8325
8343
|
}
|
|
8326
8344
|
|
|
8327
8345
|
// src/components/planner/SurroundSound.tsx
|
|
8328
|
-
import { jsx as
|
|
8346
|
+
import { jsx as jsx69, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
8329
8347
|
var CATEGORIES = [
|
|
8330
8348
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
8331
8349
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -8337,26 +8355,26 @@ var CATEGORIES = [
|
|
|
8337
8355
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
8338
8356
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
8339
8357
|
const single = present.length <= 2;
|
|
8340
|
-
return /* @__PURE__ */
|
|
8341
|
-
/* @__PURE__ */
|
|
8358
|
+
return /* @__PURE__ */ jsxs64("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
|
|
8359
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
|
|
8342
8360
|
const on = present.includes(c.key);
|
|
8343
|
-
return /* @__PURE__ */
|
|
8361
|
+
return /* @__PURE__ */ jsxs64(
|
|
8344
8362
|
"span",
|
|
8345
8363
|
{
|
|
8346
8364
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
8347
8365
|
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)" },
|
|
8348
8366
|
children: [
|
|
8349
|
-
/* @__PURE__ */
|
|
8350
|
-
/* @__PURE__ */
|
|
8367
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
8368
|
+
/* @__PURE__ */ jsx69("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
|
|
8351
8369
|
]
|
|
8352
8370
|
},
|
|
8353
8371
|
c.key
|
|
8354
8372
|
);
|
|
8355
8373
|
}) }),
|
|
8356
|
-
/* @__PURE__ */
|
|
8357
|
-
/* @__PURE__ */
|
|
8358
|
-
/* @__PURE__ */
|
|
8359
|
-
/* @__PURE__ */
|
|
8374
|
+
/* @__PURE__ */ jsxs64("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
8375
|
+
/* @__PURE__ */ jsxs64("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
8376
|
+
/* @__PURE__ */ jsx69("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
|
|
8377
|
+
/* @__PURE__ */ jsxs64("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
|
|
8360
8378
|
"+",
|
|
8361
8379
|
bonusPct,
|
|
8362
8380
|
"% of +",
|
|
@@ -8364,8 +8382,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
8364
8382
|
"%"
|
|
8365
8383
|
] })
|
|
8366
8384
|
] }),
|
|
8367
|
-
/* @__PURE__ */
|
|
8368
|
-
/* @__PURE__ */
|
|
8385
|
+
/* @__PURE__ */ jsx69("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx69("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
|
|
8386
|
+
/* @__PURE__ */ jsxs64("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
|
|
8369
8387
|
present.length,
|
|
8370
8388
|
" of 6 channel categories present.",
|
|
8371
8389
|
" ",
|
|
@@ -8377,7 +8395,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
8377
8395
|
}
|
|
8378
8396
|
|
|
8379
8397
|
// src/components/planner/Importance.tsx
|
|
8380
|
-
import { jsx as
|
|
8398
|
+
import { jsx as jsx70, jsxs as jsxs65 } from "react/jsx-runtime";
|
|
8381
8399
|
var IMPORTANCE_LEVELS = [
|
|
8382
8400
|
{ id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
|
|
8383
8401
|
{ id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
|
|
@@ -8407,23 +8425,23 @@ function importanceTokens(id) {
|
|
|
8407
8425
|
function ImportanceTag({ level, showLabel = true, size = "sm", className = "" }) {
|
|
8408
8426
|
const lvl = importanceLevel(level);
|
|
8409
8427
|
const t = importanceTokens(level);
|
|
8410
|
-
return /* @__PURE__ */
|
|
8428
|
+
return /* @__PURE__ */ jsxs65(
|
|
8411
8429
|
"span",
|
|
8412
8430
|
{
|
|
8413
8431
|
className: ["fd-imp-tag", size === "md" ? "is-md" : "", className].filter(Boolean).join(" "),
|
|
8414
8432
|
style: { background: t.fill, borderColor: t.edge, color: t.text },
|
|
8415
8433
|
title: lvl.label + " \u2014 " + lvl.description,
|
|
8416
8434
|
children: [
|
|
8417
|
-
/* @__PURE__ */
|
|
8418
|
-
showLabel ? lvl.label : /* @__PURE__ */
|
|
8435
|
+
/* @__PURE__ */ jsx70("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
|
|
8436
|
+
showLabel ? lvl.label : /* @__PURE__ */ jsx70("span", { className: "fd-sr", children: lvl.label })
|
|
8419
8437
|
]
|
|
8420
8438
|
}
|
|
8421
8439
|
);
|
|
8422
8440
|
}
|
|
8423
8441
|
|
|
8424
8442
|
// src/components/planner/PreferenceMeter.tsx
|
|
8425
|
-
import * as
|
|
8426
|
-
import { jsx as
|
|
8443
|
+
import * as React38 from "react";
|
|
8444
|
+
import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
8427
8445
|
function preferenceScore(criteria) {
|
|
8428
8446
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
8429
8447
|
const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
|
|
@@ -8452,8 +8470,8 @@ function PreferenceMeter({
|
|
|
8452
8470
|
className = ""
|
|
8453
8471
|
}) {
|
|
8454
8472
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
8455
|
-
const segments =
|
|
8456
|
-
return /* @__PURE__ */
|
|
8473
|
+
const segments = React38.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
8474
|
+
return /* @__PURE__ */ jsx71(
|
|
8457
8475
|
ScoreMeter,
|
|
8458
8476
|
{
|
|
8459
8477
|
score: value,
|
|
@@ -8465,22 +8483,22 @@ function PreferenceMeter({
|
|
|
8465
8483
|
placement,
|
|
8466
8484
|
className,
|
|
8467
8485
|
breakdownLabel: breakdownTitle,
|
|
8468
|
-
breakdown: /* @__PURE__ */
|
|
8469
|
-
/* @__PURE__ */
|
|
8470
|
-
/* @__PURE__ */
|
|
8471
|
-
/* @__PURE__ */
|
|
8486
|
+
breakdown: /* @__PURE__ */ jsxs66("div", { className: "fd-prefbreak", children: [
|
|
8487
|
+
/* @__PURE__ */ jsxs66("div", { className: "fd-prefbreak-head", children: [
|
|
8488
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-label-lg", children: breakdownTitle }),
|
|
8489
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
|
|
8472
8490
|
] }),
|
|
8473
|
-
/* @__PURE__ */
|
|
8491
|
+
/* @__PURE__ */ jsx71("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
|
|
8474
8492
|
const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
|
|
8475
|
-
return /* @__PURE__ */
|
|
8476
|
-
/* @__PURE__ */
|
|
8477
|
-
/* @__PURE__ */
|
|
8478
|
-
/* @__PURE__ */
|
|
8479
|
-
c.note ? /* @__PURE__ */
|
|
8493
|
+
return /* @__PURE__ */ jsxs66("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
|
|
8494
|
+
/* @__PURE__ */ jsx71(ImportanceTag, { level: c.importance }),
|
|
8495
|
+
/* @__PURE__ */ jsxs66("span", { className: "fd-prefbreak-text", children: [
|
|
8496
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-label", children: c.label }),
|
|
8497
|
+
c.note ? /* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-note", children: c.note }) : null
|
|
8480
8498
|
] }),
|
|
8481
|
-
/* @__PURE__ */
|
|
8499
|
+
/* @__PURE__ */ jsxs66("span", { className: "fd-prefbreak-val fd-tabular", children: [
|
|
8482
8500
|
Math.round(Number(c.earned) || 0),
|
|
8483
|
-
/* @__PURE__ */
|
|
8501
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-prefbreak-sep", children: "/" }),
|
|
8484
8502
|
Math.round(c.weight)
|
|
8485
8503
|
] })
|
|
8486
8504
|
] }, c.id);
|
|
@@ -8491,10 +8509,10 @@ function PreferenceMeter({
|
|
|
8491
8509
|
}
|
|
8492
8510
|
|
|
8493
8511
|
// src/components/chat/AgentChatPanel.tsx
|
|
8494
|
-
import * as
|
|
8512
|
+
import * as React44 from "react";
|
|
8495
8513
|
|
|
8496
8514
|
// src/components/chat/chatEngine.ts
|
|
8497
|
-
import * as
|
|
8515
|
+
import * as React39 from "react";
|
|
8498
8516
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
8499
8517
|
var JOB_PENDING = ["queued", "running"];
|
|
8500
8518
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -8548,22 +8566,22 @@ function useChatEngine(opts) {
|
|
|
8548
8566
|
onClear,
|
|
8549
8567
|
onFeedback
|
|
8550
8568
|
} = opts || {};
|
|
8551
|
-
const [status, setStatus] =
|
|
8552
|
-
const [threadId, setThreadId] =
|
|
8553
|
-
const [messages, setMessages] =
|
|
8554
|
-
const [queue, setQueue] =
|
|
8555
|
-
const [fatal, setFatal] =
|
|
8556
|
-
const [busy, setBusy] =
|
|
8557
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
8558
|
-
const listRef =
|
|
8559
|
-
const queueRef =
|
|
8560
|
-
const busyRef =
|
|
8561
|
-
const stoppedRef =
|
|
8562
|
-
const abortRef =
|
|
8563
|
-
const serverCount =
|
|
8564
|
-
const threadRef =
|
|
8565
|
-
const mounted =
|
|
8566
|
-
|
|
8569
|
+
const [status, setStatus] = React39.useState("idle");
|
|
8570
|
+
const [threadId, setThreadId] = React39.useState(null);
|
|
8571
|
+
const [messages, setMessages] = React39.useState([]);
|
|
8572
|
+
const [queue, setQueue] = React39.useState([]);
|
|
8573
|
+
const [fatal, setFatal] = React39.useState(null);
|
|
8574
|
+
const [busy, setBusy] = React39.useState(false);
|
|
8575
|
+
const [turnStartedAt, setTurnStartedAt] = React39.useState(null);
|
|
8576
|
+
const listRef = React39.useRef([]);
|
|
8577
|
+
const queueRef = React39.useRef([]);
|
|
8578
|
+
const busyRef = React39.useRef(false);
|
|
8579
|
+
const stoppedRef = React39.useRef(false);
|
|
8580
|
+
const abortRef = React39.useRef(null);
|
|
8581
|
+
const serverCount = React39.useRef(0);
|
|
8582
|
+
const threadRef = React39.useRef(null);
|
|
8583
|
+
const mounted = React39.useRef(true);
|
|
8584
|
+
React39.useEffect(() => {
|
|
8567
8585
|
mounted.current = true;
|
|
8568
8586
|
return () => {
|
|
8569
8587
|
mounted.current = false;
|
|
@@ -8585,14 +8603,14 @@ function useChatEngine(opts) {
|
|
|
8585
8603
|
}
|
|
8586
8604
|
return false;
|
|
8587
8605
|
};
|
|
8588
|
-
const loadThread =
|
|
8606
|
+
const loadThread = React39.useCallback(async (id) => {
|
|
8589
8607
|
const data = await apiAdapter.getThread(id);
|
|
8590
8608
|
const list = [...data && data.messages || []];
|
|
8591
8609
|
serverCount.current = list.length;
|
|
8592
8610
|
commit(list);
|
|
8593
8611
|
return list;
|
|
8594
8612
|
}, [apiAdapter]);
|
|
8595
|
-
|
|
8613
|
+
React39.useEffect(() => {
|
|
8596
8614
|
if (!apiAdapter) {
|
|
8597
8615
|
setStatus("idle");
|
|
8598
8616
|
setFatal(null);
|
|
@@ -8805,7 +8823,7 @@ function useChatEngine(opts) {
|
|
|
8805
8823
|
await dispatchTurn(turn);
|
|
8806
8824
|
}
|
|
8807
8825
|
}
|
|
8808
|
-
const send =
|
|
8826
|
+
const send = React39.useCallback((text, attachments) => {
|
|
8809
8827
|
const body = (text || "").trim();
|
|
8810
8828
|
if (!body && !(attachments && attachments.length)) return;
|
|
8811
8829
|
if (status === "disconnected") return;
|
|
@@ -8815,7 +8833,7 @@ function useChatEngine(opts) {
|
|
|
8815
8833
|
stoppedRef.current = false;
|
|
8816
8834
|
drain();
|
|
8817
8835
|
}, [status]);
|
|
8818
|
-
const stop =
|
|
8836
|
+
const stop = React39.useCallback(() => {
|
|
8819
8837
|
stoppedRef.current = true;
|
|
8820
8838
|
const ac = abortRef.current;
|
|
8821
8839
|
if (ac) {
|
|
@@ -8834,11 +8852,11 @@ function useChatEngine(opts) {
|
|
|
8834
8852
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
8835
8853
|
}
|
|
8836
8854
|
}, [apiAdapter]);
|
|
8837
|
-
const removeQueued =
|
|
8855
|
+
const removeQueued = React39.useCallback((id) => {
|
|
8838
8856
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
8839
8857
|
setQueue(queueRef.current.slice());
|
|
8840
8858
|
}, []);
|
|
8841
|
-
const retry =
|
|
8859
|
+
const retry = React39.useCallback(() => {
|
|
8842
8860
|
const list = listRef.current;
|
|
8843
8861
|
let at = -1;
|
|
8844
8862
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -8854,19 +8872,19 @@ function useChatEngine(opts) {
|
|
|
8854
8872
|
setQueue(queueRef.current.slice());
|
|
8855
8873
|
drain();
|
|
8856
8874
|
}, []);
|
|
8857
|
-
const clear =
|
|
8875
|
+
const clear = React39.useCallback(() => {
|
|
8858
8876
|
commit([]);
|
|
8859
8877
|
serverCount.current = 0;
|
|
8860
8878
|
queueRef.current = [];
|
|
8861
8879
|
setQueue([]);
|
|
8862
8880
|
onClear && onClear();
|
|
8863
8881
|
}, [onClear]);
|
|
8864
|
-
const setFeedback =
|
|
8882
|
+
const setFeedback = React39.useCallback((id, value) => {
|
|
8865
8883
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
8866
8884
|
const msg = listRef.current.find((m) => m.id === id);
|
|
8867
8885
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
8868
8886
|
}, [onFeedback]);
|
|
8869
|
-
const reload =
|
|
8887
|
+
const reload = React39.useCallback(async () => {
|
|
8870
8888
|
if (!threadRef.current) return;
|
|
8871
8889
|
setStatus("loading");
|
|
8872
8890
|
try {
|
|
@@ -8904,11 +8922,11 @@ var ChatKit = {
|
|
|
8904
8922
|
};
|
|
8905
8923
|
|
|
8906
8924
|
// src/components/chat/ChatTranscript.tsx
|
|
8907
|
-
import * as
|
|
8925
|
+
import * as React41 from "react";
|
|
8908
8926
|
|
|
8909
8927
|
// src/components/chat/ChatTurn.tsx
|
|
8910
|
-
import * as
|
|
8911
|
-
import { jsx as
|
|
8928
|
+
import * as React40 from "react";
|
|
8929
|
+
import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
8912
8930
|
function JsonView({ value }) {
|
|
8913
8931
|
let text;
|
|
8914
8932
|
try {
|
|
@@ -8916,67 +8934,67 @@ function JsonView({ value }) {
|
|
|
8916
8934
|
} catch (e) {
|
|
8917
8935
|
text = String(value);
|
|
8918
8936
|
}
|
|
8919
|
-
return /* @__PURE__ */
|
|
8937
|
+
return /* @__PURE__ */ jsx72(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
8920
8938
|
}
|
|
8921
8939
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
8922
8940
|
if (!packet) return null;
|
|
8923
8941
|
const s = schema || {};
|
|
8924
8942
|
const invalid = packet.valid === false;
|
|
8925
8943
|
const title = s.heading || packet.type;
|
|
8926
|
-
return /* @__PURE__ */
|
|
8927
|
-
/* @__PURE__ */
|
|
8928
|
-
/* @__PURE__ */
|
|
8929
|
-
/* @__PURE__ */
|
|
8930
|
-
packet.repaired ? /* @__PURE__ */
|
|
8931
|
-
invalid ? /* @__PURE__ */
|
|
8944
|
+
return /* @__PURE__ */ jsxs67("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
|
|
8945
|
+
/* @__PURE__ */ jsxs67("header", { className: "fdc-packet-head", children: [
|
|
8946
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
|
|
8947
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-packet-title", children: title }),
|
|
8948
|
+
packet.repaired ? /* @__PURE__ */ jsx72("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
|
|
8949
|
+
invalid ? /* @__PURE__ */ jsx72("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
|
|
8932
8950
|
] }),
|
|
8933
|
-
invalid ? /* @__PURE__ */
|
|
8934
|
-
/* @__PURE__ */
|
|
8935
|
-
/* @__PURE__ */
|
|
8936
|
-
] }) : /* @__PURE__ */
|
|
8937
|
-
!invalid && onApply ? /* @__PURE__ */
|
|
8938
|
-
packet.repaired ? /* @__PURE__ */
|
|
8939
|
-
/* @__PURE__ */
|
|
8940
|
-
/* @__PURE__ */
|
|
8951
|
+
invalid ? /* @__PURE__ */ jsxs67("div", { className: "fdc-packet-alert", role: "alert", children: [
|
|
8952
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
8953
|
+
/* @__PURE__ */ jsx72("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
|
|
8954
|
+
] }) : /* @__PURE__ */ jsx72("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx72(JsonView, { value: packet.payload }) }),
|
|
8955
|
+
!invalid && onApply ? /* @__PURE__ */ jsxs67("footer", { className: "fdc-packet-foot", children: [
|
|
8956
|
+
packet.repaired ? /* @__PURE__ */ jsx72("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx72("span", {}),
|
|
8957
|
+
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
|
|
8958
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
|
|
8941
8959
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
8942
8960
|
] })
|
|
8943
8961
|
] }) : null
|
|
8944
8962
|
] });
|
|
8945
8963
|
}
|
|
8946
8964
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
8947
|
-
const [open, setOpen] =
|
|
8965
|
+
const [open, setOpen] = React40.useState(defaultOpen);
|
|
8948
8966
|
if (!text) return null;
|
|
8949
|
-
return /* @__PURE__ */
|
|
8950
|
-
/* @__PURE__ */
|
|
8951
|
-
/* @__PURE__ */
|
|
8952
|
-
/* @__PURE__ */
|
|
8953
|
-
streaming ? /* @__PURE__ */
|
|
8954
|
-
/* @__PURE__ */
|
|
8955
|
-
/* @__PURE__ */
|
|
8956
|
-
/* @__PURE__ */
|
|
8967
|
+
return /* @__PURE__ */ jsxs67("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
8968
|
+
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
8969
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-brain", "aria-hidden": "true" }),
|
|
8970
|
+
/* @__PURE__ */ jsx72("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
|
|
8971
|
+
streaming ? /* @__PURE__ */ jsxs67("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
8972
|
+
/* @__PURE__ */ jsx72("span", {}),
|
|
8973
|
+
/* @__PURE__ */ jsx72("span", {}),
|
|
8974
|
+
/* @__PURE__ */ jsx72("span", {})
|
|
8957
8975
|
] }) : null,
|
|
8958
|
-
/* @__PURE__ */
|
|
8976
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
8959
8977
|
] }),
|
|
8960
|
-
open ? /* @__PURE__ */
|
|
8978
|
+
open ? /* @__PURE__ */ jsx72("div", { className: "fdc-think-body", children: text }) : null
|
|
8961
8979
|
] });
|
|
8962
8980
|
}
|
|
8963
8981
|
function Citations({ items = [], onOpen }) {
|
|
8964
|
-
const [open, setOpen] =
|
|
8982
|
+
const [open, setOpen] = React40.useState(false);
|
|
8965
8983
|
if (!items.length) return null;
|
|
8966
|
-
return /* @__PURE__ */
|
|
8967
|
-
/* @__PURE__ */
|
|
8968
|
-
/* @__PURE__ */
|
|
8969
|
-
/* @__PURE__ */
|
|
8984
|
+
return /* @__PURE__ */ jsxs67("div", { className: "fdc-cites", children: [
|
|
8985
|
+
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
8986
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
|
|
8987
|
+
/* @__PURE__ */ jsxs67("span", { children: [
|
|
8970
8988
|
items.length,
|
|
8971
8989
|
" source",
|
|
8972
8990
|
items.length === 1 ? "" : "s"
|
|
8973
8991
|
] }),
|
|
8974
|
-
/* @__PURE__ */
|
|
8992
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
8975
8993
|
] }),
|
|
8976
|
-
open ? /* @__PURE__ */
|
|
8977
|
-
/* @__PURE__ */
|
|
8978
|
-
c.url ? /* @__PURE__ */
|
|
8979
|
-
c.detail ? /* @__PURE__ */
|
|
8994
|
+
open ? /* @__PURE__ */ jsx72("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs67("li", { children: [
|
|
8995
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
|
|
8996
|
+
c.url ? /* @__PURE__ */ jsx72("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx72("span", { children: c.title || "Source" }),
|
|
8997
|
+
c.detail ? /* @__PURE__ */ jsx72("span", { className: "fdc-cite-detail", children: c.detail }) : null
|
|
8980
8998
|
] }, c.id || i)) }) : null
|
|
8981
8999
|
] });
|
|
8982
9000
|
}
|
|
@@ -8987,29 +9005,29 @@ function clampText(text, max) {
|
|
|
8987
9005
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
8988
9006
|
}
|
|
8989
9007
|
function MessageBody({ message: m, ctx }) {
|
|
8990
|
-
const [expanded, setExpanded] =
|
|
9008
|
+
const [expanded, setExpanded] = React40.useState(false);
|
|
8991
9009
|
const isUser = m.role === "user";
|
|
8992
9010
|
const raw = m.text || "";
|
|
8993
9011
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
8994
9012
|
const body = clamped != null ? clamped : raw;
|
|
8995
9013
|
const showMd = ctx.markdown && !isUser;
|
|
8996
|
-
return /* @__PURE__ */
|
|
8997
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */
|
|
8998
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */
|
|
8999
|
-
body ? /* @__PURE__ */
|
|
9000
|
-
showMd ? /* @__PURE__ */
|
|
9001
|
-
m.streaming ? /* @__PURE__ */
|
|
9014
|
+
return /* @__PURE__ */ jsxs67("div", { className: "fdc-body", children: [
|
|
9015
|
+
m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx72(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
|
|
9016
|
+
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx72(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
|
|
9017
|
+
body ? /* @__PURE__ */ jsxs67("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
|
|
9018
|
+
showMd ? /* @__PURE__ */ jsx72(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx72("div", { className: "fdc-plain", children: body }),
|
|
9019
|
+
m.streaming ? /* @__PURE__ */ jsx72("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
|
|
9002
9020
|
] }) : null,
|
|
9003
|
-
clamped != null ? /* @__PURE__ */
|
|
9004
|
-
/* @__PURE__ */
|
|
9021
|
+
clamped != null ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
|
|
9022
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
|
|
9005
9023
|
"Show more",
|
|
9006
|
-
/* @__PURE__ */
|
|
9007
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */
|
|
9008
|
-
/* @__PURE__ */
|
|
9024
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
|
|
9025
|
+
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
|
|
9026
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
|
|
9009
9027
|
"Show less"
|
|
9010
9028
|
] }) : null,
|
|
9011
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */
|
|
9012
|
-
m.packet ? /* @__PURE__ */
|
|
9029
|
+
m.attachments && m.attachments.length ? /* @__PURE__ */ jsx72(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
|
|
9030
|
+
m.packet ? /* @__PURE__ */ jsx72(
|
|
9013
9031
|
PacketCard,
|
|
9014
9032
|
{
|
|
9015
9033
|
packet: m.packet,
|
|
@@ -9019,44 +9037,44 @@ function MessageBody({ message: m, ctx }) {
|
|
|
9019
9037
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
9020
9038
|
}
|
|
9021
9039
|
) : null,
|
|
9022
|
-
m.citations && m.citations.length ? /* @__PURE__ */
|
|
9023
|
-
m.working ? /* @__PURE__ */
|
|
9024
|
-
/* @__PURE__ */
|
|
9025
|
-
/* @__PURE__ */
|
|
9026
|
-
/* @__PURE__ */
|
|
9027
|
-
/* @__PURE__ */
|
|
9040
|
+
m.citations && m.citations.length ? /* @__PURE__ */ jsx72(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
|
|
9041
|
+
m.working ? /* @__PURE__ */ jsxs67("div", { className: "fdc-working", role: "status", children: [
|
|
9042
|
+
/* @__PURE__ */ jsxs67("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
9043
|
+
/* @__PURE__ */ jsx72("span", {}),
|
|
9044
|
+
/* @__PURE__ */ jsx72("span", {}),
|
|
9045
|
+
/* @__PURE__ */ jsx72("span", {})
|
|
9028
9046
|
] }),
|
|
9029
|
-
/* @__PURE__ */
|
|
9047
|
+
/* @__PURE__ */ jsxs67("span", { className: "fdc-working-label", children: [
|
|
9030
9048
|
m.resumed ? "Resuming" : "Working",
|
|
9031
|
-
m.job && m.job.status ? /* @__PURE__ */
|
|
9049
|
+
m.job && m.job.status ? /* @__PURE__ */ jsxs67("span", { className: "fdc-working-job", children: [
|
|
9032
9050
|
" \xB7 ",
|
|
9033
9051
|
m.job.status
|
|
9034
9052
|
] }) : null,
|
|
9035
|
-
m.job && m.job.detail ? /* @__PURE__ */
|
|
9053
|
+
m.job && m.job.detail ? /* @__PURE__ */ jsxs67("span", { className: "fdc-working-job", children: [
|
|
9036
9054
|
" \xB7 ",
|
|
9037
9055
|
m.job.detail
|
|
9038
9056
|
] }) : null
|
|
9039
9057
|
] }),
|
|
9040
|
-
m.jobId ? /* @__PURE__ */
|
|
9058
|
+
m.jobId ? /* @__PURE__ */ jsx72("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
9041
9059
|
] }) : null,
|
|
9042
|
-
m.stopped ? /* @__PURE__ */
|
|
9043
|
-
/* @__PURE__ */
|
|
9060
|
+
m.stopped ? /* @__PURE__ */ jsxs67("div", { className: "fdc-stopped", children: [
|
|
9061
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
9044
9062
|
"Stopped"
|
|
9045
9063
|
] }) : null,
|
|
9046
|
-
m.error ? /* @__PURE__ */
|
|
9047
|
-
/* @__PURE__ */
|
|
9048
|
-
/* @__PURE__ */
|
|
9049
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */
|
|
9050
|
-
/* @__PURE__ */
|
|
9064
|
+
m.error ? /* @__PURE__ */ jsxs67("div", { className: "fdc-error", role: "alert", children: [
|
|
9065
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
9066
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
|
|
9067
|
+
m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
|
|
9068
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
9051
9069
|
"Retry"
|
|
9052
9070
|
] }) : null
|
|
9053
9071
|
] }) : null
|
|
9054
9072
|
] });
|
|
9055
9073
|
}
|
|
9056
9074
|
function useCopyRun() {
|
|
9057
|
-
const [done, setDone] =
|
|
9058
|
-
const t =
|
|
9059
|
-
|
|
9075
|
+
const [done, setDone] = React40.useState(false);
|
|
9076
|
+
const t = React40.useRef(null);
|
|
9077
|
+
React40.useEffect(() => () => {
|
|
9060
9078
|
if (t.current) clearTimeout(t.current);
|
|
9061
9079
|
}, []);
|
|
9062
9080
|
return [done, (text) => {
|
|
@@ -9076,16 +9094,16 @@ function RunActions({ group, ctx }) {
|
|
|
9076
9094
|
const isAssistant = group.role === "assistant";
|
|
9077
9095
|
const fb = last.feedback;
|
|
9078
9096
|
if (!ctx.messageActions) return null;
|
|
9079
|
-
return /* @__PURE__ */
|
|
9080
|
-
/* @__PURE__ */
|
|
9081
|
-
/* @__PURE__ */
|
|
9082
|
-
/* @__PURE__ */
|
|
9097
|
+
return /* @__PURE__ */ jsxs67("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
|
|
9098
|
+
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
|
|
9099
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
|
|
9100
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
|
|
9083
9101
|
] }),
|
|
9084
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */
|
|
9085
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */
|
|
9086
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */
|
|
9087
|
-
/* @__PURE__ */
|
|
9088
|
-
/* @__PURE__ */
|
|
9102
|
+
isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
9103
|
+
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
9104
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs67(React40.Fragment, { children: [
|
|
9105
|
+
/* @__PURE__ */ jsx72("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__ */ jsx72("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
9106
|
+
/* @__PURE__ */ jsx72("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__ */ jsx72("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
9089
9107
|
] }) : null,
|
|
9090
9108
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
9091
9109
|
] });
|
|
@@ -9095,22 +9113,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
9095
9113
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
9096
9114
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
9097
9115
|
const stamp = group.messages[0].timestamp;
|
|
9098
|
-
return /* @__PURE__ */
|
|
9099
|
-
/* @__PURE__ */
|
|
9100
|
-
ctx.showAvatars ? /* @__PURE__ */
|
|
9101
|
-
/* @__PURE__ */
|
|
9102
|
-
stamp ? /* @__PURE__ */
|
|
9103
|
-
group.messages.some((m) => m.model) ? /* @__PURE__ */
|
|
9116
|
+
return /* @__PURE__ */ jsxs67("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
|
|
9117
|
+
/* @__PURE__ */ jsxs67("div", { className: "fdc-turn-head", children: [
|
|
9118
|
+
ctx.showAvatars ? /* @__PURE__ */ jsx72("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx72("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx72("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx72("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
|
|
9119
|
+
/* @__PURE__ */ jsx72("span", { className: "fdc-who", children: name }),
|
|
9120
|
+
stamp ? /* @__PURE__ */ jsx72(RelativeTime, { className: "fdc-when", value: stamp }) : null,
|
|
9121
|
+
group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx72("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
|
|
9104
9122
|
] }),
|
|
9105
|
-
/* @__PURE__ */
|
|
9106
|
-
group.messages.map((m) => /* @__PURE__ */
|
|
9107
|
-
/* @__PURE__ */
|
|
9123
|
+
/* @__PURE__ */ jsxs67("div", { className: "fdc-turn-body", children: [
|
|
9124
|
+
group.messages.map((m) => /* @__PURE__ */ jsx72("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx72(MessageBody, { message: m, ctx }) }, m.id)),
|
|
9125
|
+
/* @__PURE__ */ jsx72(RunActions, { group, ctx })
|
|
9108
9126
|
] })
|
|
9109
9127
|
] });
|
|
9110
9128
|
}
|
|
9111
9129
|
|
|
9112
9130
|
// src/components/chat/ChatTranscript.tsx
|
|
9113
|
-
import { jsx as
|
|
9131
|
+
import { jsx as jsx73, jsxs as jsxs68 } from "react/jsx-runtime";
|
|
9114
9132
|
var GROUP_WINDOW = 6e4;
|
|
9115
9133
|
var STICK_PX = 100;
|
|
9116
9134
|
function groupMessages(list) {
|
|
@@ -9143,25 +9161,25 @@ function dayLabel(key) {
|
|
|
9143
9161
|
}
|
|
9144
9162
|
function Suggestions({ items = [], onPick }) {
|
|
9145
9163
|
if (!items.length) return null;
|
|
9146
|
-
return /* @__PURE__ */
|
|
9164
|
+
return /* @__PURE__ */ jsx73("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
9147
9165
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
9148
|
-
return /* @__PURE__ */
|
|
9149
|
-
it.icon ? /* @__PURE__ */
|
|
9150
|
-
/* @__PURE__ */
|
|
9151
|
-
/* @__PURE__ */
|
|
9152
|
-
it.description ? /* @__PURE__ */
|
|
9166
|
+
return /* @__PURE__ */ jsxs68("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
|
|
9167
|
+
it.icon ? /* @__PURE__ */ jsx73("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
|
|
9168
|
+
/* @__PURE__ */ jsxs68("span", { className: "fdc-suggest-text", children: [
|
|
9169
|
+
/* @__PURE__ */ jsx73("span", { className: "fdc-suggest-label", children: it.label }),
|
|
9170
|
+
it.description ? /* @__PURE__ */ jsx73("span", { className: "fdc-suggest-desc", children: it.description }) : null
|
|
9153
9171
|
] }),
|
|
9154
|
-
/* @__PURE__ */
|
|
9172
|
+
/* @__PURE__ */ jsx73("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
9155
9173
|
] }, it.id || i);
|
|
9156
9174
|
}) });
|
|
9157
9175
|
}
|
|
9158
9176
|
function LoadingTurns() {
|
|
9159
|
-
return /* @__PURE__ */
|
|
9160
|
-
/* @__PURE__ */
|
|
9161
|
-
/* @__PURE__ */
|
|
9162
|
-
/* @__PURE__ */
|
|
9163
|
-
/* @__PURE__ */
|
|
9164
|
-
/* @__PURE__ */
|
|
9177
|
+
return /* @__PURE__ */ jsx73("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs68("div", { className: "fdc-skel-turn", children: [
|
|
9178
|
+
/* @__PURE__ */ jsx73("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
|
|
9179
|
+
/* @__PURE__ */ jsxs68("div", { className: "fdc-skel-lines", children: [
|
|
9180
|
+
/* @__PURE__ */ jsx73("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
|
|
9181
|
+
/* @__PURE__ */ jsx73("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
|
|
9182
|
+
/* @__PURE__ */ jsx73("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
|
|
9165
9183
|
] })
|
|
9166
9184
|
] }, i)) });
|
|
9167
9185
|
}
|
|
@@ -9178,10 +9196,10 @@ function ChatTranscript({
|
|
|
9178
9196
|
renderEmpty,
|
|
9179
9197
|
className = ""
|
|
9180
9198
|
}) {
|
|
9181
|
-
const scroller =
|
|
9182
|
-
const stick =
|
|
9183
|
-
const [pill, setPill] =
|
|
9184
|
-
const seen =
|
|
9199
|
+
const scroller = React41.useRef(null);
|
|
9200
|
+
const stick = React41.useRef(true);
|
|
9201
|
+
const [pill, setPill] = React41.useState(0);
|
|
9202
|
+
const seen = React41.useRef(0);
|
|
9185
9203
|
const toBottom = (smooth) => {
|
|
9186
9204
|
const el = scroller.current;
|
|
9187
9205
|
if (!el) return;
|
|
@@ -9200,7 +9218,7 @@ function ChatTranscript({
|
|
|
9200
9218
|
seen.current = messages.length;
|
|
9201
9219
|
}
|
|
9202
9220
|
};
|
|
9203
|
-
|
|
9221
|
+
React41.useLayoutEffect(() => {
|
|
9204
9222
|
const el = scroller.current;
|
|
9205
9223
|
if (!el) return;
|
|
9206
9224
|
if (stick.current) {
|
|
@@ -9208,7 +9226,7 @@ function ChatTranscript({
|
|
|
9208
9226
|
seen.current = messages.length;
|
|
9209
9227
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
9210
9228
|
}, [messages]);
|
|
9211
|
-
|
|
9229
|
+
React41.useEffect(() => {
|
|
9212
9230
|
const el = scroller.current;
|
|
9213
9231
|
const inner = el && el.firstChild;
|
|
9214
9232
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -9218,38 +9236,38 @@ function ChatTranscript({
|
|
|
9218
9236
|
ro.observe(inner);
|
|
9219
9237
|
return () => ro.disconnect();
|
|
9220
9238
|
}, []);
|
|
9221
|
-
const groups =
|
|
9239
|
+
const groups = React41.useMemo(() => groupMessages(messages), [messages]);
|
|
9222
9240
|
const empty = !messages.length && status === "ready";
|
|
9223
|
-
return /* @__PURE__ */
|
|
9224
|
-
/* @__PURE__ */
|
|
9225
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */
|
|
9226
|
-
status === "disconnected" ? /* @__PURE__ */
|
|
9227
|
-
/* @__PURE__ */
|
|
9228
|
-
/* @__PURE__ */
|
|
9229
|
-
/* @__PURE__ */
|
|
9230
|
-
ctx.onReconnect ? /* @__PURE__ */
|
|
9231
|
-
/* @__PURE__ */
|
|
9241
|
+
return /* @__PURE__ */ jsxs68("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
9242
|
+
/* @__PURE__ */ jsxs68("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
9243
|
+
status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx73(LoadingTurns, {}) : null,
|
|
9244
|
+
status === "disconnected" ? /* @__PURE__ */ jsxs68("div", { className: "fdc-dead", children: [
|
|
9245
|
+
/* @__PURE__ */ jsx73("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx73("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
|
|
9246
|
+
/* @__PURE__ */ jsx73("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
|
|
9247
|
+
/* @__PURE__ */ jsx73("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." }),
|
|
9248
|
+
ctx.onReconnect ? /* @__PURE__ */ jsxs68("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
|
|
9249
|
+
/* @__PURE__ */ jsx73("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
9232
9250
|
"Try again"
|
|
9233
9251
|
] }) : null
|
|
9234
9252
|
] }) : null,
|
|
9235
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
9236
|
-
/* @__PURE__ */
|
|
9237
|
-
/* @__PURE__ */
|
|
9238
|
-
emptyDescription ? /* @__PURE__ */
|
|
9239
|
-
/* @__PURE__ */
|
|
9253
|
+
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs68("div", { className: "fdc-empty", children: [
|
|
9254
|
+
/* @__PURE__ */ jsx73("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx73("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
|
|
9255
|
+
/* @__PURE__ */ jsx73("h3", { className: "fdc-empty-title", children: emptyTitle }),
|
|
9256
|
+
emptyDescription ? /* @__PURE__ */ jsx73("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
|
|
9257
|
+
/* @__PURE__ */ jsx73(Suggestions, { items: suggestions, onPick })
|
|
9240
9258
|
] }) : null,
|
|
9241
9259
|
groups.map((g, i) => {
|
|
9242
9260
|
const prev = groups[i - 1];
|
|
9243
9261
|
const k = dayKey(g.messages[0].timestamp);
|
|
9244
9262
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
9245
|
-
return /* @__PURE__ */
|
|
9246
|
-
showDay ? /* @__PURE__ */
|
|
9247
|
-
/* @__PURE__ */
|
|
9263
|
+
return /* @__PURE__ */ jsxs68(React41.Fragment, { children: [
|
|
9264
|
+
showDay ? /* @__PURE__ */ jsx73("div", { className: "fdc-day", children: /* @__PURE__ */ jsx73("span", { children: dayLabel(k) }) }) : null,
|
|
9265
|
+
/* @__PURE__ */ jsx73(ChatTurn, { group: g, ctx })
|
|
9248
9266
|
] }, g.key || i);
|
|
9249
9267
|
})
|
|
9250
9268
|
] }),
|
|
9251
|
-
pill ? /* @__PURE__ */
|
|
9252
|
-
/* @__PURE__ */
|
|
9269
|
+
pill ? /* @__PURE__ */ jsxs68("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
|
|
9270
|
+
/* @__PURE__ */ jsx73("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
|
|
9253
9271
|
pill,
|
|
9254
9272
|
" new message",
|
|
9255
9273
|
pill === 1 ? "" : "s"
|
|
@@ -9259,8 +9277,8 @@ function ChatTranscript({
|
|
|
9259
9277
|
var TranscriptKit = { groupMessages };
|
|
9260
9278
|
|
|
9261
9279
|
// src/components/chat/ChatComposer.tsx
|
|
9262
|
-
import * as
|
|
9263
|
-
import { jsx as
|
|
9280
|
+
import * as React42 from "react";
|
|
9281
|
+
import { jsx as jsx74, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
9264
9282
|
function ChatComposer({
|
|
9265
9283
|
onSubmit,
|
|
9266
9284
|
onStop,
|
|
@@ -9287,17 +9305,17 @@ function ChatComposer({
|
|
|
9287
9305
|
onReject,
|
|
9288
9306
|
onOpenAttachment
|
|
9289
9307
|
}) {
|
|
9290
|
-
const [text, setText] =
|
|
9291
|
-
const [trigger, setTrigger] =
|
|
9292
|
-
const [mentionItems, setMentionItems] =
|
|
9293
|
-
const [listening, setListening] =
|
|
9294
|
-
const [notice, setNotice] =
|
|
9295
|
-
const editor =
|
|
9296
|
-
const wrap =
|
|
9297
|
-
const stopVoice =
|
|
9308
|
+
const [text, setText] = React42.useState(draft || "");
|
|
9309
|
+
const [trigger, setTrigger] = React42.useState(null);
|
|
9310
|
+
const [mentionItems, setMentionItems] = React42.useState([]);
|
|
9311
|
+
const [listening, setListening] = React42.useState(false);
|
|
9312
|
+
const [notice, setNotice] = React42.useState(null);
|
|
9313
|
+
const editor = React42.useRef(null);
|
|
9314
|
+
const wrap = React42.useRef(null);
|
|
9315
|
+
const stopVoice = React42.useRef(null);
|
|
9298
9316
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
9299
9317
|
} });
|
|
9300
|
-
|
|
9318
|
+
React42.useEffect(() => {
|
|
9301
9319
|
if (draft != null && draft !== text) setText(draft);
|
|
9302
9320
|
}, [draft]);
|
|
9303
9321
|
const change = (v) => {
|
|
@@ -9331,7 +9349,7 @@ function ChatComposer({
|
|
|
9331
9349
|
e.preventDefault();
|
|
9332
9350
|
staged.add(found.files);
|
|
9333
9351
|
};
|
|
9334
|
-
|
|
9352
|
+
React42.useEffect(() => {
|
|
9335
9353
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
9336
9354
|
setMentionItems([]);
|
|
9337
9355
|
return;
|
|
@@ -9349,7 +9367,7 @@ function ChatComposer({
|
|
|
9349
9367
|
const q = (trigger.query || "").toLowerCase();
|
|
9350
9368
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
9351
9369
|
}, [trigger, mentionSources]);
|
|
9352
|
-
const slashItems =
|
|
9370
|
+
const slashItems = React42.useMemo(() => {
|
|
9353
9371
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
9354
9372
|
const q = (trigger.query || "").toLowerCase();
|
|
9355
9373
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -9363,7 +9381,7 @@ function ChatComposer({
|
|
|
9363
9381
|
description: it.description,
|
|
9364
9382
|
icon: it.icon,
|
|
9365
9383
|
meta: mention.meta,
|
|
9366
|
-
shortcut: slash.shortcut ? /* @__PURE__ */
|
|
9384
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ jsx74(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
9367
9385
|
onSelect: () => {
|
|
9368
9386
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
9369
9387
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -9426,14 +9444,14 @@ function ChatComposer({
|
|
|
9426
9444
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
9427
9445
|
};
|
|
9428
9446
|
};
|
|
9429
|
-
return /* @__PURE__ */
|
|
9430
|
-
queue.length ? /* @__PURE__ */
|
|
9431
|
-
/* @__PURE__ */
|
|
9432
|
-
/* @__PURE__ */
|
|
9433
|
-
onRemoveQueued ? /* @__PURE__ */
|
|
9447
|
+
return /* @__PURE__ */ jsxs69("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
|
|
9448
|
+
queue.length ? /* @__PURE__ */ jsx74("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs69("div", { className: "fdc-queue-row", children: [
|
|
9449
|
+
/* @__PURE__ */ jsx74("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
|
|
9450
|
+
/* @__PURE__ */ jsx74("span", { className: "fdc-queue-text", children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
|
|
9451
|
+
onRemoveQueued ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
9434
9452
|
] }, q.id)) }) : null,
|
|
9435
9453
|
sessionBar,
|
|
9436
|
-
/* @__PURE__ */
|
|
9454
|
+
/* @__PURE__ */ jsx74(
|
|
9437
9455
|
Dropzone,
|
|
9438
9456
|
{
|
|
9439
9457
|
className: "fdc-field",
|
|
@@ -9447,9 +9465,9 @@ function ChatComposer({
|
|
|
9447
9465
|
disabled: !fileUploadHandler || disabled,
|
|
9448
9466
|
label: "Drop to attach",
|
|
9449
9467
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
9450
|
-
children: /* @__PURE__ */
|
|
9451
|
-
staged.items.length ? /* @__PURE__ */
|
|
9452
|
-
/* @__PURE__ */
|
|
9468
|
+
children: /* @__PURE__ */ jsxs69("div", { ref: wrap, className: "fdc-field-inner", children: [
|
|
9469
|
+
staged.items.length ? /* @__PURE__ */ jsx74("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx74(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
|
|
9470
|
+
/* @__PURE__ */ jsx74(
|
|
9453
9471
|
MarkdownEditor,
|
|
9454
9472
|
{
|
|
9455
9473
|
ref: editor,
|
|
@@ -9468,33 +9486,33 @@ function ChatComposer({
|
|
|
9468
9486
|
ariaLabel: "Message"
|
|
9469
9487
|
}
|
|
9470
9488
|
),
|
|
9471
|
-
/* @__PURE__ */
|
|
9472
|
-
fileUploadHandler ? /* @__PURE__ */
|
|
9473
|
-
voiceHandler ? /* @__PURE__ */
|
|
9489
|
+
/* @__PURE__ */ jsxs69("div", { className: "fdc-tools", children: [
|
|
9490
|
+
fileUploadHandler ? /* @__PURE__ */ jsx74(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
|
|
9491
|
+
voiceHandler ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
|
|
9474
9492
|
toolbarExtras,
|
|
9475
|
-
/* @__PURE__ */
|
|
9476
|
-
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */
|
|
9493
|
+
/* @__PURE__ */ jsx74("span", { className: "fdc-tools-gap" }),
|
|
9494
|
+
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs69("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
|
|
9477
9495
|
text.length,
|
|
9478
9496
|
"/",
|
|
9479
9497
|
maxLength
|
|
9480
9498
|
] }) : null,
|
|
9481
|
-
busy ? /* @__PURE__ */
|
|
9482
|
-
/* @__PURE__ */
|
|
9483
|
-
/* @__PURE__ */
|
|
9484
|
-
] }) : /* @__PURE__ */
|
|
9485
|
-
/* @__PURE__ */
|
|
9486
|
-
/* @__PURE__ */
|
|
9499
|
+
busy ? /* @__PURE__ */ jsxs69("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
|
|
9500
|
+
/* @__PURE__ */ jsx74("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
9501
|
+
/* @__PURE__ */ jsx74("span", { children: "Stop" })
|
|
9502
|
+
] }) : /* @__PURE__ */ jsxs69("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
|
|
9503
|
+
/* @__PURE__ */ jsx74("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
|
|
9504
|
+
/* @__PURE__ */ jsx74("span", { className: "fdc-send-label", children: "Send" })
|
|
9487
9505
|
] })
|
|
9488
9506
|
] })
|
|
9489
9507
|
] })
|
|
9490
9508
|
}
|
|
9491
9509
|
),
|
|
9492
|
-
notice ? /* @__PURE__ */
|
|
9493
|
-
/* @__PURE__ */
|
|
9510
|
+
notice ? /* @__PURE__ */ jsxs69("div", { className: "fdc-notice", role: "status", children: [
|
|
9511
|
+
/* @__PURE__ */ jsx74("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
9494
9512
|
notice
|
|
9495
9513
|
] }) : null,
|
|
9496
|
-
hint && !notice ? /* @__PURE__ */
|
|
9497
|
-
/* @__PURE__ */
|
|
9514
|
+
hint && !notice ? /* @__PURE__ */ jsx74("div", { className: "fdc-hint", children: hint }) : null,
|
|
9515
|
+
/* @__PURE__ */ jsx74(
|
|
9498
9516
|
Popover,
|
|
9499
9517
|
{
|
|
9500
9518
|
open: menuOpen,
|
|
@@ -9508,12 +9526,12 @@ function ChatComposer({
|
|
|
9508
9526
|
returnFocus: false,
|
|
9509
9527
|
closeOnOutside: true,
|
|
9510
9528
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
9511
|
-
children: /* @__PURE__ */
|
|
9529
|
+
children: /* @__PURE__ */ jsx74(
|
|
9512
9530
|
Menu,
|
|
9513
9531
|
{
|
|
9514
9532
|
items: menuItems,
|
|
9515
9533
|
autoFocus: false,
|
|
9516
|
-
header: /* @__PURE__ */
|
|
9534
|
+
header: /* @__PURE__ */ jsx74("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
9517
9535
|
onClose: () => setTrigger(null)
|
|
9518
9536
|
}
|
|
9519
9537
|
)
|
|
@@ -9523,12 +9541,12 @@ function ChatComposer({
|
|
|
9523
9541
|
}
|
|
9524
9542
|
|
|
9525
9543
|
// src/components/chat/ChatSessionBar.tsx
|
|
9526
|
-
import * as
|
|
9527
|
-
import { jsx as
|
|
9544
|
+
import * as React43 from "react";
|
|
9545
|
+
import { jsx as jsx75, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
9528
9546
|
var compact2 = meterFormats.compact;
|
|
9529
9547
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
9530
|
-
const [open, setOpen] =
|
|
9531
|
-
const anchor =
|
|
9548
|
+
const [open, setOpen] = React43.useState(false);
|
|
9549
|
+
const anchor = React43.useRef(null);
|
|
9532
9550
|
const stats = sessionStats || null;
|
|
9533
9551
|
const cu = contextUsage || null;
|
|
9534
9552
|
const limits = usageLimits || null;
|
|
@@ -9543,9 +9561,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9543
9561
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
9544
9562
|
if (cu) bits.push(pct + "% context");
|
|
9545
9563
|
const expandable = !!(cu || limits);
|
|
9546
|
-
return /* @__PURE__ */
|
|
9547
|
-
/* @__PURE__ */
|
|
9548
|
-
/* @__PURE__ */
|
|
9564
|
+
return /* @__PURE__ */ jsxs70(React43.Fragment, { children: [
|
|
9565
|
+
/* @__PURE__ */ jsxs70("div", { className: "fdc-bar", children: [
|
|
9566
|
+
/* @__PURE__ */ jsxs70(
|
|
9549
9567
|
"button",
|
|
9550
9568
|
{
|
|
9551
9569
|
type: "button",
|
|
@@ -9556,16 +9574,16 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9556
9574
|
"aria-expanded": expandable ? open : void 0,
|
|
9557
9575
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
9558
9576
|
children: [
|
|
9559
|
-
cu ? /* @__PURE__ */
|
|
9560
|
-
/* @__PURE__ */
|
|
9561
|
-
expandable ? /* @__PURE__ */
|
|
9577
|
+
cu ? /* @__PURE__ */ jsx75("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx75(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
|
|
9578
|
+
/* @__PURE__ */ jsx75("span", { className: "fdc-bar-text", children: bits.join(" \xB7 ") }),
|
|
9579
|
+
expandable ? /* @__PURE__ */ jsx75("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
|
|
9562
9580
|
]
|
|
9563
9581
|
}
|
|
9564
9582
|
),
|
|
9565
9583
|
extras
|
|
9566
9584
|
] }),
|
|
9567
|
-
/* @__PURE__ */
|
|
9568
|
-
cu ? /* @__PURE__ */
|
|
9585
|
+
/* @__PURE__ */ jsx75(Popover, { open, anchorRef: anchor, placement: "top-start", onClose: () => setOpen(false), minWidth: 330, maxHeight: 460, padded: true, label: "Usage", children: /* @__PURE__ */ jsxs70("div", { className: "fdc-usage", children: [
|
|
9586
|
+
cu ? /* @__PURE__ */ jsx75("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx75(
|
|
9569
9587
|
SegmentedMeter,
|
|
9570
9588
|
{
|
|
9571
9589
|
total,
|
|
@@ -9577,9 +9595,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9577
9595
|
remainderLabel: "Free"
|
|
9578
9596
|
}
|
|
9579
9597
|
) }) : null,
|
|
9580
|
-
limits && limits.length ? /* @__PURE__ */
|
|
9581
|
-
/* @__PURE__ */
|
|
9582
|
-
/* @__PURE__ */
|
|
9598
|
+
limits && limits.length ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec", children: [
|
|
9599
|
+
/* @__PURE__ */ jsx75("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
9600
|
+
/* @__PURE__ */ jsx75("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx75(
|
|
9583
9601
|
QuotaRow,
|
|
9584
9602
|
{
|
|
9585
9603
|
label: l.label,
|
|
@@ -9589,32 +9607,32 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9589
9607
|
l.id
|
|
9590
9608
|
)) })
|
|
9591
9609
|
] }) : null,
|
|
9592
|
-
stats ? /* @__PURE__ */
|
|
9593
|
-
stats.elapsedMs ? /* @__PURE__ */
|
|
9594
|
-
/* @__PURE__ */
|
|
9595
|
-
/* @__PURE__ */
|
|
9610
|
+
stats ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
9611
|
+
stats.elapsedMs ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9612
|
+
/* @__PURE__ */ jsx75("span", { children: "Session" }),
|
|
9613
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
9596
9614
|
] }) : null,
|
|
9597
|
-
stats.tokens ? /* @__PURE__ */
|
|
9598
|
-
/* @__PURE__ */
|
|
9599
|
-
/* @__PURE__ */
|
|
9615
|
+
stats.tokens ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9616
|
+
/* @__PURE__ */ jsx75("span", { children: "Tokens" }),
|
|
9617
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
9600
9618
|
] }) : null,
|
|
9601
|
-
stats.costUsd != null ? /* @__PURE__ */
|
|
9602
|
-
/* @__PURE__ */
|
|
9603
|
-
/* @__PURE__ */
|
|
9619
|
+
stats.costUsd != null ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9620
|
+
/* @__PURE__ */ jsx75("span", { children: "Cost" }),
|
|
9621
|
+
/* @__PURE__ */ jsxs70("b", { className: "fd-tabular", children: [
|
|
9604
9622
|
"$",
|
|
9605
9623
|
Number(stats.costUsd).toFixed(3)
|
|
9606
9624
|
] })
|
|
9607
9625
|
] }) : null,
|
|
9608
|
-
stats.turns ? /* @__PURE__ */
|
|
9609
|
-
/* @__PURE__ */
|
|
9610
|
-
/* @__PURE__ */
|
|
9626
|
+
stats.turns ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9627
|
+
/* @__PURE__ */ jsx75("span", { children: "Turns" }),
|
|
9628
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.turns })
|
|
9611
9629
|
] }) : null
|
|
9612
9630
|
] }) : null,
|
|
9613
|
-
onClear ? /* @__PURE__ */
|
|
9631
|
+
onClear ? /* @__PURE__ */ jsx75("footer", { className: "fdc-usage-foot", children: /* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
9614
9632
|
setOpen(false);
|
|
9615
9633
|
onClear();
|
|
9616
9634
|
}, children: [
|
|
9617
|
-
/* @__PURE__ */
|
|
9635
|
+
/* @__PURE__ */ jsx75("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
9618
9636
|
"Clear conversation"
|
|
9619
9637
|
] }) }) : null
|
|
9620
9638
|
] }) })
|
|
@@ -9651,7 +9669,7 @@ function ModelControls({
|
|
|
9651
9669
|
disabled: m.disabled,
|
|
9652
9670
|
checked: m.id === (current2 && current2.id),
|
|
9653
9671
|
meta: m.meta,
|
|
9654
|
-
shortcut: m.shortcut ? /* @__PURE__ */
|
|
9672
|
+
shortcut: m.shortcut ? /* @__PURE__ */ jsx75(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
9655
9673
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
9656
9674
|
});
|
|
9657
9675
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -9664,15 +9682,15 @@ function ModelControls({
|
|
|
9664
9682
|
items.push({ kind: "section", label: "Fast mode" });
|
|
9665
9683
|
items.push({
|
|
9666
9684
|
kind: "custom",
|
|
9667
|
-
render: () => /* @__PURE__ */
|
|
9668
|
-
/* @__PURE__ */
|
|
9669
|
-
/* @__PURE__ */
|
|
9670
|
-
/* @__PURE__ */
|
|
9685
|
+
render: () => /* @__PURE__ */ jsxs70("label", { className: "fdc-switchrow", children: [
|
|
9686
|
+
/* @__PURE__ */ jsx75("span", { children: fastModeLabel }),
|
|
9687
|
+
/* @__PURE__ */ jsx75("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
|
|
9688
|
+
/* @__PURE__ */ jsx75("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx75("span", { className: "fd-switch-thumb" }) })
|
|
9671
9689
|
] })
|
|
9672
9690
|
});
|
|
9673
9691
|
}
|
|
9674
|
-
return /* @__PURE__ */
|
|
9675
|
-
/* @__PURE__ */
|
|
9692
|
+
return /* @__PURE__ */ jsxs70(React43.Fragment, { children: [
|
|
9693
|
+
/* @__PURE__ */ jsx75(
|
|
9676
9694
|
MenuButton,
|
|
9677
9695
|
{
|
|
9678
9696
|
items,
|
|
@@ -9683,7 +9701,7 @@ function ModelControls({
|
|
|
9683
9701
|
title: "Choose a model"
|
|
9684
9702
|
}
|
|
9685
9703
|
),
|
|
9686
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */
|
|
9704
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ jsx75(
|
|
9687
9705
|
MenuButton,
|
|
9688
9706
|
{
|
|
9689
9707
|
placement: "top-end",
|
|
@@ -9704,7 +9722,7 @@ function ModelControls({
|
|
|
9704
9722
|
}
|
|
9705
9723
|
|
|
9706
9724
|
// src/components/chat/AgentChatPanel.tsx
|
|
9707
|
-
import { jsx as
|
|
9725
|
+
import { jsx as jsx76, jsxs as jsxs71 } from "react/jsx-runtime";
|
|
9708
9726
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
9709
9727
|
function AgentChatPanel({
|
|
9710
9728
|
/* required */
|
|
@@ -9788,11 +9806,11 @@ function AgentChatPanel({
|
|
|
9788
9806
|
onFeedback,
|
|
9789
9807
|
onEditMessage
|
|
9790
9808
|
}) {
|
|
9791
|
-
const [panelWidth, setPanelWidth] =
|
|
9792
|
-
const [applied, setApplied] =
|
|
9793
|
-
const [draft, setDraft] =
|
|
9794
|
-
const dragging =
|
|
9795
|
-
|
|
9809
|
+
const [panelWidth, setPanelWidth] = React44.useState(width);
|
|
9810
|
+
const [applied, setApplied] = React44.useState({});
|
|
9811
|
+
const [draft, setDraft] = React44.useState("");
|
|
9812
|
+
const dragging = React44.useRef(null);
|
|
9813
|
+
React44.useEffect(() => setPanelWidth(width), [width]);
|
|
9796
9814
|
const engine = useChatEngine({
|
|
9797
9815
|
contextType,
|
|
9798
9816
|
contextId,
|
|
@@ -9858,7 +9876,7 @@ function AgentChatPanel({
|
|
|
9858
9876
|
onReconnect: engine.reload,
|
|
9859
9877
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
9860
9878
|
};
|
|
9861
|
-
const sessionBar = /* @__PURE__ */
|
|
9879
|
+
const sessionBar = /* @__PURE__ */ jsx76(
|
|
9862
9880
|
ChatSessionBar,
|
|
9863
9881
|
{
|
|
9864
9882
|
sessionStats,
|
|
@@ -9867,7 +9885,7 @@ function AgentChatPanel({
|
|
|
9867
9885
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
9868
9886
|
}
|
|
9869
9887
|
);
|
|
9870
|
-
const modelControls = /* @__PURE__ */
|
|
9888
|
+
const modelControls = /* @__PURE__ */ jsx76(
|
|
9871
9889
|
ModelControls,
|
|
9872
9890
|
{
|
|
9873
9891
|
models,
|
|
@@ -9882,7 +9900,7 @@ function AgentChatPanel({
|
|
|
9882
9900
|
narrow
|
|
9883
9901
|
}
|
|
9884
9902
|
);
|
|
9885
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */
|
|
9903
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx76(
|
|
9886
9904
|
MenuButton,
|
|
9887
9905
|
{
|
|
9888
9906
|
variant: "ghost",
|
|
@@ -9909,7 +9927,7 @@ function AgentChatPanel({
|
|
|
9909
9927
|
})))
|
|
9910
9928
|
}
|
|
9911
9929
|
) : null;
|
|
9912
|
-
return /* @__PURE__ */
|
|
9930
|
+
return /* @__PURE__ */ jsxs71(
|
|
9913
9931
|
"aside",
|
|
9914
9932
|
{
|
|
9915
9933
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -9920,7 +9938,7 @@ function AgentChatPanel({
|
|
|
9920
9938
|
},
|
|
9921
9939
|
"aria-label": title,
|
|
9922
9940
|
children: [
|
|
9923
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */
|
|
9941
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ jsx76(
|
|
9924
9942
|
"div",
|
|
9925
9943
|
{
|
|
9926
9944
|
className: "fdc-grip",
|
|
@@ -9935,20 +9953,20 @@ function AgentChatPanel({
|
|
|
9935
9953
|
}
|
|
9936
9954
|
}
|
|
9937
9955
|
) : null,
|
|
9938
|
-
showHeader ? /* @__PURE__ */
|
|
9939
|
-
/* @__PURE__ */
|
|
9940
|
-
/* @__PURE__ */
|
|
9941
|
-
/* @__PURE__ */
|
|
9942
|
-
subtitle ? /* @__PURE__ */
|
|
9956
|
+
showHeader ? /* @__PURE__ */ jsxs71("header", { className: "fdc-head", children: [
|
|
9957
|
+
/* @__PURE__ */ jsx76("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx76("i", { className: "ph ph-" + assistantIcon }) }),
|
|
9958
|
+
/* @__PURE__ */ jsxs71("span", { className: "fdc-head-titles", children: [
|
|
9959
|
+
/* @__PURE__ */ jsx76("span", { className: "fdc-head-title", children: title }),
|
|
9960
|
+
subtitle ? /* @__PURE__ */ jsx76("span", { className: "fdc-head-sub", children: subtitle }) : null
|
|
9943
9961
|
] }),
|
|
9944
|
-
/* @__PURE__ */
|
|
9962
|
+
/* @__PURE__ */ jsxs71("span", { className: "fdc-head-acts", children: [
|
|
9945
9963
|
headerActions,
|
|
9946
9964
|
threadMenu,
|
|
9947
|
-
onNewThread ? /* @__PURE__ */
|
|
9948
|
-
onClose ? /* @__PURE__ */
|
|
9965
|
+
onNewThread ? /* @__PURE__ */ jsx76("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx76("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
|
|
9966
|
+
onClose ? /* @__PURE__ */ jsx76("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx76("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
9949
9967
|
] })
|
|
9950
9968
|
] }) : null,
|
|
9951
|
-
/* @__PURE__ */
|
|
9969
|
+
/* @__PURE__ */ jsx76(
|
|
9952
9970
|
ChatTranscript,
|
|
9953
9971
|
{
|
|
9954
9972
|
messages: engine.visible,
|
|
@@ -9963,7 +9981,7 @@ function AgentChatPanel({
|
|
|
9963
9981
|
renderEmpty
|
|
9964
9982
|
}
|
|
9965
9983
|
),
|
|
9966
|
-
/* @__PURE__ */
|
|
9984
|
+
/* @__PURE__ */ jsx76(
|
|
9967
9985
|
ChatComposer,
|
|
9968
9986
|
{
|
|
9969
9987
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -9996,7 +10014,7 @@ function AgentChatPanel({
|
|
|
9996
10014
|
}
|
|
9997
10015
|
|
|
9998
10016
|
// src/kits/query.ts
|
|
9999
|
-
import * as
|
|
10017
|
+
import * as React45 from "react";
|
|
10000
10018
|
function eqFilter(get2) {
|
|
10001
10019
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
10002
10020
|
}
|
|
@@ -10028,22 +10046,22 @@ function compare(a, b, dir) {
|
|
|
10028
10046
|
var API = null;
|
|
10029
10047
|
var PREFS = null;
|
|
10030
10048
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
10031
|
-
const [query, setQuery] =
|
|
10049
|
+
const [query, setQuery] = React45.useState(() => {
|
|
10032
10050
|
const store = PREFS || window.PlannerPrefs;
|
|
10033
10051
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
10034
10052
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
10035
10053
|
});
|
|
10036
|
-
const savePref =
|
|
10054
|
+
const savePref = React45.useCallback((patch2) => {
|
|
10037
10055
|
const store = PREFS || window.PlannerPrefs;
|
|
10038
10056
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
10039
10057
|
}, [prefsKey]);
|
|
10040
|
-
const [res, setRes] =
|
|
10041
|
-
const [loading, setLoading] =
|
|
10042
|
-
const seq2 =
|
|
10058
|
+
const [res, setRes] = React45.useState(null);
|
|
10059
|
+
const [loading, setLoading] = React45.useState(true);
|
|
10060
|
+
const seq2 = React45.useRef(0);
|
|
10043
10061
|
const depKey = (deps || []).join("|");
|
|
10044
10062
|
const paramKey = JSON.stringify(params || {});
|
|
10045
10063
|
const queryKey = JSON.stringify(query);
|
|
10046
|
-
|
|
10064
|
+
React45.useEffect(() => {
|
|
10047
10065
|
const id = ++seq2.current;
|
|
10048
10066
|
setLoading(true);
|
|
10049
10067
|
const t = setTimeout(() => {
|