plutonium 0.34.1 → 0.35.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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium/skill.md +53 -0
  3. data/.claude/skills/{assets → plutonium-assets}/SKILL.md +13 -8
  4. data/.claude/skills/{connect-resource → plutonium-connect-resource}/SKILL.md +1 -1
  5. data/.claude/skills/{controller → plutonium-controller}/SKILL.md +27 -13
  6. data/.claude/skills/{create-resource → plutonium-create-resource}/SKILL.md +1 -1
  7. data/.claude/skills/{definition → plutonium-definition}/SKILL.md +10 -10
  8. data/.claude/skills/{definition-actions → plutonium-definition-actions}/SKILL.md +34 -9
  9. data/.claude/skills/{definition-fields → plutonium-definition-fields}/SKILL.md +38 -10
  10. data/.claude/skills/plutonium-definition-query/SKILL.md +356 -0
  11. data/.claude/skills/{forms → plutonium-forms}/SKILL.md +6 -6
  12. data/.claude/skills/{installation → plutonium-installation}/SKILL.md +9 -9
  13. data/.claude/skills/{interaction → plutonium-interaction}/SKILL.md +20 -19
  14. data/.claude/skills/{model → plutonium-model}/SKILL.md +3 -3
  15. data/.claude/skills/{model-features → plutonium-model-features}/SKILL.md +3 -3
  16. data/.claude/skills/{nested-resources → plutonium-nested-resources}/SKILL.md +5 -5
  17. data/.claude/skills/{package → plutonium-package}/SKILL.md +7 -8
  18. data/.claude/skills/{policy → plutonium-policy}/SKILL.md +26 -4
  19. data/.claude/skills/{portal → plutonium-portal}/SKILL.md +33 -31
  20. data/.claude/skills/{resource → plutonium-resource}/SKILL.md +27 -27
  21. data/.claude/skills/{rodauth → plutonium-rodauth}/SKILL.md +5 -5
  22. data/.claude/skills/plutonium-theming/SKILL.md +424 -0
  23. data/.claude/skills/{views → plutonium-views}/SKILL.md +7 -7
  24. data/CHANGELOG.md +52 -0
  25. data/CLAUDE.md +215 -0
  26. data/CONTRIBUTING.md +72 -18
  27. data/README.md +100 -19
  28. data/app/assets/plutonium.css +1 -11
  29. data/app/assets/plutonium.js +1685 -1146
  30. data/app/assets/plutonium.js.map +4 -4
  31. data/app/assets/plutonium.min.js +70 -70
  32. data/app/assets/plutonium.min.js.map +4 -4
  33. data/app/views/resource/interactive_bulk_action.html.erb +1 -5
  34. data/app/views/rodauth/_email_auth_request_form.html.erb +1 -1
  35. data/app/views/rodauth/_login_form.html.erb +15 -55
  36. data/app/views/rodauth/_login_form_footer.html.erb +2 -2
  37. data/app/views/rodauth/_password_visibility.html.erb +2 -8
  38. data/app/views/rodauth/add_recovery_codes.html.erb +2 -2
  39. data/app/views/rodauth/change_login.html.erb +36 -19
  40. data/app/views/rodauth/change_password.html.erb +34 -10
  41. data/app/views/rodauth/close_account.html.erb +12 -4
  42. data/app/views/rodauth/confirm_password.html.erb +19 -17
  43. data/app/views/rodauth/create_account.html.erb +30 -109
  44. data/app/views/rodauth/email_auth.html.erb +1 -1
  45. data/app/views/rodauth/logout.html.erb +4 -4
  46. data/app/views/rodauth/otp_auth.html.erb +13 -4
  47. data/app/views/rodauth/otp_disable.html.erb +12 -4
  48. data/app/views/rodauth/otp_setup.html.erb +29 -12
  49. data/app/views/rodauth/otp_unlock.html.erb +19 -10
  50. data/app/views/rodauth/otp_unlock_not_available.html.erb +7 -7
  51. data/app/views/rodauth/recovery_auth.html.erb +12 -4
  52. data/app/views/rodauth/recovery_codes.html.erb +12 -4
  53. data/app/views/rodauth/remember.html.erb +7 -7
  54. data/app/views/rodauth/reset_password.html.erb +23 -7
  55. data/app/views/rodauth/reset_password_request.html.erb +14 -10
  56. data/app/views/rodauth/sms_auth.html.erb +13 -4
  57. data/app/views/rodauth/sms_confirm.html.erb +13 -4
  58. data/app/views/rodauth/sms_disable.html.erb +12 -4
  59. data/app/views/rodauth/sms_request.html.erb +1 -1
  60. data/app/views/rodauth/sms_setup.html.erb +23 -7
  61. data/app/views/rodauth/two_factor_auth.html.erb +2 -2
  62. data/app/views/rodauth/two_factor_disable.html.erb +12 -4
  63. data/app/views/rodauth/two_factor_manage.html.erb +7 -7
  64. data/app/views/rodauth/unlock_account.html.erb +13 -5
  65. data/app/views/rodauth/unlock_account_request.html.erb +2 -2
  66. data/app/views/rodauth/verify_account.html.erb +25 -7
  67. data/app/views/rodauth/verify_account_resend.html.erb +14 -10
  68. data/app/views/rodauth/verify_login_change.html.erb +1 -1
  69. data/app/views/rodauth/webauthn_auth.html.erb +1 -1
  70. data/app/views/rodauth/webauthn_remove.html.erb +18 -8
  71. data/app/views/rodauth/webauthn_setup.html.erb +12 -4
  72. data/docs/.vitepress/config.ts +15 -26
  73. data/docs/.vitepress/theme/custom.css +388 -29
  74. data/docs/getting-started/index.md +1 -1
  75. data/docs/getting-started/tutorial/02-first-resource.md +9 -0
  76. data/docs/getting-started/tutorial/06-nested-resources.md +2 -2
  77. data/docs/getting-started/tutorial/07-author-portal.md +191 -0
  78. data/docs/getting-started/tutorial/{07-customizing-ui.md → 08-customizing-ui.md} +7 -7
  79. data/docs/getting-started/tutorial/index.md +5 -2
  80. data/docs/guides/authorization.md +33 -0
  81. data/docs/guides/creating-packages.md +12 -16
  82. data/docs/guides/custom-actions.md +36 -0
  83. data/docs/guides/search-filtering.md +121 -42
  84. data/docs/guides/theming.md +232 -36
  85. data/docs/index.md +203 -57
  86. data/docs/public/og-image.png +0 -0
  87. data/docs/reference/controller/index.md +14 -16
  88. data/docs/reference/definition/actions.md +38 -3
  89. data/docs/reference/definition/fields.md +3 -3
  90. data/docs/reference/definition/index.md +2 -2
  91. data/docs/reference/generators/index.md +0 -1
  92. data/docs/reference/interaction/index.md +14 -10
  93. data/docs/reference/model/index.md +0 -1
  94. data/docs/reference/portal/index.md +13 -27
  95. data/gemfiles/rails_7.gemfile.lock +1 -1
  96. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  97. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  98. data/lib/generators/pu/pkg/portal/portal_generator.rb +0 -2
  99. data/lib/generators/pu/pkg/portal/templates/app/views/package/dashboard/index.html.erb +28 -72
  100. data/lib/plutonium/action/interactive.rb +2 -2
  101. data/lib/plutonium/core/controller.rb +2 -1
  102. data/lib/plutonium/definition/actions.rb +2 -2
  103. data/lib/plutonium/lib/deep_freezer.rb +3 -7
  104. data/lib/plutonium/query/filter.rb +14 -0
  105. data/lib/plutonium/query/filters/association.rb +49 -0
  106. data/lib/plutonium/query/filters/boolean.rb +35 -0
  107. data/lib/plutonium/query/filters/date.rb +97 -0
  108. data/lib/plutonium/query/filters/date_range.rb +58 -0
  109. data/lib/plutonium/query/filters/select.rb +55 -0
  110. data/lib/plutonium/resource/controllers/crud_actions.rb +24 -6
  111. data/lib/plutonium/resource/controllers/interactive_actions.rb +76 -58
  112. data/lib/plutonium/resource/controllers/queryable.rb +4 -2
  113. data/lib/plutonium/resource/query_object.rb +1 -1
  114. data/lib/plutonium/ui/action_button.rb +23 -65
  115. data/lib/plutonium/ui/actions_dropdown.rb +103 -0
  116. data/lib/plutonium/ui/block.rb +1 -1
  117. data/lib/plutonium/ui/breadcrumbs.rb +12 -19
  118. data/lib/plutonium/ui/color_mode_selector.rb +1 -1
  119. data/lib/plutonium/ui/component/kit.rb +6 -0
  120. data/lib/plutonium/ui/component_classes.rb +102 -0
  121. data/lib/plutonium/ui/display/base.rb +15 -0
  122. data/lib/plutonium/ui/display/components/attachment.rb +6 -5
  123. data/lib/plutonium/ui/display/components/boolean.rb +23 -0
  124. data/lib/plutonium/ui/display/components/color.rb +23 -0
  125. data/lib/plutonium/ui/display/resource.rb +1 -1
  126. data/lib/plutonium/ui/display/theme.rb +29 -15
  127. data/lib/plutonium/ui/empty_card.rb +3 -3
  128. data/lib/plutonium/ui/form/base.rb +20 -0
  129. data/lib/plutonium/ui/form/components/key_value_store.rb +11 -11
  130. data/lib/plutonium/ui/form/components/resource_select.rb +31 -0
  131. data/lib/plutonium/ui/form/components/secure_association.rb +1 -2
  132. data/lib/plutonium/ui/form/components/uppy.rb +5 -4
  133. data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +4 -4
  134. data/lib/plutonium/ui/form/interaction.rb +17 -1
  135. data/lib/plutonium/ui/form/query.rb +133 -80
  136. data/lib/plutonium/ui/form/theme.rb +50 -35
  137. data/lib/plutonium/ui/frame_navigator_panel.rb +2 -2
  138. data/lib/plutonium/ui/layout/base.rb +1 -1
  139. data/lib/plutonium/ui/layout/header.rb +4 -7
  140. data/lib/plutonium/ui/layout/rodauth_layout.rb +7 -7
  141. data/lib/plutonium/ui/layout/sidebar.rb +1 -1
  142. data/lib/plutonium/ui/nav_grid_menu.rb +7 -6
  143. data/lib/plutonium/ui/nav_user.rb +9 -8
  144. data/lib/plutonium/ui/page/interactive_action.rb +5 -5
  145. data/lib/plutonium/ui/page_header.rb +29 -10
  146. data/lib/plutonium/ui/panel.rb +4 -4
  147. data/lib/plutonium/ui/sidebar_menu.rb +8 -8
  148. data/lib/plutonium/ui/skeleton_table.rb +7 -8
  149. data/lib/plutonium/ui/tab_list.rb +5 -5
  150. data/lib/plutonium/ui/table/base.rb +3 -0
  151. data/lib/plutonium/ui/table/components/attachment.rb +4 -3
  152. data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +82 -0
  153. data/lib/plutonium/ui/table/components/pagy_info.rb +2 -2
  154. data/lib/plutonium/ui/table/components/pagy_pagination.rb +13 -8
  155. data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +101 -0
  156. data/lib/plutonium/ui/table/components/scopes_bar.rb +2 -2
  157. data/lib/plutonium/ui/table/components/selection_column.rb +100 -0
  158. data/lib/plutonium/ui/table/display_theme.rb +6 -6
  159. data/lib/plutonium/ui/table/resource.rb +93 -52
  160. data/lib/plutonium/ui/table/theme.rb +28 -15
  161. data/lib/plutonium/version.rb +1 -1
  162. data/package.json +2 -2
  163. data/plutonium.gemspec +5 -4
  164. data/src/css/components.css +471 -0
  165. data/src/css/intl_tel_input.css +2 -2
  166. data/src/css/plutonium.css +2 -0
  167. data/src/css/tokens.css +149 -0
  168. data/src/js/controllers/bulk_actions_controller.js +109 -0
  169. data/src/js/controllers/filter_panel_controller.js +35 -0
  170. data/src/js/controllers/register_controllers.js +5 -1
  171. data/src/js/controllers/resource_drop_down_controller.js +25 -1
  172. data/src/js/controllers/slim_select_controller.js +6 -2
  173. data/src/js/turbo/turbo_actions.js +1 -1
  174. metadata +52 -39
  175. data/.claude/skills/definition-query/SKILL.md +0 -334
  176. data/docs/concepts/architecture.md +0 -226
  177. data/docs/concepts/auto-detection.md +0 -254
  178. data/docs/concepts/index.md +0 -61
  179. data/docs/concepts/packages-portals.md +0 -304
  180. data/docs/concepts/resources.md +0 -224
  181. data/docs/cookbook/blog.md +0 -411
  182. data/docs/cookbook/index.md +0 -289
  183. data/docs/cookbook/saas.md +0 -481
  184. data/docs/public/CLAUDE.md +0 -578
  185. data/lib/generators/pu/pkg/portal/templates/app/controllers/resource_controller.rb.tt +0 -5
