@alepha/ui 0.13.2 → 0.13.4

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 (122) hide show
  1. package/dist/admin/{AdminFiles-BjofP3OC.js → AdminFiles-8CC9mVsc.js} +3 -3
  2. package/dist/admin/{AdminFiles-BjofP3OC.js.map → AdminFiles-8CC9mVsc.js.map} +1 -1
  3. package/dist/admin/AdminFiles-BRLMP_7y.js +3 -0
  4. package/dist/admin/AdminLayout-Cm-Y4YTQ.js +396 -0
  5. package/dist/admin/AdminLayout-Cm-Y4YTQ.js.map +1 -0
  6. package/dist/admin/AdminLayout-D5M9kSiV.js +3 -0
  7. package/dist/admin/AdminNotifications-DxBKi2RO.js +3 -0
  8. package/dist/admin/AdminNotifications-d-gw5Uie.js +154 -0
  9. package/dist/admin/AdminNotifications-d-gw5Uie.js.map +1 -0
  10. package/dist/admin/{AdminSessions-CmDVneE2.js → AdminSessions-CpVusqmd.js} +37 -10
  11. package/dist/admin/AdminSessions-CpVusqmd.js.map +1 -0
  12. package/dist/admin/AdminSessions-DA285-5Q.js +3 -0
  13. package/dist/admin/AdminUserCreate-CQIrSslj.js +3 -0
  14. package/dist/admin/AdminUserCreate-DH7u_yJj.js +103 -0
  15. package/dist/admin/AdminUserCreate-DH7u_yJj.js.map +1 -0
  16. package/dist/admin/AdminUserDetails-DVmFCDsU.js +221 -0
  17. package/dist/admin/AdminUserDetails-DVmFCDsU.js.map +1 -0
  18. package/dist/admin/AdminUserDetails-T3nkXSdz.js +3 -0
  19. package/dist/admin/AdminUserLayout-DdtZGX8n.js +3 -0
  20. package/dist/admin/AdminUserLayout-gpOyn0Y7.js +153 -0
  21. package/dist/admin/AdminUserLayout-gpOyn0Y7.js.map +1 -0
  22. package/dist/admin/AdminUserSessions-CWYzjB3D.js +3 -0
  23. package/dist/admin/AdminUserSessions-CdVwoM-h.js +129 -0
  24. package/dist/admin/AdminUserSessions-CdVwoM-h.js.map +1 -0
  25. package/dist/admin/AdminUserSettings-S7gZvvjO.js +164 -0
  26. package/dist/admin/AdminUserSettings-S7gZvvjO.js.map +1 -0
  27. package/dist/admin/AdminUserSettings-jCzVYw_2.js +3 -0
  28. package/dist/admin/{AdminUsers-88De5pev.js → AdminUsers-9qEzxqAL.js} +33 -15
  29. package/dist/admin/AdminUsers-9qEzxqAL.js.map +1 -0
  30. package/dist/admin/AdminUsers-BcSUxV01.js +3 -0
  31. package/dist/admin/index.d.ts +5568 -418
  32. package/dist/admin/index.js +302 -42
  33. package/dist/admin/index.js.map +1 -1
  34. package/dist/auth/AuthLayout-BSL8ZHgr.js +19 -0
  35. package/dist/auth/AuthLayout-BSL8ZHgr.js.map +1 -0
  36. package/dist/auth/{Login-OCrvjs9U.js → Login-AlVPPqQp.js} +6 -5
  37. package/dist/auth/Login-AlVPPqQp.js.map +1 -0
  38. package/dist/auth/Login-otdWVvVU.js +4 -0
  39. package/dist/auth/{Register-Ei34GSba.js → Register-BxJmOqpF.js} +9 -6
  40. package/dist/auth/Register-BxJmOqpF.js.map +1 -0
  41. package/dist/auth/Register-D10MnlQc.js +4 -0
  42. package/dist/auth/{ResetPassword-tO0oMzfo.js → ResetPassword-BhyZ9ek4.js} +3 -3
  43. package/dist/auth/ResetPassword-BhyZ9ek4.js.map +1 -0
  44. package/dist/auth/ResetPassword-llBG-STp.js +3 -0
  45. package/dist/auth/VerifyEmail-BvOG-IUC.js +3 -0
  46. package/dist/auth/VerifyEmail-DeLct3oQ.js +131 -0
  47. package/dist/auth/VerifyEmail-DeLct3oQ.js.map +1 -0
  48. package/dist/auth/index.d.ts +2412 -2254
  49. package/dist/auth/index.js +97 -20
  50. package/dist/auth/index.js.map +1 -1
  51. package/dist/core/index.d.ts +280 -95
  52. package/dist/core/index.js +1375 -394
  53. package/dist/core/index.js.map +1 -1
  54. package/package.json +7 -6
  55. package/src/admin/AdminRouter.ts +116 -29
  56. package/src/admin/AdminSidebar.ts +31 -0
  57. package/src/admin/MainRouter.ts +23 -0
  58. package/src/admin/components/AdminLayout.tsx +66 -104
  59. package/src/admin/components/AdminNotifications.tsx +196 -12
  60. package/src/admin/components/AdminSessions.tsx +43 -7
  61. package/src/admin/components/AdminUserCreate.tsx +84 -0
  62. package/src/admin/components/AdminUserDetails.tsx +180 -0
  63. package/src/admin/components/AdminUserLayout.tsx +172 -0
  64. package/src/admin/components/AdminUserSessions.tsx +158 -0
  65. package/src/admin/components/AdminUserSettings.tsx +165 -0
  66. package/src/admin/components/AdminUsers.tsx +29 -9
  67. package/src/admin/index.ts +15 -3
  68. package/src/auth/AuthI18n.ts +22 -0
  69. package/src/auth/AuthRouter.ts +82 -8
  70. package/src/auth/components/AuthLayout.tsx +12 -0
  71. package/src/auth/components/Login.tsx +14 -12
  72. package/src/auth/components/Register.tsx +6 -5
  73. package/src/auth/components/ResetPassword.tsx +1 -1
  74. package/src/auth/components/VerifyEmail.tsx +102 -0
  75. package/src/auth/components/buttons/UserButton.tsx +12 -2
  76. package/src/auth/index.ts +1 -0
  77. package/src/core/components/buttons/ActionButton.tsx +12 -4
  78. package/src/core/components/buttons/DarkModeButton.tsx +1 -1
  79. package/src/core/components/buttons/ThemeButton.tsx +31 -0
  80. package/src/core/components/layout/AdminShell.tsx +4 -2
  81. package/src/core/components/layout/AlephaMantineProvider.tsx +10 -4
  82. package/src/core/components/layout/Omnibar.tsx +27 -15
  83. package/src/core/components/layout/Sidebar.tsx +33 -17
  84. package/src/core/components/table/DataTable.tsx +9 -5
  85. package/src/core/hooks/useTheme.ts +25 -0
  86. package/src/core/index.ts +8 -3
  87. package/src/core/providers/ThemeProvider.ts +90 -0
  88. package/src/core/themes/aurora.ts +107 -0
  89. package/src/core/themes/crystal.ts +107 -0
  90. package/src/core/themes/default.ts +7 -0
  91. package/src/core/themes/ember.ts +107 -0
  92. package/src/core/themes/index.ts +7 -0
  93. package/src/core/themes/midnight.ts +98 -0
  94. package/src/core/themes/remoraid.ts +278 -0
  95. package/src/core/themes/slate.ts +81 -0
  96. package/styles.css +84 -0
  97. package/dist/admin/AdminFiles-DldZB7oo.js +0 -3
  98. package/dist/admin/AdminJobs-BOq6AZOW.js +0 -3
  99. package/dist/admin/AdminJobs-CDnVxEv6.js +0 -125
  100. package/dist/admin/AdminJobs-CDnVxEv6.js.map +0 -1
  101. package/dist/admin/AdminLayout-Bgx25J8m.js +0 -3
  102. package/dist/admin/AdminLayout-CervL8LV.js +0 -88
  103. package/dist/admin/AdminLayout-CervL8LV.js.map +0 -1
  104. package/dist/admin/AdminNotifications-BDQXt3-e.js +0 -3
  105. package/dist/admin/AdminNotifications-DvI2989x.js +0 -40
  106. package/dist/admin/AdminNotifications-DvI2989x.js.map +0 -1
  107. package/dist/admin/AdminParameters-D_v0GAvI.js +0 -3
  108. package/dist/admin/AdminParameters-P1LB6ZI1.js +0 -40
  109. package/dist/admin/AdminParameters-P1LB6ZI1.js.map +0 -1
  110. package/dist/admin/AdminSessions-CmDVneE2.js.map +0 -1
  111. package/dist/admin/AdminSessions-Dkk_fzWK.js +0 -3
  112. package/dist/admin/AdminUsers-88De5pev.js.map +0 -1
  113. package/dist/admin/AdminUsers-oyAXqZ5l.js +0 -3
  114. package/dist/admin/AdminVerifications-D93TKymL.js +0 -3
  115. package/dist/admin/AdminVerifications-DBVEoqJe.js +0 -40
  116. package/dist/admin/AdminVerifications-DBVEoqJe.js.map +0 -1
  117. package/dist/auth/Login-BC2jTczq.js +0 -4
  118. package/dist/auth/Login-OCrvjs9U.js.map +0 -1
  119. package/dist/auth/Register-Dh0lsQmI.js +0 -4
  120. package/dist/auth/Register-Ei34GSba.js.map +0 -1
  121. package/dist/auth/ResetPassword-BnlAQAOE.js +0 -3
  122. package/dist/auth/ResetPassword-tO0oMzfo.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { DataTable, Flex, Text } from "@alepha/ui";
