@questpie/admin 0.0.1 → 1.0.1

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 (250) hide show
  1. package/README.md +439 -424
  2. package/dist/auth-layout-M8K8_q5R.mjs +181 -0
  3. package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
  4. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs +273 -0
  5. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs.map +1 -0
  6. package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
  7. package/dist/card-BKHjBQfw.mjs.map +1 -0
  8. package/dist/client/styles/index.css +434 -0
  9. package/dist/client-DbpZKSgH.d.mts +13585 -0
  10. package/dist/client-DbpZKSgH.d.mts.map +1 -0
  11. package/dist/client-njX1rZmi.mjs +22612 -0
  12. package/dist/client-njX1rZmi.mjs.map +1 -0
  13. package/dist/client.d.mts +3 -0
  14. package/dist/client.mjs +13 -0
  15. package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
  16. package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
  17. package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
  18. package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
  19. package/dist/dashboard-page-mCY0pgZv.mjs +3 -0
  20. package/dist/dropzone-Do3awXKd.mjs +634 -0
  21. package/dist/dropzone-Do3awXKd.mjs.map +1 -0
  22. package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
  23. package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
  24. package/dist/forgot-password-page-CEwsdLwn.mjs +3 -0
  25. package/dist/index-B9Xwk4hi.d.mts +2753 -0
  26. package/dist/index-B9Xwk4hi.d.mts.map +1 -0
  27. package/dist/index.d.mts +3 -0
  28. package/dist/index.mjs +13 -0
  29. package/dist/login-page-BUnpCbCa.mjs +3 -0
  30. package/dist/login-page-CP4gA-dl.mjs +298 -0
  31. package/dist/login-page-CP4gA-dl.mjs.map +1 -0
  32. package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
  33. package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
  34. package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
  35. package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
  36. package/dist/reset-password-page-CufHz3h3.mjs +3 -0
  37. package/dist/runtime-6VZM878K.mjs +69 -0
  38. package/dist/runtime-6VZM878K.mjs.map +1 -0
  39. package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
  40. package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
  41. package/dist/server.d.mts +250 -0
  42. package/dist/server.d.mts.map +1 -0
  43. package/dist/server.mjs +832 -0
  44. package/dist/server.mjs.map +1 -0
  45. package/dist/setup-page-BNNzt_Z6.mjs +3 -0
  46. package/dist/setup-page-YAP_fzqh.mjs +264 -0
  47. package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
  48. package/dist/shared.d.mts +57 -0
  49. package/dist/shared.d.mts.map +1 -0
  50. package/dist/shared.mjs +3 -0
  51. package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
  52. package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
  53. package/package.json +48 -198
  54. package/.turbo/turbo-build.log +0 -108
  55. package/CHANGELOG.md +0 -10
  56. package/STATUS.md +0 -917
  57. package/VALIDATION.md +0 -602
  58. package/components.json +0 -24
  59. package/dist/__tests__/setup.mjs +0 -38
  60. package/dist/__tests__/test-utils.mjs +0 -45
  61. package/dist/__tests__/vitest.d.mjs +0 -3
  62. package/dist/components/admin-app.mjs +0 -69
  63. package/dist/components/fields/array-field.mjs +0 -190
  64. package/dist/components/fields/checkbox-field.mjs +0 -34
  65. package/dist/components/fields/custom-field.mjs +0 -32
  66. package/dist/components/fields/date-field.mjs +0 -41
  67. package/dist/components/fields/datetime-field.mjs +0 -42
  68. package/dist/components/fields/email-field.mjs +0 -37
  69. package/dist/components/fields/embedded-collection.mjs +0 -253
  70. package/dist/components/fields/field-types.mjs +0 -1
  71. package/dist/components/fields/field-utils.mjs +0 -10
  72. package/dist/components/fields/field-wrapper.mjs +0 -34
  73. package/dist/components/fields/index.mjs +0 -23
  74. package/dist/components/fields/json-field.mjs +0 -243
  75. package/dist/components/fields/locale-badge.mjs +0 -16
  76. package/dist/components/fields/number-field.mjs +0 -39
  77. package/dist/components/fields/password-field.mjs +0 -37
  78. package/dist/components/fields/relation-field.mjs +0 -104
  79. package/dist/components/fields/relation-picker.mjs +0 -229
  80. package/dist/components/fields/relation-select.mjs +0 -188
  81. package/dist/components/fields/rich-text-editor/index.mjs +0 -897
  82. package/dist/components/fields/select-field.mjs +0 -41
  83. package/dist/components/fields/switch-field.mjs +0 -34
  84. package/dist/components/fields/text-field.mjs +0 -38
  85. package/dist/components/fields/textarea-field.mjs +0 -38
  86. package/dist/components/index.mjs +0 -59
  87. package/dist/components/primitives/checkbox-input.mjs +0 -127
  88. package/dist/components/primitives/date-input.mjs +0 -303
  89. package/dist/components/primitives/index.mjs +0 -12
  90. package/dist/components/primitives/number-input.mjs +0 -104
  91. package/dist/components/primitives/select-input.mjs +0 -177
  92. package/dist/components/primitives/tag-input.mjs +0 -135
  93. package/dist/components/primitives/text-input.mjs +0 -39
  94. package/dist/components/primitives/textarea-input.mjs +0 -37
  95. package/dist/components/primitives/toggle-input.mjs +0 -31
  96. package/dist/components/primitives/types.mjs +0 -12
  97. package/dist/components/ui/accordion.mjs +0 -55
  98. package/dist/components/ui/avatar.mjs +0 -54
  99. package/dist/components/ui/badge.mjs +0 -34
  100. package/dist/components/ui/button.mjs +0 -48
  101. package/dist/components/ui/checkbox.mjs +0 -21
  102. package/dist/components/ui/combobox.mjs +0 -163
  103. package/dist/components/ui/dialog.mjs +0 -95
  104. package/dist/components/ui/dropdown-menu.mjs +0 -138
  105. package/dist/components/ui/field.mjs +0 -113
  106. package/dist/components/ui/input-group.mjs +0 -82
  107. package/dist/components/ui/input.mjs +0 -17
  108. package/dist/components/ui/label.mjs +0 -15
  109. package/dist/components/ui/popover.mjs +0 -56
  110. package/dist/components/ui/scroll-area.mjs +0 -38
  111. package/dist/components/ui/select.mjs +0 -100
  112. package/dist/components/ui/separator.mjs +0 -16
  113. package/dist/components/ui/sheet.mjs +0 -90
  114. package/dist/components/ui/sidebar.mjs +0 -387
  115. package/dist/components/ui/skeleton.mjs +0 -14
  116. package/dist/components/ui/spinner.mjs +0 -16
  117. package/dist/components/ui/switch.mjs +0 -22
  118. package/dist/components/ui/table.mjs +0 -68
  119. package/dist/components/ui/tabs.mjs +0 -48
  120. package/dist/components/ui/textarea.mjs +0 -15
  121. package/dist/components/ui/tooltip.mjs +0 -44
  122. package/dist/config/component-registry.mjs +0 -38
  123. package/dist/config/index.mjs +0 -129
  124. package/dist/hooks/admin-provider.mjs +0 -70
  125. package/dist/hooks/index.mjs +0 -7
  126. package/dist/hooks/store.mjs +0 -178
  127. package/dist/hooks/use-collection-db.mjs +0 -146
  128. package/dist/hooks/use-collection.mjs +0 -112
  129. package/dist/hooks/use-global.mjs +0 -46
  130. package/dist/hooks/use-mobile.mjs +0 -20
  131. package/dist/lib/utils.mjs +0 -10
  132. package/dist/styles/index.css +0 -336
  133. package/dist/styles/index.mjs +0 -1
  134. package/dist/utils/index.mjs +0 -9
  135. package/dist/views/auth/auth-layout.mjs +0 -52
  136. package/dist/views/auth/index.mjs +0 -6
  137. package/dist/views/auth/login-form.mjs +0 -156
  138. package/dist/views/collection/auto-form-fields.mjs +0 -525
  139. package/dist/views/collection/collection-form.mjs +0 -91
  140. package/dist/views/collection/collection-list.mjs +0 -76
  141. package/dist/views/collection/form-field.mjs +0 -42
  142. package/dist/views/collection/index.mjs +0 -6
  143. package/dist/views/common/index.mjs +0 -4
  144. package/dist/views/common/locale-switcher.mjs +0 -39
  145. package/dist/views/common/version-history.mjs +0 -272
  146. package/dist/views/index.mjs +0 -9
  147. package/dist/views/layout/admin-layout.mjs +0 -40
  148. package/dist/views/layout/admin-router.mjs +0 -95
  149. package/dist/views/layout/admin-sidebar.mjs +0 -63
  150. package/dist/views/layout/index.mjs +0 -5
  151. package/src/__tests__/setup.ts +0 -44
  152. package/src/__tests__/test-utils.tsx +0 -49
  153. package/src/__tests__/vitest.d.ts +0 -9
  154. package/src/components/admin-app.tsx +0 -221
  155. package/src/components/fields/array-field.tsx +0 -237
  156. package/src/components/fields/checkbox-field.tsx +0 -47
  157. package/src/components/fields/custom-field.tsx +0 -50
  158. package/src/components/fields/date-field.tsx +0 -65
  159. package/src/components/fields/datetime-field.tsx +0 -67
  160. package/src/components/fields/email-field.tsx +0 -51
  161. package/src/components/fields/embedded-collection.tsx +0 -315
  162. package/src/components/fields/field-types.ts +0 -162
  163. package/src/components/fields/field-utils.ts +0 -6
  164. package/src/components/fields/field-wrapper.tsx +0 -52
  165. package/src/components/fields/index.ts +0 -66
  166. package/src/components/fields/json-field.tsx +0 -440
  167. package/src/components/fields/locale-badge.tsx +0 -15
  168. package/src/components/fields/number-field.tsx +0 -57
  169. package/src/components/fields/password-field.tsx +0 -51
  170. package/src/components/fields/relation-field.tsx +0 -243
  171. package/src/components/fields/relation-picker.tsx +0 -402
  172. package/src/components/fields/relation-select.tsx +0 -327
  173. package/src/components/fields/rich-text-editor/index.tsx +0 -1337
  174. package/src/components/fields/select-field.tsx +0 -61
  175. package/src/components/fields/switch-field.tsx +0 -47
  176. package/src/components/fields/text-field.tsx +0 -55
  177. package/src/components/fields/textarea-field.tsx +0 -55
  178. package/src/components/index.ts +0 -40
  179. package/src/components/primitives/checkbox-input.tsx +0 -193
  180. package/src/components/primitives/date-input.tsx +0 -401
  181. package/src/components/primitives/index.ts +0 -24
  182. package/src/components/primitives/number-input.tsx +0 -132
  183. package/src/components/primitives/select-input.tsx +0 -296
  184. package/src/components/primitives/tag-input.tsx +0 -200
  185. package/src/components/primitives/text-input.tsx +0 -49
  186. package/src/components/primitives/textarea-input.tsx +0 -46
  187. package/src/components/primitives/toggle-input.tsx +0 -36
  188. package/src/components/primitives/types.ts +0 -235
  189. package/src/components/ui/accordion.tsx +0 -72
  190. package/src/components/ui/avatar.tsx +0 -106
  191. package/src/components/ui/badge.tsx +0 -48
  192. package/src/components/ui/button.tsx +0 -53
  193. package/src/components/ui/card.tsx +0 -94
  194. package/src/components/ui/checkbox.tsx +0 -27
  195. package/src/components/ui/combobox.tsx +0 -290
  196. package/src/components/ui/dialog.tsx +0 -151
  197. package/src/components/ui/dropdown-menu.tsx +0 -254
  198. package/src/components/ui/field.tsx +0 -227
  199. package/src/components/ui/input-group.tsx +0 -149
  200. package/src/components/ui/input.tsx +0 -20
  201. package/src/components/ui/label.tsx +0 -18
  202. package/src/components/ui/popover.tsx +0 -88
  203. package/src/components/ui/scroll-area.tsx +0 -53
  204. package/src/components/ui/select.tsx +0 -192
  205. package/src/components/ui/separator.tsx +0 -23
  206. package/src/components/ui/sheet.tsx +0 -127
  207. package/src/components/ui/sidebar.tsx +0 -723
  208. package/src/components/ui/skeleton.tsx +0 -13
  209. package/src/components/ui/spinner.tsx +0 -10
  210. package/src/components/ui/switch.tsx +0 -32
  211. package/src/components/ui/table.tsx +0 -99
  212. package/src/components/ui/tabs.tsx +0 -82
  213. package/src/components/ui/textarea.tsx +0 -18
  214. package/src/components/ui/tooltip.tsx +0 -70
  215. package/src/config/component-registry.ts +0 -190
  216. package/src/config/index.ts +0 -1099
  217. package/src/hooks/README.md +0 -269
  218. package/src/hooks/admin-provider.tsx +0 -110
  219. package/src/hooks/index.ts +0 -41
  220. package/src/hooks/store.ts +0 -248
  221. package/src/hooks/use-auth.ts +0 -168
  222. package/src/hooks/use-collection-db.ts +0 -209
  223. package/src/hooks/use-collection.ts +0 -156
  224. package/src/hooks/use-global.ts +0 -69
  225. package/src/hooks/use-mobile.ts +0 -21
  226. package/src/lib/utils.ts +0 -6
  227. package/src/styles/index.css +0 -340
  228. package/src/utils/index.ts +0 -6
  229. package/src/views/auth/auth-layout.tsx +0 -77
  230. package/src/views/auth/forgot-password-form.tsx +0 -192
  231. package/src/views/auth/index.ts +0 -21
  232. package/src/views/auth/login-form.tsx +0 -229
  233. package/src/views/auth/reset-password-form.tsx +0 -232
  234. package/src/views/collection/auto-form-fields.tsx +0 -982
  235. package/src/views/collection/collection-form.tsx +0 -186
  236. package/src/views/collection/collection-list.tsx +0 -223
  237. package/src/views/collection/form-field.tsx +0 -52
  238. package/src/views/collection/index.ts +0 -15
  239. package/src/views/common/index.ts +0 -8
  240. package/src/views/common/locale-switcher.tsx +0 -45
  241. package/src/views/common/version-history.tsx +0 -406
  242. package/src/views/index.ts +0 -25
  243. package/src/views/layout/admin-layout.tsx +0 -117
  244. package/src/views/layout/admin-router.tsx +0 -206
  245. package/src/views/layout/admin-sidebar.tsx +0 -185
  246. package/src/views/layout/index.ts +0 -12
  247. package/tsconfig.json +0 -13
  248. package/tsconfig.tsbuildinfo +0 -1
  249. package/tsdown.config.ts +0 -13
  250. package/vitest.config.ts +0 -29