@@ -4,11 +4,224 @@ This guide covers customizing colors, styles, and branding.
4
4
 
5
5
  ## Overview
6
6
 
7
- Plutonium uses TailwindCSS 4 for styling. Customization happens through:
7
+ Plutonium uses TailwindCSS 4 with a design token system for consistent styling. Customization happens through:
8
8
 
9
+ - **Design Tokens** - CSS custom properties for colors, spacing, shadows
10
+ - **Component Classes** - Pre-built `.pu-*` classes for buttons, inputs, tables
9
11
  - **Tailwind Configuration** - Extend colors and design tokens
10
12
  - **Component Themes** - Override form, table, and display styling
11
- - **Asset Configuration** - Custom CSS, JS, logo, and favicon
13
+
14
+ ## Design Token System
15
+
16
+ Plutonium uses CSS custom properties (design tokens) for theming. These tokens automatically adapt to light and dark modes.
17
+
18
+ ### Available Tokens
19
+
20
+ #### Surface Colors
21
+
22
+ ```css
23
+ --pu-body /* Page background */
24
+ --pu-surface /* Card/panel backgrounds */
25
+ --pu-surface-alt /* Alternate surface (headers, sidebars) */
26
+ --pu-surface-raised /* Elevated surfaces */
27
+ --pu-surface-overlay /* Modal/dropdown overlays */
28
+ ```
29
+
30
+ #### Border Colors
31
+
32
+ ```css
33
+ --pu-border /* Default borders */
34
+ --pu-border-muted /* Subtle borders */
35
+ --pu-border-strong /* Emphasized borders */
36
+ ```
37
+
38
+ #### Text Colors
39
+
40
+ ```css
41
+ --pu-text /* Primary text */
42
+ --pu-text-muted /* Secondary text */
43
+ --pu-text-subtle /* Tertiary/placeholder text */
44
+ ```
45
+
46
+ #### Table Tokens
47
+
48
+ ```css
49
+ --pu-table-header-bg /* Header background */
50
+ --pu-table-header-text /* Header text color */
51
+ --pu-table-row-bg /* Row background */
52
+ --pu-table-row-hover /* Row hover state */
53
+ --pu-table-row-selected /* Selected row */
54
+ --pu-table-border /* Row borders */
55
+ ```
56
+
57
+ #### Form Tokens
58
+
59
+ ```css
60
+ --pu-input-bg /* Input background */
61
+ --pu-input-border /* Input border */
62
+ --pu-input-focus-ring /* Focus ring color */
63
+ --pu-input-placeholder /* Placeholder text */
64
+ ```
65
+
66
+ #### Card Tokens
67
+
68
+ ```css
69
+ --pu-card-bg /* Card background */
70
+ --pu-card-border /* Card border */
71
+ ```
72
+
73
+ #### Shadow System
74
+
75
+ ```css
76
+ --pu-shadow-sm /* Subtle shadow */
77
+ --pu-shadow-md /* Medium shadow */
78
+ --pu-shadow-lg /* Large shadow */
79
+ ```
80
+
81
+ #### Spacing Scale
82
+
83
+ ```css
84
+ --pu-space-xs /* 0.25rem */
85
+ --pu-space-sm /* 0.5rem */
86
+ --pu-space-md /* 1rem */
87
+ --pu-space-lg /* 1.5rem */
88
+ --pu-space-xl /* 2rem */
89
+ ```
90
+
91
+ #### Border Radius
92
+
93
+ ```css
94
+ --pu-radius-sm /* 0.375rem */
95
+ --pu-radius-md /* 0.5rem */
96
+ --pu-radius-lg /* 0.75rem */
97
+ --pu-radius-xl /* 1rem */
98
+ --pu-radius-full /* 9999px */
99
+ ```
100
+
101
+ #### Transitions
102
+
103
+ ```css
104
+ --pu-transition-fast /* 150ms */
105
+ --pu-transition-normal /* 200ms */
106
+ --pu-transition-slow /* 300ms */
107
+ ```
108
+
109
+ ### Overriding Tokens
110
+
111
+ Override tokens in your CSS to customize the theme:
112
+
113
+ ```css
114
+ /* app/assets/stylesheets/application.css */
115
+ @import "tailwindcss";
116
+ @import "gem:plutonium/src/css/plutonium.css";
117
+
118
+ /* Light mode overrides */
119
+ :root {
120
+ --pu-surface: #fafafa;
121
+ --pu-border: #d4d4d4;
122
+ --pu-input-focus-ring: #6366f1;
123
+ }
124
+
125
+ /* Dark mode overrides */
126
+ .dark {
127
+ --pu-surface: #18181b;
128
+ --pu-border: #3f3f46;
129
+ }
130
+ ```
131
+
132
+ ## Component Classes
133
+
134
+ Plutonium provides pre-built component classes for common UI elements.
135
+
136
+ ### Buttons
137
+
138
+ ```html
139
+ <!-- Sizes -->
140
+ <button class="pu-btn pu-btn-md pu-btn-primary">Medium</button>
141
+ <button class="pu-btn pu-btn-sm pu-btn-primary">Small</button>
142
+ <button class="pu-btn pu-btn-xs pu-btn-primary">Extra Small</button>
143
+
144
+ <!-- Solid variants -->
145
+ <button class="pu-btn pu-btn-md pu-btn-primary">Primary</button>
146
+ <button class="pu-btn pu-btn-md pu-btn-secondary">Secondary</button>
147
+ <button class="pu-btn pu-btn-md pu-btn-success">Success</button>
148
+ <button class="pu-btn pu-btn-md pu-btn-danger">Danger</button>
149
+ <button class="pu-btn pu-btn-md pu-btn-warning">Warning</button>
150
+ <button class="pu-btn pu-btn-md pu-btn-info">Info</button>
151
+ <button class="pu-btn pu-btn-md pu-btn-accent">Accent</button>
152
+
153
+ <!-- Soft variants (tinted backgrounds) -->
154
+ <button class="pu-btn pu-btn-md pu-btn-soft-primary">Soft Primary</button>
155
+ <button class="pu-btn pu-btn-md pu-btn-soft-secondary">Soft Secondary</button>
156
+ <button class="pu-btn pu-btn-md pu-btn-soft-success">Soft Success</button>
157
+ <button class="pu-btn pu-btn-md pu-btn-soft-danger">Soft Danger</button>
158
+ <button class="pu-btn pu-btn-md pu-btn-soft-warning">Soft Warning</button>
159
+ <button class="pu-btn pu-btn-md pu-btn-soft-info">Soft Info</button>
160
+ <button class="pu-btn pu-btn-md pu-btn-soft-accent">Soft Accent</button>
161
+
162
+ <!-- Other styles -->
163
+ <button class="pu-btn pu-btn-md pu-btn-ghost">Ghost</button>
164
+ <button class="pu-btn pu-btn-md pu-btn-outline">Outline</button>
165
+ ```
166
+
167
+ ### Form Inputs
168
+
169
+ ```html
170
+ <label class="pu-label">Email</label>
171
+ <input type="email" class="pu-input" placeholder="you@example.com">
172
+ <p class="pu-hint">We'll never share your email.</p>
173
+
174
+ <!-- Validation states -->
175
+ <input type="text" class="pu-input pu-input-invalid">
176
+ <p class="pu-error">This field is required.</p>
177
+
178
+ <input type="text" class="pu-input pu-input-valid">
179
+ ```
180
+
181
+ ### Checkboxes
182
+
183
+ ```html
184
+ <input type="checkbox" class="pu-checkbox">
185
+ ```
186
+
187
+ ### Cards
188
+
189
+ ```html
190
+ <div class="pu-card">
191
+ <div class="pu-card-body">
192
+ Card content here
193
+ </div>
194
+ </div>
195
+ ```
196
+
197
+ ### Tables
198
+
199
+ ```html
200
+ <div class="pu-table-wrapper">
201
+ <table class="pu-table">
202
+ <thead class="pu-table-header">
203
+ <tr>
204
+ <th class="pu-table-header-cell">Name</th>
205
+ </tr>
206
+ </thead>
207
+ <tbody>
208
+ <tr class="pu-table-body-row">
209
+ <td class="pu-table-body-cell">John</td>
210
+ </tr>
211
+ </tbody>
212
+ </table>
213
+ </div>
214
+ ```
215
+
216
+ ### Empty States
217
+
218
+ ```html
219
+ <div class="pu-empty-state">
220
+ <svg class="pu-empty-state-icon">...</svg>
221
+ <h3 class="pu-empty-state-title">No items found</h3>
222
+ <p class="pu-empty-state-description">Get started by creating a new item.</p>
223
+ </div>
224
+ ```
12
225
 
