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.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium/SKILL.md +85 -102
  3. data/.claude/skills/plutonium-app/SKILL.md +572 -0
  4. data/.claude/skills/plutonium-auth/SKILL.md +163 -300
  5. data/.claude/skills/plutonium-behavior/SKILL.md +838 -0
  6. data/.claude/skills/plutonium-resource/SKILL.md +1176 -0
  7. data/.claude/skills/plutonium-tenancy/SKILL.md +655 -0
  8. data/.claude/skills/plutonium-testing/SKILL.md +6 -5
  9. data/.claude/skills/plutonium-ui/SKILL.md +900 -0
  10. data/CHANGELOG.md +27 -2
  11. data/Rakefile +2 -1
  12. data/app/assets/plutonium.css +1 -11
  13. data/app/assets/plutonium.js +1009 -1214
  14. data/app/assets/plutonium.js.map +3 -3
  15. data/app/assets/plutonium.min.js +52 -51
  16. data/app/assets/plutonium.min.js.map +3 -3
  17. data/docs/.vitepress/config.ts +37 -27
  18. data/docs/getting-started/index.md +22 -29
  19. data/docs/getting-started/installation.md +37 -80
  20. data/docs/getting-started/tutorial/index.md +4 -5
  21. data/docs/guides/adding-resources.md +66 -377
  22. data/docs/guides/authentication.md +94 -463
  23. data/docs/guides/authorization.md +124 -370
  24. data/docs/guides/creating-packages.md +94 -296
  25. data/docs/guides/custom-actions.md +121 -441
  26. data/docs/guides/index.md +22 -42
  27. data/docs/guides/multi-tenancy.md +116 -187
  28. data/docs/guides/nested-resources.md +103 -431
  29. data/docs/guides/search-filtering.md +123 -240
  30. data/docs/guides/testing.md +5 -4
  31. data/docs/guides/theming.md +157 -407
  32. data/docs/guides/troubleshooting.md +5 -3
  33. data/docs/guides/user-invites.md +106 -425
  34. data/docs/guides/user-profile.md +76 -243
  35. data/docs/index.md +1 -1
  36. data/docs/reference/app/generators.md +517 -0
  37. data/docs/reference/app/index.md +158 -0
  38. data/docs/reference/app/packages.md +146 -0
  39. data/docs/reference/app/portals.md +377 -0
  40. data/docs/reference/auth/accounts.md +230 -0
  41. data/docs/reference/auth/index.md +88 -0
  42. data/docs/reference/auth/profile.md +185 -0
  43. data/docs/reference/behavior/controllers.md +395 -0
  44. data/docs/reference/behavior/index.md +22 -0
  45. data/docs/reference/behavior/interactions.md +341 -0
  46. data/docs/reference/behavior/policies.md +417 -0
  47. data/docs/reference/index.md +56 -49
  48. data/docs/reference/resource/actions.md +423 -0
  49. data/docs/reference/resource/definition.md +508 -0
  50. data/docs/reference/resource/index.md +50 -0
  51. data/docs/reference/resource/model.md +348 -0
  52. data/docs/reference/resource/query.md +305 -0
  53. data/docs/reference/tenancy/entity-scoping.md +361 -0
  54. data/docs/reference/tenancy/index.md +36 -0
  55. data/docs/reference/tenancy/invites.md +393 -0
  56. data/docs/reference/tenancy/nested-resources.md +267 -0
  57. data/docs/reference/testing/index.md +287 -0
  58. data/docs/reference/ui/assets.md +400 -0
  59. data/docs/reference/ui/components.md +165 -0
  60. data/docs/reference/ui/displays.md +104 -0
  61. data/docs/reference/ui/forms.md +284 -0
  62. data/docs/reference/ui/index.md +30 -0
  63. data/docs/reference/ui/layouts.md +106 -0
  64. data/docs/reference/ui/pages.md +189 -0
  65. data/docs/reference/ui/tables.md +117 -0
  66. data/docs/superpowers/specs/2026-05-09-typeahead-endpoint-design.md +203 -0
  67. data/docs/superpowers/specs/2026-05-12-skill-compaction-design.md +99 -0
  68. data/docs/superpowers/specs/2026-05-13-docs-restructure-design.md +186 -0
  69. data/gemfiles/rails_7.gemfile.lock +1 -1
  70. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  71. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  72. data/lib/generators/pu/core/update/update_generator.rb +0 -20
  73. data/lib/generators/pu/invites/install_generator.rb +1 -0
  74. data/lib/plutonium/definition/base.rb +1 -1
  75. data/lib/plutonium/definition/{views.rb → index_views.rb} +21 -20
  76. data/lib/plutonium/helpers/turbo_helper.rb +11 -0
  77. data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +14 -0
  78. data/lib/plutonium/resource/controller.rb +1 -0
  79. data/lib/plutonium/resource/controllers/crud_actions.rb +19 -1
  80. data/lib/plutonium/resource/controllers/typeahead.rb +180 -0
  81. data/lib/plutonium/resource/policy.rb +7 -0
  82. data/lib/plutonium/routing/mapper_extensions.rb +15 -0
  83. data/lib/plutonium/ui/component/methods.rb +4 -0
  84. data/lib/plutonium/ui/form/base.rb +6 -2
  85. data/lib/plutonium/ui/form/components/json.rb +58 -0
  86. data/lib/plutonium/ui/form/components/resource_select.rb +62 -8
  87. data/lib/plutonium/ui/form/components/secure_association.rb +98 -22
  88. data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +83 -0
  89. data/lib/plutonium/ui/form/resource.rb +0 -4
  90. data/lib/plutonium/ui/grid/resource.rb +1 -1
  91. data/lib/plutonium/ui/layout/base.rb +1 -0
  92. data/lib/plutonium/ui/page/base.rb +0 -7
  93. data/lib/plutonium/ui/page/index.rb +4 -4
  94. data/lib/plutonium/ui/table/resource.rb +1 -1
  95. data/lib/plutonium/version.rb +1 -1
  96. data/lib/plutonium.rb +8 -0
  97. data/lib/tasks/release.rake +15 -1
  98. data/package.json +10 -10
  99. data/src/css/slim_select.css +4 -0
  100. data/src/js/controllers/slim_select_controller.js +61 -0
  101. data/src/js/turbo/turbo_actions.js +33 -0
  102. data/yarn.lock +553 -543
  103. metadata +44 -33
  104. data/.claude/skills/plutonium-assets/SKILL.md +0 -512
  105. data/.claude/skills/plutonium-controller/SKILL.md +0 -396
  106. data/.claude/skills/plutonium-create-resource/SKILL.md +0 -303
  107. data/.claude/skills/plutonium-definition/SKILL.md +0 -1223
  108. data/.claude/skills/plutonium-entity-scoping/SKILL.md +0 -317
  109. data/.claude/skills/plutonium-forms/SKILL.md +0 -465
  110. data/.claude/skills/plutonium-installation/SKILL.md +0 -331
  111. data/.claude/skills/plutonium-interaction/SKILL.md +0 -413
  112. data/.claude/skills/plutonium-invites/SKILL.md +0 -408
  113. data/.claude/skills/plutonium-model/SKILL.md +0 -440
  114. data/.claude/skills/plutonium-nested-resources/SKILL.md +0 -360
  115. data/.claude/skills/plutonium-package/SKILL.md +0 -198
  116. data/.claude/skills/plutonium-policy/SKILL.md +0 -456
  117. data/.claude/skills/plutonium-portal/SKILL.md +0 -410
  118. data/.claude/skills/plutonium-views/SKILL.md +0 -651
  119. data/docs/reference/assets/index.md +0 -496
  120. data/docs/reference/controller/index.md +0 -412
  121. data/docs/reference/definition/actions.md +0 -462
  122. data/docs/reference/definition/fields.md +0 -383
  123. data/docs/reference/definition/index.md +0 -326
  124. data/docs/reference/definition/query.md +0 -351
  125. data/docs/reference/generators/index.md +0 -648
  126. data/docs/reference/interaction/index.md +0 -449
  127. data/docs/reference/model/features.md +0 -248
  128. data/docs/reference/model/index.md +0 -218
  129. data/docs/reference/policy/index.md +0 -456
  130. data/docs/reference/portal/index.md +0 -379
  131. data/docs/reference/views/forms.md +0 -411
  132. data/docs/reference/views/index.md +0 -544
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plutonium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.50.0
4
+ version: 0.51.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Froelich
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-05-11 00:00:00.000000000 Z
10
+ date: 2026-05-14 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: zeitwerk
@@ -427,23 +427,13 @@ extensions: []
427
427
  extra_rdoc_files: []
