@alepha/ui 0.18.0 → 0.18.2

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 (187) hide show
  1. package/dist/admin/{AdminApiKeys-C-6_Q-lH.js → AdminApiKeys-BJhIwfD6.js} +17 -38
  2. package/dist/admin/AdminApiKeys-BJhIwfD6.js.map +1 -0
  3. package/dist/admin/{AdminAudits-Bgbf04hO.js → AdminAudits-DzD_4cDt.js} +23 -19
  4. package/dist/admin/AdminAudits-DzD_4cDt.js.map +1 -0
  5. package/dist/admin/AdminDashboard-C92tIc6x.js +67 -0
  6. package/dist/admin/AdminDashboard-C92tIc6x.js.map +1 -0
  7. package/dist/admin/{AdminFiles-B9a7G3cY.js → AdminFiles-DLpfhBkf.js} +3 -7
  8. package/dist/admin/AdminFiles-DLpfhBkf.js.map +1 -0
  9. package/dist/admin/{AdminJobDashboard-DaTwf5OY.js → AdminJobDashboard-KIOkeMgE.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-DaTwf5OY.js.map → AdminJobDashboard-KIOkeMgE.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-B9cek5dl.js → AdminJobExecutions-D0Yo_PU0.js} +24 -36
  12. package/dist/admin/AdminJobExecutions-D0Yo_PU0.js.map +1 -0
  13. package/dist/admin/{AdminJobRegistry-DFgV3oqx.js → AdminJobRegistry-PFajqaGK.js} +10 -18
  14. package/dist/admin/AdminJobRegistry-PFajqaGK.js.map +1 -0
  15. package/dist/admin/AdminLayout-B1DXZHDn.js +61 -0
  16. package/dist/admin/AdminLayout-B1DXZHDn.js.map +1 -0
  17. package/dist/admin/{AdminParameters-DHw9ATgl.js → AdminParameters-BspPeqp_.js} +2 -2
  18. package/dist/admin/{AdminParameters-DHw9ATgl.js.map → AdminParameters-BspPeqp_.js.map} +1 -1
  19. package/dist/admin/{AdminSessions-BhGJPI3z.js → AdminSessions-BnH5CZQl.js} +48 -53
  20. package/dist/admin/AdminSessions-BnH5CZQl.js.map +1 -0
  21. package/dist/admin/{AdminUserLayout-BdC4Te8m.js → AdminUserLayout-DUbC6-BI.js} +2 -2
  22. package/dist/admin/{AdminUserLayout-BdC4Te8m.js.map → AdminUserLayout-DUbC6-BI.js.map} +1 -1
  23. package/dist/admin/{AdminUserProfile-DAt23fqY.js → AdminUserProfile-DuTUnjdG.js} +3 -3
  24. package/dist/admin/{AdminUserProfile-DAt23fqY.js.map → AdminUserProfile-DuTUnjdG.js.map} +1 -1
  25. package/dist/admin/{AdminUserSessions-1uzcx02z.js → AdminUserSessions-DvZdAGpL.js} +33 -35
  26. package/dist/admin/AdminUserSessions-DvZdAGpL.js.map +1 -0
  27. package/dist/admin/AdminUsers-CR9z0g_5.js +206 -0
  28. package/dist/admin/AdminUsers-CR9z0g_5.js.map +1 -0
  29. package/dist/admin/{AuthLayout-DFJvCvzw.js → AuthLayout-DsUfp9RG.js} +2 -2
  30. package/dist/admin/{AuthLayout-DFJvCvzw.js.map → AuthLayout-DsUfp9RG.js.map} +1 -1
  31. package/dist/admin/{IconGoogle-CSQLPYwX.js → IconGoogle-Ch1m3Uzl.js} +1 -1
  32. package/dist/admin/{IconGoogle-CSQLPYwX.js.map → IconGoogle-Ch1m3Uzl.js.map} +1 -1
  33. package/dist/admin/{Login-BGheURrg.js → Login-DHbYJKwg.js} +3 -3
  34. package/dist/{auth/Login-Denw_UGy.js.map → admin/Login-DHbYJKwg.js.map} +1 -1
  35. package/dist/{auth/Profile-BMX_Ar_s.js → admin/Profile-B2EcIDB9.js} +2 -2
  36. package/dist/{auth/Profile-BMX_Ar_s.js.map → admin/Profile-B2EcIDB9.js.map} +1 -1
  37. package/dist/admin/{Register-Cs10l8vX.js → Register-Z3fxRbUF.js} +3 -3
  38. package/dist/{demo/Register-a70LPgs2.js.map → admin/Register-Z3fxRbUF.js.map} +1 -1
  39. package/dist/admin/{ResetPassword-BwDdfkGH.js → ResetPassword-_Y1qTTKh.js} +2 -2
  40. package/dist/admin/{ResetPassword-BwDdfkGH.js.map → ResetPassword-_Y1qTTKh.js.map} +1 -1
  41. package/dist/admin/{VerifyEmail-DfXHAiQl.js → VerifyEmail-Bg22bwcC.js} +2 -2
  42. package/dist/admin/{VerifyEmail-DfXHAiQl.js.map → VerifyEmail-Bg22bwcC.js.map} +1 -1
  43. package/dist/admin/{core-2xoLiT0o.js → core-BVO_TQxb.js} +1474 -233
  44. package/dist/admin/core-BVO_TQxb.js.map +1 -0
  45. package/dist/admin/index.d.ts +29 -4
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +448 -69
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/auth/{AuthLayout-CAE1pX9s.js → AuthLayout-C161NeF6.js} +2 -2
  50. package/dist/auth/{AuthLayout-CAE1pX9s.js.map → AuthLayout-C161NeF6.js.map} +1 -1
  51. package/dist/auth/{Login-Denw_UGy.js → Login-C7jIqf00.js} +2 -2
  52. package/dist/{admin/Login-BGheURrg.js.map → auth/Login-C7jIqf00.js.map} +1 -1
  53. package/dist/{admin/Profile-B-c9pCPf.js → auth/Profile-BMpXJ0oi.js} +2 -2
  54. package/dist/{demo/Profile-CWqti7FB.js.map → auth/Profile-BMpXJ0oi.js.map} +1 -1
  55. package/dist/auth/{Register-6hi_cpfF.js → Register-2gx8qll-.js} +2 -2
  56. package/dist/auth/{Register-6hi_cpfF.js.map → Register-2gx8qll-.js.map} +1 -1
  57. package/dist/{demo/ResetPassword-DWN0lzr5.js → auth/ResetPassword-DBxt9hKk.js} +2 -2
  58. package/dist/auth/{ResetPassword-CqfTk1FI.js.map → ResetPassword-DBxt9hKk.js.map} +1 -1
  59. package/dist/{demo/VerifyEmail-DZWL72K4.js → auth/VerifyEmail-Z80Ubajk.js} +2 -2
  60. package/dist/auth/{VerifyEmail-nWiSTMjF.js.map → VerifyEmail-Z80Ubajk.js.map} +1 -1
  61. package/dist/auth/{core-niW0sFLv.js → core-DyfeVr5c.js} +1002 -38
  62. package/dist/auth/core-DyfeVr5c.js.map +1 -0
  63. package/dist/auth/index.d.ts +12 -1
  64. package/dist/auth/index.d.ts.map +1 -1
  65. package/dist/auth/index.js +12 -13
  66. package/dist/auth/index.js.map +1 -1
  67. package/dist/core/index.d.ts +95 -14
  68. package/dist/core/index.d.ts.map +1 -1
  69. package/dist/core/index.js +1473 -232
  70. package/dist/core/index.js.map +1 -1
  71. package/dist/demo/{AuthLayout-jLa0aKsI.js → AuthLayout-DN-ClJQk.js} +2 -2
  72. package/dist/demo/{AuthLayout-jLa0aKsI.js.map → AuthLayout-DN-ClJQk.js.map} +1 -1
  73. package/dist/demo/{DemoButton-BmaWZVwf.js → DemoButton-CGUyR9eM.js} +3 -3
  74. package/dist/demo/{DemoButton-BmaWZVwf.js.map → DemoButton-CGUyR9eM.js.map} +1 -1
  75. package/dist/demo/{DemoDataTable-Z9xyV221.js → DemoDataTable-QFG-xXSx.js} +15 -19
  76. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +1 -0
  77. package/dist/demo/{DemoDialog-4ItHLf9t.js → DemoDialog-DW8QEvD1.js} +2 -2
  78. package/dist/demo/{DemoDialog-4ItHLf9t.js.map → DemoDialog-DW8QEvD1.js.map} +1 -1
  79. package/dist/demo/{DemoFlex-EtVq8QfX.js → DemoFlex-CAhLUanT.js} +3 -3
  80. package/dist/demo/{DemoFlex-EtVq8QfX.js.map → DemoFlex-CAhLUanT.js.map} +1 -1
  81. package/dist/demo/{DemoHeading-BS-vGfkI.js → DemoHeading-yIFmNjHB.js} +3 -3
  82. package/dist/demo/{DemoHeading-BS-vGfkI.js.map → DemoHeading-yIFmNjHB.js.map} +1 -1
  83. package/dist/demo/{DemoHome-Clbn8AmS.js → DemoHome-BSGuBHus.js} +2 -2
  84. package/dist/demo/{DemoHome-Clbn8AmS.js.map → DemoHome-BSGuBHus.js.map} +1 -1
  85. package/dist/demo/{DemoJsonViewer-DkIX_ky2.js → DemoJsonViewer-DsA2IpgV.js} +3 -3
  86. package/dist/demo/{DemoJsonViewer-DkIX_ky2.js.map → DemoJsonViewer-DsA2IpgV.js.map} +1 -1
  87. package/dist/demo/{DemoLayout-C56xb5EE.js → DemoLayout-Cy6xjn6P.js} +2 -2
  88. package/dist/demo/{DemoLayout-C56xb5EE.js.map → DemoLayout-Cy6xjn6P.js.map} +1 -1
  89. package/dist/demo/{DemoLogin-BZwpicOS.js → DemoLogin-vqxgTu4P.js} +8 -8
  90. package/dist/demo/{DemoLogin-BZwpicOS.js.map → DemoLogin-vqxgTu4P.js.map} +1 -1
  91. package/dist/demo/{DemoRegister-C7_qc4MJ.js → DemoRegister-YHPvPg77.js} +8 -8
  92. package/dist/demo/{DemoRegister-C7_qc4MJ.js.map → DemoRegister-YHPvPg77.js.map} +1 -1
  93. package/dist/demo/{DemoResetPassword-BI1Ct4Dw.js → DemoResetPassword-mOW18Zlm.js} +8 -8
  94. package/dist/demo/{DemoResetPassword-BI1Ct4Dw.js.map → DemoResetPassword-mOW18Zlm.js.map} +1 -1
  95. package/dist/demo/{DemoSidebar-CcBo4ltC.js → DemoSidebar-od7aLjP_.js} +3 -3
  96. package/dist/demo/{DemoSidebar-CcBo4ltC.js.map → DemoSidebar-od7aLjP_.js.map} +1 -1
  97. package/dist/demo/{DemoText-CzXuUn3g.js → DemoText-DU3JeRS0.js} +3 -3
  98. package/dist/demo/{DemoText-CzXuUn3g.js.map → DemoText-DU3JeRS0.js.map} +1 -1
  99. package/dist/demo/{DemoToast-BgHDhWrX.js → DemoToast-CUJEiPRa.js} +2 -2
  100. package/dist/demo/{DemoToast-BgHDhWrX.js.map → DemoToast-CUJEiPRa.js.map} +1 -1
  101. package/dist/demo/{DemoTypeForm-DDzWoMSV.js → DemoTypeForm-C1dNkahD.js} +3 -3
  102. package/dist/demo/{DemoTypeForm-DDzWoMSV.js.map → DemoTypeForm-C1dNkahD.js.map} +1 -1
  103. package/dist/demo/{DemoVerifyEmail-C_Irdnov.js → DemoVerifyEmail-D9EcXZ38.js} +8 -8
  104. package/dist/demo/{DemoVerifyEmail-C_Irdnov.js.map → DemoVerifyEmail-D9EcXZ38.js.map} +1 -1
  105. package/dist/demo/{Login-hSOU3jZc.js → Login-CoYf_P_F.js} +2 -2
  106. package/dist/demo/{Login-hSOU3jZc.js.map → Login-CoYf_P_F.js.map} +1 -1
  107. package/dist/demo/{Profile-CWqti7FB.js → Profile-BE_Y3co2.js} +2 -2
  108. package/dist/{admin/Profile-B-c9pCPf.js.map → demo/Profile-BE_Y3co2.js.map} +1 -1
  109. package/dist/demo/{Register-a70LPgs2.js → Register-fXHmBpr3.js} +2 -2
  110. package/dist/{admin/Register-Cs10l8vX.js.map → demo/Register-fXHmBpr3.js.map} +1 -1
  111. package/dist/{auth/ResetPassword-CqfTk1FI.js → demo/ResetPassword-CAPj8MO3.js} +2 -2
  112. package/dist/demo/{ResetPassword-DWN0lzr5.js.map → ResetPassword-CAPj8MO3.js.map} +1 -1
  113. package/dist/demo/{Showcase-Dq3MISpd.js → Showcase-BtEU0pY9.js} +2 -2
  114. package/dist/demo/{Showcase-Dq3MISpd.js.map → Showcase-BtEU0pY9.js.map} +1 -1
  115. package/dist/{auth/VerifyEmail-nWiSTMjF.js → demo/VerifyEmail-DFmdCdYs.js} +2 -2
  116. package/dist/demo/{VerifyEmail-DZWL72K4.js.map → VerifyEmail-DFmdCdYs.js.map} +1 -1
  117. package/dist/demo/{auth-d6n3xbug.js → auth-Djd7SKiw.js} +8 -8
  118. package/dist/demo/{auth-d6n3xbug.js.map → auth-Djd7SKiw.js.map} +1 -1
  119. package/dist/demo/{core-RCUw1Q-a.js → core-B7LNjM78.js} +1484 -226
  120. package/dist/demo/core-B7LNjM78.js.map +1 -0
  121. package/dist/demo/index.js +17 -17
  122. package/package.json +4 -4
  123. package/src/admin/{AdminRouter.ts → AdminRouter.tsx} +128 -19
  124. package/src/admin/components/AdminDashboard.tsx +52 -0
  125. package/src/admin/components/AdminLayout.tsx +32 -40
  126. package/src/admin/components/audits/AdminAudits.tsx +22 -16
  127. package/src/admin/components/files/AdminFiles.tsx +1 -6
  128. package/src/admin/components/jobs/AdminJobExecutions.tsx +33 -39
  129. package/src/admin/components/jobs/AdminJobRegistry.tsx +9 -18
  130. package/src/admin/components/keys/AdminApiKeys.tsx +23 -41
  131. package/src/admin/components/sessions/AdminSessions.tsx +71 -71
  132. package/src/admin/components/users/AdminUserSessions.tsx +33 -31
  133. package/src/admin/components/users/AdminUsers.tsx +184 -72
  134. package/src/admin/index.ts +2 -2
  135. package/src/admin/primitives/$uiAdmin.ts +1 -1
  136. package/src/auth/components/buttons/UserButton.tsx +1 -3
  137. package/src/core/atoms/alephaSidebarAtom.ts +1 -1
  138. package/src/core/atoms/alephaThemeListAtom.ts +14 -1
  139. package/src/core/atoms/alephaThemeOverridesAtom.ts +17 -0
  140. package/src/core/atoms/themes/editorial.ts +184 -0
  141. package/src/core/atoms/themes/monochrome.ts +197 -0
  142. package/src/core/atoms/themes/rosePine.ts +208 -0
  143. package/src/core/atoms/themes/softBrutalism.ts +221 -0
  144. package/src/core/atoms/themes/terminal.ts +186 -0
  145. package/src/core/components/Flex.tsx +91 -1
  146. package/src/core/components/Text.tsx +1 -1
  147. package/src/core/components/buttons/ActionButton.tsx +15 -19
  148. package/src/core/components/buttons/DarkModeButton.tsx +3 -3
  149. package/src/core/components/buttons/LanguageButton.tsx +1 -1
  150. package/src/core/components/buttons/OmnibarButton.tsx +1 -2
  151. package/src/core/components/buttons/ThemeButton.tsx +40 -11
  152. package/src/core/components/buttons/ThemeExpertModal.tsx +184 -0
  153. package/src/core/components/buttons/ToggleSidebarButton.tsx +1 -2
  154. package/src/core/components/layout/AppBar.tsx +10 -0
  155. package/src/core/components/layout/DashboardShell.tsx +10 -7
  156. package/src/core/components/layout/Sidebar.tsx +60 -52
  157. package/src/core/constants/ui.ts +5 -5
  158. package/src/core/hooks/useTheme.ts +26 -3
  159. package/src/core/index.ts +6 -1
  160. package/src/core/interfaces/AlephaTheme.ts +2 -0
  161. package/src/core/providers/ThemeProvider.ts +108 -8
  162. package/src/core/services/DialogService.tsx +24 -3
  163. package/src/core/styles.css +26 -23
  164. package/src/core/table/components/DataTable.tsx +167 -137
  165. package/src/core/table/components/DataTableFilters.tsx +1 -6
  166. package/src/core/table/components/DataTablePagination.tsx +51 -28
  167. package/src/core/table/components/DataTableToolbar.tsx +9 -4
  168. package/src/core/table/index.ts +1 -0
  169. package/src/core/table/interfaces/types.ts +13 -9
  170. package/src/demo/components/core/DemoDataTable.tsx +15 -19
  171. package/dist/admin/AdminApiKeys-C-6_Q-lH.js.map +0 -1
  172. package/dist/admin/AdminAudits-Bgbf04hO.js.map +0 -1
  173. package/dist/admin/AdminFiles-B9a7G3cY.js.map +0 -1
  174. package/dist/admin/AdminJobExecutions-B9cek5dl.js.map +0 -1
  175. package/dist/admin/AdminJobRegistry-DFgV3oqx.js.map +0 -1
  176. package/dist/admin/AdminLayout-DHsvWxVB.js +0 -70
  177. package/dist/admin/AdminLayout-DHsvWxVB.js.map +0 -1
  178. package/dist/admin/AdminSessions-BhGJPI3z.js.map +0 -1
  179. package/dist/admin/AdminUserSessions-1uzcx02z.js.map +0 -1
  180. package/dist/admin/AdminUsers-C85c3eiQ.js +0 -121
  181. package/dist/admin/AdminUsers-C85c3eiQ.js.map +0 -1
  182. package/dist/admin/auth-Dr0Cf8I7.js +0 -319
  183. package/dist/admin/auth-Dr0Cf8I7.js.map +0 -1
  184. package/dist/admin/core-2xoLiT0o.js.map +0 -1
  185. package/dist/auth/core-niW0sFLv.js.map +0 -1
  186. package/dist/demo/DemoDataTable-Z9xyV221.js.map +0 -1
  187. package/dist/demo/core-RCUw1Q-a.js.map +0 -1