13
226
  ## Setup Custom Assets
14
227
 
@@ -125,7 +338,7 @@ Plutonium includes these semantic colors:
125
338
  @import "tailwindcss";
126
339
  @config '../../../tailwind.config.js';
127
340
 
128
- /* Your custom styles */
341
+ /* Your custom styles and token overrides */
129
342
  ```
130
343
 
131
344
  ## Component Themes
@@ -140,14 +353,14 @@ class PostDefinition < ResourceDefinition
140
353
  class Theme < Plutonium::UI::Form::Theme
141
354
  def self.theme
142
355
  super.merge({
143
- base: "bg-white dark:bg-gray-800 shadow-md rounded-lg p-6",
356
+ base: "pu-card my-4 p-8 space-y-8",
144
357
  fields_wrapper: "grid grid-cols-2 gap-6",
145
358
  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",
359
+ label: "pu-label",
360
+ input: "pu-input",
361
+ hint: "pu-hint",
362
+ error: "pu-error",
363
+ button: "pu-btn pu-btn-md pu-btn-primary",
151
364
  })
152
365
  end
153
366
  end
@@ -164,8 +377,8 @@ class PostDefinition < ResourceDefinition
164
377
  def self.theme
165
378
  super.merge({
166
379
  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",
380
+ label: "text-sm font-bold text-[var(--pu-text-muted)] mb-1",
381
+ string: "text-lg text-[var(--pu-text)]",
169
382
  link: "text-primary-600 hover:underline",
170
383
  })
171
384
  end
@@ -182,12 +395,12 @@ class PostDefinition < ResourceDefinition
182
395
  class Theme < Plutonium::UI::Table::Theme
183
396
  def self.theme
184
397
  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",
398
+ wrapper: "pu-table-wrapper",
399
+ base: "pu-table",
400
+ header: "pu-table-header",
401
+ header_cell: "pu-table-header-cell",
402
+ body_row: "pu-table-body-row",
403
+ body_cell: "pu-table-body-cell",
191
404
  })
192
405
  end
193
406
  end
@@ -253,6 +466,8 @@ document.documentElement.classList.toggle('dark');
253
466
 
254
467
  Plutonium includes a color mode selector component that handles this automatically.
255
468
 
469
+ Design tokens automatically adapt to dark mode - override the `.dark` selector in your CSS to customize dark mode colors.
470
+
256
471
  ## Stimulus Controllers
257
472
 
258
473
  Register Plutonium's Stimulus controllers in your application:
@@ -296,25 +511,6 @@ import CustomController from "./custom_controller"
296
511
  application.register("custom", CustomController)
297
512
  ```