428
428
  files:
429
429
  - "# Plutonium: The pre-alpha demo.md"
430
- - ".claude/skills/plutonium-assets/SKILL.md"
430
+ - ".claude/skills/plutonium-app/SKILL.md"
431
431
  - ".claude/skills/plutonium-auth/SKILL.md"
432
- - ".claude/skills/plutonium-controller/SKILL.md"
433
- - ".claude/skills/plutonium-create-resource/SKILL.md"
434
- - ".claude/skills/plutonium-definition/SKILL.md"
435
- - ".claude/skills/plutonium-entity-scoping/SKILL.md"
436
- - ".claude/skills/plutonium-forms/SKILL.md"
437
- - ".claude/skills/plutonium-installation/SKILL.md"
438
- - ".claude/skills/plutonium-interaction/SKILL.md"
439
- - ".claude/skills/plutonium-invites/SKILL.md"
440
- - ".claude/skills/plutonium-model/SKILL.md"
441
- - ".claude/skills/plutonium-nested-resources/SKILL.md"
442
- - ".claude/skills/plutonium-package/SKILL.md"
443
- - ".claude/skills/plutonium-policy/SKILL.md"
444
- - ".claude/skills/plutonium-portal/SKILL.md"
432
+ - ".claude/skills/plutonium-behavior/SKILL.md"
433
+ - ".claude/skills/plutonium-resource/SKILL.md"
434
+ - ".claude/skills/plutonium-tenancy/SKILL.md"
445
435
  - ".claude/skills/plutonium-testing/SKILL.md"
