plutonium 0.45.2 → 0.46.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 +146 -0
- data/.claude/skills/plutonium-assets/SKILL.md +248 -157
- data/.claude/skills/{plutonium-rodauth → plutonium-auth}/SKILL.md +195 -229
- data/.claude/skills/plutonium-controller/SKILL.md +9 -2
- data/.claude/skills/plutonium-create-resource/SKILL.md +22 -1
- data/.claude/skills/plutonium-definition/SKILL.md +521 -7
- data/.claude/skills/plutonium-entity-scoping/SKILL.md +317 -0
- data/.claude/skills/plutonium-forms/SKILL.md +8 -1
- data/.claude/skills/plutonium-installation/SKILL.md +25 -2
- data/.claude/skills/plutonium-interaction/SKILL.md +9 -2
- data/.claude/skills/plutonium-invites/SKILL.md +11 -7
- data/.claude/skills/plutonium-model/SKILL.md +50 -50
- data/.claude/skills/plutonium-nested-resources/SKILL.md +8 -1
- data/.claude/skills/plutonium-package/SKILL.md +8 -1
- data/.claude/skills/plutonium-policy/SKILL.md +69 -78
- data/.claude/skills/plutonium-portal/SKILL.md +26 -70
- data/.claude/skills/plutonium-views/SKILL.md +9 -2
- data/CHANGELOG.md +33 -0
- data/app/assets/plutonium.css +1 -1
- data/app/views/rodauth/_login_form.html.erb +0 -3
- data/app/views/rodauth/confirm_password.html.erb +0 -4
- data/app/views/rodauth/create_account.html.erb +0 -3
- data/app/views/rodauth/logout.html.erb +0 -3
- data/config/initializers/pagy.rb +1 -1
- data/docs/superpowers/plans/2026-04-08-plutonium-skills-overhaul.md +481 -0
- data/docs/superpowers/specs/2026-04-08-plutonium-skills-overhaul-design.md +236 -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 +8 -0
- data/lib/generators/pu/gem/active_shrine/active_shrine_generator.rb +56 -0
- data/lib/generators/pu/invites/install_generator.rb +8 -1
- data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +43 -0
- data/lib/generators/pu/profile/concerns/profile_arguments.rb +10 -4
- data/lib/generators/pu/profile/conn_generator.rb +9 -12
- data/lib/generators/pu/profile/install_generator.rb +5 -2
- data/lib/generators/pu/rodauth/templates/app/rodauth/account_rodauth_plugin.rb.tt +3 -0
- data/lib/generators/pu/saas/portal_generator.rb +4 -9
- data/lib/generators/pu/saas/welcome/templates/app/views/welcome/onboarding.html.erb.tt +2 -2
- data/lib/plutonium/engine.rb +18 -5
- data/lib/plutonium/ui/layout/rodauth_layout.rb +6 -1
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- metadata +7 -8
- data/.claude/skills/plutonium/skill.md +0 -130
- data/.claude/skills/plutonium-definition-actions/SKILL.md +0 -424
- data/.claude/skills/plutonium-definition-query/SKILL.md +0 -364
- data/.claude/skills/plutonium-profile/SKILL.md +0 -276
- data/.claude/skills/plutonium-theming/SKILL.md +0 -424
|
@@ -1,33 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plutonium-assets
|
|
3
|
-
description: Use
|
|
3
|
+
description: Use BEFORE configuring Tailwind, registering a Stimulus controller, or editing design tokens / theming in a Plutonium app. Also when running pu:core:assets or editing tailwind.config.js. Covers the full frontend toolchain.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Plutonium Assets &
|
|
6
|
+
# Plutonium Assets, Stimulus & Theming
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## 🚨 Critical (read first)
|
|
9
|
+
- **Use the generator.** `pu:core:assets` wires Tailwind, imports Plutonium CSS, registers Stimulus controllers, and updates the Plutonium config. Never hand-roll this.
|
|
10
|
+
- **Always register Stimulus controllers.** `registerControllers(application)` is required — Plutonium's controllers (color-mode, form, slim-select, flatpickr, easymde, etc.) are dead without it. Custom controllers must also be explicitly registered.
|
|
11
|
+
- **Use `plutoniumTailwindConfig.merge`** when overriding theme keys. Plain object merge drops Plutonium's defaults.
|
|
12
|
+
- **Prefer `.pu-*` classes and CSS tokens** over hardcoded `gray-*/dark:gray-*` pairs — they switch with dark mode automatically.
|
|
13
|
+
- **Related skills:** `plutonium-views` (layout customization), `plutonium-forms` (form theming), `plutonium-installation` (initial setup).
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
Plutonium uses TailwindCSS 4 for styling with a customizable theme system for components, and ships its own Stimulus controllers and CSS design token system.
|
|
11
16
|
|
|
12
|
-
##
|
|
17
|
+
## Contents
|
|
18
|
+
- [Asset configuration](#asset-configuration)
|
|
19
|
+
- [TailwindCSS configuration](#tailwindcss-configuration)
|
|
20
|
+
- [CSS imports](#css-imports)
|
|
21
|
+
- [Phlexi component themes](#phlexi-component-themes)
|
|
22
|
+
- [Stimulus controllers](#stimulus-controllers)
|
|
23
|
+
- [Design tokens and theming](#design-tokens-and-theming)
|
|
24
|
+
- [Component classes (`.pu-*`)](#component-classes)
|
|
25
|
+
- [Gotchas](#gotchas)
|
|
13
26
|
|
|
14
|
-
|
|
27
|
+
## Asset configuration
|
|
15
28
|
|
|
16
29
|
```ruby
|
|
17
30
|
# config/initializers/plutonium.rb
|
|
18
31
|
Plutonium.configure do |config|
|
|
19
32
|
config.load_defaults 1.0
|
|
20
33
|
|
|
21
|
-
# Custom assets
|
|
22
34
|
config.assets.stylesheet = "application" # Your CSS file
|
|
23
35
|
config.assets.script = "application" # Your JS file
|
|
24
|
-
config.assets.logo = "my_logo.png"
|
|
25
|
-
config.assets.favicon = "my_favicon.ico"
|
|
36
|
+
config.assets.logo = "my_logo.png"
|
|
37
|
+
config.assets.favicon = "my_favicon.ico"
|
|
26
38
|
end
|
|
27
39
|
```
|
|
28
40
|
|
|
29
|
-
## Setup Custom Assets
|
|
30
|
-
|
|
31
41
|
Run the assets generator to set up your own TailwindCSS build:
|
|
32
42
|
|
|
33
43
|
```bash
|
|
@@ -41,7 +51,7 @@ This:
|
|
|
41
51
|
4. Registers Plutonium's Stimulus controllers
|
|
42
52
|
5. Updates Plutonium config to use your assets
|
|
43
53
|
|
|
44
|
-
## TailwindCSS
|
|
54
|
+
## TailwindCSS configuration
|
|
45
55
|
|
|
46
56
|
### Generated Config
|
|
47
57
|
|
|
@@ -53,9 +63,7 @@ const plutoniumTailwindConfig = require(`${plutoniumGemPath}/tailwind.options.js
|
|
|
53
63
|
|
|
54
64
|
module.exports = {
|
|
55
65
|
darkMode: plutoniumTailwindConfig.darkMode,
|
|
56
|
-
plugins: [
|
|
57
|
-
// Add your plugins here
|
|
58
|
-
].concat(plutoniumTailwindConfig.plugins),
|
|
66
|
+
plugins: [].concat(plutoniumTailwindConfig.plugins),
|
|
59
67
|
theme: plutoniumTailwindConfig.merge(
|
|
60
68
|
plutoniumTailwindConfig.theme,
|
|
61
69
|
{
|
|
@@ -72,30 +80,15 @@ module.exports = {
|
|
|
72
80
|
|
|
73
81
|
### Customizing Colors
|
|
74
82
|
|
|
75
|
-
Override Plutonium's color palette:
|
|
76
|
-
|
|
77
83
|
```javascript
|
|
78
|
-
// tailwind.config.js
|
|
79
84
|
theme: plutoniumTailwindConfig.merge(
|
|
80
85
|
plutoniumTailwindConfig.theme,
|
|
81
86
|
{
|
|
82
87
|
extend: {
|
|
83
88
|
colors: {
|
|
84
89
|
primary: {
|
|
85
|
-
50: '#eff6ff',
|
|
86
|
-
|
|
87
|
-
200: '#bfdbfe',
|
|
88
|
-
300: '#93c5fd',
|
|
89
|
-
400: '#60a5fa',
|
|
90
|
-
500: '#3b82f6', // Your brand color
|
|
91
|
-
600: '#2563eb',
|
|
92
|
-
700: '#1d4ed8',
|
|
93
|
-
800: '#1e40af',
|
|
94
|
-
900: '#1e3a8a',
|
|
95
|
-
950: '#172554',
|
|
96
|
-
},
|
|
97
|
-
secondary: {
|
|
98
|
-
// Your secondary palette
|
|
90
|
+
50: '#eff6ff', 500: '#3b82f6', 900: '#1e3a8a',
|
|
91
|
+
// ...
|
|
99
92
|
},
|
|
100
93
|
},
|
|
101
94
|
},
|
|
@@ -105,8 +98,6 @@ theme: plutoniumTailwindConfig.merge(
|
|
|
105
98
|
|
|
106
99
|
### Default Color Palette
|
|
107
100
|
|
|
108
|
-
Plutonium includes these semantic colors:
|
|
109
|
-
|
|
110
101
|
| Color | Usage |
|
|
111
102
|
|-------|-------|
|
|
112
103
|
| `primary` | Primary brand color (turquoise by default) |
|
|
@@ -119,24 +110,9 @@ Plutonium includes these semantic colors:
|
|
|
119
110
|
|
|
120
111
|
### Dark Mode
|
|
121
112
|
|
|
122
|
-
Plutonium uses `selector` strategy for dark mode
|
|
123
|
-
|
|
124
|
-
```javascript
|
|
125
|
-
darkMode: "selector"
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Toggle dark mode by adding/removing the `dark` class on `<html>`:
|
|
129
|
-
|
|
130
|
-
```javascript
|
|
131
|
-
// Toggle dark mode
|
|
132
|
-
document.documentElement.classList.toggle('dark');
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
Plutonium includes a color mode selector component that handles this automatically.
|
|
136
|
-
|
|
137
|
-
## CSS Imports
|
|
113
|
+
Plutonium uses `selector` strategy for dark mode. Toggle by adding/removing `dark` class on `<html>`. Plutonium includes a color mode selector component that handles this automatically.
|
|
138
114
|
|
|
139
|
-
|
|
115
|
+
## CSS imports
|
|
140
116
|
|
|
141
117
|
```css
|
|
142
118
|
/* app/assets/stylesheets/application.tailwind.css */
|
|
@@ -148,20 +124,12 @@ Plutonium includes a color mode selector component that handles this automatical
|
|
|
148
124
|
/* Your custom styles */
|
|
149
125
|
```
|
|
150
126
|
|
|
151
|
-
|
|
127
|
+
Plutonium CSS includes: core utility classes, EasyMDE (markdown editor) styles, Slim Select styles, International telephone input styles, Flatpickr (date picker) styles.
|
|
152
128
|
|
|
153
|
-
|
|
154
|
-
- EasyMDE (markdown editor) styles
|
|
155
|
-
- Slim Select styles
|
|
156
|
-
- International telephone input styles
|
|
157
|
-
- Flatpickr (date picker) styles
|
|
158
|
-
|
|
159
|
-
## Component Themes (Phlexi)
|
|
129
|
+
## Phlexi component themes
|
|
160
130
|
|
|
161
131
|
Plutonium components use a theme system based on Phlexi for customizing Form, Display, and Table components. Each component type has a theme class with named style tokens.
|
|
162
132
|
|
|
163
|
-
> **Note:** This is different from the CSS design token system (`.pu-*` classes). For pre-built component classes, see `plutonium-theming`.
|
|
164
|
-
|
|
165
133
|
### Form Theme
|
|
166
134
|
|
|
167
135
|
```ruby
|
|
@@ -170,28 +138,15 @@ class PostDefinition < ResourceDefinition
|
|
|
170
138
|
class Theme < Plutonium::UI::Form::Theme
|
|
171
139
|
def self.theme
|
|
172
140
|
super.merge({
|
|
173
|
-
# Container
|
|
174
141
|
base: "bg-white dark:bg-gray-800 shadow-md rounded-lg p-6",
|
|
175
142
|
fields_wrapper: "grid grid-cols-2 gap-6",
|
|
176
143
|
actions_wrapper: "flex justify-end mt-6 space-x-2",
|
|
177
|
-
|
|
178
|
-
# Labels
|
|
179
144
|
label: "block mb-2 text-base font-bold",
|
|
180
145
|
invalid_label: "text-red-700 dark:text-red-500",
|
|
181
|
-
valid_label: "text-green-700 dark:text-green-500",
|
|
182
|
-
neutral_label: "text-gray-500 dark:text-gray-400",
|
|
183
|
-
|
|
184
|
-
# Inputs
|
|
185
146
|
input: "w-full p-2 border rounded-md shadow-sm",
|
|
186
147
|
invalid_input: "bg-red-50 border-red-500 text-red-900",
|
|
187
|
-
valid_input: "bg-green-50 border-green-500 text-green-900",
|
|
188
|
-
neutral_input: "border-gray-300 dark:border-gray-600",
|
|
189
|
-
|
|
190
|
-
# Hints & Errors
|
|
191
148
|
hint: "mt-2 text-sm text-gray-500",
|
|
192
149
|
error: "mt-2 text-sm text-red-600",
|
|
193
|
-
|
|
194
|
-
# Buttons
|
|
195
150
|
button: "px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700",
|
|
196
151
|
})
|
|
197
152
|
end
|
|
@@ -243,61 +198,13 @@ end
|
|
|
243
198
|
|
|
244
199
|
### Theme Keys Reference
|
|
245
200
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
| `wrapper` | Individual field wrapper |
|
|
254
|
-
| `inner_wrapper` | Inner field wrapper |
|
|
255
|
-
| `label` | Label base styles |
|
|
256
|
-
| `invalid_label` | Label when field invalid |
|
|
257
|
-
| `valid_label` | Label when field valid |
|
|
258
|
-
| `neutral_label` | Label default state |
|
|
259
|
-
| `input` | Input base styles |
|
|
260
|
-
| `invalid_input` | Input when invalid |
|
|
261
|
-
| `valid_input` | Input when valid |
|
|
262
|
-
| `neutral_input` | Input default state |
|
|
263
|
-
| `hint` | Hint text |
|
|
264
|
-
| `error` | Error message |
|
|
265
|
-
| `button` | Submit button |
|
|
266
|
-
| `checkbox` | Checkbox input |
|
|
267
|
-
| `select` | Select dropdown |
|
|
268
|
-
|
|
269
|
-
#### Display Theme Keys
|
|
270
|
-
|
|
271
|
-
| Key | Description |
|
|
272
|
-
|-----|-------------|
|
|
273
|
-
| `fields_wrapper` | Grid wrapper |
|
|
274
|
-
| `label` | Field label |
|
|
275
|
-
| `description` | Field description |
|
|
276
|
-
| `string` | String values |
|
|
277
|
-
| `text` | Text values |
|
|
278
|
-
| `link` | URL links |
|
|
279
|
-
| `email` | Email links |
|
|
280
|
-
| `phone` | Phone links |
|
|
281
|
-
| `markdown` | Markdown content |
|
|
282
|
-
| `json` | JSON display |
|
|
283
|
-
|
|
284
|
-
#### Table Theme Keys
|
|
285
|
-
|
|
286
|
-
| Key | Description |
|
|
287
|
-
|-----|-------------|
|
|
288
|
-
| `wrapper` | Table container |
|
|
289
|
-
| `base` | Table element |
|
|
290
|
-
| `header` | Header row |
|
|
291
|
-
| `header_cell` | Header cell |
|
|
292
|
-
| `body_row` | Body row |
|
|
293
|
-
| `body_cell` | Body cell |
|
|
294
|
-
| `sort_icon` | Sort indicator |
|
|
295
|
-
|
|
296
|
-
## Using Tokens in Components
|
|
297
|
-
|
|
298
|
-
### The `tokens` Helper
|
|
299
|
-
|
|
300
|
-
Conditionally apply classes:
|
|
201
|
+
**Form theme keys:** `base`, `fields_wrapper`, `actions_wrapper`, `wrapper`, `inner_wrapper`, `label`, `invalid_label`, `valid_label`, `neutral_label`, `input`, `invalid_input`, `valid_input`, `neutral_input`, `hint`, `error`, `button`, `checkbox`, `select`.
|
|
202
|
+
|
|
203
|
+
**Display theme keys:** `fields_wrapper`, `label`, `description`, `string`, `text`, `link`, `email`, `phone`, `markdown`, `json`.
|
|
204
|
+
|
|
205
|
+
**Table theme keys:** `wrapper`, `base`, `header`, `header_cell`, `body_row`, `body_cell`, `sort_icon`.
|
|
206
|
+
|
|
207
|
+
### Using `tokens` and `classes` helpers
|
|
301
208
|
|
|
302
209
|
```ruby
|
|
303
210
|
class MyComponent < Plutonium::UI::Component::Base
|
|
@@ -310,9 +217,7 @@ class MyComponent < Plutonium::UI::Component::Base
|
|
|
310
217
|
"base-class",
|
|
311
218
|
active?: "bg-primary-500 text-white",
|
|
312
219
|
inactive?: "bg-gray-200 text-gray-700"
|
|
313
|
-
)) {
|
|
314
|
-
"Content"
|
|
315
|
-
}
|
|
220
|
+
)) { "Content" }
|
|
316
221
|
end
|
|
317
222
|
|
|
318
223
|
private
|
|
@@ -322,27 +227,19 @@ class MyComponent < Plutonium::UI::Component::Base
|
|
|
322
227
|
end
|
|
323
228
|
```
|
|
324
229
|
|
|
325
|
-
### The `classes` Helper
|
|
326
|
-
|
|
327
|
-
Returns a hash suitable for splatting:
|
|
328
|
-
|
|
329
230
|
```ruby
|
|
330
231
|
div(**classes("p-4", "rounded", active?: "ring-2")) { }
|
|
331
232
|
# => <div class="p-4 rounded ring-2">
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### Conditional Tokens with Hash
|
|
335
233
|
|
|
336
|
-
```ruby
|
|
337
234
|
tokens(
|
|
338
235
|
"base",
|
|
339
236
|
condition?: { then: "if-true", else: "if-false" }
|
|
340
237
|
)
|
|
341
238
|
```
|
|
342
239
|
|
|
343
|
-
## Stimulus
|
|
240
|
+
## Stimulus controllers
|
|
344
241
|
|
|
345
|
-
Plutonium
|
|
242
|
+
Register Plutonium's Stimulus controllers in your application:
|
|
346
243
|
|
|
347
244
|
```javascript
|
|
348
245
|
// app/javascript/controllers/index.js
|
|
@@ -354,7 +251,7 @@ registerControllers(application)
|
|
|
354
251
|
// Your custom controllers...
|
|
355
252
|
```
|
|
356
253
|
|
|
357
|
-
### Available
|
|
254
|
+
### Available controllers
|
|
358
255
|
|
|
359
256
|
- `color-mode` - Dark/light mode toggle
|
|
360
257
|
- `form` - Form handling (pre-submit, etc.)
|
|
@@ -364,9 +261,7 @@ registerControllers(application)
|
|
|
364
261
|
- `easymde` - Markdown editor
|
|
365
262
|
- Various UI controllers
|
|
366
263
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
Add your own controllers alongside Plutonium's:
|
|
264
|
+
### Custom Stimulus controllers
|
|
370
265
|
|
|
371
266
|
```javascript
|
|
372
267
|
// app/javascript/controllers/custom_controller.js
|
|
@@ -379,31 +274,26 @@ export default class extends Controller {
|
|
|
379
274
|
}
|
|
380
275
|
```
|
|
381
276
|
|
|
382
|
-
Register
|
|
277
|
+
Register:
|
|
383
278
|
|
|
384
279
|
```javascript
|
|
385
280
|
import CustomController from "./custom_controller"
|
|
386
281
|
application.register("custom", CustomController)
|
|
387
282
|
```
|
|
388
283
|
|
|
389
|
-
|
|
284
|
+
### Typography
|
|
390
285
|
|
|
391
|
-
Plutonium uses Lato
|
|
392
|
-
|
|
393
|
-
Override in your layout:
|
|
286
|
+
Plutonium uses Lato by default. Override:
|
|
394
287
|
|
|
395
288
|
```ruby
|
|
396
289
|
class MyLayout < Plutonium::UI::Layout::ResourceLayout
|
|
397
290
|
def render_fonts
|
|
398
|
-
# Your custom fonts
|
|
399
291
|
link(rel: "preconnect", href: "https://fonts.googleapis.com")
|
|
400
292
|
link(href: "https://fonts.googleapis.com/css2?family=Inter&display=swap", rel: "stylesheet")
|
|
401
293
|
end
|
|
402
294
|
end
|
|
403
295
|
```
|
|
404
296
|
|
|
405
|
-
Update Tailwind config:
|
|
406
|
-
|
|
407
297
|
```javascript
|
|
408
298
|
theme: {
|
|
409
299
|
fontFamily: {
|
|
@@ -413,9 +303,210 @@ theme: {
|
|
|
413
303
|
}
|
|
414
304
|
```
|
|
415
305
|
|
|
416
|
-
##
|
|
306
|
+
## Design tokens and theming
|
|
307
|
+
|
|
308
|
+
Plutonium uses a comprehensive CSS design token system for consistent, themeable UI components — CSS custom properties and reusable component classes that automatically support light and dark modes. Tokens are defined in `src/css/tokens.css`.
|
|
309
|
+
|
|
310
|
+
### Surface & background colors
|
|
311
|
+
|
|
312
|
+
```css
|
|
313
|
+
/* Light */
|
|
314
|
+
--pu-body: #f8fafc;
|
|
315
|
+
--pu-surface: #ffffff;
|
|
316
|
+
--pu-surface-alt: #f1f5f9;
|
|
317
|
+
--pu-surface-raised: #ffffff;
|
|
318
|
+
--pu-surface-overlay: rgba(255, 255, 255, 0.95);
|
|
319
|
+
|
|
320
|
+
/* Dark (.dark class) */
|
|
321
|
+
--pu-body: #0f172a;
|
|
322
|
+
--pu-surface: #1e293b;
|
|
323
|
+
--pu-surface-alt: #0f172a;
|
|
324
|
+
--pu-surface-raised: #334155;
|
|
325
|
+
--pu-surface-overlay: rgba(30, 41, 59, 0.95);
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Text colors
|
|
329
|
+
|
|
330
|
+
```css
|
|
331
|
+
/* Light */
|
|
332
|
+
--pu-text: #0f172a;
|
|
333
|
+
--pu-text-muted: #64748b;
|
|
334
|
+
--pu-text-subtle: #94a3b8;
|
|
335
|
+
|
|
336
|
+
/* Dark */
|
|
337
|
+
--pu-text: #f8fafc;
|
|
338
|
+
--pu-text-muted: #94a3b8;
|
|
339
|
+
--pu-text-subtle: #64748b;
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Border colors
|
|
343
|
+
|
|
344
|
+
```css
|
|
345
|
+
--pu-border: #e2e8f0;
|
|
346
|
+
--pu-border-muted: #f1f5f9;
|
|
347
|
+
--pu-border-strong: #cbd5e1;
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Form tokens
|
|
351
|
+
|
|
352
|
+
```css
|
|
353
|
+
--pu-input-bg: #ffffff;
|
|
354
|
+
--pu-input-border: #e2e8f0;
|
|
355
|
+
--pu-input-focus-ring: theme(colors.primary.500);
|
|
356
|
+
--pu-input-placeholder: #94a3b8;
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Card tokens
|
|
360
|
+
|
|
361
|
+
```css
|
|
362
|
+
--pu-card-bg: #ffffff;
|
|
363
|
+
--pu-card-border: #e2e8f0;
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Shadows
|
|
367
|
+
|
|
368
|
+
```css
|
|
369
|
+
--pu-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.03), 0 1px 3px 0 rgb(0 0 0 / 0.05);
|
|
370
|
+
--pu-shadow-md: 0 2px 4px -1px rgb(0 0 0 / 0.04), 0 4px 6px -1px rgb(0 0 0 / 0.06);
|
|
371
|
+
--pu-shadow-lg: 0 4px 6px -2px rgb(0 0 0 / 0.03), 0 10px 15px -3px rgb(0 0 0 / 0.08);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Radius, spacing, transitions
|
|
375
|
+
|
|
376
|
+
```css
|
|
377
|
+
--pu-radius-sm: 0.375rem;
|
|
378
|
+
--pu-radius-md: 0.5rem;
|
|
379
|
+
--pu-radius-lg: 0.75rem;
|
|
380
|
+
--pu-radius-xl: 1rem;
|
|
381
|
+
--pu-radius-full: 9999px;
|
|
382
|
+
|
|
383
|
+
--pu-space-xs: 0.25rem;
|
|
384
|
+
--pu-space-sm: 0.5rem;
|
|
385
|
+
--pu-space-md: 1rem;
|
|
386
|
+
--pu-space-lg: 1.5rem;
|
|
387
|
+
--pu-space-xl: 2rem;
|
|
388
|
+
|
|
389
|
+
--pu-transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
390
|
+
--pu-transition-normal: 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
391
|
+
--pu-transition-slow: 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Customizing tokens
|
|
395
|
+
|
|
396
|
+
```css
|
|
397
|
+
/* app/assets/stylesheets/application.tailwind.css */
|
|
398
|
+
@import "gem:plutonium/src/css/plutonium.css";
|
|
399
|
+
@import "tailwindcss";
|
|
400
|
+
|
|
401
|
+
:root {
|
|
402
|
+
--pu-surface: #fafafa;
|
|
403
|
+
--pu-border: #d1d5db;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.dark {
|
|
407
|
+
--pu-surface: #111827;
|
|
408
|
+
--pu-border: #374151;
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Component classes
|
|
413
|
+
|
|
414
|
+
Component classes are defined in `src/css/components.css` for ready-to-use styled components.
|
|
415
|
+
|
|
416
|
+
### Buttons
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
.pu-btn /* Base */
|
|
420
|
+
.pu-btn-md / .pu-btn-sm / .pu-btn-xs
|
|
421
|
+
.pu-btn-primary / -secondary / -danger / -success / -warning / -info / -accent
|
|
422
|
+
.pu-btn-ghost / -outline
|
|
423
|
+
.pu-btn-soft-primary / -soft-danger / ...
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
```erb
|
|
427
|
+
<%= form.submit "Save", class: "pu-btn pu-btn-md pu-btn-primary" %>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Inputs & labels
|
|
431
|
+
|
|
432
|
+
```
|
|
433
|
+
.pu-input / .pu-input-invalid / .pu-input-valid
|
|
434
|
+
.pu-label / .pu-label-required
|
|
435
|
+
.pu-hint / .pu-error
|
|
436
|
+
.pu-checkbox
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Cards, panels, tables, toolbar, empty state
|
|
440
|
+
|
|
441
|
+
```
|
|
442
|
+
.pu-card / .pu-card-body
|
|
443
|
+
.pu-panel-header / .pu-panel-title / .pu-panel-description
|
|
444
|
+
.pu-table-wrapper / .pu-table / .pu-table-header / .pu-table-header-cell /
|
|
445
|
+
.pu-table-body-row / .pu-table-body-row-selected / .pu-table-body-cell / .pu-selection-cell
|
|
446
|
+
.pu-toolbar / .pu-toolbar-text / .pu-toolbar-actions
|
|
447
|
+
.pu-empty-state / .pu-empty-state-icon / .pu-empty-state-title / .pu-empty-state-description
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Ruby component class constants
|
|
451
|
+
|
|
452
|
+
The `Plutonium::UI::ComponentClasses` module (in `lib/plutonium/ui/component_classes.rb`) provides Ruby constants for consistent class usage:
|
|
453
|
+
|
|
454
|
+
```ruby
|
|
455
|
+
ComponentClasses::Button.classes(variant: :primary, size: :default, soft: false)
|
|
456
|
+
# => "pu-btn pu-btn-md pu-btn-primary"
|
|
457
|
+
|
|
458
|
+
ComponentClasses::Form::INPUT # "pu-input"
|
|
459
|
+
ComponentClasses::Form::LABEL # "pu-label"
|
|
460
|
+
ComponentClasses::Table::WRAPPER # "pu-table-wrapper"
|
|
461
|
+
ComponentClasses::Card::BASE # "pu-card"
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Using tokens in templates
|
|
465
|
+
|
|
466
|
+
```erb
|
|
467
|
+
<h1 class="text-[var(--pu-text)]">Title</h1>
|
|
468
|
+
<p class="text-[var(--pu-text-muted)]">Description</p>
|
|
469
|
+
|
|
470
|
+
<div class="bg-[var(--pu-surface)] border border-[var(--pu-border)] rounded-[var(--pu-radius-lg)]">
|
|
471
|
+
Content
|
|
472
|
+
</div>
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
```ruby
|
|
476
|
+
class MyComponent < Plutonium::UI::Component::Base
|
|
477
|
+
def view_template
|
|
478
|
+
div(class: "bg-[var(--pu-surface)] border border-[var(--pu-border)] rounded-[var(--pu-radius-lg)]",
|
|
479
|
+
style: "box-shadow: var(--pu-shadow-md)") {
|
|
480
|
+
h2(class: "text-lg font-semibold text-[var(--pu-text)]") { "Title" }
|
|
481
|
+
p(class: "text-[var(--pu-text-muted)]") { "Description" }
|
|
482
|
+
}
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Migration from hardcoded classes
|
|
488
|
+
|
|
489
|
+
| Old | New |
|
|
490
|
+
|-----|-----|
|
|
491
|
+
| `text-gray-900 dark:text-white` | `text-[var(--pu-text)]` |
|
|
492
|
+
| `text-gray-500 dark:text-gray-400` | `text-[var(--pu-text-muted)]` |
|
|
493
|
+
| `bg-gray-50 dark:bg-gray-700` | `bg-[var(--pu-surface)]` |
|
|
494
|
+
| `border-gray-300 dark:border-gray-600` | `border-[var(--pu-border)]` |
|
|
495
|
+
| long input class | `pu-input` |
|
|
496
|
+
| `block mb-2 text-sm font-semibold ...` | `pu-label` |
|
|
497
|
+
| `text-red-600 dark:text-red-400` | `pu-error` |
|
|
498
|
+
| long button class | `pu-btn pu-btn-md pu-btn-primary` |
|
|
499
|
+
|
|
500
|
+
## Gotchas
|
|
501
|
+
|
|
502
|
+
- **Always register Stimulus controllers** — Plutonium controllers won't work without `registerControllers(application)`. Custom controllers must also be registered.
|
|
503
|
+
- **Use `plutoniumTailwindConfig.merge`** when overriding theme — plain object merge drops Plutonium's defaults.
|
|
504
|
+
- **Dark mode uses `selector`**, not `class`. Toggle via `document.documentElement.classList.toggle('dark')`.
|
|
505
|
+
- **Tokens are CSS variables**, not Tailwind keys — use `bg-[var(--pu-surface)]`, not `bg-pu-surface`.
|
|
506
|
+
- **Prefer `.pu-*` component classes and tokens** over hardcoded `gray-*/dark:gray-*` pairs — they switch automatically with dark mode.
|
|
507
|
+
|
|
508
|
+
## Related skills
|
|
417
509
|
|
|
418
|
-
- `plutonium-theming` - CSS design tokens and component classes (`.pu-*`)
|
|
419
510
|
- `plutonium-views` - Layout customization
|
|
420
|
-
- `plutonium-forms` - Form theming
|
|
511
|
+
- `plutonium-forms` - Form theming and custom inputs
|
|
421
512
|
- `plutonium-installation` - Initial setup
|