ruby_cms 0.2.1.1 → 1.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 (647) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -72
  3. data/README.md +293 -158
  4. data/Rakefile +0 -18
  5. data/SYNC_RULES.md +84 -0
  6. data/exe/ruby_cms +13 -18
  7. data/lib/generators/ruby_cms/admin_page_generator.rb +116 -60
  8. data/lib/generators/ruby_cms/templates/admin.html.erb +35 -17
  9. data/lib/generators/ruby_cms/templates/admin_page/_admin_table_content.html.erb.tt +25 -0
  10. data/lib/generators/ruby_cms/templates/admin_page/_form.html.erb.tt +36 -0
  11. data/lib/generators/ruby_cms/templates/admin_page/_row.html.erb.tt +20 -0
  12. data/lib/generators/ruby_cms/templates/admin_page/controller.rb.tt +74 -2
  13. data/lib/generators/ruby_cms/templates/admin_page/edit.html.erb.tt +14 -0
  14. data/lib/generators/ruby_cms/templates/admin_page/index.html.erb.tt +21 -10
  15. data/lib/generators/ruby_cms/templates/admin_page/new.html.erb.tt +14 -0
  16. data/lib/generators/ruby_cms/templates/assets/tailwind/application.css +225 -0
  17. data/lib/generators/ruby_cms/templates/components/ruby_ui/accordion/accordion.rb +17 -0
  18. data/lib/generators/ruby_cms/templates/components/ruby_ui/accordion/accordion_content.rb +21 -0
  19. data/lib/generators/ruby_cms/templates/components/ruby_ui/accordion/accordion_default_content.rb +17 -0
  20. data/lib/generators/ruby_cms/templates/components/ruby_ui/accordion/accordion_default_trigger.rb +19 -0
  21. data/lib/generators/ruby_cms/templates/components/ruby_ui/accordion/accordion_icon.rb +38 -0
  22. data/lib/generators/ruby_cms/templates/components/ruby_ui/accordion/accordion_item.rb +28 -0
  23. data/lib/generators/ruby_cms/templates/components/ruby_ui/accordion/accordion_trigger.rb +17 -0
  24. data/lib/generators/ruby_cms/templates/components/ruby_ui/admin_page/admin_page.rb +31 -0
  25. data/lib/generators/ruby_cms/templates/components/ruby_ui/admin_page/admin_page_header.rb +65 -0
  26. data/lib/generators/ruby_cms/templates/components/ruby_ui/admin_page/admin_resource_card.rb +28 -0
  27. data/lib/generators/ruby_cms/templates/components/ruby_ui/admin_page/admin_table_content.rb +20 -0
  28. data/lib/generators/ruby_cms/templates/components/ruby_ui/alert/alert.rb +36 -0
  29. data/lib/generators/ruby_cms/templates/components/ruby_ui/alert/alert_description.rb +17 -0
  30. data/lib/generators/ruby_cms/templates/components/ruby_ui/alert/alert_title.rb +17 -0
  31. data/lib/generators/ruby_cms/templates/components/ruby_ui/aspect_ratio/aspect_ratio.rb +33 -0
  32. data/lib/generators/ruby_cms/templates/components/ruby_ui/avatar/avatar.rb +31 -0
  33. data/lib/generators/ruby_cms/templates/components/ruby_ui/avatar/avatar_fallback.rb +17 -0
  34. data/lib/generators/ruby_cms/templates/components/ruby_ui/avatar/avatar_image.rb +26 -0
  35. data/lib/generators/ruby_cms/templates/components/ruby_ui/badge/badge.rb +60 -0
  36. data/lib/generators/ruby_cms/templates/components/ruby_ui/base.rb +29 -0
  37. data/lib/generators/ruby_cms/templates/components/ruby_ui/box/box.rb +15 -0
  38. data/lib/generators/ruby_cms/templates/components/ruby_ui/breadcrumb/breadcrumb.rb +17 -0
  39. data/lib/generators/ruby_cms/templates/components/ruby_ui/breadcrumb/breadcrumb_ellipsis.rb +39 -0
  40. data/lib/generators/ruby_cms/templates/components/ruby_ui/breadcrumb/breadcrumb_item.rb +17 -0
  41. data/lib/generators/ruby_cms/templates/components/ruby_ui/breadcrumb/breadcrumb_link.rb +22 -0
  42. data/lib/generators/ruby_cms/templates/components/ruby_ui/breadcrumb/breadcrumb_list.rb +17 -0
  43. data/lib/generators/ruby_cms/templates/components/ruby_ui/breadcrumb/breadcrumb_page.rb +19 -0
  44. data/lib/generators/ruby_cms/templates/components/ruby_ui/breadcrumb/breadcrumb_separator.rb +38 -0
  45. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_button.rb +82 -0
  46. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table.rb +133 -0
  47. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_actions.rb +104 -0
  48. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_body.rb +17 -0
  49. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_checkbox_cell.rb +40 -0
  50. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_checkbox_head.rb +34 -0
  51. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_delete_modal.rb +43 -0
  52. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_header.rb +42 -0
  53. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_pagination.rb +115 -0
  54. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_action_table_row.rb +77 -0
  55. data/lib/generators/ruby_cms/templates/components/ruby_ui/bulk_action_table/bulk_actions.rb +86 -0
  56. data/lib/generators/ruby_cms/templates/components/ruby_ui/button/button.rb +113 -0
  57. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar.rb +39 -0
  58. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar_body.rb +19 -0
  59. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar_days.rb +104 -0
  60. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar_header.rb +17 -0
  61. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar_next.rb +43 -0
  62. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar_prev.rb +43 -0
  63. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar_title.rb +27 -0
  64. data/lib/generators/ruby_cms/templates/components/ruby_ui/calendar/calendar_weekdays.rb +33 -0
  65. data/lib/generators/ruby_cms/templates/components/ruby_ui/card/card.rb +17 -0
  66. data/lib/generators/ruby_cms/templates/components/ruby_ui/card/card_content.rb +17 -0
  67. data/lib/generators/ruby_cms/templates/components/ruby_ui/card/card_description.rb +17 -0
  68. data/lib/generators/ruby_cms/templates/components/ruby_ui/card/card_footer.rb +17 -0
  69. data/lib/generators/ruby_cms/templates/components/ruby_ui/card/card_header.rb +17 -0
  70. data/lib/generators/ruby_cms/templates/components/ruby_ui/card/card_title.rb +17 -0
  71. data/lib/generators/ruby_cms/templates/components/ruby_ui/carousel/carousel.rb +44 -0
  72. data/lib/generators/ruby_cms/templates/components/ruby_ui/carousel/carousel_content.rb +23 -0
  73. data/lib/generators/ruby_cms/templates/components/ruby_ui/carousel/carousel_item.rb +23 -0
  74. data/lib/generators/ruby_cms/templates/components/ruby_ui/carousel/carousel_next.rb +48 -0
  75. data/lib/generators/ruby_cms/templates/components/ruby_ui/carousel/carousel_previous.rb +49 -0
  76. data/lib/generators/ruby_cms/templates/components/ruby_ui/checkbox/checkbox.rb +29 -0
  77. data/lib/generators/ruby_cms/templates/components/ruby_ui/checkbox/checkbox_group.rb +20 -0
  78. data/lib/generators/ruby_cms/templates/components/ruby_ui/clipboard/clipboard.rb +42 -0
  79. data/lib/generators/ruby_cms/templates/components/ruby_ui/clipboard/clipboard_popover.rb +40 -0
  80. data/lib/generators/ruby_cms/templates/components/ruby_ui/clipboard/clipboard_source.rb +19 -0
  81. data/lib/generators/ruby_cms/templates/components/ruby_ui/clipboard/clipboard_trigger.rb +20 -0
  82. data/lib/generators/ruby_cms/templates/components/ruby_ui/codeblock/codeblock.rb +102 -0
  83. data/lib/generators/ruby_cms/templates/components/ruby_ui/collapsible/collapsible.rb +25 -0
  84. data/lib/generators/ruby_cms/templates/components/ruby_ui/collapsible/collapsible_content.rb +18 -0
  85. data/lib/generators/ruby_cms/templates/components/ruby_ui/collapsible/collapsible_trigger.rb +19 -0
  86. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox.rb +26 -0
  87. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_checkbox.rb +25 -0
  88. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_empty_state.rb +21 -0
  89. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_item.rb +25 -0
  90. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_list.rb +18 -0
  91. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_list_group.rb +20 -0
  92. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_popover.rb +30 -0
  93. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_radio.rb +26 -0
  94. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_search_input.rb +53 -0
  95. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +25 -0
  96. data/lib/generators/ruby_cms/templates/components/ruby_ui/combobox/combobox_trigger.rb +57 -0
  97. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command.rb +9 -0
  98. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_dialog.rb +17 -0
  99. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_dialog_content.rb +48 -0
  100. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_dialog_trigger.rb +29 -0
  101. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_empty.rb +19 -0
  102. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_group.rb +40 -0
  103. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_input.rb +56 -0
  104. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_item.rb +32 -0
  105. data/lib/generators/ruby_cms/templates/components/ruby_ui/command/command_list.rb +17 -0
  106. data/lib/generators/ruby_cms/templates/components/ruby_ui/container/container.rb +33 -0
  107. data/lib/generators/ruby_cms/templates/components/ruby_ui/container/container_section.rb +31 -0
  108. data/lib/generators/ruby_cms/templates/components/ruby_ui/context_menu/context_menu.rb +26 -0
  109. data/lib/generators/ruby_cms/templates/components/ruby_ui/context_menu/context_menu_content.rb +25 -0
  110. data/lib/generators/ruby_cms/templates/components/ruby_ui/context_menu/context_menu_item.rb +66 -0
  111. data/lib/generators/ruby_cms/templates/components/ruby_ui/context_menu/context_menu_label.rb +24 -0
  112. data/lib/generators/ruby_cms/templates/components/ruby_ui/context_menu/context_menu_separator.rb +19 -0
  113. data/lib/generators/ruby_cms/templates/components/ruby_ui/context_menu/context_menu_trigger.rb +20 -0
  114. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table.rb +29 -0
  115. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_bulk_actions.rb +18 -0
  116. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_column_toggle.rb +62 -0
  117. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_expand_toggle.rb +53 -0
  118. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_form.rb +39 -0
  119. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_kaminari_adapter.rb +17 -0
  120. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_manual_adapter.rb +17 -0
  121. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_pagination.rb +100 -0
  122. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_pagination_bar.rb +15 -0
  123. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_pagy_adapter.rb +17 -0
  124. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_per_page_select.rb +35 -0
  125. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_row_checkbox.rb +30 -0
  126. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_search.rb +57 -0
  127. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_select_all_checkbox.rb +21 -0
  128. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_selection_summary.rb +25 -0
  129. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_sort_head.rb +112 -0
  130. data/lib/generators/ruby_cms/templates/components/ruby_ui/data_table/data_table_toolbar.rb +15 -0
  131. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog.rb +25 -0
  132. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog_content.rb +78 -0
  133. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog_description.rb +17 -0
  134. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog_footer.rb +17 -0
  135. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog_header.rb +17 -0
  136. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog_middle.rb +17 -0
  137. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog_title.rb +17 -0
  138. data/lib/generators/ruby_cms/templates/components/ruby_ui/dialog/dialog_trigger.rb +20 -0
  139. data/lib/generators/ruby_cms/templates/components/ruby_ui/dropdown_menu/dropdown_menu.rb +35 -0
  140. data/lib/generators/ruby_cms/templates/components/ruby_ui/dropdown_menu/dropdown_menu_content.rb +44 -0
  141. data/lib/generators/ruby_cms/templates/components/ruby_ui/dropdown_menu/dropdown_menu_item.rb +28 -0
  142. data/lib/generators/ruby_cms/templates/components/ruby_ui/dropdown_menu/dropdown_menu_label.rb +17 -0
  143. data/lib/generators/ruby_cms/templates/components/ruby_ui/dropdown_menu/dropdown_menu_separator.rb +19 -0
  144. data/lib/generators/ruby_cms/templates/components/ruby_ui/dropdown_menu/dropdown_menu_trigger.rb +18 -0
  145. data/lib/generators/ruby_cms/templates/components/ruby_ui/empty_state/empty_state.rb +190 -0
  146. data/lib/generators/ruby_cms/templates/components/ruby_ui/form/form.rb +15 -0
  147. data/lib/generators/ruby_cms/templates/components/ruby_ui/form/form_field.rb +20 -0
  148. data/lib/generators/ruby_cms/templates/components/ruby_ui/form/form_field_error.rb +20 -0
  149. data/lib/generators/ruby_cms/templates/components/ruby_ui/form/form_field_hint.rb +15 -0
  150. data/lib/generators/ruby_cms/templates/components/ruby_ui/form/form_field_label.rb +15 -0
  151. data/lib/generators/ruby_cms/templates/components/ruby_ui/hover_card/hover_card.rb +27 -0
  152. data/lib/generators/ruby_cms/templates/components/ruby_ui/hover_card/hover_card_content.rb +22 -0
  153. data/lib/generators/ruby_cms/templates/components/ruby_ui/hover_card/hover_card_trigger.rb +20 -0
  154. data/lib/generators/ruby_cms/templates/components/ruby_ui/input/input.rb +34 -0
  155. data/lib/generators/ruby_cms/templates/components/ruby_ui/link/link.rb +106 -0
  156. data/lib/generators/ruby_cms/templates/components/ruby_ui/masked_input/masked_input.rb +15 -0
  157. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal.rb +26 -0
  158. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal_action.rb +17 -0
  159. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal_cancel.rb +20 -0
  160. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal_content.rb +68 -0
  161. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal_description.rb +17 -0
  162. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal_footer.rb +17 -0
  163. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal_header.rb +17 -0
  164. data/lib/generators/ruby_cms/templates/components/ruby_ui/modal/modal_title.rb +17 -0
  165. data/lib/generators/ruby_cms/templates/components/ruby_ui/native_select/native_select.rb +39 -0
  166. data/lib/generators/ruby_cms/templates/components/ruby_ui/native_select/native_select_group.rb +15 -0
  167. data/lib/generators/ruby_cms/templates/components/ruby_ui/native_select/native_select_icon.rb +39 -0
  168. data/lib/generators/ruby_cms/templates/components/ruby_ui/native_select/native_select_option.rb +15 -0
  169. data/lib/generators/ruby_cms/templates/components/ruby_ui/pagination/pagination.rb +19 -0
  170. data/lib/generators/ruby_cms/templates/components/ruby_ui/pagination/pagination_content.rb +17 -0
  171. data/lib/generators/ruby_cms/templates/components/ruby_ui/pagination/pagination_ellipsis.rb +42 -0
  172. data/lib/generators/ruby_cms/templates/components/ruby_ui/pagination/pagination_item.rb +28 -0
  173. data/lib/generators/ruby_cms/templates/components/ruby_ui/popover/popover.rb +26 -0
  174. data/lib/generators/ruby_cms/templates/components/ruby_ui/popover/popover_content.rb +27 -0
  175. data/lib/generators/ruby_cms/templates/components/ruby_ui/popover/popover_trigger.rb +20 -0
  176. data/lib/generators/ruby_cms/templates/components/ruby_ui/progress/progress.rb +37 -0
  177. data/lib/generators/ruby_cms/templates/components/ruby_ui/radio_button/radio_button.rb +25 -0
  178. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select.rb +23 -0
  179. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select_content.rb +32 -0
  180. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select_group.rb +15 -0
  181. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select_input.rb +22 -0
  182. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select_item.rb +52 -0
  183. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select_label.rb +17 -0
  184. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select_trigger.rb +54 -0
  185. data/lib/generators/ruby_cms/templates/components/ruby_ui/select/select_value.rb +27 -0
  186. data/lib/generators/ruby_cms/templates/components/ruby_ui/separator/separator.rb +38 -0
  187. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet.rb +17 -0
  188. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet_content.rb +77 -0
  189. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet_description.rb +17 -0
  190. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet_footer.rb +17 -0
  191. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet_header.rb +17 -0
  192. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet_middle.rb +17 -0
  193. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet_title.rb +17 -0
  194. data/lib/generators/ruby_cms/templates/components/ruby_ui/sheet/sheet_trigger.rb +17 -0
  195. data/lib/generators/ruby_cms/templates/components/ruby_ui/shortcut_key/shortcut_key.rb +17 -0
  196. data/lib/generators/ruby_cms/templates/components/ruby_ui/skeleton/skeleton.rb +17 -0
  197. data/lib/generators/ruby_cms/templates/components/ruby_ui/switch/switch.rb +24 -0
  198. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table.rb +19 -0
  199. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table_body.rb +17 -0
  200. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table_caption.rb +17 -0
  201. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table_cell.rb +17 -0
  202. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table_footer.rb +17 -0
  203. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table_head.rb +17 -0
  204. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table_header.rb +17 -0
  205. data/lib/generators/ruby_cms/templates/components/ruby_ui/table/table_row.rb +17 -0
  206. data/lib/generators/ruby_cms/templates/components/ruby_ui/tabs/tabs.rb +25 -0
  207. data/lib/generators/ruby_cms/templates/components/ruby_ui/tabs/tabs_content.rb +26 -0
  208. data/lib/generators/ruby_cms/templates/components/ruby_ui/tabs/tabs_list.rb +17 -0
  209. data/lib/generators/ruby_cms/templates/components/ruby_ui/tabs/tabs_trigger.rb +28 -0
  210. data/lib/generators/ruby_cms/templates/components/ruby_ui/textarea/textarea.rb +26 -0
  211. data/lib/generators/ruby_cms/templates/components/ruby_ui/theme_toggle/set_dark_mode.rb +16 -0
  212. data/lib/generators/ruby_cms/templates/components/ruby_ui/theme_toggle/set_light_mode.rb +16 -0
  213. data/lib/generators/ruby_cms/templates/components/ruby_ui/theme_toggle/theme_toggle.rb +9 -0
  214. data/lib/generators/ruby_cms/templates/components/ruby_ui/tooltip/tooltip.rb +26 -0
  215. data/lib/generators/ruby_cms/templates/components/ruby_ui/tooltip/tooltip_content.rb +26 -0
  216. data/lib/generators/ruby_cms/templates/components/ruby_ui/tooltip/tooltip_trigger.rb +19 -0
  217. data/lib/generators/ruby_cms/templates/components/ruby_ui/typography/heading.rb +60 -0
  218. data/lib/generators/ruby_cms/templates/components/ruby_ui/typography/inline_code.rb +17 -0
  219. data/lib/generators/ruby_cms/templates/components/ruby_ui/typography/inline_link.rb +22 -0
  220. data/lib/generators/ruby_cms/templates/components/ruby_ui/typography/text.rb +53 -0
  221. data/lib/generators/ruby_cms/templates/components/ruby_ui/typography/typography_blockquote.rb +17 -0
  222. data/lib/generators/ruby_cms/templates/{ruby_cms.rb → config/initializers/admin.rb} +15 -9
  223. data/lib/generators/ruby_cms/templates/config/initializers/admin_dashboard.rb +43 -0
  224. data/lib/generators/ruby_cms/templates/config/initializers/pagy.rb +7 -0
  225. data/lib/generators/ruby_cms/templates/config/initializers/ruby_cms_core.rb +25 -0
  226. data/lib/generators/ruby_cms/templates/config/initializers/ruby_cms_custom_settings.rb +35 -0
  227. data/lib/generators/ruby_cms/templates/config/initializers/webauthn.rb +28 -0
  228. data/lib/generators/ruby_cms/templates/config/locales/en.yml +277 -0
  229. data/lib/generators/ruby_cms/templates/config/locales/nl.yml +329 -0
  230. data/lib/generators/ruby_cms/templates/controllers/admin/analytics_controller.rb +211 -0
  231. data/lib/generators/ruby_cms/templates/controllers/admin/application_controller.rb +186 -0
  232. data/lib/generators/ruby_cms/templates/controllers/admin/audit_log_entries_controller.rb +69 -0
  233. data/lib/generators/ruby_cms/templates/controllers/admin/commands_controller.rb +146 -0
  234. data/lib/generators/ruby_cms/templates/controllers/admin/content_block_versions_controller.rb +96 -0
  235. data/lib/generators/ruby_cms/templates/controllers/admin/content_blocks_controller.rb +405 -0
  236. data/lib/generators/ruby_cms/templates/controllers/admin/dashboard_controller.rb +114 -0
  237. data/lib/generators/ruby_cms/templates/controllers/admin/invitations_controller.rb +64 -0
  238. data/lib/generators/ruby_cms/templates/controllers/admin/locale_controller.rb +19 -0
  239. data/lib/generators/ruby_cms/templates/controllers/admin/media_assets_controller.rb +186 -0
  240. data/lib/generators/ruby_cms/templates/controllers/admin/notifications_controller.rb +37 -0
  241. data/lib/generators/ruby_cms/templates/controllers/admin/passkey_credentials_controller.rb +17 -0
  242. data/lib/generators/ruby_cms/templates/controllers/admin/passkey_registrations_controller.rb +50 -0
  243. data/lib/generators/ruby_cms/templates/controllers/admin/permissions_controller.rb +132 -0
  244. data/lib/generators/ruby_cms/templates/controllers/admin/redirects_controller.rb +175 -0
  245. data/lib/generators/ruby_cms/templates/controllers/admin/security_controller.rb +146 -0
  246. data/lib/generators/ruby_cms/templates/controllers/admin/settings_controller.rb +298 -0
  247. data/lib/generators/ruby_cms/templates/controllers/admin/system_health_controller.rb +11 -0
  248. data/lib/generators/ruby_cms/templates/controllers/admin/trash_controller.rb +61 -0
  249. data/lib/generators/ruby_cms/templates/controllers/admin/user_permissions_controller.rb +91 -0
  250. data/lib/generators/ruby_cms/templates/controllers/admin/users_controller.rb +220 -0
  251. data/lib/generators/ruby_cms/templates/controllers/admin/visitor_errors_controller.rb +114 -0
  252. data/lib/generators/ruby_cms/templates/controllers/admin/visual_editor_controller.rb +384 -0
  253. data/lib/generators/ruby_cms/templates/controllers/concerns/.keep +0 -0
  254. data/lib/generators/ruby_cms/templates/controllers/concerns/admin_bulk_actions.rb +59 -0
  255. data/lib/generators/ruby_cms/templates/controllers/concerns/admin_pagination.rb +106 -0
  256. data/lib/generators/ruby_cms/templates/controllers/concerns/admin_turbo_table.rb +46 -0
  257. data/lib/generators/ruby_cms/templates/controllers/concerns/audit_loggable.rb +28 -0
  258. data/lib/generators/ruby_cms/templates/controllers/concerns/authentication.rb +63 -0
  259. data/lib/generators/ruby_cms/templates/controllers/concerns/page_tracking.rb +45 -0
  260. data/lib/generators/ruby_cms/templates/controllers/concerns/security_monitoring.rb +102 -0
  261. data/lib/generators/ruby_cms/templates/controllers/concerns/sudo_mode.rb +29 -0
  262. data/lib/generators/ruby_cms/templates/controllers/concerns/visitor_error_capture.rb +35 -0
  263. data/lib/generators/ruby_cms/templates/controllers/errors_controller.rb +36 -0
  264. data/lib/generators/ruby_cms/templates/controllers/passkey_sessions_controller.rb +69 -0
  265. data/lib/generators/ruby_cms/templates/db/migrate/20251121085414_create_email_blocklists.rb +12 -0
  266. data/lib/generators/ruby_cms/templates/db/migrate/20251121161828_create_ip_blocklists.rb +12 -0
  267. data/lib/generators/ruby_cms/templates/db/migrate/20251205120000_add_analytics_indices.rb +48 -0
  268. data/lib/generators/ruby_cms/templates/db/migrate/20251216064753_backfill_security_fields_in_ahoy_events.rb +49 -0
  269. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260125000001_create_ruby_cms_permissions.rb +2 -2
  270. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260125000002_create_ruby_cms_user_permissions.rb +2 -2
  271. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260125000003_create_ruby_cms_content_blocks.rb +3 -3
  272. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260125000010_add_indexes_to_ruby_cms_tables.rb +1 -1
  273. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260127000001_add_locale_to_ruby_cms_content_blocks.rb +8 -6
  274. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260129000001_create_ruby_cms_visitor_errors.rb +4 -4
  275. data/lib/generators/ruby_cms/templates/db/migrate/20260130000001_add_referer_and_query_to_ruby_cms_visitor_errors.rb +10 -0
  276. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260130000002_create_ruby_cms_preferences.rb +2 -2
  277. data/lib/generators/ruby_cms/templates/db/migrate/20260130000003_add_category_to_ruby_cms_preferences.rb +10 -0
  278. data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260328000001_create_content_block_versions.rb +2 -2
  279. data/lib/generators/ruby_cms/templates/db/migrate/20260525120000_create_audit_log_entries.rb +24 -0
  280. data/lib/generators/ruby_cms/templates/db/migrate/20260525130000_create_redirects.rb +28 -0
  281. data/lib/generators/ruby_cms/templates/db/migrate/20260525140000_create_media_assets.rb +25 -0
  282. data/lib/generators/ruby_cms/templates/db/migrate/20260525150000_create_invitations.rb +22 -0
  283. data/lib/generators/ruby_cms/templates/db/migrate/20260525160000_create_command_runs.rb +22 -0
  284. data/lib/generators/ruby_cms/templates/db/migrate/20260525190000_add_state_to_visitor_errors.rb +20 -0
  285. data/lib/generators/ruby_cms/templates/db/migrate/20260527165017_add_discarded_at_to_visitor_errors.rb +10 -0
  286. data/lib/generators/ruby_cms/templates/db/migrate/20260527165728_add_discarded_at_to_cms_tables.rb +12 -0
  287. data/lib/generators/ruby_cms/templates/db/migrate/20260605151935_create_passkey_credentials.rb +15 -0
  288. data/lib/generators/ruby_cms/templates/db/migrate/20260605151936_add_webauthn_id_to_users.rb +22 -0
  289. data/lib/generators/ruby_cms/templates/db/migrate/20260606000001_add_authenticated_at_to_sessions.rb +14 -0
  290. data/lib/generators/ruby_cms/templates/helpers/admin/admin_page_helper.rb +9 -0
  291. data/lib/generators/ruby_cms/templates/helpers/admin/dashboard_helper.rb +16 -0
  292. data/lib/generators/ruby_cms/templates/helpers/admin/media_assets_helper.rb +38 -0
  293. data/lib/generators/ruby_cms/templates/helpers/admin/relative_time_helper.rb +37 -0
  294. data/lib/generators/ruby_cms/templates/helpers/admin/ui_helper.rb +48 -0
  295. data/lib/generators/ruby_cms/templates/helpers/cms_application_helpers.rb +70 -0
  296. data/lib/generators/ruby_cms/templates/helpers/content_blocks_helper.rb +382 -0
  297. data/lib/generators/ruby_cms/templates/helpers/settings_helper.rb +192 -0
  298. data/lib/generators/ruby_cms/templates/javascript/admin.js +6 -0
  299. data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/admin}/admin_commands_controller.js +2 -2
  300. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/autosearch_controller.js +18 -0
  301. data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/admin}/clickable_row_controller.js +11 -0
  302. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/clipboard_controller.js +34 -0
  303. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/command_palette_controller.js +189 -0
  304. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/commands_controller.js +300 -0
  305. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/content_block_history_controller.js +167 -0
  306. data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/admin}/flash_messages_controller.js +1 -1
  307. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/inline_rich_editor_controller.js +157 -0
  308. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/media_selection_controller.js +76 -0
  309. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/media_uploader_controller.js +23 -0
  310. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/mobile_menu_controller.js +125 -0
  311. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/nav_order_sortable_controller.js +296 -0
  312. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/nav_shortcuts_controller.js +47 -0
  313. data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/admin}/page_preview_controller.js +64 -3
  314. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/permission_matrix_controller.js +49 -0
  315. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/search_shortcut_controller.js +24 -0
  316. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/settings_rail_search_controller.js +17 -0
  317. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/shortcuts_overlay_controller.js +39 -0
  318. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/sidebar_collapse_controller.js +135 -0
  319. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/sidebar_nav_persist_controller.js +48 -0
  320. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/sidebar_toggle_trigger_controller.js +10 -0
  321. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/topbar_controller.js +88 -0
  322. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/visual_editor_controller.js +721 -0
  323. data/lib/generators/ruby_cms/templates/javascript/controllers/admin/visual_editor_page_select_controller.js +174 -0
  324. data/lib/generators/ruby_cms/templates/javascript/controllers/application.js +10 -0
  325. data/lib/generators/ruby_cms/templates/javascript/controllers/index.js +2 -0
  326. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/accordion_controller.js +97 -0
  327. data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui}/bulk_action_table_controller.js +86 -233
  328. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/calendar_controller.js +249 -0
  329. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/calendar_input_controller.js +8 -0
  330. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/carousel_controller.js +60 -0
  331. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/checkbox_group_controller.js +21 -0
  332. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/clipboard_controller.js +54 -0
  333. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/collapsible_controller.js +47 -0
  334. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/combobox_controller.js +190 -0
  335. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/command_controller.js +138 -0
  336. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/context_menu_controller.js +144 -0
  337. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/data_table_column_visibility_controller.js +14 -0
  338. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/data_table_controller.js +109 -0
  339. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/data_table_search_controller.js +62 -0
  340. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/dialog_controller.js +32 -0
  341. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/dropdown_menu_controller.js +149 -0
  342. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/form_field_controller.js +61 -0
  343. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/hover_card_controller.js +153 -0
  344. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/masked_input_controller.js +9 -0
  345. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/modal_controller.js +45 -0
  346. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/popover_controller.js +107 -0
  347. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/select_controller.js +192 -0
  348. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/select_item_controller.js +11 -0
  349. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/sheet_content_controller.js +7 -0
  350. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/sheet_controller.js +9 -0
  351. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/tabs_controller.js +67 -0
  352. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/theme_toggle_controller.js +30 -0
  353. data/lib/generators/ruby_cms/templates/javascript/controllers/ruby_ui/tooltip_controller.js +38 -0
  354. data/lib/generators/ruby_cms/templates/javascript/controllers/webauthn_controller.js +153 -0
  355. data/lib/generators/ruby_cms/templates/lib/ruby_cms/cli.rb +170 -0
  356. data/lib/generators/ruby_cms/templates/lib/ruby_cms/commands_registry.rb +76 -0
  357. data/lib/{ruby_cms → generators/ruby_cms/templates/lib/ruby_cms}/content_blocks_grouping.rb +2 -6
  358. data/lib/{ruby_cms → generators/ruby_cms/templates/lib/ruby_cms}/content_blocks_sync.rb +6 -8
  359. data/lib/{ruby_cms → generators/ruby_cms/templates/lib/ruby_cms}/dashboard_blocks.rb +5 -5
  360. data/lib/{ruby_cms → generators/ruby_cms/templates/lib/ruby_cms}/icons.rb +41 -10
  361. data/lib/{ruby_cms → generators/ruby_cms/templates/lib/ruby_cms}/settings.rb +60 -10
  362. data/lib/{ruby_cms → generators/ruby_cms/templates/lib/ruby_cms}/settings_registry.rb +79 -3
  363. data/lib/generators/ruby_cms/templates/lib/ruby_cms.rb +342 -0
  364. data/lib/{tasks → generators/ruby_cms/templates/lib/tasks}/admin.rake +16 -16
  365. data/lib/generators/ruby_cms/templates/lib/tasks/ruby_cms.rake +158 -0
  366. data/lib/generators/ruby_cms/templates/models/audit_log_entry.rb +56 -0
  367. data/lib/generators/ruby_cms/templates/models/command_run.rb +29 -0
  368. data/lib/generators/ruby_cms/templates/models/concerns/content_block/searchable.rb +18 -0
  369. data/{app → lib/generators/ruby_cms/templates}/models/concerns/content_block/versionable.rb +1 -1
  370. data/lib/generators/ruby_cms/templates/models/concerns/ransackable.rb +32 -0
  371. data/{app → lib/generators/ruby_cms/templates}/models/content_block.rb +13 -5
  372. data/lib/generators/ruby_cms/templates/models/email_blocklist.rb +21 -0
  373. data/lib/generators/ruby_cms/templates/models/invitation.rb +86 -0
  374. data/lib/generators/ruby_cms/templates/models/ip_blocklist.rb +34 -0
  375. data/lib/generators/ruby_cms/templates/models/media_asset.rb +90 -0
  376. data/lib/generators/ruby_cms/templates/models/passkey_credential.rb +6 -0
  377. data/lib/generators/ruby_cms/templates/models/permission.rb +71 -0
  378. data/lib/generators/ruby_cms/templates/models/permittable.rb +69 -0
  379. data/lib/generators/ruby_cms/templates/models/preference.rb +109 -0
  380. data/lib/generators/ruby_cms/templates/models/redirect.rb +100 -0
  381. data/lib/generators/ruby_cms/templates/models/user_permission.rb +25 -0
  382. data/lib/generators/ruby_cms/templates/models/visitor_error.rb +157 -0
  383. data/lib/generators/ruby_cms/templates/nav/analytics.rb +3 -0
  384. data/lib/generators/ruby_cms/templates/nav/audit_log.rb +3 -0
  385. data/lib/generators/ruby_cms/templates/nav/commands.rb +3 -0
  386. data/lib/generators/ruby_cms/templates/nav/content_blocks.rb +3 -0
  387. data/lib/generators/ruby_cms/templates/nav/core.rb +13 -0
  388. data/lib/generators/ruby_cms/templates/nav/media.rb +3 -0
  389. data/lib/generators/ruby_cms/templates/nav/permissions.rb +3 -0
  390. data/lib/generators/ruby_cms/templates/nav/redirects.rb +3 -0
  391. data/lib/generators/ruby_cms/templates/nav/security.rb +4 -0
  392. data/lib/generators/ruby_cms/templates/nav/system_health.rb +3 -0
  393. data/lib/generators/ruby_cms/templates/nav/trash.rb +3 -0
  394. data/lib/generators/ruby_cms/templates/nav/users.rb +3 -0
  395. data/lib/generators/ruby_cms/templates/nav/visual_editor.rb +3 -0
  396. data/lib/generators/ruby_cms/templates/routes/analytics.rb +5 -0
  397. data/lib/generators/ruby_cms/templates/routes/audit_log.rb +3 -0
  398. data/lib/generators/ruby_cms/templates/routes/auth.public.rb +4 -0
  399. data/lib/generators/ruby_cms/templates/routes/auth.rb +6 -0
  400. data/lib/generators/ruby_cms/templates/routes/commands.rb +4 -0
  401. data/lib/generators/ruby_cms/templates/routes/content_blocks.rb +12 -0
  402. data/lib/generators/ruby_cms/templates/routes/core.public.rb +5 -0
  403. data/lib/generators/ruby_cms/templates/routes/core.rb +16 -0
  404. data/lib/generators/ruby_cms/templates/routes/media.rb +9 -0
  405. data/lib/generators/ruby_cms/templates/routes/passkeys.public.rb +4 -0
  406. data/lib/generators/ruby_cms/templates/routes/passkeys.rb +5 -0
  407. data/lib/generators/ruby_cms/templates/routes/permissions.rb +5 -0
  408. data/lib/generators/ruby_cms/templates/routes/redirects.rb +10 -0
  409. data/lib/generators/ruby_cms/templates/routes/security.rb +20 -0
  410. data/lib/generators/ruby_cms/templates/routes/system_health.rb +3 -0
  411. data/lib/generators/ruby_cms/templates/routes/trash.rb +5 -0
  412. data/lib/generators/ruby_cms/templates/routes/users.rb +10 -0
  413. data/lib/generators/ruby_cms/templates/routes/visual_editor.rb +5 -0
  414. data/lib/generators/ruby_cms/templates/services/admin/health_check.rb +362 -0
  415. data/lib/generators/ruby_cms/templates/services/analytics/report.rb +503 -0
  416. data/lib/generators/ruby_cms/templates/services/analytics_service.rb +305 -0
  417. data/lib/generators/ruby_cms/templates/services/audit_log.rb +60 -0
  418. data/lib/generators/ruby_cms/templates/services/command_runner.rb +79 -0
  419. data/lib/generators/ruby_cms/templates/services/security_service.rb +203 -0
  420. data/lib/generators/ruby_cms/templates/services/security_tracker.rb +90 -0
  421. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/index.html.erb +61 -50
  422. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/page_details.html.erb +15 -10
  423. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_browser_device.html.erb +2 -2
  424. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_conversions.html.erb +3 -3
  425. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_daily_activity_chart.html.erb +18 -17
  426. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_exit_pages.html.erb +4 -4
  427. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_hourly_activity_chart.html.erb +18 -17
  428. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_landing_pages.html.erb +3 -3
  429. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_os_stats.html.erb +2 -2
  430. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_popular_pages.html.erb +4 -4
  431. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_recent_activity.html.erb +4 -4
  432. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_top_referrers.html.erb +3 -3
  433. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_top_visitors.html.erb +4 -4
  434. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_utm_sources.html.erb +2 -2
  435. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/visitor_details.html.erb +15 -10
  436. data/lib/generators/ruby_cms/templates/views/admin/audit_log_entries/_admin_table_content.html.erb +55 -0
  437. data/lib/generators/ruby_cms/templates/views/admin/audit_log_entries/_row.html.erb +84 -0
  438. data/lib/generators/ruby_cms/templates/views/admin/audit_log_entries/index.html.erb +33 -0
  439. data/lib/generators/ruby_cms/templates/views/admin/audit_log_entries/show.html.erb +89 -0
  440. data/lib/generators/ruby_cms/templates/views/admin/commands/index.html.erb +393 -0
  441. data/lib/generators/ruby_cms/templates/views/admin/content_block_versions/index.html.erb +63 -0
  442. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/content_block_versions/show.html.erb +2 -2
  443. data/lib/generators/ruby_cms/templates/views/admin/content_blocks/_audits.html.erb +49 -0
  444. data/lib/generators/ruby_cms/templates/views/admin/content_blocks/_form.html.erb +79 -0
  445. data/lib/generators/ruby_cms/templates/views/admin/content_blocks/_rich_field.html.erb +44 -0
  446. data/lib/generators/ruby_cms/templates/views/admin/content_blocks/_row.html.erb +60 -0
  447. data/lib/generators/ruby_cms/templates/views/admin/content_blocks/index.html.erb +84 -0
  448. data/lib/generators/ruby_cms/templates/views/admin/content_blocks/new.html.erb +18 -0
  449. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/content_blocks/show.html.erb +67 -61
  450. data/lib/generators/ruby_cms/templates/views/admin/dashboard/_gmail_token_status.html.erb +69 -0
  451. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/dashboard/blocks/_analytics_overview.html.erb +11 -11
  452. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/dashboard/blocks/_content_blocks_stats.html.erb +3 -3
  453. data/lib/generators/ruby_cms/templates/views/admin/dashboard/blocks/_notifications.html.erb +50 -0
  454. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/dashboard/blocks/_permissions_stats.html.erb +3 -3
  455. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/dashboard/blocks/_quick_actions.html.erb +13 -13
  456. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/dashboard/blocks/_recent_errors.html.erb +8 -8
  457. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/dashboard/blocks/_users_stats.html.erb +3 -3
  458. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/dashboard/blocks/_visitor_errors_stats.html.erb +3 -3
  459. data/lib/generators/ruby_cms/templates/views/admin/dashboard/index.html.erb +34 -0
  460. data/lib/generators/ruby_cms/templates/views/admin/media_assets/_admin_table_content.html.erb +107 -0
  461. data/lib/generators/ruby_cms/templates/views/admin/media_assets/_form.html.erb +33 -0
  462. data/lib/generators/ruby_cms/templates/views/admin/media_assets/_grid.html.erb +58 -0
  463. data/lib/generators/ruby_cms/templates/views/admin/media_assets/_list.html.erb +43 -0
  464. data/lib/generators/ruby_cms/templates/views/admin/media_assets/edit.html.erb +13 -0
  465. data/lib/generators/ruby_cms/templates/views/admin/media_assets/index.html.erb +36 -0
  466. data/lib/generators/ruby_cms/templates/views/admin/media_assets/show.html.erb +97 -0
  467. data/lib/generators/ruby_cms/templates/views/admin/passkey_credentials/index.html.erb +30 -0
  468. data/lib/generators/ruby_cms/templates/views/admin/passkey_registrations/new.html.erb +23 -0
  469. data/lib/generators/ruby_cms/templates/views/admin/permissions/_admin_table_content.html.erb +45 -0
  470. data/lib/generators/ruby_cms/templates/views/admin/permissions/_matrix.html.erb +75 -0
  471. data/lib/generators/ruby_cms/templates/views/admin/permissions/_row.html.erb +62 -0
  472. data/lib/generators/ruby_cms/templates/views/admin/permissions/index.html.erb +65 -0
  473. data/lib/generators/ruby_cms/templates/views/admin/redirects/_admin_table_content.html.erb +77 -0
  474. data/lib/generators/ruby_cms/templates/views/admin/redirects/_form.html.erb +97 -0
  475. data/lib/generators/ruby_cms/templates/views/admin/redirects/_row.html.erb +82 -0
  476. data/lib/generators/ruby_cms/templates/views/admin/redirects/edit.html.erb +21 -0
  477. data/lib/generators/ruby_cms/templates/views/admin/redirects/index.html.erb +40 -0
  478. data/lib/generators/ruby_cms/templates/views/admin/redirects/new.html.erb +12 -0
  479. data/lib/generators/ruby_cms/templates/views/admin/security/index.html.erb +88 -0
  480. data/lib/generators/ruby_cms/templates/views/admin/security/ip_blocklist_content.html.erb +3 -0
  481. data/lib/generators/ruby_cms/templates/views/admin/security/partials/_events_by_type.html.erb +24 -0
  482. data/lib/generators/ruby_cms/templates/views/admin/security/partials/_ip_blocklist.html.erb +37 -0
  483. data/lib/generators/ruby_cms/templates/views/admin/security/partials/_ip_blocklist_content.html.erb +41 -0
  484. data/lib/generators/ruby_cms/templates/views/admin/security/partials/_ip_management.html.erb +11 -0
  485. data/lib/generators/ruby_cms/templates/views/admin/security/partials/_recent_events.html.erb +59 -0
  486. data/lib/generators/ruby_cms/templates/views/admin/security/partials/_top_threat_ips.html.erb +21 -0
  487. data/lib/generators/ruby_cms/templates/views/admin/settings/index.html.erb +509 -0
  488. data/lib/generators/ruby_cms/templates/views/admin/shared/_add_button.html.erb +15 -0
  489. data/lib/generators/ruby_cms/templates/views/admin/shared/_data_table.html.erb +255 -0
  490. data/lib/generators/ruby_cms/templates/views/admin/shared/_turbo_pagination.html.erb +53 -0
  491. data/lib/generators/ruby_cms/templates/views/admin/system_health/index.html.erb +248 -0
  492. data/lib/generators/ruby_cms/templates/views/admin/trash/index.html.erb +58 -0
  493. data/lib/generators/ruby_cms/templates/views/admin/user_permissions/_row.html.erb +29 -0
  494. data/lib/generators/ruby_cms/templates/views/admin/user_permissions/index.html.erb +78 -0
  495. data/lib/generators/ruby_cms/templates/views/admin/users/_admin_table_content.html.erb +50 -0
  496. data/lib/generators/ruby_cms/templates/views/admin/users/_invite_form.html.erb +43 -0
  497. data/lib/generators/ruby_cms/templates/views/admin/users/_invites_panel.html.erb +91 -0
  498. data/lib/generators/ruby_cms/templates/views/admin/users/_row.html.erb +109 -0
  499. data/lib/generators/ruby_cms/templates/views/admin/users/index.html.erb +43 -0
  500. data/lib/generators/ruby_cms/templates/views/admin/users/show.html.erb +343 -0
  501. data/lib/generators/ruby_cms/templates/views/admin/visitor_errors/_admin_table_content.html.erb +61 -0
  502. data/lib/generators/ruby_cms/templates/views/admin/visitor_errors/_row.html.erb +90 -0
  503. data/lib/generators/ruby_cms/templates/views/admin/visitor_errors/index.html.erb +18 -0
  504. data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/visitor_errors/show.html.erb +4 -4
  505. data/lib/generators/ruby_cms/templates/views/admin/visual_editor/index.html.erb +383 -0
  506. data/{app/views/layouts/ruby_cms → lib/generators/ruby_cms/templates/views/layouts/admin}/_admin_flash_messages.html.erb +3 -3
  507. data/{app/views/layouts/ruby_cms → lib/generators/ruby_cms/templates/views/layouts/admin}/_admin_sidebar.html.erb +47 -48
  508. data/lib/generators/ruby_cms/templates/views/layouts/admin/_command_palette.html.erb +65 -0
  509. data/lib/generators/ruby_cms/templates/views/layouts/admin/_shortcuts_overlay.html.erb +81 -0
  510. data/lib/generators/ruby_cms/templates/views/layouts/admin/_topbar_widgets.html.erb +9 -0
  511. data/lib/generators/ruby_cms/templates/views/layouts/admin/minimal.html.erb +71 -0
  512. data/lib/generators/ruby_cms/templates/views/layouts/admin/topbar/_bell.html.erb +81 -0
  513. data/lib/generators/ruby_cms/templates/views/layouts/admin/topbar/_profile_menu.html.erb +86 -0
  514. data/lib/generators/ruby_cms/templates/views/layouts/admin/topbar/_search_trigger.html.erb +9 -0
  515. data/lib/generators/ruby_cms/templates/views/layouts/admin/topbar/_shortcuts_button.html.erb +8 -0
  516. data/lib/generators/ruby_cms/templates/views/shared/_maintenance_banner.html.erb +10 -0
  517. data/lib/ruby_cms/app_wiring.rb +56 -0
  518. data/lib/ruby_cms/auth_wiring.rb +64 -0
  519. data/lib/ruby_cms/cli.rb +181 -121
  520. data/lib/ruby_cms/excludes.rb +41 -0
  521. data/lib/ruby_cms/file_installer.rb +41 -0
  522. data/lib/ruby_cms/gem_setup.rb +113 -0
  523. data/lib/ruby_cms/helper_wiring.rb +32 -0
  524. data/lib/ruby_cms/importmap_wiring.rb +41 -0
  525. data/lib/ruby_cms/installer.rb +133 -0
  526. data/lib/ruby_cms/lockfile.rb +49 -0
  527. data/lib/ruby_cms/manifest.rb +88 -0
  528. data/lib/ruby_cms/manifest_data.rb +233 -0
  529. data/lib/ruby_cms/migration_installer.rb +64 -0
  530. data/lib/ruby_cms/nav_assembler.rb +43 -0
  531. data/lib/ruby_cms/passkey_wiring.rb +42 -0
  532. data/lib/ruby_cms/path_map.rb +26 -0
  533. data/lib/ruby_cms/routes_assembler.rb +103 -0
  534. data/lib/ruby_cms/syncer.rb +81 -0
  535. data/lib/ruby_cms/updater.rb +76 -0
  536. data/lib/ruby_cms/version.rb +1 -1
  537. data/lib/ruby_cms.rb +4 -328
  538. metadata +606 -170
  539. data/.cursor/dhh.mdc +0 -698
  540. data/app/components/ruby_cms/admin/admin_page/admin_table_content.rb +0 -32
  541. data/app/components/ruby_cms/admin/admin_page.rb +0 -345
  542. data/app/components/ruby_cms/admin/admin_page_header.rb +0 -79
  543. data/app/components/ruby_cms/admin/admin_resource_card.rb +0 -55
  544. data/app/components/ruby_cms/admin/base_component.rb +0 -78
  545. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table.rb +0 -157
  546. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_actions.rb +0 -127
  547. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_body.rb +0 -15
  548. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_checkbox_cell.rb +0 -43
  549. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_checkbox_head.rb +0 -35
  550. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_delete_modal.rb +0 -174
  551. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_header.rb +0 -59
  552. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_header_bar.rb +0 -169
  553. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_pagination.rb +0 -192
  554. data/app/components/ruby_cms/admin/bulk_action_table/bulk_action_table_row.rb +0 -96
  555. data/app/components/ruby_cms/admin/bulk_action_table/bulk_actions.rb +0 -196
  556. data/app/controllers/concerns/ruby_cms/admin_pagination.rb +0 -120
  557. data/app/controllers/concerns/ruby_cms/admin_turbo_table.rb +0 -68
  558. data/app/controllers/concerns/ruby_cms/page_tracking.rb +0 -67
  559. data/app/controllers/concerns/ruby_cms/visitor_error_capture.rb +0 -39
  560. data/app/controllers/ruby_cms/admin/analytics_controller.rb +0 -213
  561. data/app/controllers/ruby_cms/admin/base_controller.rb +0 -132
  562. data/app/controllers/ruby_cms/admin/commands_controller.rb +0 -122
  563. data/app/controllers/ruby_cms/admin/content_block_versions_controller.rb +0 -62
  564. data/app/controllers/ruby_cms/admin/content_blocks_controller.rb +0 -391
  565. data/app/controllers/ruby_cms/admin/dashboard_controller.rb +0 -89
  566. data/app/controllers/ruby_cms/admin/locale_controller.rb +0 -21
  567. data/app/controllers/ruby_cms/admin/permissions_controller.rb +0 -66
  568. data/app/controllers/ruby_cms/admin/settings_controller.rb +0 -223
  569. data/app/controllers/ruby_cms/admin/user_permissions_controller.rb +0 -77
  570. data/app/controllers/ruby_cms/admin/users_controller.rb +0 -107
  571. data/app/controllers/ruby_cms/admin/visitor_errors_controller.rb +0 -89
  572. data/app/controllers/ruby_cms/admin/visual_editor_controller.rb +0 -345
  573. data/app/controllers/ruby_cms/errors_controller.rb +0 -35
  574. data/app/helpers/ruby_cms/admin/admin_page_helper.rb +0 -21
  575. data/app/helpers/ruby_cms/admin/bulk_action_table_helper.rb +0 -159
  576. data/app/helpers/ruby_cms/admin/dashboard_helper.rb +0 -20
  577. data/app/helpers/ruby_cms/application_helper.rb +0 -49
  578. data/app/helpers/ruby_cms/bulk_action_table_helper.rb +0 -151
  579. data/app/helpers/ruby_cms/content_blocks_helper.rb +0 -399
  580. data/app/helpers/ruby_cms/settings_helper.rb +0 -172
  581. data/app/javascript/controllers/ruby_cms/content_block_history_controller.js +0 -91
  582. data/app/javascript/controllers/ruby_cms/index.js +0 -117
  583. data/app/javascript/controllers/ruby_cms/mobile_menu_controller.js +0 -55
  584. data/app/javascript/controllers/ruby_cms/nav_order_sortable_controller.js +0 -192
  585. data/app/javascript/controllers/ruby_cms/visual_editor_controller.js +0 -325
  586. data/app/models/concerns/content_block/searchable.rb +0 -22
  587. data/app/models/ruby_cms/content_block.rb +0 -8
  588. data/app/models/ruby_cms/permission.rb +0 -57
  589. data/app/models/ruby_cms/permittable.rb +0 -37
  590. data/app/models/ruby_cms/preference.rb +0 -111
  591. data/app/models/ruby_cms/user_permission.rb +0 -12
  592. data/app/models/ruby_cms/visitor_error.rb +0 -109
  593. data/app/services/ruby_cms/analytics/report.rb +0 -512
  594. data/app/services/ruby_cms/command_runner.rb +0 -42
  595. data/app/services/ruby_cms/security_tracker.rb +0 -92
  596. data/app/views/admin/content_block_versions/index.html.erb +0 -52
  597. data/app/views/admin/content_block_versions/show.html.erb +0 -37
  598. data/app/views/layouts/ruby_cms/admin.html.erb +0 -77
  599. data/app/views/layouts/ruby_cms/minimal.html.erb +0 -181
  600. data/app/views/ruby_cms/_tailwind_safelist.html.erb +0 -2
  601. data/app/views/ruby_cms/admin/commands/index.html.erb +0 -104
  602. data/app/views/ruby_cms/admin/content_block_versions/index.html.erb +0 -52
  603. data/app/views/ruby_cms/admin/content_blocks/_form.html.erb +0 -92
  604. data/app/views/ruby_cms/admin/content_blocks/_row.html.erb +0 -25
  605. data/app/views/ruby_cms/admin/content_blocks/index.html.erb +0 -62
  606. data/app/views/ruby_cms/admin/content_blocks/new.html.erb +0 -10
  607. data/app/views/ruby_cms/admin/dashboard/index.html.erb +0 -31
  608. data/app/views/ruby_cms/admin/permissions/_row.html.erb +0 -11
  609. data/app/views/ruby_cms/admin/permissions/index.html.erb +0 -62
  610. data/app/views/ruby_cms/admin/settings/index.html.erb +0 -268
  611. data/app/views/ruby_cms/admin/shared/_bulk_action_table_index.html.erb +0 -56
  612. data/app/views/ruby_cms/admin/user_permissions/index.html.erb +0 -85
  613. data/app/views/ruby_cms/admin/users/_row.html.erb +0 -17
  614. data/app/views/ruby_cms/admin/users/index.html.erb +0 -70
  615. data/app/views/ruby_cms/admin/visitor_errors/_row.html.erb +0 -35
  616. data/app/views/ruby_cms/admin/visitor_errors/index.html.erb +0 -57
  617. data/app/views/ruby_cms/admin/visual_editor/index.html.erb +0 -157
  618. data/app/views/ruby_cms/errors/not_found.html.erb +0 -92
  619. data/config/database.yml +0 -6
  620. data/config/importmap.rb +0 -40
  621. data/config/locales/en.yml +0 -198
  622. data/config/locales/nl.yml +0 -156
  623. data/config/routes.rb +0 -76
  624. data/db/migrate/20260130000001_add_referer_and_query_to_ruby_cms_visitor_errors.rb +0 -8
  625. data/db/migrate/20260130000003_add_category_to_ruby_cms_preferences.rb +0 -8
  626. data/docs/assets/ruby_cms_logo.png +0 -0
  627. data/lib/generators/ruby_cms/install_generator.rb +0 -1159
  628. data/lib/ruby_cms/app_integration.rb +0 -82
  629. data/lib/ruby_cms/commands_registry.rb +0 -40
  630. data/lib/ruby_cms/css_compiler.rb +0 -35
  631. data/lib/ruby_cms/engine/admin_permissions.rb +0 -69
  632. data/lib/ruby_cms/engine/content_blocks_tasks.rb +0 -66
  633. data/lib/ruby_cms/engine/css.rb +0 -14
  634. data/lib/ruby_cms/engine/dashboard_registration.rb +0 -66
  635. data/lib/ruby_cms/engine/navigation_registration.rb +0 -90
  636. data/lib/ruby_cms/engine.rb +0 -273
  637. /data/{app → lib/generators/ruby_cms/templates}/assets/images/ruby_cms/logo.png +0 -0
  638. /data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260211000001_add_ruby_cms_analytics_fields_to_ahoy_events.rb +0 -0
  639. /data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260212000001_use_unprefixed_cms_tables.rb +0 -0
  640. /data/{db → lib/generators/ruby_cms/templates/db}/migrate/20260409000001_add_analytics_performance_indexes.rb +0 -0
  641. /data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/admin}/auto_save_preference_controller.js +0 -0
  642. /data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/admin}/locale_tabs_controller.js +0 -0
  643. /data/{app/javascript/controllers/ruby_cms → lib/generators/ruby_cms/templates/javascript/controllers/admin}/toggle_controller.js +0 -0
  644. /data/{app → lib/generators/ruby_cms/templates}/models/concerns/content_block/publishable.rb +0 -0
  645. /data/{app → lib/generators/ruby_cms/templates}/models/content_block_version.rb +0 -0
  646. /data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_back_button.html.erb +0 -0
  647. /data/{app/views/ruby_cms → lib/generators/ruby_cms/templates/views}/admin/analytics/partials/_security_alert.html.erb +0 -0