298
513
 
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
514
  ## Related
319
515
 
320
516
  - [Custom Actions](./custom-actions)
data/docs/index.md CHANGED
@@ -2,81 +2,227 @@
2
2
  layout: home
3
3
  hero:
4
4
  name: Plutonium
5
- text: Rapid Application Development for Rails
6
- tagline: Build production-ready Rails applications in minutes, not months. Convention-driven, fully customizable.
5
+ text: Ship Rails Apps 10x Faster
6
+ tagline: Build production-ready Rails applications in minutes, not days. Convention-driven, fully customizable. Built for the AI era.
7
+ image:
8
+ src: /plutonium.png
9
+ alt: Plutonium
7
10
  actions:
8
11
  - theme: brand
9
- text: Get Started
12
+ text: Get Started
10
13
  link: /getting-started/
11
14
  - theme: alt
12
- text: View on GitHub
15
+ text: GitHub
13
16
  link: https://github.com/radioactive-labs/plutonium-core
14
-
15
- features:
16
- - icon: 🚀
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.
22
- - icon: 🎨
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.
34
17
  ---
35
18
 
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.
19
+ <div class="landing-content">
20
+
21
+ <section class="before-after">
22
+ <h2>The Old Way vs The Plutonium Way</h2>
23
+ <div class="comparison">
24
+ <div class="before">
25
+ <h3>Without Plutonium</h3>
26
+ <div class="file-tree">
27
+ <div class="file">app/controllers/posts_controller.rb</div>
28
+ <div class="file">app/controllers/comments_controller.rb</div>
29
+ <div class="file">app/views/posts/index.html.erb</div>
30
+ <div class="file">app/views/posts/show.html.erb</div>
31
+ <div class="file">app/views/posts/new.html.erb</div>
32
+ <div class="file">app/views/posts/edit.html.erb</div>
33
+ <div class="file">app/views/posts/_form.html.erb</div>
34
+ <div class="file dim">...12 more files</div>
35
+ </div>
36
+ <div class="stats">
37
+ <span>~200 lines</span>
38
+ <span>30+ minutes</span>
39
+ <span>No auth yet</span>
40
+ </div>
41
+ </div>
42
+ <div class="arrow">→</div>
43
+ <div class="after">
44
+ <h3>With Plutonium</h3>
45
45
 
