@questpie/admin 0.0.1 → 1.0.0

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-h7zXD78Y.mjs +274 -0
  5. package/dist/bulk-upload-dialog-h7zXD78Y.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-BCGpkAz6.mjs +22635 -0
  10. package/dist/client-BCGpkAz6.mjs.map +1 -0
  11. package/dist/client-CcWZbkBP.d.mts +13585 -0
  12. package/dist/client-CcWZbkBP.d.mts.map +1 -0
  13. package/dist/client.d.mts +3 -0
  14. package/dist/client.mjs +14 -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-CVlyR40m.mjs +6 -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-CIILVhfo.mjs +7 -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 +14 -0
  29. package/dist/login-page-8K7fo0qK.mjs +7 -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-DLATv0xQ.mjs +7 -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-CMZ5P_OE.mjs +6 -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 -197
  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,269 +0,0 @@
1
- # Admin Hooks - TanStack DB Integration
2
-
3
- Admin hooks sú postavené na **TanStack DB Collections** pre offline-first, realtime data management.
4
-
5
- ## Výhody TanStack DB
6
-
7
- ✅ **Offline-first** - Data sú dostupné aj bez pripojenia
8
- ✅ **Optimistic updates** - Okamžitá UI odozva
9
- ✅ **Realtime sync** - Automatická synchronizácia cez SSE
10
- ✅ **Better DX** - Jednoduchšie API než query/mutation hooks
11
- ✅ **Built-in caching** - Inteligentné cache management
12
-
13
- ## Basic Usage
14
-
15
- ### 1. Setup AdminProvider
16
-
17
- ```tsx
18
- import { AdminProvider } from '@questpie/admin/hooks'
19
- import { createQCMSClient } from '@questpie/cms/client'
20
- import { QueryClient } from '@tanstack/react-query'
21
- import type { cms } from './server/cms'
22
-
23
- const client = createQCMSClient<typeof cms>({
24
- baseURL: 'http://localhost:3000'
25
- })
26
-
27
- const queryClient = new QueryClient()
28
-
29
- function App() {
30
- return (
31
- <AdminProvider client={client} queryClient={queryClient}>
32
- <YourAdminApp />
33
- </AdminProvider>
34
- )
35
- }
36
- ```
37
-
38
- ### 2. Use Collection Hook
39
-
40
- ```tsx
41
- import { useCollection } from '@questpie/admin/hooks'
42
- import type { cms } from './server/cms'
43
-
44
- function PostsList() {
45
- const posts = useCollection<typeof cms, 'posts'>('posts', {
46
- // Optional: Add filters
47
- baseFindOptions: {
48
- where: { published: { eq: true } },
49
- orderBy: { createdAt: 'desc' },
50
- },
51
- // Enable realtime sync
52
- realtime: true,
53
- })
54
-
55
- return (
56
- <div>
57
- <h1>Posts ({posts.items.length})</h1>
58
- {posts.items.map(post => (
59
- <div key={post.id}>
60
- <h2>{post.title}</h2>
61
- <p>{post.content}</p>
62
- </div>
63
- ))}
64
- </div>
65
- )
66
- }
67
- ```
68
-
69
- ### 3. Create Item (Optimistic Update)
70
-
71
- ```tsx
72
- import { useCollection } from '@questpie/admin/hooks'
73
-
74
- function CreatePost() {
75
- const posts = useCollection<typeof cms, 'posts'>('posts')
76
-
77
- const handleCreate = async () => {
78
- // Optimistic insert - UI updates immediately
79
- await posts.insert({
80
- title: 'New Post',
81
- content: 'Hello World',
82
- published: false,
83
- })
84
- }
85
-
86
- return (
87
- <button onClick={handleCreate}>
88
- Create Post
89
- </button>
90
- )
91
- }
92
- ```
93
-
94
- ### 4. Update Item (Optimistic Update)
95
-
96
- ```tsx
97
- import { useCollection, useCollectionItemById } from '@questpie/admin/hooks'
98
-
99
- function EditPost({ id }: { id: string }) {
100
- const posts = useCollection<typeof cms, 'posts'>('posts')
101
- const post = useCollectionItemById(posts, id)
102
-
103
- const handleUpdate = async () => {
104
- if (!post) return
105
-
106
- // Optimistic update - UI updates immediately
107
- await posts.update(id, {
108
- title: 'Updated Title',
109
- })
110
- }
111
-
112
- if (!post) return <div>Loading...</div>
113
-
114
- return (
115
- <div>
116
- <h1>{post.title}</h1>
117
- <button onClick={handleUpdate}>Update Title</button>
118
- </div>
119
- )
120
- }
121
- ```
122
-
123
- ### 5. Delete Item (Optimistic Update)
124
-
125
- ```tsx
126
- import { useCollection } from '@questpie/admin/hooks'
127
-
128
- function DeletePost({ id }: { id: string }) {
129
- const posts = useCollection<typeof cms, 'posts'>('posts')
130
-
131
- const handleDelete = async () => {
132
- // Optimistic delete - UI updates immediately
133
- await posts.delete(id)
134
- }
135
-
136
- return (
137
- <button onClick={handleDelete}>
138
- Delete
139
- </button>
140
- )
141
- }
142
- ```
143
-
144
- ## Advanced Usage
145
-
146
- ### Realtime Sync with Custom Config
147
-
148
- ```tsx
149
- const posts = useCollection<typeof cms, 'posts'>('posts', {
150
- realtime: {
151
- enabled: true,
152
- baseURL: 'http://localhost:3000',
153
- basePath: '/cms',
154
- },
155
- })
156
- ```
157
-
158
- ### With Relations (Eager Loading)
159
-
160
- ```tsx
161
- const posts = useCollection<typeof cms, 'posts'>('posts', {
162
- baseFindOptions: {
163
- with: {
164
- author: true,
165
- tags: true,
166
- },
167
- },
168
- })
169
-
170
- // Now posts.items include author and tags data
171
- posts.items.forEach(post => {
172
- console.log(post.author?.name)
173
- console.log(post.tags?.map(t => t.name))
174
- })
175
- ```
176
-
177
- ### Filter & Sort
178
-
179
- ```tsx
180
- const posts = useCollection<typeof cms, 'posts'>('posts', {
181
- baseFindOptions: {
182
- where: {
183
- AND: [
184
- { published: { eq: true } },
185
- { createdAt: { gte: new Date('2024-01-01') } },
186
- ],
187
- },
188
- orderBy: { createdAt: 'desc' },
189
- limit: 10,
190
- },
191
- })
192
- ```
193
-
194
- ### Pagination with LoadSubset
195
-
196
- ```tsx
197
- import { useCollection } from '@questpie/admin/hooks'
198
-
199
- function PaginatedPosts() {
200
- const posts = useCollection<typeof cms, 'posts'>('posts')
201
-
202
- const handleLoadMore = () => {
203
- posts.loadSubset({
204
- limit: 10,
205
- offset: posts.items.length,
206
- })
207
- }
208
-
209
- return (
210
- <div>
211
- {posts.items.map(post => (
212
- <div key={post.id}>{post.title}</div>
213
- ))}
214
- <button onClick={handleLoadMore}>Load More</button>
215
- </div>
216
- )
217
- }
218
- ```
219
-
220
- ## API Reference
221
-
222
- ### `useCollection(collectionName, options)`
223
-
224
- Returns a TanStack DB Collection with full CRUD operations.
225
-
226
- **Options:**
227
- - `baseFindOptions` - Initial query (filters, sorting, relations)
228
- - `realtime` - Enable SSE realtime sync (boolean or config object)
229
- - `getKey` - Custom key extractor (defaults to `item.id`)
230
-
231
- **Returns Collection with:**
232
- - `items` - Array of collection items
233
- - `insert(data)` - Create new item (optimistic)
234
- - `update(id, data)` - Update item (optimistic)
235
- - `delete(id)` - Delete item (optimistic)
236
- - `loadSubset(options)` - Load more items with filters
237
- - `replaceAll(items)` - Replace all items (for realtime)
238
-
239
- ### `useCollectionItemById(collection, id)`
240
-
241
- Get single item from collection by ID (offline-first).
242
-
243
- ### `useCollectionInsert(collectionName)`
244
-
245
- Get insert function for collection.
246
-
247
- ### `useCollectionUpdate(collectionName)`
248
-
249
- Get update function for collection.
250
-
251
- ### `useCollectionDelete(collectionName)`
252
-
253
- Get delete function for collection.
254
-
255
- ## Legacy Query/Mutation Hooks
256
-
257
- For backward compatibility, query/mutation hooks are still available:
258
-
259
- ```tsx
260
- import {
261
- useCollectionList,
262
- useCollectionItem,
263
- useCollectionCreate,
264
- useCollectionUpdateMutation,
265
- useCollectionDeleteMutation,
266
- } from '@questpie/admin/hooks'
267
- ```
268
-
269
- **Recommendation:** Use TanStack DB hooks (`useCollection`) for better DX and offline-first support.
@@ -1,110 +0,0 @@
1
- import React, { createContext, useContext } from "react";
2
- import type { QuestpieClient } from "questpie/client";
3
- import type { Questpie } from "questpie";
4
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
-
6
- /**
7
- * Admin context - provides access to CMS client
8
- */
9
- export type AdminContext<T extends Questpie<any>> = {
10
- client: QuestpieClient<T>;
11
- locale?: string;
12
- setLocale?: (locale: string) => void;
13
- locales?: {
14
- default: string;
15
- available: string[];
16
- };
17
- };
18
-
19
- const AdminContextInstance = createContext<AdminContext<any> | null>(null);
20
-
21
- /**
22
- * Hook to access admin context
23
- */
24
- export function useAdminContext<T extends Questpie<any>>(): AdminContext<T> {
25
- const context = useContext(AdminContextInstance);
26
- if (!context) {
27
- throw new Error(
28
- "useAdminContext must be used within AdminProvider. Wrap your app with <AdminProvider client={client}>",
29
- );
30
- }
31
- return context;
32
- }
33
-
34
- /**
35
- * Admin provider props
36
- */
37
- export type AdminProviderProps<T extends Questpie<any>> = {
38
- client: QuestpieClient<T>;
39
- queryClient?: QueryClient;
40
- locales?: {
41
- default: string;
42
- available: string[];
43
- };
44
- children: React.ReactNode;
45
- };
46
-
47
- /**
48
- * Admin provider - provides CMS client and query client to the app
49
- *
50
- * @example
51
- * ```tsx
52
- * import { AdminProvider } from '@questpie/admin/hooks'
53
- * import { createQuestpieClient } from 'questpie/client'
54
- * import { QueryClient } from '@tanstack/react-query'
55
- * import type { cms } from './server/cms'
56
- *
57
- * const client = createQuestpieClient<typeof cms>({
58
- * baseURL: 'http://localhost:3000'
59
- * })
60
- *
61
- * const queryClient = new QueryClient()
62
- *
63
- * function App() {
64
- * return (
65
- * <AdminProvider client={client} queryClient={queryClient}>
66
- * <YourAdminApp />
67
- * </AdminProvider>
68
- * )
69
- * }
70
- * ```
71
- */
72
- export function AdminProvider<T extends Questpie<any>>({
73
- client,
74
- queryClient,
75
- locales,
76
- children,
77
- }: AdminProviderProps<T>): React.ReactElement {
78
- const [defaultQueryClient] = React.useState(
79
- () => queryClient ?? new QueryClient(),
80
- );
81
- const [locale, setLocale] = React.useState(() => {
82
- if (locales?.default) return locales.default;
83
- if (locales?.available?.length) return locales.available[0];
84
- return typeof client.getLocale === "function"
85
- ? client.getLocale()
86
- : undefined;
87
- });
88
-
89
- React.useEffect(() => {
90
- if (!locales?.available?.length) return;
91
- if (!locale || !locales.available.includes(locale)) {
92
- setLocale(locales.default ?? locales.available[0]);
93
- }
94
- }, [locale, locales]);
95
-
96
- React.useEffect(() => {
97
- if (typeof client.setLocale !== "function") return;
98
- client.setLocale(locale);
99
- }, [client, locale]);
100
-
101
- return (
102
- <AdminContextInstance.Provider
103
- value={{ client, locale, setLocale, locales }}
104
- >
105
- <QueryClientProvider client={defaultQueryClient}>
106
- {children}
107
- </QueryClientProvider>
108
- </AdminContextInstance.Provider>
109
- );
110
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * React hooks for admin package
3
- */
4
-
5
- // Provider and context
6
- export { AdminProvider, useAdminContext } from "./admin-provider";
7
- export type { AdminProviderProps, AdminContext } from "./admin-provider";
8
-
9
- // Auth client (Better Auth integration)
10
- export { createAdminAuthClient } from "./use-auth";
11
- export type {
12
- AdminAuthClient,
13
- AdminAuthClientOptions,
14
- AdminSession,
15
- AdminUser,
16
- } from "./use-auth";
17
-
18
- // Jotai state management
19
- // TODO: Add explicit types for isolatedDeclarations support
20
- // export * from "./store";
21
-
22
- // TanStack DB Collection hooks (recommended - offline-first, realtime)
23
- export {
24
- useCollection,
25
- useCollectionItemById,
26
- useCollectionInsert,
27
- useCollectionUpdate,
28
- useCollectionDelete,
29
- } from "./use-collection-db";
30
-
31
- // Legacy TanStack Query hooks (for backward compatibility)
32
- export {
33
- useCollectionList,
34
- useCollectionItem,
35
- useCollectionCreate,
36
- useCollectionUpdate as useCollectionUpdateMutation,
37
- useCollectionDelete as useCollectionDeleteMutation,
38
- } from "./use-collection";
39
-
40
- // Global hooks
41
- export { useGlobal, useGlobalUpdate } from "./use-global";
@@ -1,248 +0,0 @@
1
- /**
2
- * Jotai Store for Admin State Management
3
- *
4
- * Centralized state atoms for the admin UI.
5
- * Uses Jotai for reactive, atomic state management.
6
- */
7
-
8
- import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
9
- import { atomWithStorage } from "jotai/utils";
10
-
11
- // ============================================================================
12
- // UI State Atoms
13
- // ============================================================================
14
-
15
- /**
16
- * Sidebar collapsed state (persisted to localStorage)
17
- */
18
- export const sidebarCollapsedAtom = atomWithStorage(
19
- "admin:sidebar-collapsed",
20
- false,
21
- );
22
-
23
- /**
24
- * Current active locale
25
- */
26
- export const localeAtom = atom<string | null>(null);
27
-
28
- /**
29
- * Available locales configuration
30
- */
31
- export const localesConfigAtom = atom<{
32
- default: string;
33
- available: string[];
34
- } | null>(null);
35
-
36
- /**
37
- * Mobile menu open state
38
- */
39
- export const mobileMenuOpenAtom = atom(false);
40
-
41
- /**
42
- * Command palette open state
43
- */
44
- export const commandPaletteOpenAtom = atom(false);
45
-
46
- // ============================================================================
47
- // Theme Atoms
48
- // ============================================================================
49
-
50
- /**
51
- * Theme mode (persisted to localStorage)
52
- */
53
- export type ThemeMode = "light" | "dark" | "system";
54
-
55
- export const themeModeAtom = atomWithStorage<ThemeMode>(
56
- "admin:theme-mode",
57
- "system",
58
- );
59
-
60
- /**
61
- * Derived atom for resolved theme (accounts for system preference)
62
- */
63
- export const resolvedThemeAtom = atom((get) => {
64
- const mode = get(themeModeAtom);
65
- if (mode !== "system") return mode;
66
-
67
- // Check system preference (this is a static check, won't react to changes)
68
- if (typeof window !== "undefined") {
69
- return window.matchMedia("(prefers-color-scheme: dark)").matches
70
- ? "dark"
71
- : "light";
72
- }
73
- return "light";
74
- });
75
-
76
- // ============================================================================
77
- // Navigation State Atoms
78
- // ============================================================================
79
-
80
- /**
81
- * Current active collection (for breadcrumbs, etc.)
82
- */
83
- export const activeCollectionAtom = atom<string | null>(null);
84
-
85
- /**
86
- * Current active item ID (for editing)
87
- */
88
- export const activeItemIdAtom = atom<string | null>(null);
89
-
90
- /**
91
- * Navigation history stack
92
- */
93
- export const navigationHistoryAtom = atom<string[]>([]);
94
-
95
- // ============================================================================
96
- // Form State Atoms
97
- // ============================================================================
98
-
99
- /**
100
- * Global form dirty state (to warn on navigation)
101
- */
102
- export const formDirtyAtom = atom(false);
103
-
104
- /**
105
- * Active form errors count
106
- */
107
- export const formErrorsCountAtom = atom(0);
108
-
109
- // ============================================================================
110
- // Notification Atoms
111
- // ============================================================================
112
-
113
- export type NotificationType = "success" | "error" | "warning" | "info";
114
-
115
- export type Notification = {
116
- id: string;
117
- type: NotificationType;
118
- title: string;
119
- message?: string;
120
- duration?: number;
121
- action?: {
122
- label: string;
123
- onClick: () => void;
124
- };
125
- };
126
-
127
- export const notificationsAtom = atom<Notification[]>([]);
128
-
129
- /**
130
- * Derived atom to add notification
131
- */
132
- export const addNotificationAtom = atom(
133
- null,
134
- (get, set, notification: Omit<Notification, "id">) => {
135
- const id = Math.random().toString(36).substring(2, 9);
136
- const newNotification = { ...notification, id };
137
- set(notificationsAtom, [...get(notificationsAtom), newNotification]);
138
-
139
- // Auto-remove after duration
140
- if (notification.duration !== 0) {
141
- setTimeout(() => {
142
- set(notificationsAtom, (prev) => prev.filter((n) => n.id !== id));
143
- }, notification.duration ?? 5000);
144
- }
145
-
146
- return id;
147
- },
148
- );
149
-
150
- /**
151
- * Derived atom to remove notification
152
- */
153
- export const removeNotificationAtom = atom(null, (get, set, id: string) => {
154
- set(notificationsAtom, (prev) => prev.filter((n) => n.id !== id));
155
- });
156
-
157
- // ============================================================================
158
- // Custom Hooks
159
- // ============================================================================
160
-
161
- /**
162
- * Hook for sidebar state
163
- */
164
- export function useSidebar() {
165
- const [collapsed, setCollapsed] = useAtom(sidebarCollapsedAtom);
166
- return {
167
- collapsed,
168
- setCollapsed,
169
- toggle: () => setCollapsed(!collapsed),
170
- };
171
- }
172
-
173
- /**
174
- * Hook for theme state
175
- */
176
- export function useTheme() {
177
- const [mode, setMode] = useAtom(themeModeAtom);
178
- const resolved = useAtomValue(resolvedThemeAtom);
179
- return {
180
- mode,
181
- setMode,
182
- resolved,
183
- isDark: resolved === "dark",
184
- isLight: resolved === "light",
185
- };
186
- }
187
-
188
- /**
189
- * Hook for locale state
190
- */
191
- export function useLocale() {
192
- const [locale, setLocale] = useAtom(localeAtom);
193
- const config = useAtomValue(localesConfigAtom);
194
- return {
195
- locale: locale ?? config?.default ?? null,
196
- setLocale,
197
- available: config?.available ?? [],
198
- default: config?.default ?? null,
199
- };
200
- }
201
-
202
- /**
203
- * Hook for notifications
204
- */
205
- export function useNotifications() {
206
- const notifications = useAtomValue(notificationsAtom);
207
- const addNotification = useSetAtom(addNotificationAtom);
208
- const removeNotification = useSetAtom(removeNotificationAtom);
209
-
210
- return {
211
- notifications,
212
- add: addNotification,
213
- remove: removeNotification,
214
- success: (title: string, message?: string) =>
215
- addNotification({ type: "success", title, message }),
216
- error: (title: string, message?: string) =>
217
- addNotification({ type: "error", title, message }),
218
- warning: (title: string, message?: string) =>
219
- addNotification({ type: "warning", title, message }),
220
- info: (title: string, message?: string) =>
221
- addNotification({ type: "info", title, message }),
222
- };
223
- }
224
-
225
- /**
226
- * Hook for command palette
227
- */
228
- export function useCommandPalette() {
229
- const [open, setOpen] = useAtom(commandPaletteOpenAtom);
230
- return {
231
- open,
232
- setOpen,
233
- toggle: () => setOpen(!open),
234
- };
235
- }
236
-
237
- /**
238
- * Hook for form dirty state
239
- */
240
- export function useFormDirty() {
241
- const [dirty, setDirty] = useAtom(formDirtyAtom);
242
- return {
243
- dirty,
244
- setDirty,
245
- markDirty: () => setDirty(true),
246
- markClean: () => setDirty(false),
247
- };
248
- }