better_page 2.0.0

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +62 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +357 -0
  5. data/Rakefile +3 -0
  6. data/docs/00-README.md +17 -0
  7. data/docs/01-getting-started.md +137 -0
  8. data/docs/02-component-registry.md +192 -0
  9. data/docs/03-base-pages.md +238 -0
  10. data/docs/04-schema-validation.md +180 -0
  11. data/docs/05-turbo-support.md +220 -0
  12. data/docs/06-compliance-analyzer.md +147 -0
  13. data/docs/07-configuration.md +157 -0
  14. data/guide/00-README.md +32 -0
  15. data/guide/01-quick-start.md +148 -0
  16. data/guide/02-building-index-page.md +258 -0
  17. data/guide/03-building-show-page.md +266 -0
  18. data/guide/04-building-form-page.md +309 -0
  19. data/guide/05-custom-pages.md +325 -0
  20. data/guide/06-best-practices.md +311 -0
  21. data/lib/better_page/base_page.rb +161 -0
  22. data/lib/better_page/compliance/analyzer.rb +409 -0
  23. data/lib/better_page/component_registry.rb +393 -0
  24. data/lib/better_page/config.rb +165 -0
  25. data/lib/better_page/configuration.rb +153 -0
  26. data/lib/better_page/custom_base_page.rb +85 -0
  27. data/lib/better_page/default_components.rb +200 -0
  28. data/lib/better_page/form_base_page.rb +170 -0
  29. data/lib/better_page/index_base_page.rb +69 -0
  30. data/lib/better_page/railtie.rb +34 -0
  31. data/lib/better_page/show_base_page.rb +120 -0
  32. data/lib/better_page/validation_error.rb +7 -0
  33. data/lib/better_page/version.rb +3 -0
  34. data/lib/better_page.rb +80 -0
  35. data/lib/generators/better_page/component_generator.rb +131 -0
  36. data/lib/generators/better_page/install_generator.rb +160 -0
  37. data/lib/generators/better_page/page_generator.rb +101 -0
  38. data/lib/generators/better_page/sync_generator.rb +109 -0
  39. data/lib/generators/better_page/templates/application_page.rb.tt +12 -0
  40. data/lib/generators/better_page/templates/better_page_initializer.rb.tt +53 -0
  41. data/lib/generators/better_page/templates/custom_base_page.rb.tt +83 -0
  42. data/lib/generators/better_page/templates/custom_page.rb.tt +31 -0
  43. data/lib/generators/better_page/templates/edit_page.rb.tt +46 -0
  44. data/lib/generators/better_page/templates/form_base_page.rb.tt +126 -0
  45. data/lib/generators/better_page/templates/index_base_page.rb.tt +65 -0
  46. data/lib/generators/better_page/templates/index_page.rb.tt +56 -0
  47. data/lib/generators/better_page/templates/javascript/controllers/app_nav_controller.js +57 -0
  48. data/lib/generators/better_page/templates/javascript/controllers/drawer_controller.js +99 -0
  49. data/lib/generators/better_page/templates/javascript/controllers/dropdown_controller.js +60 -0
  50. data/lib/generators/better_page/templates/javascript/controllers/index.js +36 -0
  51. data/lib/generators/better_page/templates/javascript/controllers/modal_controller.js +70 -0
  52. data/lib/generators/better_page/templates/javascript/controllers/sidebar_controller.js +152 -0
  53. data/lib/generators/better_page/templates/javascript/controllers/table_controller.js +60 -0
  54. data/lib/generators/better_page/templates/javascript/controllers/tabs_controller.js +89 -0
  55. data/lib/generators/better_page/templates/new_page.rb.tt +46 -0
  56. data/lib/generators/better_page/templates/show_base_page.rb.tt +117 -0
  57. data/lib/generators/better_page/templates/show_page.rb.tt +45 -0
  58. data/lib/generators/better_page/templates/view_components/application_view_component.rb.tt +7 -0
  59. data/lib/generators/better_page/templates/view_components/custom_view_component.html.erb.tt +21 -0
  60. data/lib/generators/better_page/templates/view_components/custom_view_component.rb.tt +21 -0
  61. data/lib/generators/better_page/templates/view_components/form_view_component.html.erb.tt +25 -0
  62. data/lib/generators/better_page/templates/view_components/form_view_component.rb.tt +23 -0
  63. data/lib/generators/better_page/templates/view_components/index_view_component.html.erb.tt +33 -0
  64. data/lib/generators/better_page/templates/view_components/index_view_component.rb.tt +29 -0
  65. data/lib/generators/better_page/templates/view_components/show_view_component.html.erb.tt +29 -0
  66. data/lib/generators/better_page/templates/view_components/show_view_component.rb.tt +25 -0
  67. data/lib/generators/better_page/templates/view_components/ui/alerts_component.html.erb.tt +47 -0
  68. data/lib/generators/better_page/templates/view_components/ui/alerts_component.rb.tt +47 -0
  69. data/lib/generators/better_page/templates/view_components/ui/content_section_component.html.erb.tt +42 -0
  70. data/lib/generators/better_page/templates/view_components/ui/content_section_component.rb.tt +34 -0
  71. data/lib/generators/better_page/templates/view_components/ui/drawer_component.html.erb.tt +73 -0
  72. data/lib/generators/better_page/templates/view_components/ui/drawer_component.rb.tt +78 -0
  73. data/lib/generators/better_page/templates/view_components/ui/errors_component.html.erb.tt +23 -0
  74. data/lib/generators/better_page/templates/view_components/ui/errors_component.rb.tt +18 -0
  75. data/lib/generators/better_page/templates/view_components/ui/field_component.html.erb.tt +65 -0
  76. data/lib/generators/better_page/templates/view_components/ui/field_component.rb.tt +91 -0
  77. data/lib/generators/better_page/templates/view_components/ui/footer_component.html.erb.tt +33 -0
  78. data/lib/generators/better_page/templates/view_components/ui/footer_component.rb.tt +32 -0
  79. data/lib/generators/better_page/templates/view_components/ui/header_component.html.erb.tt +55 -0
  80. data/lib/generators/better_page/templates/view_components/ui/header_component.rb.tt +39 -0
  81. data/lib/generators/better_page/templates/view_components/ui/modal_component.html.erb.tt +70 -0
  82. data/lib/generators/better_page/templates/view_components/ui/modal_component.rb.tt +54 -0
  83. data/lib/generators/better_page/templates/view_components/ui/overview_component.html.erb.tt +22 -0
  84. data/lib/generators/better_page/templates/view_components/ui/overview_component.rb.tt +71 -0
  85. data/lib/generators/better_page/templates/view_components/ui/pagination_component.html.erb.tt +63 -0
  86. data/lib/generators/better_page/templates/view_components/ui/pagination_component.rb.tt +69 -0
  87. data/lib/generators/better_page/templates/view_components/ui/panel_component.html.erb.tt +31 -0
  88. data/lib/generators/better_page/templates/view_components/ui/panel_component.rb.tt +23 -0
  89. data/lib/generators/better_page/templates/view_components/ui/statistics_component.html.erb.tt +33 -0
  90. data/lib/generators/better_page/templates/view_components/ui/statistics_component.rb.tt +51 -0
  91. data/lib/generators/better_page/templates/view_components/ui/table_component.html.erb.tt +112 -0
  92. data/lib/generators/better_page/templates/view_components/ui/table_component.rb.tt +88 -0
  93. data/lib/generators/better_page/templates/view_components/ui/tabs_component.html.erb.tt +52 -0
  94. data/lib/generators/better_page/templates/view_components/ui/tabs_component.rb.tt +76 -0
  95. data/lib/generators/better_page/templates/view_components/ui/widget_component.html.erb.tt +72 -0
  96. data/lib/generators/better_page/templates/view_components/ui/widget_component.rb.tt +34 -0
  97. data/lib/tasks/better_page.rake +70 -0
  98. data/lib/tasks/better_page_tasks.rake +4 -0
  99. metadata +188 -0
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "better_page/version"
4
+ require "better_page/railtie" if defined?(Rails::Railtie)
5
+
6
+ module BetterPage
7
+ # Core components
8
+ autoload :ValidationError, "better_page/validation_error"
9
+ autoload :Config, "better_page/config"
10
+ autoload :ComponentRegistry, "better_page/component_registry"
11
+ autoload :ComponentDefinition, "better_page/component_registry"
12
+ autoload :Configuration, "better_page/configuration"
13
+ autoload :DefaultComponents, "better_page/default_components"
14
+
15
+ # Base page classes
16
+ autoload :BasePage, "better_page/base_page"
17
+ autoload :IndexBasePage, "better_page/index_base_page"
18
+ autoload :ShowBasePage, "better_page/show_base_page"
19
+ autoload :FormBasePage, "better_page/form_base_page"
20
+ autoload :CustomBasePage, "better_page/custom_base_page"
21
+
22
+ # Compliance module
23
+ module Compliance
24
+ autoload :Analyzer, "better_page/compliance/analyzer"
25
+ end
26
+
27
+ # ViewComponent classes (loaded from user's app/components directory)
28
+ # These are defined when the user runs the install generator
29
+ module Ui
30
+ # UI components are autoloaded from the user's application
31
+ end
32
+
33
+ class << self
34
+ # Access the global configuration
35
+ #
36
+ # @return [Configuration]
37
+ def configuration
38
+ @configuration ||= Configuration.new
39
+ end
40
+
41
+ # Configure BetterPage components
42
+ #
43
+ # @yield [Configuration] yields the configuration object
44
+ # @return [Configuration]
45
+ #
46
+ # @example
47
+ # BetterPage.configure do |config|
48
+ # config.register_component :sidebar, default: { enabled: false }
49
+ # config.allow_components :index, :sidebar
50
+ # end
51
+ #
52
+ def configure
53
+ yield(configuration)
54
+ configuration
55
+ end
56
+
57
+ # Reset configuration to empty state
58
+ # Used primarily for testing
59
+ #
60
+ # @return [void]
61
+ def reset_configuration!
62
+ @configuration = Configuration.new
63
+ end
64
+
65
+ # Check if default components have been registered
66
+ #
67
+ # @return [Boolean]
68
+ def defaults_registered?
69
+ @defaults_registered ||= false
70
+ end
71
+
72
+ # Mark defaults as registered
73
+ # Called by railtie after registering default components
74
+ #
75
+ # @return [void]
76
+ def defaults_registered!
77
+ @defaults_registered = true
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module BetterPage
6
+ module Generators
7
+ class ComponentGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ argument :component_name, type: :string, required: true,
11
+ desc: "Name of the component to install (e.g., 'header', 'table', 'index')"
12
+
13
+ desc "Installs a specific BetterPage ViewComponent"
14
+
15
+ MAIN_COMPONENTS = %w[index show form custom].freeze
16
+ UI_COMPONENTS = %w[
17
+ header table alerts statistics pagination
18
+ panel field errors overview content_section
19
+ widget footer tabs drawer
20
+ ].freeze
21
+
22
+ def validate_component
23
+ return if valid_component?
24
+
25
+ say_error "Unknown component: #{component_name}"
26
+ say ""
27
+ say "Available main components: #{MAIN_COMPONENTS.join(', ')}"
28
+ say "Available UI components: #{UI_COMPONENTS.join(', ')}"
29
+ say ""
30
+ say "Or use 'all' to install all components."
31
+ raise Thor::Error, "Invalid component name"
32
+ end
33
+
34
+ def create_component_directories
35
+ empty_directory "app/components/better_page"
36
+ empty_directory "app/components/better_page/ui" if ui_component? || install_all?
37
+ end
38
+
39
+ def install_component
40
+ if install_all?
41
+ install_all_components
42
+ elsif main_component?
43
+ install_main_component
44
+ else
45
+ install_ui_component
46
+ end
47
+ end
48
+
49
+ def show_post_install_message
50
+ say ""
51
+ say "Component(s) installed successfully!", :green
52
+ say ""
53
+ say "You can customize the components in app/components/better_page/"
54
+ say ""
55
+ end
56
+
57
+ private
58
+
59
+ def valid_component?
60
+ install_all? || main_component? || ui_component?
61
+ end
62
+
63
+ def install_all?
64
+ component_name.downcase == "all"
65
+ end
66
+
67
+ def main_component?
68
+ MAIN_COMPONENTS.include?(normalized_name)
69
+ end
70
+
71
+ def ui_component?
72
+ UI_COMPONENTS.include?(normalized_name)
73
+ end
74
+
75
+ def normalized_name
76
+ @normalized_name ||= component_name.downcase.gsub(/_component$/, "").gsub(/_view_component$/, "")
77
+ end
78
+
79
+ def install_all_components
80
+ MAIN_COMPONENTS.each { |name| copy_main_component(name) }
81
+ UI_COMPONENTS.each { |name| copy_ui_component(name) }
82
+ end
83
+
84
+ def install_main_component
85
+ copy_main_component(normalized_name)
86
+ end
87
+
88
+ def install_ui_component
89
+ copy_ui_component(normalized_name)
90
+ end
91
+
92
+ def copy_main_component(name)
93
+ template "view_components/#{name}_view_component.rb.tt",
94
+ "app/components/better_page/#{name}_view_component.rb"
95
+ template "view_components/#{name}_view_component.html.erb.tt",
96
+ "app/components/better_page/#{name}_view_component.html.erb"
97
+ say " Installed: #{name}_view_component", :green
98
+ end
99
+
100
+ def copy_ui_component(name)
101
+ template "view_components/ui/#{name}_component.rb.tt",
102
+ "app/components/better_page/ui/#{name}_component.rb"
103
+ template "view_components/ui/#{name}_component.html.erb.tt",
104
+ "app/components/better_page/ui/#{name}_component.html.erb"
105
+ say " Installed: ui/#{name}_component", :green
106
+
107
+ # Install dropdown controller if table component is installed
108
+ install_dropdown_controller if name == "table"
109
+
110
+ # Install drawer controller if drawer component is installed
111
+ install_drawer_controller if name == "drawer"
112
+ end
113
+
114
+ def install_dropdown_controller
115
+ return if File.exist?(Rails.root.join("app/javascript/controllers/dropdown_controller.js"))
116
+
117
+ copy_file "javascript/controllers/dropdown_controller.js",
118
+ "app/javascript/controllers/dropdown_controller.js"
119
+ say " Installed: dropdown_controller.js (Stimulus)", :green
120
+ end
121
+
122
+ def install_drawer_controller
123
+ return if File.exist?(Rails.root.join("app/javascript/controllers/drawer_controller.js"))
124
+
125
+ copy_file "javascript/controllers/drawer_controller.js",
126
+ "app/javascript/controllers/drawer_controller.js"
127
+ say " Installed: drawer_controller.js (Stimulus)", :green
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module BetterPage
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ desc "Creates the app/pages directory, ApplicationPage base class, base page classes, initializer, and ViewComponents"
11
+
12
+ class_option :skip_components, type: :boolean, default: false,
13
+ desc: "Skip installing ViewComponents"
14
+
15
+ def create_pages_directory
16
+ empty_directory "app/pages"
17
+ end
18
+
19
+ def create_initializer
20
+ template "better_page_initializer.rb.tt", "config/initializers/better_page.rb"
21
+ end
22
+
23
+ def create_application_page
24
+ template "application_page.rb.tt", "app/pages/application_page.rb"
25
+ end
26
+
27
+ def create_base_pages
28
+ template "index_base_page.rb.tt", "app/pages/index_base_page.rb"
29
+ template "show_base_page.rb.tt", "app/pages/show_base_page.rb"
30
+ template "form_base_page.rb.tt", "app/pages/form_base_page.rb"
31
+ template "custom_base_page.rb.tt", "app/pages/custom_base_page.rb"
32
+ end
33
+
34
+ def create_view_components
35
+ return if options[:skip_components]
36
+
37
+ # Create main directory structure
38
+ empty_directory "app/components/better_page"
39
+ empty_directory "app/components/better_page/ui"
40
+
41
+ # Copy base component first (all components inherit from this)
42
+ template "view_components/application_view_component.rb.tt",
43
+ "app/components/better_page/application_view_component.rb"
44
+
45
+ # Copy main view components
46
+ copy_view_component "index_view_component"
47
+ copy_view_component "show_view_component"
48
+ copy_view_component "form_view_component"
49
+ copy_view_component "custom_view_component"
50
+
51
+ # Copy UI components
52
+ ui_components.each do |component|
53
+ copy_ui_component component
54
+ end
55
+ end
56
+
57
+ def create_stimulus_controllers
58
+ return if options[:skip_components]
59
+
60
+ # Create directory for BetterPage controllers
61
+ empty_directory "app/javascript/controllers/better_page"
62
+
63
+ # Copy Stimulus controllers for interactive components
64
+ copy_file "javascript/controllers/dropdown_controller.js",
65
+ "app/javascript/controllers/better_page/dropdown_controller.js"
66
+ copy_file "javascript/controllers/index.js",
67
+ "app/javascript/controllers/better_page/index.js"
68
+
69
+ # Add import to the main controllers/index.js if it exists
70
+ controllers_index = "app/javascript/controllers/index.js"
71
+ if File.exist?(Rails.root.join(controllers_index))
72
+ append_to_file controllers_index, <<~JS
73
+
74
+ // BetterPage controllers
75
+ import { registerBetterPageControllers } from "./better_page"
76
+ registerBetterPageControllers(application)
77
+ JS
78
+ end
79
+ end
80
+
81
+ def show_post_install_message
82
+ say ""
83
+ say "BetterPage has been installed successfully!", :green
84
+ say ""
85
+ say "Created:"
86
+ say " - config/initializers/better_page.rb (component configuration)"
87
+ say " - app/pages/application_page.rb"
88
+ say " - app/pages/index_base_page.rb"
89
+ say " - app/pages/show_base_page.rb"
90
+ say " - app/pages/form_base_page.rb"
91
+ say " - app/pages/custom_base_page.rb"
92
+ unless options[:skip_components]
93
+ say " - app/components/better_page/application_view_component.rb (base component)"
94
+ say " - app/components/better_page/ (ViewComponents)"
95
+ say " - app/javascript/controllers/better_page/ (Stimulus controllers)"
96
+ say ""
97
+ say "ViewComponents and Stimulus controllers have been copied to your project."
98
+ say "You can customize them to match your design system."
99
+ say ""
100
+ say "Note: Make sure you have @hotwired/stimulus installed."
101
+ say ""
102
+ say "Alternative: Install via npm instead of copying files:"
103
+ say " npm install better-page-stimulus"
104
+ say " # or"
105
+ say " yarn add better-page-stimulus"
106
+ end
107
+ say ""
108
+ say "Base page classes in app/pages/ can be customized:"
109
+ say " - Add custom components with register_component"
110
+ say " - Override helper methods"
111
+ say " - Customize stream_components"
112
+ say ""
113
+ say "You can now generate pages using:"
114
+ say " rails g better_page:page Namespace::Resource index show new edit"
115
+ say ""
116
+ say "Example:"
117
+ say " rails g better_page:page Admin::Users index show new edit"
118
+ say ""
119
+ say "To check for gem updates:"
120
+ say " rails g better_page:sync"
121
+ say ""
122
+ say "To add individual components later:"
123
+ say " rails g better_page:component ComponentName"
124
+ say ""
125
+ end
126
+
127
+ private
128
+
129
+ def copy_view_component(name)
130
+ template "view_components/#{name}.rb.tt", "app/components/better_page/#{name}.rb"
131
+ template "view_components/#{name}.html.erb.tt", "app/components/better_page/#{name}.html.erb"
132
+ end
133
+
134
+ def copy_ui_component(name)
135
+ template "view_components/ui/#{name}_component.rb.tt",
136
+ "app/components/better_page/ui/#{name}_component.rb"
137
+ template "view_components/ui/#{name}_component.html.erb.tt",
138
+ "app/components/better_page/ui/#{name}_component.html.erb"
139
+ end
140
+
141
+ def ui_components
142
+ %w[
143
+ header
144
+ table
145
+ alerts
146
+ statistics
147
+ pagination
148
+ panel
149
+ field
150
+ errors
151
+ overview
152
+ content_section
153
+ widget
154
+ footer
155
+ tabs
156
+ ]
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module BetterPage
6
+ module Generators
7
+ class PageGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ argument :resource, type: :string, required: true,
11
+ desc: "The resource name (e.g., Admin::Users or Users)"
12
+ argument :actions, type: :array, default: [],
13
+ desc: "The actions to generate (index, show, new, edit, custom)"
14
+
15
+ desc "Generates page classes for the specified resource and actions"
16
+
17
+ def check_pages_directory
18
+ unless File.directory?(Rails.root.join("app", "pages"))
19
+ say "app/pages directory not found. Run 'rails g better_page:install' first.", :red
20
+ exit 1
21
+ end
22
+ end
23
+
24
+ def create_page_files
25
+ actions_to_generate = actions.empty? ? %w[index show new edit] : actions
26
+
27
+ actions_to_generate.each do |action|
28
+ template_name = template_for_action(action)
29
+ if template_name
30
+ template "#{template_name}.rb.tt", page_path(action)
31
+ else
32
+ say "Unknown action: #{action}. Skipping.", :yellow
33
+ end
34
+ end
35
+ end
36
+
37
+ def show_completion_message
38
+ say ""
39
+ say "Pages generated successfully!", :green
40
+ say ""
41
+ end
42
+
43
+ private
44
+
45
+ def template_for_action(action)
46
+ case action.to_s
47
+ when "index" then "index_page"
48
+ when "show" then "show_page"
49
+ when "new" then "new_page"
50
+ when "edit" then "edit_page"
51
+ when "custom" then "custom_page"
52
+ end
53
+ end
54
+
55
+ def page_path(action)
56
+ File.join("app", "pages", *namespace_path, "#{action}_page.rb")
57
+ end
58
+
59
+ def namespace_path
60
+ resource.underscore.split("/")
61
+ end
62
+
63
+ def resource_namespace
64
+ parts = resource.split("::")
65
+ parts.length > 1 ? parts[0..-2].join("::") : nil
66
+ end
67
+
68
+ def resource_name
69
+ resource.split("::").last
70
+ end
71
+
72
+ def resource_singular
73
+ resource_name.singularize.underscore
74
+ end
75
+
76
+ def resource_plural
77
+ resource_name.pluralize.underscore
78
+ end
79
+
80
+ def full_class_name(action)
81
+ parts = resource.split("::")
82
+ parts << "#{action.to_s.camelize}Page"
83
+ parts.join("::")
84
+ end
85
+
86
+ def module_nesting_start
87
+ parts = resource.split("::")
88
+ parts.map { |part| "module #{part}" }.join("\n ")
89
+ end
90
+
91
+ def module_nesting_end
92
+ parts = resource.split("::")
93
+ parts.map { "end" }.join("\n")
94
+ end
95
+
96
+ def class_indent
97
+ " " * resource.split("::").length
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module BetterPage
6
+ module Generators
7
+ # Generator to check for new components available in the BetterPage gem.
8
+ #
9
+ # Usage:
10
+ # rails g better_page:sync
11
+ #
12
+ # This compares the components registered in the gem's DefaultComponents
13
+ # with those in your application's initializer and base page classes,
14
+ # showing what's new and what might need updating.
15
+ #
16
+ class SyncGenerator < Rails::Generators::Base
17
+ desc "Check for new components available in BetterPage gem"
18
+
19
+ def check_components
20
+ say ""
21
+ say "BetterPage Sync Check", :green
22
+ say "=" * 50
23
+ say ""
24
+
25
+ # Get gem's default component names
26
+ gem_components = BetterPage::DefaultComponents.component_names
27
+
28
+ # Get user's configured components
29
+ user_components = BetterPage.configuration.component_names
30
+
31
+ # Find differences
32
+ new_in_gem = gem_components - user_components
33
+ custom_in_user = user_components - gem_components
34
+
35
+ if new_in_gem.empty? && custom_in_user.empty?
36
+ say "Your configuration is up to date!", :green
37
+ say ""
38
+ else
39
+ if new_in_gem.any?
40
+ say "New components available from gem:", :yellow
41
+ new_in_gem.each { |c| say " + #{c}" }
42
+ say ""
43
+ say "These components are automatically available via global configuration."
44
+ say "No action needed unless you want to customize their defaults."
45
+ say ""
46
+ end
47
+
48
+ if custom_in_user.any?
49
+ say "Custom components in your configuration:", :cyan
50
+ custom_in_user.each { |c| say " * #{c}" }
51
+ say ""
52
+ end
53
+ end
54
+
55
+ check_page_type_components
56
+ check_base_page_files
57
+ end
58
+
59
+ private
60
+
61
+ def check_page_type_components
62
+ say "Page Type Component Mapping:", :green
63
+ say "-" * 50
64
+
65
+ %i[index show form custom].each do |page_type|
66
+ gem_for_type = BetterPage.configuration.components_for(page_type)
67
+ say " #{page_type.to_s.ljust(10)} #{gem_for_type.join(', ')}"
68
+ end
69
+
70
+ say ""
71
+ end
72
+
73
+ def check_base_page_files
74
+ say "Local Base Page Files:", :green
75
+ say "-" * 50
76
+
77
+ base_files = {
78
+ "index_base_page.rb" => "app/pages/index_base_page.rb",
79
+ "show_base_page.rb" => "app/pages/show_base_page.rb",
80
+ "form_base_page.rb" => "app/pages/form_base_page.rb",
81
+ "custom_base_page.rb" => "app/pages/custom_base_page.rb"
82
+ }
83
+
84
+ base_files.each do |name, path|
85
+ full_path = Rails.root.join(path)
86
+ if File.exist?(full_path)
87
+ local_components = extract_local_components(full_path)
88
+ if local_components.any?
89
+ say " #{name}: #{local_components.join(', ')}", :cyan
90
+ else
91
+ say " #{name}: (no custom components)", :white
92
+ end
93
+ else
94
+ say " #{name}: NOT FOUND", :red
95
+ say " Run: rails g better_page:install", :yellow
96
+ end
97
+ end
98
+
99
+ say ""
100
+ end
101
+
102
+ def extract_local_components(file_path)
103
+ content = File.read(file_path)
104
+ # Extract component names from register_component calls
105
+ content.scan(/register_component\s+:(\w+)/).flatten.map(&:to_sym)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base class for all application pages.
4
+ # Add common functionality and helpers here.
5
+ class ApplicationPage < BetterPage::BasePage
6
+ # Add common helpers for your application here
7
+ #
8
+ # Example:
9
+ # def current_user_name
10
+ # @user&.full_name || "Guest"
11
+ # end
12
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # BetterPage Configuration
4
+ # ========================
5
+ #
6
+ # Default components are registered automatically by the gem.
7
+ # Use this file to:
8
+ # - Add custom global components
9
+ # - Override default component settings
10
+ # - Map custom components to page types
11
+ #
12
+ # Components can also be registered locally in:
13
+ # - Base page classes (app/pages/*_base_page.rb)
14
+ # - Individual page classes (for page-specific components)
15
+
16
+ BetterPage.configure do |config|
17
+ # ─────────────────────────────────────────────────────────────────
18
+ # CUSTOM COMPONENTS
19
+ # ─────────────────────────────────────────────────────────────────
20
+ #
21
+ # Register a custom component and allow it for specific page types:
22
+ #
23
+ # config.register_component :sidebar, default: { enabled: false } do
24
+ # optional(:enabled).filled(:bool)
25
+ # optional(:items).array(:hash)
26
+ # end
27
+ # config.allow_components :index, :sidebar
28
+ #
29
+ # ─────────────────────────────────────────────────────────────────
30
+ # OVERRIDE DEFAULT COMPONENTS
31
+ # ─────────────────────────────────────────────────────────────────
32
+ #
33
+ # Override a default component's settings:
34
+ #
35
+ # config.register_component :pagination, default: { enabled: true, per_page: 25 }
36
+ #
37
+ # ─────────────────────────────────────────────────────────────────
38
+ # EXAMPLES
39
+ # ─────────────────────────────────────────────────────────────────
40
+ #
41
+ # Example: Add a timeline component to show pages
42
+ #
43
+ # config.register_component :timeline, default: { events: [] }
44
+ # config.allow_components :show, :timeline
45
+ #
46
+ # Example: Add a dashboard widget to custom pages
47
+ #
48
+ # config.register_component :dashboard_widget, default: { enabled: false } do
49
+ # optional(:title).filled(:string)
50
+ # optional(:data).hash
51
+ # end
52
+ # config.allow_components :custom, :dashboard_widget
53
+ end