data/README.md CHANGED
@@ -1,21 +1,44 @@
1
1
  # RubyCMS
2
2
 
3
- Reusable Rails engine for a CMS-style admin: content blocks, visual editor, versioning, pluggable dashboard, permissions, analytics, and visitor error tracking.
3
+ Standalone CLI gem for a modular CMS-style admin: content blocks, visual editor, versioning, pluggable dashboard, permissions, analytics, and visitor error tracking.
4
4
 
5
- Your app owns product features (pages, models, business logic); RubyCMS manages content workflows and admin screens.
5
+ Your app owns product features (pages, models, business logic). RubyCMS scaffolds the admin layer into your codebase so you can customize everything without a runtime engine dependency.
6
+
7
+ ## How it works
8
+
9
+ RubyCMS is **install-only**. Running `ruby_cms install` (the CLI) copies controllers, views, models, helpers, JavaScript, and `lib/ruby_cms/` into your host app for whichever modules you select. After install you can remove the gem from your `Gemfile` — the app runs entirely on copied code.
10
+
11
+ | Layer | Location after install |
12
+ |-------|------------------------|
13
+ | Registries (nav, permissions, dashboard, settings, icons) | `lib/ruby_cms/` |
14
+ | Core configuration (`RubyCms.configure`, visual-editor preview) | `config/initializers/admin.rb` |
15
+ | Sidebar nav (generated from module fragments; user-editable) | `config/initializers/admin_nav.rb` |
16
+ | Dashboard blocks | `config/initializers/admin_dashboard.rb` |
17
+ | Admin controllers & views | `app/controllers/admin/`, `app/views/admin/` |
18
+ | UI components (Phlex / RubyUI) | `app/components/ruby_ui/admin_page/` |
19
+ | Rake tasks | `lib/tasks/ruby_cms.rake` |
20
+ | Module manifest / lockfile | `.ruby_cms.yml` |
21
+
22
+ Keep the gem in your `Gemfile` only when you need install/update commands:
23
+
24
+ ```ruby
25
+ # Uncomment temporarily for install or updates:
26
+ # gem "ruby_cms", path: "../gems/ruby_cms"
27
+ ```
6
28
 