2
2
  import { t } from "alepha";
3
3
  import { useClient } from "@alepha/react";
4
- import { useI18n } from "@alepha/react/i18n";
5
4
  import { Badge } from "@mantine/core";
6
- import { files } from "alepha/api/files";
7
5
  import { jsx } from "react/jsx-runtime";
6
+ import { useI18n } from "@alepha/react/i18n";
7
+ import { files } from "alepha/api/files";
8
8
 
9
9
  //#region src/admin/components/AdminFiles.tsx
10
10
  const AdminFiles = () => {
@@ -114,4 +114,4 @@ var AdminFiles_default = AdminFiles;
114
114
 
115
115
  //#endregion
116
116
  export { AdminFiles_default as t };
117
- //# sourceMappingURL=AdminFiles-BjofP3OC.js.map
117
+ //# sourceMappingURL=AdminFiles-8CC9mVsc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminFiles-BjofP3OC.js","names":["filters"],"sources":["../../src/admin/components/AdminFiles.tsx"],"sourcesContent":["import { useClient } from \"@alepha/react\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { DataTable, Flex, Text } from \"@alepha/ui\";\nimport { Badge } from \"@mantine/core\";\nimport { type Page, t } from \"alepha\";\nimport { type FileController, type FileEntity, files } from \"alepha/api/files\";\n\nconst AdminFiles = () => {\n const client = useClient<FileController>();\n const { l } = useI18n();\n\n const filters = t.object({\n bucket: t.optional(t.string()),\n name: t.optional(\n t.string({\n $control: {\n query: t.pick(files.schema, [\"name\", \"bucket\", \"mimeType\"]),\n },\n }),\n ),\n });\n\n const formatFileSize = (bytes: number) => {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${Number.parseFloat((bytes / k ** i).toFixed(1))} ${sizes[i]}`;\n };\n\n return (\n <Flex flex={1}>\n <DataTable<FileEntity, typeof filters>\n submitOnInit\n defaultSize={10}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 3,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n }}\n onFilterChange={(key, _value, form) => {\n if (key === \"name\" || key === \"bucket\") {\n return form.submit();\n }\n }}\n filters={filters}\n items={async (filters) => {\n const response = await client.findFiles({\n query: filters,\n });\n\n return response as Page<FileEntity>;\n }}\n columns={{\n name: {\n label: \"Name\",\n value: (item) => (\n <Text size=\"sm\" fw={500} lineClamp={1}>\n {item.name}\n </Text>\n ),\n },\n bucket: {\n label: \"Bucket\",\n fit: true,\n value: (item) => (\n <Badge size=\"sm\" variant=\"light\" color=\"blue\">\n {item.bucket}\n </Badge>\n ),\n },\n mimeType: {\n label: \"Type\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {item.mimeType}\n </Text>\n ),\n },\n size: {\n label: \"Size\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {formatFileSize(item.size)}\n </Text>\n ),\n },\n creatorName: {\n label: \"Creator\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {item.creatorName || \"-\"}\n </Text>\n ),\n },\n createdAt: {\n label: \"Created\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n }}\n />\n </Flex>\n );\n};\n\nexport default AdminFiles;\n"],"mappings":";;;;;;;;;AAOA,MAAM,mBAAmB;CACvB,MAAM,SAAS,WAA2B;CAC1C,MAAM,EAAE,MAAM,SAAS;CAEvB,MAAM,UAAU,EAAE,OAAO;EACvB,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC;EAC9B,MAAM,EAAE,SACN,EAAE,OAAO,EACP,UAAU,EACR,OAAO,EAAE,KAAK,MAAM,QAAQ;GAAC;GAAQ;GAAU;GAAW,CAAC,EAC5D,EACF,CAAC,CACH;EACF,CAAC;CAEF,MAAM,kBAAkB,UAAkB;AACxC,MAAI,UAAU,EAAG,QAAO;EACxB,MAAM,IAAI;EACV,MAAM,QAAQ;GAAC;GAAK;GAAM;GAAM;GAAK;EACrC,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC;AACnD,SAAO,GAAG,OAAO,YAAY,QAAQ,KAAK,GAAG,QAAQ,EAAE,CAAC,CAAC,GAAG,MAAM;;AAGpE,QACE,oBAAC;EAAK,MAAM;YACV,oBAAC;GACC;GACA,aAAa;GACb,eAAe;IACb,kBAAkB;IAClB,SAAS;IACV;GACD,YAAY;IACV,mBAAmB;IACnB,iBAAiB;IAClB;GACD,iBAAiB,KAAK,QAAQ,SAAS;AACrC,QAAI,QAAQ,UAAU,QAAQ,SAC5B,QAAO,KAAK,QAAQ;;GAGf;GACT,OAAO,OAAO,cAAY;AAKxB,WAJiB,MAAM,OAAO,UAAU,EACtC,OAAOA,WACR,CAAC;;GAIJ,SAAS;IACP,MAAM;KACJ,OAAO;KACP,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,IAAI;MAAK,WAAW;gBACjC,KAAK;OACD;KAEV;IACD,QAAQ;KACN,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAM,MAAK;MAAK,SAAQ;MAAQ,OAAM;gBACpC,KAAK;OACA;KAEX;IACD,UAAU;KACR,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,KAAK;OACD;KAEV;IACD,MAAM;KACJ,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,eAAe,KAAK,KAAK;OACrB;KAEV;IACD,aAAa;KACX,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,KAAK,eAAe;OAChB;KAEV;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;OAClC;KAEV;IACF;IACD;GACG;;AAIX,yBAAe"}
1
+ {"version":3,"file":"AdminFiles-8CC9mVsc.js","names":["filters"],"sources":["../../src/admin/components/AdminFiles.tsx"],"sourcesContent":["import { useClient } from \"@alepha/react\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { DataTable, Flex, Text } from \"@alepha/ui\";\nimport { Badge } from \"@mantine/core\";\nimport { type Page, t } from \"alepha\";\nimport { type FileController, type FileEntity, files } from \"alepha/api/files\";\n\nconst AdminFiles = () => {\n const client = useClient<FileController>();\n const { l } = useI18n();\n\n const filters = t.object({\n bucket: t.optional(t.string()),\n name: t.optional(\n t.string({\n $control: {\n query: t.pick(files.schema, [\"name\", \"bucket\", \"mimeType\"]),\n },\n }),\n ),\n });\n\n const formatFileSize = (bytes: number) => {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${Number.parseFloat((bytes / k ** i).toFixed(1))} ${sizes[i]}`;\n };\n\n return (\n <Flex flex={1}>\n <DataTable<FileEntity, typeof filters>\n submitOnInit\n defaultSize={10}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 3,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n }}\n onFilterChange={(key, _value, form) => {\n if (key === \"name\" || key === \"bucket\") {\n return form.submit();\n }\n }}\n filters={filters}\n items={async (filters) => {\n const response = await client.findFiles({\n query: filters,\n });\n\n return response as Page<FileEntity>;\n }}\n columns={{\n name: {\n label: \"Name\",\n value: (item) => (\n <Text size=\"sm\" fw={500} lineClamp={1}>\n {item.name}\n </Text>\n ),\n },\n bucket: {\n label: \"Bucket\",\n fit: true,\n value: (item) => (\n <Badge size=\"sm\" variant=\"light\" color=\"blue\">\n {item.bucket}\n </Badge>\n ),\n },\n mimeType: {\n label: \"Type\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {item.mimeType}\n </Text>\n ),\n },\n size: {\n label: \"Size\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {formatFileSize(item.size)}\n </Text>\n ),\n },\n creatorName: {\n label: \"Creator\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {item.creatorName || \"-\"}\n </Text>\n ),\n },\n createdAt: {\n label: \"Created\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n }}\n />\n </Flex>\n );\n};\n\nexport default AdminFiles;\n"],"mappings":";;;;;;;;;AAOA,MAAM,mBAAmB;CACvB,MAAM,SAAS,WAA2B;CAC1C,MAAM,EAAE,MAAM,SAAS;CAEvB,MAAM,UAAU,EAAE,OAAO;EACvB,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC;EAC9B,MAAM,EAAE,SACN,EAAE,OAAO,EACP,UAAU,EACR,OAAO,EAAE,KAAK,MAAM,QAAQ;GAAC;GAAQ;GAAU;GAAW,CAAC,EAC5D,EACF,CAAC,CACH;EACF,CAAC;CAEF,MAAM,kBAAkB,UAAkB;AACxC,MAAI,UAAU,EAAG,QAAO;EACxB,MAAM,IAAI;EACV,MAAM,QAAQ;GAAC;GAAK;GAAM;GAAM;GAAK;EACrC,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC;AACnD,SAAO,GAAG,OAAO,YAAY,QAAQ,KAAK,GAAG,QAAQ,EAAE,CAAC,CAAC,GAAG,MAAM;;AAGpE,QACE,oBAAC;EAAK,MAAM;YACV,oBAAC;GACC;GACA,aAAa;GACb,eAAe;IACb,kBAAkB;IAClB,SAAS;IACV;GACD,YAAY;IACV,mBAAmB;IACnB,iBAAiB;IAClB;GACD,iBAAiB,KAAK,QAAQ,SAAS;AACrC,QAAI,QAAQ,UAAU,QAAQ,SAC5B,QAAO,KAAK,QAAQ;;GAGf;GACT,OAAO,OAAO,cAAY;AAKxB,WAJiB,MAAM,OAAO,UAAU,EACtC,OAAOA,WACR,CAAC;;GAIJ,SAAS;IACP,MAAM;KACJ,OAAO;KACP,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,IAAI;MAAK,WAAW;gBACjC,KAAK;OACD;KAEV;IACD,QAAQ;KACN,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAM,MAAK;MAAK,SAAQ;MAAQ,OAAM;gBACpC,KAAK;OACA;KAEX;IACD,UAAU;KACR,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,KAAK;OACD;KAEV;IACD,MAAM;KACJ,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,eAAe,KAAK,KAAK;OACrB;KAEV;IACD,aAAa;KACX,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,KAAK,eAAe;OAChB;KAEV;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;OAClC;KAEV;IACF;IACD;GACG;;AAIX,yBAAe"}
@@ -0,0 +1,3 @@
1
+ import { t as AdminFiles_default } from "./AdminFiles-8CC9mVsc.js";
2
+
3
+ export { AdminFiles_default as default };
@@ -0,0 +1,396 @@
1
+ import { ActionButton, AdminShell, OmnibarButton, ThemeButton } from "@alepha/ui";
2
+ import { UserButton } from "@alepha/ui/auth";
3
+ import { NestedView, useAction, useActive, useInject, useRouter, useStore } from "@alepha/react";
4
+ import { IconArrowLeft, IconCheck, IconChevronRight, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightCollapse } from "@tabler/icons-react";
5
+ import { Children, createElement, isValidElement } from "react";
6
+ import { useFormState } from "@alepha/react/form";
7
+ import { Anchor, Button, Flex as Flex$1, Menu, ThemeIcon, Tooltip } from "@mantine/core";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+
10
+ //#region src/core/constants/ui.ts
11
+ const ui = {
12
+ colors: {
13
+ transparent: "transparent",
14
+ background: "var(--alepha-background)",
15
+ surface: "var(--alepha-surface)",
16
+ elevated: "var(--alepha-elevated)",
17
+ border: "var(--alepha-border)"
18
+ },
19
+ sizes: { icon: {
20
+ xs: 12,
21
+ sm: 16,
22
+ md: 20,
23
+ lg: 24,
24
+ xl: 32
25
+ } }
26
+ };
27
+
28
+ //#endregion
29
+ //#region src/core/components/buttons/ActionButton.tsx
30
+ const ActionMenuItem = (props) => {
31
+ const { item, index } = props;
32
+ const router = useRouter();
33
+ const action = useAction({ handler: async (e) => {
34
+ await item.onClick?.();
35
+ } }, [item.onClick]);
36
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
37
+ if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
38
+ if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
39
+ trigger: "hover",
40
+ position: "right-start",
41
+ offset: 2,
42
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
43
+ leftSection: item.icon,
44
+ rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
45
+ children: item.label
46
+ }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
47
+ item: child,
48
+ index: childIndex
49
+ }, childIndex)) })]
50
+ }, index);
51
+ const menuItemProps = {};
52
+ if (props.item.onClick) menuItemProps.onClick = action.run;
53
+ else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
54
+ return /* @__PURE__ */ jsx(Menu.Item, {
55
+ leftSection: item.icon,
56
+ onClick: item.onClick,
57
+ color: item.color,
58
+ rightSection: item.active ? /* @__PURE__ */ jsx(ThemeIcon, {
59
+ size: "xs",
60
+ variant: "transparent",
61
+ children: /* @__PURE__ */ jsx(IconCheck, {})
62
+ }) : void 0,
63
+ ...menuItemProps,
64
+ children: item.label
65
+ }, index);
66
+ };
67
+ const ActionButton$1 = (_props) => {
68
+ const props = {
69
+ variant: "subtle",
70
+ ..._props
71
+ };
72
+ const { tooltip, menu, icon, ...restProps } = props;
73
+ restProps.color ??= "gray";
74
+ restProps.c ??= "var(--mantine-color-text)";
75
+ if (props.icon) {
76
+ const icon$1 = isComponentType(props.icon) ? /* @__PURE__ */ jsx(props.icon, { size: ui.sizes.icon.md }) : /* @__PURE__ */ jsx(ThemeIcon, {
77
+ w: 24,
78
+ variant: "transparent",
79
+ size: "sm",
80
+ c: "var(--mantine-color-text)",
81
+ ...props.themeIconProps,
82
+ children: props.icon
83
+ });
84
+ if (!props.children) {
85
+ restProps.children = Children.only(icon$1);
86
+ restProps.px ??= "xs";
87
+ } else restProps.leftSection = icon$1;
88
+ }
89
+ if (props.leftSection && !props.children) restProps.px ??= "xs";
90
+ if (props.textVisibleFrom) {
91
+ const { children, textVisibleFrom, leftSection, ...rest } = restProps;
92
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex$1, {
93
+ w: "100%",
94
+ visibleFrom: textVisibleFrom,
95
+ children: /* @__PURE__ */ jsx(ActionButton$1, {
96
+ flex: 1,
97
+ ...rest,
98
+ leftSection,
99
+ tooltip,
100
+ menu,
101
+ children
102
+ })
103
+ }), /* @__PURE__ */ jsx(Flex$1, {
104
+ w: "100%",
105
+ hiddenFrom: textVisibleFrom,
106
+ children: /* @__PURE__ */ jsx(ActionButton$1, {
107
+ px: "xs",
108
+ ...rest,
109
+ tooltip,
110
+ menu,
111
+ children: leftSection
112
+ })
113
+ })] });
114
+ }
115
+ const renderAction = () => {
116
+ if ("href" in restProps && restProps.href) {
117
+ if (restProps.href.startsWith("http") || restProps.target) return /* @__PURE__ */ jsx(ActionHrefButton, {
118
+ ...restProps,
119
+ href: restProps.href,
120
+ children: restProps.children
121
+ });
122
+ return /* @__PURE__ */ jsx(ActionNavigationButton, {
123
+ ...restProps,
124
+ href: restProps.href,
125
+ children: restProps.children
126
+ });
127
+ }
128
+ delete restProps.classNameActive;
129
+ delete restProps.variantActive;
130
+ if ("action" in restProps && restProps.action) return /* @__PURE__ */ jsx(ActionHookButton, {
131
+ ...restProps,
132
+ action: restProps.action,
133
+ children: restProps.children
134
+ });
135
+ if ("onClick" in restProps && restProps.onClick) return /* @__PURE__ */ jsx(ActionClickButton, {
136
+ ...restProps,
137
+ onClick: restProps.onClick,
138
+ children: restProps.children
139
+ });
140
+ if ("form" in restProps && restProps.form) {
141
+ if (restProps.type === "reset") return /* @__PURE__ */ jsx(ActionResetButton, {
142
+ ...restProps,
143
+ form: restProps.form,
144
+ children: restProps.children
145
+ });
146
+ return /* @__PURE__ */ jsx(ActionSubmitButton, {
147
+ ...restProps,
148
+ form: restProps.form,
149
+ children: restProps.children
150
+ });
151
+ }
152
+ return /* @__PURE__ */ jsx(Button, {
153
+ ...restProps,
154
+ children: restProps.children
155
+ });
156
+ };
157
+ let actionElement = renderAction();
158
+ if (menu) actionElement = /* @__PURE__ */ jsxs(Menu, {
159
+ position: menu.position || "bottom-start",
160
+ width: menu.width || 200,
161
+ shadow: menu.shadow || "md",
162
+ trigger: menu.on === "hover" ? "hover" : "click",
163
+ ...menu.menuProps,
164
+ children: [/* @__PURE__ */ jsx(Menu.Target, {
165
+ ...menu.targetProps,
166
+ children: actionElement
167
+ }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: menu.items.map((item, index) => /* @__PURE__ */ jsx(ActionMenuItem, {
168
+ item,
169
+ index
170
+ }, index)) })]
171
+ });
172
+ if (tooltip) {
173
+ const defaultTooltipProps = { openDelay: 1e3 };
174
+ return /* @__PURE__ */ jsx(Tooltip, { ...typeof tooltip === "string" ? {
175
+ ...defaultTooltipProps,
176
+ label: tooltip,
177
+ children: actionElement
178
+ } : {
179
+ ...defaultTooltipProps,
180
+ ...tooltip,
181
+ children: actionElement
182
+ } });
183
+ }
184
+ return actionElement;
185
+ };
186
+ var ActionButton_default = ActionButton$1;
187
+ /**
188
+ * Action button that submits a form with loading and disabled state handling.
189
+ */
190
+ const ActionSubmitButton = (props) => {
191
+ const { form, ...buttonProps } = props;
192
+ const state = useFormState(form);
193
+ return /* @__PURE__ */ jsx(Button, {
194
+ ...buttonProps,
195
+ loading: state.loading,
196
+ disabled: state.loading,
197
+ type: "submit",
198
+ children: props.children
199
+ });
200
+ };
201
+ const ActionResetButton = (props) => {
202
+ const { form, ...buttonProps } = props;
203
+ const state = useFormState(form);
204
+ return /* @__PURE__ */ jsx(Button, {
205
+ ...buttonProps,
206
+ disabled: state.loading,
207
+ type: "reset",
208
+ children: props.children
209
+ });
210
+ };
211
+ /**
212
+ * Action button that integrates with useAction hook return value.
213
+ * Automatically handles loading state and executes the action on click.
214
+ *
215
+ * @example
216
+ * ```tsx
217
+ * const saveAction = useAction({
218
+ * handler: async (data) => {
219
+ * await api.save(data);
220
+ * }
221
+ * }, []);
222
+ *
223
+ * <ActionButton action={saveAction}>
224
+ * Save
225
+ * </ActionButton>
226
+ * ```
227
+ */
228
+ const ActionHookButton = (props) => {
229
+ const { action, ...buttonProps } = props;
230
+ return /* @__PURE__ */ jsx(Button, {
231
+ ...buttonProps,
232
+ disabled: action.loading || props.disabled,
233
+ loading: action.loading,
234
+ onClick: () => action.run(),
235
+ children: props.children
236
+ });
237
+ };
238
+ /**
239
+ * Basic action button that handles click events with loading and error handling.
240
+ *
241
+ * @example
242
+ * ```tsx
243
+ * <ActionButton onClick={() => api.doSomething()}>
244
+ * Do Something
245
+ * </ActionButton>
246
+ * ```
247
+ */
248
+ const ActionClickButton = (props) => {
249
+ const action = useAction({ handler: async (e) => {
250
+ await props.onClick(e);
251
+ } }, [props.onClick]);
252
+ return /* @__PURE__ */ jsx(Button, {
253
+ ...props,
254
+ disabled: action.loading || props.disabled,
255
+ loading: action.loading,
256
+ onClick: action.run,
257
+ children: props.children
258
+ });
259
+ };
260
+ /**
261
+ * Action for navigation with active state support.
262
+ */
263
+ const ActionNavigationButton = (props) => {
264
+ const { active: options, classNameActive, variantActive, routerGoOptions, ...buttonProps } = props;
265
+ const router = useRouter();
266
+ const { isPending, isActive } = useActive(options ? {
267
+ href: props.href,
268
+ ...options
269
+ } : { href: props.href });
270
+ const anchorProps = router.anchor(props.href, routerGoOptions);
271
+ const className = buttonProps.className || "";
272
+ if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
273
+ if (props.anchorProps) return /* @__PURE__ */ jsx(Anchor, {
274
+ component: "a",
275
+ ...anchorProps,
276
+ ...props.anchorProps,
277
+ children: props.children
278
+ });
279
+ return /* @__PURE__ */ jsx(Button, {
280
+ component: "a",
281
+ loading: isPending,
282
+ ...buttonProps,
283
+ ...anchorProps,
284
+ variant: isActive && options !== false ? variantActive ?? "filled" : buttonProps.variant ?? "subtle",
285
+ children: props.children
286
+ });
287
+ };
288
+ const ActionHrefButton = (props) => {
289
+ const { active: options, classNameActive, variantActive, routerGoOptions, target, ...buttonProps } = props;
290
+ return /* @__PURE__ */ jsx(Button, {
291
+ component: "a",
292
+ target,
293
+ ...buttonProps,
294
+ children: props.children
295
+ });
296
+ };
297
+ function isComponentType(param) {
298
+ if (isValidElement(param)) return false;
299
+ return typeof param === "function" || typeof param === "object" && param !== null && "$$typeof" in param;
300
+ }
301
+
302
+ //#endregion
303
+ //#region src/core/components/buttons/ToggleSidebarButton.tsx
304
+ const ToggleSidebarButton = () => {
305
+ const [collapsed, setCollapsed] = useStore("alepha.ui.sidebar.collapsed");
306
+ return /* @__PURE__ */ jsx(ActionButton_default, {
307
+ icon: collapsed ? /* @__PURE__ */ jsx(IconLayoutSidebarRightCollapse, {}) : /* @__PURE__ */ jsx(IconLayoutSidebarLeftCollapse, {}),
308
+ variant: "subtle",
309
+ size: "md",
310
+ onClick: () => setCollapsed(!collapsed),
311
+ tooltip: {
312
+ position: "right",
313
+ label: collapsed ? "Show sidebar" : "Hide sidebar"
314
+ }
315
+ });
316
+ };
317
+ var ToggleSidebarButton_default = ToggleSidebarButton;
318
+
319
+ //#endregion
320
+ //#region src/admin/AdminSidebar.ts
321
+ var AdminSidebar = class {
322
+ menu = (router) => [
323
+ { element: createElement(ToggleSidebarButton_default) },
324
+ { type: "spacer" },
325
+ {
326
+ ...router.node("adminUsers"),
327
+ description: void 0
328
+ },
329
+ {
330
+ ...router.node("adminSessions"),
331
+ description: void 0
332
+ },
333
+ {
334
+ ...router.node("adminNotifications"),
335
+ description: void 0
336
+ },
337
+ {
338
+ ...router.node("adminFiles"),
339
+ description: void 0
340
+ }
341
+ ];
342
+ };
343
+
344
+ //#endregion
345
+ //#region src/admin/components/AdminLayout.tsx
346
+ const AdminLayout = () => {
347
+ const router = useRouter();
348
+ const sidebar = useInject(AdminSidebar);
349
+ return /* @__PURE__ */ jsx(AdminShell, {
350
+ appShellMainProps: { bg: "var(--alepha-surface)" },
351
+ appShellHeaderProps: { bg: "var(--alepha-background)" },
352
+ appShellNavbarProps: {},
353
+ appShellProps: {},
354
+ appShellFooterProps: { bg: "var(--alepha-background)" },
355
+ footer: /* @__PURE__ */ jsx(Flex$1, { h: 12 }),
356
+ appBarProps: { items: [
357
+ {
358
+ element: /* @__PURE__ */ jsx(ActionButton, {
359
+ icon: IconArrowLeft,
360
+ href: "/"
361
+ }),
362
+ position: "left"
363
+ },
364
+ {
365
+ element: /* @__PURE__ */ jsx(OmnibarButton, { actionProps: { variant: "outline" } }),
366
+ position: "right"
367
+ },
368
+ {
369
+ element: /* @__PURE__ */ jsx(UserButton, {}),
370
+ position: "right"
371
+ },
372
+ {
373
+ element: /* @__PURE__ */ jsx(ThemeButton, {}),
374
+ position: "right"
375
+ },
376
+ {
377
+ type: "dark",
378
+ position: "right"
379
+ }
380
+ ] },
381
+ sidebarProps: {
382
+ gap: "xs",
383
+ menu: sidebar.menu(router)
384
+ },
385
+ children: /* @__PURE__ */ jsx(Flex$1, {
386
+ flex: 1,
387
+ bg: "var(--alepha-surface)",
388
+ children: /* @__PURE__ */ jsx(NestedView, {})
389
+ })
390
+ });
391
+ };
392
+ var AdminLayout_default = AdminLayout;
393
+
394
+ //#endregion
395
+ export { AdminSidebar as n, AdminLayout_default as t };
396
+ //# sourceMappingURL=AdminLayout-Cm-Y4YTQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminLayout-Cm-Y4YTQ.js","names":["menuItemProps: MenuItemProps & ButtonHTMLAttributes<unknown>","ActionButton","icon","Flex","defaultTooltipProps: Partial<TooltipProps>","ActionButton","ToggleSidebarButton","Flex"],"sources":["../../src/core/constants/ui.ts","../../src/core/components/buttons/ActionButton.tsx","../../src/core/components/buttons/ToggleSidebarButton.tsx","../../src/admin/AdminSidebar.ts","../../src/admin/components/AdminLayout.tsx"],"sourcesContent":["export const ui = {\n colors: {\n transparent: \"transparent\",\n background: \"var(--alepha-background)\",\n surface: \"var(--alepha-surface)\",\n elevated: \"var(--alepha-elevated)\",\n border: \"var(--alepha-border)\",\n },\n sizes: {\n icon: {\n xs: 12,\n sm: 16,\n md: 20,\n lg: 24,\n xl: 32,\n },\n },\n};\n","import {\n type RouterGoOptions,\n type UseActionReturn,\n type UseActiveOptions,\n useAction,\n useActive,\n useRouter,\n} from \"@alepha/react\";\nimport { type FormModel, useFormState } from \"@alepha/react/form\";\nimport {\n Anchor,\n type AnchorProps,\n Button,\n type ButtonProps,\n Flex,\n Menu,\n type MenuItemProps,\n type MenuProps,\n type MenuTargetProps,\n ThemeIcon,\n type ThemeIconProps,\n Tooltip,\n type TooltipProps,\n} from \"@mantine/core\";\nimport { IconCheck, IconChevronRight } from \"@tabler/icons-react\";\nimport {\n type ButtonHTMLAttributes,\n Children,\n type ComponentType,\n isValidElement,\n type ReactNode,\n} from \"react\";\nimport { ui } from \"../../constants/ui.ts\";\n\nexport interface ActionMenuItem {\n /**\n * Menu item type\n */\n type?: \"item\" | \"divider\" | \"label\";\n\n /**\n * Label text for the menu item\n */\n label?: string | ReactNode;\n\n /**\n * Icon element to display before the label\n */\n icon?: ReactNode;\n\n /**\n * Click handler for menu items\n */\n onClick?: () => void;\n\n /**\n * Href for navigation menu items\n */\n href?: string;\n\n /**\n * Color for the menu item (e.g., \"red\" for danger actions)\n */\n color?: string;\n\n /**\n * Nested submenu items\n */\n children?: ActionMenuItem[];\n\n /**\n * Whether the menu item is active\n */\n active?: boolean;\n}\n\nexport interface ActionMenuConfig {\n /**\n * Array of menu items to display\n */\n items: ActionMenuItem[];\n\n /**\n * Menu position relative to the button\n */\n position?:\n | \"bottom\"\n | \"bottom-start\"\n | \"bottom-end\"\n | \"top\"\n | \"top-start\"\n | \"top-end\"\n | \"left\"\n | \"right\";\n\n /**\n * Menu width\n */\n width?: number | string;\n\n /**\n * Menu shadow\n */\n shadow?: \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n\n on?: \"hover\" | \"click\";\n\n targetProps?: MenuTargetProps;\n\n menuProps?: MenuProps;\n}\n\nexport interface ActionCommonProps extends ButtonProps {\n children?: ReactNode;\n\n textVisibleFrom?: \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n\n /**\n * Tooltip to display on hover. Can be a string for simple tooltips\n * or a TooltipProps object for advanced configuration.\n */\n tooltip?: string | TooltipProps;\n\n /**\n * Menu configuration. When provided, the action will display a dropdown menu.\n */\n menu?: ActionMenuConfig;\n\n /**\n * If set, a confirmation dialog will be shown before performing the action.\n * If `true`, a default title and message will be used.\n * If a string, it will be used as the message with a default title.\n * If an object, it can contain `title` and `message` properties to customize the dialog.\n */\n confirm?: boolean | string | { title?: string; message: string };\n\n /**\n * Icon to display on the left side of the button.\n * If no children are provided, the button will be styled as an icon-only button.\n */\n icon?: ReactNode | ComponentType;\n\n /**\n * Additional props to pass to the ThemeIcon wrapping the icon.\n */\n themeIconProps?: ThemeIconProps;\n\n /**\n * Visual intent of the action button.\n */\n intent?: \"primary\" | \"success\" | \"danger\" | \"warning\" | \"info\";\n}\n\nexport type ActionProps = ActionCommonProps &\n (\n | ActionNavigationButtonProps\n | ActionClickButtonProps\n | ActionSubmitButtonProps\n | ActionHookButtonProps\n | {}\n );\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n// Helper function to render menu items recursively\nconst ActionMenuItem = (props: {\n item: ActionMenuItem;\n index: number;\n}): ReactNode => {\n const { item, index } = props;\n\n const router = useRouter();\n const action = useAction(\n {\n handler: async (e: any) => {\n await item.onClick?.();\n },\n },\n [item.onClick],\n );\n\n // Render divider\n if (item.type === \"divider\") {\n return <Menu.Divider key={index} />;\n }\n\n // Render label\n if (item.type === \"label\") {\n return <Menu.Label key={index}>{item.label}</Menu.Label>;\n }\n\n // Render submenu if it has children\n if (item.children && item.children.length > 0) {\n return (\n <Menu key={index} trigger=\"hover\" position=\"right-start\" offset={2}>\n <Menu.Target>\n <Menu.Item\n leftSection={item.icon}\n rightSection={<IconChevronRight size={14} />}\n >\n {item.label}\n </Menu.Item>\n </Menu.Target>\n <Menu.Dropdown>\n {item.children.map((child, childIndex) => (\n <ActionMenuItem item={child} index={childIndex} key={childIndex} />\n ))}\n </Menu.Dropdown>\n </Menu>\n );\n }\n\n const menuItemProps: MenuItemProps & ButtonHTMLAttributes<unknown> = {};\n if (props.item.onClick) {\n menuItemProps.onClick = action.run;\n } else if (props.item.href) {\n Object.assign(menuItemProps, router.anchor(props.item.href));\n }\n\n // render regular menu item\n return (\n <Menu.Item\n key={index}\n leftSection={item.icon}\n onClick={item.onClick}\n color={item.color}\n rightSection={\n item.active ? (\n <ThemeIcon size={\"xs\"} variant={\"transparent\"}>\n <IconCheck />\n </ThemeIcon>\n ) : undefined\n }\n {...menuItemProps}\n >\n {item.label}\n </Menu.Item>\n );\n};\n\nconst ActionButton = (_props: ActionProps) => {\n const props = { variant: \"subtle\", ..._props };\n const { tooltip, menu, icon, ...restProps } = props;\n\n // set default color to gray (not colored)\n restProps.color ??= \"gray\";\n restProps.c ??= \"var(--mantine-color-text)\";\n\n if (props.icon) {\n const icon = isComponentType(props.icon) ? (\n <props.icon size={ui.sizes.icon.md} />\n ) : (\n <ThemeIcon\n w={24} // TODO: make size configurable\n variant={\"transparent\"}\n size={\"sm\"}\n c={\"var(--mantine-color-text)\"}\n {...props.themeIconProps}\n >\n {props.icon as ReactNode}\n </ThemeIcon>\n );\n\n if (!props.children) {\n restProps.children = Children.only(icon);\n restProps.px ??= \"xs\";\n } else {\n restProps.leftSection = icon;\n }\n }\n\n if (props.leftSection && !props.children) {\n restProps.px ??= \"xs\";\n }\n\n if (props.textVisibleFrom) {\n const { children, textVisibleFrom, leftSection, ...rest } = restProps;\n return (\n <>\n <Flex w={\"100%\"} visibleFrom={textVisibleFrom}>\n <ActionButton\n flex={1}\n {...rest}\n leftSection={leftSection}\n tooltip={tooltip}\n menu={menu}\n >\n {children}\n </ActionButton>\n </Flex>\n <Flex w={\"100%\"} hiddenFrom={textVisibleFrom}>\n <ActionButton px={\"xs\"} {...rest} tooltip={tooltip} menu={menu}>\n {leftSection}\n </ActionButton>\n </Flex>\n </>\n );\n }\n\n const renderAction = () => {\n if (\"href\" in restProps && restProps.href) {\n if (restProps.href.startsWith(\"http\") || restProps.target) {\n return (\n <ActionHrefButton {...restProps} href={restProps.href}>\n {restProps.children}\n </ActionHrefButton>\n );\n }\n return (\n <ActionNavigationButton {...restProps} href={restProps.href}>\n {restProps.children}\n </ActionNavigationButton>\n );\n }\n\n delete (restProps as any).classNameActive;\n delete (restProps as any).variantActive;\n\n if (\"action\" in restProps && restProps.action) {\n return (\n <ActionHookButton {...restProps} action={restProps.action}>\n {restProps.children}\n </ActionHookButton>\n );\n }\n\n if (\"onClick\" in restProps && restProps.onClick) {\n return (\n <ActionClickButton {...restProps} onClick={restProps.onClick}>\n {restProps.children}\n </ActionClickButton>\n );\n }\n\n if (\"form\" in restProps && restProps.form) {\n if (restProps.type === \"reset\") {\n return (\n <ActionResetButton {...restProps} form={restProps.form}>\n {restProps.children}\n </ActionResetButton>\n );\n }\n return (\n <ActionSubmitButton {...restProps} form={restProps.form}>\n {restProps.children}\n </ActionSubmitButton>\n );\n }\n\n return <Button {...(restProps as any)}>{restProps.children}</Button>;\n };\n\n let actionElement = renderAction();\n\n // wrap with Menu if provided\n if (menu) {\n actionElement = (\n <Menu\n position={menu.position || \"bottom-start\"}\n width={menu.width || 200}\n shadow={menu.shadow || \"md\"}\n trigger={menu.on === \"hover\" ? \"hover\" : \"click\"}\n {...menu.menuProps}\n >\n <Menu.Target {...menu.targetProps}>{actionElement}</Menu.Target>\n <Menu.Dropdown>\n {menu.items.map((item, index) => (\n <ActionMenuItem item={item} index={index} key={index} />\n ))}\n </Menu.Dropdown>\n </Menu>\n );\n }\n\n // Wrap with Tooltip if provided\n if (tooltip) {\n // openDelay: 1000 -> like HTML title attribute\n const defaultTooltipProps: Partial<TooltipProps> = {\n openDelay: 1000,\n };\n const tooltipProps: TooltipProps =\n typeof tooltip === \"string\"\n ? {\n ...defaultTooltipProps,\n label: tooltip,\n children: actionElement,\n }\n : { ...defaultTooltipProps, ...tooltip, children: actionElement };\n\n return <Tooltip {...tooltipProps} />;\n }\n\n return actionElement;\n};\n\nexport default ActionButton;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n// Action Submit\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface ActionSubmitButtonProps extends ButtonProps {\n form: FormModel<any>;\n type?: \"submit\" | \"reset\";\n}\n\n/**\n * Action button that submits a form with loading and disabled state handling.\n */\nconst ActionSubmitButton = (props: ActionSubmitButtonProps) => {\n const { form, ...buttonProps } = props;\n const state = useFormState(form);\n return (\n <Button\n {...buttonProps}\n loading={state.loading}\n disabled={state.loading}\n type={\"submit\"}\n >\n {props.children}\n </Button>\n );\n};\n\nconst ActionResetButton = (props: ActionSubmitButtonProps) => {\n const { form, ...buttonProps } = props;\n const state = useFormState(form);\n return (\n <Button {...buttonProps} disabled={state.loading} type={\"reset\"}>\n {props.children}\n </Button>\n );\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n// Action with useAction Hook\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface ActionHookButtonProps extends ButtonProps {\n action: UseActionReturn<any[], any>;\n}\n\n/**\n * Action button that integrates with useAction hook return value.\n * Automatically handles loading state and executes the action on click.\n *\n * @example\n * ```tsx\n * const saveAction = useAction({\n * handler: async (data) => {\n * await api.save(data);\n * }\n * }, []);\n *\n * <ActionButton action={saveAction}>\n * Save\n * </ActionButton>\n * ```\n */\nconst ActionHookButton = (props: ActionHookButtonProps) => {\n const { action, ...buttonProps } = props;\n\n return (\n <Button\n {...buttonProps}\n disabled={action.loading || props.disabled}\n loading={action.loading}\n onClick={() => action.run()}\n >\n {props.children}\n </Button>\n );\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n// Action Click\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface ActionClickButtonProps extends ButtonProps {\n onClick: (e: any) => any;\n}\n\n/**\n * Basic action button that handles click events with loading and error handling.\n *\n * @example\n * ```tsx\n * <ActionButton onClick={() => api.doSomething()}>\n * Do Something\n * </ActionButton>\n * ```\n */\nconst ActionClickButton = (props: ActionClickButtonProps) => {\n const action = useAction(\n {\n handler: async (e: any) => {\n await props.onClick(e);\n },\n },\n [props.onClick],\n );\n\n return (\n <Button\n {...props}\n disabled={action.loading || props.disabled}\n loading={action.loading}\n onClick={action.run}\n >\n {props.children}\n </Button>\n );\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n// Action Navigation\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface ActionNavigationButtonProps extends ButtonProps {\n href: string;\n active?: Partial<UseActiveOptions> | false;\n routerGoOptions?: RouterGoOptions;\n classNameActive?: string;\n variantActive?: ButtonProps[\"variant\"];\n target?: string;\n anchorProps?: AnchorProps;\n}\n\n/**\n * Action for navigation with active state support.\n */\nconst ActionNavigationButton = (props: ActionNavigationButtonProps) => {\n const {\n active: options,\n classNameActive,\n variantActive,\n routerGoOptions,\n ...buttonProps\n } = props;\n const router = useRouter();\n const { isPending, isActive } = useActive(\n options ? { href: props.href, ...options } : { href: props.href },\n );\n const anchorProps = router.anchor(props.href, routerGoOptions);\n\n const className = buttonProps.className || \"\";\n if (isActive && options !== false && classNameActive) {\n buttonProps.className = `${className} ${classNameActive}`.trim();\n }\n\n if (props.anchorProps) {\n return (\n <Anchor component={\"a\"} {...anchorProps} {...props.anchorProps}>\n {props.children}\n </Anchor>\n );\n }\n\n return (\n <Button\n component={\"a\"}\n loading={isPending}\n {...buttonProps}\n {...anchorProps}\n variant={\n isActive && options !== false\n ? (variantActive ?? \"filled\")\n : (buttonProps.variant ?? \"subtle\")\n }\n >\n {props.children}\n </Button>\n );\n};\n\nconst ActionHrefButton = (props: ActionNavigationButtonProps) => {\n const {\n active: options,\n classNameActive,\n variantActive,\n routerGoOptions,\n target,\n ...buttonProps\n } = props;\n\n return (\n <Button component={\"a\"} target={target} {...buttonProps}>\n {props.children}\n </Button>\n );\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport function isComponentType(param: any): param is ComponentType<any> {\n if (isValidElement(param)) return false;\n return (\n typeof param === \"function\" ||\n (typeof param === \"object\" && param !== null && \"$$typeof\" in param)\n );\n}\n\nexport const renderIcon = (icon: ReactNode | ComponentType): ReactNode => {\n if (!icon) return null;\n if (isValidElement(icon)) return icon;\n if (isComponentType(icon)) {\n const IconComponent = icon;\n return <IconComponent size={ui.sizes.icon.md} />;\n }\n return icon as ReactNode;\n};\n","import { useStore } from \"@alepha/react\";\nimport {\n IconLayoutSidebarLeftCollapse,\n IconLayoutSidebarRightCollapse,\n} from \"@tabler/icons-react\";\nimport ActionButton from \"./ActionButton.tsx\";\n\nconst ToggleSidebarButton = () => {\n const [collapsed, setCollapsed] = useStore(\"alepha.ui.sidebar.collapsed\");\n\n return (\n <ActionButton\n icon={\n collapsed ? (\n <IconLayoutSidebarRightCollapse />\n ) : (\n <IconLayoutSidebarLeftCollapse />\n )\n }\n variant={\"subtle\"}\n size={\"md\"}\n onClick={() => setCollapsed(!collapsed)}\n tooltip={{\n position: \"right\",\n label: collapsed ? \"Show sidebar\" : \"Hide sidebar\",\n }}\n />\n );\n};\n\nexport default ToggleSidebarButton;\n","import type { ReactRouter } from \"@alepha/react\";\nimport type { SidebarNode } from \"@alepha/ui\";\nimport { createElement } from \"react\";\nimport ToggleSidebarButton from \"../core/components/buttons/ToggleSidebarButton.tsx\";\n\nexport class AdminSidebar {\n public menu = (router: ReactRouter<any>): SidebarNode[] => [\n {\n element: createElement(ToggleSidebarButton),\n },\n {\n type: \"spacer\",\n },\n {\n ...router.node(\"adminUsers\"),\n description: undefined,\n },\n {\n ...router.node(\"adminSessions\"),\n description: undefined,\n },\n {\n ...router.node(\"adminNotifications\"),\n description: undefined,\n },\n {\n ...router.node(\"adminFiles\"),\n description: undefined,\n },\n ];\n}\n","import { NestedView, useInject, useRouter } from \"@alepha/react\";\nimport {\n ActionButton,\n AdminShell,\n OmnibarButton,\n ThemeButton,\n} from \"@alepha/ui\";\nimport { UserButton } from \"@alepha/ui/auth\";\nimport { Flex } from \"@mantine/core\";\nimport { IconArrowLeft } from \"@tabler/icons-react\";\nimport type { AdminRouter } from \"../AdminRouter.ts\";\nimport { AdminSidebar } from \"../AdminSidebar.ts\";\n\nconst AdminLayout = () => {\n const router = useRouter<AdminRouter>();\n const sidebar = useInject(AdminSidebar);\n\n return (\n <AdminShell\n appShellMainProps={{\n bg: \"var(--alepha-surface)\",\n }}\n appShellHeaderProps={{\n bg: \"var(--alepha-background)\",\n }}\n appShellNavbarProps={\n {\n // bg: \"var(--alepha-background)\",\n }\n }\n appShellProps={\n {\n // withBorder: false,\n }\n }\n appShellFooterProps={{\n bg: \"var(--alepha-background)\",\n }}\n footer={<Flex h={12} />}\n appBarProps={{\n items: [\n {\n element: <ActionButton icon={IconArrowLeft} href={\"/\"} />,\n position: \"left\",\n },\n {\n element: <OmnibarButton actionProps={{ variant: \"outline\" }} />,\n position: \"right\",\n },\n {\n element: <UserButton />,\n position: \"right\",\n },\n {\n element: <ThemeButton />,\n position: \"right\",\n },\n {\n type: \"dark\",\n position: \"right\",\n },\n ],\n }}\n sidebarProps={{\n gap: \"xs\",\n menu: sidebar.menu(router),\n }}\n >\n <Flex flex={1} bg={\"var(--alepha-surface)\"}>\n <NestedView />\n </Flex>\n </AdminShell>\n );\n};\n\nexport default AdminLayout;\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { t as AdminLayout_default } from "./AdminLayout-Cm-Y4YTQ.js";
2
+
3
+ export { AdminLayout_default as default };
@@ -0,0 +1,3 @@
1
+ import { t as AdminNotifications_default } from "./AdminNotifications-d-gw5Uie.js";
2
+
3
+ export { AdminNotifications_default as default };
@@ -0,0 +1,154 @@
1
+ import { DataTable, Flex, Text } from "@alepha/ui";
2
+ import { t } from "alepha";
3
+ import { useClient } from "@alepha/react";
4
+ import { IconAlertCircle, IconCheck, IconClock, IconMail, IconMessage } from "@tabler/icons-react";
5
+ import { Badge, Tooltip } from "@mantine/core";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { useI18n } from "@alepha/react/i18n";
8
+
9
+ //#region src/admin/components/AdminNotifications.tsx
10
+ const AdminNotifications = () => {
11
+ const client = useClient();
12
+ const { l } = useI18n();
13
+ const filters = t.object({
14
+ type: t.optional(t.enum(["email", "sms"], { title: "Type" })),
15
+ status: t.optional(t.enum([
16
+ "pending",
17
+ "sent",
18
+ "failed"
19
+ ], { title: "Status" })),
20
+ template: t.optional(t.string({ title: "Template" })),
21
+ contact: t.optional(t.string({ title: "Contact" }))
22
+ });
23
+ const getStatus = (item) => {
24
+ if (item.error) return "failed";
25
+ if (item.sentAt) return "sent";
26
+ return "pending";
27
+ };
28
+ const getStatusBadge = (item) => {
29
+ switch (getStatus(item)) {
30
+ case "sent": return /* @__PURE__ */ jsx(Badge, {
31
+ size: "sm",
32
+ variant: "light",
33
+ color: "green",
34
+ leftSection: /* @__PURE__ */ jsx(IconCheck, { size: 12 }),
35
+ children: "Sent"
36
+ });
37
+ case "failed": return /* @__PURE__ */ jsx(Tooltip, {
38
+ label: item.error?.message,
39
+ multiline: true,
40
+ maw: 300,
41
+ children: /* @__PURE__ */ jsx(Badge, {
42
+ size: "sm",
43
+ variant: "light",
44
+ color: "red",
45
+ leftSection: /* @__PURE__ */ jsx(IconAlertCircle, { size: 12 }),
46
+ children: "Failed"
47
+ })
48
+ });
49
+ default: return /* @__PURE__ */ jsx(Badge, {
50
+ size: "sm",
51
+ variant: "light",
52
+ color: "yellow",
53
+ leftSection: /* @__PURE__ */ jsx(IconClock, { size: 12 }),
54
+ children: "Pending"
55
+ });
56
+ }
57
+ };
58
+ return /* @__PURE__ */ jsx(Flex, {
59
+ flex: 1,
60
+ direction: "column",
61
+ children: /* @__PURE__ */ jsx(DataTable, {
62
+ submitOnInit: true,
63
+ defaultSize: 10,
64
+ typeFormProps: {
65
+ skipSubmitButton: true,
66
+ columns: 4
67
+ },
68
+ tableProps: {
69
+ horizontalSpacing: "xs",
70
+ verticalSpacing: "xs"
71
+ },
72
+ onFilterChange: (_key, _value, form) => {
73
+ return form.submit();
74
+ },
75
+ filters,
76
+ tableTrProps: (item) => {
77
+ if (getStatus(item) === "failed") return { bg: "var(--mantine-color-red-light)" };
78
+ return {};
79
+ },
80
+ items: async (filters$1) => {
81
+ return await client.findNotifications({ query: filters$1 });
82
+ },
83
+ columns: {
84
+ type: {
85
+ label: "Type",
86
+ fit: true,
87
+ value: (item) => /* @__PURE__ */ jsx(Badge, {
88
+ size: "sm",
89
+ variant: "outline",
90
+ leftSection: item.type === "email" ? /* @__PURE__ */ jsx(IconMail, { size: 12 }) : /* @__PURE__ */ jsx(IconMessage, { size: 12 }),
91
+ children: item.type.toUpperCase()
92
+ })
93
+ },
94
+ template: {
95
+ label: "Template",
96
+ value: (item) => /* @__PURE__ */ jsx(Text, {
97
+ size: "sm",
98
+ fw: 500,
99
+ children: item.template
100
+ })
101
+ },
102
+ contact: {
103
+ label: "Contact",
104
+ value: (item) => /* @__PURE__ */ jsx(Text, {
105
+ size: "sm",
106
+ ff: "monospace",
107
+ children: item.contact
108
+ })
109
+ },
110
+ category: {
111
+ label: "Category",
112
+ fit: true,
113
+ value: (item) => item.category ? /* @__PURE__ */ jsx(Badge, {
114
+ size: "xs",
115
+ variant: "light",
116
+ children: item.category
117
+ }) : /* @__PURE__ */ jsx(Text, {
118
+ size: "xs",
119
+ c: "dimmed",
120
+ children: "-"
121
+ })
122
+ },
123
+ status: {
124
+ label: "Status",
125
+ fit: true,
126
+ value: (item) => getStatusBadge(item)
127
+ },
128
+ sentAt: {
129
+ label: "Sent",
130
+ fit: true,
131
+ value: (item) => /* @__PURE__ */ jsx(Text, {
132
+ size: "xs",
133
+ c: "dimmed",
134
+ children: item.sentAt ? l(item.sentAt, { date: "fromNow" }) : "-"
135
+ })
136
+ },
137
+ createdAt: {
138
+ label: "Created",
139
+ fit: true,
140
+ value: (item) => /* @__PURE__ */ jsx(Text, {
141
+ size: "xs",
142
+ c: "dimmed",
143
+ children: l(item.createdAt, { date: "fromNow" })
144
+ })
145
+ }
146
+ }
147
+ })
148
+ });
149
+ };
150
+ var AdminNotifications_default = AdminNotifications;
151
+
152
+ //#endregion
153
+ export { AdminNotifications_default as t };
154
+ //# sourceMappingURL=AdminNotifications-d-gw5Uie.js.map