46
46
  ```bash
47
- # Create a new Plutonium app
48
- rails new myapp -a propshaft -j esbuild -c tailwind \
49
- -m https://radioactive-labs.github.io/plutonium-core/templates/plutonium.rb
47
+ rails g pu:res:scaffold Post \
48
+ title:string body:text
50
49
 
51
- # Generate a resource
52
- rails g pu:res:scaffold Post title:string body:text published:boolean
53
-
54
- # Connect it to a portal
55
- rails g pu:res:conn Post --dest=admin_portal
50
+ rails g pu:res:conn Post \
51
+ --dest=admin_portal
52
+ ```
56
53
 
57
- # Done. Full CRUD with auth, policies, and UI.
54
+ <div class="stats success">
55
+ <span>2 commands</span>
56
+ <span>30 seconds</span>
57
+ <span>Auth included</span>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </section>
62
+
63
+ <section class="ai-section">
64
+ <h2>Built for the AI Era</h2>
65
+ <p class="ai-intro">Plutonium is the first Rails framework designed from the ground up for AI-assisted development. Every pattern, every convention, every file structure is optimized for AI comprehension.</p>
66
+
67
+ <div class="ai-features">
68
+ <div class="ai-feature">
69
+ <div class="ai-icon">🧠</div>
70
+ <h3>Claude Code Skills</h3>
71
+ <p>20+ built-in skills teach AI assistants your app's patterns. Resources, policies, definitions, interactions - Claude understands them all.</p>
72
+ </div>
73
+ <div class="ai-feature">
74
+ <div class="ai-icon">⚡</div>
75
+ <h3>Predictable Patterns</h3>
76
+ <p>Convention-heavy architecture means AI can accurately predict file locations, naming, and relationships. Less hallucination, more precision.</p>
77
+ </div>
78
+ <div class="ai-feature">
79
+ <div class="ai-icon">🔄</div>
80
+ <h3>Generate & Iterate</h3>
81
+ <p>Tell Claude what you need. It generates the scaffold, policy, and definition. You refine. Ship in minutes what used to take hours.</p>
82
+ </div>
83
+ </div>
84
+
85
+ <div class="ai-example">
86
+ <div class="ai-prompt">
87
+ <span class="prompt-label">You say:</span>
88
+ <p>"Add a blog with posts and comments. Posts belong to users. Only authors can edit their posts. Add a publish action."</p>
89
+ </div>
90
+ <div class="ai-result">
91
+ <span class="result-label">Claude generates:</span>
92
+ <p>Model, migration, policy, definition, interaction, and connects it to your portal. Ready to customize.</p>
93
+ </div>
94
+ </div>
95
+ </section>
96
+
97
+ <section class="features-detailed">
98
+ <h2>Everything You Need, Nothing You Don't</h2>
99
+
100
+ <div class="feature-row">
101
+ <div class="feature-text">
102
+ <h3>Resources Are Your Foundation</h3>
103
+ <p>Just ActiveRecord. Associations, scopes, validations you already know. No new ORM to learn.</p>
104
+ </div>
105
+ <div class="feature-code">
106
+
107
+ ```ruby
108
+ class Post < ApplicationRecord
109
+ include Plutonium::Resource::Record
110
+
111
+ belongs_to :author, class_name: "User"
112
+ has_many :comments
113
+
114
+ scope :published, -> { where.not(published_at: nil) }
115
+ scope :drafts, -> { where(published_at: nil) }
116
+ end
58
117
  ```