7
29
  ## Features
8
30
 
9
- - **Content blocks** -- rich text, plain text, images, links, and lists with locale support
10
- - **Content block versioning** -- automatic version history with rollback and side-by-side diffs
11
- - **Visual editor** -- inline editing on live page previews
12
- - **Pluggable dashboard** -- registry-based blocks with permission gating and host-app extensibility
13
- - **Permissions** -- key-based access control with templates and per-user assignment
14
- - **Admin page generator** -- one command to scaffold a new admin page with nav, permission, and route
15
- - **Named icon registry** -- 20+ Heroicons by name, no SVG copy-pasting
16
- - **Settings** -- DB-backed admin settings with categories and UI
17
- - **Analytics** -- Ahoy-powered visit/event tracking with dashboard drill-downs
18
- - **Visitor error tracking** -- automatic 404/500 capture with admin overview
31
+ - **Content blocks** rich text, plain text, images, links, and lists with locale support
32
+ - **Content block versioning** automatic version history with rollback and side-by-side diffs
33
+ - **Visual editor** inline editing on live page previews
34
+ - **Pluggable dashboard** registry-based blocks with permission gating and host-app extensibility
35
+ - **Permissions** key-based access control with templates and per-user assignment
36
+ - **Admin page generator** one command to scaffold a new admin page with nav, permission, and route
37
+ - **Named icon registry** 20+ Heroicons by name, no SVG copy-pasting
38
+ - **Settings** DB-backed admin settings with categories and UI
39
+ - **Analytics** Ahoy-powered visit/event tracking with dashboard drill-downs
40
+ - **Visitor error tracking** automatic 404/500 capture with admin overview
41
+ - **Admin UI components** — reusable `AdminPage`, `AdminPageHeader`, `AdminTableContent`, and `AdminResourceCard` (RubyUI / Phlex)
19
42
 