@@ -0,0 +1,184 @@
1
+ import {
2
+ ColorSwatch,
3
+ Flex,
4
+ Select,
5
+ SimpleGrid,
6
+ Text,
7
+ useMantineTheme,
8
+ } from "@mantine/core";
9
+ import { IconCheck } from "@tabler/icons-react";
10
+ import type { AlephaThemeOverrides } from "../../atoms/alephaThemeOverridesAtom.ts";
11
+ import { useDialog } from "../../hooks/useDialog.ts";
12
+ import { useTheme } from "../../hooks/useTheme.ts";
13
+ import ActionButton from "./ActionButton.tsx";
14
+
15
+ const MANTINE_COLORS = [
16
+ "red",
17
+ "pink",
18
+ "grape",
19
+ "violet",
20
+ "indigo",
21
+ "blue",
22
+ "cyan",
23
+ "teal",
24
+ "green",
25
+ "lime",
26
+ "yellow",
27
+ "orange",
28
+ ];
29
+
30
+ const RADIUS_OPTIONS = [
31
+ { label: "xs", value: "xs" },
32
+ { label: "sm", value: "sm" },
33
+ { label: "md", value: "md" },
34
+ { label: "lg", value: "lg" },
35
+ { label: "xl", value: "xl" },
36
+ ];
37
+
38
+ const SIZE_OPTIONS = [
39
+ { label: "xs", value: "xs" },
40
+ { label: "sm", value: "sm" },
41
+ { label: "md", value: "md" },
42
+ { label: "lg", value: "lg" },
43
+ { label: "xl", value: "xl" },
44
+ ];
45
+
46
+ const FONT_OPTIONS = [
47
+ { label: "System", value: "" },
48
+ { label: "Inter", value: "Inter, sans-serif" },
49
+ { label: "Mono", value: "ui-monospace, SFMono-Regular, Menlo, monospace" },
50
+ { label: "Serif", value: "Georgia, 'Times New Roman', serif" },
51
+ ];
52
+
53
+ const ThemeExpertModal = () => {
54
+ const [, , expert] = useTheme();
55
+ const dialog = useDialog();
56
+ const mantineTheme = useMantineTheme();
57
+ const { overrides, setOverrides } = expert;
58
+
59
+ const currentColor = overrides.primaryColor || mantineTheme.primaryColor;
60
+ const currentRadius = overrides.radius || mantineTheme.defaultRadius || "md";
61
+ const currentFont = overrides.fontFamily || "";
62
+ const currentFontSize = overrides.fontSize || "md";
63
+ const currentScale = overrides.scale || "md";
64
+
65
+ const updateOverrides = (patch: Partial<AlephaThemeOverrides>) => {
66
+ setOverrides({ ...overrides, ...patch });
67
+ };
68
+
69
+ return (
70
+ <Flex direction="column" gap="lg">
71
+ <Flex direction="column" gap="xs">
72
+ <Text fw={500} size="sm">
73
+ Primary Color
74
+ </Text>
75
+ <SimpleGrid cols={6} spacing="xs">
76
+ {MANTINE_COLORS.map((color) => (
77
+ <Flex key={color} justify="center">
78
+ <ColorSwatch
79
+ color={mantineTheme.colors[color]?.[6] ?? color}
80
+ onClick={() => updateOverrides({ primaryColor: color })}
81
+ style={{ cursor: "pointer" }}
82
+ size={32}
83
+ >
84
+ {currentColor === color && (
85
+ <IconCheck size={14} color="white" />
86
+ )}
87
+ </ColorSwatch>
88
+ </Flex>
89
+ ))}
90
+ </SimpleGrid>
91
+ </Flex>
92
+
93
+ <Flex direction="column" gap="xs">
94
+ <Text fw={500} size="sm">
95
+ Border Radius
96
+ </Text>
97
+ <Flex gap="xs">
98
+ {RADIUS_OPTIONS.map((opt) => (
99
+ <ActionButton
100
+ key={opt.value}
101
+ variant={
102
+ String(currentRadius) === opt.value ? "filled" : "default"
103
+ }
104
+ size="xs"
105
+ flex={1}
106
+ onClick={() => updateOverrides({ radius: opt.value })}
107
+ >
108
+ {opt.label}
109
+ </ActionButton>
110
+ ))}
111
+ </Flex>
112
+ </Flex>
113
+
114
+ <Flex direction="column" gap="xs">
115
+ <Text fw={500} size="sm">
116
+ Font Family
117
+ </Text>
118
+ <Select
119
+ data={FONT_OPTIONS}
120
+ value={currentFont}
121
+ onChange={(value) => updateOverrides({ fontFamily: value ?? "" })}
122
+ allowDeselect={false}
123
+ />
124
+ </Flex>
125
+
126
+ <Flex direction="column" gap="xs">
127
+ <Text fw={500} size="sm">
128
+ Font Size
129
+ </Text>
130
+ <Flex gap="xs">
131
+ {SIZE_OPTIONS.map((opt) => (
132
+ <ActionButton
133
+ key={opt.value}
134
+ variant={currentFontSize === opt.value ? "filled" : "default"}
135
+ size="xs"
136
+ flex={1}
137
+ onClick={() => updateOverrides({ fontSize: opt.value })}
138
+ >
139
+ {opt.label}
140
+ </ActionButton>
141
+ ))}
142
+ </Flex>
143
+ </Flex>
144
+
145
+ <Flex direction="column" gap="xs">
146
+ <Text fw={500} size="sm">
147
+ Scale
148
+ </Text>
149
+ <Flex gap="xs">
150
+ {SIZE_OPTIONS.map((opt) => (
151
+ <ActionButton
152
+ key={opt.value}
153
+ variant={currentScale === opt.value ? "filled" : "default"}
154
+ size="xs"
155
+ flex={1}
156
+ onClick={() => updateOverrides({ scale: opt.value })}
157
+ >
158
+ {opt.label}
159
+ </ActionButton>
160
+ ))}
161
+ </Flex>
162
+ </Flex>
163
+
164
+ <Flex justify="space-between">
165
+ <ActionButton
166
+ variant="subtle"
167
+ color="red"
168
+ onClick={() => expert.resetOverrides()}
169
+ >
170
+ Reset
171
+ </ActionButton>
172
+ <ActionButton
173
+ variant={"default"}
174
+ px={"xl"}
175
+ onClick={() => dialog.close()}
176
+ >
177
+ OK
178
+ </ActionButton>
179
+ </Flex>
180
+ </Flex>
181
+ );
182
+ };
183
+
184
+ export default ThemeExpertModal;
@@ -19,8 +19,7 @@ const ToggleSidebarButton = (props: Props) => {
19
19
  : IconLayoutSidebarLeftCollapse
20
20
  }
