convex-cms 0.0.3 → 0.0.5-alpha.2

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 (375) hide show
  1. package/README.md +107 -60
  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-CRswfTzk.js → CmsEmptyState-CkqBIab3.js} +2 -2
  158. package/admin-dist/public/assets/{CmsPageHeader-CirpXndm.js → CmsPageHeader-CUtl5MMG.js} +1 -1
  159. package/admin-dist/public/assets/{CmsStatusBadge-CbEUpQu-.js → CmsStatusBadge-CUYFgEe-.js} +1 -1
  160. package/admin-dist/public/assets/CmsSurface-CsJfAVa3.js +1 -0
  161. package/admin-dist/public/assets/{CmsToolbar-BI2nZOXp.js → CmsToolbar-CnfbcxeP.js} +1 -1
  162. package/admin-dist/public/assets/{ContentEntryEditor-CBeCyK_m.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-CKU_glsK.js → _entryId-CuVMExbb.js} +1 -1
  166. package/admin-dist/public/assets/alert-CF1BSzGR.js +1 -0
  167. package/admin-dist/public/assets/{badge-hvUOzpVZ.js → badge-CmuOIVKp.js} +1 -1
  168. package/admin-dist/public/assets/{circle-check-big-CF_pR17r.js → circle-check-big-BKDVG6DU.js} +1 -1
  169. package/admin-dist/public/assets/{command-DU82cJlt.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-KNtpL71g.js → label-CHCnXeBk.js} +1 -1
  175. package/admin-dist/public/assets/{link-2-Bw2aI4V4.js → link-2-Bb34judH.js} +1 -1
  176. package/admin-dist/public/assets/{list-sYepHjt_.js → list-9Pzt48ld.js} +1 -1
  177. package/admin-dist/public/assets/{main-CKj5yfEi.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-C3LstjNs.js → new._contentTypeId-C_I4YxIa.js} +1 -1
  180. package/admin-dist/public/assets/{plus-DUn8v_Xf.js → plus-Ceef7DHk.js} +1 -1
  181. package/admin-dist/public/assets/{rotate-ccw-DJEoHcRI.js → rotate-ccw-7k7-4VUq.js} +1 -1
  182. package/admin-dist/public/assets/scroll-area-CC6wujnp.js +1 -0
  183. package/admin-dist/public/assets/{search-MuAUDJKR.js → search-DwoUV2pv.js} +1 -1
  184. package/admin-dist/public/assets/select-hOZTp8aC.js +1 -0
  185. package/admin-dist/public/assets/settings-t2PbCZh4.js +1 -0
  186. package/admin-dist/public/assets/switch-jX2pDaNU.js +1 -0
  187. package/admin-dist/public/assets/tabs-q4EbZk7c.js +1 -0
  188. package/admin-dist/public/assets/tanstack-adapter-B-Glm4kH.js +1 -0
  189. package/admin-dist/public/assets/taxonomies-kyk5P4ZW.js +1 -0
  190. package/admin-dist/public/assets/{textarea-BTy7nwzR.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-E52Vfeuh.js → triangle-alert-CXFIO_Gu.js} +1 -1
  193. package/admin-dist/public/assets/useBreadcrumbLabel-_6qBagc3.js +1 -0
  194. package/admin-dist/public/assets/{usePermissions-Basjs9BT.js → usePermissions-M1ijZ7a6.js} +1 -1
  195. package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +7 -0
  196. package/admin-dist/server/_ssr/{badge-6BsP37vG.mjs → CmsButton-DOiTVKQq.mjs} +33 -33
  197. package/admin-dist/server/_ssr/{CmsEmptyState-DU7-7-mV.mjs → CmsEmptyState-fbnGt3LD.mjs} +2 -2
  198. package/admin-dist/server/_ssr/{CmsPageHeader-CseW0AHm.mjs → CmsPageHeader-DHRrdOZa.mjs} +1 -1
  199. package/admin-dist/server/_ssr/{CmsStatusBadge-B_pi4KCp.mjs → CmsStatusBadge-s7obWbKZ.mjs} +2 -2
  200. package/admin-dist/server/_ssr/CmsSurface-rFoYjb62.mjs +44 -0
  201. package/admin-dist/server/_ssr/{CmsToolbar-X75ex6ek.mjs → CmsToolbar-zTE45z2q.mjs} +2 -2
  202. package/admin-dist/server/_ssr/{ContentEntryEditor-CepusRsA.mjs → ContentEntryEditor-BLoEjT_m.mjs} +12 -12
  203. package/admin-dist/server/_ssr/{TaxonomyFilter-Bwrq0-cz.mjs → TaxonomyFilter-XAtaJC2z.mjs} +5 -5
  204. package/admin-dist/server/_ssr/{_contentTypeId-BqYKEcLr.mjs → _contentTypeId-Csl4822C.mjs} +13 -13
  205. package/admin-dist/server/_ssr/{_entryId-CRfnqeDf.mjs → _entryId-D8alLFBx.mjs} +15 -15
  206. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-BffZedId.mjs +4 -0
  207. package/admin-dist/server/_ssr/{command-fy8epIKf.mjs → command-C0Di14--.mjs} +1 -1
  208. package/admin-dist/server/_ssr/{content-B5RhL7uW.mjs → content-CT-FPsmV.mjs} +170 -98
  209. package/admin-dist/server/_ssr/{content-types-BIOqCQYN.mjs → content-types-C8cBFdzE.mjs} +260 -115
  210. package/admin-dist/server/_ssr/{index-DHSHDPt1.mjs → index-BJtcrEc-.mjs} +88 -17
  211. package/admin-dist/server/_ssr/index.mjs +2 -2
  212. package/admin-dist/server/_ssr/{label-C8Dko1j7.mjs → label-qn2Afwl4.mjs} +1 -1
  213. package/admin-dist/server/_ssr/{media-CSx3XttC.mjs → media-qv5IAsMZ.mjs} +43 -43
  214. package/admin-dist/server/_ssr/{new._contentTypeId-DzanEZQM.mjs → new._contentTypeId-DdGyrhqs.mjs} +13 -13
  215. package/admin-dist/server/_ssr/{router-DDWcF-kt.mjs → router-nSVkxb6Y.mjs} +11 -11
  216. package/admin-dist/server/_ssr/{scroll-area-bjPYwhXN.mjs → scroll-area-BCinP455.mjs} +1 -1
  217. package/admin-dist/server/_ssr/{select-BUhDDf4T.mjs → select-BKQlQScw.mjs} +1 -1
  218. package/admin-dist/server/_ssr/{settings-DAsxnw2q.mjs → settings-BCr2KQlk.mjs} +236 -139
  219. package/admin-dist/server/_ssr/{switch-BgyRtQ1Z.mjs → switch-BaOi42fE.mjs} +1 -1
  220. package/admin-dist/server/_ssr/{tabs-DzMdRB1A.mjs → tabs-DYXEi9kq.mjs} +5 -3
  221. package/admin-dist/server/_ssr/tanstack-adapter-Bsz8kha-.mjs +119 -0
  222. package/admin-dist/server/_ssr/{taxonomies-C8j8g5Q5.mjs → taxonomies-CueMHTbE.mjs} +184 -73
  223. package/admin-dist/server/_ssr/{textarea-9jNeYJSc.mjs → textarea-CI0Jqx2x.mjs} +1 -1
  224. package/admin-dist/server/_ssr/{trash-DYMxwhZB.mjs → trash-DE6W8GoX.mjs} +211 -88
  225. package/admin-dist/server/_ssr/{useBreadcrumbLabel-FNSAr2Ha.mjs → useBreadcrumbLabel-B5Yi72lM.mjs} +1 -1
  226. package/admin-dist/server/_ssr/{usePermissions-BJGGahrJ.mjs → usePermissions-C3nZ-Izm.mjs} +1 -1
  227. package/admin-dist/server/index.mjs +189 -182
  228. package/dist/cli/commands/init.d.ts +6 -0
  229. package/dist/cli/commands/init.d.ts.map +1 -0
  230. package/dist/cli/commands/init.js +156 -0
  231. package/dist/cli/commands/init.js.map +1 -0
  232. package/dist/cli/index.js +6 -0
  233. package/dist/cli/index.js.map +1 -1
  234. package/dist/client/admin/bulk.d.ts +79 -0
  235. package/dist/client/admin/bulk.d.ts.map +1 -0
  236. package/dist/client/admin/bulk.js +72 -0
  237. package/dist/client/admin/bulk.js.map +1 -0
  238. package/dist/client/admin/contentLock.d.ts +118 -0
  239. package/dist/client/admin/contentLock.d.ts.map +1 -0
  240. package/dist/client/admin/contentLock.js +81 -0
  241. package/dist/client/admin/contentLock.js.map +1 -0
  242. package/dist/client/admin/contentTypes.d.ts +1204 -0
  243. package/dist/client/admin/contentTypes.d.ts.map +1 -0
  244. package/dist/client/admin/contentTypes.js +122 -0
  245. package/dist/client/admin/contentTypes.js.map +1 -0
  246. package/dist/client/admin/dashboard.d.ts +16 -0
  247. package/dist/client/admin/dashboard.d.ts.map +1 -0
  248. package/dist/client/admin/dashboard.js +33 -0
  249. package/dist/client/admin/dashboard.js.map +1 -0
  250. package/dist/client/admin/entries.d.ts +358 -0
  251. package/dist/client/admin/entries.d.ts.map +1 -0
  252. package/dist/client/admin/entries.js +220 -0
  253. package/dist/client/admin/entries.js.map +1 -0
  254. package/dist/client/admin/index.d.ts +6568 -0
  255. package/dist/client/admin/index.d.ts.map +1 -0
  256. package/dist/client/admin/index.js +305 -0
  257. package/dist/client/admin/index.js.map +1 -0
  258. package/dist/client/admin/media.d.ts +1038 -0
  259. package/dist/client/admin/media.d.ts.map +1 -0
  260. package/dist/client/admin/media.js +489 -0
  261. package/dist/client/admin/media.js.map +1 -0
  262. package/dist/client/admin/taxonomies.d.ts +339 -0
  263. package/dist/client/admin/taxonomies.d.ts.map +1 -0
  264. package/dist/client/admin/taxonomies.js +364 -0
  265. package/dist/client/admin/taxonomies.js.map +1 -0
  266. package/dist/client/admin/trash.d.ts +91 -0
  267. package/dist/client/admin/trash.d.ts.map +1 -0
  268. package/dist/client/admin/trash.js +71 -0
  269. package/dist/client/admin/trash.js.map +1 -0
  270. package/dist/client/admin/types.d.ts +320 -0
  271. package/dist/client/admin/types.d.ts.map +1 -0
  272. package/dist/client/admin/types.js +7 -0
  273. package/dist/client/admin/types.js.map +1 -0
  274. package/dist/client/admin/validators.d.ts +3886 -0
  275. package/dist/client/admin/validators.d.ts.map +1 -0
  276. package/dist/client/admin/validators.js +322 -0
  277. package/dist/client/admin/validators.js.map +1 -0
  278. package/dist/client/admin/versions.d.ts +106 -0
  279. package/dist/client/admin/versions.d.ts.map +1 -0
  280. package/dist/client/admin/versions.js +57 -0
  281. package/dist/client/admin/versions.js.map +1 -0
  282. package/dist/client/adminApiTypes.d.ts +27 -0
  283. package/dist/client/adminApiTypes.d.ts.map +1 -0
  284. package/dist/client/adminApiTypes.js +12 -0
  285. package/dist/client/adminApiTypes.js.map +1 -0
  286. package/dist/client/{admin-config.d.ts → adminConfig.d.ts} +4 -4
  287. package/dist/client/adminConfig.d.ts.map +1 -0
  288. package/dist/client/{admin-config.js → adminConfig.js} +3 -3
  289. package/dist/client/adminConfig.js.map +1 -0
  290. package/dist/client/agentTools.d.ts +11 -21
  291. package/dist/client/agentTools.d.ts.map +1 -1
  292. package/dist/client/agentTools.js +4 -4
  293. package/dist/client/index.d.ts +6 -6
  294. package/dist/client/index.d.ts.map +1 -1
  295. package/dist/client/index.js +19 -6
  296. package/dist/client/index.js.map +1 -1
  297. package/dist/client/schema/codegen.d.ts +2 -2
  298. package/dist/client/schema/codegen.d.ts.map +1 -1
  299. package/dist/client/schema/codegen.js +3 -3
  300. package/dist/client/schema/codegen.js.map +1 -1
  301. package/dist/client/schema/defineContentType.d.ts +3 -3
  302. package/dist/client/schema/defineContentType.js +3 -3
  303. package/dist/client/schema/index.d.ts +7 -7
  304. package/dist/client/schema/index.d.ts.map +1 -1
  305. package/dist/client/schema/index.js +5 -5
  306. package/dist/client/schema/index.js.map +1 -1
  307. package/dist/client/schema/schemaDrift.d.ts +1 -1
  308. package/dist/client/schema/schemaDrift.js +1 -1
  309. package/dist/client/schema/typedClient.d.ts +2 -2
  310. package/dist/client/schema/typedClient.js +2 -2
  311. package/dist/client/schema/types.d.ts +1 -1
  312. package/dist/client/schema/types.js +1 -1
  313. package/dist/client/wrapper.d.ts +108 -65
  314. package/dist/client/wrapper.d.ts.map +1 -1
  315. package/dist/client/wrapper.js +22 -22
  316. package/dist/client/wrapper.js.map +1 -1
  317. package/dist/component/contentEntries.d.ts +4 -4
  318. package/dist/component/contentEntryMutations.d.ts +46 -0
  319. package/dist/component/contentEntryMutations.d.ts.map +1 -1
  320. package/dist/component/contentEntryMutations.js +1 -1
  321. package/dist/component/contentEntryMutations.js.map +1 -1
  322. package/dist/component/contentTypeMigration.d.ts +1 -1
  323. package/dist/component/contentTypeMutations.d.ts +22 -0
  324. package/dist/component/contentTypeMutations.d.ts.map +1 -1
  325. package/dist/component/contentTypeMutations.js +1 -1
  326. package/dist/component/contentTypeMutations.js.map +1 -1
  327. package/dist/component/convex.config.d.ts +2 -2
  328. package/dist/component/convex.config.js +2 -2
  329. package/dist/component/index.d.ts +1 -1
  330. package/dist/component/index.js +1 -1
  331. package/dist/component/lib/ragContentChunker.d.ts +1 -1
  332. package/dist/component/lib/ragContentChunker.js +1 -1
  333. package/dist/component/mediaAssetMutations.d.ts +47 -0
  334. package/dist/component/mediaAssetMutations.d.ts.map +1 -1
  335. package/dist/component/mediaAssetMutations.js +1 -1
  336. package/dist/component/mediaAssetMutations.js.map +1 -1
  337. package/dist/component/roles.d.ts +1 -1
  338. package/dist/component/roles.js +1 -1
  339. package/dist/component/schema.d.ts +9 -0
  340. package/dist/component/schema.d.ts.map +1 -1
  341. package/dist/component/schema.js +1 -1
  342. package/dist/component/schema.js.map +1 -1
  343. package/dist/react/index.d.ts +2 -2
  344. package/dist/react/index.d.ts.map +1 -1
  345. package/dist/react/index.js +13 -7
  346. package/dist/react/index.js.map +1 -1
  347. package/dist/test.d.ts +2 -2
  348. package/dist/test.js +2 -2
  349. package/package.json +115 -13
  350. package/admin-dist/public/assets/ErrorState-BIVaWmom.js +0 -1
  351. package/admin-dist/public/assets/TaxonomyFilter-ChaY6Y_x.js +0 -1
  352. package/admin-dist/public/assets/_contentTypeId-DQ8k_Rvw.js +0 -1
  353. package/admin-dist/public/assets/alert-BXjTqrwQ.js +0 -1
  354. package/admin-dist/public/assets/content-_LXl3pp7.js +0 -1
  355. package/admin-dist/public/assets/content-types-KjxaXGxY.js +0 -2
  356. package/admin-dist/public/assets/globals-CS6BZ0zp.css +0 -1
  357. package/admin-dist/public/assets/index-DNGIZHL-.js +0 -1
  358. package/admin-dist/public/assets/media-Bkrkffm7.js +0 -1
  359. package/admin-dist/public/assets/scroll-area-DfIlT0in.js +0 -1
  360. package/admin-dist/public/assets/select-BD29IXCI.js +0 -1
  361. package/admin-dist/public/assets/settings-DmMyn_6A.js +0 -1
  362. package/admin-dist/public/assets/switch-h3Rrnl5i.js +0 -1
  363. package/admin-dist/public/assets/tabs-imc8h-Dp.js +0 -1
  364. package/admin-dist/public/assets/taxonomies-dAsrT65H.js +0 -1
  365. package/admin-dist/public/assets/trash-SAWKZZHv.js +0 -1
  366. package/admin-dist/public/assets/useBreadcrumbLabel-BECBMCzM.js +0 -1
  367. package/admin-dist/server/_ssr/ErrorState-cI-bKLez.mjs +0 -89
  368. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-BwDlABVk.mjs +0 -4
  369. package/admin-dist/server/_ssr/alert-CVt45UUP.mjs +0 -92
  370. package/dist/client/admin-config.d.ts.map +0 -1
  371. package/dist/client/admin-config.js.map +0 -1
  372. package/dist/client/adminApi.d.ts +0 -2273
  373. package/dist/client/adminApi.d.ts.map +0 -1
  374. package/dist/client/adminApi.js +0 -716
  375. package/dist/client/adminApi.js.map +0 -1
