@alepha/ui 0.13.6 → 0.13.7
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/admin/AdminAudits-CwvH8e8c.js +215 -0
- package/dist/admin/AdminAudits-CwvH8e8c.js.map +1 -0
- package/dist/admin/AdminAudits-Dv8Vk_6r.js +3 -0
- package/dist/admin/AdminFiles-5CPA3lQk.js +3 -0
- package/dist/admin/{AdminFiles-B_jfB_Py.js → AdminFiles-C_w1tb_x.js} +4 -3
- package/dist/admin/AdminFiles-C_w1tb_x.js.map +1 -0
- package/dist/admin/AdminLayout-BnSmtA4x.js +3 -0
- package/dist/admin/AdminLayout-XiSivwWH.js +39 -0
- package/dist/admin/AdminLayout-XiSivwWH.js.map +1 -0
- package/dist/admin/AdminNotifications-DLjmZWtf.js +3 -0
- package/dist/admin/{AdminNotifications-BFEjqpqx.js → AdminNotifications-DuYy74AN.js} +3 -3
- package/dist/admin/AdminNotifications-DuYy74AN.js.map +1 -0
- package/dist/admin/AdminParameters-DYg48Jwe.js +3 -0
- package/dist/admin/AdminParameters-YagqWTG3.js +575 -0
- package/dist/admin/AdminParameters-YagqWTG3.js.map +1 -0
- package/dist/admin/{AdminSessions-D7DESfWK.js → AdminSessions-BCjgJ-93.js} +4 -4
- package/dist/admin/AdminSessions-BCjgJ-93.js.map +1 -0
- package/dist/admin/AdminSessions-DEh2uN-4.js +3 -0
- package/dist/admin/AdminUserAudits-B_PUXCKC.js +177 -0
- package/dist/admin/AdminUserAudits-B_PUXCKC.js.map +1 -0
- package/dist/admin/AdminUserAudits-D7cTcElL.js +3 -0
- package/dist/admin/{AdminUserCreate-Bhxsn92l.js → AdminUserCreate-DzfRbGZ4.js} +4 -4
- package/dist/admin/AdminUserCreate-DzfRbGZ4.js.map +1 -0
- package/dist/admin/{AdminUserCreate-CYI_xW5T.js → AdminUserCreate-oUA1KDIl.js} +1 -1
- package/dist/admin/{AdminUserDetails-C2y1Ig4n.js → AdminUserDetails-DeTrJm-t.js} +5 -5
- package/dist/admin/AdminUserDetails-DeTrJm-t.js.map +1 -0
- package/dist/admin/{AdminUserDetails-Cmzx9HxH.js → AdminUserDetails-y1H5DW8Y.js} +1 -1
- package/dist/admin/{AdminUserLayout-sW6cjZL0.js → AdminUserLayout-CsfrrZkD.js} +4 -7
- package/dist/admin/AdminUserLayout-CsfrrZkD.js.map +1 -0
- package/dist/admin/{AdminUserLayout-DGSf612u.js → AdminUserLayout-Dejnz13m.js} +1 -1
- package/dist/admin/AdminUserSessions-Bbhcpz4k.js +3 -0
- package/dist/admin/{AdminUserSessions-CvN15wPe.js → AdminUserSessions-DO9H85O-.js} +4 -4
- package/dist/admin/AdminUserSessions-DO9H85O-.js.map +1 -0
- package/dist/admin/{AdminUserSettings-DvaaxgcV.js → AdminUserSettings-B3jA8g3p.js} +4 -4
- package/dist/admin/AdminUserSettings-B3jA8g3p.js.map +1 -0
- package/dist/admin/AdminUserSettings-CE0xpbQc.js +3 -0
- package/dist/admin/AdminUsers-CegGZDhW.js +3 -0
- package/dist/admin/{AdminUsers-BR3C-jrg.js → AdminUsers-ebbrJBT0.js} +13 -17
- package/dist/admin/AdminUsers-ebbrJBT0.js.map +1 -0
- package/dist/admin/index.d.ts +2044 -1044
- package/dist/admin/index.js +65 -62
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/AuthLayout-BAZJHzDG.js +23 -0
- package/dist/auth/AuthLayout-BAZJHzDG.js.map +1 -0
- package/dist/auth/{Login-7HlBjDeV.js → Login-CeNZZjrr.js} +80 -44
- package/dist/auth/Login-CeNZZjrr.js.map +1 -0
- package/dist/auth/Login-hQcu1nlu.js +4 -0
- package/dist/auth/Register-B6HBNVHS.js +4 -0
- package/dist/auth/{Register-CuQr3kgi.js → Register-s4ENeyiE.js} +131 -91
- package/dist/auth/Register-s4ENeyiE.js.map +1 -0
- package/dist/auth/ResetPassword-Cjd-W-Nu.js +3 -0
- package/dist/auth/ResetPassword-GLIFkJT7.js +278 -0
- package/dist/auth/ResetPassword-GLIFkJT7.js.map +1 -0
- package/dist/auth/index.d.ts +471 -426
- package/dist/auth/index.js +26 -18
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +400 -130
- package/dist/core/index.js +1751 -1369
- package/dist/core/index.js.map +1 -1
- package/package.json +15 -11
- package/src/admin/AdminRouter.ts +70 -16
- package/src/admin/components/AdminLayout.tsx +41 -61
- package/src/admin/components/audits/AdminAudits.tsx +240 -0
- package/src/admin/components/{AdminFiles.tsx → files/AdminFiles.tsx} +1 -1
- package/src/admin/components/{AdminJobs.tsx → jobs/AdminJobs.tsx} +1 -1
- package/src/admin/components/parameters/AdminParameters.tsx +137 -0
- package/src/admin/components/parameters/ParameterDetails.tsx +228 -0
- package/src/admin/components/parameters/ParameterHistory.tsx +146 -0
- package/src/admin/components/parameters/ParameterTree.tsx +146 -0
- package/src/admin/components/parameters/types.ts +35 -0
- package/src/admin/components/{AdminSessions.tsx → sessions/AdminSessions.tsx} +1 -1
- package/src/admin/components/users/AdminUserAudits.tsx +183 -0
- package/src/admin/components/{AdminUserCreate.tsx → users/AdminUserCreate.tsx} +1 -1
- package/src/admin/components/{AdminUserLayout.tsx → users/AdminUserLayout.tsx} +1 -4
- package/src/admin/components/{AdminUserSettings.tsx → users/AdminUserSettings.tsx} +1 -1
- package/src/admin/components/{AdminUsers.tsx → users/AdminUsers.tsx} +10 -12
- package/src/admin/index.ts +24 -16
- package/src/auth/AuthRouter.ts +23 -17
- package/src/auth/components/AuthLayout.tsx +6 -3
- package/src/auth/components/Login.tsx +109 -47
- package/src/auth/components/Register.tsx +158 -94
- package/src/auth/components/ResetPassword.tsx +51 -5
- package/src/auth/components/buttons/UserButton.tsx +2 -0
- package/src/core/atoms/alephaThemeAtom.ts +13 -0
- package/src/core/atoms/alephaThemeListAtom.ts +10 -0
- package/src/core/atoms/themes/default.ts +6 -0
- package/src/core/{themes → atoms/themes}/midnight.ts +3 -5
- package/src/core/components/buttons/ActionButton.tsx +33 -26
- package/src/core/components/buttons/DarkModeButton.tsx +0 -1
- package/src/core/components/buttons/ThemeButton.tsx +10 -7
- package/src/core/components/buttons/ToggleSidebarButton.tsx +19 -16
- package/src/core/components/data/ErrorViewer.tsx +171 -0
- package/src/core/components/data/JsonViewer.tsx +147 -138
- package/src/core/components/form/Control.tsx +95 -18
- package/src/core/components/form/ControlArray.tsx +377 -0
- package/src/core/components/form/ControlObject.tsx +127 -0
- package/src/core/components/form/TypeForm.tsx +99 -37
- package/src/core/components/layout/AdminShell.tsx +14 -1
- package/src/core/components/layout/AlephaMantineProvider.tsx +7 -3
- package/src/core/components/layout/Omnibar.tsx +1 -1
- package/src/core/components/layout/Sidebar.tsx +47 -14
- package/src/core/components/table/ColumnPicker.tsx +126 -0
- package/src/core/components/table/DataTable.tsx +354 -181
- package/src/core/components/table/DataTableFilters.tsx +64 -0
- package/src/core/components/table/DataTablePagination.tsx +59 -0
- package/src/core/components/table/DataTableToolbar.tsx +126 -0
- package/src/core/components/table/FilterPicker.tsx +138 -0
- package/src/core/components/table/types.ts +199 -0
- package/src/core/helpers/isComponentType.ts +9 -0
- package/src/core/helpers/renderIcon.tsx +13 -0
- package/src/core/hooks/useTheme.ts +24 -18
- package/src/core/index.ts +24 -3
- package/src/core/interfaces/AlephaTheme.ts +8 -0
- package/src/core/providers/ThemeProvider.ts +44 -62
- package/src/core/services/DialogService.tsx +24 -0
- package/src/core/utils/parseInput.ts +2 -2
- package/styles.css +1 -1
- package/dist/admin/AdminFiles-B-0UcHVV.js +0 -3
- package/dist/admin/AdminFiles-B_jfB_Py.js.map +0 -1
- package/dist/admin/AdminLayout-BMtiXAzS.js +0 -396
- package/dist/admin/AdminLayout-BMtiXAzS.js.map +0 -1
- package/dist/admin/AdminLayout-BNo3GoHR.js +0 -3
- package/dist/admin/AdminNotifications-BFEjqpqx.js.map +0 -1
- package/dist/admin/AdminNotifications-DJs2ZjNj.js +0 -3
- package/dist/admin/AdminSessions-D7DESfWK.js.map +0 -1
- package/dist/admin/AdminSessions-PS2M8iXi.js +0 -3
- package/dist/admin/AdminUserCreate-Bhxsn92l.js.map +0 -1
- package/dist/admin/AdminUserDetails-C2y1Ig4n.js.map +0 -1
- package/dist/admin/AdminUserLayout-sW6cjZL0.js.map +0 -1
- package/dist/admin/AdminUserSessions-CvN15wPe.js.map +0 -1
- package/dist/admin/AdminUserSessions-D-aOcZgV.js +0 -3
- package/dist/admin/AdminUserSettings-CEMhIYrI.js +0 -3
- package/dist/admin/AdminUserSettings-DvaaxgcV.js.map +0 -1
- package/dist/admin/AdminUsers-BR3C-jrg.js.map +0 -1
- package/dist/admin/AdminUsers-CMW9vN09.js +0 -3
- package/dist/auth/AuthLayout-CzwUKD9y.js +0 -19
- package/dist/auth/AuthLayout-CzwUKD9y.js.map +0 -1
- package/dist/auth/Login-7HlBjDeV.js.map +0 -1
- package/dist/auth/Login-C-e27DGb.js +0 -4
- package/dist/auth/Register-CuQr3kgi.js.map +0 -1
- package/dist/auth/Register-DbvXwgbG.js +0 -4
- package/dist/auth/ResetPassword-BzU-cdd4.js +0 -243
- package/dist/auth/ResetPassword-BzU-cdd4.js.map +0 -1
- package/dist/auth/ResetPassword-DSvrdpaA.js +0 -3
- package/src/admin/AdminSidebar.ts +0 -31
- package/src/admin/components/AdminParameters.tsx +0 -24
- package/src/core/themes/aurora.ts +0 -107
- package/src/core/themes/crystal.ts +0 -107
- package/src/core/themes/default.ts +0 -7
- package/src/core/themes/ember.ts +0 -107
- package/src/core/themes/index.ts +0 -7
- package/src/core/themes/remoraid.ts +0 -278
- package/src/core/themes/slate.ts +0 -81
- /package/src/admin/components/{AdminNotifications.tsx → notifications/AdminNotifications.tsx} +0 -0
- /package/src/admin/components/{AdminUserDetails.tsx → users/AdminUserDetails.tsx} +0 -0
- /package/src/admin/components/{AdminUserSessions.tsx → users/AdminUserSessions.tsx} +0 -0
- /package/src/admin/components/{AdminVerifications.tsx → verifications/AdminVerifications.tsx} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FormModel } from "@alepha/react/form";
|
|
2
|
-
import { Flex, Grid } from "@mantine/core";
|
|
2
|
+
import { Card, Flex, type FlexProps, Grid } from "@mantine/core";
|
|
3
3
|
import type { TObject } from "alepha";
|
|
4
4
|
import type { ReactNode } from "react";
|
|
5
5
|
import ActionButton, {
|
|
@@ -21,17 +21,37 @@ export interface TypeFormProps<T extends TObject> {
|
|
|
21
21
|
};
|
|
22
22
|
schema?: TObject;
|
|
23
23
|
children?: (input: FormModel<T>["input"]) => ReactNode;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Control props applied to all fields.
|
|
27
|
+
*/
|
|
24
28
|
controlProps?: Partial<Omit<ControlProps, "input">>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Per-field control props override.
|
|
32
|
+
* Keys are field names from the schema.
|
|
33
|
+
*/
|
|
34
|
+
fieldControlProps?: Record<string, Partial<Omit<ControlProps, "input">>>;
|
|
25
35
|
skipFormElement?: boolean;
|
|
26
36
|
skipSubmitButton?: boolean;
|
|
27
37
|
submitButtonProps?: Partial<Omit<ActionSubmitButtonProps, "form">>;
|
|
28
38
|
resetButtonProps?: Partial<Omit<ActionSubmitButtonProps, "form">>;
|
|
39
|
+
|
|
40
|
+
fill?: boolean;
|
|
41
|
+
flexProps?: FlexProps;
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
/**
|
|
32
45
|
* TypeForm component that automatically renders all form inputs based on schema.
|
|
33
46
|
* Uses the Control component to render individual fields and Mantine Grid for responsive layout.
|
|
34
47
|
*
|
|
48
|
+
* Supports all field types including:
|
|
49
|
+
* - Primitive types (string, number, boolean, etc.)
|
|
50
|
+
* - Enum types (rendered as Select)
|
|
51
|
+
* - Arrays of primitives (rendered as MultiSelect/TagsInput)
|
|
52
|
+
* - Arrays of objects (rendered as ControlArray)
|
|
53
|
+
* - Nested objects (rendered as ControlObject)
|
|
54
|
+
*
|
|
35
55
|
* @example
|
|
36
56
|
* ```tsx
|
|
37
57
|
* import { t } from "alepha";
|
|
@@ -44,6 +64,15 @@ export interface TypeFormProps<T extends TObject> {
|
|
|
44
64
|
* email: t.text(),
|
|
45
65
|
* age: t.integer(),
|
|
46
66
|
* subscribe: t.boolean(),
|
|
67
|
+
* address: t.object({
|
|
68
|
+
* street: t.text(),
|
|
69
|
+
* city: t.text(),
|
|
70
|
+
* }),
|
|
71
|
+
* tags: t.array(t.text()),
|
|
72
|
+
* contacts: t.array(t.object({
|
|
73
|
+
* name: t.text(),
|
|
74
|
+
* email: t.text(),
|
|
75
|
+
* })),
|
|
47
76
|
* }),
|
|
48
77
|
* handler: (values) => {
|
|
49
78
|
* console.log(values);
|
|
@@ -59,6 +88,7 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
59
88
|
columns = 3,
|
|
60
89
|
children,
|
|
61
90
|
controlProps,
|
|
91
|
+
fieldControlProps,
|
|
62
92
|
skipFormElement = false,
|
|
63
93
|
skipSubmitButton = false,
|
|
64
94
|
submitButtonProps,
|
|
@@ -71,30 +101,9 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
71
101
|
|
|
72
102
|
const fieldNames = Object.keys(schema.properties);
|
|
73
103
|
|
|
74
|
-
// Filter
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (!field || typeof field !== "object" || !("schema" in field)) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const schema: any = field.schema;
|
|
82
|
-
|
|
83
|
-
// Skip if it's an object (not supported by Control)
|
|
84
|
-
// Arrays are now supported via ControlSelect (MultiSelect/TagsInput)
|
|
85
|
-
if ("type" in schema) {
|
|
86
|
-
if (schema.type === "object") {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Check if it has properties (nested object)
|
|
92
|
-
if ("properties" in schema && schema.properties) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return true;
|
|
97
|
-
});
|
|
104
|
+
// Filter to only include valid InputFields
|
|
105
|
+
// All types are now supported: primitives, enums, arrays, objects
|
|
106
|
+
const supportedFields = fieldNames;
|
|
98
107
|
|
|
99
108
|
// Handle column configuration with defaults: xs=1, sm=2, lg=3
|
|
100
109
|
const colSpan =
|
|
@@ -122,15 +131,40 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
122
131
|
<Grid>
|
|
123
132
|
{supportedFields.map((fieldName) => {
|
|
124
133
|
const field = form.input[fieldName as keyof typeof form.input];
|
|
134
|
+
const fieldSchema: any = schema.properties[fieldName];
|
|
125
135
|
|
|
126
136
|
// Type guard to ensure field has the expected structure
|
|
127
|
-
if (!field ||
|
|
137
|
+
if (!field || !fieldSchema) {
|
|
128
138
|
return null;
|
|
129
139
|
}
|
|
130
140
|
|
|
141
|
+
// Determine if this is a complex type (object or array of objects)
|
|
142
|
+
// that should span full width
|
|
143
|
+
const isObject =
|
|
144
|
+
fieldSchema &&
|
|
145
|
+
"type" in fieldSchema &&
|
|
146
|
+
fieldSchema.type === "object";
|
|
147
|
+
|
|
148
|
+
const isArrayOfObjects =
|
|
149
|
+
fieldSchema &&
|
|
150
|
+
"type" in fieldSchema &&
|
|
151
|
+
fieldSchema.type === "array" &&
|
|
152
|
+
"items" in fieldSchema &&
|
|
153
|
+
fieldSchema.items &&
|
|
154
|
+
"properties" in fieldSchema.items;
|
|
155
|
+
|
|
156
|
+
// Complex types span full width, primitives use grid columns
|
|
157
|
+
const span = isObject || isArrayOfObjects ? 12 : colSpan;
|
|
158
|
+
|
|
159
|
+
// Merge control props: base controlProps + field-specific overrides
|
|
160
|
+
const mergedControlProps = {
|
|
161
|
+
...controlProps,
|
|
162
|
+
...fieldControlProps?.[fieldName],
|
|
163
|
+
};
|
|
164
|
+
|
|
131
165
|
return (
|
|
132
|
-
<Grid.Col key={fieldName} span={
|
|
133
|
-
<Control input={field
|
|
166
|
+
<Grid.Col key={fieldName} span={span}>
|
|
167
|
+
<Control input={field} {...mergedControlProps} />
|
|
134
168
|
</Grid.Col>
|
|
135
169
|
);
|
|
136
170
|
})}
|
|
@@ -139,15 +173,34 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
139
173
|
};
|
|
140
174
|
|
|
141
175
|
const content = (
|
|
142
|
-
<Flex
|
|
143
|
-
{
|
|
176
|
+
<Flex
|
|
177
|
+
direction={"column"}
|
|
178
|
+
gap={"sm"}
|
|
179
|
+
flex={props.fill ? 1 : undefined}
|
|
180
|
+
{...props.flexProps}
|
|
181
|
+
>
|
|
182
|
+
<Flex direction={"column"} gap={"sm"} flex={1}>
|
|
183
|
+
{renderFields()}
|
|
184
|
+
</Flex>
|
|
144
185
|
{!skipSubmitButton && (
|
|
145
|
-
<
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
186
|
+
<Card w={"100%"} withBorder>
|
|
187
|
+
<Flex gap={"sm"} flex={1}>
|
|
188
|
+
<Flex></Flex>
|
|
189
|
+
<Flex flex={1}></Flex>
|
|
190
|
+
<Flex gap={"sm"}>
|
|
191
|
+
<ActionButton variant={"subtle"} type={"reset"}>
|
|
192
|
+
Reset
|
|
193
|
+
</ActionButton>
|
|
194
|
+
<ActionButton
|
|
195
|
+
intent={"primary"}
|
|
196
|
+
form={form}
|
|
197
|
+
{...submitButtonProps}
|
|
198
|
+
>
|
|
199
|
+
{submitButtonProps?.children ?? "Submit"}
|
|
200
|
+
</ActionButton>
|
|
201
|
+
</Flex>
|
|
202
|
+
</Flex>
|
|
203
|
+
</Card>
|
|
151
204
|
)}
|
|
152
205
|
</Flex>
|
|
153
206
|
);
|
|
@@ -156,7 +209,16 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
156
209
|
return content;
|
|
157
210
|
}
|
|
158
211
|
|
|
159
|
-
return
|
|
212
|
+
return (
|
|
213
|
+
<Flex
|
|
214
|
+
component={"form"}
|
|
215
|
+
flex={props.fill ? 1 : undefined}
|
|
216
|
+
{...form.props}
|
|
217
|
+
{...props.flexProps}
|
|
218
|
+
>
|
|
219
|
+
{content}
|
|
220
|
+
</Flex>
|
|
221
|
+
);
|
|
160
222
|
};
|
|
161
223
|
|
|
162
224
|
export default TypeForm;
|
|
@@ -91,6 +91,10 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
91
91
|
const hasSidebar = showSidebar && props.sidebarProps !== undefined;
|
|
92
92
|
const hasAppBar = hasSidebar || props.appBarProps || props.header;
|
|
93
93
|
|
|
94
|
+
const headerHeight = hasAppBar ? 60 : 0;
|
|
95
|
+
const footerHeight = props.footer ? 24 : 0;
|
|
96
|
+
const sidebarWidth = hasSidebar ? (collapsed ? 78 : 300) : 0;
|
|
97
|
+
|
|
94
98
|
return (
|
|
95
99
|
<AppShell
|
|
96
100
|
w={"100%"}
|
|
@@ -121,7 +125,16 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
121
125
|
</AppShell.Navbar>
|
|
122
126
|
)}
|
|
123
127
|
|
|
124
|
-
<AppShell.Main
|
|
128
|
+
<AppShell.Main
|
|
129
|
+
pl={sidebarWidth}
|
|
130
|
+
pt={headerHeight}
|
|
131
|
+
pb={footerHeight}
|
|
132
|
+
pr={0}
|
|
133
|
+
display={"flex"}
|
|
134
|
+
flex={1}
|
|
135
|
+
style={{ flexDirection: "column" }}
|
|
136
|
+
{...props.appShellMainProps}
|
|
137
|
+
>
|
|
125
138
|
{props.children ?? <NestedView />}
|
|
126
139
|
</AppShell.Main>
|
|
127
140
|
|
|
@@ -22,7 +22,7 @@ export interface AlephaMantineProviderProps {
|
|
|
22
22
|
navigationProgress?: NavigationProgressProps;
|
|
23
23
|
notifications?: NotificationsProps;
|
|
24
24
|
modals?: ModalsProviderProps;
|
|
25
|
-
omnibar?: OmnibarProps;
|
|
25
|
+
omnibar?: OmnibarProps | false;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const AlephaMantineProvider = (props: AlephaMantineProviderProps) => {
|
|
@@ -53,14 +53,18 @@ const AlephaMantineProvider = (props: AlephaMantineProviderProps) => {
|
|
|
53
53
|
[],
|
|
54
54
|
);
|
|
55
55
|
|
|
56
|
+
const defaultColorScheme =
|
|
57
|
+
props.mantine?.defaultColorScheme ?? theme.defaultColorScheme;
|
|
58
|
+
|
|
56
59
|
return (
|
|
57
60
|
<>
|
|
58
61
|
<ColorSchemeScript
|
|
59
|
-
defaultColorScheme={
|
|
62
|
+
defaultColorScheme={defaultColorScheme}
|
|
60
63
|
{...props.colorSchemeScript}
|
|
61
64
|
/>
|
|
62
65
|
<MantineProvider
|
|
63
66
|
{...props.mantine}
|
|
67
|
+
defaultColorScheme={defaultColorScheme}
|
|
64
68
|
theme={{
|
|
65
69
|
// Spread all theme properties from the selected theme
|
|
66
70
|
...theme,
|
|
@@ -71,7 +75,7 @@ const AlephaMantineProvider = (props: AlephaMantineProviderProps) => {
|
|
|
71
75
|
<Notifications {...props.notifications} />
|
|
72
76
|
<NavigationProgress {...props.navigationProgress} />
|
|
73
77
|
<ModalsProvider {...props.modals}>
|
|
74
|
-
<Omnibar {...props.omnibar} />
|
|
78
|
+
{props.omnibar !== false && <Omnibar {...props.omnibar} />}
|
|
75
79
|
{props.children ?? <NestedView />}
|
|
76
80
|
</ModalsProvider>
|
|
77
81
|
</MantineProvider>
|
|
@@ -3,7 +3,7 @@ import { Spotlight, type SpotlightActionData } from "@mantine/spotlight";
|
|
|
3
3
|
import { IconSearch } from "@tabler/icons-react";
|
|
4
4
|
import { type ReactNode, useMemo } from "react";
|
|
5
5
|
import { ui } from "../../constants/ui.ts";
|
|
6
|
-
import { renderIcon } from "
|
|
6
|
+
import { renderIcon } from "../../helpers/renderIcon.tsx";
|
|
7
7
|
|
|
8
8
|
export interface OmnibarProps {
|
|
9
9
|
shortcut?: string | string[];
|
|
@@ -14,13 +14,13 @@ import {
|
|
|
14
14
|
type ComponentType,
|
|
15
15
|
type ReactNode,
|
|
16
16
|
useCallback,
|
|
17
|
+
useMemo,
|
|
17
18
|
useState,
|
|
18
19
|
} from "react";
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
renderIcon,
|
|
22
|
-
} from "../buttons/ActionButton.tsx";
|
|
20
|
+
import { renderIcon } from "../../helpers/renderIcon.tsx";
|
|
21
|
+
import ActionButton, { type ActionProps } from "../buttons/ActionButton.tsx";
|
|
23
22
|
import OmnibarButton from "../buttons/OmnibarButton.tsx";
|
|
23
|
+
import ToggleSidebarButton from "../buttons/ToggleSidebarButton.tsx";
|
|
24
24
|
|
|
25
25
|
export interface SidebarProps {
|
|
26
26
|
menu?: SidebarNode[];
|
|
@@ -35,6 +35,15 @@ export interface SidebarProps {
|
|
|
35
35
|
hide?: {
|
|
36
36
|
paths?: string[];
|
|
37
37
|
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Automatically populate the menu from the router's pages.
|
|
41
|
+
*/
|
|
42
|
+
autoPopulateMenu?:
|
|
43
|
+
| boolean
|
|
44
|
+
| {
|
|
45
|
+
startsWith: string;
|
|
46
|
+
};
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
export const Sidebar = (props: SidebarProps) => {
|
|
@@ -63,6 +72,10 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
63
72
|
return <OmnibarButton collapsed={props.collapsed} key={key} />;
|
|
64
73
|
}
|
|
65
74
|
|
|
75
|
+
if (item.type === "toggle") {
|
|
76
|
+
return <ToggleSidebarButton key={key} />;
|
|
77
|
+
}
|
|
78
|
+
|
|
66
79
|
if (item.type === "section") {
|
|
67
80
|
if (props.collapsed) return;
|
|
68
81
|
return (
|
|
@@ -114,16 +127,29 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
114
127
|
);
|
|
115
128
|
};
|
|
116
129
|
|
|
130
|
+
const getSidebarNodes = (): SidebarNode[] => {
|
|
131
|
+
if (props.menu) return props.menu;
|
|
132
|
+
if (props.autoPopulateMenu) {
|
|
133
|
+
const items = router.concretePages.map((page) => ({
|
|
134
|
+
label: page.label ?? page.name,
|
|
135
|
+
description: page.description?.slice(0, 32),
|
|
136
|
+
icon: renderIcon(page.icon),
|
|
137
|
+
href: router.path(page.name),
|
|
138
|
+
})) as SidebarMenuItem[];
|
|
139
|
+
if (
|
|
140
|
+
typeof props.autoPopulateMenu === "object" &&
|
|
141
|
+
props.autoPopulateMenu.startsWith
|
|
142
|
+
) {
|
|
143
|
+
const startsWith = props.autoPopulateMenu.startsWith;
|
|
144
|
+
return items.filter((item) => item.href?.startsWith(startsWith));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return [];
|
|
148
|
+
};
|
|
149
|
+
|
|
117
150
|
const padding = "md";
|
|
118
|
-
const gap = props.gap;
|
|
119
|
-
const menu =
|
|
120
|
-
props.menu ??
|
|
121
|
-
(router.concretePages.map((page) => ({
|
|
122
|
-
label: page.label ?? page.name,
|
|
123
|
-
description: page.description,
|
|
124
|
-
icon: renderIcon(page.icon),
|
|
125
|
-
href: router.path(page.name),
|
|
126
|
-
})) as SidebarMenuItem[]);
|
|
151
|
+
const gap = props.menu ? props.gap : "xs";
|
|
152
|
+
const menu = useMemo(() => getSidebarNodes(), []);
|
|
127
153
|
|
|
128
154
|
return (
|
|
129
155
|
<Flex
|
|
@@ -229,6 +255,8 @@ export const SidebarItem = (props: SidebarItemProps) => {
|
|
|
229
255
|
props.theme.button?.size ??
|
|
230
256
|
(level === 0 ? "sm" : "xs")
|
|
231
257
|
}
|
|
258
|
+
c={"var(--mantine-color-text)"}
|
|
259
|
+
color={"gray"}
|
|
232
260
|
variant={"subtle"}
|
|
233
261
|
variantActive={"default"}
|
|
234
262
|
radius={props.item.theme?.radius ?? props.theme.button?.radius ?? "md"}
|
|
@@ -385,7 +413,8 @@ export type SidebarNode =
|
|
|
385
413
|
| SidebarDivider
|
|
386
414
|
| SidebarSearch
|
|
387
415
|
| SidebarElement
|
|
388
|
-
| SidebarSection
|
|
416
|
+
| SidebarSection
|
|
417
|
+
| SidebarToggle;
|
|
389
418
|
|
|
390
419
|
export interface SidebarAbstractItem {
|
|
391
420
|
position?: "top" | "bottom";
|
|
@@ -407,6 +436,10 @@ export interface SidebarSearch extends SidebarAbstractItem {
|
|
|
407
436
|
type: "search";
|
|
408
437
|
}
|
|
409
438
|
|
|
439
|
+
export interface SidebarToggle extends SidebarAbstractItem {
|
|
440
|
+
type: "toggle";
|
|
441
|
+
}
|
|
442
|
+
|
|
410
443
|
export interface SidebarSection extends SidebarAbstractItem {
|
|
411
444
|
type: "section";
|
|
412
445
|
label: string;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
Checkbox,
|
|
4
|
+
Group,
|
|
5
|
+
Popover,
|
|
6
|
+
ScrollArea,
|
|
7
|
+
Stack,
|
|
8
|
+
Text,
|
|
9
|
+
} from "@mantine/core";
|
|
10
|
+
import { IconColumns } from "@tabler/icons-react";
|
|
11
|
+
import type { TObject } from "alepha";
|
|
12
|
+
import { useState } from "react";
|
|
13
|
+
import { ui } from "../../constants/ui.ts";
|
|
14
|
+
import ActionButton from "../buttons/ActionButton.tsx";
|
|
15
|
+
import type { ColumnVisibility, DataTableColumn } from "./types.ts";
|
|
16
|
+
|
|
17
|
+
export interface ColumnPickerProps<T extends object, Filters extends TObject> {
|
|
18
|
+
columns: { [key: string]: DataTableColumn<T, Filters> };
|
|
19
|
+
visibility: ColumnVisibility;
|
|
20
|
+
onVisibilityChange: (visibility: ColumnVisibility) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ColumnPicker = <T extends object, Filters extends TObject>({
|
|
24
|
+
columns,
|
|
25
|
+
visibility,
|
|
26
|
+
onVisibilityChange,
|
|
27
|
+
}: ColumnPickerProps<T, Filters>) => {
|
|
28
|
+
const [opened, setOpened] = useState(false);
|
|
29
|
+
const columnEntries = Object.entries(columns);
|
|
30
|
+
|
|
31
|
+
const handleShowAll = () => {
|
|
32
|
+
const newVisibility = columnEntries.reduce(
|
|
33
|
+
(acc, [key]) => ({ ...acc, [key]: true }),
|
|
34
|
+
{} as ColumnVisibility,
|
|
35
|
+
);
|
|
36
|
+
onVisibilityChange(newVisibility);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleHideAll = () => {
|
|
40
|
+
const newVisibility = columnEntries.reduce(
|
|
41
|
+
(acc, [key]) => ({ ...acc, [key]: false }),
|
|
42
|
+
{} as ColumnVisibility,
|
|
43
|
+
);
|
|
44
|
+
onVisibilityChange(newVisibility);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleToggle = (key: string, checked: boolean) => {
|
|
48
|
+
onVisibilityChange({
|
|
49
|
+
...visibility,
|
|
50
|
+
[key]: checked,
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const visibleCount = columnEntries.filter(
|
|
55
|
+
([key]) => visibility[key] !== false,
|
|
56
|
+
).length;
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Popover
|
|
60
|
+
width={280}
|
|
61
|
+
position="bottom-start"
|
|
62
|
+
shadow="md"
|
|
63
|
+
opened={opened}
|
|
64
|
+
onChange={setOpened}
|
|
65
|
+
closeOnClickOutside
|
|
66
|
+
closeOnEscape
|
|
67
|
+
transitionProps={{
|
|
68
|
+
transition: "fade-up",
|
|
69
|
+
duration: 200,
|
|
70
|
+
timingFunction: "ease",
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<Popover.Target>
|
|
74
|
+
<ActionButton variant="subtle" icon={IconColumns} />
|
|
75
|
+
</Popover.Target>
|
|
76
|
+
<Popover.Dropdown
|
|
77
|
+
bg="transparent"
|
|
78
|
+
p="xs"
|
|
79
|
+
bd={`1px solid ${ui.colors.border}`}
|
|
80
|
+
style={{
|
|
81
|
+
backdropFilter: "blur(20px)",
|
|
82
|
+
}}
|
|
83
|
+
>
|
|
84
|
+
<Stack gap="xs" bg={ui.colors.surface} p="sm" bdrs="sm">
|
|
85
|
+
<Group justify="space-between">
|
|
86
|
+
<Text size="sm" fw={500}>
|
|
87
|
+
Columns ({visibleCount}/{columnEntries.length})
|
|
88
|
+
</Text>
|
|
89
|
+
<Group gap={4}>
|
|
90
|
+
<Button
|
|
91
|
+
size="compact-xs"
|
|
92
|
+
variant="subtle"
|
|
93
|
+
onClick={handleShowAll}
|
|
94
|
+
>
|
|
95
|
+
All
|
|
96
|
+
</Button>
|
|
97
|
+
<Button
|
|
98
|
+
size="compact-xs"
|
|
99
|
+
variant="subtle"
|
|
100
|
+
onClick={handleHideAll}
|
|
101
|
+
>
|
|
102
|
+
None
|
|
103
|
+
</Button>
|
|
104
|
+
</Group>
|
|
105
|
+
</Group>
|
|
106
|
+
|
|
107
|
+
<ScrollArea.Autosize mah={300}>
|
|
108
|
+
<Stack gap={4}>
|
|
109
|
+
{columnEntries.map(([key, col]) => (
|
|
110
|
+
<Checkbox
|
|
111
|
+
key={key}
|
|
112
|
+
label={col.label}
|
|
113
|
+
checked={visibility[key] !== false}
|
|
114
|
+
onChange={(e) => handleToggle(key, e.currentTarget.checked)}
|
|
115
|
+
size="sm"
|
|
116
|
+
/>
|
|
117
|
+
))}
|
|
118
|
+
</Stack>
|
|
119
|
+
</ScrollArea.Autosize>
|
|
120
|
+
</Stack>
|
|
121
|
+
</Popover.Dropdown>
|
|
122
|
+
</Popover>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default ColumnPicker;
|