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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +62 -0
- data/MIT-LICENSE +20 -0
- data/README.md +357 -0
- data/Rakefile +3 -0
- data/docs/00-README.md +17 -0
- data/docs/01-getting-started.md +137 -0
- data/docs/02-component-registry.md +192 -0
- data/docs/03-base-pages.md +238 -0
- data/docs/04-schema-validation.md +180 -0
- data/docs/05-turbo-support.md +220 -0
- data/docs/06-compliance-analyzer.md +147 -0
- data/docs/07-configuration.md +157 -0
- data/guide/00-README.md +32 -0
- data/guide/01-quick-start.md +148 -0
- data/guide/02-building-index-page.md +258 -0
- data/guide/03-building-show-page.md +266 -0
- data/guide/04-building-form-page.md +309 -0
- data/guide/05-custom-pages.md +325 -0
- data/guide/06-best-practices.md +311 -0
- data/lib/better_page/base_page.rb +161 -0
- data/lib/better_page/compliance/analyzer.rb +409 -0
- data/lib/better_page/component_registry.rb +393 -0
- data/lib/better_page/config.rb +165 -0
- data/lib/better_page/configuration.rb +153 -0
- data/lib/better_page/custom_base_page.rb +85 -0
- data/lib/better_page/default_components.rb +200 -0
- data/lib/better_page/form_base_page.rb +170 -0
- data/lib/better_page/index_base_page.rb +69 -0
- data/lib/better_page/railtie.rb +34 -0
- data/lib/better_page/show_base_page.rb +120 -0
- data/lib/better_page/validation_error.rb +7 -0
- data/lib/better_page/version.rb +3 -0
- data/lib/better_page.rb +80 -0
- data/lib/generators/better_page/component_generator.rb +131 -0
- data/lib/generators/better_page/install_generator.rb +160 -0
- data/lib/generators/better_page/page_generator.rb +101 -0
- data/lib/generators/better_page/sync_generator.rb +109 -0
- data/lib/generators/better_page/templates/application_page.rb.tt +12 -0
- data/lib/generators/better_page/templates/better_page_initializer.rb.tt +53 -0
- data/lib/generators/better_page/templates/custom_base_page.rb.tt +83 -0
- data/lib/generators/better_page/templates/custom_page.rb.tt +31 -0
- data/lib/generators/better_page/templates/edit_page.rb.tt +46 -0
- data/lib/generators/better_page/templates/form_base_page.rb.tt +126 -0
- data/lib/generators/better_page/templates/index_base_page.rb.tt +65 -0
- data/lib/generators/better_page/templates/index_page.rb.tt +56 -0
- data/lib/generators/better_page/templates/javascript/controllers/app_nav_controller.js +57 -0
- data/lib/generators/better_page/templates/javascript/controllers/drawer_controller.js +99 -0
- data/lib/generators/better_page/templates/javascript/controllers/dropdown_controller.js +60 -0
- data/lib/generators/better_page/templates/javascript/controllers/index.js +36 -0
- data/lib/generators/better_page/templates/javascript/controllers/modal_controller.js +70 -0
- data/lib/generators/better_page/templates/javascript/controllers/sidebar_controller.js +152 -0
- data/lib/generators/better_page/templates/javascript/controllers/table_controller.js +60 -0
- data/lib/generators/better_page/templates/javascript/controllers/tabs_controller.js +89 -0
- data/lib/generators/better_page/templates/new_page.rb.tt +46 -0
- data/lib/generators/better_page/templates/show_base_page.rb.tt +117 -0
- data/lib/generators/better_page/templates/show_page.rb.tt +45 -0
- data/lib/generators/better_page/templates/view_components/application_view_component.rb.tt +7 -0
- data/lib/generators/better_page/templates/view_components/custom_view_component.html.erb.tt +21 -0
- data/lib/generators/better_page/templates/view_components/custom_view_component.rb.tt +21 -0
- data/lib/generators/better_page/templates/view_components/form_view_component.html.erb.tt +25 -0
- data/lib/generators/better_page/templates/view_components/form_view_component.rb.tt +23 -0
- data/lib/generators/better_page/templates/view_components/index_view_component.html.erb.tt +33 -0
- data/lib/generators/better_page/templates/view_components/index_view_component.rb.tt +29 -0
- data/lib/generators/better_page/templates/view_components/show_view_component.html.erb.tt +29 -0
- data/lib/generators/better_page/templates/view_components/show_view_component.rb.tt +25 -0
- data/lib/generators/better_page/templates/view_components/ui/alerts_component.html.erb.tt +47 -0
- data/lib/generators/better_page/templates/view_components/ui/alerts_component.rb.tt +47 -0
- data/lib/generators/better_page/templates/view_components/ui/content_section_component.html.erb.tt +42 -0
- data/lib/generators/better_page/templates/view_components/ui/content_section_component.rb.tt +34 -0
- data/lib/generators/better_page/templates/view_components/ui/drawer_component.html.erb.tt +73 -0
- data/lib/generators/better_page/templates/view_components/ui/drawer_component.rb.tt +78 -0
- data/lib/generators/better_page/templates/view_components/ui/errors_component.html.erb.tt +23 -0
- data/lib/generators/better_page/templates/view_components/ui/errors_component.rb.tt +18 -0
- data/lib/generators/better_page/templates/view_components/ui/field_component.html.erb.tt +65 -0
- data/lib/generators/better_page/templates/view_components/ui/field_component.rb.tt +91 -0
- data/lib/generators/better_page/templates/view_components/ui/footer_component.html.erb.tt +33 -0
- data/lib/generators/better_page/templates/view_components/ui/footer_component.rb.tt +32 -0
- data/lib/generators/better_page/templates/view_components/ui/header_component.html.erb.tt +55 -0
- data/lib/generators/better_page/templates/view_components/ui/header_component.rb.tt +39 -0
- data/lib/generators/better_page/templates/view_components/ui/modal_component.html.erb.tt +70 -0
- data/lib/generators/better_page/templates/view_components/ui/modal_component.rb.tt +54 -0
- data/lib/generators/better_page/templates/view_components/ui/overview_component.html.erb.tt +22 -0
- data/lib/generators/better_page/templates/view_components/ui/overview_component.rb.tt +71 -0
- data/lib/generators/better_page/templates/view_components/ui/pagination_component.html.erb.tt +63 -0
- data/lib/generators/better_page/templates/view_components/ui/pagination_component.rb.tt +69 -0
- data/lib/generators/better_page/templates/view_components/ui/panel_component.html.erb.tt +31 -0
- data/lib/generators/better_page/templates/view_components/ui/panel_component.rb.tt +23 -0
- data/lib/generators/better_page/templates/view_components/ui/statistics_component.html.erb.tt +33 -0
- data/lib/generators/better_page/templates/view_components/ui/statistics_component.rb.tt +51 -0
- data/lib/generators/better_page/templates/view_components/ui/table_component.html.erb.tt +112 -0
- data/lib/generators/better_page/templates/view_components/ui/table_component.rb.tt +88 -0
- data/lib/generators/better_page/templates/view_components/ui/tabs_component.html.erb.tt +52 -0
- data/lib/generators/better_page/templates/view_components/ui/tabs_component.rb.tt +76 -0
- data/lib/generators/better_page/templates/view_components/ui/widget_component.html.erb.tt +72 -0
- data/lib/generators/better_page/templates/view_components/ui/widget_component.rb.tt +34 -0
- data/lib/tasks/better_page.rake +70 -0
- data/lib/tasks/better_page_tasks.rake +4 -0
- metadata +188 -0
data/lib/better_page.rb
ADDED
|
@@ -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
|