59
118
 
60
- ## How It Works
119
+ </div>
120
+ </div>
61
121
 
62
- Plutonium follows a layered architecture where each layer has a single responsibility:
122
+ <div class="feature-row reverse">
123
+ <div class="feature-text">
124
+ <h3>Definitions Control UI</h3>
125
+ <p>Declare how fields render. Add search, filters, scopes. Custom actions. All in one place.</p>
126
+ </div>
127
+ <div class="feature-code">
63
128
 
64
- | Layer | Purpose | File |
65
- |-------|---------|------|
66
- | **Model** | Data structure and validations | `app/models/post.rb` |
67
- | **Definition** | How the resource renders (fields, actions) | `app/definitions/post_definition.rb` |
68
- | **Policy** | Who can do what | `app/policies/post_policy.rb` |
69
- | **Controller** | HTTP handling and customization | `app/controllers/posts_controller.rb` |
129
+ ```ruby
130
+ class PostDefinition < ResourceDefinition
131
+ input :body, as: :markdown
70
132
 
71
- Each layer auto-detects sensible defaults. You only write code when you need to customize.
133
+ search do |scope, query|
134
+ scope.where("title ILIKE ?", "%#{query}%")
135
+ end
72
136
 
73
- ## Quick Links
137
+ scope :published
138
+ scope :drafts
74
139
 
75
- <div class="quick-links">
140
+ action :publish, interaction: PublishPost
141
+ end
142
+ ```
143
+
144
+ </div>
145
+ </div>
146
+
147
+ <div class="feature-row">
148
+ <div class="feature-text">
149
+ <h3>Interactions Encapsulate Logic</h3>
150
+ <p>Complex actions become simple classes. Validated inputs. Clear outcomes. Easy to test.</p>
151
+ </div>
152
+ <div class="feature-code">
153
+
154
+ ```ruby
155
+ class PublishPost < ResourceInteraction
156
+ attribute :resource
157
+ attribute :publish_at, :datetime
158
+
159
+ def execute
160
+ resource.published_at = publish_at
161
+ if resource.save
162
+ succeed(resource).with_message("Published!")
163
+ else
164
+ failed(resource.errors)
165
+ end
166
+ end
167
+ end
168
+ ```
169
+
170
+ </div>
171
+ </div>
172
+
173
+ <div class="feature-row reverse">
174
+ <div class="feature-text">
175
+ <h3>Policies Control Access</h3>
176
+ <p>Define who can do what. Attribute-level permissions. Automatic scoping. No more <code>if current_user.admin?</code> scattered everywhere.</p>
177
+ </div>
178
+ <div class="feature-code">
179
+
180
+ ```ruby
181
+ class PostPolicy < ResourcePolicy
182
+ def update?
183
+ record.author == user || user.admin?
184
+ end
185
+
186
+ def permitted_attributes_for_create
187
+ %i[title body]
188
+ end
189
+ end
190
+ ```
76
191
 
