@fayz-ai/ui 0.8.4 → 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.
Files changed (78) hide show
  1. package/dist/ChartWidgetInner-GDE5PBTR.js +46 -0
  2. package/dist/ChartWidgetInner-GDE5PBTR.js.map +1 -0
  3. package/dist/{chunk-VVQ45ZDZ.js → chunk-KV3MHB6N.js} +85 -179
  4. package/dist/chunk-KV3MHB6N.js.map +1 -0
  5. package/dist/{chunk-M34ACV5E.js → chunk-OUPJDGKE.js} +6 -41
  6. package/dist/chunk-OUPJDGKE.js.map +1 -0
  7. package/dist/chunk-PVIB724L.js +161 -0
  8. package/dist/chunk-PVIB724L.js.map +1 -0
  9. package/dist/{chunk-DYMBFHD7.js → chunk-VDAYIQX4.js} +202 -3
  10. package/dist/chunk-VDAYIQX4.js.map +1 -0
  11. package/dist/{chunk-R4LPSXTT.js → chunk-YLQGUJAQ.js} +18 -6
  12. package/dist/chunk-YLQGUJAQ.js.map +1 -0
  13. package/dist/dashboard/ChartWidget.d.ts.map +1 -1
  14. package/dist/dashboard/ChartWidgetInner.d.ts +11 -0
  15. package/dist/dashboard/ChartWidgetInner.d.ts.map +1 -0
  16. package/dist/dashboard/index.js +2 -1
  17. package/dist/icons.d.ts +8 -0
  18. package/dist/icons.d.ts.map +1 -0
  19. package/dist/icons.js +3 -0
  20. package/dist/icons.js.map +1 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +5 -5
  24. package/dist/layout/Sidebar.d.ts +1 -2
  25. package/dist/layout/Sidebar.d.ts.map +1 -1
  26. package/dist/layout/index.js +2 -1
  27. package/dist/preset.cjs +201 -11
  28. package/dist/preset.cjs.map +1 -1
  29. package/dist/preset.js +201 -1
  30. package/dist/preset.js.map +1 -1
  31. package/dist/primitives/date-picker.d.ts +7 -1
  32. package/dist/primitives/date-picker.d.ts.map +1 -1
  33. package/dist/primitives/index.js +1 -1
  34. package/dist/tailwind.cjs +199 -2
  35. package/dist/tailwind.cjs.map +1 -1
  36. package/dist/tailwind.js +198 -1
  37. package/dist/tailwind.js.map +1 -1
  38. package/dist/theme/index.js +1 -2
  39. package/package.json +24 -22
  40. package/src/dashboard/ChartWidget.tsx +8 -65
  41. package/src/dashboard/ChartWidgetInner.tsx +83 -0
  42. package/src/dashboard/icon.ts +2 -2
  43. package/src/icons.ts +66 -0
  44. package/src/index.ts +4 -0
  45. package/src/layout/Sidebar.tsx +4 -110
  46. package/src/primitives/date-picker.tsx +30 -4
  47. package/dist/chunk-2P7T6QQK.cjs +0 -206
  48. package/dist/chunk-2P7T6QQK.cjs.map +0 -1
  49. package/dist/chunk-7ZQQZD4Q.cjs +0 -1823
  50. package/dist/chunk-7ZQQZD4Q.cjs.map +0 -1
  51. package/dist/chunk-B3BTZDTA.cjs +0 -1701
  52. package/dist/chunk-B3BTZDTA.cjs.map +0 -1
  53. package/dist/chunk-DYMBFHD7.js.map +0 -1
  54. package/dist/chunk-H6OULCHF.cjs +0 -81
  55. package/dist/chunk-H6OULCHF.cjs.map +0 -1
  56. package/dist/chunk-IWBXYV4U.js +0 -203
  57. package/dist/chunk-IWBXYV4U.js.map +0 -1
  58. package/dist/chunk-M34ACV5E.js.map +0 -1
  59. package/dist/chunk-MUGRP5DD.cjs +0 -701
  60. package/dist/chunk-MUGRP5DD.cjs.map +0 -1
  61. package/dist/chunk-NZV47HWO.cjs +0 -380
  62. package/dist/chunk-NZV47HWO.cjs.map +0 -1
  63. package/dist/chunk-OW73RZOU.cjs +0 -313
  64. package/dist/chunk-OW73RZOU.cjs.map +0 -1
  65. package/dist/chunk-R4LPSXTT.js.map +0 -1
  66. package/dist/chunk-R4SQ2GVD.cjs +0 -475
  67. package/dist/chunk-R4SQ2GVD.cjs.map +0 -1
  68. package/dist/chunk-VVQ45ZDZ.js.map +0 -1
  69. package/dist/dashboard/index.cjs +0 -106
  70. package/dist/dashboard/index.cjs.map +0 -1
  71. package/dist/index.cjs +0 -650
  72. package/dist/index.cjs.map +0 -1
  73. package/dist/layout/index.cjs +0 -98
  74. package/dist/layout/index.cjs.map +0 -1
  75. package/dist/primitives/index.cjs +0 -363
  76. package/dist/primitives/index.cjs.map +0 -1
  77. package/dist/theme/index.cjs +0 -41
  78. package/dist/theme/index.cjs.map +0 -1
