plutonium 0.33.1 → 0.34.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/# Plutonium: The pre-alpha demo.md +4 -2
  3. data/.claude/skills/assets/SKILL.md +416 -0
  4. data/.claude/skills/connect-resource/SKILL.md +112 -0
  5. data/.claude/skills/controller/SKILL.md +302 -0
  6. data/.claude/skills/create-resource/SKILL.md +240 -0
  7. data/.claude/skills/definition/SKILL.md +218 -0
  8. data/.claude/skills/definition-actions/SKILL.md +386 -0
  9. data/.claude/skills/definition-fields/SKILL.md +474 -0
  10. data/.claude/skills/definition-query/SKILL.md +334 -0
  11. data/.claude/skills/forms/SKILL.md +439 -0
  12. data/.claude/skills/installation/SKILL.md +300 -0
  13. data/.claude/skills/interaction/SKILL.md +382 -0
  14. data/.claude/skills/model/SKILL.md +267 -0
  15. data/.claude/skills/model-features/SKILL.md +286 -0
  16. data/.claude/skills/nested-resources/SKILL.md +274 -0
  17. data/.claude/skills/package/SKILL.md +191 -0
  18. data/.claude/skills/policy/SKILL.md +352 -0
  19. data/.claude/skills/portal/SKILL.md +400 -0
  20. data/.claude/skills/resource/SKILL.md +281 -0
  21. data/.claude/skills/rodauth/SKILL.md +452 -0
  22. data/.claude/skills/views/SKILL.md +563 -0
  23. data/Appraisals +46 -4
  24. data/CHANGELOG.md +32 -1
  25. data/app/assets/plutonium.css +2 -2
  26. data/config/brakeman.ignore +239 -0
  27. data/config/initializers/action_policy.rb +1 -1
  28. data/docs/.vitepress/config.ts +132 -47
  29. data/docs/concepts/architecture.md +226 -0
  30. data/docs/concepts/auto-detection.md +254 -0
  31. data/docs/concepts/index.md +61 -0
  32. data/docs/concepts/packages-portals.md +304 -0
  33. data/docs/concepts/resources.md +224 -0
  34. data/docs/cookbook/blog.md +412 -0
  35. data/docs/cookbook/index.md +289 -0
  36. data/docs/cookbook/saas.md +481 -0
  37. data/docs/getting-started/index.md +56 -0
  38. data/docs/getting-started/installation.md +146 -0
  39. data/docs/getting-started/tutorial/01-setup.md +118 -0
  40. data/docs/getting-started/tutorial/02-first-resource.md +180 -0
  41. data/docs/getting-started/tutorial/03-authentication.md +246 -0
  42. data/docs/getting-started/tutorial/04-authorization.md +170 -0
  43. data/docs/getting-started/tutorial/05-custom-actions.md +202 -0
  44. data/docs/getting-started/tutorial/06-nested-resources.md +147 -0
  45. data/docs/getting-started/tutorial/07-customizing-ui.md +254 -0
  46. data/docs/getting-started/tutorial/index.md +64 -0
  47. data/docs/guides/adding-resources.md +420 -0
  48. data/docs/guides/authentication.md +551 -0
  49. data/docs/guides/authorization.md +468 -0
  50. data/docs/guides/creating-packages.md +380 -0
  51. data/docs/guides/custom-actions.md +523 -0
  52. data/docs/guides/index.md +45 -0
  53. data/docs/guides/multi-tenancy.md +302 -0
  54. data/docs/guides/nested-resources.md +411 -0
  55. data/docs/guides/search-filtering.md +266 -0
  56. data/docs/guides/theming.md +321 -0
  57. data/docs/index.md +67 -26
  58. data/docs/public/CLAUDE.md +64 -21
  59. data/docs/reference/assets/index.md +496 -0
  60. data/docs/reference/controller/index.md +363 -0
  61. data/docs/reference/definition/actions.md +400 -0
  62. data/docs/reference/definition/fields.md +350 -0
  63. data/docs/reference/definition/index.md +252 -0
  64. data/docs/reference/definition/query.md +342 -0
  65. data/docs/reference/generators/index.md +469 -0
  66. data/docs/reference/index.md +49 -0
  67. data/docs/reference/interaction/index.md +445 -0
  68. data/docs/reference/model/features.md +248 -0
  69. data/docs/reference/model/index.md +219 -0
  70. data/docs/reference/policy/index.md +385 -0
  71. data/docs/reference/portal/index.md +382 -0
  72. data/docs/reference/views/forms.md +396 -0
  73. data/docs/reference/views/index.md +479 -0
  74. data/gemfiles/rails_7.gemfile +9 -2
  75. data/gemfiles/rails_7.gemfile.lock +146 -111
  76. data/gemfiles/rails_8.0.gemfile +20 -0
  77. data/gemfiles/rails_8.0.gemfile.lock +417 -0
  78. data/gemfiles/rails_8.1.gemfile +20 -0
  79. data/gemfiles/rails_8.1.gemfile.lock +419 -0
  80. data/lib/generators/pu/gem/dotenv/templates/.env +2 -0
  81. data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +3 -1
  82. data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +13 -16
  83. data/lib/generators/pu/pkg/portal/USAGE +65 -0
  84. data/lib/generators/pu/pkg/portal/portal_generator.rb +22 -9
  85. data/lib/generators/pu/res/conn/USAGE +71 -0
  86. data/lib/generators/pu/res/model/USAGE +106 -110
  87. data/lib/generators/pu/res/model/templates/model.rb.tt +6 -2
  88. data/lib/generators/pu/res/scaffold/USAGE +85 -0
  89. data/lib/generators/pu/rodauth/install_generator.rb +2 -6
  90. data/lib/generators/pu/rodauth/templates/config/initializers/url_options.rb +17 -0
  91. data/lib/generators/pu/skills/sync/USAGE +14 -0
  92. data/lib/generators/pu/skills/sync/sync_generator.rb +66 -0
  93. data/lib/plutonium/action_policy/sti_policy_lookup.rb +1 -1
  94. data/lib/plutonium/core/controller.rb +2 -2
  95. data/lib/plutonium/interaction/base.rb +1 -0
  96. data/lib/plutonium/package/engine.rb +2 -2
  97. data/lib/plutonium/query/adhoc_block.rb +6 -2
  98. data/lib/plutonium/query/model_scope.rb +1 -1
  99. data/lib/plutonium/railtie.rb +4 -0
  100. data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +1 -1
  101. data/lib/plutonium/resource/query_object.rb +38 -8
  102. data/lib/plutonium/ui/table/components/scopes_bar.rb +39 -34
  103. data/lib/plutonium/version.rb +1 -1
  104. data/lib/tasks/release.rake +19 -4
  105. data/package.json +1 -1
  106. metadata +76 -39
  107. data/brakeman.ignore +0 -28
  108. data/docs/api-examples.md +0 -49
  109. data/docs/guide/claude-code-guide.md +0 -74
  110. data/docs/guide/deep-dive/authorization.md +0 -189
  111. data/docs/guide/deep-dive/multitenancy.md +0 -256
  112. data/docs/guide/deep-dive/resources.md +0 -390
  113. data/docs/guide/getting-started/01-installation.md +0 -165
  114. data/docs/guide/index.md +0 -28
  115. data/docs/guide/introduction/01-what-is-plutonium.md +0 -211
  116. data/docs/guide/introduction/02-core-concepts.md +0 -440
  117. data/docs/guide/tutorial/01-project-setup.md +0 -75
  118. data/docs/guide/tutorial/02-creating-a-feature-package.md +0 -45
  119. data/docs/guide/tutorial/03-defining-resources.md +0 -90
  120. data/docs/guide/tutorial/04-creating-a-portal.md +0 -101
  121. data/docs/guide/tutorial/05-customizing-the-ui.md +0 -128
  122. data/docs/guide/tutorial/06-adding-custom-actions.md +0 -101
  123. data/docs/guide/tutorial/07-implementing-authorization.md +0 -90
  124. data/docs/markdown-examples.md +0 -85
  125. data/docs/modules/action.md +0 -244
  126. data/docs/modules/authentication.md +0 -236
  127. data/docs/modules/configuration.md +0 -599
  128. data/docs/modules/controller.md +0 -443
  129. data/docs/modules/core.md +0 -316
  130. data/docs/modules/definition.md +0 -1308
  131. data/docs/modules/display.md +0 -759
  132. data/docs/modules/form.md +0 -495
  133. data/docs/modules/generator.md +0 -400
  134. data/docs/modules/index.md +0 -167
  135. data/docs/modules/interaction.md +0 -642
  136. data/docs/modules/package.md +0 -151
  137. data/docs/modules/policy.md +0 -176
  138. data/docs/modules/portal.md +0 -710
  139. data/docs/modules/query.md +0 -297
  140. data/docs/modules/resource_record.md +0 -618
  141. data/docs/modules/routing.md +0 -690
  142. data/docs/modules/table.md +0 -301
  143. data/docs/modules/ui.md +0 -631