77
- - [Installation Guide](/getting-started/installation) - Set up Plutonium in a new or existing Rails app
78
- - [Tutorial](/getting-started/tutorial/) - Build a complete blog application step by step
79
- - [Architecture Overview](/concepts/architecture) - Understand how the pieces fit together
80
- - [Reference Documentation](/reference/model/) - Detailed API documentation
192
+ </div>
193
+ </div>
194
+ </section>
195
+
196
+ <section class="feature-grid">
197
+ <div class="grid-item">
198
+ <div class="icon">📦</div>
199
+ <h3>Modular Packages</h3>
200
+ <p>Split your app into Feature Packages and Portals. Each isolated, testable, and reusable.</p>
201
+ </div>
202
+ <div class="grid-item">
203
+ <div class="icon">🔐</div>
204
+ <h3>Auth Built In</h3>
205
+ <p>Rodauth integration with login, registration, 2FA, and password reset. Ready in one command.</p>
206
+ </div>
207
+ <div class="grid-item">
208
+ <div class="icon">🏢</div>
209
+ <h3>Multi-Tenancy</h3>
210
+ <p>Entity scoping works out of the box. Path-based or custom strategies. Data isolation guaranteed.</p>
211
+ </div>
212
+ <div class="grid-item">
213
+ <div class="icon">🎨</div>
214
+ <h3>Fully Customizable</h3>
215
+ <p>Override any layer. Custom views with Phlex. Your CSS. No black boxes.</p>
216
+ </div>
217
+ </section>
218
+
219
+ <section class="cta-section">
220
+ <h2>Ready to Build Faster?</h2>
221
+ <p>Get a complete admin interface running in under 5 minutes.</p>
222
+ <div class="cta-buttons">
223
+ <a href="./getting-started/" class="cta-primary">Get Started</a>
224
+ <a href="./getting-started/tutorial/" class="cta-secondary">Follow the Tutorial</a>
225
+ </div>
226
+ </section>
81
227
 
