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,220 @@
1
+ # Turbo Support
2
+
3
+ BetterPage provides built-in support for Turbo Frames and Turbo Streams.
4
+
5
+ ### Turbo Helpers in ViewComponents
6
+
7
+ All BetterPage ViewComponents inherit from `ApplicationViewComponent`, which includes `Turbo::FramesHelper`. This means you have access to Turbo helpers like `turbo_frame_tag` directly in your component templates.
8
+
9
+ ```ruby
10
+ # app/components/better_page/application_view_component.rb
11
+ module BetterPage
12
+ class ApplicationViewComponent < ViewComponent::Base
13
+ include Turbo::FramesHelper
14
+ end
15
+ end
16
+ ```
17
+
18
+ This allows you to use Turbo helpers in any component template:
19
+
20
+ ```erb
21
+ <%# In any component .html.erb template %>
22
+ <%= turbo_frame_tag "my_frame" do %>
23
+ <!-- Content -->
24
+ <% end %>
25
+ ```
26
+
27
+ --------------------------------
28
+
29
+ ### Overview
30
+
31
+ | Method Type | Use Case | Returns |
32
+ |-------------|----------|---------|
33
+ | `frame_*` | Lazy loading, navigation | Single Hash |
34
+ | `stream_*` | Real-time updates, form responses | Array of Hashes |
35
+
36
+ --------------------------------
37
+
38
+ ### Turbo Frame - Lazy Load Component
39
+
40
+ Use `frame_<action>(:component)` to get a single component for Turbo Frame.
41
+
42
+ ```ruby
43
+ # In controller
44
+ def table
45
+ @products = Product.all
46
+ component = Products::IndexPage.new(@products, current_user).frame_index(:table)
47
+
48
+ render component[:klass].new(**component[:config])
49
+ end
50
+
51
+ # frame_index(:table) returns:
52
+ # {
53
+ # component: :table,
54
+ # config: { items: [...], columns: [...] },
55
+ # klass: TableComponent,
56
+ # target: "better_page_table"
57
+ # }
58
+ ```
59
+
60
+ --------------------------------
61
+
62
+ ### Turbo Frame View Setup
63
+
64
+ ```erb
65
+ <turbo-frame id="better_page_table" src="<%= table_products_path %>" loading="lazy">
66
+ <p>Loading products...</p>
67
+ </turbo-frame>
68
+ ```
69
+
70
+ --------------------------------
71
+
72
+ ### Turbo Stream - Update Multiple Components
73
+
74
+ Use `stream_<action>(*components)` to get multiple components for Turbo Stream.
75
+
76
+ ```ruby
77
+ # In controller
78
+ def refresh
79
+ @products = Product.filtered(params)
80
+ components = Products::IndexPage.new(@products, current_user).stream_index(:table, :statistics)
81
+
82
+ respond_to do |format|
83
+ format.turbo_stream do
84
+ render turbo_stream: components.map { |c|
85
+ turbo_stream.replace(c[:target], c[:klass].new(**c[:config]))
86
+ }
87
+ end
88
+ end
89
+ end
90
+
91
+ # stream_index(:table, :statistics) returns:
92
+ # [
93
+ # { component: :table, config: {...}, klass: TableComponent, target: "better_page_table" },
94
+ # { component: :statistics, config: {...}, klass: StatsComponent, target: "better_page_statistics" }
95
+ # ]
96
+ ```
97
+
98
+ --------------------------------
99
+
100
+ ### Turbo Stream View Setup
101
+
102
+ ```erb
103
+ <div id="better_page_alerts">
104
+ <%# Alerts rendered here %>
105
+ </div>
106
+
107
+ <div id="better_page_statistics">
108
+ <%# Statistics rendered here %>
109
+ </div>
110
+
111
+ <div id="better_page_table">
112
+ <%# Table rendered here %>
113
+ </div>
114
+
115
+ <div id="better_page_pagination">
116
+ <%# Pagination rendered here %>
117
+ </div>
118
+ ```
119
+
120
+ --------------------------------
121
+
122
+ ### Dynamic Methods by Page Type
123
+
124
+ Methods are generated based on the page's main action.
125
+
126
+ | Page Type | Main Action | Frame Method | Stream Method |
127
+ |-----------|-------------|--------------|---------------|
128
+ | IndexBasePage | `index` | `frame_index(:component)` | `stream_index(*components)` |
129
+ | ShowBasePage | `show` | `frame_show(:component)` | `stream_show(*components)` |
130
+ | FormBasePage | `form` | `frame_form(:component)` | `stream_form(*components)` |
131
+ | CustomBasePage | `custom` | `frame_custom(:component)` | `stream_custom(*components)` |
132
+
133
+ --------------------------------
134
+
135
+ ### Custom Action Methods
136
+
137
+ If you define a custom action, turbo methods work automatically.
138
+
139
+ ```ruby
140
+ class Reports::DailyPage < CustomBasePage
141
+ register_component :chart, default: {}
142
+
143
+ def daily
144
+ build_page
145
+ end
146
+
147
+ def chart
148
+ { type: :line, data: @data }
149
+ end
150
+ end
151
+
152
+ # Usage
153
+ page = Reports::DailyPage.new(@data)
154
+ page.frame_daily(:chart) # Single component
155
+ page.stream_daily(:chart, :summary) # Multiple components
156
+ ```
157
+
158
+ --------------------------------
159
+
160
+ ### Customize Default Stream Components
161
+
162
+ Override `stream_components` to define defaults.
163
+
164
+ ```ruby
165
+ class Products::IndexPage < IndexBasePage
166
+ def stream_components
167
+ %i[alerts statistics table pagination]
168
+ end
169
+ end
170
+
171
+ # Now stream_index without arguments returns these four
172
+ page.stream_index # => alerts, statistics, table, pagination
173
+ ```
174
+
175
+ --------------------------------
176
+
177
+ ### Customize Frame Target
178
+
179
+ Override `frame_target` to customize DOM element IDs.
180
+
181
+ ```ruby
182
+ def frame_target(name)
183
+ "products_#{name}" # "products_table" instead of "better_page_table"
184
+ end
185
+ ```
186
+
187
+ --------------------------------
188
+
189
+ ### Customize Stream Target
190
+
191
+ Override `stream_target` to customize DOM element IDs.
192
+
193
+ ```ruby
194
+ def stream_target(name)
195
+ "products_#{name}"
196
+ end
197
+ ```
198
+
199
+ --------------------------------
200
+
201
+ ### Available Turbo Stream Actions
202
+
203
+ ```ruby
204
+ components.each do |c|
205
+ # Replace - replaces entire element
206
+ turbo_stream.replace(c[:target], c[:klass].new(**c[:config]))
207
+
208
+ # Update - replaces content only
209
+ turbo_stream.update(c[:target], c[:klass].new(**c[:config]))
210
+
211
+ # Append - adds after existing content
212
+ turbo_stream.append(c[:target], c[:klass].new(**c[:config]))
213
+
214
+ # Prepend - adds before existing content
215
+ turbo_stream.prepend(c[:target], c[:klass].new(**c[:config]))
216
+
217
+ # Remove - removes element
218
+ turbo_stream.remove(c[:target])
219
+ end
220
+ ```
@@ -0,0 +1,147 @@
1
+ # Compliance Analyzer
2
+
3
+ The Compliance Analyzer checks that pages follow BetterPage architecture rules.
4
+
5
+ ### Run Compliance Analyzer
6
+
7
+ ```bash
8
+ rake better_page:compliance:analyze
9
+ ```
10
+
11
+ --------------------------------
12
+
13
+ ### Run in Verbose Mode
14
+
15
+ ```bash
16
+ VERBOSE=true rake better_page:compliance:analyze
17
+ ```
18
+
19
+ --------------------------------
20
+
21
+ ### Architecture Rules
22
+
23
+ Pages must follow these rules:
24
+
25
+ 1. **No database queries** - Data passed via constructor
26
+ 2. **No business logic** - UI configuration only
27
+ 3. **No service layer access** - No service objects
28
+ 4. **Hash-only structures** - No OpenStruct/Struct
29
+ 5. **Separate panels for checkboxes** - Checkbox/radio fields in separate panels
30
+
31
+ --------------------------------
32
+
33
+ ### Required Component Methods
34
+
35
+ Each page type must implement required methods.
36
+
37
+ | Page Type | Required Methods |
38
+ |-----------|-----------------|
39
+ | IndexPage | `header`, `table` |
40
+ | ShowPage | `header` |
41
+ | FormPage | `header`, `panels` |
42
+ | CustomPage | `content` |
43
+
44
+ --------------------------------
45
+
46
+ ### Forbidden Database Patterns
47
+
48
+ ```ruby
49
+ # WRONG - Database queries in page
50
+ def header
51
+ { title: "#{User.count} Users" }
52
+ end
53
+
54
+ def table
55
+ { items: User.where(active: true) }
56
+ end
57
+
58
+ # CORRECT - Data passed via constructor
59
+ def initialize(users, stats)
60
+ @users = users
61
+ @stats = stats
62
+ end
63
+
64
+ def header
65
+ { title: "#{@stats[:count]} Users" }
66
+ end
67
+
68
+ def table
69
+ { items: @users }
70
+ end
71
+ ```
72
+
73
+ --------------------------------
74
+
75
+ ### Forbidden Business Logic Patterns
76
+
77
+ ```ruby
78
+ # WRONG - Business logic in page
79
+ def calculate_total # Business calculation
80
+ def process_data # Business processing
81
+ def validate_user # Validation logic
82
+ def save_record # Persistence
83
+
84
+ # WRONG - Service access
85
+ def header
86
+ result = UserService.new.get_stats
87
+ { title: result[:title] }
88
+ end
89
+ ```
90
+
91
+ --------------------------------
92
+
93
+ ### Forbidden External Dependencies
94
+
95
+ ```ruby
96
+ # WRONG - External HTTP clients
97
+ Net::HTTP.get(...)
98
+ HTTParty.get(...)
99
+ Faraday.get(...)
100
+
101
+ # WRONG - External services
102
+ Redis.current.get(...)
103
+ ```
104
+
105
+ --------------------------------
106
+
107
+ ### Compliance Report Output
108
+
109
+ ```
110
+ SUMMARY
111
+ =======
112
+ Total pages analyzed: 25
113
+ [OK] Fully compliant: 20 (80.0%)
114
+ [WARN] With warnings: 3 (12.0%)
115
+ [ERROR] With errors: 2 (8.0%)
116
+
117
+ CRITICAL ISSUES
118
+ ===============
119
+ - app/pages/admin/users/index_page.rb
120
+ - Database queries forbidden in Page
121
+ - Missing required component method: table
122
+
123
+ RECOMMENDATIONS
124
+ ===============
125
+ 1. Remove database queries from Pages
126
+ 2. Remove business logic - keep UI configuration only
127
+ 3. Implement required component methods
128
+ ```
129
+
130
+ --------------------------------
131
+
132
+ ### Programmatic Usage
133
+
134
+ ```ruby
135
+ analyzer = BetterPage::Compliance::Analyzer.new
136
+
137
+ # Analyze single page
138
+ result = analyzer.analyze_page("app/pages/admin/users/index_page.rb")
139
+ puts result[:status] # :compliant, :warning, or :error
140
+ puts result[:issues] # Array of issue messages
141
+ puts result[:warnings] # Array of warning messages
142
+
143
+ # Analyze all pages
144
+ analyzer.analyze_all
145
+ puts analyzer.compliant_count
146
+ puts analyzer.error_count
147
+ ```
@@ -0,0 +1,157 @@
1
+ # Configuration
2
+
3
+ BetterPage uses a hybrid configuration system that combines global configuration with local customization.
4
+
5
+ ### Configuration Levels
6
+
7
+ Components can be registered at three levels:
8
+
9
+ 1. **Gem Defaults** - Built-in components registered by `BetterPage::DefaultComponents`
10
+ 2. **Global Configuration** - User customizations in `config/initializers/better_page.rb`
11
+ 3. **Local Classes** - Components in base page classes or individual pages
12
+
13
+ --------------------------------
14
+
15
+ ### Global Configuration
16
+
17
+ Configure BetterPage in your initializer:
18
+
19
+ ```ruby
20
+ # config/initializers/better_page.rb
21
+ BetterPage.configure do |config|
22
+ # Register a new component
23
+ config.register_component :sidebar, default: { enabled: false } do
24
+ optional(:enabled).filled(:bool)
25
+ optional(:items).array(:hash)
26
+ end
27
+
28
+ # Map component to page types
29
+ config.allow_components :index, :sidebar
30
+ config.allow_components :show, :sidebar
31
+
32
+ # Make component required for a page type
33
+ config.require_components :index, :sidebar
34
+
35
+ # Override a default component
36
+ config.register_component :pagination, default: { enabled: true, per_page: 25 }
37
+ end
38
+ ```
39
+
40
+ --------------------------------
41
+
42
+ ### Configuration API
43
+
44
+ | Method | Description |
45
+ |--------|-------------|
46
+ | `register_component(name, options, &schema)` | Register a component with optional schema |
47
+ | `allow_components(page_type, *names)` | Map components to a page type |
48
+ | `require_components(page_type, *names)` | Mark components as required for a page type |
49
+ | `components_for(page_type)` | Get component names for a page type |
50
+ | `component(name)` | Get a component definition |
51
+ | `component_required?(page_type, name)` | Check if component is required |
52
+
53
+ --------------------------------
54
+
55
+ ### Page Type DSL
56
+
57
+ Base page classes use `page_type` to inherit components from global configuration:
58
+
59
+ ```ruby
60
+ # app/pages/index_base_page.rb
61
+ class IndexBasePage < ApplicationPage
62
+ page_type :index # Inherits components mapped to :index
63
+
64
+ # Add local components
65
+ register_component :quick_filters, default: []
66
+
67
+ def index
68
+ build_page
69
+ end
70
+
71
+ def view_component_class
72
+ BetterPage::IndexViewComponent
73
+ end
74
+ end
75
+ ```
76
+
77
+ Available page types: `:index`, `:show`, `:form`, `:custom`
78
+
79
+ --------------------------------
80
+
81
+ ### Default Components
82
+
83
+ BetterPage registers these components by default:
84
+
85
+ **Shared Components:**
86
+ - `header` - Page header with title, breadcrumbs, actions
87
+ - `alerts` - Alert messages (default: `[]`)
88
+ - `footer` - Footer section (default: `{ enabled: false }`)
89
+ - `statistics` - Statistic cards (default: `[]`)
90
+ - `overview` - Overview section (default: `{ enabled: false }`)
91
+
92
+ **Index Components:**
93
+ - `table` - Data table with columns and actions
94
+ - `metrics` - Metric displays
95
+ - `tabs` - Tab navigation
96
+ - `search` - Search configuration
97
+ - `pagination` - Pagination settings
98
+ - `calendar` - Calendar view
99
+ - `modals` - Modal dialogs
100
+ - `split_view` - Split view layout
101
+
102
+ **Show Components:**
103
+ - `content_sections` - Content sections
104
+
105
+ **Form Components:**
106
+ - `panels` - Form panels with fields
107
+ - `errors` - Error display
108
+
109
+ **Custom Components:**
110
+ - `content` - Custom content
111
+
112
+ --------------------------------
113
+
114
+ ### Sync Generator
115
+
116
+ Check for new components when upgrading BetterPage:
117
+
118
+ ```bash
119
+ rails generate better_page:sync
120
+ ```
121
+
122
+ This compares your configuration with gem defaults and reports:
123
+ - New components available from the gem
124
+ - Components you've customized
125
+
126
+ --------------------------------
127
+
128
+ ### Example: Adding a Custom Component
129
+
130
+ ```ruby
131
+ # 1. Register in initializer
132
+ # config/initializers/better_page.rb
133
+ BetterPage.configure do |config|
134
+ config.register_component :activity_feed, default: { events: [], limit: 10 } do
135
+ optional(:events).array(:hash)
136
+ optional(:limit).filled(:integer)
137
+ end
138
+ config.allow_components :show, :activity_feed
139
+ end
140
+
141
+ # 2. Use in a page
142
+ # app/pages/admin/users/show_page.rb
143
+ class Admin::Users::ShowPage < ShowBasePage
144
+ def activity_feed
145
+ {
146
+ events: @user.recent_activities.map { |a| format_activity(a) },
147
+ limit: 20
148
+ }
149
+ end
150
+
151
+ private
152
+
153
+ def format_activity(activity)
154
+ { type: activity.type, message: activity.message, at: activity.created_at }
155
+ end
156
+ end
157
+ ```
@@ -0,0 +1,32 @@
1
+ # BetterPage Guides
2
+
3
+ Step-by-step tutorials for building pages with BetterPage.
4
+
5
+ ### Guide Index
6
+
7
+ | Guide | Description |
8
+ |-------|-------------|
9
+ | [01-quick-start](01-quick-start.md) | Get started in 5 minutes |
10
+ | [02-building-index-page](02-building-index-page.md) | Build feature-rich list pages |
11
+ | [03-building-show-page](03-building-show-page.md) | Build detail pages with content sections |
12
+ | [04-building-form-page](04-building-form-page.md) | Build new and edit forms |
13
+ | [05-custom-pages](05-custom-pages.md) | Build dashboards and reports |
14
+ | [06-best-practices](06-best-practices.md) | Guidelines for maintainable pages |
15
+
16
+ --------------------------------
17
+
18
+ ### Prerequisites
19
+
20
+ Before starting, ensure you have:
21
+ - Rails >= 8.1.1
22
+ - BetterPage gem installed
23
+ - Basic familiarity with Ruby and Rails
24
+
25
+ --------------------------------
26
+
27
+ ### Getting Help
28
+
29
+ If you need assistance:
30
+ - Check the [documentation](../docs/00-README.md)
31
+ - Review the example code in each guide
32
+ - Run compliance checks: `rake better_page:analyze`
@@ -0,0 +1,148 @@
1
+ # Quick Start Guide
2
+
3
+ Get started with BetterPage in 5 minutes.
4
+
5
+ ### Install the Gem
6
+
7
+ ```ruby
8
+ # Gemfile
9
+ gem "better_page"
10
+ ```
11
+
12
+ ```bash
13
+ bundle install
14
+ rails g better_page:install
15
+ ```
16
+
17
+ This creates:
18
+ - `app/pages/application_page.rb` - Base page class
19
+ - `app/pages/index_base_page.rb` - Base for index pages
20
+ - `app/pages/show_base_page.rb` - Base for show pages
21
+ - `app/pages/form_base_page.rb` - Base for form pages
22
+ - `app/pages/custom_base_page.rb` - Base for custom pages
23
+ - `config/initializers/better_page.rb` - Configuration file
24
+
25
+ --------------------------------
26
+
27
+ ### Generate Your First Page
28
+
29
+ ```bash
30
+ rails g better_page:page Admin::Products index show new edit
31
+ ```
32
+
33
+ This creates:
34
+ - `app/pages/admin/products/index_page.rb`
35
+ - `app/pages/admin/products/show_page.rb`
36
+ - `app/pages/admin/products/new_page.rb`
37
+ - `app/pages/admin/products/edit_page.rb`
38
+
39
+ --------------------------------
40
+
41
+ ### Basic Index Page
42
+
43
+ ```ruby
44
+ # app/pages/admin/products/index_page.rb
45
+ module Admin
46
+ module Products
47
+ class IndexPage < IndexBasePage
48
+ def initialize(products, metadata = {})
49
+ @products = products
50
+ @user = metadata[:user]
51
+ super(products, metadata)
52
+ end
53
+
54
+ private
55
+
56
+ def header
57
+ {
58
+ title: "Products",
59
+ breadcrumbs: [
60
+ { label: "Home", path: "/" },
61
+ { label: "Products" }
62
+ ],
63
+ actions: [
64
+ { label: "New Product", path: "/products/new", icon: "plus", style: :primary }
65
+ ]
66
+ }
67
+ end
68
+
69
+ def table
70
+ {
71
+ items: @products,
72
+ columns: [
73
+ { key: :name, label: "Name", type: :link },
74
+ { key: :price, label: "Price", format: :currency },
75
+ { key: :active, label: "Status", type: :boolean }
76
+ ],
77
+ empty_state: {
78
+ icon: "box",
79
+ title: "No products yet",
80
+ message: "Create your first product to get started"
81
+ }
82
+ }
83
+ end
84
+ end
85
+ end
86
+ end
87
+ ```
88
+
89
+ --------------------------------
90
+
91
+ ### Use in Controller
92
+
93
+ ```ruby
94
+ # app/controllers/admin/products_controller.rb
95
+ class Admin::ProductsController < ApplicationController
96
+ def index
97
+ products = Product.all
98
+ @page = Admin::Products::IndexPage.new(products, user: current_user).index
99
+ end
100
+ end
101
+ ```
102
+
103
+ --------------------------------
104
+
105
+ ### Render in View
106
+
107
+ ```erb
108
+ <%# app/views/admin/products/index.html.erb %>
109
+ <%= render "shared/page", page: @page %>
110
+ ```
111
+
112
+ Or access data directly:
113
+
114
+ ```erb
115
+ <h1><%= @page[:header][:title] %></h1>
116
+
117
+ <table>
118
+ <thead>
119
+ <tr>
120
+ <% @page[:table][:columns].each do |column| %>
121
+ <th><%= column[:label] %></th>
122
+ <% end %>
123
+ </tr>
124
+ </thead>
125
+ <tbody>
126
+ <% @page[:table][:items].each do |item| %>
127
+ <tr>
128
+ <% @page[:table][:columns].each do |column| %>
129
+ <td><%= item.send(column[:key]) %></td>
130
+ <% end %>
131
+ </tr>
132
+ <% end %>
133
+ </tbody>
134
+ </table>
135
+ ```
136
+
137
+ --------------------------------
138
+
139
+ ### Verify Compliance
140
+
141
+ ```bash
142
+ rake better_page:analyze
143
+ ```
144
+
145
+ This ensures your pages follow the architecture rules:
146
+ - No database queries in pages
147
+ - No business logic
148
+ - Data passed via constructor