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.
- checksums.yaml +4 -4
- data/.claude/skills/plutonium/skill.md +53 -0
- data/.claude/skills/{assets → plutonium-assets}/SKILL.md +13 -8
- data/.claude/skills/{connect-resource → plutonium-connect-resource}/SKILL.md +1 -1
- data/.claude/skills/{controller → plutonium-controller}/SKILL.md +27 -13
- data/.claude/skills/{create-resource → plutonium-create-resource}/SKILL.md +1 -1
- data/.claude/skills/{definition → plutonium-definition}/SKILL.md +10 -10
- data/.claude/skills/{definition-actions → plutonium-definition-actions}/SKILL.md +34 -9
- data/.claude/skills/{definition-fields → plutonium-definition-fields}/SKILL.md +38 -10
- data/.claude/skills/plutonium-definition-query/SKILL.md +356 -0
- data/.claude/skills/{forms → plutonium-forms}/SKILL.md +6 -6
- data/.claude/skills/{installation → plutonium-installation}/SKILL.md +9 -9
- data/.claude/skills/{interaction → plutonium-interaction}/SKILL.md +20 -19
- data/.claude/skills/{model → plutonium-model}/SKILL.md +3 -3
- data/.claude/skills/{model-features → plutonium-model-features}/SKILL.md +3 -3
- data/.claude/skills/{nested-resources → plutonium-nested-resources}/SKILL.md +5 -5
- data/.claude/skills/{package → plutonium-package}/SKILL.md +7 -8
- data/.claude/skills/{policy → plutonium-policy}/SKILL.md +26 -4
- data/.claude/skills/{portal → plutonium-portal}/SKILL.md +33 -31
- data/.claude/skills/{resource → plutonium-resource}/SKILL.md +27 -27
- data/.claude/skills/{rodauth → plutonium-rodauth}/SKILL.md +5 -5
- data/.claude/skills/plutonium-theming/SKILL.md +424 -0
- data/.claude/skills/{views → plutonium-views}/SKILL.md +7 -7
- data/CHANGELOG.md +52 -0
- data/CLAUDE.md +215 -0
- data/CONTRIBUTING.md +72 -18
- data/README.md +100 -19
- data/app/assets/plutonium.css +1 -11
- data/app/assets/plutonium.js +1685 -1146
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +70 -70
- data/app/assets/plutonium.min.js.map +4 -4
- data/app/views/resource/interactive_bulk_action.html.erb +1 -5
- data/app/views/rodauth/_email_auth_request_form.html.erb +1 -1
- data/app/views/rodauth/_login_form.html.erb +15 -55
- data/app/views/rodauth/_login_form_footer.html.erb +2 -2
- data/app/views/rodauth/_password_visibility.html.erb +2 -8
- data/app/views/rodauth/add_recovery_codes.html.erb +2 -2
- data/app/views/rodauth/change_login.html.erb +36 -19
- data/app/views/rodauth/change_password.html.erb +34 -10
- data/app/views/rodauth/close_account.html.erb +12 -4
- data/app/views/rodauth/confirm_password.html.erb +19 -17
- data/app/views/rodauth/create_account.html.erb +30 -109
- data/app/views/rodauth/email_auth.html.erb +1 -1
- data/app/views/rodauth/logout.html.erb +4 -4
- data/app/views/rodauth/otp_auth.html.erb +13 -4
- data/app/views/rodauth/otp_disable.html.erb +12 -4
- data/app/views/rodauth/otp_setup.html.erb +29 -12
- data/app/views/rodauth/otp_unlock.html.erb +19 -10
- data/app/views/rodauth/otp_unlock_not_available.html.erb +7 -7
- data/app/views/rodauth/recovery_auth.html.erb +12 -4
- data/app/views/rodauth/recovery_codes.html.erb +12 -4
- data/app/views/rodauth/remember.html.erb +7 -7
- data/app/views/rodauth/reset_password.html.erb +23 -7
- data/app/views/rodauth/reset_password_request.html.erb +14 -10
- data/app/views/rodauth/sms_auth.html.erb +13 -4
- data/app/views/rodauth/sms_confirm.html.erb +13 -4
- data/app/views/rodauth/sms_disable.html.erb +12 -4
- data/app/views/rodauth/sms_request.html.erb +1 -1
- data/app/views/rodauth/sms_setup.html.erb +23 -7
- data/app/views/rodauth/two_factor_auth.html.erb +2 -2
- data/app/views/rodauth/two_factor_disable.html.erb +12 -4
- data/app/views/rodauth/two_factor_manage.html.erb +7 -7
- data/app/views/rodauth/unlock_account.html.erb +13 -5
- data/app/views/rodauth/unlock_account_request.html.erb +2 -2
- data/app/views/rodauth/verify_account.html.erb +25 -7
- data/app/views/rodauth/verify_account_resend.html.erb +14 -10
- data/app/views/rodauth/verify_login_change.html.erb +1 -1
- data/app/views/rodauth/webauthn_auth.html.erb +1 -1
- data/app/views/rodauth/webauthn_remove.html.erb +18 -8
- data/app/views/rodauth/webauthn_setup.html.erb +12 -4
- data/docs/.vitepress/config.ts +15 -26
- data/docs/.vitepress/theme/custom.css +388 -29
- data/docs/getting-started/index.md +1 -1
- data/docs/getting-started/tutorial/02-first-resource.md +9 -0
- data/docs/getting-started/tutorial/06-nested-resources.md +2 -2
- data/docs/getting-started/tutorial/07-author-portal.md +191 -0
- data/docs/getting-started/tutorial/{07-customizing-ui.md → 08-customizing-ui.md} +7 -7
- data/docs/getting-started/tutorial/index.md +5 -2
- data/docs/guides/authorization.md +33 -0
- data/docs/guides/creating-packages.md +12 -16
- data/docs/guides/custom-actions.md +36 -0
- data/docs/guides/search-filtering.md +121 -42
- data/docs/guides/theming.md +232 -36
- data/docs/index.md +203 -57
- data/docs/public/og-image.png +0 -0
- data/docs/reference/controller/index.md +14 -16
- data/docs/reference/definition/actions.md +38 -3
- data/docs/reference/definition/fields.md +3 -3
- data/docs/reference/definition/index.md +2 -2
- data/docs/reference/generators/index.md +0 -1
- data/docs/reference/interaction/index.md +14 -10
- data/docs/reference/model/index.md +0 -1
- data/docs/reference/portal/index.md +13 -27
- data/gemfiles/rails_7.gemfile.lock +1 -1
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/pkg/portal/portal_generator.rb +0 -2
- data/lib/generators/pu/pkg/portal/templates/app/views/package/dashboard/index.html.erb +28 -72
- data/lib/plutonium/action/interactive.rb +2 -2
- data/lib/plutonium/core/controller.rb +2 -1
- data/lib/plutonium/definition/actions.rb +2 -2
- data/lib/plutonium/lib/deep_freezer.rb +3 -7
- data/lib/plutonium/query/filter.rb +14 -0
- data/lib/plutonium/query/filters/association.rb +49 -0
- data/lib/plutonium/query/filters/boolean.rb +35 -0
- data/lib/plutonium/query/filters/date.rb +97 -0
- data/lib/plutonium/query/filters/date_range.rb +58 -0
- data/lib/plutonium/query/filters/select.rb +55 -0
- data/lib/plutonium/resource/controllers/crud_actions.rb +24 -6
- data/lib/plutonium/resource/controllers/interactive_actions.rb +76 -58
- data/lib/plutonium/resource/controllers/queryable.rb +4 -2
- data/lib/plutonium/resource/query_object.rb +1 -1
- data/lib/plutonium/ui/action_button.rb +23 -65
- data/lib/plutonium/ui/actions_dropdown.rb +103 -0
- data/lib/plutonium/ui/block.rb +1 -1
- data/lib/plutonium/ui/breadcrumbs.rb +12 -19
- data/lib/plutonium/ui/color_mode_selector.rb +1 -1
- data/lib/plutonium/ui/component/kit.rb +6 -0
- data/lib/plutonium/ui/component_classes.rb +102 -0
- data/lib/plutonium/ui/display/base.rb +15 -0
- data/lib/plutonium/ui/display/components/attachment.rb +6 -5
- data/lib/plutonium/ui/display/components/boolean.rb +23 -0
- data/lib/plutonium/ui/display/components/color.rb +23 -0
- data/lib/plutonium/ui/display/resource.rb +1 -1
- data/lib/plutonium/ui/display/theme.rb +29 -15
- data/lib/plutonium/ui/empty_card.rb +3 -3
- data/lib/plutonium/ui/form/base.rb +20 -0
- data/lib/plutonium/ui/form/components/key_value_store.rb +11 -11
- data/lib/plutonium/ui/form/components/resource_select.rb +31 -0
- data/lib/plutonium/ui/form/components/secure_association.rb +1 -2
- data/lib/plutonium/ui/form/components/uppy.rb +5 -4
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +4 -4
- data/lib/plutonium/ui/form/interaction.rb +17 -1
- data/lib/plutonium/ui/form/query.rb +133 -80
- data/lib/plutonium/ui/form/theme.rb +50 -35
- data/lib/plutonium/ui/frame_navigator_panel.rb +2 -2
- data/lib/plutonium/ui/layout/base.rb +1 -1
- data/lib/plutonium/ui/layout/header.rb +4 -7
- data/lib/plutonium/ui/layout/rodauth_layout.rb +7 -7
- data/lib/plutonium/ui/layout/sidebar.rb +1 -1
- data/lib/plutonium/ui/nav_grid_menu.rb +7 -6
- data/lib/plutonium/ui/nav_user.rb +9 -8
- data/lib/plutonium/ui/page/interactive_action.rb +5 -5
- data/lib/plutonium/ui/page_header.rb +29 -10
- data/lib/plutonium/ui/panel.rb +4 -4
- data/lib/plutonium/ui/sidebar_menu.rb +8 -8
- data/lib/plutonium/ui/skeleton_table.rb +7 -8
- data/lib/plutonium/ui/tab_list.rb +5 -5
- data/lib/plutonium/ui/table/base.rb +3 -0
- data/lib/plutonium/ui/table/components/attachment.rb +4 -3
- data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +82 -0
- data/lib/plutonium/ui/table/components/pagy_info.rb +2 -2
- data/lib/plutonium/ui/table/components/pagy_pagination.rb +13 -8
- data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +101 -0
- data/lib/plutonium/ui/table/components/scopes_bar.rb +2 -2
- data/lib/plutonium/ui/table/components/selection_column.rb +100 -0
- data/lib/plutonium/ui/table/display_theme.rb +6 -6
- data/lib/plutonium/ui/table/resource.rb +93 -52
- data/lib/plutonium/ui/table/theme.rb +28 -15
- data/lib/plutonium/version.rb +1 -1
- data/package.json +2 -2
- data/plutonium.gemspec +5 -4
- data/src/css/components.css +471 -0
- data/src/css/intl_tel_input.css +2 -2
- data/src/css/plutonium.css +2 -0
- data/src/css/tokens.css +149 -0
- data/src/js/controllers/bulk_actions_controller.js +109 -0
- data/src/js/controllers/filter_panel_controller.js +35 -0
- data/src/js/controllers/register_controllers.js +5 -1
- data/src/js/controllers/resource_drop_down_controller.js +25 -1
- data/src/js/controllers/slim_select_controller.js +6 -2
- data/src/js/turbo/turbo_actions.js +1 -1
- metadata +52 -39
- data/.claude/skills/definition-query/SKILL.md +0 -334
- data/docs/concepts/architecture.md +0 -226
- data/docs/concepts/auto-detection.md +0 -254
- data/docs/concepts/index.md +0 -61
- data/docs/concepts/packages-portals.md +0 -304
- data/docs/concepts/resources.md +0 -224
- data/docs/cookbook/blog.md +0 -411
- data/docs/cookbook/index.md +0 -289
- data/docs/cookbook/saas.md +0 -481
- data/docs/public/CLAUDE.md +0 -578
- data/lib/generators/pu/pkg/portal/templates/app/controllers/resource_controller.rb.tt +0 -5
data/docs/guides/theming.md
CHANGED
|
@@ -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
|
-
|
|
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: "
|
|
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: "
|
|
147
|
-
input: "
|
|
148
|
-
hint: "
|
|
149
|
-
error: "
|
|
150
|
-
button: "
|
|
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-
|
|
168
|
-
string: "text-lg text-
|
|
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: "
|
|
186
|
-
base: "
|
|
187
|
-
header: "
|
|
188
|
-
header_cell: "
|
|
189
|
-
body_row: "
|
|
190
|
-
body_cell: "
|
|
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:
|
|
6
|
-
tagline: Build production-ready Rails applications in minutes, not
|
|
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:
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
61
121
|
|
|
62
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
133
|
+
search do |scope, query|
|
|
134
|
+
scope.where("title ILIKE ?", "%#{query}%")
|
|
135
|
+
end
|
|
72
136
|
|
|
73
|
-
|
|
137
|
+
scope :published
|
|
138
|
+
scope :drafts
|
|
74
139
|
|
|
75
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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?)
|
|
71
|
-
current_policy
|
|
72
|
-
permitted_attributes
|
|
73
|
-
current_authorized_scope
|
|
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
|