@@ -1,701 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkNZV47HWO_cjs = require('./chunk-NZV47HWO.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
- chunkNZV47HWO_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(chunkNZV47HWO_cjs.Dropdown, { children: [
150
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_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(chunkNZV47HWO_cjs.DropdownContent, { align: "end", className: "max-h-[70vh] w-60 overflow-y-auto", children: [
155
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.DropdownLabel, { children: label ?? "Show widgets" }),
156
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.DropdownSeparator, {}),
157
- widgets.map((w) => /* @__PURE__ */ jsxRuntime.jsx(
158
- chunkNZV47HWO_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(chunkNZV47HWO_cjs.DropdownSeparator, {}),
168
- /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_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(chunkNZV47HWO_cjs.Card, { children: [
264
- /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_cjs.CardHeader, { children: [
265
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.CardTitle, { children: "Welcome!" }),
266
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.CardDescription, { children: "Your dashboard will show key metrics and information here." })
267
- ] }),
268
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_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(chunkNZV47HWO_cjs.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_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(chunkNZV47HWO_cjs.Card, { className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_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(chunkNZV47HWO_cjs.Card, { className, children: [
488
- (title || headerAction) && /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_cjs.CardHeader, { className: "flex-row items-center justify-between space-y-0", children: [
489
- title ? /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_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(chunkNZV47HWO_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(chunkNZV47HWO_cjs.Card, { className, children: [
535
- (title || headerAction) && /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_cjs.CardHeader, { className: "flex-row items-center justify-between space-y-0", children: [
536
- title ? /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_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(chunkNZV47HWO_cjs.CardContent, { className: "p-0", children: /* @__PURE__ */ jsxRuntime.jsx(
543
- chunkNZV47HWO_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 OnboardingSkeleton({ rows, className }) {
557
- return /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_cjs.Card, { className, "aria-busy": "true", children: [
558
- /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_cjs.CardHeader, { children: [
559
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.Skeleton, { className: "h-5 w-40" }),
560
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.Skeleton, { className: "mt-1.5 h-3.5 w-64 max-w-full" }),
561
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-3", children: [
562
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.Skeleton, { className: "h-1.5 flex-1 rounded-full" }),
563
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.Skeleton, { className: "h-3 w-8" })
564
- ] })
565
- ] }),
566
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.CardContent, { className: "space-y-1 pt-0", children: Array.from({ length: Math.max(rows, 1) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-2 py-2.5", children: [
567
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.Skeleton, { className: "h-7 w-7 shrink-0 rounded-full" }),
568
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1.5", children: [
569
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.Skeleton, { className: "h-3.5 w-1/2" }),
570
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.Skeleton, { className: "h-3 w-3/4" })
571
- ] })
572
- ] }, i)) })
573
- ] });
574
- }
575
- function OnboardingWidget({
576
- title = "Getting started",
577
- subtitle,
578
- steps,
579
- onNavigate,
580
- hideWhenComplete = true,
581
- className
582
- }) {
583
- const [completed, setCompleted] = React__namespace.useState(
584
- () => Object.fromEntries(steps.map((s) => [s.id, Boolean(s.done)]))
585
- );
586
- const [resolved, setResolved] = React__namespace.useState(() => steps.every((s) => s.done != null || !s.check));
587
- React__namespace.useEffect(() => {
588
- let cancelled = false;
589
- Promise.all(steps.map(async (s) => {
590
- if (s.done != null) return [s.id, s.done];
591
- if (!s.check) return [s.id, false];
592
- try {
593
- return [s.id, await s.check()];
594
- } catch {
595
- return [s.id, false];
596
- }
597
- })).then((entries) => {
598
- if (cancelled) return;
599
- setCompleted(Object.fromEntries(entries));
600
- setResolved(true);
601
- });
602
- return () => {
603
- cancelled = true;
604
- };
605
- }, [steps]);
606
- const doneCount = steps.filter((s) => completed[s.id]).length;
607
- const allDone = doneCount === steps.length;
608
- if (!resolved) return /* @__PURE__ */ jsxRuntime.jsx(OnboardingSkeleton, { rows: steps.length, className });
609
- if (allDone && hideWhenComplete) return null;
610
- const runAction = (action) => {
611
- if (!action) return;
612
- if (typeof action === "string") onNavigate?.(action);
613
- else action();
614
- };
615
- return /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_cjs.Card, { className, children: [
616
- /* @__PURE__ */ jsxRuntime.jsxs(chunkNZV47HWO_cjs.CardHeader, { children: [
617
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.CardTitle, { children: title }),
618
- subtitle ? /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.CardDescription, { children: subtitle }) : null,
619
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-3", children: [
620
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 flex-1 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx(
621
- "div",
622
- {
623
- className: "h-full rounded-full bg-primary transition-all",
624
- style: { width: `${steps.length ? doneCount / steps.length * 100 : 0}%` }
625
- }
626
- ) }),
627
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-muted-foreground", children: [
628
- doneCount,
629
- "/",
630
- steps.length
631
- ] })
632
- ] })
633
- ] }),
634
- /* @__PURE__ */ jsxRuntime.jsx(chunkNZV47HWO_cjs.CardContent, { className: "space-y-1 pt-0", children: steps.map((step) => {
635
- const isDone = completed[step.id];
636
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 rounded-lg px-2 py-2.5 hover:bg-muted/50", children: [
637
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: chunkH6OULCHF_cjs.cn(
638
- "flex h-7 w-7 shrink-0 items-center justify-center rounded-full",
639
- isDone ? "bg-emerald-100 text-emerald-600" : "bg-muted text-muted-foreground"
640
- ), 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" }) }),
641
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
642
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: chunkH6OULCHF_cjs.cn("text-sm font-medium", isDone && "text-muted-foreground line-through"), children: step.title }),
643
- step.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-xs text-muted-foreground", children: step.description }) : null
644
- ] }),
645
- !isDone && step.action ? /* @__PURE__ */ jsxRuntime.jsx(chunkH6OULCHF_cjs.Button, { size: "sm", variant: "outline", onClick: () => runAction(step.action), children: step.actionLabel ?? "Start" }) : null
646
- ] }, step.id);
647
- }) })
648
- ] });
649
- }
650
-
651
- // src/dashboard/define.ts
652
- function build(kind, defaultSpan, input) {
653
- return {
654
- kind,
655
- span: input.span ?? defaultSpan,
656
- defaultVisible: input.defaultVisible ?? true,
657
- id: input.id,
658
- title: input.title,
659
- description: input.description,
660
- icon: input.icon,
661
- domain: input.domain,
662
- defaultOrder: input.defaultOrder,
663
- surfaces: input.surfaces,
664
- verticalId: input.verticalId,
665
- permission: input.permission,
666
- component: input.component,
667
- props: input.props
668
- };
669
- }
670
- var defineKpiWidget = (input) => build("kpi", 1, input);
671
- var defineChartWidget = (input) => build("chart", 2, input);
672
- var defineTableWidget = (input) => build("table", 4, input);
673
- var defineOnboardingWidget = (input) => build("onboarding", 2, input);
674
- var defineCustomWidget = (input) => build("custom", 2, input);
675
-
676
- exports.ChartWidget = ChartWidget;
677
- exports.DEFAULT_RANGE_OPTIONS = DEFAULT_RANGE_OPTIONS;
678
- exports.DashboardCanvas = DashboardCanvas;
679
- exports.DashboardCustomizeMenu = DashboardCustomizeMenu;
680
- exports.DashboardGrid = DashboardGrid;
681
- exports.DashboardNavigateProvider = DashboardNavigateProvider;
682
- exports.DashboardRangeControl = DashboardRangeControl;
683
- exports.DashboardRangeProvider = DashboardRangeProvider;
684
- exports.GoldCard = GoldCard;
685
- exports.KpiCard = KpiCard;
686
- exports.OnboardingWidget = OnboardingWidget;
687
- exports.TableWidget = TableWidget;
688
- exports.WidgetGrid = WidgetGrid;
689
- exports.defineChartWidget = defineChartWidget;
690
- exports.defineCustomWidget = defineCustomWidget;
691
- exports.defineKpiWidget = defineKpiWidget;
692
- exports.defineOnboardingWidget = defineOnboardingWidget;
693
- exports.defineTableWidget = defineTableWidget;
694
- exports.formatKpiValue = formatKpiValue;
695
- exports.renderIcon = renderIcon;
696
- exports.resolveDashboardLayout = resolveDashboardLayout;
697
- exports.useDashboardNavigate = useDashboardNavigate;
698
- exports.useDashboardPreferences = useDashboardPreferences;
699
- exports.useDashboardRange = useDashboardRange;
700
- //# sourceMappingURL=chunk-MUGRP5DD.cjs.map
701
- //# sourceMappingURL=chunk-MUGRP5DD.cjs.map