20
43
  ## Quick Start
21
44
 
@@ -23,17 +46,89 @@ Your app owns product features (pages, models, business logic); RubyCMS manages
23
46
  # Add to Gemfile
24
47
  gem "ruby_cms"
25
48
 
26
- # Install
27
- rails g ruby_cms:install
49
+ bundle install
50
+ ruby_cms install # interactive module picker
51
+ ruby_cms install --modules media,redirects # non-interactive
28
52
  rails db:migrate
29
53
  rails ruby_cms:seed_permissions
30
54
  rails ruby_cms:setup_admin
31
55
  ```
32
56
 
33
- The install generator sets up the initializer, mounts the engine at `/admin`, runs migrations, configures Tailwind, Stimulus, Action Text, and Ahoy.
57
+ The `ruby_cms install` CLI:
58
+
59
+ - Copies admin scaffold into `app/` and `lib/ruby_cms/` for selected modules
60
+ - Creates `config/initializers/admin.rb` (`RubyCms.configure` block + visual-editor preview setup)
61
+ - Generates `config/initializers/admin_nav.rb` (sidebar nav assembled from per-module fragments)
62
+ - Creates `config/initializers/admin_dashboard.rb` (dashboard blocks)
63
+ - Seeds module permissions from the manifest — no manual `register_permission_keys` needed
64
+ - Adds `namespace :admin` routes (no engine mount)
65
+ - Configures Tailwind, Stimulus, Action Text, and Ahoy
66
+ - Records installed modules in `.ruby_cms.yml`
34
67
 
35
68
  Visit `/admin` and sign in with the admin user you configured.
36
69
 
70
+ ### Adding a module later
71
+
72
+ ```bash
73
+ ruby_cms install --add media
74
+ ```
75
+
76
+ This copies the module files, seeds its permissions, and appends its nav fragment to `config/initializers/admin_nav.rb`.
77
+
78
+ ### Pulling updates from the gem
79
+
80
+ ```bash
81
+ # Re-add gem to Gemfile, then:
82
+ ruby_cms update # updates only modules in .ruby_cms.yml
83
+ ruby_cms update --only=mod1,mod2
84
+ ruby_cms update --dry-run
85
+ ```
86
+
87
+ Only changed files are overwritten. Review diffs before committing. `config/initializers/admin_nav.rb` is regenerated on every install/update, so custom sidebar entries belong in `config/initializers/admin_pages.rb` (where `rails g ruby_cms:admin_page` writes them) — that file is never touched by the gem.
88
+
89
+ ## Admin UI components
90
+
91
+ Admin views use Phlex components under `app/components/ruby_ui/admin_page/` (registered as `AdminPage`, `AdminPageHeader`, etc. via the RubyUI kit).
92
+
93
+ | Component | Purpose |
94
+ |-----------|---------|
95
+ | `RubyUI::AdminPage` | White card wrapper; optional `turbo_frame:` for full-page Turbo updates |
96
+ | `RubyUI::AdminPageHeader` | Breadcrumbs, title, subtitle, action slot |
97
+ | `RubyUI::AdminTableContent` | Turbo Frame (`id: "admin_table_content"`) for pagination, filters, search |
98
+ | `RubyUI::AdminResourceCard` | Layout constants for show/edit pages (grid, sidebar, form classes) |
99
+
100
+ ### Usage in views
101
+
102
+ ```erb
103
+ <%= AdminPage do %>
104
+ <%= AdminPageHeader(
105
+ title: "Users",
106
+ breadcrumbs: [
107
+ { label: "Admin", url: admin_root_path },
108
+ { label: "Users" }
109
+ ]
110
+ ) do %>
111
+ <%= link_to "New user", new_admin_user_path, class: "..." %>
112
+ <% end %>
113
+
114
+ <%= admin_table_content do %>
115
+ <%# table rows, pagination — replaces frame on Turbo navigation %>
116
+ <% end %>
117
+ <% end %>
118
+ ```
119
+
120
+ `admin_table_content` is provided by `Admin::AdminPageHelper`.
121
+
122
+ For resource show pages, use `RubyUI::AdminResourceCard` constants:
123
+
124
+ ```erb
125
+ <div class="<%= RubyUI::AdminResourceCard::CARD_CLASS %>">
126
+ <div class="<%= RubyUI::AdminResourceCard::GRID_CLASS %>">
127
+ ...
128
+ </div>
129
+ </div>
130
+ ```
131
+
37
132
  ## Content Blocks
38
133
 
39
134
  Use the `content_block` helper in any view:
@@ -133,12 +228,13 @@ POST /admin/content_blocks/:id/versions/:vid/rollback
133
228
 
134
229
  ## Visual Editor
135
230
 
136
- Configure preview templates in `config/initializers/ruby_cms.rb`:
231
+ Configure preview templates in `config/initializers/admin.rb`:
137
232
 
138
233
  ```ruby