package/README.md CHANGED
@@ -1,26 +1,84 @@
1
1
  # Convex CMS
2
2
 
3
- A developer-first headless CMS built as a [Convex Component](https://docs.convex.dev/components).
3
+ A headless CMS built as a [Convex Component](https://docs.convex.dev/components) — content management that runs inside your Convex app.
4
4
 
5
- ## Features
5
+ ## Choose Your Path
6
6
 
7
- - **Type-safe APIs** - Full TypeScript support with generated types
8
- - **Flexible content modeling** - Define content types with 13 field types
9
- - **Publishing workflows** - Draft, publish, schedule, and version content
10
- - **Media management** - Upload, organize, and serve media with variants
11
- - **Role-based access control** - Fine-grained permissions with custom roles
12
- - **Multi-locale support** - Content localization with fallback chains
13
- - **Admin UI** - Ready-to-use React admin interface
7
+ ### Need an Admin Interface?
14
8
 
15
- ## Installation
9
+ Use **`defineAdminAPI`** — one line creates all the backend functions for a working admin UI.
16
10
 
17
- ```bash
18
- npm install convex-cms
19
11
  ```
12
+ Your App Admin UI
13
+ │ │
14
+ └── convex/admin.ts ────────────┘
15
+ defineAdminAPI()
16
+
17
+ ├── listContentTypes
18
+ ├── getEntry
19
+ ├── publishEntry
20
+ └── ... (30+ functions)
21
+
22
+
23
+ CMS Component
24
+ ```
25
+
26
+ → **[Admin UI Setup Guide](./docs/guides/admin-ui-setup.md)**
27
+
28
+ ### Building Custom Content Logic?
29
+
30
+ Use **`createCmsClient`** — full programmatic control with typed methods in your Convex functions.
31
+
32
+ ```
33
+ Your Convex Functions
34
+
35
+ └── cms.contentEntries.list(ctx, { status: "published" })
36
+ cms.contentTypes.create(ctx, { name: "blog", ... })
37
+ cms.mediaAssets.upload(ctx, { ... })
38
+
39
+
40
+ CMS Component
41
+ ```
42
+
43
+ → **[Getting Started Guide](./docs/guides/getting-started.md)**
44
+
45
+ ### Want Full Type Safety?
46
+
47
+ Use **code-first schemas** — define content types with Convex validators, get TypeScript inference.
48
+
49
+ ```typescript
50
+ const blogPost = defineContentType({
51
+ name: "blog_post",
52
+ validator: v.object({
53
+ title: v.string(),
54
+ content: v.string(),
55
+ }),
56
+ });
57
+
58
+ // TypeScript knows entry.data.title is string
59
+ const entry = await cms.typedContentEntries.get<"blog_post">(ctx, id);
60
+ ```
61
+
62
+ → **[Code-First Schema Reference](./docs/api/code-first-schema.md)**
63
+
64
+ ### Need Both?
65
+
66
+ **Most apps use both.** This is the typical setup:
67
+
68
+ - `defineAdminAPI` powers the admin interface for content editors
69
+ - `createCmsClient` gives you typed methods for custom queries on your frontend
70
+
71
+ They work together through the same CMS component.
20
72
 
21
73
  ## Quick Start
22
74
 
23
- ### 1. Configure Convex Component
75
+ ### 1. Install
76
+
77
+ ```bash
78
+ npm install convex-cms
79
+ ```
80
+
81
+ ### 2. Add the Component
24
82
 
25
83
  ```typescript
26
84
  // convex/convex.config.ts
@@ -32,62 +90,51 @@ app.use(convexCms);
32
90
  export default app;
33
91
  ```
34
92
 
35
- ### 2. Create CMS Client
93
+ ### 3. Choose Your Setup
36
94
 
37
- ```typescript
38
- // convex/cms.ts
39
- import { createCmsClient } from "convex-cms";
40
- import { components } from "./_generated/api";
95
+ **For Admin UI:** Run `npx convex-cms init` then `npx convex-cms admin`
96
+ [Full Admin UI Setup](./docs/guides/admin-ui-setup.md)
41
97
 
42
- export const cms = createCmsClient(components.convexCms, {
43
- defaultLocale: "en",
44
- permissiveMode: true, // For development only
45
- });
46
- ```
98
+ **For Custom Functions:** Create a CMS client and use it in your functions
99
+ [Full Getting Started Guide](./docs/guides/getting-started.md)
47
100
 
48
- ### 3. Use in Your Functions
101
+ ## What's Included
49
102
 
50
- ```typescript
51
- // convex/blog.ts
52
- import { query, mutation } from "./_generated/server";
53
- import { v } from "convex/values";
54
- import { cms } from "./cms";
55
-
56
- export const getPosts = query({
57
- handler: async (ctx) => {
58
- const result = await cms.contentEntries.list(ctx, {
59
- status: "published",
60
- });
61
- return result.items;
62
- },
63
- });
103
+ - **13 field types** — text, richText, media, reference, select, and more
104
+ - **Publishing workflows** — draft → scheduled → published with version history
105
+ - **Media management** — uploads, folders, variants, and metadata
106
+ - **RBAC** 4 built-in roles + custom roles with fine-grained permissions
107
+ - **Multi-locale** content localization with fallback chains
108
+ - **Admin UI** — pre-built React interface (CLI or embeddable)
109
+ - **Agent tools** Zod schemas for AI integration
64
110
 
65
- export const createPost = mutation({
66
- args: { title: v.string(), content: v.string() },
67
- handler: async (ctx, args) => {
68
- return await cms.contentEntries.create(ctx, {
69
- contentTypeId: blogTypeId,
70
- data: args,
71
- });
72
- },
73
- });
74
- ```
111
+ ## Admin UI Modes
75
112
 
76
- ## Documentation
113
+ | Mode | Command | Best For |
114
+ |------|---------|----------|
115
+ | **CLI** | `npx convex-cms admin` | Development |
116
+ | **Embed** | `<CmsAdmin api={api.admin} />` | Production |
77
117
 
78
- - [Getting Started Guide](./docs/guides/getting-started.md)
79
- - [Content Modeling](./docs/guides/content-modeling.md)
80
- - [Media Management](./docs/guides/media.md)
81
- - [Authorization](./docs/guides/authorization.md)
82
- - [API Reference](./docs/api/client-api.md)
118
+ Both modes call the same functions from your `convex/admin.ts`.
83
119
 
84
- ## Admin UI
85
-
86
- Convex CMS includes a ready-to-use admin interface:
120
+ ## Documentation
87
121
 
88
- ```bash
89
- npx convex-cms admin
90
- ```
122
+ | Guide | Description |
123
+ |-------|-------------|
124
+ | [Admin UI Setup](./docs/guides/admin-ui-setup.md) | CLI and embed modes, auth integration |
125
+ | [Getting Started](./docs/guides/getting-started.md) | Programmatic usage with createCmsClient |
126
+ | [Integration Patterns](./docs/guides/integration-patterns.md) | Common setups and when to use each |
127
+ | [Content Modeling](./docs/guides/content-modeling.md) | Content types and field definitions |
128
+ | [Authorization](./docs/guides/authorization.md) | Roles, permissions, and custom auth |
129
+ | [Media Management](./docs/guides/media.md) | Uploads, folders, and variants |
130
+
131
+ | Reference | Description |
132
+ |-----------|-------------|
133
+ | [Client API](./docs/api/client-api.md) | createCmsClient methods |
134
+ | [Admin API](./docs/api/admin-api.md) | defineAdminAPI functions |
135
+ | [Code-First Schema](./docs/api/code-first-schema.md) | TypeScript-first content types |
136
+ | [Field Types](./docs/api/field-types.md) | All 13 field types |
137
+ | [Configuration](./docs/api/configuration.md) | All config options |
91
138
 
92
139
  ## Requirements
93
140
 
@@ -0,0 +1,99 @@
1
+ # Convex CMS Admin UI
2
+
3
+ The Admin UI for Convex CMS, built with TanStack Start and React.
4
+
5
+ ## Getting Started
6
+
7
+ ### Prerequisites
8
+
9
+ - Node.js 18+
10
+ - A Convex account and project
11
+
12
+ ### Installation
13
+
14
+ ```bash
15
+ cd admin
16
+ npm install
17
+ ```
18
+
19
+ ### Development
20
+
21
+ 1. Start the Convex development server:
22
+
23
+ ```bash
24
+ npx convex dev
25
+ ```
26
+
27
+ This will generate the Convex API types and provide a `VITE_CONVEX_URL`.
28
+
29
+ 2. Create a `.env` file with your Convex URL:
30
+
31
+ ```bash
32
+ cp .env.example .env
33
+ # Edit .env with your VITE_CONVEX_URL from step 1
34
+ ```
35
+
36
+ 3. Start the development server:
37
+
38
+ ```bash
39
+ npm run dev:vite
40
+ ```
41
+
42
+ Or run both Convex and Vite together:
43
+
44
+ ```bash
45
+ npm run dev
46
+ ```
47
+
48
+ 4. Open [http://localhost:3000](http://localhost:3000) in your browser.
49
+
50
+ ## Project Structure
51
+
52
+ ```
53
+ admin/
54
+ ├── convex/ # Convex configuration
55
+ │ └── convex.config.ts # CMS component integration
56
+ ├── src/
57
+ │ ├── routes/ # TanStack Router routes
58
+ │ │ ├── __root.tsx # Root layout with Convex provider
59
+ │ │ ├── index.tsx # Dashboard page
60
+ │ │ ├── content.tsx # Content entries list
61
+ │ │ ├── media.tsx # Media library
62
+ │ │ ├── content-types.tsx # Content type management
63
+ │ │ └── settings.tsx # CMS settings
64
+ │ ├── components/ # Reusable React components
65
+ │ ├── lib/ # Utilities and helpers
66
+ │ │ └── convex.ts # Convex client utilities
67
+ │ ├── styles/ # CSS styles
68
+ │ │ └── app.css # Main stylesheet
69
+ │ └── router.tsx # Router configuration
70
+ ├── public/ # Static assets
71
+ ├── vite.config.ts # Vite + TanStack Start configuration
72
+ ├── tsconfig.json # TypeScript configuration
73
+ └── package.json # Dependencies and scripts
74
+ ```
75
+
76
+ ## Available Scripts
77
+
78
+ - `npm run dev` - Start Convex and Vite development servers
79
+ - `npm run dev:vite` - Start only the Vite development server
80
+ - `npm run dev:convex` - Start only the Convex development server
81
+ - `npm run build` - Build for production
82
+ - `npm run preview` - Preview production build
83
+ - `npm run typecheck` - Run TypeScript type checking
84
+
85
+ ## Features
86
+
87
+ - **Dashboard** - Overview of CMS status and quick navigation
88
+ - **Content Management** - Browse and manage content entries
89
+ - **Media Library** - Upload and organize media assets
90
+ - **Content Types** - Define content schemas with custom fields
91
+ - **Settings** - Configure CMS features and preferences
92
+
93
+ ## Technology Stack
94
+
95
+ - [TanStack Start](https://tanstack.com/start) - Full-stack React framework
96
+ - [TanStack Router](https://tanstack.com/router) - Type-safe routing
97
+ - [Convex](https://convex.dev) - Real-time backend platform
98
+ - [React 19](https://react.dev) - UI library
99
+ - [Vite 7](https://vitejs.dev) - Build tool
@@ -0,0 +1,22 @@
1
+ import type { ReactNode } from "react";
2
+ import { Sidebar } from "./Sidebar";
3
+ import { Header } from "./Header";
4
+ import { useAdminConfig } from "~/contexts";
5
+
6
+ interface AdminLayoutProps {
7
+ children: ReactNode;
8
+ }
9
+
10
+ export function AdminLayout({ children }: AdminLayoutProps) {
11
+ const { layout } = useAdminConfig();
12
+
13
+ return (
14
+ <div className="flex min-h-screen bg-background">
15
+ <Sidebar />
16
+ <div className="flex flex-1 flex-col" style={{ marginLeft: layout.sidebarWidth }}>
17
+ <Header />
18
+ <main className="flex-1 overflow-auto p-6">{children}</main>
19
+ </div>
20
+ </div>
21
+ );
22
+ }
@@ -0,0 +1,81 @@
1
+ import { AlertTriangle } from 'lucide-react'
2
+ import { CmsDialog } from '~/components/cmsds/CmsDialog'
3
+ import { CmsButton } from '~/components/cmsds/CmsButton'
4
+
5
+ interface BreakingChangesWarningDialogProps {
6
+ isOpen: boolean
7
+ onClose: () => void
8
+ breakingChanges: string[]
9
+ onForceUpdate: () => void
10
+ onCancel: () => void
11
+ isLoading: boolean
12
+ }
13
+
14
+ export function BreakingChangesWarningDialog({
15
+ isOpen,
16
+ onClose,
17
+ breakingChanges,
18
+ onForceUpdate,
19
+ onCancel,
20
+ isLoading,
21
+ }: BreakingChangesWarningDialogProps) {
22
+ const handleCancel = () => {
23
+ onCancel()
24
+ onClose()
25
+ }
26
+
27
+ return (
28
+ <CmsDialog
29
+ open={isOpen}
30
+ onOpenChange={(open) => !open && !isLoading && handleCancel()}
31
+ title="Breaking Changes Detected"
32
+ size="lg"
33
+ footer={
34
+ <>
35
+ <CmsButton variant="outline" onClick={handleCancel} disabled={isLoading}>
36
+ Cancel
37
+ </CmsButton>
38
+ <CmsButton variant="danger" onClick={onForceUpdate} loading={isLoading}>
39
+ Force Update
40
+ </CmsButton>
41
+ </>
42
+ }
43
+ >
44
+ <div className="space-y-4">
45
+ <div className="flex items-start gap-3 rounded-lg border border-amber-200 bg-amber-50 p-3">
46
+ <AlertTriangle className="mt-0.5 size-5 shrink-0 text-amber-600" />
47
+ <div className="space-y-1">
48
+ <p className="text-sm font-medium text-amber-800">
49
+ These changes may affect existing content
50
+ </p>
51
+ <p className="text-sm text-amber-700">
52
+ The following changes could cause data loss or validation errors for existing entries.
53
+ Review carefully before proceeding.
54
+ </p>
55
+ </div>
56
+ </div>
57
+
58
+ <div className="space-y-2">
59
+ <p className="text-sm font-medium text-foreground">
60
+ {breakingChanges.length} breaking change{breakingChanges.length !== 1 ? 's' : ''} detected:
61
+ </p>
62
+ <ul className="space-y-2">
63
+ {breakingChanges.map((change, index) => (
64
+ <li
65
+ key={index}
66
+ className="flex items-start gap-2 rounded-md border bg-muted/30 px-3 py-2 text-sm"
67
+ >
68
+ <span className="mt-0.5 size-1.5 shrink-0 rounded-full bg-amber-500" />
69
+ <span className="text-muted-foreground">{change}</span>
70
+ </li>
71
+ ))}
72
+ </ul>
73
+ </div>
74
+
75
+ <p className="text-xs text-muted-foreground">
76
+ Click "Force Update" to apply these changes anyway, or "Cancel" to go back and modify your changes.
77
+ </p>
78
+ </div>
79
+ </CmsDialog>
80
+ )
81
+ }
@@ -0,0 +1,190 @@
1
+ import { useState, useCallback } from 'react'
2
+ import { useMutation } from 'convex/react'
3
+ import { api } from '../../convex/_generated/api'
4
+ import { BulkOperationModal } from './BulkOperationModal'
5
+ import { CmsButton } from '~/components/cmsds/CmsButton'
6
+ import { Badge } from '~/components/ui/badge'
7
+ import { X } from 'lucide-react'
8
+
9
+ type BulkAction = 'publish' | 'unpublish' | 'delete' | 'archive'
10
+
11
+ interface BulkActionBarProps {
12
+ selectedIds: string[]
13
+ onClearSelection: () => void
14
+ onOperationComplete?: () => void
15
+ }
16
+
17
+ export function BulkActionBar({
18
+ selectedIds,
19
+ onClearSelection,
20
+ onOperationComplete,
21
+ }: BulkActionBarProps) {
22
+ const [activeAction, setActiveAction] = useState<BulkAction | null>(null)
23
+ const [isProcessing, setIsProcessing] = useState(false)
24
+ const [result, setResult] = useState<{
25
+ succeeded: number
26
+ failed: number
27
+ errors?: string[]
28
+ } | null>(null)
29
+
30
+ const bulkPublish = useMutation(api.bulkOperations.bulkPublish)
31
+ const bulkUnpublish = useMutation(api.bulkOperations.bulkUnpublish)
32
+ const bulkDelete = useMutation(api.bulkOperations.bulkDelete)
33
+ const bulkUpdate = useMutation(api.bulkOperations.bulkUpdate)
34
+
35
+ const handleAction = useCallback((action: BulkAction) => {
36
+ setActiveAction(action)
37
+ setResult(null)
38
+ }, [])
39
+
40
+ const handleConfirm = useCallback(async () => {
41
+ if (!activeAction || selectedIds.length === 0) return
42
+
43
+ setIsProcessing(true)
44
+ setResult(null)
45
+
46
+ try {
47
+ let response: {
48
+ succeeded: number
49
+ failed: number
50
+ errors?: { id: string; error: string }[]
51
+ }
52
+
53
+ switch (activeAction) {
54
+ case 'publish':
55
+ response = await bulkPublish({
56
+ ids: selectedIds,
57
+ changeDescription: 'Bulk published from admin',
58
+ })
59
+ break
60
+ case 'unpublish':
61
+ response = await bulkUnpublish({
62
+ ids: selectedIds,
63
+ })
64
+ break
65
+ case 'delete':
66
+ response = await bulkDelete({
67
+ ids: selectedIds,
68
+ hardDelete: false,
69
+ })
70
+ break
71
+ case 'archive':
72
+ response = await bulkUpdate({
73
+ ids: selectedIds,
74
+ status: 'archived',
75
+ })
76
+ break
77
+ default:
78
+ throw new Error(`Unknown action: ${activeAction}`)
79
+ }
80
+
81
+ setResult({
82
+ succeeded: response.succeeded,
83
+ failed: response.failed,
84
+ errors: response.errors?.map((e) => `${e.id}: ${e.error}`),
85
+ })
86
+
87
+ if (response.failed === 0) {
88
+ setTimeout(() => {
89
+ setActiveAction(null)
90
+ onClearSelection()
91
+ onOperationComplete?.()
92
+ }, 1500)
93
+ }
94
+ } catch (error) {
95
+ const message = error instanceof Error ? error.message : 'Operation failed'
96
+ setResult({
97
+ succeeded: 0,
98
+ failed: selectedIds.length,
99
+ errors: [message],
100
+ })
101
+ } finally {
102
+ setIsProcessing(false)
103
+ }
104
+ }, [
105
+ activeAction,
106
+ selectedIds,
107
+ bulkPublish,
108
+ bulkUnpublish,
109
+ bulkDelete,
110
+ bulkUpdate,
111
+ onClearSelection,
112
+ onOperationComplete,
113
+ ])
114
+
115
+ const handleCancel = useCallback(() => {
116
+ setActiveAction(null)
117
+ setResult(null)
118
+ }, [])
119
+
120
+ if (selectedIds.length === 0) {
121
+ return null
122
+ }
123
+
124
+ return (
125
+ <>
126
+ <div className="fixed inset-x-0 bottom-0 z-50 border-t bg-background/95 px-6 py-3 shadow-lg backdrop-blur supports-[backdrop-filter]:bg-background/80">
127
+ <div className="mx-auto flex max-w-7xl items-center justify-between">
128
+ <div className="flex items-center gap-3">
129
+ <Badge variant="secondary" className="text-sm font-semibold">
130
+ {selectedIds.length}
131
+ </Badge>
132
+ <span className="text-sm text-muted-foreground">
133
+ {selectedIds.length === 1 ? 'item' : 'items'} selected
134
+ </span>
135
+ <button
136
+ type="button"
137
+ onClick={onClearSelection}
138
+ className="flex items-center gap-1 text-sm text-muted-foreground transition-colors hover:text-foreground"
139
+ >
140
+ <X className="size-3" />
141
+ Clear
142
+ </button>
143
+ </div>
144
+
145
+ <div className="flex items-center gap-2">
146
+ <CmsButton
147
+ variant="success"
148
+ size="sm"
149
+ onClick={() => handleAction('publish')}
150
+ >
151
+ Publish
152
+ </CmsButton>
153
+ <CmsButton
154
+ variant="warning"
155
+ size="sm"
156
+ onClick={() => handleAction('unpublish')}
157
+ >
158
+ Unpublish
159
+ </CmsButton>
160
+ <CmsButton
161
+ variant="secondary"
162
+ size="sm"
163
+ onClick={() => handleAction('archive')}
164
+ >
165
+ Archive
166
+ </CmsButton>
167
+ <CmsButton
168
+ variant="danger"
169
+ size="sm"
170
+ onClick={() => handleAction('delete')}
171
+ >
172
+ Delete
173
+ </CmsButton>
174
+ </div>
175
+ </div>
176
+ </div>
177
+
178
+ {activeAction && (
179
+ <BulkOperationModal
180
+ action={activeAction}
181
+ count={selectedIds.length}
182
+ isProcessing={isProcessing}
183
+ result={result}
184
+ onConfirm={handleConfirm}
185
+ onCancel={handleCancel}
186
+ />
187
+ )}
188
+ </>
189
+ )
190
+ }