betterstart-cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/README.md +5 -0
  2. package/dist/assets/adapters/next/integrations/mailchimp/actions/mailchimp.ts +38 -0
  3. package/dist/assets/adapters/next/integrations/mailchimp/integration.ts +33 -0
  4. package/dist/assets/adapters/next/integrations/r2/actions/r2.ts +77 -0
  5. package/dist/assets/adapters/next/integrations/r2/integration.ts +39 -0
  6. package/dist/assets/adapters/next/integrations/resend/actions/resend.ts +138 -0
  7. package/dist/assets/adapters/next/integrations/resend/integration.ts +36 -0
  8. package/dist/assets/adapters/next/plugins/blog/plugin.ts +17 -0
  9. package/dist/assets/adapters/next/plugins/blog/schemas/posts.json +169 -0
  10. package/dist/assets/adapters/next/templates/init/admin-globals.css +677 -0
  11. package/dist/assets/adapters/next/templates/init/api/auth-route.ts +3 -0
  12. package/dist/assets/adapters/next/templates/init/api/upload-route.ts +132 -0
  13. package/dist/assets/adapters/next/templates/init/components/layouts/admin-header.tsx +32 -0
  14. package/dist/assets/adapters/next/templates/init/components/layouts/admin-nav-link.tsx +23 -0
  15. package/dist/assets/adapters/next/templates/init/components/layouts/admin-providers.tsx +33 -0
  16. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-branding-rsc.tsx +8 -0
  17. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-branding-skeleton.tsx +10 -0
  18. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-nav-link-skeleton.tsx +11 -0
  19. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-nav-link.tsx +12 -0
  20. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu-skeleton.tsx +15 -0
  21. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu.tsx +90 -0
  22. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar.tsx +78 -0
  23. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sign-out.tsx +44 -0
  24. package/dist/assets/adapters/next/templates/init/components/layouts/content-skeleton.tsx +44 -0
  25. package/dist/assets/adapters/next/templates/init/components/layouts/sidebar-branding.tsx +41 -0
  26. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table-pagination.tsx +139 -0
  27. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx +236 -0
  28. package/dist/assets/adapters/next/templates/init/components/shared/delete-dialog.tsx +67 -0
  29. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/copyable-code-block.tsx +104 -0
  30. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-code-mirror.tsx +68 -0
  31. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-types.ts +75 -0
  32. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/lifecycle-hooks-tab.tsx +111 -0
  33. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/plain-code-fallback.tsx +11 -0
  34. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/snippets-tab.tsx +125 -0
  35. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode-integrate.tsx +108 -0
  36. package/dist/assets/adapters/next/templates/init/components/shared/entity-filters-bar.tsx +184 -0
  37. package/dist/assets/adapters/next/templates/init/components/shared/entity-metadata.tsx +93 -0
  38. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-version-item.tsx +55 -0
  39. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-version-restore-dialog.tsx +80 -0
  40. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-button.tsx +74 -0
  41. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-current-row.tsx +48 -0
  42. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-drawer.tsx +79 -0
  43. package/dist/assets/adapters/next/templates/init/components/shared/media/edit-media-dialog-content.tsx +222 -0
  44. package/dist/assets/adapters/next/templates/init/components/shared/media/edit-media-dialog.tsx +56 -0
  45. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-dialog.tsx +83 -0
  46. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-drawer.tsx +148 -0
  47. package/dist/assets/adapters/next/templates/init/components/shared/media/media-empty-state.tsx +45 -0
  48. package/dist/assets/adapters/next/templates/init/components/shared/media/media-filters-bar.tsx +129 -0
  49. package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx +182 -0
  50. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-item.tsx +56 -0
  51. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-pagination.tsx +114 -0
  52. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid.tsx +44 -0
  53. package/dist/assets/adapters/next/templates/init/components/shared/media/media-preview.tsx +69 -0
  54. package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx +139 -0
  55. package/dist/assets/adapters/next/templates/init/components/shared/page-header.tsx +46 -0
  56. package/dist/assets/adapters/next/templates/init/components/shared/search-input.tsx +88 -0
  57. package/dist/assets/adapters/next/templates/init/components/shared/sort-indicator.tsx +24 -0
  58. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-dialog.tsx +242 -0
  59. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-drag-overlay-item.tsx +15 -0
  60. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-item.tsx +32 -0
  61. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-types.ts +9 -0
  62. package/dist/assets/adapters/next/templates/init/data/navigation.ts +43 -0
  63. package/dist/assets/adapters/next/templates/init/drizzle.config.ts +36 -0
  64. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-blockquote.ts +251 -0
  65. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-code-block.ts +258 -0
  66. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-color-highlight.ts +347 -0
  67. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-media-insertion.ts +59 -0
  68. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-mobile-toolbar.ts +17 -0
  69. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-slash-menu.ts +116 -0
  70. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-source-mode.tsx +638 -0
  71. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-table-add-controls.ts +174 -0
  72. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor.ts +288 -0
  73. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-heading-dropdown-menu.ts +127 -0
  74. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-heading.ts +269 -0
  75. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-is-breakpoint.ts +32 -0
  76. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-link-popover.ts +278 -0
  77. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-list-dropdown-menu.ts +199 -0
  78. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-list.ts +290 -0
  79. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-mark.ts +199 -0
  80. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-menu-navigation.ts +221 -0
  81. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-tiptap-editor.ts +46 -0
  82. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-undo-redo.ts +169 -0
  83. package/dist/assets/adapters/next/templates/init/hooks/use-admin-theme.tsx +74 -0
  84. package/dist/assets/adapters/next/templates/init/hooks/use-copy-to-clipboard.ts +48 -0
  85. package/dist/assets/adapters/next/templates/init/hooks/use-dev-mode-integration.ts +43 -0
  86. package/dist/assets/adapters/next/templates/init/hooks/use-entity-versions.ts +32 -0
  87. package/dist/assets/adapters/next/templates/init/hooks/use-failed-image-url.ts +21 -0
  88. package/dist/assets/adapters/next/templates/init/hooks/use-local-storage.ts +46 -0
  89. package/dist/assets/adapters/next/templates/init/hooks/use-media-filters-bar.ts +72 -0
  90. package/dist/assets/adapters/next/templates/init/hooks/use-media.ts +102 -0
  91. package/dist/assets/adapters/next/templates/init/hooks/use-mobile.ts +19 -0
  92. package/dist/assets/adapters/next/templates/init/hooks/use-page-boundary-blur-visibility.ts +59 -0
  93. package/dist/assets/adapters/next/templates/init/hooks/use-page-scroll-threshold.ts +27 -0
  94. package/dist/assets/adapters/next/templates/init/hooks/use-table-utils.ts +315 -0
  95. package/dist/assets/adapters/next/templates/init/hooks/use-upload.ts +321 -0
  96. package/dist/assets/adapters/next/templates/init/hooks/use-users.ts +12 -0
  97. package/dist/assets/adapters/next/templates/init/lib/actions/auth/auth.ts +58 -0
  98. package/dist/assets/adapters/next/templates/init/lib/actions/auth/client.ts +12 -0
  99. package/dist/assets/adapters/next/templates/init/lib/actions/auth/middleware.ts +46 -0
  100. package/dist/assets/adapters/next/templates/init/lib/actions/email/form-delivery.ts +72 -0
  101. package/dist/assets/adapters/next/templates/init/lib/actions/email/index.ts +4 -0
  102. package/dist/assets/adapters/next/templates/init/lib/actions/email/is-email-delivery-configured.ts +5 -0
  103. package/dist/assets/adapters/next/templates/init/lib/actions/email/none.ts +24 -0
  104. package/dist/assets/adapters/next/templates/init/lib/actions/email/provider.ts +6 -0
  105. package/dist/assets/adapters/next/templates/init/lib/actions/email/send-email.ts +6 -0
  106. package/dist/assets/adapters/next/templates/init/lib/actions/email/send-password-reset-email.ts +10 -0
  107. package/dist/assets/adapters/next/templates/init/lib/actions/email/types.ts +25 -0
  108. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/get-entity-versions.ts +48 -0
  109. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/index.ts +10 -0
  110. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/internal-create-entity-version.ts +43 -0
  111. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/internal-delete-entity-versions.ts +19 -0
  112. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/types.ts +26 -0
  113. package/dist/assets/adapters/next/templates/init/lib/actions/forms/get-all-form-settings.ts +21 -0
  114. package/dist/assets/adapters/next/templates/init/lib/actions/forms/get-form-settings.ts +27 -0
  115. package/dist/assets/adapters/next/templates/init/lib/actions/forms/index.ts +9 -0
  116. package/dist/assets/adapters/next/templates/init/lib/actions/forms/test-form-webhook.ts +40 -0
  117. package/dist/assets/adapters/next/templates/init/lib/actions/forms/types.ts +26 -0
  118. package/dist/assets/adapters/next/templates/init/lib/actions/forms/upsert-form-settings.ts +40 -0
  119. package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +39 -0
  120. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media-bulk.ts +29 -0
  121. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media.ts +22 -0
  122. package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media-by-id.ts +18 -0
  123. package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media-by-ids.ts +25 -0
  124. package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media.ts +71 -0
  125. package/dist/assets/adapters/next/templates/init/lib/actions/media/index.ts +14 -0
  126. package/dist/assets/adapters/next/templates/init/lib/actions/media/types.ts +31 -0
  127. package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +35 -0
  128. package/dist/assets/adapters/next/templates/init/lib/actions/profile/index.ts +4 -0
  129. package/dist/assets/adapters/next/templates/init/lib/actions/profile/invalidate-users-cache.ts +14 -0
  130. package/dist/assets/adapters/next/templates/init/lib/actions/profile/is-email-configured.ts +7 -0
  131. package/dist/assets/adapters/next/templates/init/lib/actions/profile/types.ts +4 -0
  132. package/dist/assets/adapters/next/templates/init/lib/actions/profile/update-email.ts +57 -0
  133. package/dist/assets/adapters/next/templates/init/lib/actions/storage/index.ts +2 -0
  134. package/dist/assets/adapters/next/templates/init/lib/actions/storage/local.ts +31 -0
  135. package/dist/assets/adapters/next/templates/init/lib/actions/storage/provider.ts +6 -0
  136. package/dist/assets/adapters/next/templates/init/lib/actions/storage/save-upload.ts +11 -0
  137. package/dist/assets/adapters/next/templates/init/lib/actions/storage/types.ts +18 -0
  138. package/dist/assets/adapters/next/templates/init/lib/actions/upload/index.ts +9 -0
  139. package/dist/assets/adapters/next/templates/init/lib/actions/upload/types.ts +17 -0
  140. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-file.ts +11 -0
  141. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-files.ts +92 -0
  142. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-image-from-url.ts +22 -0
  143. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-media-from-url.ts +133 -0
  144. package/dist/assets/adapters/next/templates/init/lib/actions/users/create-user.ts +55 -0
  145. package/dist/assets/adapters/next/templates/init/lib/actions/users/delete-user.ts +24 -0
  146. package/dist/assets/adapters/next/templates/init/lib/actions/users/get-users.ts +49 -0
  147. package/dist/assets/adapters/next/templates/init/lib/actions/users/index.ts +12 -0
  148. package/dist/assets/adapters/next/templates/init/lib/actions/users/types.ts +43 -0
  149. package/dist/assets/adapters/next/templates/init/lib/actions/users/update-user-role.ts +28 -0
  150. package/dist/assets/adapters/next/templates/init/lib/db/client.ts +13 -0
  151. package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +160 -0
  152. package/dist/assets/adapters/next/templates/init/lib/db/schema.ts +1 -0
  153. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/index.ts +19 -0
  154. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/register.local.ts +2 -0
  155. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/register.ts +9 -0
  156. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/registry.ts +55 -0
  157. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +51 -0
  158. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/types.ts +39 -0
  159. package/dist/assets/adapters/next/templates/init/pages/account-layout.tsx +11 -0
  160. package/dist/assets/adapters/next/templates/init/pages/account-shell-rsc.tsx +30 -0
  161. package/dist/assets/adapters/next/templates/init/pages/admin-layout.tsx +24 -0
  162. package/dist/assets/adapters/next/templates/init/pages/auth-gate-rsc.tsx +6 -0
  163. package/dist/assets/adapters/next/templates/init/pages/authenticated-layout.tsx +18 -0
  164. package/dist/assets/adapters/next/templates/init/pages/dashboard-page.tsx +121 -0
  165. package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +124 -0
  166. package/dist/assets/adapters/next/templates/init/pages/forgot-password-page-skeleton.tsx +24 -0
  167. package/dist/assets/adapters/next/templates/init/pages/forgot-password-page.tsx +21 -0
  168. package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +131 -0
  169. package/dist/assets/adapters/next/templates/init/pages/login-page-rsc.tsx +14 -0
  170. package/dist/assets/adapters/next/templates/init/pages/login-page-skeleton.tsx +26 -0
  171. package/dist/assets/adapters/next/templates/init/pages/login-page.tsx +21 -0
  172. package/dist/assets/adapters/next/templates/init/pages/media/media-page-content.tsx +273 -0
  173. package/dist/assets/adapters/next/templates/init/pages/media/media-page-skeleton.tsx +7 -0
  174. package/dist/assets/adapters/next/templates/init/pages/media/media-page.tsx +11 -0
  175. package/dist/assets/adapters/next/templates/init/pages/minimal-account-shell.tsx +25 -0
  176. package/dist/assets/adapters/next/templates/init/pages/profile/profile-form.tsx +281 -0
  177. package/dist/assets/adapters/next/templates/init/pages/profile/profile-page.tsx +31 -0
  178. package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +161 -0
  179. package/dist/assets/adapters/next/templates/init/pages/reset-password-page-skeleton.tsx +26 -0
  180. package/dist/assets/adapters/next/templates/init/pages/reset-password-page.tsx +21 -0
  181. package/dist/assets/adapters/next/templates/init/pages/users/columns.tsx +170 -0
  182. package/dist/assets/adapters/next/templates/init/pages/users/create-user-dialog.tsx +221 -0
  183. package/dist/assets/adapters/next/templates/init/pages/users/delete-user-dialog.tsx +172 -0
  184. package/dist/assets/adapters/next/templates/init/pages/users/edit-role-dialog.tsx +91 -0
  185. package/dist/assets/adapters/next/templates/init/pages/users/users-page-content.tsx +25 -0
  186. package/dist/assets/adapters/next/templates/init/pages/users/users-page-skeleton.tsx +7 -0
  187. package/dist/assets/adapters/next/templates/init/pages/users/users-page.tsx +11 -0
  188. package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +221 -0
  189. package/dist/assets/adapters/next/templates/init/types/auth.ts +71 -0
  190. package/dist/assets/adapters/next/templates/init/types/index.ts +108 -0
  191. package/dist/assets/adapters/next/templates/init/types/navigation.ts +11 -0
  192. package/dist/assets/adapters/next/templates/init/types/table-meta.ts +14 -0
  193. package/dist/assets/adapters/next/templates/init/utils/auth/roles.ts +17 -0
  194. package/dist/assets/adapters/next/templates/init/utils/date/date.ts +90 -0
  195. package/dist/assets/adapters/next/templates/init/utils/dev-mode/code-block-height.ts +9 -0
  196. package/dist/assets/adapters/next/templates/init/utils/editor/content-editor-rich-extensions.ts +824 -0
  197. package/dist/assets/adapters/next/templates/init/utils/editor/content-editor.ts +316 -0
  198. package/dist/assets/adapters/next/templates/init/utils/editor/editor-view.ts +19 -0
  199. package/dist/assets/adapters/next/templates/init/utils/editor/markdown.ts +542 -0
  200. package/dist/assets/adapters/next/templates/init/utils/editor/node-attrs.ts +25 -0
  201. package/dist/assets/adapters/next/templates/init/utils/editor/slash-commands.ts +148 -0
  202. package/dist/assets/adapters/next/templates/init/utils/editor/source-media.ts +11 -0
  203. package/dist/assets/adapters/next/templates/init/utils/editor/table-add-controls.ts +91 -0
  204. package/dist/assets/adapters/next/templates/init/utils/editor/table-bubble.ts +172 -0
  205. package/dist/assets/adapters/next/templates/init/utils/editor/table-input.ts +5 -0
  206. package/dist/assets/adapters/next/templates/init/utils/editor/task-item.ts +19 -0
  207. package/dist/assets/adapters/next/templates/init/utils/editor/tiptap.ts +991 -0
  208. package/dist/assets/adapters/next/templates/init/utils/email/form-delivery.ts +104 -0
  209. package/dist/assets/adapters/next/templates/init/utils/media/fallback.ts +37 -0
  210. package/dist/assets/adapters/next/templates/init/utils/media/media.ts +91 -0
  211. package/dist/assets/adapters/next/templates/init/utils/media/query.ts +96 -0
  212. package/dist/assets/adapters/next/templates/init/utils/navigation/order.ts +6 -0
  213. package/dist/assets/adapters/next/templates/init/utils/navigation/sidebar.ts +26 -0
  214. package/dist/assets/adapters/next/templates/init/utils/page/boundary.ts +32 -0
  215. package/dist/assets/adapters/next/templates/init/utils/seo/seo.ts +90 -0
  216. package/dist/assets/adapters/next/templates/init/utils/shared/cn.ts +6 -0
  217. package/dist/assets/adapters/next/templates/init/utils/storage/local.ts +9 -0
  218. package/dist/assets/adapters/next/templates/init/utils/table/table.ts +10 -0
  219. package/dist/assets/adapters/next/templates/init/utils/text/text.ts +4 -0
  220. package/dist/assets/adapters/next/templates/init/utils/theme/system.ts +6 -0
  221. package/dist/assets/adapters/next/templates/init/utils/upload/remote.ts +55 -0
  222. package/dist/assets/adapters/next/templates/init/utils/upload/upload.ts +26 -0
  223. package/dist/assets/adapters/next/templates/init/utils/user/user.ts +11 -0
  224. package/dist/assets/adapters/next/templates/init/utils/validation/validation.ts +114 -0
  225. package/dist/assets/adapters/next/templates/init/utils/webhook/webhook.ts +28 -0
  226. package/dist/assets/shared-assets/react-admin/custom/content-editor/editor-toolbar.tsx +25 -0
  227. package/dist/assets/shared-assets/react-admin/custom/content-editor/horizontal-rule-button.tsx +22 -0
  228. package/dist/assets/shared-assets/react-admin/custom/content-editor/index.tsx +142 -0
  229. package/dist/assets/shared-assets/react-admin/custom/content-editor/main-toolbar-content.tsx +118 -0
  230. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-bubble-menu.tsx +80 -0
  231. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-button.tsx +22 -0
  232. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-editor-controls.tsx +117 -0
  233. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-popover-button.tsx +59 -0
  234. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-popover.tsx +6 -0
  235. package/dist/assets/shared-assets/react-admin/custom/content-editor/media-gallery-block.tsx +31 -0
  236. package/dist/assets/shared-assets/react-admin/custom/content-editor/mobile-toolbar-content.tsx +56 -0
  237. package/dist/assets/shared-assets/react-admin/custom/content-editor/mode-toggle-button.tsx +29 -0
  238. package/dist/assets/shared-assets/react-admin/custom/content-editor/remove-table-part-icon.tsx +17 -0
  239. package/dist/assets/shared-assets/react-admin/custom/content-editor/selection-bubble-menu.tsx +105 -0
  240. package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +65 -0
  241. package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode-dropdown-button.tsx +52 -0
  242. package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +360 -0
  243. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-add-controls.tsx +46 -0
  244. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-bubble-menu.tsx +290 -0
  245. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-button.tsx +116 -0
  246. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-extension/node-background-extension.ts +138 -0
  247. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/horizontal-rule-node/horizontal-rule-node-extension.ts +10 -0
  248. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/media-gallery-placeholder-node/index.tsx +1 -0
  249. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/media-gallery-placeholder-node/media-gallery-placeholder-node-extension.ts +117 -0
  250. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/media-gallery-placeholder-node/media-gallery-placeholder-node.tsx +63 -0
  251. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/index.tsx +1 -0
  252. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node-extension.ts +11 -0
  253. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node.tsx +168 -0
  254. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/task-item-node/task-item-node-extension.tsx +142 -0
  255. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/blockquote-button/blockquote-button.tsx +114 -0
  256. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/blockquote-button/index.tsx +1 -0
  257. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/code-block-button/code-block-button.tsx +112 -0
  258. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/code-block-button/index.tsx +1 -0
  259. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-button/color-highlight-button.tsx +185 -0
  260. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-button/index.tsx +1 -0
  261. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-button.tsx +40 -0
  262. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-content.tsx +130 -0
  263. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +98 -0
  264. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/highlight-color-button.tsx +75 -0
  265. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/highlight-colors.ts +24 -0
  266. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/index.tsx +1 -0
  267. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/source-color-highlight-popover.tsx +65 -0
  268. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/control-options.ts +27 -0
  269. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu-item.tsx +35 -0
  270. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +119 -0
  271. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/index.tsx +1 -0
  272. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/index.tsx +1 -0
  273. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-button.tsx +39 -0
  274. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-content.tsx +13 -0
  275. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-control-popover.tsx +90 -0
  276. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-main.tsx +96 -0
  277. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-popover.tsx +121 -0
  278. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/index.tsx +1 -0
  279. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu-item.tsx +44 -0
  280. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +115 -0
  281. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/mark-button/index.tsx +1 -0
  282. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/mark-button/mark-button.tsx +117 -0
  283. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/undo-redo-button/index.tsx +1 -0
  284. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/undo-redo-button/undo-redo-button.tsx +115 -0
  285. package/dist/assets/shared-assets/react-admin/custom/date-picker.tsx +70 -0
  286. package/dist/assets/shared-assets/react-admin/custom/date-range-picker.tsx +216 -0
  287. package/dist/assets/shared-assets/react-admin/custom/dynamic-list-field.tsx +111 -0
  288. package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +124 -0
  289. package/dist/assets/shared-assets/react-admin/custom/gallery-thumbnail.tsx +39 -0
  290. package/dist/assets/shared-assets/react-admin/custom/icon-picker.tsx +377 -0
  291. package/dist/assets/shared-assets/react-admin/custom/icons-column-skeleton.tsx +16 -0
  292. package/dist/assets/shared-assets/react-admin/custom/icons-data.ts +8 -0
  293. package/dist/assets/shared-assets/react-admin/custom/logo.tsx +115 -0
  294. package/dist/assets/shared-assets/react-admin/custom/media-gallery-field.tsx +182 -0
  295. package/dist/assets/shared-assets/react-admin/custom/page-skeleton.tsx +11 -0
  296. package/dist/assets/shared-assets/react-admin/custom/placeholder-card.tsx +34 -0
  297. package/dist/assets/shared-assets/react-admin/custom/placeholder.tsx +25 -0
  298. package/dist/assets/shared-assets/react-admin/custom/progressive-blur.tsx +62 -0
  299. package/dist/assets/shared-assets/react-admin/custom/sortable-gallery-item.tsx +68 -0
  300. package/dist/assets/shared-assets/react-admin/custom/upload-dropzone.tsx +107 -0
  301. package/dist/assets/shared-assets/react-admin/dependencies.ts +73 -0
  302. package/dist/assets/shared-assets/react-admin/schema.json +1670 -0
  303. package/dist/assets/shared-assets/react-admin/ui/accordion.tsx +86 -0
  304. package/dist/assets/shared-assets/react-admin/ui/alert-dialog.tsx +178 -0
  305. package/dist/assets/shared-assets/react-admin/ui/alert.tsx +72 -0
  306. package/dist/assets/shared-assets/react-admin/ui/aspect-ratio.tsx +9 -0
  307. package/dist/assets/shared-assets/react-admin/ui/avatar.tsx +95 -0
  308. package/dist/assets/shared-assets/react-admin/ui/badge.tsx +48 -0
  309. package/dist/assets/shared-assets/react-admin/ui/breadcrumb.tsx +99 -0
  310. package/dist/assets/shared-assets/react-admin/ui/button-group.tsx +76 -0
  311. package/dist/assets/shared-assets/react-admin/ui/button.tsx +66 -0
  312. package/dist/assets/shared-assets/react-admin/ui/calendar.tsx +184 -0
  313. package/dist/assets/shared-assets/react-admin/ui/card.tsx +94 -0
  314. package/dist/assets/shared-assets/react-admin/ui/carousel.tsx +239 -0
  315. package/dist/assets/shared-assets/react-admin/ui/chart.tsx +336 -0
  316. package/dist/assets/shared-assets/react-admin/ui/checkbox.tsx +28 -0
  317. package/dist/assets/shared-assets/react-admin/ui/collapsible.tsx +21 -0
  318. package/dist/assets/shared-assets/react-admin/ui/combobox.tsx +272 -0
  319. package/dist/assets/shared-assets/react-admin/ui/command.tsx +180 -0
  320. package/dist/assets/shared-assets/react-admin/ui/context-menu.tsx +243 -0
  321. package/dist/assets/shared-assets/react-admin/ui/dialog.tsx +141 -0
  322. package/dist/assets/shared-assets/react-admin/ui/direction.tsx +20 -0
  323. package/dist/assets/shared-assets/react-admin/ui/drawer.tsx +119 -0
  324. package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +253 -0
  325. package/dist/assets/shared-assets/react-admin/ui/empty.tsx +93 -0
  326. package/dist/assets/shared-assets/react-admin/ui/field.tsx +234 -0
  327. package/dist/assets/shared-assets/react-admin/ui/form.tsx +172 -0
  328. package/dist/assets/shared-assets/react-admin/ui/hover-card.tsx +37 -0
  329. package/dist/assets/shared-assets/react-admin/ui/input-group.tsx +134 -0
  330. package/dist/assets/shared-assets/react-admin/ui/input-otp.tsx +85 -0
  331. package/dist/assets/shared-assets/react-admin/ui/input.tsx +18 -0
  332. package/dist/assets/shared-assets/react-admin/ui/item.tsx +180 -0
  333. package/dist/assets/shared-assets/react-admin/ui/kbd.tsx +26 -0
  334. package/dist/assets/shared-assets/react-admin/ui/label.tsx +20 -0
  335. package/dist/assets/shared-assets/react-admin/ui/menubar.tsx +259 -0
  336. package/dist/assets/shared-assets/react-admin/ui/native-select.tsx +54 -0
  337. package/dist/assets/shared-assets/react-admin/ui/navigation-menu.tsx +159 -0
  338. package/dist/assets/shared-assets/react-admin/ui/pagination.tsx +111 -0
  339. package/dist/assets/shared-assets/react-admin/ui/popover.tsx +75 -0
  340. package/dist/assets/shared-assets/react-admin/ui/progress.tsx +30 -0
  341. package/dist/assets/shared-assets/react-admin/ui/radio-group.tsx +43 -0
  342. package/dist/assets/shared-assets/react-admin/ui/resizable.tsx +41 -0
  343. package/dist/assets/shared-assets/react-admin/ui/scroll-area.tsx +54 -0
  344. package/dist/assets/shared-assets/react-admin/ui/select.tsx +183 -0
  345. package/dist/assets/shared-assets/react-admin/ui/separator.tsx +27 -0
  346. package/dist/assets/shared-assets/react-admin/ui/sheet.tsx +129 -0
  347. package/dist/assets/shared-assets/react-admin/ui/sidebar.tsx +688 -0
  348. package/dist/assets/shared-assets/react-admin/ui/skeleton.tsx +13 -0
  349. package/dist/assets/shared-assets/react-admin/ui/slider.tsx +53 -0
  350. package/dist/assets/shared-assets/react-admin/ui/sonner.tsx +45 -0
  351. package/dist/assets/shared-assets/react-admin/ui/spinner.tsx +15 -0
  352. package/dist/assets/shared-assets/react-admin/ui/switch.tsx +32 -0
  353. package/dist/assets/shared-assets/react-admin/ui/table.tsx +101 -0
  354. package/dist/assets/shared-assets/react-admin/ui/tabs.tsx +79 -0
  355. package/dist/assets/shared-assets/react-admin/ui/textarea.tsx +17 -0
  356. package/dist/assets/shared-assets/react-admin/ui/toggle-group.tsx +85 -0
  357. package/dist/assets/shared-assets/react-admin/ui/toggle.tsx +45 -0
  358. package/dist/assets/shared-assets/react-admin/ui/tooltip.tsx +51 -0
  359. package/dist/chunk-MUZQCVQA.js +306 -0
  360. package/dist/chunk-MUZQCVQA.js.map +1 -0
  361. package/dist/cli.d.ts +2 -0
  362. package/dist/cli.js +23437 -0
  363. package/dist/cli.js.map +1 -0
  364. package/dist/index.d.ts +90 -0
  365. package/dist/index.js +8 -0
  366. package/dist/index.js.map +1 -0
  367. package/dist/template-reader-YKWE2C7O.js +13 -0
  368. package/dist/template-reader-YKWE2C7O.js.map +1 -0
  369. package/package.json +74 -0