@@ -0,0 +1,266 @@
1
+ # Search and Filtering
2
+
3
+ This guide covers implementing search, filters, scopes, and sorting.
4
+
5
+ ## Overview
6
+
7
+ Plutonium provides built-in support for:
8
+ - **Search** - Full-text search across fields
9
+ - **Filters** - Input filters for specific fields
10
+ - **Scopes** - Predefined query shortcuts (quick filter buttons)
11
+ - **Sorting** - Column-based ordering
12
+
13
+ ## Search
14
+
15
+ Define global search in the definition:
16
+
17
+ ```ruby
18
+ class PostDefinition < ResourceDefinition
19
+ search do |scope, query|
20
+ scope.where("title ILIKE ?", "%#{query}%")
21
+ end
22
+ end
23
+ ```
24
+
25
+ ### Multi-Field Search
26
+
27
+ ```ruby
28
+ search do |scope, query|
29
+ scope.where(
30
+ "title ILIKE :q OR content ILIKE :q OR author_name ILIKE :q",
31
+ q: "%#{query}%"
32
+ )
33
+ end
34
+ ```
35
+
36
+ ### Search with Associations
37
+
38
+ ```ruby
39
+ search do |scope, query|
40
+ scope.joins(:author).where(
41
+ "posts.title ILIKE :q OR users.name ILIKE :q",
42
+ q: "%#{query}%"
43
+ ).distinct
44
+ end
45
+ ```
46
+
47
+ ### Split Search Terms
48
+
49
+ ```ruby
50
+ search do |scope, query|
51
+ terms = query.split(/\s+/)
52
+ terms.reduce(scope) do |current_scope, term|
53
+ current_scope.where("title ILIKE ?", "%#{term}%")
54
+ end
55
+ end
56
+ ```
57
+
58
+ ### Full-Text Search (PostgreSQL)
59
+
60
+ ```ruby
61
+ search do |scope, query|
62
+ scope.where(
63
+ "to_tsvector('english', title || ' ' || body) @@ plainto_tsquery('english', ?)",
64
+ query
65
+ )
66
+ end
67
+ ```
68
+
69
+ ## Filters
70
+
71
+ Filters provide UI controls for narrowing results.
72
+
73
+ ### Text Filter
74
+
75
+ The built-in `Text` filter supports various predicates:
76
+
77
+ ```ruby
78
+ class PostDefinition < ResourceDefinition
79
+ # Exact match
80
+ filter :status, with: Plutonium::Query::Filters::Text, predicate: :eq
81
+
82
+ # Contains (LIKE %value%)
83
+ filter :title, with: Plutonium::Query::Filters::Text, predicate: :contains
84
+
85
+ # Starts with
86
+ filter :slug, with: Plutonium::Query::Filters::Text, predicate: :starts_with
87
+
88
+ # Ends with
89
+ filter :email, with: Plutonium::Query::Filters::Text, predicate: :ends_with
90
+ end
91
+ ```
92
+
93
+ ### Available Predicates
94
+
95
+ | Predicate | SQL | Description |
96
+ |-----------|-----|-------------|
97
+ | `:eq` | `= value` | Exact match |
98
+ | `:not_eq` | `!= value` | Not equal |
99
+ | `:contains` | `LIKE %value%` | Contains text |
100
+ | `:not_contains` | `NOT LIKE %value%` | Does not contain |
101
+ | `:starts_with` | `LIKE value%` | Starts with |
102
+ | `:ends_with` | `LIKE %value` | Ends with |
103
+ | `:matches` | `LIKE value` | Pattern match (`*` becomes `%`) |
104
+ | `:not_matches` | `NOT LIKE value` | Does not match pattern |
105
+
106
+ ### Custom Filter with Lambda
107
+
108
+ ```ruby
109
+ filter :published, with: ->(scope, value) {
110
+ value == "true" ? scope.where.not(published_at: nil) : scope.where(published_at: nil)
111
+ }
112
+
113
+ filter :has_comments, with: ->(scope, value) {
114
+ if value == "true"
115
+ scope.joins(:comments).distinct
116
+ else
117
+ scope.left_joins(:comments).where(comments: { id: nil })
118
+ end
119
+ }
120
+ ```
121
+
122
+ ### Custom Filter Class
123
+
124
+ ```ruby
125
+ class DateRangeFilter < Plutonium::Query::Filter
126
+ def apply(scope, start_date: nil, end_date: nil)
127
+ scope = scope.where("#{key} >= ?", start_date.beginning_of_day) if start_date.present?
128
+ scope = scope.where("#{key} <= ?", end_date.end_of_day) if end_date.present?
129
+ scope
130
+ end
131
+
132
+ def customize_inputs
133
+ input :start_date, as: :date
134
+ input :end_date, as: :date
135
+ end
136
+ end
137
+
138
+ # Use in definition
139
+ filter :created_at, with: DateRangeFilter
140
+ ```
141
+
142
+ ## Scopes
143
+
144
+ Scopes appear as quick filter buttons. They reference model scopes or use inline blocks.
145
+
146
+ ### Basic Scopes
147
+
148
+ Reference existing model scopes:
149
+
150
+ ```ruby
151
+ class PostDefinition < ResourceDefinition
152
+ scope :published # Uses Post.published
153
+ scope :draft # Uses Post.draft
154
+ scope :featured # Uses Post.featured
155
+ end
156
+ ```
157
+
158
+ ### Inline Scopes
159
+
160
+ Use block syntax with the scope passed as an argument:
161
+
162
+ ```ruby
163
+ scope(:recent) { |scope| scope.where("created_at > ?", 1.week.ago) }
164
+ scope(:this_month) { |scope| scope.where(created_at: Time.current.all_month) }
165
+ ```
166
+
167
+ ### With Controller Context
168
+
169
+ Inline scopes have access to controller context like `current_user`:
170
+
171
+ ```ruby
172
+ scope(:mine) { |scope| scope.where(author: current_user) }
173
+ scope(:my_team) { |scope| scope.where(team: current_user.team) }
174
+ ```
175
+
176
+ ### Default Scope
177
+
178
+ Set a scope as default:
179
+
180
+ ```ruby
181
+ class PostDefinition < ResourceDefinition
182
+ scope :published, default: true # Applied by default
183
+ scope :draft
184
+ scope :archived
185
+ end
186
+ ```
187
+
188
+ When a default scope is set:
189
+ - The default scope is applied on initial page load
190
+ - The default scope button is highlighted (not "All")
191
+ - Clicking "All" shows all records without any scope filter
192
+
193
+ ## Sorting
194
+
195
+ ### Define Sortable Fields
196
+
197
+ ```ruby
198
+ class PostDefinition < ResourceDefinition
199
+ sort :title
200
+ sort :created_at
201
+ sort :view_count
202
+
203
+ # Multiple at once
204
+ sorts :title, :created_at, :view_count
205
+ end
206
+ ```
207
+
208
+ ### Default Sort Order
209
+
210
+ ```ruby
211
+ # Field and direction
212
+ default_sort :created_at, :desc
213
+ default_sort :title, :asc
214
+
215
+ # Complex sorting with block
216
+ default_sort { |scope| scope.order(featured: :desc, created_at: :desc) }
217
+ ```
218
+
219
+ **Note:** Default sort only applies when no sort params are provided. The system default is `:id, :desc`.
220
+
221
+ ## URL Parameters
222
+
223
+ Query parameters are structured under `q`:
224
+
225
+ ```
226
+ /posts?q[search]=rails
227
+ /posts?q[status][query]=published
228
+ /posts?q[scope]=recent
229
+ /posts?q[sort_fields][]=created_at&q[sort_directions][created_at]=desc
230
+ ```
231
+
232
+ ## Complete Example
233
+
234
+ ```ruby
235
+ class PostDefinition < ResourceDefinition
236
+ # Full-text search
237
+ search do |scope, query|
238
+ scope.where(
239
+ "title ILIKE :q OR content ILIKE :q",
240
+ q: "%#{query}%"
241
+ )
242
+ end
243
+
244
+ # Filters
245
+ filter :status, with: Plutonium::Query::Filters::Text, predicate: :eq
246
+ filter :category, with: Plutonium::Query::Filters::Text, predicate: :eq
247
+ filter :title, with: Plutonium::Query::Filters::Text, predicate: :contains
248
+
249
+ # Quick scopes (reference model scopes)
250
+ scope :published
251
+ scope :draft
252
+ scope :featured
253
+ scope(:recent) { |scope| scope.where("created_at > ?", 1.week.ago) }
254
+
255
+ # Sortable columns
256
+ sorts :title, :created_at, :view_count, :published_at
257
+
258
+ # Default: newest first
259
+ default_sort :created_at, :desc
260
+ end
261
+ ```
262
+
263
+ ## Related
264
+
265
+ - [Custom Actions](./custom-actions)
266
+ - [Authorization](./authorization)
@@ -0,0 +1,321 @@
1
+ # Theming
2
+
3
+ This guide covers customizing colors, styles, and branding.
4
+
5
+ ## Overview
6
+
7
+ Plutonium uses TailwindCSS 4 for styling. Customization happens through:
8
+
9
+ - **Tailwind Configuration** - Extend colors and design tokens
10
+ - **Component Themes** - Override form, table, and display styling
11
+ - **Asset Configuration** - Custom CSS, JS, logo, and favicon
12
+
13
+ ## Setup Custom Assets
14
+
15
+ Run the assets generator to set up your own TailwindCSS build:
16
+
17
+ ```bash
18
+ rails generate pu:core:assets
19
+ ```
20
+
21
+ This:
22
+ 1. Installs required npm packages (`@radioactive-labs/plutonium`, TailwindCSS plugins)
23
+ 2. Creates `tailwind.config.js` that extends Plutonium's config
24
+ 3. Imports Plutonium CSS into your `application.tailwind.css`
25
+ 4. Registers Plutonium's Stimulus controllers
26
+ 5. Updates Plutonium config to use your assets
27
+
28
+ ## Asset Configuration
29
+
30
+ Configure assets in the initializer:
31
+
32
+ ```ruby
33
+ # config/initializers/plutonium.rb
34
+ Plutonium.configure do |config|
35
+ config.load_defaults 1.0
36
+
37
+ config.assets.stylesheet = "application" # Your CSS file
38
+ config.assets.script = "application" # Your JS file
39
+ config.assets.logo = "my_logo.png" # Logo image
40
+ config.assets.favicon = "my_favicon.ico" # Favicon
41
+ end
42
+ ```
43
+
44
+ ## TailwindCSS Configuration
45
+
46
+ ### Generated Config
47
+
48
+ ```javascript
49
+ // tailwind.config.js
50
+ const { execSync } = require('child_process');
51
+ const plutoniumGemPath = execSync("bundle show plutonium").toString().trim();
52
+ const plutoniumTailwindConfig = require(`${plutoniumGemPath}/tailwind.options.js`)
53
+
54
+ module.exports = {
55
+ darkMode: plutoniumTailwindConfig.darkMode,
56
+ plugins: [
57
+ // Add your plugins here
58
+ ].concat(plutoniumTailwindConfig.plugins),
59
+ theme: plutoniumTailwindConfig.merge(
60
+ plutoniumTailwindConfig.theme,
61
+ {
62
+ // Your custom theme overrides
63
+ },
64
+ ),
65
+ content: [
66
+ `${__dirname}/app/**/*.{erb,haml,html,slim,rb}`,
67
+ `${__dirname}/app/javascript/**/*.js`,
68
+ `${__dirname}/packages/**/app/**/*.{erb,haml,html,slim,rb}`,
69
+ ].concat(plutoniumTailwindConfig.content),
70
+ }
71
+ ```
72
+
73
+ ### Customizing Colors
74
+
75
+ Override Plutonium's color palette:
76
+
77
+ ```javascript
78
+ // tailwind.config.js
79
+ theme: plutoniumTailwindConfig.merge(
80
+ plutoniumTailwindConfig.theme,
81
+ {
82
+ extend: {
83
+ colors: {
84
+ primary: {
85
+ 50: '#eff6ff',
86
+ 100: '#dbeafe',
87
+ 200: '#bfdbfe',
88
+ 300: '#93c5fd',
89
+ 400: '#60a5fa',
90
+ 500: '#3b82f6', // Your brand color
91
+ 600: '#2563eb',
92
+ 700: '#1d4ed8',
93
+ 800: '#1e40af',
94
+ 900: '#1e3a8a',
95
+ 950: '#172554',
96
+ },
97
+ },
98
+ },
99
+ },
100
+ ),
101
+ ```
102
+
103
+ ### Semantic Colors
104
+
105
+ Plutonium includes these semantic colors:
106
+
107
+ | Color | Usage |
108
+ |-------|-------|
109
+ | `primary` | Primary brand color |
110
+ | `secondary` | Secondary color |
111
+ | `success` | Success states (green) |
112
+ | `info` | Informational states (blue) |
113
+ | `warning` | Warning states (amber) |
114
+ | `danger` | Error/danger states (red) |
115
+ | `accent` | Accent highlights |
116
+
117
+ ## CSS Imports
118
+
119
+ ### Application Stylesheet
120
+
121
+ ```css
122
+ /* app/assets/stylesheets/application.tailwind.css */
123
+ @import "gem:plutonium/src/css/plutonium.css";
124
+
125
+ @import "tailwindcss";
126
+ @config '../../../tailwind.config.js';
127
+
128
+ /* Your custom styles */
129
+ ```
130
+
131
+ ## Component Themes
132
+
133
+ Plutonium components use a theme system. Override themes by defining nested Theme classes in your definitions.
134
+
135
+ ### Form Theme
136
+
137
+ ```ruby
138
+ class PostDefinition < ResourceDefinition
139
+ class Form < Form
140
+ class Theme < Plutonium::UI::Form::Theme
141
+ def self.theme
142
+ super.merge({
143
+ base: "bg-white dark:bg-gray-800 shadow-md rounded-lg p-6",
144
+ fields_wrapper: "grid grid-cols-2 gap-6",
145
+ actions_wrapper: "flex justify-end mt-6 space-x-2",
146
+ label: "block mb-2 text-base font-bold",
147
+ input: "w-full p-2 border rounded-md shadow-sm",
148
+ hint: "mt-2 text-sm text-gray-500",
149
+ error: "mt-2 text-sm text-red-600",
150
+ button: "px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700",
151
+ })
152
+ end
153
+ end
154
+ end
155
+ end
156
+ ```
157
+
158
+ ### Display Theme
159
+
160
+ ```ruby
161
+ class PostDefinition < ResourceDefinition
162
+ class Display < Display
163
+ class Theme < Plutonium::UI::Display::Theme
164
+ def self.theme
165
+ super.merge({
166
+ fields_wrapper: "grid grid-cols-3 gap-8",
167
+ label: "text-sm font-bold text-gray-500 mb-1",
168
+ string: "text-lg text-gray-900 dark:text-white",
169
+ link: "text-primary-600 hover:underline",
170
+ })
171
+ end
172
+ end
173
+ end
174
+ end
175
+ ```
176
+
177
+ ### Table Theme
178
+
179
+ ```ruby
180
+ class PostDefinition < ResourceDefinition
181
+ class Table < Table
182
+ class Theme < Plutonium::UI::Table::Theme
183
+ def self.theme
184
+ super.merge({
185
+ wrapper: "overflow-x-auto shadow-md rounded-lg",
186
+ base: "w-full text-sm text-gray-500",
187
+ header: "text-xs uppercase bg-gray-100 dark:bg-gray-700",
188
+ header_cell: "px-6 py-3",
189
+ body_row: "bg-white border-b dark:bg-gray-800",
190
+ body_cell: "px-6 py-4",
191
+ })
192
+ end
193
+ end
194
+ end
195
+ end
196
+ ```
197
+
198
+ ## Branding
199
+
200
+ ### Application Name
201
+
202
+ ```ruby
203
+ # config/initializers/plutonium.rb
204
+ Plutonium.application_name = "My Application"
205
+ ```
206
+
207
+ ### Custom Logo
208
+
209
+ Override the logo in your layout:
210
+
211
+ ```ruby
212
+ # packages/admin_portal/app/views/layouts/admin_portal/application.rb
213
+ module AdminPortal
214
+ class ApplicationLayout < Plutonium::UI::Layout::Application
215
+ def render_logo
216
+ img(src: helpers.asset_path("logo.svg"), alt: "My App", class: "h-8")
217
+ end
218
+ end
219
+ end
220
+ ```
221
+
222
+ ### Custom Fonts
223
+
224
+ Override in your layout:
225
+
226
+ ```ruby
227
+ class MyLayout < Plutonium::UI::Layout::ResourceLayout
228
+ def render_fonts
229
+ link(rel: "preconnect", href: "https://fonts.googleapis.com")
230
+ link(href: "https://fonts.googleapis.com/css2?family=Inter&display=swap", rel: "stylesheet")
231
+ end
232
+ end
233
+ ```
234
+
235
+ Update Tailwind config:
236
+
237
+ ```javascript
238
+ theme: {
239
+ fontFamily: {
240
+ 'body': ['Inter', 'sans-serif'],
241
+ 'sans': ['Inter', 'sans-serif'],
242
+ }
243
+ }
244
+ ```
245
+
246
+ ## Dark Mode
247
+
248
+ Plutonium uses `selector` strategy for dark mode. Toggle by adding/removing the `dark` class on `<html>`:
249
+
250
+ ```javascript
251
+ document.documentElement.classList.toggle('dark');
252
+ ```
253
+
254
+ Plutonium includes a color mode selector component that handles this automatically.
255
+
256
+ ## Stimulus Controllers
257
+
258
+ Register Plutonium's Stimulus controllers in your application:
259
+
260
+ ```javascript
261
+ // app/javascript/controllers/index.js
262
+ import { application } from "./application"
263
+
264
+ import { registerControllers } from "@radioactive-labs/plutonium"
265
+ registerControllers(application)
266
+
267
+ // Your custom controllers...
268
+ ```
269
+
270
+ ### Available Controllers
271
+
272
+ - `color-mode` - Dark/light mode toggle
273
+ - `form` - Form handling
274
+ - `nested-resource-form-fields` - Nested form management
275
+ - `slim-select` - Enhanced select boxes
276
+ - `flatpickr` - Date/time pickers
277
+ - `easymde` - Markdown editor
278
+
279
+ ### Custom Controllers
280
+
281
+ ```javascript
282
+ // app/javascript/controllers/custom_controller.js
283
+ import { Controller } from "@hotwired/stimulus"
284
+
285
+ export default class extends Controller {
286
+ connect() {
287
+ console.log("Connected")
288
+ }
289
+ }
290
+ ```
291
+
292
+ Register in your index:
293
+
294
+ ```javascript
295
+ import CustomController from "./custom_controller"
296
+ application.register("custom", CustomController)
297
+ ```
298
+
299
+ ## Portal-Specific Themes
300
+
301
+ Different portals can have different themes by overriding definitions per-portal:
302
+
303
+ ```ruby
304
+ # packages/admin_portal/app/definitions/admin_portal/post_definition.rb
305
+ class AdminPortal::PostDefinition < ::PostDefinition
306
+ class Form < Form
307
+ class Theme < Plutonium::UI::Form::Theme
308
+ def self.theme
309
+ super.merge({
310
+ base: "bg-blue-50 p-8", # Admin-specific styling
311
+ })
312
+ end
313
+ end
314
+ end
315
+ end
316
+ ```
317
+
318
+ ## Related
319
+
320
+ - [Custom Actions](./custom-actions)
321
+ - [Creating Packages](./creating-packages)
data/docs/index.md CHANGED
@@ -1,40 +1,81 @@
1
1
  ---
