@close-by/clay 0.2.4 → 0.2.6
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/package.json +5 -5
- package/src/index.ts +59 -0
- package/src/pages.ts +79 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@close-by/clay",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "NiceGUI-like ui.* facade for Clay apps",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@close-by/clay-compiler": "0.2.
|
|
31
|
-
"@close-by/clay-core": "0.2.
|
|
32
|
-
"@close-by/clay-components": "0.2.
|
|
33
|
-
"@close-by/clay-server": "0.2.
|
|
30
|
+
"@close-by/clay-compiler": "0.2.6",
|
|
31
|
+
"@close-by/clay-core": "0.2.6",
|
|
32
|
+
"@close-by/clay-components": "0.2.6",
|
|
33
|
+
"@close-by/clay-server": "0.2.6",
|
|
34
34
|
"@tailwindcss/cli": "^4.3.3",
|
|
35
35
|
"tailwindcss": "^4.3.3"
|
|
36
36
|
}
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
radioGroup as radioGroupFactory,
|
|
10
10
|
combobox as comboboxFactory,
|
|
11
11
|
date as dateFactory,
|
|
12
|
+
dateRange as dateRangeFactory,
|
|
13
|
+
timeline as timelineFactory,
|
|
14
|
+
stepper as stepperFactory,
|
|
12
15
|
tooltip as tooltipFactory,
|
|
13
16
|
avatar as avatarFactory,
|
|
14
17
|
skeleton as skeletonFactory,
|
|
@@ -34,6 +37,7 @@ import {
|
|
|
34
37
|
radialChart as radialChartFactory,
|
|
35
38
|
scatterChart as scatterChartFactory,
|
|
36
39
|
composedChart as composedChartFactory,
|
|
40
|
+
sparkline as sparklineFactory,
|
|
37
41
|
row as rowFactory,
|
|
38
42
|
column as columnFactory,
|
|
39
43
|
container as containerFactory,
|
|
@@ -101,6 +105,14 @@ import {
|
|
|
101
105
|
type RadioGroupProps,
|
|
102
106
|
type ComboboxProps,
|
|
103
107
|
type DateProps,
|
|
108
|
+
type DateRangeProps,
|
|
109
|
+
type DateRangePreset,
|
|
110
|
+
type TimelineProps,
|
|
111
|
+
type TimelineItem,
|
|
112
|
+
type TimelineItemStatus,
|
|
113
|
+
type StepperProps,
|
|
114
|
+
type StepperStepOptions,
|
|
115
|
+
type StepperStepStatus,
|
|
104
116
|
type TooltipProps,
|
|
105
117
|
type AvatarProps,
|
|
106
118
|
type SkeletonProps,
|
|
@@ -152,6 +164,11 @@ import {
|
|
|
152
164
|
type ComposedSeriesType,
|
|
153
165
|
type CartesianChartProps,
|
|
154
166
|
type ChartSeries,
|
|
167
|
+
type ChartHeadline,
|
|
168
|
+
type ChartPeriod,
|
|
169
|
+
type ChartReferenceLine,
|
|
170
|
+
type ChartReferenceArea,
|
|
171
|
+
type SparklineProps,
|
|
155
172
|
type CardProps,
|
|
156
173
|
type DialogProps,
|
|
157
174
|
type DialogStackProps,
|
|
@@ -318,6 +335,7 @@ import {
|
|
|
318
335
|
TableBuilder,
|
|
319
336
|
DialogElement,
|
|
320
337
|
DialogStackElement,
|
|
338
|
+
StepperElement,
|
|
321
339
|
AlertDialogElement,
|
|
322
340
|
DropdownMenuElement,
|
|
323
341
|
ContextMenuElement,
|
|
@@ -446,6 +464,14 @@ export type {
|
|
|
446
464
|
DialogProps,
|
|
447
465
|
DialogStackProps,
|
|
448
466
|
DialogStackStepOptions,
|
|
467
|
+
StepperProps,
|
|
468
|
+
StepperStepOptions,
|
|
469
|
+
StepperStepStatus,
|
|
470
|
+
TimelineProps,
|
|
471
|
+
TimelineItem,
|
|
472
|
+
TimelineItemStatus,
|
|
473
|
+
DateRangeProps,
|
|
474
|
+
DateRangePreset,
|
|
449
475
|
AlertDialogProps,
|
|
450
476
|
DropdownMenuProps,
|
|
451
477
|
DropdownItemOptions,
|
|
@@ -600,6 +626,7 @@ export {
|
|
|
600
626
|
TableBuilder,
|
|
601
627
|
DialogElement,
|
|
602
628
|
DialogStackElement,
|
|
629
|
+
StepperElement,
|
|
603
630
|
AlertDialogElement,
|
|
604
631
|
DropdownMenuElement,
|
|
605
632
|
SheetElement,
|
|
@@ -680,6 +707,29 @@ export function date(props?: DateProps): Element {
|
|
|
680
707
|
return dateFactory(props);
|
|
681
708
|
}
|
|
682
709
|
|
|
710
|
+
/** Date range picker with presets. Prefer `ui.dateRange`. See {@link DateRangeProps}. */
|
|
711
|
+
export function dateRange(props?: DateRangeProps): Element {
|
|
712
|
+
return dateRangeFactory(props);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/** Chronological events for feeds and deploy logs. See {@link TimelineProps}. */
|
|
716
|
+
export function timeline(props: TimelineProps): Element {
|
|
717
|
+
return timelineFactory(props);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/** Inline multi-step flow with step panels. See {@link StepperProps}. */
|
|
721
|
+
export function stepper(
|
|
722
|
+
fn: (s: StepperElement) => void,
|
|
723
|
+
props?: StepperProps,
|
|
724
|
+
): StepperElement;
|
|
725
|
+
export function stepper(
|
|
726
|
+
props: StepperProps,
|
|
727
|
+
fn: (s: StepperElement) => void,
|
|
728
|
+
): StepperElement;
|
|
729
|
+
export function stepper(a: any, b?: any): StepperElement {
|
|
730
|
+
return stepperFactory(a, b);
|
|
731
|
+
}
|
|
732
|
+
|
|
683
733
|
/** Tooltip around content (`fn` or props-first). Prefer `ui.tooltip`. See {@link TooltipProps}. */
|
|
684
734
|
export function tooltip(fn: () => void, props: TooltipProps): Element;
|
|
685
735
|
export function tooltip(props: TooltipProps, fn: () => void): Element;
|
|
@@ -970,6 +1020,11 @@ export function composedChart(props: ComposedChartProps): Element {
|
|
|
970
1020
|
return composedChartFactory(props);
|
|
971
1021
|
}
|
|
972
1022
|
|
|
1023
|
+
/** KPI card with inline sparkline. Prefer `ui.sparkline`. See {@link SparklineProps}. */
|
|
1024
|
+
export function sparkline(props: SparklineProps): Element {
|
|
1025
|
+
return sparklineFactory(props);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
973
1028
|
/** Horizontal flex row (`fn` or props-first). Prefer `ui.row`. */
|
|
974
1029
|
export function row(fn: () => void, props?: Parameters<typeof rowFactory>[1]): Element;
|
|
975
1030
|
export function row(props: Parameters<typeof rowFactory>[0], fn: () => void): Element;
|
|
@@ -1522,6 +1577,9 @@ export const ui = {
|
|
|
1522
1577
|
radioGroup,
|
|
1523
1578
|
combobox,
|
|
1524
1579
|
date,
|
|
1580
|
+
dateRange,
|
|
1581
|
+
timeline,
|
|
1582
|
+
stepper,
|
|
1525
1583
|
tooltip,
|
|
1526
1584
|
avatar,
|
|
1527
1585
|
skeleton,
|
|
@@ -1568,6 +1626,7 @@ export const ui = {
|
|
|
1568
1626
|
radialChart,
|
|
1569
1627
|
scatterChart,
|
|
1570
1628
|
composedChart,
|
|
1629
|
+
sparkline,
|
|
1571
1630
|
row,
|
|
1572
1631
|
column,
|
|
1573
1632
|
container,
|
package/src/pages.ts
CHANGED
|
@@ -58,6 +58,10 @@ export type PageMeta = {
|
|
|
58
58
|
* UX only — still call `requireRole` in the page builder.
|
|
59
59
|
*/
|
|
60
60
|
roles?: string[];
|
|
61
|
+
/** Nest this page under a collapsible sidebar group with the given label. */
|
|
62
|
+
group?: string;
|
|
63
|
+
/** Lucide icon for the group parent row (first page in the group with this set wins). */
|
|
64
|
+
groupIcon?: string;
|
|
61
65
|
};
|
|
62
66
|
|
|
63
67
|
const pageMetaByPath = new Map<string, PageMeta>();
|
|
@@ -140,8 +144,76 @@ export type NavFromPagesOptions = {
|
|
|
140
144
|
role?: string;
|
|
141
145
|
/** Viewer roles — page is shown if it has no `roles` meta, or any overlap. */
|
|
142
146
|
roles?: string[];
|
|
147
|
+
/**
|
|
148
|
+
* When true, nest `/examples/*` routes (except `/examples/auth`) under an
|
|
149
|
+
* "Examples" group. Individual pages can override with `pageMeta.group`.
|
|
150
|
+
*/
|
|
151
|
+
groupExamples?: boolean;
|
|
152
|
+
/** Label for the auto examples group. Default `"Examples"`. */
|
|
153
|
+
groupExamplesLabel?: string;
|
|
154
|
+
/** Icon for the auto examples group. Default `"layout-grid"`. */
|
|
155
|
+
groupExamplesIcon?: string;
|
|
143
156
|
};
|
|
144
157
|
|
|
158
|
+
type RankedNavPage = {
|
|
159
|
+
href: string;
|
|
160
|
+
label: string;
|
|
161
|
+
icon: string;
|
|
162
|
+
order: number;
|
|
163
|
+
group?: string;
|
|
164
|
+
groupIcon?: string;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
function resolvePageGroup(
|
|
168
|
+
href: string,
|
|
169
|
+
meta: PageMeta,
|
|
170
|
+
opts?: NavFromPagesOptions,
|
|
171
|
+
): { group?: string; groupIcon?: string } {
|
|
172
|
+
if (meta.group !== undefined) {
|
|
173
|
+
return meta.group ? { group: meta.group, groupIcon: meta.groupIcon } : {};
|
|
174
|
+
}
|
|
175
|
+
if (opts?.groupExamples && href.startsWith('/examples/') && href !== '/examples/auth') {
|
|
176
|
+
return {
|
|
177
|
+
group: opts.groupExamplesLabel ?? 'Examples',
|
|
178
|
+
groupIcon: opts.groupExamplesIcon ?? 'layout-grid',
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function buildNavFromRanked(ranked: RankedNavPage[]): AppNavItem[] {
|
|
185
|
+
const top: Array<{ order: number; node: AppNavItem }> = [];
|
|
186
|
+
const groups = new Map<string, AppNavItem>();
|
|
187
|
+
|
|
188
|
+
for (const row of ranked) {
|
|
189
|
+
const leaf: AppNavItem = { label: row.label, href: row.href, icon: row.icon };
|
|
190
|
+
if (!row.group) {
|
|
191
|
+
top.push({ order: row.order, node: leaf });
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let parent = groups.get(row.group);
|
|
196
|
+
if (!parent) {
|
|
197
|
+
parent = {
|
|
198
|
+
label: row.group,
|
|
199
|
+
href: row.href,
|
|
200
|
+
icon: row.groupIcon ?? 'folder',
|
|
201
|
+
items: [],
|
|
202
|
+
};
|
|
203
|
+
groups.set(row.group, parent);
|
|
204
|
+
top.push({ order: row.order, node: parent });
|
|
205
|
+
} else {
|
|
206
|
+
const entry = top.find((t) => t.node === parent);
|
|
207
|
+
if (entry) entry.order = Math.min(entry.order, row.order);
|
|
208
|
+
if (row.groupIcon && parent.icon === 'folder') parent.icon = row.groupIcon;
|
|
209
|
+
}
|
|
210
|
+
parent.items!.push(leaf);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
top.sort((a, b) => a.order - b.order || a.node.label.localeCompare(b.node.label));
|
|
214
|
+
return top.map((t) => t.node);
|
|
215
|
+
}
|
|
216
|
+
|
|
145
217
|
/**
|
|
146
218
|
* Build primary sidebar nav from registered pages + collected `pageMeta`.
|
|
147
219
|
* Filters by `nav: false` and optional role overlap; sorts by `order` then path.
|
|
@@ -160,10 +232,11 @@ export function navFromPages(opts?: NavFromPagesOptions): AppNavItem[] {
|
|
|
160
232
|
}
|
|
161
233
|
|
|
162
234
|
const paths = getRegisteredPaths();
|
|
163
|
-
const ranked = paths
|
|
235
|
+
const ranked: RankedNavPage[] = paths
|
|
164
236
|
.map((href) => {
|
|
165
237
|
const meta = pageMetaByPath.get(href) ?? {};
|
|
166
238
|
const order = href === '/' ? 0 : (meta.order ?? 100);
|
|
239
|
+
const { group, groupIcon } = resolvePageGroup(href, meta, opts);
|
|
167
240
|
return {
|
|
168
241
|
href,
|
|
169
242
|
label: meta.label ?? labelFromPath(href),
|
|
@@ -171,6 +244,8 @@ export function navFromPages(opts?: NavFromPagesOptions): AppNavItem[] {
|
|
|
171
244
|
order,
|
|
172
245
|
nav: meta.nav !== false,
|
|
173
246
|
roles: meta.roles,
|
|
247
|
+
group,
|
|
248
|
+
groupIcon,
|
|
174
249
|
};
|
|
175
250
|
})
|
|
176
251
|
.filter((item) => {
|
|
@@ -178,9 +253,10 @@ export function navFromPages(opts?: NavFromPagesOptions): AppNavItem[] {
|
|
|
178
253
|
if (!item.roles || item.roles.length === 0) return true;
|
|
179
254
|
if (viewer.size === 0) return false;
|
|
180
255
|
return item.roles.some((r) => viewer.has(r));
|
|
181
|
-
})
|
|
256
|
+
})
|
|
257
|
+
.map(({ nav: _nav, roles: _roles, ...rest }) => rest);
|
|
182
258
|
ranked.sort((a, b) => a.order - b.order || a.href.localeCompare(b.href));
|
|
183
|
-
return ranked
|
|
259
|
+
return buildNavFromRanked(ranked);
|
|
184
260
|
}
|
|
185
261
|
|
|
186
262
|
/** Test helper: clear page registry + meta map. */
|