@@ -1,129 +0,0 @@
1
- //#region src/config/index.ts
2
- /**
3
- * Define admin configuration with type inference
4
- *
5
- * @example
6
- * ```ts
7
- * import { defineAdminConfig } from '@questpie/admin/config'
8
- * import type { cms } from './server/cms'
9
- *
10
- * export const admin = defineAdminConfig<typeof cms>()({
11
- * app: {
12
- * brand: { name: "My CMS" }
13
- * },
14
- * collections: {
15
- * posts: {
16
- * label: "Posts",
17
- * icon: "posts"
18
- * }
19
- * }
20
- * })
21
- * ```
22
- */
23
- const defineAdminConfig = () => (config) => {
24
- return config;
25
- };
26
- /**
27
- * Define a single collection config (for modular configs)
28
- *
29
- * @example
30
- * ```ts
31
- * // collections/posts.admin.ts
32
- * import { defineCollectionConfig } from '@questpie/admin/config'
33
- * import type { cms } from '../server/cms'
34
- *
35
- * export const postsAdminConfig = defineCollectionConfig<typeof cms, "posts">()({
36
- * label: "Blog Posts",
37
- * icon: "article",
38
- * list: {
39
- * defaultColumns: ["title", "status", "createdAt"],
40
- * },
41
- * edit: {
42
- * sections: [
43
- * { title: "Content", fields: ["title", "content"] },
44
- * { title: "Settings", fields: ["status", "publishedAt"] },
45
- * ],
46
- * },
47
- * })
48
- * ```
49
- */
50
- const defineCollectionConfig = () => (config) => {
51
- return config;
52
- };
53
- /**
54
- * Merge multiple admin configs into one
55
- *
56
- * @example
57
- * ```ts
58
- * const admin = defineAdminConfig<typeof cms>()(
59
- * mergeAdminConfigs([
60
- * baseConfig,
61
- * postsConfig,
62
- * productsConfig,
63
- * ])
64
- * )
65
- * ```
66
- */
67
- function mergeAdminConfigs(configs) {
68
- const result = { app: {} };
69
- for (const config of configs) {
70
- if (config.app) result.app = {
71
- ...result.app,
72
- ...config.app
73
- };
74
- if (config.collections) result.collections = {
75
- ...result.collections,
76
- ...config.collections
77
- };
78
- }
79
- return result;
80
- }
81
- /**
82
- * Define app config separately
83
- *
84
- * @example
85
- * ```ts
86
- * export const appConfig = defineAppConfig({
87
- * brand: { name: "My CMS" },
88
- * locales: { default: "en", available: ["en", "sk"] },
89
- * })
90
- * ```
91
- */
92
- const defineAppConfig = (config) => {
93
- return config;
94
- };
95
- /**
96
- * Define dashboard config
97
- *
98
- * @example
99
- * ```ts
100
- * export const dashboardConfig = defineDashboardConfig({
101
- * widgets: [
102
- * { id: "stats", type: "stats", position: { x: 0, y: 0, w: 4, h: 2 } },
103
- * ],
104
- * })
105
- * ```
106
- */
107
- const defineDashboardConfig = (config) => {
108
- return config;
109
- };
110
- /**
111
- * Define views configuration
112
- *
113
- * @example
114
- * ```ts
115
- * import { defineViewsConfig } from '@questpie/admin/config'
116
- * import { CustomLoginForm } from './components/CustomLoginForm'
117
- *
118
- * export const viewsConfig = defineViewsConfig({
119
- * LoginForm: CustomLoginForm,
120
- * // Override any default view
121
- * })
122
- * ```
123
- */
124
- const defineViewsConfig = (config) => {
125
- return config;
126
- };
127
-
128
- //#endregion
129
- export { defineAdminConfig, defineAppConfig, defineCollectionConfig, defineDashboardConfig, defineViewsConfig, mergeAdminConfigs };
@@ -1,70 +0,0 @@
1
- import React, { createContext, useContext } from "react";
2
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3
- import { jsx } from "react/jsx-runtime";
4
-
5
- //#region src/hooks/admin-provider.tsx
6
- const AdminContextInstance = createContext(null);
7
- /**
8
- * Hook to access admin context
9
- */
10
- function useAdminContext() {
11
- const context = useContext(AdminContextInstance);
12
- if (!context) throw new Error("useAdminContext must be used within AdminProvider. Wrap your app with <AdminProvider client={client}>");
13
- return context;
14
- }
15
- /**
16
- * Admin provider - provides CMS client and query client to the app
17
- *
18
- * @example
19
- * ```tsx
20
- * import { AdminProvider } from '@questpie/admin/hooks'
21
- * import { createQuestpieClient } from 'questpie/client'
22
- * import { QueryClient } from '@tanstack/react-query'
23
- * import type { cms } from './server/cms'
24
- *
25
- * const client = createQuestpieClient<typeof cms>({
26
- * baseURL: 'http://localhost:3000'
27
- * })
28
- *
29
- * const queryClient = new QueryClient()
30
- *
31
- * function App() {
32
- * return (
33
- * <AdminProvider client={client} queryClient={queryClient}>
34
- * <YourAdminApp />
35
- * </AdminProvider>
36
- * )
37
- * }
38
- * ```
39
- */
40
- function AdminProvider({ client, queryClient, locales, children }) {
41
- const [defaultQueryClient] = React.useState(() => queryClient ?? new QueryClient());
42
- const [locale, setLocale] = React.useState(() => {
43
- if (locales?.default) return locales.default;
44
- if (locales?.available?.length) return locales.available[0];
45
- return typeof client.getLocale === "function" ? client.getLocale() : void 0;
46
- });
47
- React.useEffect(() => {
48
- if (!locales?.available?.length) return;
49
- if (!locale || !locales.available.includes(locale)) setLocale(locales.default ?? locales.available[0]);
50
- }, [locale, locales]);
51
- React.useEffect(() => {
52
- if (typeof client.setLocale !== "function") return;
53
- client.setLocale(locale);
54
- }, [client, locale]);
55
- return /* @__PURE__ */ jsx(AdminContextInstance.Provider, {
56
- value: {
57
- client,
58
- locale,
59
- setLocale,
60
- locales
61
- },
62
- children: /* @__PURE__ */ jsx(QueryClientProvider, {
63
- client: defaultQueryClient,
64
- children
65
- })
66
- });
67
- }
68
-
69
- //#endregion
70
- export { AdminProvider, useAdminContext };
@@ -1,7 +0,0 @@
1
- import { AdminProvider, useAdminContext } from "./admin-provider";
2
- import { createAdminAuthClient } from "./use-auth";
3
- import { useCollection, useCollectionDelete, useCollectionInsert, useCollectionItemById, useCollectionUpdate } from "./use-collection-db";
4
- import { useCollectionCreate, useCollectionDelete as useCollectionDeleteMutation, useCollectionItem, useCollectionList, useCollectionUpdate as useCollectionUpdateMutation } from "./use-collection";
5
- import { useGlobal, useGlobalUpdate } from "./use-global";
6
-
7
- export { AdminProvider, createAdminAuthClient, useAdminContext, useCollection, useCollectionCreate, useCollectionDelete, useCollectionDeleteMutation, useCollectionInsert, useCollectionItem, useCollectionItemById, useCollectionList, useCollectionUpdate, useCollectionUpdateMutation, useGlobal, useGlobalUpdate };
@@ -1,178 +0,0 @@
1
- import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
2
- import { atomWithStorage } from "jotai/utils";
3
-
4
- //#region src/hooks/store.ts
5
- /**
6
- * Jotai Store for Admin State Management
7
- *
8
- * Centralized state atoms for the admin UI.
9
- * Uses Jotai for reactive, atomic state management.
10
- */
11
- /**
12
- * Sidebar collapsed state (persisted to localStorage)
13
- */
14
- const sidebarCollapsedAtom = atomWithStorage("admin:sidebar-collapsed", false);
15
- /**
16
- * Current active locale
17
- */
18
- const localeAtom = atom(null);
19
- /**
20
- * Available locales configuration
21
- */
22
- const localesConfigAtom = atom(null);
23
- /**
24
- * Mobile menu open state
25
- */
26
- const mobileMenuOpenAtom = atom(false);
27
- /**
28
- * Command palette open state
29
- */
30
- const commandPaletteOpenAtom = atom(false);
31
- const themeModeAtom = atomWithStorage("admin:theme-mode", "system");
32
- /**
33
- * Derived atom for resolved theme (accounts for system preference)
34
- */
35
- const resolvedThemeAtom = atom((get) => {
36
- const mode = get(themeModeAtom);
37
- if (mode !== "system") return mode;
38
- if (typeof window !== "undefined") return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
39
- return "light";
40
- });
41
- /**
42
- * Current active collection (for breadcrumbs, etc.)
43
- */
44
- const activeCollectionAtom = atom(null);
45
- /**
46
- * Current active item ID (for editing)
47
- */
48
- const activeItemIdAtom = atom(null);
49
- /**
50
- * Navigation history stack
51
- */
52
- const navigationHistoryAtom = atom([]);
53
- /**
54
- * Global form dirty state (to warn on navigation)
55
- */
56
- const formDirtyAtom = atom(false);
57
- /**
58
- * Active form errors count
59
- */
60
- const formErrorsCountAtom = atom(0);
61
- const notificationsAtom = atom([]);
62
- /**
63
- * Derived atom to add notification
64
- */
65
- const addNotificationAtom = atom(null, (get, set, notification) => {
66
- const id = Math.random().toString(36).substring(2, 9);
67
- const newNotification = {
68
- ...notification,
69
- id
70
- };
71
- set(notificationsAtom, [...get(notificationsAtom), newNotification]);
72
- if (notification.duration !== 0) setTimeout(() => {
73
- set(notificationsAtom, (prev) => prev.filter((n) => n.id !== id));
74
- }, notification.duration ?? 5e3);
75
- return id;
76
- });
77
- /**
78
- * Derived atom to remove notification
79
- */
80
- const removeNotificationAtom = atom(null, (get, set, id) => {
81
- set(notificationsAtom, (prev) => prev.filter((n) => n.id !== id));
82
- });
83
- /**
84
- * Hook for sidebar state
85
- */
86
- function useSidebar() {
87
- const [collapsed, setCollapsed] = useAtom(sidebarCollapsedAtom);
88
- return {
89
- collapsed,
90
- setCollapsed,
91
- toggle: () => setCollapsed(!collapsed)
92
- };
93
- }
94
- /**
95
- * Hook for theme state
96
- */
97
- function useTheme() {
98
- const [mode, setMode] = useAtom(themeModeAtom);
99
- const resolved = useAtomValue(resolvedThemeAtom);
100
- return {
101
- mode,
102
- setMode,
103
- resolved,
104
- isDark: resolved === "dark",
105
- isLight: resolved === "light"
106
- };
107
- }
108
- /**
109
- * Hook for locale state
110
- */
111
- function useLocale() {
112
- const [locale, setLocale] = useAtom(localeAtom);
113
- const config = useAtomValue(localesConfigAtom);
114
- return {
115
- locale: locale ?? config?.default ?? null,
116
- setLocale,
117
- available: config?.available ?? [],
118
- default: config?.default ?? null
119
- };
120
- }
121
- /**
122
- * Hook for notifications
123
- */
124
- function useNotifications() {
125
- const notifications = useAtomValue(notificationsAtom);
126
- const addNotification = useSetAtom(addNotificationAtom);
127
- return {
128
- notifications,
129
- add: addNotification,
130
- remove: useSetAtom(removeNotificationAtom),
131
- success: (title, message) => addNotification({
132
- type: "success",
133
- title,
134
- message
135
- }),
136
- error: (title, message) => addNotification({
137
- type: "error",
138
- title,
139
- message
140
- }),
141
- warning: (title, message) => addNotification({
142
- type: "warning",
143
- title,
144
- message
145
- }),
146
- info: (title, message) => addNotification({
147
- type: "info",
148
- title,
149
- message
150
- })
151
- };
152
- }
153
- /**
154
- * Hook for command palette
155
- */
156
- function useCommandPalette() {
157
- const [open, setOpen] = useAtom(commandPaletteOpenAtom);
158
- return {
159
- open,
160
- setOpen,
161
- toggle: () => setOpen(!open)
162
- };
163
- }
164
- /**
165
- * Hook for form dirty state
166
- */
167
- function useFormDirty() {
168
- const [dirty, setDirty] = useAtom(formDirtyAtom);
169
- return {
170
- dirty,
171
- setDirty,
172
- markDirty: () => setDirty(true),
173
- markClean: () => setDirty(false)
174
- };
175
- }
176
-
177
- //#endregion
178
- export { activeCollectionAtom, activeItemIdAtom, addNotificationAtom, commandPaletteOpenAtom, formDirtyAtom, formErrorsCountAtom, localeAtom, localesConfigAtom, mobileMenuOpenAtom, navigationHistoryAtom, notificationsAtom, removeNotificationAtom, resolvedThemeAtom, sidebarCollapsedAtom, themeModeAtom, useCommandPalette, useFormDirty, useLocale, useNotifications, useSidebar, useTheme };
@@ -1,146 +0,0 @@
1
- import { useMemo } from "react";
2
- import { useQueryClient } from "@tanstack/react-query";
3
- import { useAdminContext } from "./admin-provider";
4
- import { createQuestpieDBHelpers } from "@questpie/tanstack-query/db";
5
-
6
- //#region src/hooks/use-collection-db.ts
7
- /**
8
- * Hook to get TanStack DB Collection for a CMS collection
9
- * Provides offline-first, realtime-synced collection with optimistic updates
10
- *
11
- * @example
12
- * ```tsx
13
- * function PostsList() {
14
- * const posts = useCollection('posts', {
15
- * baseFindOptions: { where: { published: { eq: true } } },
16
- * realtime: true, // Enable realtime sync
17
- * })
18
- *
19
- * return (
20
- * <div>
21
- * {posts.items.map(post => (
22
- * <div key={post.id}>{post.title}</div>
23
- * ))}
24
- * </div>
25
- * )
26
- * }
27
- * ```
28
- */
29
- function useCollection(collectionName, options) {
30
- const { client, locale } = useAdminContext();
31
- const queryClient = useQueryClient();
32
- const localeKey = locale ?? "default";
33
- return useMemo(() => {
34
- const collectionHelper = createQuestpieDBHelpers(client, { keyPrefix: [
35
- "qcms",
36
- "locale",
37
- localeKey
38
- ] }).collections[collectionName];
39
- if (!collectionHelper) throw new Error(`Collection "${String(collectionName)}" not found in CMS`);
40
- return collectionHelper.createCollection({
41
- queryClient,
42
- getKey: options?.getKey ?? ((item) => item.id),
43
- baseFindOptions: options?.baseFindOptions,
44
- realtime: options?.realtime ?? false
45
- });
46
- }, [
47
- client,
48
- queryClient,
49
- collectionName,
50
- localeKey,
51
- options?.baseFindOptions,
52
- options?.realtime,
53
- options?.getKey
54
- ]);
55
- }
56
- /**
57
- * Hook to get a single item from collection by ID
58
- * Uses TanStack DB Collection for offline-first access
59
- *
60
- * @example
61
- * ```tsx
62
- * function PostDetail({ id }: { id: string }) {
63
- * const posts = useCollection('posts')
64
- * const post = useCollectionItemById(posts, id)
65
- *
66
- * if (!post) return <div>Loading...</div>
67
- *
68
- * return <div>{post.title}</div>
69
- * }
70
- * ```
71
- */
72
- function useCollectionItemById(collection, id) {
73
- return collection.toArray.find((item) => collection.config.getKey(item) === id);
74
- }
75
- /**
76
- * Hook to create item in collection
77
- * Uses TanStack DB Collection with optimistic updates
78
- *
79
- * @example
80
- * ```tsx
81
- * function CreatePost() {
82
- * const posts = useCollection('posts')
83
- *
84
- * const handleCreate = async () => {
85
- * await posts.insert({
86
- * title: 'New Post',
87
- * content: 'Hello World'
88
- * })
89
- * }
90
- *
91
- * return <button onClick={handleCreate}>Create Post</button>
92
- * }
93
- * ```
94
- */
95
- function useCollectionInsert(collectionName) {
96
- const collection = useCollection(collectionName);
97
- return collection.insert.bind(collection);
98
- }
99
- /**
100
- * Hook to update item in collection
101
- * Uses TanStack DB Collection with optimistic updates
102
- *
103
- * @example
104
- * ```tsx
105
- * function EditPost({ id }: { id: string }) {
106
- * const posts = useCollection('posts')
107
- * const post = useCollectionItemById(posts, id)
108
- *
109
- * const handleUpdate = async () => {
110
- * await posts.update(id, {
111
- * title: 'Updated Title'
112
- * })
113
- * }
114
- *
115
- * return <button onClick={handleUpdate}>Update</button>
116
- * }
117
- * ```
118
- */
119
- function useCollectionUpdate(collectionName) {
120
- const collection = useCollection(collectionName);
121
- return collection.update.bind(collection);
122
- }
123
- /**
124
- * Hook to delete item from collection
125
- * Uses TanStack DB Collection with optimistic updates
126
- *
127
- * @example
128
- * ```tsx
129
- * function DeletePost({ id }: { id: string }) {
130
- * const posts = useCollection('posts')
131
- *
132
- * const handleDelete = async () => {
133
- * await posts.delete(id)
134
- * }
135
- *
136
- * return <button onClick={handleDelete}>Delete</button>
137
- * }
138
- * ```
139
- */
140
- function useCollectionDelete(collectionName) {
141
- const collection = useCollection(collectionName);
142
- return collection.delete.bind(collection);
143
- }
144
-
145
- //#endregion
146
- export { useCollection, useCollectionDelete, useCollectionInsert, useCollectionItemById, useCollectionUpdate };
@@ -1,112 +0,0 @@
1
- import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2
- import { useAdminContext } from "./admin-provider";
3
- import { createQuestpieQueryOptions } from "@questpie/tanstack-query";
4
-
5
- //#region src/hooks/use-collection.ts
6
- /**
7
- * Hook to fetch collection list with filters, sorting, pagination
8
- */
9
- function useCollectionList(collection, options, queryOptions) {
10
- const { client, locale } = useAdminContext();
11
- return useQuery({
12
- ...createQuestpieQueryOptions(client, { keyPrefix: [
13
- "qcms",
14
- "locale",
15
- locale ?? "default"
16
- ] }).collections[collection].find(options),
17
- ...queryOptions
18
- });
19
- }
20
- /**
21
- * Hook to fetch single collection item
22
- */
23
- function useCollectionItem(collection, id, options, queryOptions) {
24
- const { client, locale } = useAdminContext();
25
- return useQuery({
26
- ...createQuestpieQueryOptions(client, { keyPrefix: [
27
- "qcms",
28
- "locale",
29
- locale ?? "default"
30
- ] }).collections[collection].findOne({
31
- where: { id },
32
- ...options
33
- }),
34
- ...queryOptions
35
- });
36
- }
37
- /**
38
- * Hook to create collection item
39
- */
40
- function useCollectionCreate(collection, mutationOptions) {
41
- const { client, locale } = useAdminContext();
42
- const queryClient = useQueryClient();
43
- const keyPrefix = [
44
- "qcms",
45
- "locale",
46
- locale ?? "default"
47
- ];
48
- return useMutation({
49
- ...createQuestpieQueryOptions(client, { keyPrefix }).collections[collection].create(),
50
- onSuccess: (data, variables, context) => {
51
- queryClient.invalidateQueries({ queryKey: [
52
- ...keyPrefix,
53
- "collections",
54
- collection,
55
- "find"
56
- ] });
57
- (mutationOptions?.onSuccess)?.(data, variables, context);
58
- },
59
- ...mutationOptions
60
- });
61
- }
62
- /**
63
- * Hook to update collection item
64
- */
65
- function useCollectionUpdate(collection, mutationOptions) {
66
- const { client, locale } = useAdminContext();
67
- const queryClient = useQueryClient();
68
- const keyPrefix = [
69
- "qcms",
70
- "locale",
71
- locale ?? "default"
72
- ];
73
- return useMutation({
74
- ...createQuestpieQueryOptions(client, { keyPrefix }).collections[collection].update(),
75
- onSuccess: (data, variables, context) => {
76
- queryClient.invalidateQueries({ queryKey: [
77
- ...keyPrefix,
78
- "collections",
79
- collection
80
- ] });
81
- (mutationOptions?.onSuccess)?.(data, variables, context);
82
- },
83
- ...mutationOptions
84
- });
85
- }
86
- /**
87
- * Hook to delete collection item
88
- */
89
- function useCollectionDelete(collection, mutationOptions) {
90
- const { client, locale } = useAdminContext();
91
- const queryClient = useQueryClient();
92
- const keyPrefix = [
93
- "qcms",
94
- "locale",
95
- locale ?? "default"
96
- ];
97
- return useMutation({
98
- ...createQuestpieQueryOptions(client, { keyPrefix }).collections[collection].delete(),
99
- onSuccess: (data, variables, context) => {
100
- queryClient.invalidateQueries({ queryKey: [
101
- ...keyPrefix,
102
- "collections",
103
- collection
104
- ] });
105
- (mutationOptions?.onSuccess)?.(data, variables, context);
106
- },
107
- ...mutationOptions
108
- });
109
- }
110
-
111
- //#endregion
112
- export { useCollectionCreate, useCollectionDelete, useCollectionItem, useCollectionList, useCollectionUpdate };
@@ -1,46 +0,0 @@
1
- import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2
- import { useAdminContext } from "./admin-provider";
3
- import { createQuestpieQueryOptions } from "@questpie/tanstack-query";
4
-
5
- //#region src/hooks/use-global.ts
6
- /**
7
- * Hook to fetch global settings
8
- */
9
- function useGlobal(globalName, options, queryOptions) {
10
- const { client, locale } = useAdminContext();
11
- return useQuery({
12
- ...createQuestpieQueryOptions(client, { keyPrefix: [
13
- "qcms",
14
- "locale",
15
- locale ?? "default"
16
- ] }).globals[globalName].get(options),
17
- ...queryOptions
18
- });
19
- }
20
- /**
21
- * Hook to update global settings
22
- */
23
- function useGlobalUpdate(globalName, mutationOptions) {
24
- const { client, locale } = useAdminContext();
25
- const queryClient = useQueryClient();
26
- const keyPrefix = [
27
- "qcms",
28
- "locale",
29
- locale ?? "default"
30
- ];
31
- return useMutation({
32
- ...createQuestpieQueryOptions(client, { keyPrefix }).globals[globalName].update(),
33
- onSuccess: (...args) => {
34
- queryClient.invalidateQueries({ queryKey: [
35
- ...keyPrefix,
36
- "globals",
37
- globalName
38
- ] });
39
- mutationOptions?.onSuccess?.(...args);
40
- },
41
- ...mutationOptions
42
- });
43
- }
44
-
45
- //#endregion
46
- export { useGlobal, useGlobalUpdate };
@@ -1,20 +0,0 @@
1
- import * as React$1 from "react";
2
-
3
- //#region src/hooks/use-mobile.ts
4
- const MOBILE_BREAKPOINT = 768;
5
- function useIsMobile() {
6
- const [isMobile, setIsMobile] = React$1.useState(void 0);
7
- React$1.useEffect(() => {
8
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
9
- const onChange = () => {
10
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
11
- };
12
- mql.addEventListener("change", onChange);
13
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14
- return () => mql.removeEventListener("change", onChange);
15
- }, []);
16
- return !!isMobile;
17
- }
18
-
19
- //#endregion
20
- export { useIsMobile };