plutonium 0.50.0 → 0.51.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 +85 -102
- data/.claude/skills/plutonium-app/SKILL.md +572 -0
- data/.claude/skills/plutonium-auth/SKILL.md +163 -300
- data/.claude/skills/plutonium-behavior/SKILL.md +838 -0
- data/.claude/skills/plutonium-resource/SKILL.md +1176 -0
- data/.claude/skills/plutonium-tenancy/SKILL.md +655 -0
- data/.claude/skills/plutonium-testing/SKILL.md +6 -5
- data/.claude/skills/plutonium-ui/SKILL.md +900 -0
- data/CHANGELOG.md +27 -2
- data/Rakefile +2 -1
- data/app/assets/plutonium.css +1 -11
- data/app/assets/plutonium.js +1009 -1214
- data/app/assets/plutonium.js.map +3 -3
- data/app/assets/plutonium.min.js +52 -51
- data/app/assets/plutonium.min.js.map +3 -3
- data/docs/.vitepress/config.ts +37 -27
- data/docs/getting-started/index.md +22 -29
- data/docs/getting-started/installation.md +37 -80
- data/docs/getting-started/tutorial/index.md +4 -5
- data/docs/guides/adding-resources.md +66 -377
- data/docs/guides/authentication.md +94 -463
- data/docs/guides/authorization.md +124 -370
- data/docs/guides/creating-packages.md +94 -296
- data/docs/guides/custom-actions.md +121 -441
- data/docs/guides/index.md +22 -42
- data/docs/guides/multi-tenancy.md +116 -187
- data/docs/guides/nested-resources.md +103 -431
- data/docs/guides/search-filtering.md +123 -240
- data/docs/guides/testing.md +5 -4
- data/docs/guides/theming.md +157 -407
- data/docs/guides/troubleshooting.md +5 -3
- data/docs/guides/user-invites.md +106 -425
- data/docs/guides/user-profile.md +76 -243
- data/docs/index.md +1 -1
- data/docs/reference/app/generators.md +517 -0
- data/docs/reference/app/index.md +158 -0
- data/docs/reference/app/packages.md +146 -0
- data/docs/reference/app/portals.md +377 -0
- data/docs/reference/auth/accounts.md +230 -0
- data/docs/reference/auth/index.md +88 -0
- data/docs/reference/auth/profile.md +185 -0
- data/docs/reference/behavior/controllers.md +395 -0
- data/docs/reference/behavior/index.md +22 -0
- data/docs/reference/behavior/interactions.md +341 -0
- data/docs/reference/behavior/policies.md +417 -0
- data/docs/reference/index.md +56 -49
- data/docs/reference/resource/actions.md +423 -0
- data/docs/reference/resource/definition.md +508 -0
- data/docs/reference/resource/index.md +50 -0
- data/docs/reference/resource/model.md +348 -0
- data/docs/reference/resource/query.md +305 -0
- data/docs/reference/tenancy/entity-scoping.md +361 -0
- data/docs/reference/tenancy/index.md +36 -0
- data/docs/reference/tenancy/invites.md +393 -0
- data/docs/reference/tenancy/nested-resources.md +267 -0
- data/docs/reference/testing/index.md +287 -0
- data/docs/reference/ui/assets.md +400 -0
- data/docs/reference/ui/components.md +165 -0
- data/docs/reference/ui/displays.md +104 -0
- data/docs/reference/ui/forms.md +284 -0
- data/docs/reference/ui/index.md +30 -0
- data/docs/reference/ui/layouts.md +106 -0
- data/docs/reference/ui/pages.md +189 -0
- data/docs/reference/ui/tables.md +117 -0
- data/docs/superpowers/specs/2026-05-09-typeahead-endpoint-design.md +203 -0
- data/docs/superpowers/specs/2026-05-12-skill-compaction-design.md +99 -0
- data/docs/superpowers/specs/2026-05-13-docs-restructure-design.md +186 -0
- 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/core/update/update_generator.rb +0 -20
- data/lib/generators/pu/invites/install_generator.rb +1 -0
- data/lib/plutonium/definition/base.rb +1 -1
- data/lib/plutonium/definition/{views.rb → index_views.rb} +21 -20
- data/lib/plutonium/helpers/turbo_helper.rb +11 -0
- data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +14 -0
- data/lib/plutonium/resource/controller.rb +1 -0
- data/lib/plutonium/resource/controllers/crud_actions.rb +19 -1
- data/lib/plutonium/resource/controllers/typeahead.rb +180 -0
- data/lib/plutonium/resource/policy.rb +7 -0
- data/lib/plutonium/routing/mapper_extensions.rb +15 -0
- data/lib/plutonium/ui/component/methods.rb +4 -0
- data/lib/plutonium/ui/form/base.rb +6 -2
- data/lib/plutonium/ui/form/components/json.rb +58 -0
- data/lib/plutonium/ui/form/components/resource_select.rb +62 -8
- data/lib/plutonium/ui/form/components/secure_association.rb +98 -22
- data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +83 -0
- data/lib/plutonium/ui/form/resource.rb +0 -4
- data/lib/plutonium/ui/grid/resource.rb +1 -1
- data/lib/plutonium/ui/layout/base.rb +1 -0
- data/lib/plutonium/ui/page/base.rb +0 -7
- data/lib/plutonium/ui/page/index.rb +4 -4
- data/lib/plutonium/ui/table/resource.rb +1 -1
- data/lib/plutonium/version.rb +1 -1
- data/lib/plutonium.rb +8 -0
- data/lib/tasks/release.rake +15 -1
- data/package.json +10 -10
- data/src/css/slim_select.css +4 -0
- data/src/js/controllers/slim_select_controller.js +61 -0
- data/src/js/turbo/turbo_actions.js +33 -0
- data/yarn.lock +553 -543
- metadata +44 -33
- data/.claude/skills/plutonium-assets/SKILL.md +0 -512
- data/.claude/skills/plutonium-controller/SKILL.md +0 -396
- data/.claude/skills/plutonium-create-resource/SKILL.md +0 -303
- data/.claude/skills/plutonium-definition/SKILL.md +0 -1223
- data/.claude/skills/plutonium-entity-scoping/SKILL.md +0 -317
- data/.claude/skills/plutonium-forms/SKILL.md +0 -465
- data/.claude/skills/plutonium-installation/SKILL.md +0 -331
- data/.claude/skills/plutonium-interaction/SKILL.md +0 -413
- data/.claude/skills/plutonium-invites/SKILL.md +0 -408
- data/.claude/skills/plutonium-model/SKILL.md +0 -440
- data/.claude/skills/plutonium-nested-resources/SKILL.md +0 -360
- data/.claude/skills/plutonium-package/SKILL.md +0 -198
- data/.claude/skills/plutonium-policy/SKILL.md +0 -456
- data/.claude/skills/plutonium-portal/SKILL.md +0 -410
- data/.claude/skills/plutonium-views/SKILL.md +0 -651
- data/docs/reference/assets/index.md +0 -496
- data/docs/reference/controller/index.md +0 -412
- data/docs/reference/definition/actions.md +0 -462
- data/docs/reference/definition/fields.md +0 -383
- data/docs/reference/definition/index.md +0 -326
- data/docs/reference/definition/query.md +0 -351
- data/docs/reference/generators/index.md +0 -648
- data/docs/reference/interaction/index.md +0 -449
- data/docs/reference/model/features.md +0 -248
- data/docs/reference/model/index.md +0 -218
- data/docs/reference/policy/index.md +0 -456
- data/docs/reference/portal/index.md +0 -379
- data/docs/reference/views/forms.md +0 -411
- data/docs/reference/views/index.md +0 -544
data/docs/guides/theming.md
CHANGED
|
@@ -1,440 +1,184 @@
|
|
|
1
1
|
# Theming
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Customize colors, styles, dark mode, and branding.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Goal
|
|
6
6
|
|
|
7
|
-
Plutonium
|
|
7
|
+
Adapt Plutonium's defaults to match your brand: primary color, fonts, logo, dark mode behavior, optionally per-component theming.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **Component Classes** - Pre-built `.pu-*` classes for buttons, inputs, tables
|
|
11
|
-
- **Tailwind Configuration** - Extend colors and design tokens
|
|
12
|
-
- **Component Themes** - Override form, table, and display styling
|
|
9
|
+
## How theming layers stack
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
| Layer | What to edit | When to use |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| **Asset config** | `Plutonium.configure` | Logo / favicon / asset file paths |
|
|
14
|
+
| **CSS tokens** | `--pu-*` variables in your CSS | Colors that should auto-switch with dark mode |
|
|
15
|
+
| **Tailwind theme** | `tailwind.config.js` | Brand color palettes, custom fonts |
|
|
16
|
+
| **`.pu-*` classes** | Use in markup | Pre-styled buttons / inputs / cards |
|
|
17
|
+
| **Phlexi component themes** | Per-resource `Theme` class | Override Form/Display/Table per resource |
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
## 🚨 Critical
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
- **Always register Stimulus controllers** — `registerControllers(application)`. Without it, the entire interactive layer is dead.
|
|
22
|
+
- **Use `plutoniumTailwindConfig.merge`** when overriding Tailwind theme — plain object spread drops Plutonium's defaults.
|
|
23
|
+
- **Tokens are CSS variables, not Tailwind keys** — `bg-[var(--pu-surface)]`, NOT `bg-pu-surface`.
|
|
24
|
+
- **Dark mode is `selector`, not `class`** — toggle by adding/removing `dark` on `<html>`.
|
|
25
|
+
- **Prefer `.pu-*` classes and `var(--pu-*)` tokens** over hardcoded `gray-X/dark:gray-Y` pairs — they switch with dark mode automatically.
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
## Step 1: Run the assets generator
|
|
21
28
|
|
|
22
|
-
```
|
|
23
|
-
|
|
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 */
|
|
29
|
+
```bash
|
|
30
|
+
rails generate pu:core:assets
|
|
55
31
|
```
|
|
56
32
|
|
|
57
|
-
|
|
33
|
+
This installs npm packages, creates `tailwind.config.js`, imports Plutonium CSS, registers Stimulus controllers, and points `Plutonium.configure` at your asset files. Run once per app.
|
|
58
34
|
|
|
59
|
-
|
|
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
|
|
35
|
+
## Step 2: Asset configuration
|
|
67
36
|
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
#### Shadow System
|
|
37
|
+
```ruby
|
|
38
|
+
# config/initializers/plutonium.rb
|
|
39
|
+
Plutonium.configure do |config|
|
|
40
|
+
config.load_defaults 1.0
|
|
74
41
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
42
|
+
config.assets.stylesheet = "application"
|
|
43
|
+
config.assets.script = "application"
|
|
44
|
+
config.assets.logo = "my_logo.png"
|
|
45
|
+
config.assets.favicon = "my_favicon.ico"
|
|
46
|
+
end
|
|
79
47
|
```
|
|
80
48
|
|
|
81
|
-
|
|
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
|
-
```
|
|
49
|
+
Logo / favicon resolved from `app/assets/images/`.
|
|
90
50
|
|
|
91
|
-
|
|
51
|
+
## Step 3: Customize colors via Tailwind
|
|
92
52
|
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
53
|
+
```javascript
|
|
54
|
+
// tailwind.config.js
|
|
55
|
+
theme: plutoniumTailwindConfig.merge(plutoniumTailwindConfig.theme, {
|
|
56
|
+
extend: {
|
|
57
|
+
colors: {
|
|
58
|
+
primary: { 50: '#eff6ff', 500: '#3b82f6', 900: '#1e3a8a' },
|
|
59
|
+
secondary: { 50: '#f3f4f6', 500: '#6b7280', 900: '#111827' },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
})
|
|
99
63
|
```
|
|
100
64
|
|
|
101
|
-
|
|
65
|
+
### Default palette
|
|
102
66
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
67
|
+
| Color | Use |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `primary` | Brand primary (turquoise default) |
|
|
70
|
+
| `secondary` | Brand secondary (navy default) |
|
|
71
|
+
| `success` | Success states (green) |
|
|
72
|
+
| `info` | Informational (blue) |
|
|
73
|
+
| `warning` | Warning (amber) |
|
|
74
|
+
| `danger` | Error (red) |
|
|
75
|
+
| `accent` | Highlight (coral pink) |
|
|
110
76
|
|
|
111
|
-
|
|
77
|
+
## Step 4: Customize design tokens (dark-mode-aware)
|
|
112
78
|
|
|
113
79
|
```css
|
|
114
|
-
/* app/assets/stylesheets/application.css */
|
|
115
|
-
@import "tailwindcss";
|
|
80
|
+
/* app/assets/stylesheets/application.tailwind.css */
|
|
116
81
|
@import "gem:plutonium/src/css/plutonium.css";
|
|
82
|
+
@import "tailwindcss";
|
|
117
83
|
|
|
118
|
-
/* Light mode overrides */
|
|
119
84
|
:root {
|
|
120
85
|
--pu-surface: #fafafa;
|
|
121
|
-
--pu-border:
|
|
122
|
-
--pu-input-focus-ring: #6366f1;
|
|
86
|
+
--pu-border: #d1d5db;
|
|
123
87
|
}
|
|
124
88
|
|
|
125
|
-
/* Dark mode overrides */
|
|
126
89
|
.dark {
|
|
127
|
-
--pu-surface: #
|
|
128
|
-
--pu-border:
|
|
90
|
+
--pu-surface: #111827;
|
|
91
|
+
--pu-border: #374151;
|
|
129
92
|
}
|
|
130
93
|
```
|
|
131
94
|
|
|
132
|
-
|
|
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
|
|
95
|
+
Tokens auto-switch when the user toggles dark mode. See [Reference › UI › Assets › Design tokens](/reference/ui/assets#design-tokens) for the full token catalog.
|
|
182
96
|
|
|
183
|
-
|
|
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
|
-
```
|
|
97
|
+
## Using tokens in your code
|
|
196
98
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
|
99
|
+
```erb
|
|
100
|
+
<h1 class="text-[var(--pu-text)]">Title</h1>
|
|
101
|
+
<p class="text-[var(--pu-text-muted)]">Description</p>
|
|
217
102
|
|
|
218
|
-
|
|
219
|
-
|
|
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>
|
|
103
|
+
<div class="bg-[var(--pu-surface)] border border-[var(--pu-border)] rounded-[var(--pu-radius-lg)]">
|
|
104
|
+
Content
|
|
223
105
|
</div>
|
|
224
106
|
```
|
|
225
107
|
|
|
226
|
-
## Setup Custom Assets
|
|
227
|
-
|
|
228
|
-
Run the assets generator to set up your own TailwindCSS build:
|
|
229
|
-
|
|
230
|
-
```bash
|
|
231
|
-
rails generate pu:core:assets
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
This:
|
|
235
|
-
1. Installs required npm packages (`@radioactive-labs/plutonium`, TailwindCSS plugins)
|
|
236
|
-
2. Creates `tailwind.config.js` that extends Plutonium's config
|
|
237
|
-
3. Imports Plutonium CSS into your `application.tailwind.css`
|
|
238
|
-
4. Registers Plutonium's Stimulus controllers
|
|
239
|
-
5. Updates Plutonium config to use your assets
|
|
240
|
-
|
|
241
|
-
## Asset Configuration
|
|
242
|
-
|
|
243
|
-
Configure assets in the initializer:
|
|
244
|
-
|
|
245
108
|
```ruby
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
109
|
+
class MyComponent < Plutonium::UI::Component::Base
|
|
110
|
+
def view_template
|
|
111
|
+
div(
|
|
112
|
+
class: "bg-[var(--pu-surface)] border border-[var(--pu-border)] rounded-[var(--pu-radius-lg)]",
|
|
113
|
+
style: "box-shadow: var(--pu-shadow-md)"
|
|
114
|
+
) do
|
|
115
|
+
h2(class: "text-lg font-semibold text-[var(--pu-text)]") { "Title" }
|
|
116
|
+
p(class: "text-[var(--pu-text-muted)]") { "Description" }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
254
119
|
end
|
|
255
120
|
```
|
|
256
121
|
|
|
257
|
-
##
|
|
122
|
+
## Use `.pu-*` component classes
|
|
258
123
|
|
|
259
|
-
|
|
124
|
+
Pre-styled ready-to-use components:
|
|
260
125
|
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
const { execSync } = require('child_process');
|
|
264
|
-
const plutoniumGemPath = execSync("bundle show plutonium").toString().trim();
|
|
265
|
-
const plutoniumTailwindConfig = require(`${plutoniumGemPath}/tailwind.options.js`)
|
|
266
|
-
|
|
267
|
-
module.exports = {
|
|
268
|
-
darkMode: plutoniumTailwindConfig.darkMode,
|
|
269
|
-
plugins: [
|
|
270
|
-
// Add your plugins here
|
|
271
|
-
].concat(plutoniumTailwindConfig.plugins),
|
|
272
|
-
theme: plutoniumTailwindConfig.merge(
|
|
273
|
-
plutoniumTailwindConfig.theme,
|
|
274
|
-
{
|
|
275
|
-
// Your custom theme overrides
|
|
276
|
-
},
|
|
277
|
-
),
|
|
278
|
-
content: [
|
|
279
|
-
`${__dirname}/app/**/*.{erb,haml,html,slim,rb}`,
|
|
280
|
-
`${__dirname}/app/javascript/**/*.js`,
|
|
281
|
-
`${__dirname}/packages/**/app/**/*.{erb,haml,html,slim,rb}`,
|
|
282
|
-
].concat(plutoniumTailwindConfig.content),
|
|
283
|
-
}
|
|
126
|
+
```erb
|
|
127
|
+
<%= form.submit "Save", class: "pu-btn pu-btn-md pu-btn-primary" %>
|
|
284
128
|
```
|
|
285
129
|
|
|
286
|
-
|
|
130
|
+
| Family | Classes |
|
|
131
|
+
|---|---|
|
|
132
|
+
| Buttons | `.pu-btn`, `.pu-btn-md/-sm/-xs`, `.pu-btn-primary/-secondary/-danger/-success/-warning/-info/-accent`, `.pu-btn-ghost/-outline`, `.pu-btn-soft-*` |
|
|
133
|
+
| Inputs | `.pu-input/-invalid/-valid`, `.pu-label/-required`, `.pu-hint`, `.pu-error`, `.pu-checkbox` |
|
|
134
|
+
| Cards | `.pu-card`, `.pu-card-body`, `.pu-panel-header`, `.pu-panel-title`, `.pu-panel-description` |
|
|
135
|
+
| Tables | `.pu-table-wrapper`, `.pu-table`, `-header`, `-header-cell`, `-body-row`, `-body-row-selected`, `-body-cell`, `.pu-selection-cell` |
|
|
136
|
+
| Toolbars / empty states | `.pu-toolbar`, `-text`, `-actions`; `.pu-empty-state`, `-icon`, `-title`, `-description` |
|
|
287
137
|
|
|
288
|
-
|
|
138
|
+
Full catalog: [Reference › UI › Assets › Component classes](/reference/ui/assets#component-classes-pu-).
|
|
289
139
|
|
|
290
|
-
|
|
291
|
-
// tailwind.config.js
|
|
292
|
-
theme: plutoniumTailwindConfig.merge(
|
|
293
|
-
plutoniumTailwindConfig.theme,
|
|
294
|
-
{
|
|
295
|
-
extend: {
|
|
296
|
-
colors: {
|
|
297
|
-
primary: {
|
|
298
|
-
50: '#eff6ff',
|
|
299
|
-
100: '#dbeafe',
|
|
300
|
-
200: '#bfdbfe',
|
|
301
|
-
300: '#93c5fd',
|
|
302
|
-
400: '#60a5fa',
|
|
303
|
-
500: '#3b82f6', // Your brand color
|
|
304
|
-
600: '#2563eb',
|
|
305
|
-
700: '#1d4ed8',
|
|
306
|
-
800: '#1e40af',
|
|
307
|
-
900: '#1e3a8a',
|
|
308
|
-
950: '#172554',
|
|
309
|
-
},
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
),
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### Semantic Colors
|
|
317
|
-
|
|
318
|
-
Plutonium includes these semantic colors:
|
|
319
|
-
|
|
320
|
-
| Color | Usage |
|
|
321
|
-
|-------|-------|
|
|
322
|
-
| `primary` | Primary brand color |
|
|
323
|
-
| `secondary` | Secondary color |
|
|
324
|
-
| `success` | Success states (green) |
|
|
325
|
-
| `info` | Informational states (blue) |
|
|
326
|
-
| `warning` | Warning states (amber) |
|
|
327
|
-
| `danger` | Error/danger states (red) |
|
|
328
|
-
| `accent` | Accent highlights |
|
|
329
|
-
|
|
330
|
-
## CSS Imports
|
|
331
|
-
|
|
332
|
-
### Application Stylesheet
|
|
333
|
-
|
|
334
|
-
```css
|
|
335
|
-
/* app/assets/stylesheets/application.tailwind.css */
|
|
336
|
-
@import "gem:plutonium/src/css/plutonium.css";
|
|
337
|
-
|
|
338
|
-
@import "tailwindcss";
|
|
339
|
-
@config '../../../tailwind.config.js';
|
|
140
|
+
## Migrating from hardcoded classes
|
|
340
141
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
142
|
+
| Old | New |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `text-gray-900 dark:text-white` | `text-[var(--pu-text)]` |
|
|
145
|
+
| `text-gray-500 dark:text-gray-400` | `text-[var(--pu-text-muted)]` |
|
|
146
|
+
| `bg-gray-50 dark:bg-gray-700` | `bg-[var(--pu-surface)]` |
|
|
147
|
+
| `border-gray-300 dark:border-gray-600` | `border-[var(--pu-border)]` |
|
|
148
|
+
| Long input class chain | `pu-input` |
|
|
149
|
+
| Long button class chain | `pu-btn pu-btn-md pu-btn-primary` |
|
|
345
150
|
|
|
346
|
-
|
|
151
|
+
## Per-resource theming (Phlexi themes)
|
|
347
152
|
|
|
348
|
-
|
|
153
|
+
Override Form/Display/Table appearance per resource via a nested `Theme` class:
|
|
349
154
|
|
|
350
155
|
```ruby
|
|
351
156
|
class PostDefinition < ResourceDefinition
|
|
352
157
|
class Form < Form
|
|
353
158
|
class Theme < Plutonium::UI::Form::Theme
|
|
354
159
|
def self.theme
|
|
355
|
-
super.merge(
|
|
356
|
-
base:
|
|
357
|
-
fields_wrapper:
|
|
160
|
+
super.merge(
|
|
161
|
+
base: "bg-[var(--pu-card-bg)] shadow-md rounded-lg p-6",
|
|
162
|
+
fields_wrapper: "grid grid-cols-2 gap-6",
|
|
358
163
|
actions_wrapper: "flex justify-end mt-6 space-x-2",
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
error: "pu-error",
|
|
363
|
-
button: "pu-btn pu-btn-md pu-btn-primary",
|
|
364
|
-
})
|
|
164
|
+
input: "pu-input",
|
|
165
|
+
button: "pu-btn pu-btn-md pu-btn-primary"
|
|
166
|
+
)
|
|
365
167
|
end
|
|
366
168
|
end
|
|
367
169
|
end
|
|
368
170
|
end
|
|
369
171
|
```
|
|
370
172
|
|
|
371
|
-
|
|
173
|
+
::: warning Always `super.merge(...)`
|
|
174
|
+
Don't replace the theme wholesale — Plutonium's defaults handle invalid states, focus rings, and dark mode. `super.merge` keeps them.
|
|
175
|
+
:::
|
|
372
176
|
|
|
373
|
-
|
|
374
|
-
class PostDefinition < ResourceDefinition
|
|
375
|
-
class Display < Display
|
|
376
|
-
class Theme < Plutonium::UI::Display::Theme
|
|
377
|
-
def self.theme
|
|
378
|
-
super.merge({
|
|
379
|
-
fields_wrapper: "grid grid-cols-3 gap-8",
|
|
380
|
-
label: "text-sm font-bold text-[var(--pu-text-muted)] mb-1",
|
|
381
|
-
string: "text-lg text-[var(--pu-text)]",
|
|
382
|
-
link: "text-primary-600 hover:underline",
|
|
383
|
-
})
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
```
|
|
177
|
+
Full theme key catalog: [Reference › UI › Assets › Phlexi component themes](/reference/ui/assets#phlexi-component-themes).
|
|
389
178
|
|
|
390
|
-
|
|
179
|
+
## Typography
|
|
391
180
|
|
|
392
|
-
|
|
393
|
-
class PostDefinition < ResourceDefinition
|
|
394
|
-
class Table < Table
|
|
395
|
-
class Theme < Plutonium::UI::Table::Theme
|
|
396
|
-
def self.theme
|
|
397
|
-
super.merge({
|
|
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",
|
|
404
|
-
})
|
|
405
|
-
end
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
end
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
## Branding
|
|
412
|
-
|
|
413
|
-
### Application Name
|
|
414
|
-
|
|
415
|
-
```ruby
|
|
416
|
-
# config/initializers/plutonium.rb
|
|
417
|
-
Plutonium.application_name = "My Application"
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### Custom Logo
|
|
421
|
-
|
|
422
|
-
Override the logo in your layout:
|
|
423
|
-
|
|
424
|
-
```ruby
|
|
425
|
-
# packages/admin_portal/app/views/layouts/admin_portal/application.rb
|
|
426
|
-
module AdminPortal
|
|
427
|
-
class ApplicationLayout < Plutonium::UI::Layout::Application
|
|
428
|
-
def render_logo
|
|
429
|
-
img(src: helpers.asset_path("logo.svg"), alt: "My App", class: "h-8")
|
|
430
|
-
end
|
|
431
|
-
end
|
|
432
|
-
end
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Custom Fonts
|
|
436
|
-
|
|
437
|
-
Override in your layout:
|
|
181
|
+
Default font: Lato. Override via the layout:
|
|
438
182
|
|
|
439
183
|
```ruby
|
|
440
184
|
class MyLayout < Plutonium::UI::Layout::ResourceLayout
|
|
@@ -445,73 +189,79 @@ class MyLayout < Plutonium::UI::Layout::ResourceLayout
|
|
|
445
189
|
end
|
|
446
190
|
```
|
|
447
191
|
|
|
448
|
-
|
|
192
|
+
Then configure Tailwind to use it:
|
|
449
193
|
|
|
450
194
|
```javascript
|
|
451
|
-
theme: {
|
|
195
|
+
theme: plutoniumTailwindConfig.merge(plutoniumTailwindConfig.theme, {
|
|
452
196
|
fontFamily: {
|
|
453
|
-
|
|
454
|
-
|
|
197
|
+
body: ['Inter', 'sans-serif'],
|
|
198
|
+
sans: ['Inter', 'sans-serif']
|
|
455
199
|
}
|
|
456
|
-
}
|
|
200
|
+
})
|
|
457
201
|
```
|
|
458
202
|
|
|
459
|
-
## Dark
|
|
203
|
+
## Dark mode
|
|
204
|
+
|
|
205
|
+
`selector` strategy. The bundled `color-mode` Stimulus controller handles toggling; Plutonium ships a switcher in the topbar.
|
|
460
206
|
|
|
461
|
-
|
|
207
|
+
Manual toggle:
|
|
462
208
|
|
|
463
209
|
```javascript
|
|
464
|
-
document.documentElement.classList.toggle('dark')
|
|
210
|
+
document.documentElement.classList.toggle('dark')
|
|
465
211
|
```
|
|
466
212
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
Design tokens automatically adapt to dark mode - override the `.dark` selector in your CSS to customize dark mode colors.
|
|
213
|
+
If you've overridden tokens via `:root` and `.dark`, both modes Just Work.
|
|
470
214
|
|
|
471
|
-
##
|
|
215
|
+
## Per-portal chrome — eject the shell
|
|
472
216
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
```javascript
|
|
476
|
-
// app/javascript/controllers/index.js
|
|
477
|
-
import { application } from "./application"
|
|
478
|
-
|
|
479
|
-
import { registerControllers } from "@radioactive-labs/plutonium"
|
|
480
|
-
registerControllers(application)
|
|
217
|
+
For per-portal headers/sidebars:
|
|
481
218
|
|
|
482
|
-
|
|
219
|
+
```bash
|
|
220
|
+
rails generate pu:eject:shell --dest=admin_portal
|
|
483
221
|
```
|
|
484
222
|
|
|
485
|
-
|
|
223
|
+
Copies `_resource_header.html.erb` and `_resource_sidebar.html.erb` into the portal's `app/views/plutonium/`. Edit directly.
|
|
486
224
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
- `slim-select` - Enhanced select boxes
|
|
491
|
-
- `flatpickr` - Date/time pickers
|
|
492
|
-
- `easymde` - Markdown editor
|
|
225
|
+
```bash
|
|
226
|
+
rails generate pu:eject:layout
|
|
227
|
+
```
|
|
493
228
|
|
|
494
|
-
|
|
229
|
+
Copies `layouts/resource.html.erb` for layout-level edits.
|
|
495
230
|
|
|
496
|
-
|
|
497
|
-
// app/javascript/controllers/custom_controller.js
|
|
498
|
-
import { Controller } from "@hotwired/stimulus"
|
|
231
|
+
## Shell config
|
|
499
232
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
233
|
+
```ruby
|
|
234
|
+
Plutonium.configure do |config|
|
|
235
|
+
config.shell = :modern # default — topbar + icon rail
|
|
236
|
+
# config.shell = :classic # legacy header + sidebar (only when upgrading)
|
|
237
|
+
end
|
|
505
238
|
```
|
|
506
239
|
|
|
507
|
-
|
|
240
|
+
## Stimulus
|
|
508
241
|
|
|
509
242
|
```javascript
|
|
243
|
+
// app/javascript/controllers/index.js
|
|
244
|
+
import { application } from "./application"
|
|
245
|
+
import { registerControllers } from "@radioactive-labs/plutonium"
|
|
246
|
+
|
|
247
|
+
registerControllers(application) // ← mandatory
|
|
248
|
+
|
|
249
|
+
// Your custom controllers...
|
|
510
250
|
import CustomController from "./custom_controller"
|
|
511
251
|
application.register("custom", CustomController)
|
|
512
252
|
```
|
|
513
253
|
|
|
254
|
+
Bundled controllers: `color-mode`, `form` (pre-submit), `nested-resource-form-fields`, `slim-select`, `flatpickr`, `easymde`.
|
|
255
|
+
|
|
256
|
+
## Common issues
|
|
257
|
+
|
|
258
|
+
- **Stimulus controllers silently fail** — if `registerControllers(application)` isn't called, the entire UI's interactive layer is dead (color-mode toggle, slim-select, flatpickr, easymde, pre-submit). No error — just no behavior.
|
|
259
|
+
- **`plutoniumTailwindConfig.merge` is mandatory** — plain spread drops defaults silently.
|
|
260
|
+
- **Tokens not switching in dark mode** — you used `bg-pu-surface` instead of `bg-[var(--pu-surface)]`. Tokens are CSS variables, not Tailwind keys.
|
|
261
|
+
- **`.pu-btn` styles not applying** — check that Plutonium CSS is imported BEFORE Tailwind: `@import "gem:plutonium/src/css/plutonium.css";` then `@import "tailwindcss";`.
|
|
262
|
+
|
|
514
263
|
## Related
|
|
515
264
|
|
|
516
|
-
- [
|
|
517
|
-
- [
|
|
265
|
+
- [Reference › UI › Assets](/reference/ui/assets) — full Tailwind / Stimulus / design tokens / component classes surface
|
|
266
|
+
- [Reference › UI › Layouts](/reference/ui/layouts) — shell, eject, ResourceLayout
|
|
267
|
+
- [Reference › UI › Forms › Theming](/reference/ui/forms#theming) — Form theme keys
|
|
@@ -77,6 +77,8 @@ If you encounter an issue not covered here, please [open an issue](https://githu
|
|
|
77
77
|
|
|
78
78
|
## Related
|
|
79
79
|
|
|
80
|
-
- [Nested
|
|
81
|
-
- [Adding
|
|
82
|
-
- [
|
|
80
|
+
- [Nested resources](./nested-resources)
|
|
81
|
+
- [Adding resources](./adding-resources)
|
|
82
|
+
- [Reference › Behavior › Controllers](/reference/behavior/controllers) — `controller_for`, `resource_url_for`, `current_parent`
|
|
83
|
+
- [Reference › Tenancy › Nested resources](/reference/tenancy/nested-resources) — nested URL generation
|
|
84
|
+
- [Rails Inflections](https://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html)
|