446
- - ".claude/skills/plutonium-views/SKILL.md"
436
+ - ".claude/skills/plutonium-ui/SKILL.md"
447
437
  - ".claude/skills/plutonium/SKILL.md"
448
438
  - ".cliff.toml"
449
439
  - ".node-version"
@@ -593,21 +583,36 @@ files:
593
583
  - docs/public/tutorial/plutonium-posts-detail-customized.png
594
584
  - docs/public/tutorial/plutonium-posts-detail.png
595
585
  - docs/public/tutorial/plutonium-publish-post.png
596
- - docs/reference/assets/index.md
597
- - docs/reference/controller/index.md
598
- - docs/reference/definition/actions.md
599
- - docs/reference/definition/fields.md
600
- - docs/reference/definition/index.md
601
- - docs/reference/definition/query.md
602
- - docs/reference/generators/index.md
586
+ - docs/reference/app/generators.md
587
+ - docs/reference/app/index.md
588
+ - docs/reference/app/packages.md
589
+ - docs/reference/app/portals.md
590
+ - docs/reference/auth/accounts.md
591
+ - docs/reference/auth/index.md
592
+ - docs/reference/auth/profile.md
593
+ - docs/reference/behavior/controllers.md
594
+ - docs/reference/behavior/index.md
595
+ - docs/reference/behavior/interactions.md
596
+ - docs/reference/behavior/policies.md
603
597
  - docs/reference/index.md
604
- - docs/reference/interaction/index.md
605
- - docs/reference/model/features.md
606
- - docs/reference/model/index.md
607
- - docs/reference/policy/index.md
608
- - docs/reference/portal/index.md
609
- - docs/reference/views/forms.md
610
- - docs/reference/views/index.md
598
+ - docs/reference/resource/actions.md
599
+ - docs/reference/resource/definition.md
600
+ - docs/reference/resource/index.md
601
+ - docs/reference/resource/model.md
602
+ - docs/reference/resource/query.md
603
+ - docs/reference/tenancy/entity-scoping.md
604
+ - docs/reference/tenancy/index.md
605
+ - docs/reference/tenancy/invites.md
606
+ - docs/reference/tenancy/nested-resources.md
607
+ - docs/reference/testing/index.md
608
+ - docs/reference/ui/assets.md
609
+ - docs/reference/ui/components.md
610
+ - docs/reference/ui/displays.md
611
+ - docs/reference/ui/forms.md
612
+ - docs/reference/ui/index.md
613
+ - docs/reference/ui/layouts.md
614
+ - docs/reference/ui/pages.md
615
+ - docs/reference/ui/tables.md
611
616
  - docs/superpowers/plans/2026-04-08-plutonium-skills-overhaul.md
612
617
  - docs/superpowers/plans/2026-04-14-plutonium-testing.md
613
618
  - docs/superpowers/plans/2026-04-14-plutonium-testing.md.tasks.json
