convex-cms 0.0.5-alpha.0 → 0.0.5-alpha.3

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 (323) hide show
  1. package/README.md +95 -144
  2. package/admin/README.md +99 -0
  3. package/admin/src/components/AdminLayout.tsx +22 -0
  4. package/admin/src/components/BreakingChangesWarningDialog.tsx +81 -0
  5. package/admin/src/components/BulkActionBar.tsx +190 -0
  6. package/admin/src/components/BulkOperationModal.tsx +177 -0
  7. package/admin/src/components/ContentEntryEditor.tsx +1104 -0
  8. package/admin/src/components/ContentTypeFormModal.tsx +1012 -0
  9. package/admin/src/components/ErrorBoundary.tsx +83 -0
  10. package/admin/src/components/ErrorState.tsx +147 -0
  11. package/admin/src/components/Header.tsx +294 -0
  12. package/admin/src/components/RouteGuard.tsx +264 -0
  13. package/admin/src/components/Sidebar.tsx +90 -0
  14. package/admin/src/components/TaxonomyEditor.tsx +348 -0
  15. package/admin/src/components/TermTree.tsx +533 -0
  16. package/admin/src/components/UploadDropzone.tsx +383 -0
  17. package/admin/src/components/VersionCompare.tsx +250 -0
  18. package/admin/src/components/VersionHistory.tsx +279 -0
  19. package/admin/src/components/VersionRollbackModal.tsx +79 -0
  20. package/admin/src/components/cmsds/CmsButton.tsx +101 -0
  21. package/admin/src/components/cmsds/CmsDialog.tsx +139 -0
  22. package/admin/src/components/cmsds/CmsDropdown.tsx +62 -0
  23. package/admin/src/components/cmsds/CmsEmptyState.tsx +54 -0
  24. package/admin/src/components/cmsds/CmsField.tsx +47 -0
  25. package/admin/src/components/cmsds/CmsPageHeader.tsx +35 -0
  26. package/admin/src/components/cmsds/CmsStatusBadge.tsx +153 -0
  27. package/admin/src/components/cmsds/CmsSurface.tsx +52 -0
  28. package/admin/src/components/cmsds/CmsTable.tsx +164 -0
  29. package/admin/src/components/cmsds/CmsToolbar.tsx +58 -0
  30. package/admin/src/components/cmsds/index.ts +10 -0
  31. package/admin/src/components/fields/BooleanField.tsx +74 -0
  32. package/admin/src/components/fields/CategoryField.tsx +394 -0
  33. package/admin/src/components/fields/DateField.tsx +173 -0
  34. package/admin/src/components/fields/DefaultFieldRenderer.tsx +74 -0
  35. package/admin/src/components/fields/FieldRenderer.tsx +180 -0
  36. package/admin/src/components/fields/FieldWrapper.tsx +57 -0
  37. package/admin/src/components/fields/JsonField.tsx +172 -0
  38. package/admin/src/components/fields/MediaField.tsx +367 -0
  39. package/admin/src/components/fields/MultiSelectField.tsx +118 -0
  40. package/admin/src/components/fields/NumberField.tsx +77 -0
  41. package/admin/src/components/fields/ReferenceField.tsx +386 -0
  42. package/admin/src/components/fields/RichTextField.tsx +171 -0
  43. package/admin/src/components/fields/SelectField.tsx +62 -0
  44. package/admin/src/components/fields/TagField.tsx +325 -0
  45. package/admin/src/components/fields/TextAreaField.tsx +68 -0
  46. package/admin/src/components/fields/TextField.tsx +56 -0
  47. package/admin/src/components/fields/index.ts +54 -0
  48. package/admin/src/components/fields/registry.ts +64 -0
  49. package/admin/src/components/fields/types.ts +217 -0
  50. package/admin/src/components/filters/TaxonomyFilter.tsx +254 -0
  51. package/admin/src/components/filters/index.ts +1 -0
  52. package/admin/src/components/index.ts +8 -0
  53. package/admin/src/components/media/MediaAssetActions.tsx +115 -0
  54. package/admin/src/components/media/MediaAssetEditDialog.tsx +217 -0
  55. package/admin/src/components/media/MediaBulkActionBar.tsx +51 -0
  56. package/admin/src/components/media/MediaFolderActions.tsx +69 -0
  57. package/admin/src/components/media/MediaFolderEditDialog.tsx +126 -0
  58. package/admin/src/components/media/MediaMoveModal.tsx +179 -0
  59. package/admin/src/components/media/MediaPreviewModal.tsx +370 -0
  60. package/admin/src/components/media/MediaTaxonomyPicker.tsx +304 -0
  61. package/admin/src/components/media/MediaTrashBulkActionBar.tsx +59 -0
  62. package/admin/src/components/ui/accordion.tsx +64 -0
  63. package/admin/src/components/ui/alert-dialog.tsx +155 -0
  64. package/admin/src/components/ui/alert.tsx +66 -0
  65. package/admin/src/components/ui/avatar.tsx +53 -0
  66. package/admin/src/components/ui/badge.tsx +46 -0
  67. package/admin/src/components/ui/breadcrumb.tsx +109 -0
  68. package/admin/src/components/ui/button.tsx +62 -0
  69. package/admin/src/components/ui/calendar.tsx +220 -0
  70. package/admin/src/components/ui/card.tsx +92 -0
  71. package/admin/src/components/ui/checkbox.tsx +30 -0
  72. package/admin/src/components/ui/command.tsx +182 -0
  73. package/admin/src/components/ui/dialog.tsx +143 -0
  74. package/admin/src/components/ui/dropdown-menu.tsx +257 -0
  75. package/admin/src/components/ui/form.tsx +167 -0
  76. package/admin/src/components/ui/input.tsx +21 -0
  77. package/admin/src/components/ui/label.tsx +24 -0
  78. package/admin/src/components/ui/popover.tsx +46 -0
  79. package/admin/src/components/ui/scroll-area.tsx +56 -0
  80. package/admin/src/components/ui/select.tsx +190 -0
  81. package/admin/src/components/ui/separator.tsx +26 -0
  82. package/admin/src/components/ui/sheet.tsx +137 -0
  83. package/admin/src/components/ui/sidebar.tsx +724 -0
  84. package/admin/src/components/ui/skeleton.tsx +13 -0
  85. package/admin/src/components/ui/sonner.tsx +38 -0
  86. package/admin/src/components/ui/switch.tsx +31 -0
  87. package/admin/src/components/ui/table.tsx +114 -0
  88. package/admin/src/components/ui/tabs.tsx +66 -0
  89. package/admin/src/components/ui/textarea.tsx +18 -0
  90. package/admin/src/components/ui/tooltip.tsx +61 -0
  91. package/admin/src/contexts/AdminConfigContext.tsx +30 -0
  92. package/admin/src/contexts/AuthContext.tsx +330 -0
  93. package/admin/src/contexts/BreadcrumbContext.tsx +49 -0
  94. package/admin/src/contexts/SettingsConfigContext.tsx +57 -0
  95. package/admin/src/contexts/ThemeContext.tsx +91 -0
  96. package/admin/src/contexts/index.ts +20 -0
  97. package/admin/src/embed/components/EmbedHeader.tsx +103 -0
  98. package/admin/src/embed/components/EmbedLayout.tsx +29 -0
  99. package/admin/src/embed/components/EmbedSidebar.tsx +119 -0
  100. package/admin/src/embed/components/index.ts +3 -0
  101. package/admin/src/embed/contexts/ApiContext.tsx +32 -0
  102. package/admin/src/embed/index.tsx +184 -0
  103. package/admin/src/embed/navigation.tsx +202 -0
  104. package/admin/src/embed/pages/Content.tsx +19 -0
  105. package/admin/src/embed/pages/ContentTypes.tsx +19 -0
  106. package/admin/src/embed/pages/Dashboard.tsx +19 -0
  107. package/admin/src/embed/pages/Media.tsx +19 -0
  108. package/admin/src/embed/pages/Settings.tsx +22 -0
  109. package/admin/src/embed/pages/Taxonomies.tsx +22 -0
  110. package/admin/src/embed/pages/Trash.tsx +22 -0
  111. package/admin/src/embed/pages/index.ts +7 -0
  112. package/admin/src/embed/types.ts +24 -0
  113. package/admin/src/hooks/index.ts +2 -0
  114. package/admin/src/hooks/use-mobile.ts +19 -0
  115. package/admin/src/hooks/useBreadcrumbLabel.ts +15 -0
  116. package/admin/src/hooks/usePermissions.ts +211 -0
  117. package/admin/src/lib/admin-config.ts +111 -0
  118. package/admin/src/lib/cn.ts +6 -0
  119. package/admin/src/lib/config.server.ts +56 -0
  120. package/admin/src/lib/convex.ts +26 -0
  121. package/admin/src/lib/embed-adapter.ts +80 -0
  122. package/admin/src/lib/icons.tsx +96 -0
  123. package/admin/src/lib/loadAdminConfig.ts +92 -0
  124. package/admin/src/lib/motion.ts +29 -0
  125. package/admin/src/lib/navigation.ts +43 -0
  126. package/admin/src/lib/tanstack-adapter.ts +82 -0
  127. package/admin/src/pages/ContentPage.tsx +337 -0
  128. package/admin/src/pages/ContentTypesPage.tsx +457 -0
  129. package/admin/src/pages/DashboardPage.tsx +163 -0
  130. package/admin/src/pages/MediaPage.tsx +34 -0
  131. package/admin/src/pages/SettingsPage.tsx +486 -0
  132. package/admin/src/pages/TaxonomiesPage.tsx +289 -0
  133. package/admin/src/pages/TrashPage.tsx +421 -0
  134. package/admin/src/pages/index.ts +14 -0
  135. package/admin/src/routeTree.gen.ts +262 -0
  136. package/admin/src/router.tsx +22 -0
  137. package/admin/src/routes/__root.tsx +250 -0
  138. package/admin/src/routes/content-types.tsx +20 -0
  139. package/admin/src/routes/content.tsx +20 -0
  140. package/admin/src/routes/entries/$entryId.tsx +107 -0
  141. package/admin/src/routes/entries/new.$contentTypeId.tsx +69 -0
  142. package/admin/src/routes/entries/type/$contentTypeId.tsx +503 -0
  143. package/admin/src/routes/index.tsx +20 -0
  144. package/admin/src/routes/media.tsx +1095 -0
  145. package/admin/src/routes/settings.tsx +20 -0
  146. package/admin/src/routes/taxonomies.tsx +20 -0
  147. package/admin/src/routes/trash.tsx +20 -0
  148. package/admin/src/styles/globals.css +69 -0
  149. package/admin/src/styles/tailwind-config.css +74 -0
  150. package/admin/src/styles/theme.css +73 -0
  151. package/admin/src/types/index.ts +221 -0
  152. package/admin/src/utils/errorParsing.ts +163 -0
  153. package/admin/src/utils/index.ts +5 -0
  154. package/admin/src/vite-env.d.ts +14 -0
  155. package/admin/tailwind.preset.cjs +102 -0
  156. package/admin-dist/nitro.json +1 -1
  157. package/admin-dist/public/assets/{CmsEmptyState-CiMQwSQV.js → CmsEmptyState-CkqBIab3.js} +1 -1
  158. package/admin-dist/public/assets/{CmsPageHeader-ohOq0luT.js → CmsPageHeader-CUtl5MMG.js} +1 -1
  159. package/admin-dist/public/assets/{CmsStatusBadge-BdNf0V9v.js → CmsStatusBadge-CUYFgEe-.js} +1 -1
  160. package/admin-dist/public/assets/{CmsSurface-CWup6Jh7.js → CmsSurface-CsJfAVa3.js} +1 -1
  161. package/admin-dist/public/assets/{CmsToolbar-cEBlCHa3.js → CmsToolbar-CnfbcxeP.js} +1 -1
  162. package/admin-dist/public/assets/{ContentEntryEditor-BY5ypfUs.js → ContentEntryEditor-BU220CCy.js} +1 -1
  163. package/admin-dist/public/assets/TaxonomyFilter-CWCxC5HZ.js +1 -0
  164. package/admin-dist/public/assets/_contentTypeId-DK8cskRt.js +1 -0
  165. package/admin-dist/public/assets/{_entryId-BpSmrfAm.js → _entryId-CuVMExbb.js} +1 -1
  166. package/admin-dist/public/assets/{alert-Bf2l8kxw.js → alert-CF1BSzGR.js} +1 -1
  167. package/admin-dist/public/assets/{badge-qPrc4AUM.js → badge-CmuOIVKp.js} +1 -1
  168. package/admin-dist/public/assets/{circle-check-big-Dgozy3vV.js → circle-check-big-BKDVG6DU.js} +1 -1
  169. package/admin-dist/public/assets/{command-QOmNhlb0.js → command-XJxnF2Sd.js} +1 -1
  170. package/admin-dist/public/assets/content-QBUxdxbS.js +1 -0
  171. package/admin-dist/public/assets/content-types-CrNEm8Hf.js +2 -0
  172. package/admin-dist/public/assets/globals-B7Wsfh_v.css +1 -0
  173. package/admin-dist/public/assets/index-C7xOwudI.js +1 -0
  174. package/admin-dist/public/assets/{label-DCsUdvFh.js → label-CHCnXeBk.js} +1 -1
  175. package/admin-dist/public/assets/{link-2-Czw1N61H.js → link-2-Bb34judH.js} +1 -1
  176. package/admin-dist/public/assets/{list-DtCsXj8-.js → list-9Pzt48ld.js} +1 -1
  177. package/admin-dist/public/assets/{main-CXgkZMhe.js → main-CjQ2VI9L.js} +3 -3
  178. package/admin-dist/public/assets/media-Dc5PWt2Q.js +1 -0
  179. package/admin-dist/public/assets/{new._contentTypeId-CoTDxKzf.js → new._contentTypeId-C_I4YxIa.js} +1 -1
  180. package/admin-dist/public/assets/{plus-xCFJK0RC.js → plus-Ceef7DHk.js} +1 -1
  181. package/admin-dist/public/assets/{rotate-ccw-DIqK63wY.js → rotate-ccw-7k7-4VUq.js} +1 -1
  182. package/admin-dist/public/assets/{scroll-area-B-yrE66a.js → scroll-area-CC6wujnp.js} +1 -1
  183. package/admin-dist/public/assets/{search-CbCbboeU.js → search-DwoUV2pv.js} +1 -1
  184. package/admin-dist/public/assets/{select-Co3TZFJb.js → select-hOZTp8aC.js} +1 -1
  185. package/admin-dist/public/assets/{settings-BspTTv_o.js → settings-t2PbCZh4.js} +1 -1
  186. package/admin-dist/public/assets/{switch-CfavASmR.js → switch-jX2pDaNU.js} +1 -1
  187. package/admin-dist/public/assets/{tabs-CN5s5u2W.js → tabs-q4EbZk7c.js} +1 -1
  188. package/admin-dist/public/assets/{tanstack-adapter-npeE3RdY.js → tanstack-adapter-B-Glm4kH.js} +1 -1
  189. package/admin-dist/public/assets/taxonomies-kyk5P4ZW.js +1 -0
  190. package/admin-dist/public/assets/{textarea-BJ0XFZpT.js → textarea-B6SfBmr0.js} +1 -1
  191. package/admin-dist/public/assets/trash-BOCnIznD.js +1 -0
  192. package/admin-dist/public/assets/{triangle-alert-BZRcqsUg.js → triangle-alert-CXFIO_Gu.js} +1 -1
  193. package/admin-dist/public/assets/{useBreadcrumbLabel-DwZlwvFF.js → useBreadcrumbLabel-_6qBagc3.js} +1 -1
  194. package/admin-dist/public/assets/{usePermissions-C1JQhfqb.js → usePermissions-M1ijZ7a6.js} +1 -1
  195. package/admin-dist/server/_ssr/{CmsButton-B45JAKR1.mjs → CmsButton-DOiTVKQq.mjs} +1 -1
  196. package/admin-dist/server/_ssr/{CmsEmptyState-D_BQFAVR.mjs → CmsEmptyState-fbnGt3LD.mjs} +2 -2
  197. package/admin-dist/server/_ssr/{CmsPageHeader-CrUZA59A.mjs → CmsPageHeader-DHRrdOZa.mjs} +1 -1
  198. package/admin-dist/server/_ssr/{CmsStatusBadge-B-sj6yaj.mjs → CmsStatusBadge-s7obWbKZ.mjs} +2 -2
  199. package/admin-dist/server/_ssr/{CmsSurface-DKJZhpjk.mjs → CmsSurface-rFoYjb62.mjs} +1 -1
  200. package/admin-dist/server/_ssr/{CmsToolbar-ByaW5iXf.mjs → CmsToolbar-zTE45z2q.mjs} +2 -2
  201. package/admin-dist/server/_ssr/{ContentEntryEditor-D3_Jb1dq.mjs → ContentEntryEditor-BLoEjT_m.mjs} +12 -12
  202. package/admin-dist/server/_ssr/{TaxonomyFilter-BRJkuCtA.mjs → TaxonomyFilter-XAtaJC2z.mjs} +5 -5
  203. package/admin-dist/server/_ssr/{_contentTypeId-B9kA6CaM.mjs → _contentTypeId-Csl4822C.mjs} +13 -13
  204. package/admin-dist/server/_ssr/{_entryId-BddcMkZN.mjs → _entryId-D8alLFBx.mjs} +15 -15
  205. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-BffZedId.mjs +4 -0
  206. package/admin-dist/server/_ssr/{command-CGtVr8Gb.mjs → command-C0Di14--.mjs} +1 -1
  207. package/admin-dist/server/_ssr/{content-D1tbeOd0.mjs → content-CT-FPsmV.mjs} +12 -55
  208. package/admin-dist/server/_ssr/{content-types-BZqY_BER.mjs → content-types-C8cBFdzE.mjs} +15 -46
  209. package/admin-dist/server/_ssr/{index-BIdq4xaC.mjs → index-BJtcrEc-.mjs} +5 -5
  210. package/admin-dist/server/_ssr/index.mjs +2 -2
  211. package/admin-dist/server/_ssr/{label-T-QNKAr6.mjs → label-qn2Afwl4.mjs} +1 -1
  212. package/admin-dist/server/_ssr/{media-C-xqjBrl.mjs → media-qv5IAsMZ.mjs} +14 -14
  213. package/admin-dist/server/_ssr/{new._contentTypeId-DWic9cRq.mjs → new._contentTypeId-DdGyrhqs.mjs} +13 -13
  214. package/admin-dist/server/_ssr/{router-D1BMAMJT.mjs → router-nSVkxb6Y.mjs} +11 -11
  215. package/admin-dist/server/_ssr/{scroll-area-C0pic_WA.mjs → scroll-area-BCinP455.mjs} +1 -1
  216. package/admin-dist/server/_ssr/{select-CqmuN2F6.mjs → select-BKQlQScw.mjs} +1 -1
  217. package/admin-dist/server/_ssr/{settings-CAkncGGV.mjs → settings-BCr2KQlk.mjs} +55 -40
  218. package/admin-dist/server/_ssr/{switch-CgmuJkT9.mjs → switch-BaOi42fE.mjs} +1 -1
  219. package/admin-dist/server/_ssr/{tabs-CnMj0aRy.mjs → tabs-DYXEi9kq.mjs} +2 -2
  220. package/admin-dist/server/_ssr/{tanstack-adapter-BXZrMauE.mjs → tanstack-adapter-Bsz8kha-.mjs} +1 -1
  221. package/admin-dist/server/_ssr/{taxonomies-thl3BfVm.mjs → taxonomies-CueMHTbE.mjs} +30 -19
  222. package/admin-dist/server/_ssr/{textarea-4K5OJgeh.mjs → textarea-CI0Jqx2x.mjs} +1 -1
  223. package/admin-dist/server/_ssr/{trash-B40Gx5zP.mjs → trash-DE6W8GoX.mjs} +20 -17
  224. package/admin-dist/server/_ssr/{useBreadcrumbLabel-rn-fL4zV.mjs → useBreadcrumbLabel-B5Yi72lM.mjs} +1 -1
  225. package/admin-dist/server/_ssr/{usePermissions-CKeM6_Vw.mjs → usePermissions-C3nZ-Izm.mjs} +1 -1
  226. package/admin-dist/server/index.mjs +187 -194
  227. package/dist/client/admin/bulk.d.ts +79 -0
  228. package/dist/client/admin/bulk.d.ts.map +1 -0
  229. package/dist/client/admin/bulk.js +72 -0
  230. package/dist/client/admin/bulk.js.map +1 -0
  231. package/dist/client/admin/contentLock.d.ts +118 -0
  232. package/dist/client/admin/contentLock.d.ts.map +1 -0
  233. package/dist/client/admin/contentLock.js +81 -0
  234. package/dist/client/admin/contentLock.js.map +1 -0
  235. package/dist/client/{adminApi.d.ts → admin/contentTypes.d.ts} +39 -1134
  236. package/dist/client/admin/contentTypes.d.ts.map +1 -0
  237. package/dist/client/admin/contentTypes.js +122 -0
  238. package/dist/client/admin/contentTypes.js.map +1 -0
  239. package/dist/client/admin/dashboard.d.ts +16 -0
  240. package/dist/client/admin/dashboard.d.ts.map +1 -0
  241. package/dist/client/admin/dashboard.js +33 -0
  242. package/dist/client/admin/dashboard.js.map +1 -0
  243. package/dist/client/admin/entries.d.ts +358 -0
  244. package/dist/client/admin/entries.d.ts.map +1 -0
  245. package/dist/client/admin/entries.js +220 -0
  246. package/dist/client/admin/entries.js.map +1 -0
  247. package/dist/client/admin/index.d.ts +6568 -0
  248. package/dist/client/admin/index.d.ts.map +1 -0
  249. package/dist/client/admin/index.js +305 -0
  250. package/dist/client/admin/index.js.map +1 -0
  251. package/dist/client/admin/media.d.ts +1038 -0
  252. package/dist/client/admin/media.d.ts.map +1 -0
  253. package/dist/client/admin/media.js +489 -0
  254. package/dist/client/admin/media.js.map +1 -0
  255. package/dist/client/admin/taxonomies.d.ts +339 -0
  256. package/dist/client/admin/taxonomies.d.ts.map +1 -0
  257. package/dist/client/admin/taxonomies.js +364 -0
  258. package/dist/client/admin/taxonomies.js.map +1 -0
  259. package/dist/client/admin/trash.d.ts +91 -0
  260. package/dist/client/admin/trash.d.ts.map +1 -0
  261. package/dist/client/admin/trash.js +71 -0
  262. package/dist/client/admin/trash.js.map +1 -0
  263. package/dist/client/admin/types.d.ts +320 -0
  264. package/dist/client/admin/types.d.ts.map +1 -0
  265. package/dist/client/admin/types.js +7 -0
  266. package/dist/client/admin/types.js.map +1 -0
  267. package/dist/client/admin/validators.d.ts +3886 -0
  268. package/dist/client/admin/validators.d.ts.map +1 -0
  269. package/dist/client/admin/validators.js +322 -0
  270. package/dist/client/admin/validators.js.map +1 -0
  271. package/dist/client/admin/versions.d.ts +106 -0
  272. package/dist/client/admin/versions.d.ts.map +1 -0
  273. package/dist/client/admin/versions.js +57 -0
  274. package/dist/client/admin/versions.js.map +1 -0
  275. package/dist/client/adminApiTypes.d.ts +27 -0
  276. package/dist/client/adminApiTypes.d.ts.map +1 -0
  277. package/dist/client/adminApiTypes.js +12 -0
  278. package/dist/client/adminApiTypes.js.map +1 -0
  279. package/dist/client/{admin-config.d.ts → adminConfig.d.ts} +2 -2
  280. package/dist/client/adminConfig.d.ts.map +1 -0
  281. package/dist/client/{admin-config.js → adminConfig.js} +1 -1
  282. package/dist/client/adminConfig.js.map +1 -0
  283. package/dist/client/agentTools.d.ts +4 -4
  284. package/dist/client/index.d.ts +2 -2
  285. package/dist/client/index.d.ts.map +1 -1
  286. package/dist/client/index.js +15 -2
  287. package/dist/client/index.js.map +1 -1
  288. package/dist/component/contentEntries.d.ts +4 -4
  289. package/dist/component/contentEntryMutations.d.ts +46 -0
  290. package/dist/component/contentEntryMutations.d.ts.map +1 -1
  291. package/dist/component/contentEntryMutations.js +1 -1
  292. package/dist/component/contentEntryMutations.js.map +1 -1
  293. package/dist/component/contentTypeMigration.d.ts +1 -1
  294. package/dist/component/contentTypeMutations.d.ts +22 -0
  295. package/dist/component/contentTypeMutations.d.ts.map +1 -1
  296. package/dist/component/contentTypeMutations.js +1 -1
  297. package/dist/component/contentTypeMutations.js.map +1 -1
  298. package/dist/component/mediaAssetMutations.d.ts +47 -0
  299. package/dist/component/mediaAssetMutations.d.ts.map +1 -1
  300. package/dist/component/mediaAssetMutations.js +1 -1
  301. package/dist/component/mediaAssetMutations.js.map +1 -1
  302. package/dist/component/schema.d.ts +9 -0
  303. package/dist/component/schema.d.ts.map +1 -1
  304. package/dist/component/schema.js +1 -1
  305. package/dist/component/schema.js.map +1 -1
  306. package/package.json +85 -3
  307. package/admin-dist/public/assets/ErrorState-C4nJ-ml4.js +0 -1
  308. package/admin-dist/public/assets/TaxonomyFilter-BgE_SR_O.js +0 -1
  309. package/admin-dist/public/assets/_contentTypeId-DtZectcC.js +0 -1
  310. package/admin-dist/public/assets/content-OEBGlxg1.js +0 -1
  311. package/admin-dist/public/assets/content-types-CjQliqVV.js +0 -2
  312. package/admin-dist/public/assets/globals-hAmgC66w.css +0 -1
  313. package/admin-dist/public/assets/index-BH_ECMhv.js +0 -1
  314. package/admin-dist/public/assets/media-DTJ3-ViE.js +0 -1
  315. package/admin-dist/public/assets/taxonomies-CgG46fIF.js +0 -1
  316. package/admin-dist/public/assets/trash-B3daldm5.js +0 -1
  317. package/admin-dist/server/_ssr/ErrorState-cI-bKLez.mjs +0 -89
  318. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-Dd7AmelK.mjs +0 -4
  319. package/dist/client/admin-config.d.ts.map +0 -1
  320. package/dist/client/admin-config.js.map +0 -1
  321. package/dist/client/adminApi.d.ts.map +0 -1
  322. package/dist/client/adminApi.js +0 -736
  323. package/dist/client/adminApi.js.map +0 -1