2
- # https://vitepress.dev/reference/default-theme-home-page
3
2
  layout: home
4
-
5
3
  hero:
6
4
  name: Plutonium
7
- text: The Rails RAD Toolkit
8
- tagline: Build feature-rich, enterprise-ready applications at lightning speed. Stop writing boilerplate, start building features.
9
- image:
10
- src: /plutonium.png
11
- alt: Plutonium
5
+ text: Rapid Application Development for Rails
6
+ tagline: Build production-ready Rails applications in minutes, not months. Convention-driven, fully customizable.
12
7
  actions:
13
8
  - theme: brand
14
- text: Start the Tutorial
15
- link: /guide/tutorial/01-project-setup
9
+ text: Get Started
10
+ link: /getting-started/
16
11
  - theme: alt
17
- text: Core Concepts
18
- link: /guide/introduction/02-core-concepts
12
+ text: View on GitHub
13
+ link: https://github.com/radioactive-labs/plutonium-core
19
14
 
20
15
  features:
21
16
  - icon: 🚀
22
- title: Unmatched Developer Experience
23
- details: Smart generators, convention-over-configuration, and intelligent defaults let you focus on what matters.
24
- - icon: 🏗️
25
- title: Robust Architecture
26
- details: Built-in multitenancy, modular packages, and advanced authorization provide a solid foundation for any project.
17
+ title: Zero to Production Fast
18
+ details: Generate complete CRUD interfaces with a single command. Authentication, authorization, and UI included out of the box.
19
+ - icon: 🧩
20
+ title: Modular Architecture
21
+ details: Organize your app into Feature Packages and Portals. Each module is isolated, testable, and reusable.
27
22
  - icon: 🎨