139
234
  RubyCms.configure do |c|
140
235
  c.preview_templates = { "home" => "pages/home", "about" => "pages/about" }
141
- c.preview_data = ->(page_key, view) { { products: Product.limit(5) } }
236
+ c.preview_data = ->(page_key, view, variant = nil) { { products: Product.limit(5) } }
237
+ c.preview_variants = ->(page_key) { [] }
142
238
  end
143
239
  ```
144
240
 
@@ -150,67 +246,71 @@ The dashboard uses a registry-based block system. Each block is a partial with o
150
246
 
151
247
  ### Default Blocks
152
248
 
249
+ Register defaults in `config/initializers/admin_dashboard.rb` (generated at install with CMS stats blocks; customize for your app):
250
+
153
251
  | Block | Section | Permission |
154
252
  |-------|---------|------------|
155
253
  | Content blocks stats | stats | `manage_content_blocks` |
156
254
  | Users stats | stats | `manage_permissions` |
157
255
  | Permissions stats | stats | `manage_permissions` |
158
256
  | Visitor errors stats | stats | `manage_visitor_errors` |
159
- | Quick actions | main | -- |
257
+ | Quick actions | main | |
160
258
  | Recent errors | main | `manage_visitor_errors` |
161
259
  | Analytics overview | main | `manage_analytics` |
162
260
 
163
261
  ### Adding Custom Blocks
164
262
 
165
263
  ```ruby