82
228
  </div>
Binary file
@@ -20,24 +20,19 @@ class PostsController < ::ResourceController
20
20
  end
21
21
  ```
22
22
 
23
- For portals:
23
+ For portals, controllers inherit from the feature package's controller and include the portal's concern:
24
24
 
25
25
  ```ruby
26
- # packages/admin_portal/app/controllers/admin_portal/resource_controller.rb
27
- module AdminPortal
28
- class ResourceController < ::ResourceController
29
- include AdminPortal::Concerns::Controller
30
- end
31
- end
32
-
33
26
  # packages/admin_portal/app/controllers/admin_portal/posts_controller.rb
34
- module AdminPortal
35
- class PostsController < ResourceController
36
- # Portal-specific customizations
37
- end
27
+ class AdminPortal::PostsController < ::PostsController
28
+ include AdminPortal::Concerns::Controller
29
+
30
+ # Portal-specific customizations
38
31
  end
39
32
  ```
40
33
 
34
+ Controllers are auto-created if not defined. When accessing a portal resource controller, Plutonium dynamically creates it by inheriting from the feature package's controller.
35
+
41
36
  ## Built-in Actions
42
37
 
43
38
  | Action | HTTP Method | Path | Purpose |
@@ -67,10 +62,13 @@ current_parent # Parent record for nested routes
67
62
  ### Authorization
68
63
 
69
64
  ```ruby
70
- authorize_current!(record, to: :action?) # Check permission
71
- current_policy # Policy for current resource
72
- permitted_attributes # Allowed attributes for action
73
- current_authorized_scope # Scoped records user can access
65
+ authorize_current!(record, to: :action?) # Check permission
66
+ current_policy # Policy for current resource
67
+ permitted_attributes # Allowed attributes for action
68
+ current_authorized_scope # Scoped records user can access
69
+ authorized_resource_scope(Post) # Authorized scope for a different resource
70
+ policy_for(record) # Get policy for any record
71
+ allowed_to?(:edit?, record) # Check if action is allowed
74
72
  ```
75
73
 
76
74
  ### Definition Access