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,14 @@
1
+ /**
2
+ * Shared Page Components
3
+ *
4
+ * These pages contain all the business logic and UI for the admin interface.
5
+ * They are used by both CLI routes (TanStack Router) and embed pages.
6
+ */
7
+
8
+ export { ContentPage, type ContentPageProps } from "./ContentPage";
9
+ export { ContentTypesPage, type ContentTypesPageProps } from "./ContentTypesPage";
10
+ export { DashboardPage } from "./DashboardPage";
11
+ export { MediaPage, type MediaPageProps } from "./MediaPage";
12
+ export { SettingsPage, type SettingsPageProps } from "./SettingsPage";
13
+ export { TaxonomiesPage, type TaxonomiesPageProps } from "./TaxonomiesPage";
14
+ export { TrashPage, type TrashPageProps } from "./TrashPage";
@@ -0,0 +1,262 @@
1
+ /* eslint-disable */
2
+
3
+ // @ts-nocheck
4
+
5
+ // noinspection JSUnusedGlobalSymbols
6
+
7
+ // This file was automatically generated by TanStack Router.
8
+ // You should NOT make any changes in this file as it will be overwritten.
9
+ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
+
11
+ import { Route as rootRouteImport } from './routes/__root'
12
+ import { Route as TrashRouteImport } from './routes/trash'
13
+ import { Route as TaxonomiesRouteImport } from './routes/taxonomies'
14
+ import { Route as SettingsRouteImport } from './routes/settings'
15
+ import { Route as MediaRouteImport } from './routes/media'
16
+ import { Route as ContentTypesRouteImport } from './routes/content-types'
17
+ import { Route as ContentRouteImport } from './routes/content'
18
+ import { Route as IndexRouteImport } from './routes/index'
19
+ import { Route as EntriesEntryIdRouteImport } from './routes/entries/$entryId'
20
+ import { Route as EntriesTypeContentTypeIdRouteImport } from './routes/entries/type/$contentTypeId'
21
+ import { Route as EntriesNewContentTypeIdRouteImport } from './routes/entries/new.$contentTypeId'
22
+
23
+ const TrashRoute = TrashRouteImport.update({
24
+ id: '/trash',
25
+ path: '/trash',
26
+ getParentRoute: () => rootRouteImport,
27
+ } as any)
28
+ const TaxonomiesRoute = TaxonomiesRouteImport.update({
29
+ id: '/taxonomies',
30
+ path: '/taxonomies',
31
+ getParentRoute: () => rootRouteImport,
32
+ } as any)
33
+ const SettingsRoute = SettingsRouteImport.update({
34
+ id: '/settings',
35
+ path: '/settings',
36
+ getParentRoute: () => rootRouteImport,
37
+ } as any)
38
+ const MediaRoute = MediaRouteImport.update({
39
+ id: '/media',
40
+ path: '/media',
41
+ getParentRoute: () => rootRouteImport,
42
+ } as any)
43
+ const ContentTypesRoute = ContentTypesRouteImport.update({
44
+ id: '/content-types',
45
+ path: '/content-types',
46
+ getParentRoute: () => rootRouteImport,
47
+ } as any)
48
+ const ContentRoute = ContentRouteImport.update({
49
+ id: '/content',
50
+ path: '/content',
51
+ getParentRoute: () => rootRouteImport,
52
+ } as any)
53
+ const IndexRoute = IndexRouteImport.update({
54
+ id: '/',
55
+ path: '/',
56
+ getParentRoute: () => rootRouteImport,
57
+ } as any)
58
+ const EntriesEntryIdRoute = EntriesEntryIdRouteImport.update({
59
+ id: '/entries/$entryId',
60
+ path: '/entries/$entryId',
61
+ getParentRoute: () => rootRouteImport,
62
+ } as any)
63
+ const EntriesTypeContentTypeIdRoute =
64
+ EntriesTypeContentTypeIdRouteImport.update({
65
+ id: '/entries/type/$contentTypeId',
66
+ path: '/entries/type/$contentTypeId',
67
+ getParentRoute: () => rootRouteImport,
68
+ } as any)
69
+ const EntriesNewContentTypeIdRoute = EntriesNewContentTypeIdRouteImport.update({
70
+ id: '/entries/new/$contentTypeId',
71
+ path: '/entries/new/$contentTypeId',
72
+ getParentRoute: () => rootRouteImport,
73
+ } as any)
74
+
75
+ export interface FileRoutesByFullPath {
76
+ '/': typeof IndexRoute
77
+ '/content': typeof ContentRoute
78
+ '/content-types': typeof ContentTypesRoute
79
+ '/media': typeof MediaRoute
80
+ '/settings': typeof SettingsRoute
81
+ '/taxonomies': typeof TaxonomiesRoute
82
+ '/trash': typeof TrashRoute
83
+ '/entries/$entryId': typeof EntriesEntryIdRoute
84
+ '/entries/new/$contentTypeId': typeof EntriesNewContentTypeIdRoute
85
+ '/entries/type/$contentTypeId': typeof EntriesTypeContentTypeIdRoute
86
+ }
87
+ export interface FileRoutesByTo {
88
+ '/': typeof IndexRoute
89
+ '/content': typeof ContentRoute
90
+ '/content-types': typeof ContentTypesRoute
91
+ '/media': typeof MediaRoute
92
+ '/settings': typeof SettingsRoute
93
+ '/taxonomies': typeof TaxonomiesRoute
94
+ '/trash': typeof TrashRoute
95
+ '/entries/$entryId': typeof EntriesEntryIdRoute
96
+ '/entries/new/$contentTypeId': typeof EntriesNewContentTypeIdRoute
97
+ '/entries/type/$contentTypeId': typeof EntriesTypeContentTypeIdRoute
98
+ }
99
+ export interface FileRoutesById {
100
+ __root__: typeof rootRouteImport
101
+ '/': typeof IndexRoute
102
+ '/content': typeof ContentRoute
103
+ '/content-types': typeof ContentTypesRoute
104
+ '/media': typeof MediaRoute
105
+ '/settings': typeof SettingsRoute
106
+ '/taxonomies': typeof TaxonomiesRoute
107
+ '/trash': typeof TrashRoute
108
+ '/entries/$entryId': typeof EntriesEntryIdRoute
109
+ '/entries/new/$contentTypeId': typeof EntriesNewContentTypeIdRoute
110
+ '/entries/type/$contentTypeId': typeof EntriesTypeContentTypeIdRoute
111
+ }
112
+ export interface FileRouteTypes {
113
+ fileRoutesByFullPath: FileRoutesByFullPath
114
+ fullPaths:
115
+ | '/'
116
+ | '/content'
117
+ | '/content-types'
118
+ | '/media'
119
+ | '/settings'
120
+ | '/taxonomies'
121
+ | '/trash'
122
+ | '/entries/$entryId'
123
+ | '/entries/new/$contentTypeId'
124
+ | '/entries/type/$contentTypeId'
125
+ fileRoutesByTo: FileRoutesByTo
126
+ to:
127
+ | '/'
128
+ | '/content'
129
+ | '/content-types'
130
+ | '/media'
131
+ | '/settings'
132
+ | '/taxonomies'
133
+ | '/trash'
134
+ | '/entries/$entryId'
135
+ | '/entries/new/$contentTypeId'
136
+ | '/entries/type/$contentTypeId'
137
+ id:
138
+ | '__root__'
139
+ | '/'
140
+ | '/content'
141
+ | '/content-types'
142
+ | '/media'
143
+ | '/settings'
144
+ | '/taxonomies'
145
+ | '/trash'
146
+ | '/entries/$entryId'
147
+ | '/entries/new/$contentTypeId'
148
+ | '/entries/type/$contentTypeId'
149
+ fileRoutesById: FileRoutesById
150
+ }
151
+ export interface RootRouteChildren {
152
+ IndexRoute: typeof IndexRoute
153
+ ContentRoute: typeof ContentRoute
154
+ ContentTypesRoute: typeof ContentTypesRoute
155
+ MediaRoute: typeof MediaRoute
156
+ SettingsRoute: typeof SettingsRoute
157
+ TaxonomiesRoute: typeof TaxonomiesRoute
158
+ TrashRoute: typeof TrashRoute
159
+ EntriesEntryIdRoute: typeof EntriesEntryIdRoute
160
+ EntriesNewContentTypeIdRoute: typeof EntriesNewContentTypeIdRoute
161
+ EntriesTypeContentTypeIdRoute: typeof EntriesTypeContentTypeIdRoute
162
+ }
163
+
164
+ declare module '@tanstack/react-router' {
165
+ interface FileRoutesByPath {
166
+ '/trash': {
167
+ id: '/trash'
168
+ path: '/trash'
169
+ fullPath: '/trash'
170
+ preLoaderRoute: typeof TrashRouteImport
171
+ parentRoute: typeof rootRouteImport
172
+ }
173
+ '/taxonomies': {
174
+ id: '/taxonomies'
175
+ path: '/taxonomies'
176
+ fullPath: '/taxonomies'
177
+ preLoaderRoute: typeof TaxonomiesRouteImport
178
+ parentRoute: typeof rootRouteImport
179
+ }
180
+ '/settings': {
181
+ id: '/settings'
182
+ path: '/settings'
183
+ fullPath: '/settings'
184
+ preLoaderRoute: typeof SettingsRouteImport
185
+ parentRoute: typeof rootRouteImport
186
+ }
187
+ '/media': {
188
+ id: '/media'
189
+ path: '/media'
190
+ fullPath: '/media'
191
+ preLoaderRoute: typeof MediaRouteImport
192
+ parentRoute: typeof rootRouteImport
193
+ }
194
+ '/content-types': {
195
+ id: '/content-types'
196
+ path: '/content-types'
197
+ fullPath: '/content-types'
198
+ preLoaderRoute: typeof ContentTypesRouteImport
199
+ parentRoute: typeof rootRouteImport
200
+ }
201
+ '/content': {
202
+ id: '/content'
203
+ path: '/content'
204
+ fullPath: '/content'
205
+ preLoaderRoute: typeof ContentRouteImport
206
+ parentRoute: typeof rootRouteImport
207
+ }
208
+ '/': {
209
+ id: '/'
210
+ path: '/'
211
+ fullPath: '/'
212
+ preLoaderRoute: typeof IndexRouteImport
213
+ parentRoute: typeof rootRouteImport
214
+ }
215
+ '/entries/$entryId': {
216
+ id: '/entries/$entryId'
217
+ path: '/entries/$entryId'
218
+ fullPath: '/entries/$entryId'
219
+ preLoaderRoute: typeof EntriesEntryIdRouteImport
220
+ parentRoute: typeof rootRouteImport
221
+ }
222
+ '/entries/type/$contentTypeId': {
223
+ id: '/entries/type/$contentTypeId'
224
+ path: '/entries/type/$contentTypeId'
225
+ fullPath: '/entries/type/$contentTypeId'
226
+ preLoaderRoute: typeof EntriesTypeContentTypeIdRouteImport
227
+ parentRoute: typeof rootRouteImport
228
+ }
229
+ '/entries/new/$contentTypeId': {
230
+ id: '/entries/new/$contentTypeId'
231
+ path: '/entries/new/$contentTypeId'
232
+ fullPath: '/entries/new/$contentTypeId'
233
+ preLoaderRoute: typeof EntriesNewContentTypeIdRouteImport
234
+ parentRoute: typeof rootRouteImport
235
+ }
236
+ }
237
+ }
238
+
239
+ const rootRouteChildren: RootRouteChildren = {
240
+ IndexRoute: IndexRoute,
241
+ ContentRoute: ContentRoute,
242
+ ContentTypesRoute: ContentTypesRoute,
243
+ MediaRoute: MediaRoute,
244
+ SettingsRoute: SettingsRoute,
245
+ TaxonomiesRoute: TaxonomiesRoute,
246
+ TrashRoute: TrashRoute,
247
+ EntriesEntryIdRoute: EntriesEntryIdRoute,
248
+ EntriesNewContentTypeIdRoute: EntriesNewContentTypeIdRoute,
249
+ EntriesTypeContentTypeIdRoute: EntriesTypeContentTypeIdRoute,
250
+ }
251
+ export const routeTree = rootRouteImport
252
+ ._addFileChildren(rootRouteChildren)
253
+ ._addFileTypes<FileRouteTypes>()
254
+
255
+ import type { getRouter } from './router.tsx'
256
+ import type { createStart } from '@tanstack/react-start'
257
+ declare module '@tanstack/react-start' {
258
+ interface Register {
259
+ ssr: true
260
+ router: Awaited<ReturnType<typeof getRouter>>
261
+ }
262
+ }
@@ -0,0 +1,22 @@
1
+ import { createRouter } from '@tanstack/react-router'
2
+ import { routeTree } from './routeTree.gen'
3
+
4
+ /**
5
+ * Creates and configures the TanStack Router instance for the admin application.
6
+ * This function is called by TanStack Start to initialize routing.
7
+ */
8
+ export function getRouter() {
9
+ const router = createRouter({
10
+ routeTree,
11
+ scrollRestoration: true,
12
+ defaultPreload: 'intent',
13
+ })
14
+
15
+ return router
16
+ }
17
+
18
+ declare module '@tanstack/react-router' {
19
+ interface Register {
20
+ router: ReturnType<typeof getRouter>
21
+ }
22
+ }
@@ -0,0 +1,250 @@
1
+ import {
2
+ Outlet,
3
+ createRootRoute,
4
+ HeadContent,
5
+ Scripts,
6
+ } from "@tanstack/react-router";
7
+ import { ConvexProvider, ConvexReactClient } from "convex/react";
8
+ import { useMemo, type ReactNode } from "react";
9
+ import globalsCss from "~/styles/globals.css?url";
10
+ import { AdminLayout, RouteGuard } from "~/components";
11
+ import {
12
+ AuthProvider,
13
+ BreadcrumbProvider,
14
+ SettingsConfigProvider,
15
+ ThemeProvider,
16
+ type GetUserHook,
17
+ type GetUserRoleHook,
18
+ type LogoutHook,
19
+ } from "~/contexts";
20
+ import type { AdminConfig } from "~/lib/admin-config";
21
+ import { resolveAdminConfig } from "~/lib/admin-config";
22
+ import { getServerConfig, type ServerConfig } from "~/lib/config.server";
23
+
24
+ /**
25
+ * Auth Configuration
26
+ *
27
+ * These hooks integrate with the parent app's authentication system.
28
+ * In a real deployment, these would be provided by your auth provider
29
+ * (Clerk, Auth0, Convex Auth, etc.).
30
+ *
31
+ * For development/demo purposes, we provide a mock implementation.
32
+ * Replace these with actual auth integration in production.
33
+ */
34
+
35
+ /**
36
+ * Mock user for development.
37
+ * Set AUTH_MODE=demo to use this, or customize for your auth provider.
38
+ */
39
+ const mockGetUser: GetUserHook = () => {
40
+ // In development/demo mode, return a mock admin user
41
+ return {
42
+ id: "mock_user_123",
43
+ name: "Demo Admin",
44
+ email: "admin@example.com",
45
+ };
46
+ };
47
+
48
+ /**
49
+ * Mock role resolver for development.
50
+ * Returns 'admin' for the mock user.
51
+ */
52
+ const mockGetUserRole: GetUserRoleHook = () => {
53
+ // In development/demo mode, return admin role
54
+ return "admin";
55
+ };
56
+
57
+ /**
58
+ * Mock logout handler.
59
+ */
60
+ const mockLogout: LogoutHook = () => {
61
+ console.log("Logout called (mock mode)");
62
+ };
63
+
64
+ /**
65
+ * No-auth mode - for when auth is not configured.
66
+ * Returns null to indicate unauthenticated state.
67
+ */
68
+ const noAuthGetUser: GetUserHook = () => null;
69
+ const noAuthGetUserRole: GetUserRoleHook = () => null;
70
+ const noAuthLogout: LogoutHook = () => {};
71
+
72
+ /**
73
+ * Get auth hooks based on configuration.
74
+ * Extend this to support different auth providers.
75
+ */
76
+ function getAuthConfig(authMode: string): {
77
+ getUser: GetUserHook;
78
+ getUserRole: GetUserRoleHook;
79
+ onLogout: LogoutHook;
80
+ } {
81
+ switch (authMode) {
82
+ case "mock":
83
+ case "demo":
84
+ return {
85
+ getUser: mockGetUser,
86
+ getUserRole: mockGetUserRole,
87
+ onLogout: mockLogout,
88
+ };
89
+ case "none":
90
+ case "disabled":
91
+ return {
92
+ getUser: noAuthGetUser,
93
+ getUserRole: noAuthGetUserRole,
94
+ onLogout: noAuthLogout,
95
+ };
96
+ default:
97
+ // Default to mock mode for development convenience
98
+ // In production, you should configure your actual auth provider
99
+ return {
100
+ getUser: mockGetUser,
101
+ getUserRole: mockGetUserRole,
102
+ onLogout: mockLogout,
103
+ };
104
+ }
105
+ }
106
+
107
+ export const Route = createRootRoute({
108
+ head: () => ({
109
+ meta: [
110
+ {
111
+ charSet: "utf-8",
112
+ },
113
+ {
114
+ name: "viewport",
115
+ content: "width=device-width, initial-scale=1",
116
+ },
117
+ {
118
+ title: "Convex CMS Admin",
119
+ },
120
+ {
121
+ name: "description",
122
+ content:
123
+ "Admin interface for Convex CMS - manage content, media, and publishing workflows",
124
+ },
125
+ ],
126
+ links: [
127
+ { rel: "stylesheet", href: globalsCss },
128
+ { rel: "icon", href: "/favicon.ico" },
129
+ ],
130
+ }),
131
+ // Load server config at route initialization
132
+ loader: async () => {
133
+ const config = await getServerConfig();
134
+ return { config };
135
+ },
136
+ component: RootComponent,
137
+ });
138
+
139
+ function RootComponent() {
140
+ const { config } = Route.useLoaderData();
141
+
142
+ const authConfig = useMemo(() => getAuthConfig(config.authMode), [config.authMode]);
143
+ const adminConfig = useMemo(
144
+ () => resolveAdminConfig(config.adminConfig),
145
+ [config.adminConfig]
146
+ );
147
+
148
+ return (
149
+ <RootDocument>
150
+ <ThemeProvider>
151
+ <BreadcrumbProvider>
152
+ <ConvexProviderWrapper config={config} adminConfig={adminConfig}>
153
+ <AuthProvider
154
+ getUser={authConfig.getUser}
155
+ getUserRole={authConfig.getUserRole}
156
+ onLogout={authConfig.onLogout}
157
+ >
158
+ <RouteGuard>
159
+ <AdminLayout>
160
+ <Outlet />
161
+ </AdminLayout>
162
+ </RouteGuard>
163
+ </AuthProvider>
164
+ </ConvexProviderWrapper>
165
+ </BreadcrumbProvider>
166
+ </ThemeProvider>
167
+ </RootDocument>
168
+ );
169
+ }
170
+
171
+ function ConvexProviderWrapper({
172
+ children,
173
+ config,
174
+ adminConfig,
175
+ }: {
176
+ children: ReactNode;
177
+ config: ServerConfig;
178
+ adminConfig: AdminConfig;
179
+ }) {
180
+ const convex = useMemo(() => {
181
+ if (!config.convexUrl) return null;
182
+ return new ConvexReactClient(config.convexUrl);
183
+ }, [config.convexUrl]);
184
+
185
+ if (!convex) {
186
+ return (
187
+ <div className="flex min-h-screen items-center justify-center bg-background p-6">
188
+ <div className="max-w-lg space-y-4 rounded-lg border border-amber-200 bg-amber-50 p-6 text-center">
189
+ <h2 className="text-xl font-semibold text-amber-900">
190
+ Convex Configuration Required
191
+ </h2>
192
+ <p className="text-sm text-amber-800">
193
+ Please provide a Convex deployment URL to connect to your backend.
194
+ </p>
195
+ <div className="space-y-2 text-left text-sm text-amber-700">
196
+ <p className="font-medium">Options:</p>
197
+ <ul className="list-inside list-disc space-y-1">
198
+ <li>
199
+ Run with URL:{" "}
200
+ <code className="rounded bg-amber-100 px-1">
201
+ npx convex-cms admin --url YOUR_URL
202
+ </code>
203
+ </li>
204
+ <li>
205
+ Set environment variable:{" "}
206
+ <code className="rounded bg-amber-100 px-1">
207
+ CONVEX_URL=YOUR_URL
208
+ </code>
209
+ </li>
210
+ <li>
211
+ Add to{" "}
212
+ <code className="rounded bg-amber-100 px-1">.env.local</code>:{" "}
213
+ <code className="rounded bg-amber-100 px-1">
214
+ CONVEX_URL=YOUR_URL
215
+ </code>
216
+ </li>
217
+ </ul>
218
+ </div>
219
+ <p className="text-sm text-amber-700">
220
+ Run{" "}
221
+ <code className="rounded bg-amber-100 px-1">npx convex dev</code> to
222
+ start Convex and get your URL.
223
+ </p>
224
+ </div>
225
+ </div>
226
+ );
227
+ }
228
+
229
+ return (
230
+ <ConvexProvider client={convex}>
231
+ <SettingsConfigProvider baseConfig={adminConfig}>
232
+ {children}
233
+ </SettingsConfigProvider>
234
+ </ConvexProvider>
235
+ );
236
+ }
237
+
238
+ function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
239
+ return (
240
+ <html lang="en">
241
+ <head>
242
+ <HeadContent />
243
+ </head>
244
+ <body>
245
+ {children}
246
+ <Scripts />
247
+ </body>
248
+ </html>
249
+ );
250
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Content Types Route (CLI)
3
+ *
4
+ * Thin wrapper around the shared ContentTypesPage component.
5
+ * Provides TanStack Router integration and API access.
6
+ */
7
+
8
+ import { createFileRoute } from "@tanstack/react-router";
9
+ import { api } from "../../convex/_generated/api";
10
+ import { ContentTypesPage } from "~/pages";
11
+ import { useTanStackNavigation } from "~/lib/tanstack-adapter";
12
+
13
+ export const Route = createFileRoute("/content-types")({
14
+ component: ContentTypesRoute,
15
+ });
16
+
17
+ function ContentTypesRoute() {
18
+ const navigation = useTanStackNavigation();
19
+ return <ContentTypesPage api={api.admin} navigation={navigation} />;
20
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Content Route (CLI)
3
+ *
4
+ * Thin wrapper around the shared ContentPage component.
5
+ * Provides TanStack Router integration and API access.
6
+ */
7
+
8
+ import { createFileRoute } from "@tanstack/react-router";
9
+ import { api } from "../../convex/_generated/api";
10
+ import { ContentPage } from "~/pages";
11
+ import { useTanStackNavigation } from "~/lib/tanstack-adapter";
12
+
13
+ export const Route = createFileRoute("/content")({
14
+ component: ContentRoute,
15
+ });
16
+
17
+ function ContentRoute() {
18
+ const navigation = useTanStackNavigation();
19
+ return <ContentPage api={api.admin} navigation={navigation} />;
20
+ }
@@ -0,0 +1,107 @@
1
+ import { createFileRoute, useNavigate } from '@tanstack/react-router';
2
+ import { useQuery } from 'convex/react';
3
+ import { api } from '../../../convex/_generated/api';
4
+ import { ContentEntryEditor } from '~/components/ContentEntryEditor';
5
+ import type { ContentType, ContentEntry } from '~/components/ContentEntryEditor';
6
+ import { usePermissions, useBreadcrumbLabel } from '~/hooks';
7
+ import { CmsEmptyState } from '~/components/cmsds/CmsEmptyState';
8
+ import { CmsButton as _CmsButton } from '~/components/cmsds/CmsButton';
9
+ import { FileText } from 'lucide-react';
10
+
11
+ export const Route = createFileRoute('/entries/$entryId')({
12
+ component: EditEntryPage,
13
+ });
14
+
15
+ function EditEntryPage() {
16
+ const { entryId } = Route.useParams();
17
+ const navigate = useNavigate();
18
+ const { canDelete } = usePermissions();
19
+
20
+ const entry = useQuery(api.entries.get, { id: entryId });
21
+
22
+ const contentType = useQuery(
23
+ api.contentTypes.get,
24
+ entry ? { id: entry.contentTypeId } : 'skip'
25
+ );
26
+
27
+ const getEntryTitle = () => {
28
+ if (!entry || !contentType) return undefined;
29
+ const titleField = contentType.titleField ?? 'title';
30
+ const title = entry.data[titleField];
31
+ return typeof title === 'string' && title ? title : 'Untitled';
32
+ };
33
+
34
+ useBreadcrumbLabel(`/entries/${entryId}`, getEntryTitle());
35
+
36
+ if (entry === undefined || (entry && contentType === undefined)) {
37
+ return (
38
+ <div className="space-y-6 p-6">
39
+ <div className="flex flex-col items-center justify-center py-12">
40
+ <div className="size-8 animate-spin rounded-full border-2 border-muted border-t-primary" />
41
+ <p className="mt-4 text-sm text-muted-foreground">Loading entry...</p>
42
+ </div>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ if (entry === null) {
48
+ return (
49
+ <div className="space-y-6 p-6">
50
+ <CmsEmptyState
51
+ icon={<FileText className="size-6" />}
52
+ title="Entry Not Found"
53
+ description="The content entry you're looking for doesn't exist or has been deleted."
54
+ action={{
55
+ label: 'Back to Content',
56
+ onClick: () => navigate({ to: '/content-types' }),
57
+ }}
58
+ />
59
+ </div>
60
+ );
61
+ }
62
+
63
+ if (contentType === null) {
64
+ return (
65
+ <div className="space-y-6 p-6">
66
+ <CmsEmptyState
67
+ icon={<FileText className="size-6" />}
68
+ title="Content Type Not Found"
69
+ description="The content type for this entry doesn't exist or has been deleted."
70
+ action={{
71
+ label: 'Back to Content',
72
+ onClick: () => navigate({ to: '/content-types' }),
73
+ }}
74
+ />
75
+ </div>
76
+ );
77
+ }
78
+
79
+ // Handle successful save
80
+ const handleSave = (_savedEntry: ContentEntry) => {
81
+ // Stay on the page but show a success state
82
+ // The component will handle the success feedback
83
+ };
84
+
85
+ // Handle cancel
86
+ const handleCancel = () => {
87
+ navigate({ to: '/content' });
88
+ };
89
+
90
+ // Handle delete - navigate back to content list
91
+ const handleDelete = () => {
92
+ navigate({ to: '/content' });
93
+ };
94
+
95
+ return (
96
+ <div className="space-y-6 p-6">
97
+ <ContentEntryEditor
98
+ contentType={contentType as ContentType}
99
+ entry={entry as ContentEntry}
100
+ onSave={handleSave}
101
+ onCancel={handleCancel}
102
+ onDelete={handleDelete}
103
+ canDelete={canDelete('contentEntries')}
104
+ />
105
+ </div>
106
+ );
107
+ }