166
- # config/initializers/ruby_cms.rb (or ruby_cms_pages.rb)
167
- Rails.application.config.to_prepare do
168
- RubyCms.dashboard_register(
169
- key: :orders_stats,
170
- label: "Orders",
171
- section: :stats, # :stats (top row) or :main (bottom grid)
172
- order: 5,
173
- partial: "admin/dashboard/orders_stats",
174
- permission: :manage_orders,
175
- span: :single, # :single or :double (grid width)
176
- data: ->(controller) {
177
- { count: Order.count, today: Order.where("created_at > ?", Date.today).count }
178
- }
179
- )
180
- end
264
+ # config/initializers/admin_dashboard.rb
265
+ RubyCms.dashboard_register(
266
+ key: :orders_stats,
267
+ label: "Orders",
268
+ section: :stats, # :stats (top row) or :main (bottom grid)
269
+ order: 5,
270
+ partial: "admin/dashboard/blocks/orders_stats",
271
+ permission: :manage_orders,
272
+ span: :single, # :single or :double (grid width)
273
+ data: ->(controller) {
274
+ { count: Order.count, today: Order.where("created_at > ?", Date.today).count }
275
+ }
276
+ )
181
277
  ```
182
278
 
183
- Then create the partial `app/views/admin/dashboard/_orders_stats.html.erb`. The `block` local contains the registration data and any computed `data`.
279
+ Then create the partial `app/views/admin/dashboard/blocks/_orders_stats.html.erb`. The `block` local contains the registration data and any computed `data`.
184
280
 
185
281
  ### Overriding Default Blocks
186
282
 
187
- Re-register with the same key to override:
283
+ Re-register with the same key to override (in `config/initializers/admin_dashboard.rb`):
188
284
 
189
285
  ```ruby
190
286
  RubyCms.dashboard_register(
191
287
  key: :quick_actions,
192
288
  label: "Quick actions",
193
289
  section: :main,
194
- partial: "admin/dashboard/my_quick_actions" # your own partial
290
+ partial: "admin/dashboard/my_quick_actions"
195
291
  )
196
292
  ```
197
293
 
198
294
  ## Navigation and Permissions
199
295
 
296
+ Navigation registration lives in **`config/initializers/admin_nav.rb`** (generated at install/add from per-module fragments; safe to edit manually). Permission keys are declared in the gem's manifest (`lib/ruby_cms/manifest.rb`) and seeded automatically at install — you do not need to call `register_permission_keys` for built-in modules. Register additional app-specific keys in `config/initializers/admin_nav.rb` or any initializer.
297
+
200
298
  ### register_page (recommended)
201
299
 
202
- One call to register a nav item and its permission:
300
+ One call to register a nav item and its permission. Place in `config/initializers/admin_nav.rb` (or any initializer):
203
301
 
204
302
  ```ruby