28
- title: Flexible UI & Theming
29
- details: Start with a beautiful, modern UI out-of-the-box, then customize any aspect with a powerful and expressive API.
30
-
23
+ title: Fully Customizable
24
+ details: Every layer is overridable. Customize fields, forms, tables, pages, and styles without fighting the framework.
25
+ - icon: 🔐
26
+ title: Built-in Authorization
27
+ details: Policy-based authorization at every level - actions, attributes, and collection scoping. Multi-tenancy ready.
28
+ - icon: 📦
29
+ title: Convention over Configuration
30
+ details: Smart defaults detect your models, associations, and validations. Only configure what you need to change.
31
+ - icon: 🛠️
32
+ title: Rails Native
33
+ details: Built on Rails conventions. Uses Phlex for views, Rodauth for auth, and standard Rails patterns throughout.
31
34
  ---
32
35
 
33
- <style>
34
- :root {
35
- --vp-home-hero-name-color: transparent;
36
- --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #da8ee7 30%, #5f4dff);
36
+ ## Why Plutonium?
37
+
38
+ Building admin panels, dashboards, and internal tools in Rails often means:
39
+ - Writing repetitive CRUD code
40
+ - Building authorization from scratch
41
+ - Creating forms and tables manually
42
+ - Handling multi-tenancy yourself
43
+
44
+ **Plutonium eliminates this boilerplate** while remaining fully customizable.
45
+
46
+ ```bash
47
+ # Create a new Plutonium app
48
+ rails new myapp -m https://radioactive-labs.github.io/plutonium-core/templates/plutonium.rb
49
+
50
+ # Generate a resource
51
+ rails g pu:res:scaffold Post title:string body:text published:boolean
52
+
53
+ # Connect it to a portal
54
+ rails g pu:res:conn Post --portal AdminPortal
55
+
56
+ # Done. Full CRUD with auth, policies, and UI.
57
+ ```
58
+
59
+ ## How It Works
60
+
61
+ Plutonium follows a layered architecture where each layer has a single responsibility:
62
+
63
+ | Layer | Purpose | File |
64
+ |-------|---------|------|
65
+ | **Model** | Data structure and validations | `app/models/post.rb` |
66
+ | **Definition** | How the resource renders (fields, actions) | `app/definitions/post_definition.rb` |
67
+ | **Policy** | Who can do what | `app/policies/post_policy.rb` |
68
+ | **Controller** | HTTP handling and customization | `app/controllers/posts_controller.rb` |
69
+
70
+ Each layer auto-detects sensible defaults. You only write code when you need to customize.
71
+
72
+ ## Quick Links
73
+
74
+ <div class="quick-links">
75
+
76
+ - [Installation Guide](/getting-started/installation) - Set up Plutonium in a new or existing Rails app
77
+ - [Tutorial](/getting-started/tutorial/) - Build a complete blog application step by step
78
+ - [Architecture Overview](/concepts/architecture) - Understand how the pieces fit together
79
+ - [Reference Documentation](/reference/model/) - Detailed API documentation
37
80
 
38
- --vp-home-hero-image-filter: blur(56px);
39
- }
40
- </style>
81
+ </div>