@@ -618,6 +623,9 @@ files:
618
623
  - docs/superpowers/specs/2026-04-08-plutonium-skills-overhaul-design.md
619
624
  - docs/superpowers/specs/2026-04-14-plutonium-testing-design.md
620
625
  - docs/superpowers/specs/2026-05-07-ui-layout-overhaul-design.md
626
+ - docs/superpowers/specs/2026-05-09-typeahead-endpoint-design.md
627
+ - docs/superpowers/specs/2026-05-12-skill-compaction-design.md
628
+ - docs/superpowers/specs/2026-05-13-docs-restructure-design.md
621
629
  - esbuild.config.js
622
630
  - exe/pug
623
631
  - gemfiles/rails_7.gemfile
@@ -912,6 +920,7 @@ files:
912
920
  - lib/plutonium/definition/base.rb
913
921
  - lib/plutonium/definition/config_attr.rb
914
922
  - lib/plutonium/definition/defineable_props.rb
923
+ - lib/plutonium/definition/index_views.rb
915
924
  - lib/plutonium/definition/inheritable_config_attr.rb
916
925
  - lib/plutonium/definition/metadata.rb
917
926
  - lib/plutonium/definition/nested_inputs.rb
@@ -919,7 +928,6 @@ files:
919
928
  - lib/plutonium/definition/scoping.rb
920
929
  - lib/plutonium/definition/search.rb
921
930
  - lib/plutonium/definition/sorting.rb
922
- - lib/plutonium/definition/views.rb
923
931
  - lib/plutonium/engine.rb
924
932
  - lib/plutonium/engine/validator.rb
925
933
  - lib/plutonium/helpers.rb
@@ -983,6 +991,7 @@ files:
983
991
  - lib/plutonium/resource/controllers/interactive_actions.rb
984
992
  - lib/plutonium/resource/controllers/presentable.rb
985
993
  - lib/plutonium/resource/controllers/queryable.rb
994
+ - lib/plutonium/resource/controllers/typeahead.rb
986
995
  - lib/plutonium/resource/definition.rb
987
996
  - lib/plutonium/resource/interaction.rb
988
997
  - lib/plutonium/resource/policy.rb
@@ -1039,6 +1048,7 @@ files:
1039
1048
  - lib/plutonium/ui/form/components/flatpickr.rb
1040
1049
  - lib/plutonium/ui/form/components/hidden_wrapper.rb
1041
1050
  - lib/plutonium/ui/form/components/intl_tel_input.rb
1051
+ - lib/plutonium/ui/form/components/json.rb
1042
1052
  - lib/plutonium/ui/form/components/key_value_store.rb
1043
1053
  - lib/plutonium/ui/form/components/resource_select.rb
1044
1054
  - lib/plutonium/ui/form/components/secure_association.rb
@@ -1046,6 +1056,7 @@ files:
1046
1056
  - lib/plutonium/ui/form/components/sticky_footer.rb
1047
1057
  - lib/plutonium/ui/form/components/uppy.rb
1048
1058
  - lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb
1059
+ - lib/plutonium/ui/form/concerns/typeahead_attributes.rb
1049
1060
  - lib/plutonium/ui/form/interaction.rb
1050
1061
  - lib/plutonium/ui/form/options/inferred_types.rb
1051
1062
  - lib/plutonium/ui/form/query.rb
@@ -1172,7 +1183,7 @@ metadata:
1172
1183
  homepage_uri: https://radioactive-labs.github.io/plutonium-core/
1173
1184
  source_code_uri: https://github.com/radioactive-labs/plutonium-core
1174
1185
  post_install_message: |
1175
- ⚠️ Plutonium 0.50.0 — breaking change
1186
+ ⚠️ Plutonium 0.51.0 — breaking change
1176
1187
 
1177
1188
  Entity-scoped URL helpers and path params have been renamed from
1178
1189
  `<entity>_scope_*` to `<entity>_scoped_*`.