21
21
  visibleFrom={"md"}
22
- variant={"subtle"}
23
- size={"md"}
22
+ variant={"default"}
24
23
  onClick={() => {
25
24
  setSidebar({
26
25
  ...sidebar,
@@ -8,6 +8,7 @@ import {
8
8
  OmnibarButton,
9
9
  type OmnibarButtonProps,
10
10
  Text,
11
+ ThemeButton,
11
12
  } from "@alepha/ui";
12
13
  import {
13
14
  Anchor,
@@ -25,6 +26,7 @@ export type AppBarItem =
25
26
  | AppBarElement
26
27
  | AppBarBurger
27
28
  | AppBarDark
29
+ | AppBarTheme
28
30
  | AppBarSearch
29
31
  | AppBarLang
30
32
  | AppBarSpacer
@@ -54,6 +56,11 @@ export interface AppBarDark extends AppBarAbstractItem {
54
56
  props?: Partial<ActionProps>;
55
57
  }
56
58
 
59
+ export interface AppBarTheme extends AppBarAbstractItem {
60
+ type: "theme";
61
+ props?: Partial<ActionProps>;
62
+ }
63
+
57
64
  export interface AppBarSearch extends AppBarAbstractItem {
58
65
  type: "search";
59
66
  props?: OmnibarButtonProps;
@@ -175,6 +182,9 @@ const AppBar = (props: AppBarProps) => {
175
182
  if (item.type === "dark") {
176
183
  return <DarkModeButton key={index} {...item.props} />;
177
184
  }
185
+ if (item.type === "theme") {
186
+ return <ThemeButton key={index} {...item.props} />;
187
+ }
178
188
  if (item.type === "search") {
179
189
  return <OmnibarButton key={index} {...item.props} />;
180
190
  }
@@ -37,7 +37,7 @@ export interface DashboardShellProps {
37
37
  /**
38
38
  * Content rendered above the Sidebar inside the navbar (e.g. logo).
39
39
  */
40
- navbarHeader?: ReactNode;
40
+ navbarHeader?: (props: { collapsed: boolean }) => ReactNode;
41
41
 
42
42
  /**
43
43
  * Content rendered below the Sidebar inside the navbar (e.g. toggle button).
@@ -136,6 +136,7 @@ const DashboardShell = (props: DashboardShellProps) => {
136
136
  <AppShell
137
137
  layout={"alt"}
138
138
  w={"100%"}
139
+ h={"100vh"}
139
140
  flex={1}
140
141
  header={hasAppBar ? { height: hHeight } : undefined}
141
142
  navbar={
@@ -159,10 +160,7 @@ const DashboardShell = (props: DashboardShellProps) => {
159
160
  )}
160
161
 
161
162
  {hasSidebar && (
162
- <AppShell.Navbar
163
- className="alepha-sidebar-navbar"
164
- {...props.appShellNavbarProps}
165
- >
163
+ <AppShell.Navbar {...props.appShellNavbarProps}>
166
164
  {props.navbarHeader ? (
167
165
  <Flex
168
166
  style={{
@@ -170,7 +168,7 @@ const DashboardShell = (props: DashboardShellProps) => {
170
168
  }}
171
169
  h={headerHeight}
172
170
  >
173
- {props.navbarHeader}
171
+ {props.navbarHeader({ collapsed })}
174
172
  </Flex>
175
173
  ) : null}
176
174
  <Sidebar {...(props.sidebarProps ?? {})} collapsed={collapsed} />
@@ -187,7 +185,12 @@ const DashboardShell = (props: DashboardShellProps) => {
187
185
  </AppShell.Navbar>
188
186
  )}
189
187
 
190
- <AppShell.Main pos={"relative"} {...props.appShellMainProps}>
188
+ <AppShell.Main
189
+ display={"flex"}
190
+ bg={"var(--alepha-ground)"}
191
+ pos={"relative"}
192
+ {...props.appShellMainProps}
193
+ >
191
194
  {props.children ?? <NestedView />}
192
195
  </AppShell.Main>
193
196
 
@@ -89,7 +89,7 @@ export const Sidebar = (props: SidebarProps) => {
89
89
 
90
90
  if (item.type === "search") {
91
91
  return (
92
- <Flex key={key} mb="xs">
92
+ <Flex key={key} mb="xs" w={"100%"} justify="center" pos={"relative"}>
93
93
  <OmnibarButton collapsed={collapsed} />
94
94
  </Flex>
95
95
  );
@@ -112,7 +112,6 @@ export const Sidebar = (props: SidebarProps) => {
112
112
  if (collapsed) {
113
113
  return (
114
114
  <Fragment key={key}>
115
- {divider(`${key}-d`, undefined, collapsed)}
116
115
  {item.children?.map((child, index) =>
117
116
  renderNode(child, `s${key}-${index}`, collapsed),
118
117
  )}
@@ -202,7 +201,7 @@ export const Sidebar = (props: SidebarProps) => {
202
201
  };
203
202
 
204
203
  const padding = "md";
205
- const gap = props.items ? (props.gap ?? 4) : "xs";
204
+ const gap = props.items ? (props.gap ?? 8) : "xs";
206
205
  const menu = useMemo(
207
206
  () => getSidebarNodes(),
208
207
  [props.items, props.autoPopulateMenu],
@@ -316,17 +315,11 @@ export const SidebarItem = (props: SidebarItemProps) => {
316
315
  props.theme.button?.size ??
317
316
  (level === 0 ? "sm" : "xs")
318
317
  }
319
- // tooltip={
320
- // item.description
321
- // ? { label: item.description, position: "right" }
322
- // : undefined
323
- // }
324
318
  bd={0}
325
319
  fw={"normal"}
326
320
  variant={"default"}
327
321
  propsActive={{
328
322
  variant: "outline",
329
- fw: "bold",
330
323
  }}
331
324
  radius={props.item.theme?.radius ?? props.theme.button?.radius ?? "md"}
332
325
  onClick={handleItemClick}
@@ -355,7 +348,7 @@ export const SidebarItem = (props: SidebarItemProps) => {
355
348
  />
356
349
 
357
350
  {item.children && isOpen && (
358
- <Flex direction={"column"} data-parent-level={level}>
351
+ <Flex direction={"column"} data-parent-level={level} gap={2} py={2}>
359
352
  <Flex
360
353
  style={{
361
354
  position: "absolute",
@@ -401,52 +394,67 @@ const SidebarCollapsedItem = (props: SidebarItemProps) => {
401
394
  ? {
402
395
  on: "hover",
403
396
  position: "right",
404
- items: item
405
- .children!.filter((child) => !child.can || child.can())
406
- .map(
407
- (child): ActionMenuItem => ({
408
- label: child.label as string,
409
- icon: renderIcon(child.icon, ui.sizes.icon.sm),
410
- href: child.href,
411
- active: child.href
412
- ? router.isActive(child.href, {
413
- startWith: child.activeStartsWith,
414
- })
415
- : undefined,
416
- }),
417
- ),
397
+ menuProps: {
398
+ arrowPosition: "center",
399
+ arrowSize: 10,
400
+ withArrow: true,
401
+ },
402
+ items: [
403
+ {
404
+ type: "label",
405
+ label: item.label,
406
+ },
407
+ ...item
408
+ .children!.filter((child) => !child.can || child.can())
409
+ .map(
410
+ (child): ActionMenuItem => ({
411
+ label: child.label as string,
412
+ icon: renderIcon(child.icon, ui.sizes.icon.sm),
413
+ href: child.href,
414
+ active: child.href
415
+ ? router.isActive(child.href, {
416
+ startWith: child.activeStartsWith,
417
+ })
418
+ : undefined,
419
+ }),
420
+ ),
421
+ ],
418
422
  }
419
423
  : undefined;
420
424
 
421
425
  return (
422
- <ActionButton
423
- size={
424
- props.item.theme?.size ??
425
- props.theme.button?.size ??
426
- (level === 0 ? "sm" : "xs")
427
- }
428
- variant={"subtle"}
429
- variantActive={"default"}
430
- tooltip={
431
- hasChildren
432
- ? undefined
433
- : {
434
- label: item.label,
435
- position: "right",
436
- }
437
- }
438
- radius={props.item.theme?.radius ?? props.theme.button?.radius ?? "md"}
439
- onClick={hasChildren ? undefined : handleItemClick}
440
- icon={
441
- renderIcon(item.icon, ui.sizes.icon.sm) ?? (
442
- <IconSquareRounded size={ui.sizes.icon.sm} />
443
- )
444
- }
445
- href={hasChildren ? undefined : (props.item.href as any)}
446
- target={hasChildren ? undefined : props.item.target}
447
- menu={menu}
448
- {...props.item.actionProps}
449
- />
426
+ <Flex w={"100%"} justify="center" pos={"relative"}>
427
+ <ActionButton
428
+ size={
429
+ props.item.theme?.size ??
430
+ props.theme.button?.size ??
431
+ (level === 0 ? "sm" : "xs")
432
+ }
433
+ bd={0}
434
+ variant={"default"}
435
+ propsActive={{
436
+ variant: "outline",
437
+ }}
438
+ tooltip={
439
+ hasChildren
440
+ ? undefined
441
+ : {
442
+ label: item.label,
443
+ position: "right",
444
+ }
445
+ }
446
+ onClick={hasChildren ? undefined : handleItemClick}
447
+ icon={
448
+ renderIcon(item.icon, ui.sizes.icon.sm) ?? (
449
+ <IconSquareRounded size={ui.sizes.icon.sm} />
450
+ )
451
+ }
452
+ href={hasChildren ? undefined : (props.item.href as any)}
453
+ target={hasChildren ? undefined : props.item.target}
454
+ menu={menu}
455
+ {...props.item.actionProps}
456
+ />
457
+ </Flex>
450
458
  );
451
459
  };
452
460
 
@@ -1,17 +1,17 @@
1
1
  export const ui = {
2
2
  colors: {
3
3
  transparent: "transparent",
4
- background: "var(--alepha-background)",
4
+ background: "var(--alepha-ground)",
5
5
  surface: "var(--alepha-surface)",
6
6
  elevated: "var(--alepha-elevated)",
7
7
  border: "var(--alepha-border)",
8
8
  },
9
9
  sizes: {
10
10
  icon: {
11
- xs: 14,
12
- sm: 16,
13
- md: 20,
14
- lg: 24,
11
+ xs: 16,
12
+ sm: 20,
13
+ md: 24,
14
+ lg: 28,
15
15
  xl: 32,
16
16
  },
17
17
  },
@@ -3,23 +3,36 @@ import {
3
3
  alephaThemeAtom,
4
4
  type CurrentAlephaTheme,
5
5
  } from "../atoms/alephaThemeAtom.ts";
6
+ import {
7
+ type AlephaThemeOverrides,
8
+ alephaThemeOverridesAtom,
9
+ } from "../atoms/alephaThemeOverridesAtom.ts";
6
10
  import type { AlephaTheme } from "../interfaces/AlephaTheme.ts";
7
11
  import { ThemeProvider } from "../providers/ThemeProvider.ts";
8
12
 
13
+ export interface ThemeExpert {
14
+ overrides: AlephaThemeOverrides;
15
+ setOverrides: (overrides: AlephaThemeOverrides) => void;
16
+ resetOverrides: () => void;
17
+ }
18
+
9
19
  /**
10
20
  * Hook to get and set the current theme.
11
21
  *
12
- * Returns a tuple with the current theme and a function to set the theme.
22
+ * Returns a tuple with the current theme, a function to set the theme,
23
+ * and expert mode controls for fine-grained customization.
13
24
  *
14
25
  * ```tsx
15
- * const [theme, setTheme] = useTheme();
26
+ * const [theme, setTheme, expert] = useTheme();
16
27
  * ```
17
28
  */
18
29
  export const useTheme = (): [
19
30
  AlephaTheme,
20
31
  (theme: CurrentAlephaTheme) => void,
32
+ ThemeExpert,
21
33
  ] => {
22
34
  useStore(alephaThemeAtom);
35
+ useStore(alephaThemeOverridesAtom);
23
36
 
24
37
  const themeProvider = useInject(ThemeProvider);
25
38
  const theme = themeProvider.getTheme();
@@ -27,5 +40,15 @@ export const useTheme = (): [
27
40
  themeProvider.setTheme(theme.index);
28
41
  };
29
42
 
30
- return [theme, setTheme] as const;
43
+ const expert: ThemeExpert = {
44
+ overrides: themeProvider.getThemeOverrides(),
45
+ setOverrides: (overrides: AlephaThemeOverrides) => {
46
+ themeProvider.setThemeOverrides(overrides);
47
+ },
48
+ resetOverrides: () => {
49
+ themeProvider.resetThemeOverrides();
50
+ },
51
+ };
52
+
53
+ return [theme, setTheme, expert] as const;
31
54
  };
package/src/core/index.ts CHANGED
@@ -5,6 +5,7 @@ import { AlephaReactI18n } from "alepha/react/i18n";
5
5
  import type { ComponentType, ReactNode } from "react";
6
6
  import { alephaSidebarAtom } from "./atoms/alephaSidebarAtom.ts";
7
7
  import { alephaThemeAtom } from "./atoms/alephaThemeAtom.ts";
8
+ import { alephaThemeOverridesAtom } from "./atoms/alephaThemeOverridesAtom.ts";
8
9
  import { ThemeProvider } from "./providers/ThemeProvider.ts";
9
10
  import { DialogService } from "./services/DialogService.tsx";
10
11
  import { ToastService } from "./services/ToastService.tsx";
@@ -15,6 +16,7 @@ import { UiRouter } from "./UiRouter.ts";
15
16
  export * from "./atoms/alephaSidebarAtom.ts";
16
17
  export * from "./atoms/alephaThemeAtom.ts";
17
18
  export * from "./atoms/alephaThemeListAtom.ts";
19
+ export * from "./atoms/alephaThemeOverridesAtom.ts";
18
20
  export * from "./atoms/themes/default.ts";
19
21
  export * from "./atoms/themes/midnight.ts";
20
22
  export type { AlephaMantineProviderProps } from "./components/AlephaMantineProvider.tsx";
@@ -109,7 +111,7 @@ export * from "./form/index.ts";
109
111
  export * from "./helpers/isComponentType.ts";
110
112
  export * from "./helpers/renderIcon.tsx";
111
113
  export { useDialog } from "./hooks/useDialog.ts";
112
- export { useTheme } from "./hooks/useTheme.ts";
114
+ export { type ThemeExpert, useTheme } from "./hooks/useTheme.ts";
113
115
  export { useToast } from "./hooks/useToast.ts";
114
116
  export * from "./interfaces/AlephaIntent.ts";
115
117
  // JSON
@@ -140,6 +142,9 @@ declare module "alepha" {
140
142
  interface State {
141
143
  [alephaSidebarAtom.key]?: Static<typeof alephaSidebarAtom.schema>;
142
144
  [alephaThemeAtom.key]?: Static<typeof alephaThemeAtom.schema>;
145
+ [alephaThemeOverridesAtom.key]?: Static<
146
+ typeof alephaThemeOverridesAtom.schema
147
+ >;
143
148
  }
144
149
  }
145
150
 
@@ -1,7 +1,9 @@
1
1
  import type { MantineThemeOverride } from "@mantine/core";
2
+ import type { SimpleHead } from "alepha/react/head";
2
3
 
3
4
  export type AlephaTheme = MantineThemeOverride & {
4
5
  name: string;
5
6
  description: string;
6
7
  defaultColorScheme?: "light" | "dark"; // or "system"
8
+ head?: Pick<SimpleHead, "link" | "meta" | "script">;
7
9
  };