205
- RubyCms.register_page(
206
- key: :backups,
207
- label: "Backups",
208
- path: :admin_backups_path, # Symbol: auto-wrapped via main_app
209
- icon: :archive_box, # Named icon from RubyCms::Icons
210
- section: :main, # :main (sidebar top) or :settings (sidebar bottom)
211
- permission: :manage_backups, # Auto-registered as permission key
212
- order: 10
213
- )
303
+ Rails.application.config.to_prepare do
304
+ RubyCms.register_page(
305
+ key: :backups,
306
+ label: "Backups",
307
+ path: ->(view) { view.admin_backups_path },
308
+ icon: :archive_box,
309
+ section: :main,
310
+ permission: :manage_backups,
311
+ order: 10
312
+ )
313
+ end
214
314
  ```
215
315
 
216
316
  ### nav_register (low-level)
@@ -231,8 +331,6 @@ RubyCms.nav_register(
231
331
 
232
332
  ### nav_group (accordion)
233
333
 
234
- Define a sidebar accordion group in the same config file as your pages:
235
-
236
334
  ```ruby
237
335
  RubyCms.nav_group(
238
336
  key: :operations,
@@ -240,9 +338,7 @@ RubyCms.nav_group(
240
338
  icon: :folder,
241
339
  section: "main",
242
340
  order: 20,
243
- # Optional: the group can have its own page
244
- path: ->(view) { view.main_app.admin_operations_path },
245
- # Child pages are referenced by the keys you used in register_page/nav_register
341
+ path: ->(view) { view.admin_operations_path },
246
342
  children: %i[backups reports]
247
343
  )
248
344
  ```
@@ -254,7 +350,7 @@ Groups are hidden automatically when they have no visible children and no `path`
254
350
  | Format | Example | Behavior |
255
351
  |--------|---------|----------|
256
352
  | Symbol | `:admin_backups_path` | Auto-wrapped: `view.main_app.send(:admin_backups_path)` |
257
- | Lambda | `-> (v) { v.some_path }` | Called with view context |
353
+ | Lambda | `->(view) { view.admin_backups_path }` | Called with view context |
258
354
  | String | `"/admin/backups"` | Used as-is |
259
355
 
260
356
  ### Named Icons
@@ -263,19 +359,16 @@ Use symbol keys from `RubyCms::Icons`:
263
359
 
264
360
  ```ruby
265
361
  RubyCms::Icons.available
266
- # => [:home, :pencil_square, :document_duplicate, :chart_bar, :shield_check,
267
- # :exclamation_triangle, :user_group, :cog_6_tooth, :archive_box, :folder,
268
- # :bell, :clock, :tag, :cube, :envelope, :wrench, :globe, :photograph,
269
- # :list_bullet, :plus_circle, :trash, :eye, :lock_closed, :currency_dollar]
362
+ # => [:home, :pencil_square, :document_duplicate, :chart_bar, :shield_check, ...]
270
363
  ```
271
364
 
272
365
  Raw SVG strings are also accepted for custom icons.
273
366
 
274
367
  ### Permission Keys
275
368
 
276
- Default keys: `manage_admin`, `manage_permissions`, `manage_content_blocks`, `manage_visitor_errors`, `manage_analytics`.
369
+ Built-in module permission keys (e.g. `manage_admin`, `manage_permissions`, `manage_content_blocks`, `manage_visitor_errors`, `manage_analytics`) are declared in the gem manifest and seeded automatically at install.
277
370
 
278
- Register additional keys:
371
+ Register additional app-specific keys in any initializer (e.g. `config/initializers/admin_nav.rb`):
279
372
 
280
373
  ```ruby
281
374
  RubyCms.register_permission_keys(:manage_orders, :manage_reports)
@@ -283,8 +376,6 @@ RubyCms.register_permission_keys(:manage_orders, :manage_reports)
283
376
 
284
377
  ### Permission Templates
285
378
 
286
- Group permission keys into reusable templates:
287
-
288
379
  ```ruby
289
380
  RubyCms.register_permission_template(:editor,
290
381
  label: "Editor",
@@ -292,17 +383,16 @@ RubyCms.register_permission_template(:editor,
292
383
  description: "Can manage content but not users"
293
384
  )
294
385
 
295
- # Apply to a user:
296
386
  RubyCms::Permission.apply_template!(user, :editor)
297
387
  ```
298
388
 
299
389
  ### cms_page Macro
300
390
 
301
- In controllers that inherit from `RubyCms::Admin::BaseController`, use `cms_page` to link to a registered page. The permission is looked up from the nav registry automatically:
391
+ In controllers under `Admin::ApplicationController`, use `cms_page` to enforce the permission from `register_page`:
302
392
 
303
393
  ```ruby
304
- class Admin::BackupsController < RubyCms::Admin::BaseController
305
- cms_page :backups # permission from register_page(:backups, permission: :manage_backups)
394
+ class Admin::BackupsController < Admin::ApplicationController
395
+ cms_page :backups
306
396
 
307
397
  def index
308
398
  @backups = Backup.recent
@@ -312,49 +402,50 @@ end
312
402
 
313
403
  ## Admin Page Generator
314
404
 
315
- Scaffold a complete admin page with one command:
405
+ Scaffold a complete admin page controller, data-table index, form and routes —
406
+ that follows the same conventions as the built-in modules. Pass optional
407
+ `field:type` pairs (type defaults to `string`) to scaffold the columns:
316
408
 
317
409
  ```bash
318
- rails g ruby_cms:admin_page backups
410
+ rails g ruby_cms:admin_page product name:string price:decimal published:boolean
319
411
  ```
320
412
 
321
413
  This generates:
322
414
 
323
415
  | File | Description |
324
416
  |------|-------------|
325
- | `app/controllers/admin/backups_controller.rb` | Controller with `cms_page :backups` |
326
- | `app/views/admin/backups/index.html.erb` | View template |
327
- | `config/routes.rb` | Route injection (`namespace :admin`) |
328
- | `config/initializers/ruby_cms_pages.rb` | `register_page` call |
417
+ | `app/controllers/admin/products_controller.rb` | Full CRUD controller on the shared concern stack (pagination, turbo tables, bulk delete, audit) |
418
+ | `app/views/admin/products/index.html.erb` | `AdminPage` + `AdminPageHeader` with a `data_table` |
419
+ | `app/views/admin/products/_admin_table_content.html.erb` | The data-table partial (headers from your fields) |
420
+ | `app/views/admin/products/_row.html.erb` | Row cells per field |
421
+ | `app/views/admin/products/_form.html.erb`, `new`, `edit` | Form scaffolded from your fields |
422
+ | `config/routes.rb` | `resources :products` (with `bulk_delete`) in `namespace :admin` |
423
+ | `config/initializers/admin_pages.rb` | Sidebar registration via `RubyCms.register_page` (host-owned — never overwritten by `ruby_cms update`) |
329
424
 
330
425
  ### Options
331
426
 
332
427
  ```bash
333
- rails g ruby_cms:admin_page backups \
334
- --permission=manage_backups \
335
- --icon=archive_box \
336
- --section=settings \
337
- --order=15
428
+ rails g ruby_cms:admin_page report --read-only --section=settings --icon=chart_bar --order=15
338
429
  ```
339
430
 
340
431
  | Option | Default | Description |
341
432
  |--------|---------|-------------|
342
- | `--permission` | `manage_<name>` | Permission key |
343
- | `--icon` | `folder` | Icon from `RubyCms::Icons` |
433
+ | `--permission` | `manage_<plural>` | Permission key |
434
+ | `--icon` | `folder` | Icon from `RubyCms::Icons` (`RubyCms::Icons.available`) |
344
435
  | `--section` | `main` | `main` or `settings` |
345
436
  | `--order` | `10` | Sort order in nav |
437
+ | `--read-only` | `false` | Index-only page (no form/create/update/destroy) |
438
+ | `--skip-route` | `false` | Don't touch `config/routes.rb` |
439
+ | `--skip-nav` | `false` | Don't register the page in the sidebar |
346
440
 
347
441
  After generating, run `rails ruby_cms:seed_permissions` to create the permission row in the database.
348
442
 
349
443
  ## Settings
350
444
 
351
- RubyCMS uses DB-backed settings with a registry for defaults and types:
445
+ DB-backed settings with a registry for defaults and types:
352
446
 
353
447
  ```ruby
354
- # Read
355
448
  RubyCms::Settings.get(:analytics_default_period, default: "week")
356
-
357
- # Write (admin UI or programmatic)
358
449
  RubyCms::Settings.set(:analytics_default_period, "month")
359
450
  ```
360
451
 
@@ -374,7 +465,7 @@ Settings are managed in **Admin > Settings** with tabs per category.
374
465
 
375
466
  ## Visitor Error Tracking
376
467
 
377
- Public exceptions are automatically captured when `RubyCms::VisitorErrorCapture` is included in your `ApplicationController` (added by the install generator).
468
+ Public exceptions are captured when `VisitorErrorCapture` is included in your `ApplicationController` (added by the install generator).
378
469
 
379
470
  View captured errors in **Admin > Visitor errors** with status codes, paths, timestamps, and resolution tracking.
380
471
 
@@ -382,22 +473,20 @@ View captured errors in **Admin > Visitor errors** with status codes, paths, tim
382
473
 
383
474
  RubyCMS integrates with Ahoy for server-side page view and event tracking.
384
475
 
385
- Include `RubyCms::PageTracking` in public controllers:
476
+ Include `PageTracking` in public controllers:
386
477
 
387
478
  ```ruby
388
479
  class PagesController < ApplicationController
389
- include RubyCms::PageTracking
480
+ include PageTracking
390
481
  end
391
482
  ```
392
483
 
393
- View analytics in **Admin > Analytics** with:
394
- - Visit and event counts
395
- - Popular pages
396
- - Top visitors
397
- - Configurable date ranges and periods
484
+ View analytics in **Admin > Analytics** with visit/event counts, popular pages, top visitors, and configurable date ranges.
398
485
 
399
486
  ### Customization Hooks
400
487
 
488
+ Place these in `config/initializers/admin.rb` inside the `RubyCms.configure` block:
489
+
401
490
  ```ruby
402
491
  RubyCms.configure do |c|
403
492
  c.analytics_visit_scope = ->(scope) { scope.where.not(ip: ["127.0.0.1"]) }
@@ -410,147 +499,193 @@ end
410
499
 
411
500
  ## Seeding Content Blocks from YAML
412
501
 
413
- Set the translation namespace:
414
-
415
502
  ```ruby
503
+ # config/initializers/admin.rb
416
504
  RubyCms.configure do |c|
417
505
  c.content_blocks_translation_namespace = "content_blocks"
418
506
  end
419
507
  ```
420
508
 
421
- Create locale files:
422
-
423
509
  ```yaml
424
510
  # config/locales/en.yml
425
511
  en:
426
512
  content_blocks:
427
513
  hero_title: "Welcome to my site"
428
- footer_text: "Copyright 2026"
429
514
  ```
430
515
 
431
- Import:
432
-
433
516
  ```bash
434
517
  rails ruby_cms:content_blocks:import
435
- ```
436
-
437
- Export DB content blocks back to YAML:
438
-
439
- ```bash
440
518
  rails ruby_cms:content_blocks:export
441
519
  ```
442
520
 
443
521
  ## Configuration
444
522
 
445
- All configuration happens in `config/initializers/ruby_cms.rb`:
523
+ Configuration is split across three generated files. All are plain Ruby initializers — edit them freely.
524
+
525
+ ### `config/initializers/admin.rb`
526
+
527
+ `RubyCms.configure` options plus visual-editor preview setup:
446
528
 
447
529
  ```ruby
530
+ # config/initializers/admin.rb
531
+
448
532
  RubyCms.configure do |c|
449
- # Base controller (must provide current_user + authentication)
450
533
  c.admin_base_controller = "ApplicationController"
451
-
452
- # Admin layout
453
534
  c.admin_layout = "admin/admin"
454
-
455
- # User model class name
456
535
  c.user_class_name = "User"
457
-
458
- # Allow user.admin? bypass when no Permission records exist
459
536
  c.bootstrap_admin_with_role = true
460
-
461
- # Redirect path for unauthenticated/unauthorized users
462
537
  c.unauthorized_redirect_path = "/"
463
-
464
- # Visual editor
465
538
  c.preview_templates = { "home" => "pages/home" }
466
- c.preview_data = ->(page_key, view) { {} }
467
-
468
- # Content blocks
539
+ c.preview_data = ->(page_key, _view, _variant = nil) { {} }
469
540
  c.content_blocks_translation_namespace = "content_blocks"
470
541
  c.image_content_types = %w[image/png image/jpeg image/gif image/webp]
471
542
  c.image_max_size = 5 * 1024 * 1024
472
543
  end
473
544
  ```
474
545
 
546
+ ### `config/initializers/admin_nav.rb`
547
+
548
+ Sidebar nav entries. Generated from per-module nav fragments at `ruby_cms install` / `ruby_cms install --add`. Safe to edit by hand; note it is **regenerated** (fragments appended) when you add a new module.
549
+
550
+ ```ruby
551
+ # config/initializers/admin_nav.rb
552
+
553
+ Rails.application.config.to_prepare do
554
+ RubyCms.register_page(key: :dashboard, ...)
555
+ RubyCms.nav_group(key: :content, ...)
556
+ # app-specific extra pages:
557
+ RubyCms.register_permission_keys(:manage_orders)
558
+ RubyCms.register_page(key: :orders, ...)
559
+ end
560
+ ```
561
+
562
+ ### `config/initializers/admin_dashboard.rb`
563
+
564
+ Dashboard block registrations:
565
+
566
+ ```ruby
567
+ # config/initializers/admin_dashboard.rb
568
+
569
+ RubyCms.dashboard_register(key: :orders_stats, ...)
570
+ ```
571
+
572
+ ### Boot initializers
573
+
574
+ | File | Role |
575
+ |------|------|
576
+ | `config/initializers/admin.rb` | `RubyCms.configure` + visual-editor preview (generated at install) |
577
+ | `config/initializers/admin_nav.rb` | Sidebar nav (generated from module fragments at install/add) |
578
+ | `config/initializers/admin_dashboard.rb` | Dashboard block registrations |
579
+ | `config/initializers/ruby_cms_core.rb` | Boot hooks: versionable concern, settings import, permission rows |
580
+
581
+ ### `config/application.rb`
582
+
583
+ After install, require the runtime module before the application class:
584
+
585
+ ```ruby
586
+ require_relative "../lib/ruby_cms"
587
+ ```
588
+
589
+ `lib/ruby_cms.rb` eager-loads `lib/ruby_cms/*.rb` so registries are available during boot.
590
+
475
591
  ## Rake Tasks
476
592
 
593
+ Copied to `lib/tasks/ruby_cms.rake` in the host app:
594
+
477
595
  | Task | Description |
478
596
  |------|-------------|
479
597
  | `ruby_cms:seed_permissions` | Create default permission rows + settings |
480
598
  | `ruby_cms:setup_admin` | Interactive first admin user setup |
481
- | `ruby_cms:grant_manage_admin` | Grant all permissions to a user by email |
599
+ | `ruby_cms:grant_manage_admin[email]` | Grant all permissions to a user by email |
482
600
  | `ruby_cms:content_blocks:export` | Export DB content blocks to YAML |
483
601
  | `ruby_cms:content_blocks:import` | Import content blocks from YAML |
484
602
  | `ruby_cms:content_blocks:sync` | Export + optional import |
485
603
  | `ruby_cms:import_initializer_settings` | Import initializer values into DB settings |
486
- | `ruby_cms:css:compile` | Compile admin CSS to host app |
487
- | `ruby_cms:css:compile_gem` | Compile admin CSS within the gem |
488
604
 
489
605
  ## Development
490
606
 
491
- ### Setup
607
+ ### Gem repository
608
+
609
+ This repository holds **generator templates** under `lib/generators/ruby_cms/templates/`. The published gem defines only `RubyCms::VERSION` in `lib/ruby_cms.rb` — no runtime engine.
492
610
 
493
611
  ```bash
494
612
  git clone https://github.com/jobhammer00/ruby_cms.git
495
613
  cd ruby_cms
496
614
  bundle install
497
- ```
498
-
499
- ### Running Tests
500
-
501
- ```bash
502
615
  bundle exec rspec
503
616
  ```
504
617
 
505
- Tests use an in-memory SQLite database via `spec/support/dummy_app.rb`. No separate dummy Rails app directory is needed.
618
+ ### Syncing changes from a host app
506
619
 
507
- ### CSS Compilation
620
+ When developing against a reference app (e.g. portfolio), push host-app edits back into gem templates using the `ruby_cms sync` CLI (run from the gem repo):
508
621
 
509
622
  ```bash
510
- rails ruby_cms:css:compile_gem
623
+ ruby_cms sync # default source: ../portfolio
624
+ ruby_cms sync --from ../gvexcelsior
625
+ ruby_cms sync --from ../gvexcelsior --dry-run
626
+ ruby_cms sync --from ../gvexcelsior --include-new # also add brand-new gem files
511
627
  ```
512
628
 
513
- ### Faster Docker Builds (`assets:precompile`)
514
-
515
- `assets:precompile` loads the Rails app in production mode and can be slow in Docker/Fly builds.
516
- RubyCMS now skips non-asset runtime initializers during this phase (navigation registration,
517
- dashboard registration, versioning hook, settings import, and permission seeding), which reduces
518
- precompile overhead.
629
+ This is the reverse of `ruby_cms update`. By default sync only **updates files the gem already ships** — manifest globs like `helpers/**/*` also match app-specific files (a public-site helper, a marketing Stimulus controller) that the gem doesn't own, and absorbing those would pollute it. New matches are skipped and listed; pass `--include-new` to pull them in deliberately when you really are adding a file to the gem.
519
630
 
520
- Recommended Docker layer order:
631
+ ### Architecture (after install)
521
632
 
522
- 1. Copy `Gemfile` / `Gemfile.lock`
523
- 2. Run `bundle install`
524
- 3. Copy app source
525
- 4. Run `SECRET_KEY_BASE=DUMMY bin/rails assets:precompile`
633
+ ```
634
+ config/initializers/
635
+ admin.rb # RubyCms.configure + visual-editor preview
636
+ admin_nav.rb # Sidebar nav (generated from module fragments)
637
+ admin_dashboard.rb # Dashboard block registrations
638
+ ruby_cms_core.rb # Boot hooks (versionable, settings, permissions)
526
639
 
527
- ### Architecture
640
+ lib/ruby_cms.rb # Module API: nav_register, register_page, configure
641
+ lib/ruby_cms/
642
+ settings.rb # DB-backed settings
643
+ settings_registry.rb # Setting definitions
644
+ dashboard_blocks.rb # Dashboard registry
645
+ commands_registry.rb # Admin commands registry
646
+ icons.rb # Named Heroicon SVG registry
647
+ content_blocks_sync.rb # YAML ↔ DB import/export
648
+ content_blocks_grouping.rb # Multi-locale grouping
649
+ cli.rb # setup_admin interactive CLI
528
650
 
529
- ```
530
- lib/ruby_cms.rb # Module: nav_register, register_page, permissions API
531
- lib/ruby_cms/engine.rb # Rails::Engine: config, initializers, rake tasks, nav registration
532
- lib/ruby_cms/icons.rb # Named Heroicon SVG registry
533
- lib/ruby_cms/dashboard_blocks.rb # Dashboard block registry
534
- lib/ruby_cms/settings.rb # DB-backed settings
535
- lib/ruby_cms/settings_registry.rb # Settings definitions and defaults
536
- app/controllers/ruby_cms/admin/ # Admin controllers (base, dashboard, content blocks, etc.)
537
- app/models/ # ContentBlock, ContentBlockVersion, Permission, etc.
538
- app/views/ruby_cms/admin/ # Admin views
539
- app/views/layouts/ruby_cms/ # Admin layout + sidebar
540
- app/components/ # ViewComponents (AdminPage, etc.)
541
- app/helpers/ # Content block, settings, dashboard helpers
651
+ app/controllers/admin/ # Dashboard, content blocks, analytics, etc.
652
+ app/views/admin/ # Admin ERB views
653
+ app/components/ruby_ui/admin_page/
654
+ admin_page.rb # Card wrapper (+ optional turbo_frame)
655
+ admin_page_header.rb # Breadcrumbs, title, actions
656
+ admin_table_content.rb # Turbo frame for tables
657
+ admin_resource_card.rb # Show-page layout constants
658
+ app/models/ # ContentBlock, Permission, Preference, etc.
659
+ lib/tasks/ruby_cms.rake # Seed, content blocks, setup_admin
542
660
  ```
543
661
 
544
- ### Key Extension Points
662
+ ### Key extension points
545
663
 
546
664
  | What | How |
547
665
  |------|-----|
548
- | New admin page | `rails g ruby_cms:admin_page <name>` |
549
- | New nav item | `RubyCms.register_page(...)` or `RubyCms.nav_register(...)` |
550
- | New permission | `RubyCms.register_permission_keys(:key)` |
551
- | New dashboard block | `RubyCms.dashboard_register(...)` |
666
+ | New admin page | `rails g ruby_cms:admin_page <name> [field:type ...]` — registers itself in `config/initializers/admin_pages.rb` |
667
+ | New nav item | `RubyCms.register_page(...)` or `RubyCms.nav_register(...)` in `config/initializers/admin_pages.rb` (host-owned; `admin_nav.rb` is regenerated) |
668
+ | New app-specific permission | `RubyCms.register_permission_keys(:key)` in `config/initializers/admin_pages.rb` |
669
+ | New dashboard block | `RubyCms.dashboard_register(...)` in `config/initializers/admin_dashboard.rb` |
552
670
  | New setting | `RubyCms::SettingsRegistry.register(...)` |
553
671
  | New icon | Pass raw SVG string to `icon:` parameter |
672
+ | Add optional module | `ruby_cms install --add <module>` |
673
+ | Pull gem updates | `ruby_cms update` |
674
+ | Push changes to gem | `ruby_cms sync [--from ../app]` (gem repo) |
675
+
676
+ ## Module reference
677
+
678
+ ### Base modules (always installed)
679
+
680
+ `core`, `auth`, `permissions`, `users`, `content_blocks`, `visual_editor`
681
+
682
+ ### Optional modules (`ruby_cms install` picker or `--add`)
683
+
684
+ `analytics`, `media`, `redirects`, `audit_log`, `trash`, `security`, `system_health`, `passkeys`, `commands`
685
+
686
+ App-specific features (contact forms, news, products, …) do **not** belong in the gem. Use **`rails g ruby_cms:admin_page`** to scaffold a CRUD admin page that plugs into nav, permissions, routes, and the shared table/UI stack — then add your model, mailers, and public controllers in the host app.
687
+
688
+ Permissions for each module are declared in the gem manifest (`lib/ruby_cms/manifest.rb` + `manifest_data.rb`) and seeded at install. You do not need to register them manually.
554
689
 
555
690
  ## License
556
691