@@ -0,0 +1,221 @@
1
+ 'use client'
2
+
3
+ import type { Editor } from '@tiptap/react'
4
+ import { useCallback, useEffect, useState } from 'react'
5
+
6
+ type Orientation = 'horizontal' | 'vertical' | 'both'
7
+ type SelectedIndexUpdater = number | ((currentIndex: number) => number)
8
+
9
+ interface SelectionState {
10
+ autoSelectFirstItem: boolean
11
+ query: string | undefined
12
+ selectedIndex: number
13
+ }
14
+
15
+ interface MenuNavigationOptions<T> {
16
+ /**
17
+ * The Tiptap editor instance, if using with a Tiptap editor.
18
+ */
19
+ editor?: Editor | null
20
+ /**
21
+ * Reference to the container element for handling keyboard events.
22
+ */
23
+ containerRef?: React.RefObject<HTMLElement | null>
24
+ /**
25
+ * Search query that affects the selected item.
26
+ */
27
+ query?: string
28
+ /**
29
+ * Array of items to navigate through.
30
+ */
31
+ items: T[]
32
+ /**
33
+ * Callback fired when an item is selected.
34
+ */
35
+ onSelect?: (item: T) => void
36
+ /**
37
+ * Callback fired when the menu should close.
38
+ */
39
+ onClose?: () => void
40
+ /**
41
+ * The navigation orientation of the menu.
42
+ * @default "vertical"
43
+ */
44
+ orientation?: Orientation
45
+ /**
46
+ * Whether to automatically select the first item when the menu opens.
47
+ * @default true
48
+ */
49
+ autoSelectFirstItem?: boolean
50
+ }
51
+
52
+ /**
53
+ * Hook that implements keyboard navigation for dropdown menus and command palettes.
54
+ *
55
+ * Handles arrow keys, tab, home/end, enter for selection, and escape to close.
56
+ * Works with both Tiptap editors and regular DOM elements.
57
+ *
58
+ * @param options - Configuration options for the menu navigation
59
+ * @returns Object containing the selected index and a setter function
60
+ */
61
+ export function useMenuNavigation<T>({
62
+ editor,
63
+ containerRef,
64
+ query,
65
+ items,
66
+ onSelect,
67
+ onClose,
68
+ orientation = 'vertical',
69
+ autoSelectFirstItem = true
70
+ }: MenuNavigationOptions<T>) {
71
+ const initialSelectedIndex = autoSelectFirstItem ? 0 : -1
72
+ const [selection, setSelection] = useState<SelectionState>(() => ({
73
+ autoSelectFirstItem,
74
+ query,
75
+ selectedIndex: initialSelectedIndex
76
+ }))
77
+ const didTrackedInputChange =
78
+ selection.query !== query || selection.autoSelectFirstItem !== autoSelectFirstItem
79
+ const nextSelectedIndex = query ? initialSelectedIndex : selection.selectedIndex
80
+
81
+ if (didTrackedInputChange) {
82
+ // Restart render immediately so query changes reset before paint without an effect.
83
+ setSelection({
84
+ autoSelectFirstItem,
85
+ query,
86
+ selectedIndex: nextSelectedIndex
87
+ })
88
+ }
89
+
90
+ const selectedIndex = didTrackedInputChange ? nextSelectedIndex : selection.selectedIndex
91
+ const setSelectedIndex = useCallback(
92
+ (value: SelectedIndexUpdater) => {
93
+ setSelection((currentSelection) => {
94
+ const didCurrentInputChange =
95
+ currentSelection.query !== query ||
96
+ currentSelection.autoSelectFirstItem !== autoSelectFirstItem
97
+ const currentSelectedIndex =
98
+ didCurrentInputChange && query ? initialSelectedIndex : currentSelection.selectedIndex
99
+ const nextSelectedIndex = typeof value === 'function' ? value(currentSelectedIndex) : value
100
+
101
+ return {
102
+ autoSelectFirstItem,
103
+ query,
104
+ selectedIndex: nextSelectedIndex
105
+ }
106
+ })
107
+ },
108
+ [autoSelectFirstItem, initialSelectedIndex, query]
109
+ )
110
+
111
+ useEffect(() => {
112
+ const handleKeyboardNavigation = (event: KeyboardEvent) => {
113
+ if (!items.length) return false
114
+
115
+ const moveNext = () =>
116
+ setSelectedIndex((currentIndex) => {
117
+ if (currentIndex === -1) return 0
118
+ return (currentIndex + 1) % items.length
119
+ })
120
+
121
+ const movePrev = () =>
122
+ setSelectedIndex((currentIndex) => {
123
+ if (currentIndex === -1) return items.length - 1
124
+ return (currentIndex - 1 + items.length) % items.length
125
+ })
126
+
127
+ switch (event.key) {
128
+ case 'ArrowUp': {
129
+ if (orientation === 'horizontal') return false
130
+ event.preventDefault()
131
+ movePrev()
132
+ return true
133
+ }
134
+
135
+ case 'ArrowDown': {
136
+ if (orientation === 'horizontal') return false
137
+ event.preventDefault()
138
+ moveNext()
139
+ return true
140
+ }
141
+
142
+ case 'ArrowLeft': {
143
+ if (orientation === 'vertical') return false
144
+ event.preventDefault()
145
+ movePrev()
146
+ return true
147
+ }
148
+
149
+ case 'ArrowRight': {
150
+ if (orientation === 'vertical') return false
151
+ event.preventDefault()
152
+ moveNext()
153
+ return true
154
+ }
155
+
156
+ case 'Tab': {
157
+ event.preventDefault()
158
+ if (event.shiftKey) {
159
+ movePrev()
160
+ } else {
161
+ moveNext()
162
+ }
163
+ return true
164
+ }
165
+
166
+ case 'Home': {
167
+ event.preventDefault()
168
+ setSelectedIndex(0)
169
+ return true
170
+ }
171
+
172
+ case 'End': {
173
+ event.preventDefault()
174
+ setSelectedIndex(items.length - 1)
175
+ return true
176
+ }
177
+
178
+ case 'Enter': {
179
+ if (event.isComposing) return false
180
+ event.preventDefault()
181
+ if (selectedIndex !== -1 && items[selectedIndex]) {
182
+ onSelect?.(items[selectedIndex])
183
+ }
184
+ return true
185
+ }
186
+
187
+ case 'Escape': {
188
+ event.preventDefault()
189
+ onClose?.()
190
+ return true
191
+ }
192
+
193
+ default:
194
+ return false
195
+ }
196
+ }
197
+
198
+ let targetElement: HTMLElement | null = null
199
+
200
+ if (editor) {
201
+ targetElement = editor.view.dom
202
+ } else if (containerRef?.current) {
203
+ targetElement = containerRef.current
204
+ }
205
+
206
+ if (targetElement) {
207
+ targetElement.addEventListener('keydown', handleKeyboardNavigation, true)
208
+
209
+ return () => {
210
+ targetElement?.removeEventListener('keydown', handleKeyboardNavigation, true)
211
+ }
212
+ }
213
+
214
+ return undefined
215
+ }, [editor, containerRef, items, selectedIndex, setSelectedIndex, onSelect, onClose, orientation])
216
+
217
+ return {
218
+ selectedIndex: items.length ? selectedIndex : undefined,
219
+ setSelectedIndex
220
+ }
221
+ }
@@ -0,0 +1,46 @@
1
+ 'use client'
2
+
3
+ import type { Editor } from '@tiptap/react'
4
+ import { useCurrentEditor, useEditorState } from '@tiptap/react'
5
+ import { useMemo } from 'react'
6
+
7
+ /**
8
+ * Hook that provides access to a Tiptap editor instance.
9
+ *
10
+ * Accepts an optional editor instance directly, or falls back to retrieving
11
+ * the editor from the Tiptap context if available. This allows components
12
+ * to work both when given an editor directly and when used within a Tiptap
13
+ * editor context.
14
+ *
15
+ * @param providedEditor - Optional editor instance to use instead of the context editor
16
+ * @returns The provided editor or the editor from context, whichever is available
17
+ */
18
+ export function useTiptapEditor(providedEditor?: Editor | null): {
19
+ editor: Editor | null
20
+ editorState?: Editor['state']
21
+ canCommand?: Editor['can']
22
+ } {
23
+ const { editor: coreEditor } = useCurrentEditor()
24
+ const mainEditor = useMemo(() => providedEditor || coreEditor, [providedEditor, coreEditor])
25
+
26
+ const editorState = useEditorState({
27
+ editor: mainEditor,
28
+ selector(context) {
29
+ if (!context.editor) {
30
+ return {
31
+ editor: null,
32
+ editorState: undefined,
33
+ canCommand: undefined
34
+ }
35
+ }
36
+
37
+ return {
38
+ editor: context.editor,
39
+ editorState: context.editor.state,
40
+ canCommand: context.editor.can
41
+ }
42
+ }
43
+ })
44
+
45
+ return editorState || { editor: null }
46
+ }
@@ -0,0 +1,169 @@
1
+ 'use client'
2
+
3
+ // --- Hooks ---
4
+ import { useTiptapEditor } from '@admin/hooks/content-editor/use-tiptap-editor'
5
+ // --- Lib ---
6
+ import { isNodeTypeSelected } from '@admin/utils/editor/tiptap'
7
+ import type { Editor } from '@tiptap/react'
8
+ // --- Icons ---
9
+ import { Redo2Icon, Undo2Icon } from 'lucide-react'
10
+ import { useCallback, useEffect, useState } from 'react'
11
+
12
+ export type UndoRedoAction = 'undo' | 'redo'
13
+
14
+ /**
15
+ * Configuration for the history functionality
16
+ */
17
+ export interface UseUndoRedoConfig {
18
+ /**
19
+ * The Tiptap editor instance.
20
+ */
21
+ editor?: Editor | null
22
+ /**
23
+ * The history action to perform (undo or redo).
24
+ */
25
+ action: UndoRedoAction
26
+ /**
27
+ * Whether the button should hide when action is not available.
28
+ * @default false
29
+ */
30
+ hideWhenUnavailable?: boolean
31
+ /**
32
+ * Callback function called after a successful action execution.
33
+ */
34
+ onExecuted?: () => void
35
+ }
36
+
37
+ export const UNDO_REDO_SHORTCUT_KEYS: Record<UndoRedoAction, string> = {
38
+ undo: 'mod+z',
39
+ redo: 'mod+shift+z'
40
+ }
41
+
42
+ export const historyActionLabels: Record<UndoRedoAction, string> = {
43
+ undo: 'Undo',
44
+ redo: 'Redo'
45
+ }
46
+
47
+ export const historyIcons = {
48
+ undo: Undo2Icon,
49
+ redo: Redo2Icon
50
+ }
51
+
52
+ /**
53
+ * Checks if a history action can be executed
54
+ */
55
+ export function canExecuteUndoRedoAction(editor: Editor | null, action: UndoRedoAction): boolean {
56
+ if (!editor || !editor.isEditable) return false
57
+ if (isNodeTypeSelected(editor, ['image'])) return false
58
+
59
+ return action === 'undo' ? editor.can().undo() : editor.can().redo()
60
+ }
61
+
62
+ /**
63
+ * Executes a history action on the editor
64
+ */
65
+ export function executeUndoRedoAction(editor: Editor | null, action: UndoRedoAction): boolean {
66
+ if (!editor || !editor.isEditable) return false
67
+ if (!canExecuteUndoRedoAction(editor, action)) return false
68
+
69
+ const chain = editor.chain().focus()
70
+ return action === 'undo' ? chain.undo().run() : chain.redo().run()
71
+ }
72
+
73
+ /**
74
+ * Determines if the history button should be shown
75
+ */
76
+ export function shouldShowButton(props: {
77
+ editor: Editor | null
78
+ hideWhenUnavailable: boolean
79
+ action: UndoRedoAction
80
+ }): boolean {
81
+ const { editor, hideWhenUnavailable, action } = props
82
+
83
+ if (!editor || !editor.isEditable) return false
84
+
85
+ if (hideWhenUnavailable && !editor.isActive('code')) {
86
+ return canExecuteUndoRedoAction(editor, action)
87
+ }
88
+
89
+ return true
90
+ }
91
+
92
+ /**
93
+ * Custom hook that provides history functionality for Tiptap editor
94
+ *
95
+ * @example
96
+ * ```tsx
97
+ * // Simple usage
98
+ * function MySimpleUndoButton() {
99
+ * const { isVisible, handleAction } = useHistory({ action: "undo" })
100
+ *
101
+ * if (!isVisible) return null
102
+ *
103
+ * return <button onClick={handleAction}>Undo</button>
104
+ * }
105
+ *
106
+ * // Advanced usage with configuration
107
+ * function MyAdvancedRedoButton() {
108
+ * const { isVisible, handleAction, label } = useHistory({
109
+ * editor: myEditor,
110
+ * action: "redo",
111
+ * hideWhenUnavailable: true,
112
+ * onExecuted: () => console.log('Action executed!')
113
+ * })
114
+ *
115
+ * if (!isVisible) return null
116
+ *
117
+ * return (
118
+ * <MyButton
119
+ * onClick={handleAction}
120
+ * aria-label={label}
121
+ * >
122
+ * Redo
123
+ * </MyButton>
124
+ * )
125
+ * }
126
+ * ```
127
+ */
128
+ export function useUndoRedo(config: UseUndoRedoConfig) {
129
+ const { editor: providedEditor, action, hideWhenUnavailable = false, onExecuted } = config
130
+
131
+ const { editor } = useTiptapEditor(providedEditor)
132
+ const [isVisible, setIsVisible] = useState<boolean>(true)
133
+ const canExecute = canExecuteUndoRedoAction(editor, action)
134
+
135
+ useEffect(() => {
136
+ if (!editor) return
137
+
138
+ const handleUpdate = () => {
139
+ setIsVisible(shouldShowButton({ editor, hideWhenUnavailable, action }))
140
+ }
141
+
142
+ handleUpdate()
143
+
144
+ editor.on('transaction', handleUpdate)
145
+
146
+ return () => {
147
+ editor.off('transaction', handleUpdate)
148
+ }
149
+ }, [editor, hideWhenUnavailable, action])
150
+
151
+ const handleAction = useCallback(() => {
152
+ if (!editor) return false
153
+
154
+ const success = executeUndoRedoAction(editor, action)
155
+ if (success) {
156
+ onExecuted?.()
157
+ }
158
+ return success
159
+ }, [editor, action, onExecuted])
160
+
161
+ return {
162
+ isVisible,
163
+ handleAction,
164
+ canExecute,
165
+ label: historyActionLabels[action],
166
+ shortcutKeys: UNDO_REDO_SHORTCUT_KEYS[action],
167
+ Icon: historyIcons[action]
168
+ }
169
+ }
@@ -0,0 +1,74 @@
1
+ 'use client'
2
+
3
+ import { getSystemTheme, type ResolvedTheme } from '@admin/utils/theme/system'
4
+ import * as React from 'react'
5
+
6
+ type Theme = 'light' | 'dark' | 'system'
7
+
8
+ interface ThemeContext {
9
+ theme: Theme
10
+ setTheme: (theme: Theme) => void
11
+ resolvedTheme: ResolvedTheme
12
+ }
13
+
14
+ const AdminThemeContext = React.createContext<ThemeContext | undefined>(undefined)
15
+
16
+ const STORAGE_KEY = 'admin-theme'
17
+
18
+ export function AdminThemeProvider({ children }: { children: React.ReactNode }) {
19
+ const [theme, setThemeState] = React.useState<Theme>('system')
20
+ const [resolved, setResolved] = React.useState<ResolvedTheme>('light')
21
+
22
+ // Read from localStorage on mount
23
+ React.useEffect(() => {
24
+ const stored = localStorage.getItem(STORAGE_KEY) as Theme | null
25
+ if (stored && ['light', 'dark', 'system'].includes(stored)) {
26
+ setThemeState(stored)
27
+ }
28
+ }, [])
29
+
30
+ // Resolve theme and apply .dark class to .admin-root
31
+ React.useEffect(() => {
32
+ const actual = theme === 'system' ? getSystemTheme() : theme
33
+ setResolved(actual)
34
+
35
+ const root = document.querySelector('.admin-root')
36
+ if (root) {
37
+ root.classList.toggle('dark', actual === 'dark')
38
+ }
39
+ }, [theme])
40
+
41
+ // Listen for system theme changes
42
+ React.useEffect(() => {
43
+ if (theme !== 'system') return
44
+ const mq = window.matchMedia('(prefers-color-scheme: dark)')
45
+ const handler = () => {
46
+ const actual = getSystemTheme()
47
+ setResolved(actual)
48
+ const root = document.querySelector('.admin-root')
49
+ if (root) {
50
+ root.classList.toggle('dark', actual === 'dark')
51
+ }
52
+ }
53
+ mq.addEventListener('change', handler)
54
+ return () => mq.removeEventListener('change', handler)
55
+ }, [theme])
56
+
57
+ const setTheme = React.useCallback((t: Theme) => {
58
+ setThemeState(t)
59
+ localStorage.setItem(STORAGE_KEY, t)
60
+ }, [])
61
+
62
+ const value = React.useMemo(
63
+ () => ({ theme, setTheme, resolvedTheme: resolved }),
64
+ [theme, setTheme, resolved]
65
+ )
66
+
67
+ return <AdminThemeContext.Provider value={value}>{children}</AdminThemeContext.Provider>
68
+ }
69
+
70
+ export function useTheme(): ThemeContext {
71
+ const ctx = React.use(AdminThemeContext)
72
+ if (!ctx) throw new Error('useTheme must be used within AdminThemeProvider')
73
+ return ctx
74
+ }
@@ -0,0 +1,48 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+
5
+ type CopyFn = (text: string) => Promise<boolean>
6
+
7
+ export function useCopyToClipboard(delay = 2000): [CopyFn, boolean] {
8
+ const [isCopied, setIsCopied] = React.useState(false)
9
+ const resetTimerRef = React.useRef<number | null>(null)
10
+
11
+ const clearResetTimer = React.useCallback(() => {
12
+ if (resetTimerRef.current === null) {
13
+ return
14
+ }
15
+
16
+ window.clearTimeout(resetTimerRef.current)
17
+ resetTimerRef.current = null
18
+ }, [])
19
+
20
+ const copy: CopyFn = React.useCallback(
21
+ async (text) => {
22
+ clearResetTimer()
23
+
24
+ if (typeof navigator === 'undefined' || !navigator.clipboard) {
25
+ console.warn('Clipboard not supported')
26
+ setIsCopied(false)
27
+ return false
28
+ }
29
+
30
+ try {
31
+ await navigator.clipboard.writeText(text)
32
+ setIsCopied(true)
33
+ resetTimerRef.current = window.setTimeout(() => {
34
+ setIsCopied(false)
35
+ resetTimerRef.current = null
36
+ }, delay)
37
+ return true
38
+ } catch (error) {
39
+ console.warn('Copy failed', error)
40
+ setIsCopied(false)
41
+ return false
42
+ }
43
+ },
44
+ [clearResetTimer, delay]
45
+ )
46
+
47
+ return [copy, isCopied]
48
+ }
@@ -0,0 +1,43 @@
1
+ 'use client'
2
+
3
+ import type {
4
+ DevModeIntegration,
5
+ DevModeIntegrationLoader
6
+ } from '@admin/components/shared/dev-mode/dev-mode-types'
7
+ import * as React from 'react'
8
+
9
+ export function useDevModeIntegration(loadIntegration: DevModeIntegrationLoader) {
10
+ const [integration, setIntegration] = React.useState<DevModeIntegration | null>(null)
11
+ const [loadError, setLoadError] = React.useState<string | null>(null)
12
+ const [isPending, startTransition] = React.useTransition()
13
+ const integrationPromiseRef = React.useRef<Promise<DevModeIntegration> | null>(null)
14
+
15
+ const handleOpenChange = React.useCallback(
16
+ (open: boolean) => {
17
+ if (!open || integration || integrationPromiseRef.current) {
18
+ return
19
+ }
20
+
21
+ startTransition(async () => {
22
+ try {
23
+ integrationPromiseRef.current = loadIntegration()
24
+ const nextIntegration = await integrationPromiseRef.current
25
+ setIntegration(nextIntegration)
26
+ setLoadError(null)
27
+ } catch (error) {
28
+ integrationPromiseRef.current = null
29
+ console.error(error)
30
+ setLoadError('Integration details could not be loaded.')
31
+ }
32
+ })
33
+ },
34
+ [integration, loadIntegration]
35
+ )
36
+
37
+ return {
38
+ integration,
39
+ isPending,
40
+ loadError,
41
+ handleOpenChange
42
+ }
43
+ }
@@ -0,0 +1,32 @@
1
+ 'use client'
2
+
3
+ import type { EntityVersionWithAuthor } from '@admin/actions/entity-versions'
4
+ import * as React from 'react'
5
+ import { toast } from 'sonner'
6
+
7
+ interface UseEntityVersionsOptions {
8
+ entityId: string
9
+ getVersionsAction: (entityId: string) => Promise<EntityVersionWithAuthor[]>
10
+ }
11
+
12
+ export function useEntityVersions({ entityId, getVersionsAction }: UseEntityVersionsOptions) {
13
+ const [versions, setVersions] = React.useState<EntityVersionWithAuthor[]>([])
14
+ const [isPending, startTransition] = React.useTransition()
15
+
16
+ const load = React.useCallback(() => {
17
+ startTransition(async () => {
18
+ try {
19
+ const nextVersions = await getVersionsAction(entityId)
20
+ setVersions(nextVersions)
21
+ } catch (error) {
22
+ toast.error(error instanceof Error ? error.message : 'Failed to load versions')
23
+ }
24
+ })
25
+ }, [entityId, getVersionsAction])
26
+
27
+ return {
28
+ versions,
29
+ isPending,
30
+ load
31
+ }
32
+ }
@@ -0,0 +1,21 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+
5
+ interface FailedImageUrlState {
6
+ hasImageFailed: boolean
7
+ markImageFailed: () => void
8
+ }
9
+
10
+ export function useFailedImageUrl(imageUrl: string): FailedImageUrlState {
11
+ const [failedImageUrl, setFailedImageUrl] = React.useState<string | null>(null)
12
+
13
+ const markImageFailed = React.useCallback(() => {
14
+ setFailedImageUrl(imageUrl)
15
+ }, [imageUrl])
16
+
17
+ return {
18
+ hasImageFailed: failedImageUrl === imageUrl,
19
+ markImageFailed
20
+ }
21
+ }
@@ -0,0 +1,46 @@
1
+ import * as React from 'react'
2
+
3
+ const ADMIN_STORAGE_PREFIX = 'admin-'
4
+
5
+ /** Type-safe wrapper for localStorage operations with admin- prefix. */
6
+ export function useLocalStorage<T>(key: string) {
7
+ const prefixedKey = ADMIN_STORAGE_PREFIX + key
8
+
9
+ const setItem = React.useCallback(
10
+ (value: T) => {
11
+ try {
12
+ localStorage.setItem(prefixedKey, JSON.stringify(value))
13
+ } catch {
14
+ // Silent failure for localStorage access errors
15
+ }
16
+ },
17
+ [prefixedKey]
18
+ )
19
+
20
+ const getItem = React.useCallback((): T | null => {
21
+ try {
22
+ const stored = localStorage.getItem(prefixedKey)
23
+ return stored ? JSON.parse(stored) : null
24
+ } catch {
25
+ return null
26
+ }
27
+ }, [prefixedKey])
28
+
29
+ const removeItem = React.useCallback(() => {
30
+ try {
31
+ localStorage.removeItem(prefixedKey)
32
+ } catch {
33
+ // Silent failure for localStorage access errors
34
+ }
35
+ }, [prefixedKey])
36
+
37
+ const hasItem = React.useCallback((): boolean => {
38
+ try {
39
+ return localStorage.getItem(prefixedKey) !== null
40
+ } catch {
41
+ return false
42
+ }
43
+ }, [prefixedKey])
44
+
45
+ return { setItem, getItem, removeItem, hasItem }
46
+ }