@@ -1,512 +0,0 @@
1
- ---
2
- name: plutonium-assets
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
- ---
5
-
6
- # Plutonium Assets, Stimulus & Theming
7
-
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).
14
-
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.
16
-
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)
26
-
27
- ## Asset configuration
28
-
29
- ```ruby
30
- # config/initializers/plutonium.rb
31
- Plutonium.configure do |config|
32
- config.load_defaults 1.0
33
-
34
- config.assets.stylesheet = "application" # Your CSS file
35
- config.assets.script = "application" # Your JS file
36
- config.assets.logo = "my_logo.png"
37
- config.assets.favicon = "my_favicon.ico"
38
- end
39
- ```
40
-
41
- Run the assets generator to set up your own TailwindCSS build:
42
-
43
- ```bash
44
- rails generate pu:core:assets
45
- ```
46
-
47
- This:
48
- 1. Installs required npm packages (`@radioactive-labs/plutonium`, TailwindCSS plugins)
49
- 2. Creates `tailwind.config.js` that extends Plutonium's config
50
- 3. Imports Plutonium CSS into your `application.tailwind.css`
51
- 4. Registers Plutonium's Stimulus controllers
52
- 5. Updates Plutonium config to use your assets
53
-
54
- ## TailwindCSS configuration
55
-
56
- ### Generated Config
57
-
58
- ```javascript
59
- // tailwind.config.js
60
- const { execSync } = require('child_process');
61
- const plutoniumGemPath = execSync("bundle show plutonium").toString().trim();
62
- const plutoniumTailwindConfig = require(`${plutoniumGemPath}/tailwind.options.js`)
63
-
64
- module.exports = {
65
- darkMode: plutoniumTailwindConfig.darkMode,
66
- plugins: [].concat(plutoniumTailwindConfig.plugins),
67
- theme: plutoniumTailwindConfig.merge(
68
- plutoniumTailwindConfig.theme,
69
- {
70
- // Your custom theme overrides
71
- },
72
- ),
73
- content: [
74
- `${__dirname}/app/**/*.{erb,haml,html,slim,rb}`,
75
- `${__dirname}/app/javascript/**/*.js`,
76
- `${__dirname}/packages/**/app/**/*.{erb,haml,html,slim,rb}`,
77
- ].concat(plutoniumTailwindConfig.content),
78
- }
79
- ```
80
-
81
- ### Customizing Colors
82
-
83
- ```javascript
84
- theme: plutoniumTailwindConfig.merge(
85
- plutoniumTailwindConfig.theme,
86
- {
87
- extend: {
88
- colors: {
89
- primary: {
90
- 50: '#eff6ff', 500: '#3b82f6', 900: '#1e3a8a',
91
- // ...
92
- },
93
- },
94
- },
95
- },
96
- ),
97
- ```
98
-
99
- ### Default Color Palette
100
-
101
- | Color | Usage |
102
- |-------|-------|
103
- | `primary` | Primary brand color (turquoise by default) |
104
- | `secondary` | Secondary color (navy by default) |
105
- | `success` | Success states (green) |
106
- | `info` | Informational states (blue) |
107
- | `warning` | Warning states (amber) |
108
- | `danger` | Error/danger states (red) |
109
- | `accent` | Accent highlights (coral pink) |
110
-
111
- ### Dark Mode
112
-
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.
114
-
115
- ## CSS imports
116
-
117
- ```css
118
- /* app/assets/stylesheets/application.tailwind.css */
119
- @import "gem:plutonium/src/css/plutonium.css";
120
-
121
- @import "tailwindcss";
122
- @config '../../../tailwind.config.js';
123
-
124
- /* Your custom styles */
125
- ```
126
-
127
- Plutonium CSS includes: core utility classes, EasyMDE (markdown editor) styles, Slim Select styles, International telephone input styles, Flatpickr (date picker) styles.
128
-
129
- ## Phlexi component themes
130
-
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.
132
-
133
- ### Form Theme
134
-
135
- ```ruby
136
- class PostDefinition < ResourceDefinition
137
- class Form < Form
138
- class Theme < Plutonium::UI::Form::Theme
139
- def self.theme
140
- super.merge({
141
- base: "bg-white dark:bg-gray-800 shadow-md rounded-lg p-6",
142
- fields_wrapper: "grid grid-cols-2 gap-6",
143
- actions_wrapper: "flex justify-end mt-6 space-x-2",
144
- label: "block mb-2 text-base font-bold",
145
- invalid_label: "text-red-700 dark:text-red-500",
146
- input: "w-full p-2 border rounded-md shadow-sm",
147
- invalid_input: "bg-red-50 border-red-500 text-red-900",
148
- hint: "mt-2 text-sm text-gray-500",
149
- error: "mt-2 text-sm text-red-600",
150
- button: "px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700",
151
- })
152
- end
153
- end
154
- end
155
- end
156
- ```
157
-
158
- ### Display Theme
159
-
160
- ```ruby
161
- class PostDefinition < ResourceDefinition
162
- class Display < Display
163
- class Theme < Plutonium::UI::Display::Theme
164
- def self.theme
165
- super.merge({
166
- fields_wrapper: "grid grid-cols-3 gap-8",
167
- label: "text-sm font-bold text-gray-500 mb-1",
168
- string: "text-lg text-gray-900 dark:text-white",
169
- link: "text-primary-600 hover:underline",
170
- markdown: "prose dark:prose-invert max-w-none",
171
- })
172
- end
173
- end
174
- end
175
- end
176
- ```
177
-
178
- ### Table Theme
179
-
180
- ```ruby
181
- class PostDefinition < ResourceDefinition
182
- class Table < Table
183
- class Theme < Plutonium::UI::Table::Theme
184
- def self.theme
185
- super.merge({
186
- wrapper: "overflow-x-auto shadow-md rounded-lg",
187
- base: "w-full text-sm text-gray-500",
188
- header: "text-xs uppercase bg-gray-100 dark:bg-gray-700",
189
- header_cell: "px-6 py-3",
190
- body_row: "bg-white border-b dark:bg-gray-800",
191
- body_cell: "px-6 py-4",
192
- })
193
- end
194
- end
195
- end
196
- end
197
- ```
198
-
199
- ### Theme Keys Reference
200
-
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
208
-
209
- ```ruby
210
- class MyComponent < Plutonium::UI::Component::Base
211
- def initialize(active:)
212
- @active = active
213
- end
214
-
215
- def view_template
216
- div(class: tokens(
217
- "base-class",
218
- active?: "bg-primary-500 text-white",
219
- inactive?: "bg-gray-200 text-gray-700"
220
- )) { "Content" }
221
- end
222
-
223
- private
224
-
225
- def active? = @active
226
- def inactive? = !@active
227
- end
228
- ```
229
-
230
- ```ruby
231
- div(**classes("p-4", "rounded", active?: "ring-2")) { }
232
- # => <div class="p-4 rounded ring-2">
233
-
234
- tokens(
235
- "base",
236
- condition?: { then: "if-true", else: "if-false" }
237
- )
238
- ```
239
-
240
- ## Stimulus controllers
241
-
242
- Register Plutonium's Stimulus controllers in your application:
243
-
244
- ```javascript
245
- // app/javascript/controllers/index.js
246
- import { application } from "./application"
247
-
248
- import { registerControllers } from "@radioactive-labs/plutonium"
249
- registerControllers(application)
250
-
251
- // Your custom controllers...
252
- ```
253
-
254
- ### Available controllers
255
-
256
- - `color-mode` - Dark/light mode toggle
257
- - `form` - Form handling (pre-submit, etc.)
258
- - `nested-resource-form-fields` - Nested form management
259
- - `slim-select` - Enhanced select boxes
260
- - `flatpickr` - Date/time pickers
261
- - `easymde` - Markdown editor
262
- - Various UI controllers
263
-
264
- ### Custom Stimulus controllers
265
-
266
- ```javascript
267
- // app/javascript/controllers/custom_controller.js
268
- import { Controller } from "@hotwired/stimulus"
269
-
270
- export default class extends Controller {
271
- connect() {
272
- console.log("Custom controller connected")
273
- }
274
- }
275
- ```
276
-
277
- Register:
278
-
279
- ```javascript
280
- import CustomController from "./custom_controller"
281
- application.register("custom", CustomController)
282
- ```
283
-
284
- ### Typography
285
-
286
- Plutonium uses Lato by default. Override:
287
-
288
- ```ruby
289
- class MyLayout < Plutonium::UI::Layout::ResourceLayout
290
- def render_fonts
291
- link(rel: "preconnect", href: "https://fonts.googleapis.com")
292
- link(href: "https://fonts.googleapis.com/css2?family=Inter&display=swap", rel: "stylesheet")
293
- end
294
- end
295
- ```
296
-
297
- ```javascript
298
- theme: {
299
- fontFamily: {
300
- 'body': ['Inter', 'sans-serif'],
301
- 'sans': ['Inter', 'sans-serif'],
302
- }
303
- }
304
- ```
305
-
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
509
-
510
- - `plutonium-views` - Layout customization
511
- - `plutonium-forms` - Form theming and custom inputs
512
- - `plutonium-installation` - Initial setup