@fayz-ai/ui 0.8.3 → 0.8.5
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/ChartWidgetInner-GDE5PBTR.js +46 -0
- package/dist/ChartWidgetInner-GDE5PBTR.js.map +1 -0
- package/dist/{chunk-BVF2KPTT.js → chunk-G6OKZ7WL.js} +30 -3
- package/dist/chunk-G6OKZ7WL.js.map +1 -0
- package/dist/{chunk-ID2HQK2Q.js → chunk-KV3MHB6N.js} +116 -213
- package/dist/chunk-KV3MHB6N.js.map +1 -0
- package/dist/{chunk-A7O7KGNL.js → chunk-OUPJDGKE.js} +27 -43
- package/dist/chunk-OUPJDGKE.js.map +1 -0
- package/dist/chunk-PVIB724L.js +161 -0
- package/dist/chunk-PVIB724L.js.map +1 -0
- package/dist/{chunk-O5F4LLSL.js → chunk-VDAYIQX4.js} +208 -8
- package/dist/chunk-VDAYIQX4.js.map +1 -0
- package/dist/{chunk-2GDQUARM.js → chunk-YLQGUJAQ.js} +24 -42
- package/dist/chunk-YLQGUJAQ.js.map +1 -0
- package/dist/dashboard/ChartWidget.d.ts.map +1 -1
- package/dist/dashboard/ChartWidgetInner.d.ts +11 -0
- package/dist/dashboard/ChartWidgetInner.d.ts.map +1 -0
- package/dist/dashboard/OnboardingWidget.d.ts.map +1 -1
- package/dist/dashboard/index.js +3 -2
- package/dist/icons.d.ts +8 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +3 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/layout/Sidebar.d.ts +5 -2
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/index.js +2 -1
- package/dist/preset.cjs +201 -11
- package/dist/preset.cjs.map +1 -1
- package/dist/preset.js +201 -1
- package/dist/preset.js.map +1 -1
- package/dist/primitives/date-picker.d.ts +7 -1
- package/dist/primitives/date-picker.d.ts.map +1 -1
- package/dist/primitives/index.js +2 -2
- package/dist/primitives/search-select.d.ts +3 -1
- package/dist/primitives/search-select.d.ts.map +1 -1
- package/dist/tailwind.cjs +199 -2
- package/dist/tailwind.cjs.map +1 -1
- package/dist/tailwind.js +198 -1
- package/dist/tailwind.js.map +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -2
- package/package.json +24 -22
- package/src/dashboard/ChartWidget.tsx +8 -65
- package/src/dashboard/ChartWidgetInner.tsx +83 -0
- package/src/dashboard/OnboardingWidget.tsx +32 -1
- package/src/dashboard/icon.ts +2 -2
- package/src/icons.ts +66 -0
- package/src/index.ts +4 -0
- package/src/layout/Sidebar.tsx +70 -136
- package/src/primitives/date-picker.tsx +30 -4
- package/src/primitives/search-select.tsx +12 -4
- package/src/theme/index.ts +9 -6
- package/dist/chunk-2GDQUARM.js.map +0 -1
- package/dist/chunk-2P7T6QQK.cjs +0 -206
- package/dist/chunk-2P7T6QQK.cjs.map +0 -1
- package/dist/chunk-A7O7KGNL.js.map +0 -1
- package/dist/chunk-BVF2KPTT.js.map +0 -1
- package/dist/chunk-H6OULCHF.cjs +0 -81
- package/dist/chunk-H6OULCHF.cjs.map +0 -1
- package/dist/chunk-ID2HQK2Q.js.map +0 -1
- package/dist/chunk-IWBXYV4U.js +0 -203
- package/dist/chunk-IWBXYV4U.js.map +0 -1
- package/dist/chunk-MI6FOB4O.cjs +0 -351
- package/dist/chunk-MI6FOB4O.cjs.map +0 -1
- package/dist/chunk-O5F4LLSL.js.map +0 -1
- package/dist/chunk-OW73RZOU.cjs +0 -313
- package/dist/chunk-OW73RZOU.cjs.map +0 -1
- package/dist/chunk-SVVKUMSL.cjs +0 -1733
- package/dist/chunk-SVVKUMSL.cjs.map +0 -1
- package/dist/chunk-TDGSY5W6.cjs +0 -474
- package/dist/chunk-TDGSY5W6.cjs.map +0 -1
- package/dist/chunk-WF3STNDX.cjs +0 -682
- package/dist/chunk-WF3STNDX.cjs.map +0 -1
- package/dist/chunk-XIRJGVDK.cjs +0 -1826
- package/dist/chunk-XIRJGVDK.cjs.map +0 -1
- package/dist/dashboard/index.cjs +0 -106
- package/dist/dashboard/index.cjs.map +0 -1
- package/dist/index.cjs +0 -650
- package/dist/index.cjs.map +0 -1
- package/dist/layout/index.cjs +0 -98
- package/dist/layout/index.cjs.map +0 -1
- package/dist/primitives/index.cjs +0 -363
- package/dist/primitives/index.cjs.map +0 -1
- package/dist/theme/index.cjs +0 -41
- package/dist/theme/index.cjs.map +0 -1
package/dist/chunk-WF3STNDX.cjs
DELETED
|
@@ -1,682 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkMI6FOB4O_cjs = require('./chunk-MI6FOB4O.cjs');
|
|
4
|
-
var chunkH6OULCHF_cjs = require('./chunk-H6OULCHF.cjs');
|
|
5
|
-
var React = require('react');
|
|
6
|
-
var LucideIcons = require('lucide-react');
|
|
7
|
-
var core = require('@fayz-ai/core');
|
|
8
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
-
var recharts = require('recharts');
|
|
10
|
-
|
|
11
|
-
function _interopNamespace(e) {
|
|
12
|
-
if (e && e.__esModule) return e;
|
|
13
|
-
var n = Object.create(null);
|
|
14
|
-
if (e) {
|
|
15
|
-
Object.keys(e).forEach(function (k) {
|
|
16
|
-
if (k !== 'default') {
|
|
17
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
-
enumerable: true,
|
|
20
|
-
get: function () { return e[k]; }
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
n.default = e;
|
|
26
|
-
return Object.freeze(n);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
30
|
-
var LucideIcons__namespace = /*#__PURE__*/_interopNamespace(LucideIcons);
|
|
31
|
-
|
|
32
|
-
var SPAN_CLASS = {
|
|
33
|
-
1: "",
|
|
34
|
-
2: "sm:col-span-2",
|
|
35
|
-
3: "sm:col-span-2 lg:col-span-3",
|
|
36
|
-
4: "sm:col-span-2 lg:col-span-4"
|
|
37
|
-
};
|
|
38
|
-
function DashboardGrid({ items, className }) {
|
|
39
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkH6OULCHF_cjs.cn("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4", className), children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: SPAN_CLASS[Math.min(Math.max(item.span ?? 1, 1), 4)] ?? "", children: item.node }, item.id)) });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// src/dashboard/layout.ts
|
|
43
|
-
function resolveDashboardLayout(registered, appConfig, userPrefs, forceVisibleByDefault = false) {
|
|
44
|
-
const overrides = /* @__PURE__ */ new Map();
|
|
45
|
-
const merge = (cfg) => {
|
|
46
|
-
for (const w of cfg?.widgets ?? []) {
|
|
47
|
-
overrides.set(w.id, { ...overrides.get(w.id), ...w });
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
merge(appConfig);
|
|
51
|
-
merge(userPrefs);
|
|
52
|
-
return registered.map((def, index) => {
|
|
53
|
-
const o = overrides.get(def.id);
|
|
54
|
-
const baseVisible = forceVisibleByDefault ? true : def.defaultVisible ?? true;
|
|
55
|
-
const visible = o?.visible ?? baseVisible;
|
|
56
|
-
const order = o?.order ?? def.defaultOrder ?? index;
|
|
57
|
-
const span = Math.min(Math.max(o?.span ?? def.span ?? 1, 1), 4);
|
|
58
|
-
return { def, visible, order, span };
|
|
59
|
-
}).filter((x) => x.visible).sort((a, b) => a.order - b.order).map(({ def, span, order }) => ({ def, span, order }));
|
|
60
|
-
}
|
|
61
|
-
var KEY = (surface, scope) => `fayz.dashboard.prefs.${scope}.${surface}`;
|
|
62
|
-
function read(key) {
|
|
63
|
-
if (typeof window === "undefined") return null;
|
|
64
|
-
try {
|
|
65
|
-
const raw = window.localStorage.getItem(key);
|
|
66
|
-
return raw ? JSON.parse(raw) : null;
|
|
67
|
-
} catch {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
function useDashboardPreferences(surface, scope = "home") {
|
|
72
|
-
const key = KEY(surface, scope);
|
|
73
|
-
const [prefs, setPrefs] = React__namespace.useState(() => read(key));
|
|
74
|
-
React__namespace.useEffect(() => {
|
|
75
|
-
setPrefs(read(key));
|
|
76
|
-
}, [key]);
|
|
77
|
-
const save = React__namespace.useCallback((next) => {
|
|
78
|
-
setPrefs(next);
|
|
79
|
-
if (typeof window !== "undefined") {
|
|
80
|
-
try {
|
|
81
|
-
window.localStorage.setItem(key, JSON.stringify(next));
|
|
82
|
-
} catch {
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}, [key]);
|
|
86
|
-
const setVisible = React__namespace.useCallback((widgetId, visible) => {
|
|
87
|
-
setPrefs((cur) => {
|
|
88
|
-
const widgets = [...cur?.widgets ?? []];
|
|
89
|
-
const i = widgets.findIndex((w) => w.id === widgetId);
|
|
90
|
-
if (i >= 0) widgets[i] = { ...widgets[i], visible };
|
|
91
|
-
else widgets.push({ id: widgetId, visible });
|
|
92
|
-
const next = { ...cur, widgets };
|
|
93
|
-
if (typeof window !== "undefined") {
|
|
94
|
-
try {
|
|
95
|
-
window.localStorage.setItem(key, JSON.stringify(next));
|
|
96
|
-
} catch {
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return next;
|
|
100
|
-
});
|
|
101
|
-
}, [key]);
|
|
102
|
-
const reset = React__namespace.useCallback(() => {
|
|
103
|
-
setPrefs(null);
|
|
104
|
-
if (typeof window !== "undefined") {
|
|
105
|
-
try {
|
|
106
|
-
window.localStorage.removeItem(key);
|
|
107
|
-
} catch {
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}, [key]);
|
|
111
|
-
return { prefs, save, setVisible, reset };
|
|
112
|
-
}
|
|
113
|
-
var DEFAULT_RANGE_OPTIONS = ["7d", "30d", "90d"];
|
|
114
|
-
var DashboardRangeContext = React__namespace.createContext(null);
|
|
115
|
-
function useDashboardRange() {
|
|
116
|
-
return React__namespace.useContext(DashboardRangeContext);
|
|
117
|
-
}
|
|
118
|
-
function DashboardRangeProvider({
|
|
119
|
-
options = DEFAULT_RANGE_OPTIONS,
|
|
120
|
-
defaultRange,
|
|
121
|
-
onChange,
|
|
122
|
-
children
|
|
123
|
-
}) {
|
|
124
|
-
const [range, setRangeState] = React__namespace.useState(defaultRange ?? options[1] ?? options[0] ?? "30d");
|
|
125
|
-
const setRange = React__namespace.useCallback((r) => {
|
|
126
|
-
setRangeState(r);
|
|
127
|
-
onChange?.(r);
|
|
128
|
-
}, [onChange]);
|
|
129
|
-
const value = React__namespace.useMemo(() => ({ range, setRange, options }), [range, setRange, options]);
|
|
130
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DashboardRangeContext.Provider, { value, children });
|
|
131
|
-
}
|
|
132
|
-
function DashboardRangeControl({ className }) {
|
|
133
|
-
const ctx = useDashboardRange();
|
|
134
|
-
if (!ctx) return null;
|
|
135
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
136
|
-
chunkMI6FOB4O_cjs.SegmentedControl,
|
|
137
|
-
{
|
|
138
|
-
options: ctx.options,
|
|
139
|
-
value: ctx.range,
|
|
140
|
-
onChange: ctx.setRange,
|
|
141
|
-
className,
|
|
142
|
-
"aria-label": "Time range"
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
function DashboardCustomizeMenu({ widgets, visibleIds, onToggle, onReset, label }) {
|
|
147
|
-
const t = core.useTranslation();
|
|
148
|
-
if (widgets.length === 0) return null;
|
|
149
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.Dropdown, { children: [
|
|
150
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkH6OULCHF_cjs.Button, { variant: "outline", size: "sm", className: "gap-1.5", children: [
|
|
151
|
-
/* @__PURE__ */ jsxRuntime.jsx(LucideIcons.SlidersHorizontal, { className: "h-3.5 w-3.5" }),
|
|
152
|
-
label ?? "Customize"
|
|
153
|
-
] }) }),
|
|
154
|
-
/* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.DropdownContent, { align: "end", className: "max-h-[70vh] w-60 overflow-y-auto", children: [
|
|
155
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.DropdownLabel, { children: label ?? "Show widgets" }),
|
|
156
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.DropdownSeparator, {}),
|
|
157
|
-
widgets.map((w) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
158
|
-
chunkMI6FOB4O_cjs.DropdownCheckboxItem,
|
|
159
|
-
{
|
|
160
|
-
checked: visibleIds.has(w.id),
|
|
161
|
-
onCheckedChange: (checked) => onToggle(w.id, Boolean(checked)),
|
|
162
|
-
onSelect: (e) => e.preventDefault(),
|
|
163
|
-
children: t(w.title)
|
|
164
|
-
},
|
|
165
|
-
w.id
|
|
166
|
-
)),
|
|
167
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.DropdownSeparator, {}),
|
|
168
|
-
/* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.DropdownItem, { onSelect: () => onReset(), children: [
|
|
169
|
-
/* @__PURE__ */ jsxRuntime.jsx(LucideIcons.RotateCcw, { className: "mr-2 h-3.5 w-3.5" }),
|
|
170
|
-
"Reset to defaults"
|
|
171
|
-
] })
|
|
172
|
-
] })
|
|
173
|
-
] });
|
|
174
|
-
}
|
|
175
|
-
function HoverHide({ id, onHide, children }) {
|
|
176
|
-
if (!onHide) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
177
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative h-full", children: [
|
|
178
|
-
children,
|
|
179
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
180
|
-
"button",
|
|
181
|
-
{
|
|
182
|
-
type: "button",
|
|
183
|
-
onClick: () => onHide(id),
|
|
184
|
-
title: "Hide widget",
|
|
185
|
-
"aria-label": "Hide widget",
|
|
186
|
-
className: "absolute right-2 top-2 z-10 inline-flex h-6 w-6 items-center justify-center rounded-md border border-border bg-background/90 text-muted-foreground opacity-0 shadow-sm transition-opacity hover:text-foreground group-hover:opacity-100",
|
|
187
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.EyeOff, { className: "h-3.5 w-3.5" })
|
|
188
|
-
}
|
|
189
|
-
)
|
|
190
|
-
] });
|
|
191
|
-
}
|
|
192
|
-
function toGridItems(laidOut, onHide) {
|
|
193
|
-
return laidOut.map(({ def, span }) => {
|
|
194
|
-
const Component = core.resolvePluginComponent(def);
|
|
195
|
-
const node = Component ? /* @__PURE__ */ jsxRuntime.jsx(Component, { ...def.props ?? {} }) : null;
|
|
196
|
-
return { id: def.id, span, node: /* @__PURE__ */ jsxRuntime.jsx(HoverHide, { id: def.id, onHide, children: node }) };
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
var DashboardNavigateContext = React__namespace.createContext(
|
|
200
|
-
(path) => core.hashRouterAdapter().navigate(path)
|
|
201
|
-
);
|
|
202
|
-
var DashboardNavigateProvider = DashboardNavigateContext.Provider;
|
|
203
|
-
function useDashboardNavigate() {
|
|
204
|
-
return React__namespace.useContext(DashboardNavigateContext);
|
|
205
|
-
}
|
|
206
|
-
function WidgetGrid({ widgets, appLayout, surface }) {
|
|
207
|
-
const { prefs, setVisible } = useDashboardPreferences(surface);
|
|
208
|
-
const laidOut = resolveDashboardLayout(widgets, appLayout, prefs ?? void 0);
|
|
209
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DashboardGrid, { items: toGridItems(laidOut, (id) => setVisible(id, false)) });
|
|
210
|
-
}
|
|
211
|
-
function DashboardCanvas({
|
|
212
|
-
surface,
|
|
213
|
-
domain,
|
|
214
|
-
title,
|
|
215
|
-
subtitle,
|
|
216
|
-
showHeader = true,
|
|
217
|
-
appLayout,
|
|
218
|
-
extraWidgets,
|
|
219
|
-
range,
|
|
220
|
-
customizable = true,
|
|
221
|
-
customizeLabel,
|
|
222
|
-
initialVisibility,
|
|
223
|
-
onNavigate,
|
|
224
|
-
className
|
|
225
|
-
}) {
|
|
226
|
-
const runtime = core.usePluginRuntime();
|
|
227
|
-
const registryWidgets = core.getDashboardWidgets(runtime, { surface, domain });
|
|
228
|
-
const widgets = React__namespace.useMemo(() => {
|
|
229
|
-
const extra = (extraWidgets ?? []).filter((w) => {
|
|
230
|
-
if (!(w.surfaces ?? ["home", "plugin-home"]).includes(surface)) return false;
|
|
231
|
-
return !domain || w.domain === domain;
|
|
232
|
-
});
|
|
233
|
-
return extra.length ? [...registryWidgets, ...extra] : registryWidgets;
|
|
234
|
-
}, [registryWidgets, extraWidgets, surface, domain]);
|
|
235
|
-
const rangeOpts = range ? range === true ? {} : range : null;
|
|
236
|
-
const forceAll = (initialVisibility ?? (surface === "plugin-home" ? "all" : "default")) === "all";
|
|
237
|
-
const { prefs, setVisible, reset } = useDashboardPreferences(surface, domain ?? "home");
|
|
238
|
-
const laidOut = resolveDashboardLayout(widgets, appLayout, prefs ?? void 0, forceAll);
|
|
239
|
-
const visibleIds = React__namespace.useMemo(() => new Set(laidOut.map((w) => w.def.id)), [laidOut]);
|
|
240
|
-
const hasControls = Boolean(rangeOpts) || customizable && widgets.length > 0;
|
|
241
|
-
const headerBlock = showHeader && (title || subtitle) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
242
|
-
title ? /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: title }) : null,
|
|
243
|
-
subtitle ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle }) : null
|
|
244
|
-
] }) : null;
|
|
245
|
-
const topRow = headerBlock || hasControls ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
246
|
-
headerBlock ?? /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
247
|
-
hasControls ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
248
|
-
customizable && widgets.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
249
|
-
DashboardCustomizeMenu,
|
|
250
|
-
{
|
|
251
|
-
widgets,
|
|
252
|
-
visibleIds,
|
|
253
|
-
onToggle: setVisible,
|
|
254
|
-
onReset: reset,
|
|
255
|
-
label: customizeLabel
|
|
256
|
-
}
|
|
257
|
-
) : null,
|
|
258
|
-
rangeOpts ? /* @__PURE__ */ jsxRuntime.jsx(DashboardRangeControl, {}) : null
|
|
259
|
-
] }) : null
|
|
260
|
-
] }) : null;
|
|
261
|
-
const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className ?? "space-y-6 p-6", children: [
|
|
262
|
-
topRow,
|
|
263
|
-
widgets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.Card, { children: [
|
|
264
|
-
/* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.CardHeader, { children: [
|
|
265
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardTitle, { children: "Welcome!" }),
|
|
266
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardDescription, { children: "Your dashboard will show key metrics and information here." })
|
|
267
|
-
] }),
|
|
268
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Enable plugins or register dashboard widgets to populate this view." }) })
|
|
269
|
-
] }) : laidOut.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardContent, { className: "p-6 text-sm text-muted-foreground", children: "All widgets are hidden. Use \u201CCustomize\u201D to choose what to show." }) }) : /* @__PURE__ */ jsxRuntime.jsx(DashboardGrid, { items: toGridItems(laidOut) })
|
|
270
|
-
] });
|
|
271
|
-
const navWrapped = onNavigate ? /* @__PURE__ */ jsxRuntime.jsx(DashboardNavigateProvider, { value: onNavigate, children: content }) : content;
|
|
272
|
-
return rangeOpts ? /* @__PURE__ */ jsxRuntime.jsx(DashboardRangeProvider, { options: rangeOpts.options, defaultRange: rangeOpts.default, onChange: rangeOpts.onChange, children: navWrapped }) : navWrapped;
|
|
273
|
-
}
|
|
274
|
-
var GoldCard = React__namespace.forwardRef(
|
|
275
|
-
({ branded = false, className, children, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
276
|
-
"div",
|
|
277
|
-
{
|
|
278
|
-
ref,
|
|
279
|
-
className: chunkH6OULCHF_cjs.cn(
|
|
280
|
-
"h-full rounded-3xl p-5",
|
|
281
|
-
branded ? "bg-primary text-primary-foreground shadow-lg shadow-primary/20" : "border border-border bg-card text-card-foreground shadow-sm",
|
|
282
|
-
className
|
|
283
|
-
),
|
|
284
|
-
...rest,
|
|
285
|
-
children
|
|
286
|
-
}
|
|
287
|
-
)
|
|
288
|
-
);
|
|
289
|
-
GoldCard.displayName = "GoldCard";
|
|
290
|
-
function renderIcon(icon, className = "h-4 w-4") {
|
|
291
|
-
if (!icon) return null;
|
|
292
|
-
if (typeof icon === "string") {
|
|
293
|
-
const Comp = LucideIcons__namespace[icon];
|
|
294
|
-
return Comp ? React__namespace.createElement(Comp, { className }) : null;
|
|
295
|
-
}
|
|
296
|
-
return React__namespace.createElement(icon, { className });
|
|
297
|
-
}
|
|
298
|
-
function formatKpiValue(value, format, currency) {
|
|
299
|
-
const locale = currency?.locale ?? "pt-BR";
|
|
300
|
-
switch (format) {
|
|
301
|
-
case "currency":
|
|
302
|
-
return new Intl.NumberFormat(locale, { style: "currency", currency: currency?.code ?? "BRL", maximumFractionDigits: 0 }).format(value);
|
|
303
|
-
case "percent":
|
|
304
|
-
return `${new Intl.NumberFormat(locale, { maximumFractionDigits: 1 }).format(value)}%`;
|
|
305
|
-
case "duration":
|
|
306
|
-
return `${Math.round(value)} min`;
|
|
307
|
-
default:
|
|
308
|
-
return new Intl.NumberFormat(locale, { maximumFractionDigits: 1 }).format(value);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
function deriveTrend(current, previous, explicit) {
|
|
312
|
-
if (explicit) return explicit;
|
|
313
|
-
if (previous == null) return void 0;
|
|
314
|
-
return current > previous ? "up" : current < previous ? "down" : "neutral";
|
|
315
|
-
}
|
|
316
|
-
function TrendChip({ trend, delta, invert }) {
|
|
317
|
-
if (trend === "neutral") return null;
|
|
318
|
-
const good = invert ? trend === "down" : trend === "up";
|
|
319
|
-
const Icon = trend === "up" ? LucideIcons.TrendingUp : LucideIcons.TrendingDown;
|
|
320
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: chunkH6OULCHF_cjs.cn(
|
|
321
|
-
"inline-flex items-center gap-0.5 text-xs font-medium",
|
|
322
|
-
good ? "text-emerald-600" : "text-rose-600"
|
|
323
|
-
), children: [
|
|
324
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3 w-3" }),
|
|
325
|
-
delta != null ? `${delta > 0 ? "+" : ""}${delta}%` : null
|
|
326
|
-
] });
|
|
327
|
-
}
|
|
328
|
-
function trendColor(trend, invert) {
|
|
329
|
-
if (!trend || trend === "neutral") return "hsl(var(--info))";
|
|
330
|
-
const good = invert ? trend === "down" : trend === "up";
|
|
331
|
-
return good ? "#10b981" : "#f43f5e";
|
|
332
|
-
}
|
|
333
|
-
function Sparkline({ data, color }) {
|
|
334
|
-
const gid = React__namespace.useId();
|
|
335
|
-
if (!data || data.length < 2) return null;
|
|
336
|
-
const W = 96, H = 32, P = 3;
|
|
337
|
-
const min = Math.min(...data);
|
|
338
|
-
const max = Math.max(...data);
|
|
339
|
-
const span = max - min || 1;
|
|
340
|
-
const step = (W - P * 2) / (data.length - 1);
|
|
341
|
-
const pts = data.map((d, i) => {
|
|
342
|
-
const x = P + i * step;
|
|
343
|
-
const y = P + (H - P * 2) * (1 - (d - min) / span);
|
|
344
|
-
return [x, y];
|
|
345
|
-
});
|
|
346
|
-
const line = pts.map(([x, y], i) => `${i === 0 ? "M" : "L"}${x.toFixed(1)},${y.toFixed(1)}`).join(" ");
|
|
347
|
-
const area = `${line} L${pts[pts.length - 1][0].toFixed(1)},${H} L${pts[0][0].toFixed(1)},${H} Z`;
|
|
348
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: `0 0 ${W} ${H}`, className: "h-8 w-24 shrink-0 overflow-visible", preserveAspectRatio: "none", "aria-hidden": true, children: [
|
|
349
|
-
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsxs("linearGradient", { id: gid, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
350
|
-
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "0%", stopColor: color, stopOpacity: "0.22" }),
|
|
351
|
-
/* @__PURE__ */ jsxRuntime.jsx("stop", { offset: "100%", stopColor: color, stopOpacity: "0" })
|
|
352
|
-
] }) }),
|
|
353
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: area, fill: `url(#${gid})` }),
|
|
354
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: line, fill: "none", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", vectorEffect: "non-scaling-stroke" })
|
|
355
|
-
] });
|
|
356
|
-
}
|
|
357
|
-
function Gauge({ value, goal, color, children }) {
|
|
358
|
-
const pct = goal > 0 ? Math.min(1, Math.max(0, value / goal)) : 0;
|
|
359
|
-
const R = 40, CX = 50, CY = 46, SW = 9;
|
|
360
|
-
const len = Math.PI * R;
|
|
361
|
-
const d = `M ${CX - R} ${CY} A ${R} ${R} 0 0 1 ${CX + R} ${CY}`;
|
|
362
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative mx-auto w-full max-w-[160px]", children: [
|
|
363
|
-
/* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 100 52", className: "w-full", "aria-hidden": true, children: [
|
|
364
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d, fill: "none", stroke: "hsl(var(--muted))", strokeWidth: SW, strokeLinecap: "round" }),
|
|
365
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
366
|
-
"path",
|
|
367
|
-
{
|
|
368
|
-
d,
|
|
369
|
-
fill: "none",
|
|
370
|
-
stroke: color,
|
|
371
|
-
strokeWidth: SW,
|
|
372
|
-
strokeLinecap: "round",
|
|
373
|
-
strokeDasharray: len,
|
|
374
|
-
strokeDashoffset: len * (1 - pct)
|
|
375
|
-
}
|
|
376
|
-
)
|
|
377
|
-
] }),
|
|
378
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-x-0 bottom-0 text-center text-2xl font-semibold tracking-tight text-foreground", children })
|
|
379
|
-
] });
|
|
380
|
-
}
|
|
381
|
-
function KpiCard(props) {
|
|
382
|
-
const { label, icon, sub, format, currency, invertTrend } = props;
|
|
383
|
-
const [computed, setComputed] = React__namespace.useState(null);
|
|
384
|
-
const [errored, setErrored] = React__namespace.useState(false);
|
|
385
|
-
React__namespace.useEffect(() => {
|
|
386
|
-
if (!props.compute) return;
|
|
387
|
-
let cancelled = false;
|
|
388
|
-
props.compute().then((v) => {
|
|
389
|
-
if (!cancelled) setComputed(v);
|
|
390
|
-
}).catch(() => {
|
|
391
|
-
if (!cancelled) setErrored(true);
|
|
392
|
-
});
|
|
393
|
-
return () => {
|
|
394
|
-
cancelled = true;
|
|
395
|
-
};
|
|
396
|
-
}, [props.compute]);
|
|
397
|
-
const isAsync = Boolean(props.compute);
|
|
398
|
-
const loading = props.loading || isAsync && computed === null && !errored;
|
|
399
|
-
let display = props.value;
|
|
400
|
-
let current = props.current;
|
|
401
|
-
let previous = props.previous;
|
|
402
|
-
let trend = props.trend;
|
|
403
|
-
let unit;
|
|
404
|
-
let spark = props.spark;
|
|
405
|
-
if (isAsync && computed) {
|
|
406
|
-
display = formatKpiValue(computed.value, format, currency);
|
|
407
|
-
current = computed.value;
|
|
408
|
-
previous = computed.previousValue;
|
|
409
|
-
trend = computed.trend;
|
|
410
|
-
unit = computed.unit;
|
|
411
|
-
spark = computed.spark ?? spark;
|
|
412
|
-
} else if (display == null && props.amount != null) {
|
|
413
|
-
display = formatKpiValue(props.amount, format, currency);
|
|
414
|
-
current = current ?? props.amount;
|
|
415
|
-
}
|
|
416
|
-
const resolvedTrend = current != null ? deriveTrend(current, previous, trend) : trend;
|
|
417
|
-
const delta = current != null && previous != null && previous !== 0 ? Math.round((current - previous) / previous * 100) : null;
|
|
418
|
-
const accent = props.accent ?? trendColor(resolvedTrend, invertTrend);
|
|
419
|
-
const valueText = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
420
|
-
display,
|
|
421
|
-
unit ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-sm font-normal text-muted-foreground", children: unit }) : null
|
|
422
|
-
] });
|
|
423
|
-
const trendChip = resolvedTrend ? /* @__PURE__ */ jsxRuntime.jsx(TrendChip, { trend: resolvedTrend, delta, invert: invertTrend }) : null;
|
|
424
|
-
const isGauge = props.goal != null && current != null;
|
|
425
|
-
const hasSpark = Boolean(spark && spark.length >= 2);
|
|
426
|
-
let body;
|
|
427
|
-
if (errored) {
|
|
428
|
-
body = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "\u2014" });
|
|
429
|
-
} else if (loading) {
|
|
430
|
-
body = isGauge ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto h-16 w-32 animate-pulse rounded bg-muted" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-7 w-20 animate-pulse rounded bg-muted" });
|
|
431
|
-
} else if (isGauge) {
|
|
432
|
-
body = /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
433
|
-
/* @__PURE__ */ jsxRuntime.jsx(Gauge, { value: current, goal: props.goal, color: accent, children: valueText }),
|
|
434
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center justify-center gap-2 text-xs text-muted-foreground", children: [
|
|
435
|
-
trendChip,
|
|
436
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: sub ?? `out of ${formatKpiValue(props.goal, format, currency)}` })
|
|
437
|
-
] })
|
|
438
|
-
] });
|
|
439
|
-
} else if (hasSpark) {
|
|
440
|
-
body = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end justify-between gap-3", children: [
|
|
441
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
442
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-semibold tracking-tight text-foreground", children: valueText }),
|
|
443
|
-
trendChip ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5", children: trendChip }) : null
|
|
444
|
-
] }),
|
|
445
|
-
/* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: spark, color: accent })
|
|
446
|
-
] });
|
|
447
|
-
} else {
|
|
448
|
-
body = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
449
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl font-semibold tracking-tight text-foreground", children: valueText }),
|
|
450
|
-
trendChip ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-0.5", children: trendChip }) : null
|
|
451
|
-
] });
|
|
452
|
-
}
|
|
453
|
-
return (
|
|
454
|
-
// h-full so cards fill the (stretch) grid cell and every card in a row matches
|
|
455
|
-
// the tallest — labels/subtitles of different lengths no longer misalign them.
|
|
456
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.Card, { className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.CardContent, { className: "flex h-full flex-col p-4", children: [
|
|
457
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
458
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: label }),
|
|
459
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: renderIcon(icon) })
|
|
460
|
-
] }),
|
|
461
|
-
body,
|
|
462
|
-
sub && !isGauge ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: sub }) : null
|
|
463
|
-
] }) })
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
var PALETTE = [
|
|
467
|
-
"hsl(var(--info))",
|
|
468
|
-
"hsl(var(--magic))",
|
|
469
|
-
"hsl(var(--success))",
|
|
470
|
-
"hsl(var(--warning))",
|
|
471
|
-
"hsl(var(--destructive))"
|
|
472
|
-
];
|
|
473
|
-
var AXIS = "hsl(var(--muted-foreground))";
|
|
474
|
-
var GRID = "hsl(var(--border))";
|
|
475
|
-
function ChartWidget({
|
|
476
|
-
type,
|
|
477
|
-
data,
|
|
478
|
-
series,
|
|
479
|
-
categoryKey = "name",
|
|
480
|
-
title,
|
|
481
|
-
icon,
|
|
482
|
-
headerAction,
|
|
483
|
-
height = 240,
|
|
484
|
-
className
|
|
485
|
-
}) {
|
|
486
|
-
const color = (i, explicit) => explicit ?? PALETTE[i % PALETTE.length];
|
|
487
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.Card, { className, children: [
|
|
488
|
-
(title || headerAction) && /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.CardHeader, { className: "flex-row items-center justify-between space-y-0", children: [
|
|
489
|
-
title ? /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.CardTitle, { className: "flex items-center gap-2", children: [
|
|
490
|
-
renderIcon(icon),
|
|
491
|
-
title
|
|
492
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
493
|
-
headerAction
|
|
494
|
-
] }),
|
|
495
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardContent, { className: "p-4 pt-2", children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height, children: type === "pie" ? /* @__PURE__ */ jsxRuntime.jsxs(recharts.PieChart, { children: [
|
|
496
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, {}),
|
|
497
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Pie, { data, dataKey: series[0]?.dataKey ?? "value", nameKey: categoryKey, innerRadius: 50, outerRadius: 80, paddingAngle: 2, children: data.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Cell, { fill: color(i, series[0]?.color) }, i)) }),
|
|
498
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {})
|
|
499
|
-
] }) : type === "bar" ? /* @__PURE__ */ jsxRuntime.jsxs(recharts.BarChart, { data, children: [
|
|
500
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: GRID, vertical: false }),
|
|
501
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: categoryKey, stroke: AXIS, fontSize: 12, tickLine: false, axisLine: false }),
|
|
502
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { stroke: AXIS, fontSize: 12, tickLine: false, axisLine: false, width: 36 }),
|
|
503
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, { cursor: { fill: GRID, opacity: 0.3 } }),
|
|
504
|
-
series.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {}),
|
|
505
|
-
series.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Bar, { dataKey: s.dataKey, name: s.label ?? s.dataKey, fill: color(i, s.color), radius: [4, 4, 0, 0] }, s.dataKey))
|
|
506
|
-
] }) : type === "area" ? /* @__PURE__ */ jsxRuntime.jsxs(recharts.AreaChart, { data, children: [
|
|
507
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: GRID, vertical: false }),
|
|
508
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: categoryKey, stroke: AXIS, fontSize: 12, tickLine: false, axisLine: false }),
|
|
509
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { stroke: AXIS, fontSize: 12, tickLine: false, axisLine: false, width: 36 }),
|
|
510
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, {}),
|
|
511
|
-
series.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {}),
|
|
512
|
-
series.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Area, { dataKey: s.dataKey, name: s.label ?? s.dataKey, stroke: color(i, s.color), fill: color(i, s.color), fillOpacity: 0.15 }, s.dataKey))
|
|
513
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, children: [
|
|
514
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: GRID, vertical: false }),
|
|
515
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.XAxis, { dataKey: categoryKey, stroke: AXIS, fontSize: 12, tickLine: false, axisLine: false }),
|
|
516
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.YAxis, { stroke: AXIS, fontSize: 12, tickLine: false, axisLine: false, width: 36 }),
|
|
517
|
-
/* @__PURE__ */ jsxRuntime.jsx(recharts.Tooltip, {}),
|
|
518
|
-
series.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(recharts.Legend, {}),
|
|
519
|
-
series.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(recharts.Line, { dataKey: s.dataKey, name: s.label ?? s.dataKey, stroke: color(i, s.color), strokeWidth: 2, dot: false }, s.dataKey))
|
|
520
|
-
] }) }) })
|
|
521
|
-
] });
|
|
522
|
-
}
|
|
523
|
-
function TableWidget({
|
|
524
|
-
title,
|
|
525
|
-
icon,
|
|
526
|
-
columns,
|
|
527
|
-
data,
|
|
528
|
-
loading,
|
|
529
|
-
emptyMessage,
|
|
530
|
-
onRowClick,
|
|
531
|
-
headerAction,
|
|
532
|
-
className
|
|
533
|
-
}) {
|
|
534
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.Card, { className, children: [
|
|
535
|
-
(title || headerAction) && /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.CardHeader, { className: "flex-row items-center justify-between space-y-0", children: [
|
|
536
|
-
title ? /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.CardTitle, { className: "flex items-center gap-2", children: [
|
|
537
|
-
renderIcon(icon),
|
|
538
|
-
title
|
|
539
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
540
|
-
headerAction
|
|
541
|
-
] }),
|
|
542
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardContent, { className: "p-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
543
|
-
chunkMI6FOB4O_cjs.DataTable,
|
|
544
|
-
{
|
|
545
|
-
columns,
|
|
546
|
-
data,
|
|
547
|
-
loading,
|
|
548
|
-
emptyMessage,
|
|
549
|
-
onRowClick,
|
|
550
|
-
variant: "flat",
|
|
551
|
-
compact: true
|
|
552
|
-
}
|
|
553
|
-
) })
|
|
554
|
-
] });
|
|
555
|
-
}
|
|
556
|
-
function OnboardingWidget({
|
|
557
|
-
title = "Getting started",
|
|
558
|
-
subtitle,
|
|
559
|
-
steps,
|
|
560
|
-
onNavigate,
|
|
561
|
-
hideWhenComplete = true,
|
|
562
|
-
className
|
|
563
|
-
}) {
|
|
564
|
-
const [completed, setCompleted] = React__namespace.useState(
|
|
565
|
-
() => Object.fromEntries(steps.map((s) => [s.id, Boolean(s.done)]))
|
|
566
|
-
);
|
|
567
|
-
const [resolved, setResolved] = React__namespace.useState(() => steps.every((s) => s.done != null || !s.check));
|
|
568
|
-
React__namespace.useEffect(() => {
|
|
569
|
-
let cancelled = false;
|
|
570
|
-
Promise.all(steps.map(async (s) => {
|
|
571
|
-
if (s.done != null) return [s.id, s.done];
|
|
572
|
-
if (!s.check) return [s.id, false];
|
|
573
|
-
try {
|
|
574
|
-
return [s.id, await s.check()];
|
|
575
|
-
} catch {
|
|
576
|
-
return [s.id, false];
|
|
577
|
-
}
|
|
578
|
-
})).then((entries) => {
|
|
579
|
-
if (cancelled) return;
|
|
580
|
-
setCompleted(Object.fromEntries(entries));
|
|
581
|
-
setResolved(true);
|
|
582
|
-
});
|
|
583
|
-
return () => {
|
|
584
|
-
cancelled = true;
|
|
585
|
-
};
|
|
586
|
-
}, [steps]);
|
|
587
|
-
const doneCount = steps.filter((s) => completed[s.id]).length;
|
|
588
|
-
const allDone = doneCount === steps.length;
|
|
589
|
-
if (!resolved) return null;
|
|
590
|
-
if (allDone && hideWhenComplete) return null;
|
|
591
|
-
const runAction = (action) => {
|
|
592
|
-
if (!action) return;
|
|
593
|
-
if (typeof action === "string") onNavigate?.(action);
|
|
594
|
-
else action();
|
|
595
|
-
};
|
|
596
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.Card, { className, children: [
|
|
597
|
-
/* @__PURE__ */ jsxRuntime.jsxs(chunkMI6FOB4O_cjs.CardHeader, { children: [
|
|
598
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardTitle, { children: title }),
|
|
599
|
-
subtitle ? /* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardDescription, { children: subtitle }) : null,
|
|
600
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-3", children: [
|
|
601
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 flex-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
602
|
-
"div",
|
|
603
|
-
{
|
|
604
|
-
className: "h-full rounded-full bg-primary transition-all",
|
|
605
|
-
style: { width: `${steps.length ? doneCount / steps.length * 100 : 0}%` }
|
|
606
|
-
}
|
|
607
|
-
) }),
|
|
608
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-muted-foreground", children: [
|
|
609
|
-
doneCount,
|
|
610
|
-
"/",
|
|
611
|
-
steps.length
|
|
612
|
-
] })
|
|
613
|
-
] })
|
|
614
|
-
] }),
|
|
615
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkMI6FOB4O_cjs.CardContent, { className: "space-y-1 pt-0", children: steps.map((step) => {
|
|
616
|
-
const isDone = completed[step.id];
|
|
617
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 rounded-lg px-2 py-2.5 hover:bg-muted/50", children: [
|
|
618
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: chunkH6OULCHF_cjs.cn(
|
|
619
|
-
"flex h-7 w-7 shrink-0 items-center justify-center rounded-full",
|
|
620
|
-
isDone ? "bg-emerald-100 text-emerald-600" : "bg-muted text-muted-foreground"
|
|
621
|
-
), children: isDone ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Check, { className: "h-4 w-4" }) : renderIcon(step.icon, "h-4 w-4") ?? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Circle, { className: "h-4 w-4" }) }),
|
|
622
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
623
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: chunkH6OULCHF_cjs.cn("text-sm font-medium", isDone && "text-muted-foreground line-through"), children: step.title }),
|
|
624
|
-
step.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-xs text-muted-foreground", children: step.description }) : null
|
|
625
|
-
] }),
|
|
626
|
-
!isDone && step.action ? /* @__PURE__ */ jsxRuntime.jsx(chunkH6OULCHF_cjs.Button, { size: "sm", variant: "outline", onClick: () => runAction(step.action), children: step.actionLabel ?? "Start" }) : null
|
|
627
|
-
] }, step.id);
|
|
628
|
-
}) })
|
|
629
|
-
] });
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// src/dashboard/define.ts
|
|
633
|
-
function build(kind, defaultSpan, input) {
|
|
634
|
-
return {
|
|
635
|
-
kind,
|
|
636
|
-
span: input.span ?? defaultSpan,
|
|
637
|
-
defaultVisible: input.defaultVisible ?? true,
|
|
638
|
-
id: input.id,
|
|
639
|
-
title: input.title,
|
|
640
|
-
description: input.description,
|
|
641
|
-
icon: input.icon,
|
|
642
|
-
domain: input.domain,
|
|
643
|
-
defaultOrder: input.defaultOrder,
|
|
644
|
-
surfaces: input.surfaces,
|
|
645
|
-
verticalId: input.verticalId,
|
|
646
|
-
permission: input.permission,
|
|
647
|
-
component: input.component,
|
|
648
|
-
props: input.props
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
var defineKpiWidget = (input) => build("kpi", 1, input);
|
|
652
|
-
var defineChartWidget = (input) => build("chart", 2, input);
|
|
653
|
-
var defineTableWidget = (input) => build("table", 4, input);
|
|
654
|
-
var defineOnboardingWidget = (input) => build("onboarding", 2, input);
|
|
655
|
-
var defineCustomWidget = (input) => build("custom", 2, input);
|
|
656
|
-
|
|
657
|
-
exports.ChartWidget = ChartWidget;
|
|
658
|
-
exports.DEFAULT_RANGE_OPTIONS = DEFAULT_RANGE_OPTIONS;
|
|
659
|
-
exports.DashboardCanvas = DashboardCanvas;
|
|
660
|
-
exports.DashboardCustomizeMenu = DashboardCustomizeMenu;
|
|
661
|
-
exports.DashboardGrid = DashboardGrid;
|
|
662
|
-
exports.DashboardNavigateProvider = DashboardNavigateProvider;
|
|
663
|
-
exports.DashboardRangeControl = DashboardRangeControl;
|
|
664
|
-
exports.DashboardRangeProvider = DashboardRangeProvider;
|
|
665
|
-
exports.GoldCard = GoldCard;
|
|
666
|
-
exports.KpiCard = KpiCard;
|
|
667
|
-
exports.OnboardingWidget = OnboardingWidget;
|
|
668
|
-
exports.TableWidget = TableWidget;
|
|
669
|
-
exports.WidgetGrid = WidgetGrid;
|
|
670
|
-
exports.defineChartWidget = defineChartWidget;
|
|
671
|
-
exports.defineCustomWidget = defineCustomWidget;
|
|
672
|
-
exports.defineKpiWidget = defineKpiWidget;
|
|
673
|
-
exports.defineOnboardingWidget = defineOnboardingWidget;
|
|
674
|
-
exports.defineTableWidget = defineTableWidget;
|
|
675
|
-
exports.formatKpiValue = formatKpiValue;
|
|
676
|
-
exports.renderIcon = renderIcon;
|
|
677
|
-
exports.resolveDashboardLayout = resolveDashboardLayout;
|
|
678
|
-
exports.useDashboardNavigate = useDashboardNavigate;
|
|
679
|
-
exports.useDashboardPreferences = useDashboardPreferences;
|
|
680
|
-
exports.useDashboardRange = useDashboardRange;
|
|
681
|
-
//# sourceMappingURL=chunk-WF3STNDX.cjs.map
|
|
682
|
-
//# sourceMappingURL=chunk-WF3STNDX.cjs.map
|