@@ -0,0 +1,49 @@
1
+ import { createContext, useContext, useState, useCallback, useMemo } from 'react'
2
+ import type { ReactNode } from 'react'
3
+
4
+ interface BreadcrumbContextValue {
5
+ overrides: Map<string, string>
6
+ setOverride: (path: string, label: string) => void
7
+ clearOverride: (path: string) => void
8
+ }
9
+
10
+ const BreadcrumbContext = createContext<BreadcrumbContextValue | null>(null)
11
+
12
+ export function BreadcrumbProvider({ children }: { children: ReactNode }) {
13
+ const [overrides, setOverrides] = useState<Map<string, string>>(new Map())
14
+
15
+ const setOverride = useCallback((path: string, label: string) => {
16
+ setOverrides((prev) => {
17
+ const next = new Map(prev)
18
+ next.set(path, label)
19
+ return next
20
+ })
21
+ }, [])
22
+
23
+ const clearOverride = useCallback((path: string) => {
24
+ setOverrides((prev) => {
25
+ const next = new Map(prev)
26
+ next.delete(path)
27
+ return next
28
+ })
29
+ }, [])
30
+
31
+ const value = useMemo(
32
+ () => ({ overrides, setOverride, clearOverride }),
33
+ [overrides, setOverride, clearOverride]
34
+ )
35
+
36
+ return (
37
+ <BreadcrumbContext.Provider value={value}>
38
+ {children}
39
+ </BreadcrumbContext.Provider>
40
+ )
41
+ }
42
+
43
+ export function useBreadcrumbContext() {
44
+ const context = useContext(BreadcrumbContext)
45
+ if (!context) {
46
+ throw new Error('useBreadcrumbContext must be used within a BreadcrumbProvider')
47
+ }
48
+ return context
49
+ }
@@ -0,0 +1,57 @@
1
+ import { useQuery } from "convex/react";
2
+ import { createContext, useContext, useMemo, type ReactNode } from "react";
3
+ import { api } from "../../convex/_generated/api";
4
+ import type { AdminConfig } from "~/lib/admin-config";
5
+ import { AdminConfigProvider } from "./AdminConfigContext";
6
+
7
+ type Settings = NonNullable<typeof api.settings.get._returnType>;
8
+
9
+ interface SettingsConfigContextValue {
10
+ baseConfig: AdminConfig;
11
+ settings: Settings | undefined;
12
+ }
13
+
14
+ const SettingsConfigContext = createContext<SettingsConfigContextValue | null>(null);
15
+
16
+ export function SettingsConfigProvider({
17
+ baseConfig,
18
+ children,
19
+ }: {
20
+ baseConfig: AdminConfig;
21
+ children: ReactNode;
22
+ }) {
23
+ const settings = useQuery(api.settings.get);
24
+
25
+ const mergedConfig = useMemo((): AdminConfig => {
26
+ if (!settings) return baseConfig;
27
+
28
+ return {
29
+ ...baseConfig,
30
+ navigation: {
31
+ ...baseConfig.navigation,
32
+ showMedia: baseConfig.navigation.showMedia && settings.features.mediaManagement,
33
+ },
34
+ };
35
+ }, [baseConfig, settings]);
36
+
37
+ const contextValue = useMemo(
38
+ () => ({ baseConfig, settings }),
39
+ [baseConfig, settings]
40
+ );
41
+
42
+ return (
43
+ <SettingsConfigContext.Provider value={contextValue}>
44
+ <AdminConfigProvider config={mergedConfig}>
45
+ {children}
46
+ </AdminConfigProvider>
47
+ </SettingsConfigContext.Provider>
48
+ );
49
+ }
50
+
51
+ export function useSettingsConfig(): SettingsConfigContextValue {
52
+ const ctx = useContext(SettingsConfigContext);
53
+ if (!ctx) {
54
+ throw new Error("useSettingsConfig must be used within SettingsConfigProvider");
55
+ }
56
+ return ctx;
57
+ }
@@ -0,0 +1,91 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ useEffect,
5
+ useState,
6
+ useCallback,
7
+ type ReactNode,
8
+ } from 'react'
9
+
10
+ type Theme = 'light' | 'dark' | 'system'
11
+
12
+ interface ThemeContextValue {
13
+ theme: Theme
14
+ resolvedTheme: 'light' | 'dark'
15
+ setTheme: (theme: Theme) => void
16
+ }
17
+
18
+ const ThemeContext = createContext<ThemeContextValue | null>(null)
19
+
20
+ const STORAGE_KEY = 'convex-cms-theme'
21
+
22
+ function getSystemTheme(): 'light' | 'dark' {
23
+ if (typeof window === 'undefined') return 'light'
24
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
25
+ }
26
+
27
+ function getStoredTheme(): Theme {
28
+ if (typeof window === 'undefined') return 'system'
29
+ const stored = localStorage.getItem(STORAGE_KEY)
30
+ if (stored === 'light' || stored === 'dark' || stored === 'system') {
31
+ return stored
32
+ }
33
+ return 'system'
34
+ }
35
+
36
+ export function ThemeProvider({ children }: { children: ReactNode }) {
37
+ const [theme, setThemeState] = useState<Theme>(() => getStoredTheme())
38
+ const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>(() => {
39
+ const stored = getStoredTheme()
40
+ return stored === 'system' ? getSystemTheme() : stored
41
+ })
42
+
43
+ const applyTheme = useCallback((newTheme: Theme) => {
44
+ const resolved = newTheme === 'system' ? getSystemTheme() : newTheme
45
+ setResolvedTheme(resolved)
46
+
47
+ const root = document.documentElement
48
+ root.classList.remove('light', 'dark')
49
+ root.classList.add(resolved)
50
+ }, [])
51
+
52
+ const setTheme = useCallback(
53
+ (newTheme: Theme) => {
54
+ setThemeState(newTheme)
55
+ localStorage.setItem(STORAGE_KEY, newTheme)
56
+ applyTheme(newTheme)
57
+ },
58
+ [applyTheme]
59
+ )
60
+
61
+ useEffect(() => {
62
+ applyTheme(theme)
63
+ }, [theme, applyTheme])
64
+
65
+ useEffect(() => {
66
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
67
+
68
+ const handleChange = () => {
69
+ if (theme === 'system') {
70
+ applyTheme('system')
71
+ }
72
+ }
73
+
74
+ mediaQuery.addEventListener('change', handleChange)
75
+ return () => mediaQuery.removeEventListener('change', handleChange)
76
+ }, [theme, applyTheme])
77
+
78
+ return (
79
+ <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>
80
+ {children}
81
+ </ThemeContext.Provider>
82
+ )
83
+ }
84
+
85
+ export function useTheme() {
86
+ const context = useContext(ThemeContext)
87
+ if (!context) {
88
+ throw new Error('useTheme must be used within a ThemeProvider')
89
+ }
90
+ return context
91
+ }
@@ -0,0 +1,20 @@
1
+ export {
2
+ AuthProvider,
3
+ useAuth,
4
+ type AuthUser,
5
+ type AuthState,
6
+ type AuthContextValue,
7
+ type AuthProviderProps,
8
+ type GetUserHook,
9
+ type GetUserRoleHook,
10
+ type LogoutHook,
11
+ type PermissionCheck,
12
+ } from './AuthContext';
13
+
14
+ export { ThemeProvider, useTheme } from './ThemeContext';
15
+
16
+ export { AdminConfigProvider, useAdminConfig } from './AdminConfigContext';
17
+
18
+ export { SettingsConfigProvider, useSettingsConfig } from './SettingsConfigContext';
19
+
20
+ export { BreadcrumbProvider, useBreadcrumbContext } from './BreadcrumbContext';
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Embed Header
3
+ *
4
+ * A simplified header for the embedded admin without router dependencies.
5
+ */
6
+
7
+ import { ChevronLeft, Bell, HelpCircle, User, LogOut, Moon, Sun } from "lucide-react";
8
+ import { useAdminConfig, useTheme, useAuth } from "../../contexts";
9
+ import { useEmbedNavigation } from "../navigation";
10
+
11
+ export function EmbedHeader() {
12
+ const { goBack, canGoBack, currentRoute } = useEmbedNavigation();
13
+ const { branding: _branding } = useAdminConfig();
14
+ const { theme, setTheme } = useTheme();
15
+ const { user, logout, isAuthenticated } = useAuth();
16
+
17
+ const routeTitles: Record<string, string> = {
18
+ dashboard: "Dashboard",
19
+ content: "Content",
20
+ "content-types": "Content Types",
21
+ media: "Media Library",
22
+ taxonomies: "Taxonomies",
23
+ settings: "Settings",
24
+ trash: "Trash",
25
+ entries: "Entries",
26
+ };
27
+
28
+ const title = routeTitles[currentRoute.route] || "Dashboard";
29
+
30
+ return (
31
+ <header className="sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background px-6">
32
+ <div className="flex items-center gap-4">
33
+ {canGoBack && (
34
+ <button
35
+ type="button"
36
+ onClick={goBack}
37
+ className="flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
38
+ >
39
+ <ChevronLeft className="size-4" />
40
+ Back
41
+ </button>
42
+ )}
43
+ <h1 className="text-lg font-semibold text-foreground">{title}</h1>
44
+ </div>
45
+
46
+ <div className="flex items-center gap-2">
47
+ <button
48
+ type="button"
49
+ onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
50
+ className="flex size-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
51
+ title={`Switch to ${theme === "dark" ? "light" : "dark"} mode`}
52
+ >
53
+ {theme === "dark" ? <Sun className="size-5" /> : <Moon className="size-5" />}
54
+ </button>
55
+
56
+ <button
57
+ type="button"
58
+ className="flex size-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
59
+ title="Notifications"
60
+ >
61
+ <Bell className="size-5" />
62
+ </button>
63
+
64
+ <button
65
+ type="button"
66
+ className="flex size-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
67
+ title="Help"
68
+ >
69
+ <HelpCircle className="size-5" />
70
+ </button>
71
+
72
+ {isAuthenticated && user && (
73
+ <div className="ml-2 flex items-center gap-2 border-l border-border pl-4">
74
+ <div className="flex size-8 items-center justify-center rounded-full bg-primary text-primary-foreground">
75
+ {user.avatarUrl ? (
76
+ <img
77
+ src={user.avatarUrl}
78
+ alt={user.name || "User"}
79
+ className="size-full rounded-full object-cover"
80
+ />
81
+ ) : (
82
+ <User className="size-4" />
83
+ )}
84
+ </div>
85
+ {user.name && (
86
+ <span className="text-sm font-medium text-foreground">
87
+ {user.name}
88
+ </span>
89
+ )}
90
+ <button
91
+ type="button"
92
+ onClick={() => logout()}
93
+ className="flex size-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
94
+ title="Log out"
95
+ >
96
+ <LogOut className="size-4" />
97
+ </button>
98
+ </div>
99
+ )}
100
+ </div>
101
+ </header>
102
+ );
103
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Embed Layout
3
+ *
4
+ * A router-agnostic layout for the embedded admin that uses
5
+ * EmbedSidebar instead of the router-dependent Sidebar.
6
+ */
7
+
8
+ import type { ReactNode } from "react";
9
+ import { EmbedSidebar } from "./EmbedSidebar";
10
+ import { EmbedHeader } from "./EmbedHeader";
11
+ import { useAdminConfig } from "../../contexts";
12
+
13
+ interface EmbedLayoutProps {
14
+ children: ReactNode;
15
+ }
16
+
17
+ export function EmbedLayout({ children }: EmbedLayoutProps) {
18
+ const { layout } = useAdminConfig();
19
+
20
+ return (
21
+ <div className="flex min-h-screen bg-background">
22
+ <EmbedSidebar />
23
+ <div className="flex flex-1 flex-col" style={{ marginLeft: layout.sidebarWidth }}>
24
+ <EmbedHeader />
25
+ <main className="flex-1 overflow-auto p-6">{children}</main>
26
+ </div>
27
+ </div>
28
+ );
29
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Embed Sidebar
3
+ *
4
+ * A router-agnostic version of the Sidebar component that uses
5
+ * the EmbedNavigation context for navigation instead of TanStack Router.
6
+ */
7
+
8
+ import { Layers } from "lucide-react";
9
+ import { cn } from "../../lib/cn";
10
+ import { useAdminConfig } from "../../contexts";
11
+ import { Icon } from "../../lib/icons";
12
+ import { useEmbedNavigation, type EmbedRoute } from "../navigation";
13
+ import type { NavItem } from "../../lib/admin-config";
14
+
15
+ function pathToRoute(path: string): EmbedRoute {
16
+ if (path === "/" || path === "") return "dashboard";
17
+ if (path.startsWith("/content-types")) return "content-types";
18
+ if (path.startsWith("/entries")) return "entries";
19
+ if (path.startsWith("/content")) return "content";
20
+ if (path.startsWith("/media")) return "media";
21
+ if (path.startsWith("/taxonomies")) return "taxonomies";
22
+ if (path.startsWith("/settings")) return "settings";
23
+ if (path.startsWith("/trash")) return "trash";
24
+ return "dashboard";
25
+ }
26
+
27
+ export function EmbedSidebar() {
28
+ const { currentPath, navigate } = useEmbedNavigation();
29
+ const config = useAdminConfig();
30
+ const { navItems, branding, layout } = config;
31
+
32
+ const isActive = (path: string, exact?: boolean) => {
33
+ const normalizedCurrent = currentPath.replace(/^\/admin/, "");
34
+ if (exact) {
35
+ return normalizedCurrent === path;
36
+ }
37
+ return normalizedCurrent.startsWith(path);
38
+ };
39
+
40
+ const handleNavClick = (item: NavItem) => {
41
+ const route = pathToRoute(item.path);
42
+ navigate(route);
43
+ };
44
+
45
+ const renderNavItem = (item: NavItem) => (
46
+ <button
47
+ key={item.id}
48
+ type="button"
49
+ onClick={() => handleNavClick(item)}
50
+ className={cn(
51
+ "flex w-full items-center gap-3 rounded-md px-2 py-2 text-left text-sm font-medium transition-colors",
52
+ isActive(item.path, item.exact)
53
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
54
+ : "text-sidebar-foreground hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground"
55
+ )}
56
+ >
57
+ <Icon name={item.icon} className="size-5" />
58
+ <span className="flex-1">{item.label}</span>
59
+ {item.badge && (
60
+ <span className="rounded-full bg-sidebar-primary px-2 py-0.5 text-xs text-sidebar-primary-foreground">
61
+ {item.badge}
62
+ </span>
63
+ )}
64
+ </button>
65
+ );
66
+
67
+ const sidebarWidth = layout.sidebarWidth;
68
+
69
+ return (
70
+ <aside
71
+ className="fixed inset-y-0 left-0 z-50 flex flex-col border-r border-sidebar-border bg-sidebar"
72
+ style={{ width: sidebarWidth }}
73
+ >
74
+ <div className="flex h-14 items-center gap-2 border-b border-sidebar-border px-4">
75
+ <button
76
+ type="button"
77
+ onClick={() => navigate("dashboard")}
78
+ className="flex items-center gap-2 font-semibold text-sidebar-foreground"
79
+ >
80
+ {branding.logo ? (
81
+ <img src={branding.logo} alt={branding.appName} className="size-8" />
82
+ ) : (
83
+ <div className="flex size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
84
+ <Layers className="size-4" />
85
+ </div>
86
+ )}
87
+ <span className="text-base">{branding.appName}</span>
88
+ </button>
89
+ </div>
90
+
91
+ <nav className="flex-1 space-y-6 overflow-y-auto p-4">
92
+ {navItems.main.length > 0 && (
93
+ <div className="space-y-1">
94
+ <span className="px-2 text-xs font-medium uppercase tracking-wider text-sidebar-foreground/60">
95
+ Main
96
+ </span>
97
+ <div className="space-y-1 pt-2">{navItems.main.map(renderNavItem)}</div>
98
+ </div>
99
+ )}
100
+
101
+ {navItems.config.length > 0 && (
102
+ <div className="space-y-1">
103
+ <span className="px-2 text-xs font-medium uppercase tracking-wider text-sidebar-foreground/60">
104
+ Configuration
105
+ </span>
106
+ <div className="space-y-1 pt-2">{navItems.config.map(renderNavItem)}</div>
107
+ </div>
108
+ )}
109
+ </nav>
110
+
111
+ <div className="border-t border-sidebar-border p-4">
112
+ <div className="flex items-center justify-between text-xs text-sidebar-foreground/60">
113
+ <span>Version</span>
114
+ <span className="font-mono">0.1.0</span>
115
+ </div>
116
+ </div>
117
+ </aside>
118
+ );
119
+ }
@@ -0,0 +1,3 @@
1
+ export { EmbedSidebar } from "./EmbedSidebar";
2
+ export { EmbedHeader } from "./EmbedHeader";
3
+ export { EmbedLayout } from "./EmbedLayout";
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Embed API Context
3
+ *
4
+ * Provides the Convex API to embedded CMS admin pages.
5
+ * The API structure matches the namespaced exports from defineAdminAPI,
6
+ * allowing shared page components to work with the generated api object.
7
+ */
8
+
9
+ import { createContext, useContext, type ReactNode } from "react";
10
+ import { api } from "../../../convex/_generated/api";
11
+
12
+ export type CmsAdminApi = typeof api["admin"];
13
+
14
+ const ApiContext = createContext<CmsAdminApi | null>(null);
15
+
16
+ export function ApiProvider({
17
+ api,
18
+ children,
19
+ }: {
20
+ api: CmsAdminApi;
21
+ children: ReactNode;
22
+ }) {
23
+ return <ApiContext.Provider value={api}>{children}</ApiContext.Provider>;
24
+ }
25
+
26
+ export function useApi(): CmsAdminApi {
27
+ const api = useContext(ApiContext);
28
+ if (!api) {
29
+ throw new Error("useApi must be used within ApiProvider");
30
+ }
31
+ return api;
32
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Embeddable CMS Admin Component
3
+ *
4
+ * Use this component to embed the CMS admin UI into your existing React app.
5
+ * Provides a fully functional admin interface with router-agnostic navigation.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { CmsAdmin } from "@convex-cms/admin/embed";
10
+ *
11
+ * function App() {
12
+ * return (
13
+ * <CmsAdmin
14
+ * convexUrl="https://your-deployment.convex.cloud"
15
+ * auth={{
16
+ * getUser: () => currentUser,
17
+ * getUserRole: (userId) => userRoles[userId] ?? null,
18
+ * onLogout: () => signOut(),
19
+ * }}
20
+ * config={{
21
+ * branding: { appName: "My CMS" },
22
+ * navigation: { showTaxonomies: false },
23
+ * }}
24
+ * basePath="/admin"
25
+ * />
26
+ * );
27
+ * }
28
+ * ```
29
+ */
30
+
31
+ import { ConvexProvider, ConvexReactClient } from "convex/react";
32
+ import { useMemo, type ReactNode } from "react";
33
+ import { AdminConfigProvider } from "../contexts/AdminConfigContext";
34
+ import {
35
+ AuthProvider,
36
+ type GetUserHook,
37
+ type GetUserRoleHook,
38
+ type LogoutHook,
39
+ } from "../contexts/AuthContext";
40
+ import { ThemeProvider } from "../contexts/ThemeContext";
41
+ import { RouteGuard } from "../components/RouteGuard";
42
+ import { resolveAdminConfig } from "../lib/admin-config";
43
+ import type { CmsAdminProps, CmsAdminAuthConfig } from "./types";
44
+ import { ApiProvider } from "./contexts/ApiContext";
45
+ import {
46
+ EmbedNavigationProvider,
47
+ useEmbedNavigation,
48
+ type EmbedRoute,
49
+ } from "./navigation";
50
+ import { EmbedLayout } from "./components/EmbedLayout";
51
+ import {
52
+ EmbedDashboard,
53
+ EmbedContent,
54
+ EmbedContentTypes,
55
+ EmbedMedia,
56
+ EmbedSettings,
57
+ EmbedTrash,
58
+ EmbedTaxonomies,
59
+ } from "./pages";
60
+
61
+ function adaptAuthConfig(auth: CmsAdminAuthConfig): {
62
+ getUser: GetUserHook;
63
+ getUserRole: GetUserRoleHook;
64
+ onLogout: LogoutHook;
65
+ } {
66
+ return {
67
+ getUser: auth.getUser,
68
+ getUserRole: ({ userId }) => auth.getUserRole(userId),
69
+ onLogout: auth.onLogout ?? (() => {}),
70
+ };
71
+ }
72
+
73
+ function ConvexProviderWrapper({
74
+ convexUrl,
75
+ children,
76
+ }: {
77
+ convexUrl: string;
78
+ children: ReactNode;
79
+ }) {
80
+ const convex = useMemo(() => {
81
+ if (!convexUrl) return null;
82
+ return new ConvexReactClient(convexUrl);
83
+ }, [convexUrl]);
84
+
85
+ if (!convex) {
86
+ return (
87
+ <div className="flex min-h-full items-center justify-center bg-background p-6">
88
+ <div className="max-w-lg space-y-4 rounded-lg border border-amber-200 bg-amber-50 p-6 text-center">
89
+ <h2 className="text-xl font-semibold text-amber-900">
90
+ Convex Configuration Required
91
+ </h2>
92
+ <p className="text-sm text-amber-800">
93
+ Please provide a valid convexUrl prop to the CmsAdmin component.
94
+ </p>
95
+ </div>
96
+ </div>
97
+ );
98
+ }
99
+
100
+ return <ConvexProvider client={convex}>{children}</ConvexProvider>;
101
+ }
102
+
103
+ function EmbedRouter() {
104
+ const { currentRoute } = useEmbedNavigation();
105
+
106
+ const renderPage = () => {
107
+ switch (currentRoute.route) {
108
+ case "dashboard":
109
+ return <EmbedDashboard />;
110
+ case "content":
111
+ return <EmbedContent />;
112
+ case "content-types":
113
+ return <EmbedContentTypes />;
114
+ case "media":
115
+ return <EmbedMedia />;
116
+ case "settings":
117
+ return <EmbedSettings />;
118
+ case "taxonomies":
119
+ return <EmbedTaxonomies />;
120
+ case "trash":
121
+ return <EmbedTrash />;
122
+ case "entries":
123
+ return <EmbedContent />;
124
+ default:
125
+ return <EmbedDashboard />;
126
+ }
127
+ };
128
+
129
+ return <EmbedLayout>{renderPage()}</EmbedLayout>;
130
+ }
131
+
132
+ export function CmsAdmin({
133
+ api,
134
+ convexUrl,
135
+ config,
136
+ auth,
137
+ basePath = "/admin",
138
+ className,
139
+ initialRoute = "dashboard",
140
+ onNavigate,
141
+ }: CmsAdminProps & {
142
+ initialRoute?: EmbedRoute;
143
+ onNavigate?: (path: string, params: Record<string, string>) => void;
144
+ }) {
145
+ const adminConfig = useMemo(() => resolveAdminConfig(config), [config]);
146
+ const authConfig = useMemo(() => adaptAuthConfig(auth), [auth]);
147
+
148
+ return (
149
+ <div className={className}>
150
+ <ApiProvider api={api}>
151
+ <ThemeProvider>
152
+ <AdminConfigProvider config={adminConfig}>
153
+ <ConvexProviderWrapper convexUrl={convexUrl}>
154
+ <AuthProvider
155
+ getUser={authConfig.getUser}
156
+ getUserRole={authConfig.getUserRole}
157
+ onLogout={authConfig.onLogout}
158
+ >
159
+ <EmbedNavigationProvider
160
+ initialRoute={initialRoute}
161
+ basePath={basePath}
162
+ onNavigate={onNavigate}
163
+ >
164
+ <RouteGuard>
165
+ <div className="min-h-screen">
166
+ <EmbedRouter />
167
+ </div>
168
+ </RouteGuard>
169
+ </EmbedNavigationProvider>
170
+ </AuthProvider>
171
+ </ConvexProviderWrapper>
172
+ </AdminConfigProvider>
173
+ </ThemeProvider>
174
+ </ApiProvider>
175
+ </div>
176
+ );
177
+ }
178
+
179
+ export type { CmsAdminProps, CmsAdminAuthConfig, CmsAdminUser } from "./types";
180
+ export type { CmsAdminApi } from "./contexts/ApiContext";
181
+ export type { AdminConfig, NavItem } from "../lib/admin-config";
182
+ export { resolveAdminConfig, defineAdminConfig } from "../lib/admin-config";
183
+ export type { EmbedRoute, EmbedRouteState } from "./navigation";
184
+ export { useEmbedNavigation, useEmbedParams, useEmbedRoute } from "./navigation";