plutonium 0.33.1 → 0.34.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/# Plutonium: The pre-alpha demo.md +4 -2
- data/.claude/skills/assets/SKILL.md +416 -0
- data/.claude/skills/connect-resource/SKILL.md +112 -0
- data/.claude/skills/controller/SKILL.md +302 -0
- data/.claude/skills/create-resource/SKILL.md +240 -0
- data/.claude/skills/definition/SKILL.md +218 -0
- data/.claude/skills/definition-actions/SKILL.md +386 -0
- data/.claude/skills/definition-fields/SKILL.md +474 -0
- data/.claude/skills/definition-query/SKILL.md +334 -0
- data/.claude/skills/forms/SKILL.md +439 -0
- data/.claude/skills/installation/SKILL.md +300 -0
- data/.claude/skills/interaction/SKILL.md +382 -0
- data/.claude/skills/model/SKILL.md +267 -0
- data/.claude/skills/model-features/SKILL.md +286 -0
- data/.claude/skills/nested-resources/SKILL.md +274 -0
- data/.claude/skills/package/SKILL.md +191 -0
- data/.claude/skills/policy/SKILL.md +352 -0
- data/.claude/skills/portal/SKILL.md +400 -0
- data/.claude/skills/resource/SKILL.md +281 -0
- data/.claude/skills/rodauth/SKILL.md +452 -0
- data/.claude/skills/views/SKILL.md +563 -0
- data/Appraisals +46 -4
- data/CHANGELOG.md +32 -1
- data/app/assets/plutonium.css +2 -2
- data/config/brakeman.ignore +239 -0
- data/config/initializers/action_policy.rb +1 -1
- data/docs/.vitepress/config.ts +132 -47
- data/docs/concepts/architecture.md +226 -0
- data/docs/concepts/auto-detection.md +254 -0
- data/docs/concepts/index.md +61 -0
- data/docs/concepts/packages-portals.md +304 -0
- data/docs/concepts/resources.md +224 -0
- data/docs/cookbook/blog.md +412 -0
- data/docs/cookbook/index.md +289 -0
- data/docs/cookbook/saas.md +481 -0
- data/docs/getting-started/index.md +56 -0
- data/docs/getting-started/installation.md +146 -0
- data/docs/getting-started/tutorial/01-setup.md +118 -0
- data/docs/getting-started/tutorial/02-first-resource.md +180 -0
- data/docs/getting-started/tutorial/03-authentication.md +246 -0
- data/docs/getting-started/tutorial/04-authorization.md +170 -0
- data/docs/getting-started/tutorial/05-custom-actions.md +202 -0
- data/docs/getting-started/tutorial/06-nested-resources.md +147 -0
- data/docs/getting-started/tutorial/07-customizing-ui.md +254 -0
- data/docs/getting-started/tutorial/index.md +64 -0
- data/docs/guides/adding-resources.md +420 -0
- data/docs/guides/authentication.md +551 -0
- data/docs/guides/authorization.md +468 -0
- data/docs/guides/creating-packages.md +380 -0
- data/docs/guides/custom-actions.md +523 -0
- data/docs/guides/index.md +45 -0
- data/docs/guides/multi-tenancy.md +302 -0
- data/docs/guides/nested-resources.md +411 -0
- data/docs/guides/search-filtering.md +266 -0
- data/docs/guides/theming.md +321 -0
- data/docs/index.md +67 -26
- data/docs/public/CLAUDE.md +64 -21
- data/docs/reference/assets/index.md +496 -0
- data/docs/reference/controller/index.md +363 -0
- data/docs/reference/definition/actions.md +400 -0
- data/docs/reference/definition/fields.md +350 -0
- data/docs/reference/definition/index.md +252 -0
- data/docs/reference/definition/query.md +342 -0
- data/docs/reference/generators/index.md +469 -0
- data/docs/reference/index.md +49 -0
- data/docs/reference/interaction/index.md +445 -0
- data/docs/reference/model/features.md +248 -0
- data/docs/reference/model/index.md +219 -0
- data/docs/reference/policy/index.md +385 -0
- data/docs/reference/portal/index.md +382 -0
- data/docs/reference/views/forms.md +396 -0
- data/docs/reference/views/index.md +479 -0
- data/gemfiles/rails_7.gemfile +9 -2
- data/gemfiles/rails_7.gemfile.lock +146 -111
- data/gemfiles/rails_8.0.gemfile +20 -0
- data/gemfiles/rails_8.0.gemfile.lock +417 -0
- data/gemfiles/rails_8.1.gemfile +20 -0
- data/gemfiles/rails_8.1.gemfile.lock +419 -0
- data/lib/generators/pu/gem/dotenv/templates/.env +2 -0
- data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +3 -1
- data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +13 -16
- data/lib/generators/pu/pkg/portal/USAGE +65 -0
- data/lib/generators/pu/pkg/portal/portal_generator.rb +22 -9
- data/lib/generators/pu/res/conn/USAGE +71 -0
- data/lib/generators/pu/res/model/USAGE +106 -110
- data/lib/generators/pu/res/model/templates/model.rb.tt +6 -2
- data/lib/generators/pu/res/scaffold/USAGE +85 -0
- data/lib/generators/pu/rodauth/install_generator.rb +2 -6
- data/lib/generators/pu/rodauth/templates/config/initializers/url_options.rb +17 -0
- data/lib/generators/pu/skills/sync/USAGE +14 -0
- data/lib/generators/pu/skills/sync/sync_generator.rb +66 -0
- data/lib/plutonium/action_policy/sti_policy_lookup.rb +1 -1
- data/lib/plutonium/core/controller.rb +2 -2
- data/lib/plutonium/interaction/base.rb +1 -0
- data/lib/plutonium/package/engine.rb +2 -2
- data/lib/plutonium/query/adhoc_block.rb +6 -2
- data/lib/plutonium/query/model_scope.rb +1 -1
- data/lib/plutonium/railtie.rb +4 -0
- data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +1 -1
- data/lib/plutonium/resource/query_object.rb +38 -8
- data/lib/plutonium/ui/table/components/scopes_bar.rb +39 -34
- data/lib/plutonium/version.rb +1 -1
- data/lib/tasks/release.rake +19 -4
- data/package.json +1 -1
- metadata +76 -39
- data/brakeman.ignore +0 -28
- data/docs/api-examples.md +0 -49
- data/docs/guide/claude-code-guide.md +0 -74
- data/docs/guide/deep-dive/authorization.md +0 -189
- data/docs/guide/deep-dive/multitenancy.md +0 -256
- data/docs/guide/deep-dive/resources.md +0 -390
- data/docs/guide/getting-started/01-installation.md +0 -165
- data/docs/guide/index.md +0 -28
- data/docs/guide/introduction/01-what-is-plutonium.md +0 -211
- data/docs/guide/introduction/02-core-concepts.md +0 -440
- data/docs/guide/tutorial/01-project-setup.md +0 -75
- data/docs/guide/tutorial/02-creating-a-feature-package.md +0 -45
- data/docs/guide/tutorial/03-defining-resources.md +0 -90
- data/docs/guide/tutorial/04-creating-a-portal.md +0 -101
- data/docs/guide/tutorial/05-customizing-the-ui.md +0 -128
- data/docs/guide/tutorial/06-adding-custom-actions.md +0 -101
- data/docs/guide/tutorial/07-implementing-authorization.md +0 -90
- data/docs/markdown-examples.md +0 -85
- data/docs/modules/action.md +0 -244
- data/docs/modules/authentication.md +0 -236
- data/docs/modules/configuration.md +0 -599
- data/docs/modules/controller.md +0 -443
- data/docs/modules/core.md +0 -316
- data/docs/modules/definition.md +0 -1308
- data/docs/modules/display.md +0 -759
- data/docs/modules/form.md +0 -495
- data/docs/modules/generator.md +0 -400
- data/docs/modules/index.md +0 -167
- data/docs/modules/interaction.md +0 -642
- data/docs/modules/package.md +0 -151
- data/docs/modules/policy.md +0 -176
- data/docs/modules/portal.md +0 -710
- data/docs/modules/query.md +0 -297
- data/docs/modules/resource_record.md +0 -618
- data/docs/modules/routing.md +0 -690
- data/docs/modules/table.md +0 -301
- data/docs/modules/ui.md +0 -631
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 38de4c2a97493b6e03b185ab05f6c6990df33ad210d89612ce98ef392e6c0ae1
|
|
4
|
+
data.tar.gz: 1de78573407b4032d3f41fc249765028b24d8204f79d68816c4571ac55edf314
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e5f97caf77d2dce2a6c8f3ac2735974a244b1387ab015ecf73ff27210bc7eb74a8c05971145f628c99cb481e55383ee8f62f42a41ac2f372597e9b3e43e4a1c5
|
|
7
|
+
data.tar.gz: 104fd85f23d698fdbbc6bbda701a5a22912516877761471028c93050260853f0a96461d0d80f609b0142f01155b6b5928b4403d654579baeaa9119b08258e1c8
|
|
@@ -43,8 +43,10 @@
|
|
|
43
43
|
```ruby
|
|
44
44
|
# packages/dashboard_app/lib/engine.rb
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
config.after_initialize do
|
|
47
|
+
scope_to_entity User, strategy: :current_user
|
|
48
|
+
# add directives above.
|
|
49
|
+
end
|
|
48
50
|
```
|
|
49
51
|
|
|
50
52
|
- Demonstrate queries
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: assets
|
|
3
|
+
description: Plutonium assets and theming - TailwindCSS configuration, custom styling, and component themes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plutonium Assets & Theming
|
|
7
|
+
|
|
8
|
+
Plutonium uses TailwindCSS 4 for styling with a customizable theme system for components.
|
|
9
|
+
|
|
10
|
+
## Asset Configuration
|
|
11
|
+
|
|
12
|
+
Configure assets in the initializer:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
# config/initializers/plutonium.rb
|
|
16
|
+
Plutonium.configure do |config|
|
|
17
|
+
config.load_defaults 1.0
|
|
18
|
+
|
|
19
|
+
# Custom assets
|
|
20
|
+
config.assets.stylesheet = "application" # Your CSS file
|
|
21
|
+
config.assets.script = "application" # Your JS file
|
|
22
|
+
config.assets.logo = "my_logo.png" # Logo image
|
|
23
|
+
config.assets.favicon = "my_favicon.ico" # Favicon
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Setup Custom Assets
|
|
28
|
+
|
|
29
|
+
Run the assets generator to set up your own TailwindCSS build:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
rails generate pu:core:assets
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This:
|
|
36
|
+
1. Installs required npm packages (`@radioactive-labs/plutonium`, TailwindCSS plugins)
|
|
37
|
+
2. Creates `tailwind.config.js` that extends Plutonium's config
|
|
38
|
+
3. Imports Plutonium CSS into your `application.tailwind.css`
|
|
39
|
+
4. Registers Plutonium's Stimulus controllers
|
|
40
|
+
5. Updates Plutonium config to use your assets
|
|
41
|
+
|
|
42
|
+
## TailwindCSS Configuration
|
|
43
|
+
|
|
44
|
+
### Generated Config
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
// tailwind.config.js
|
|
48
|
+
const { execSync } = require('child_process');
|
|
49
|
+
const plutoniumGemPath = execSync("bundle show plutonium").toString().trim();
|
|
50
|
+
const plutoniumTailwindConfig = require(`${plutoniumGemPath}/tailwind.options.js`)
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
darkMode: plutoniumTailwindConfig.darkMode,
|
|
54
|
+
plugins: [
|
|
55
|
+
// Add your plugins here
|
|
56
|
+
].concat(plutoniumTailwindConfig.plugins),
|
|
57
|
+
theme: plutoniumTailwindConfig.merge(
|
|
58
|
+
plutoniumTailwindConfig.theme,
|
|
59
|
+
{
|
|
60
|
+
// Your custom theme overrides
|
|
61
|
+
},
|
|
62
|
+
),
|
|
63
|
+
content: [
|
|
64
|
+
`${__dirname}/app/**/*.{erb,haml,html,slim,rb}`,
|
|
65
|
+
`${__dirname}/app/javascript/**/*.js`,
|
|
66
|
+
`${__dirname}/packages/**/app/**/*.{erb,haml,html,slim,rb}`,
|
|
67
|
+
].concat(plutoniumTailwindConfig.content),
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Customizing Colors
|
|
72
|
+
|
|
73
|
+
Override Plutonium's color palette:
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
// tailwind.config.js
|
|
77
|
+
theme: plutoniumTailwindConfig.merge(
|
|
78
|
+
plutoniumTailwindConfig.theme,
|
|
79
|
+
{
|
|
80
|
+
extend: {
|
|
81
|
+
colors: {
|
|
82
|
+
primary: {
|
|
83
|
+
50: '#eff6ff',
|
|
84
|
+
100: '#dbeafe',
|
|
85
|
+
200: '#bfdbfe',
|
|
86
|
+
300: '#93c5fd',
|
|
87
|
+
400: '#60a5fa',
|
|
88
|
+
500: '#3b82f6', // Your brand color
|
|
89
|
+
600: '#2563eb',
|
|
90
|
+
700: '#1d4ed8',
|
|
91
|
+
800: '#1e40af',
|
|
92
|
+
900: '#1e3a8a',
|
|
93
|
+
950: '#172554',
|
|
94
|
+
},
|
|
95
|
+
secondary: {
|
|
96
|
+
// Your secondary palette
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
),
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Default Color Palette
|
|
105
|
+
|
|
106
|
+
Plutonium includes these semantic colors:
|
|
107
|
+
|
|
108
|
+
| Color | Usage |
|
|
109
|
+
|-------|-------|
|
|
110
|
+
| `primary` | Primary brand color (turquoise by default) |
|
|
111
|
+
| `secondary` | Secondary color (navy by default) |
|
|
112
|
+
| `success` | Success states (green) |
|
|
113
|
+
| `info` | Informational states (blue) |
|
|
114
|
+
| `warning` | Warning states (amber) |
|
|
115
|
+
| `danger` | Error/danger states (red) |
|
|
116
|
+
| `accent` | Accent highlights (coral pink) |
|
|
117
|
+
|
|
118
|
+
### Dark Mode
|
|
119
|
+
|
|
120
|
+
Plutonium uses `selector` strategy for dark mode:
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
darkMode: "selector"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Toggle dark mode by adding/removing the `dark` class on `<html>`:
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// Toggle dark mode
|
|
130
|
+
document.documentElement.classList.toggle('dark');
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Plutonium includes a color mode selector component that handles this automatically.
|
|
134
|
+
|
|
135
|
+
## CSS Imports
|
|
136
|
+
|
|
137
|
+
### Application Stylesheet
|
|
138
|
+
|
|
139
|
+
```css
|
|
140
|
+
/* app/assets/stylesheets/application.tailwind.css */
|
|
141
|
+
@import "gem:plutonium/src/css/plutonium.css";
|
|
142
|
+
|
|
143
|
+
@import "tailwindcss";
|
|
144
|
+
@config '../../../tailwind.config.js';
|
|
145
|
+
|
|
146
|
+
/* Your custom styles */
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### What Plutonium CSS Includes
|
|
150
|
+
|
|
151
|
+
- Core utility classes
|
|
152
|
+
- EasyMDE (markdown editor) styles
|
|
153
|
+
- Slim Select styles
|
|
154
|
+
- International telephone input styles
|
|
155
|
+
- Flatpickr (date picker) styles
|
|
156
|
+
|
|
157
|
+
## Component Themes
|
|
158
|
+
|
|
159
|
+
Plutonium components use a theme system based on Phlexi. Each component type has a theme class with named style tokens.
|
|
160
|
+
|
|
161
|
+
### Form Theme
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
class PostDefinition < ResourceDefinition
|
|
165
|
+
class Form < Form
|
|
166
|
+
class Theme < Plutonium::UI::Form::Theme
|
|
167
|
+
def self.theme
|
|
168
|
+
super.merge({
|
|
169
|
+
# Container
|
|
170
|
+
base: "bg-white dark:bg-gray-800 shadow-md rounded-lg p-6",
|
|
171
|
+
fields_wrapper: "grid grid-cols-2 gap-6",
|
|
172
|
+
actions_wrapper: "flex justify-end mt-6 space-x-2",
|
|
173
|
+
|
|
174
|
+
# Labels
|
|
175
|
+
label: "block mb-2 text-base font-bold",
|
|
176
|
+
invalid_label: "text-red-700 dark:text-red-500",
|
|
177
|
+
valid_label: "text-green-700 dark:text-green-500",
|
|
178
|
+
neutral_label: "text-gray-500 dark:text-gray-400",
|
|
179
|
+
|
|
180
|
+
# Inputs
|
|
181
|
+
input: "w-full p-2 border rounded-md shadow-sm",
|
|
182
|
+
invalid_input: "bg-red-50 border-red-500 text-red-900",
|
|
183
|
+
valid_input: "bg-green-50 border-green-500 text-green-900",
|
|
184
|
+
neutral_input: "border-gray-300 dark:border-gray-600",
|
|
185
|
+
|
|
186
|
+
# Hints & Errors
|
|
187
|
+
hint: "mt-2 text-sm text-gray-500",
|
|
188
|
+
error: "mt-2 text-sm text-red-600",
|
|
189
|
+
|
|
190
|
+
# Buttons
|
|
191
|
+
button: "px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700",
|
|
192
|
+
})
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Display Theme
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
class PostDefinition < ResourceDefinition
|
|
203
|
+
class Display < Display
|
|
204
|
+
class Theme < Plutonium::UI::Display::Theme
|
|
205
|
+
def self.theme
|
|
206
|
+
super.merge({
|
|
207
|
+
fields_wrapper: "grid grid-cols-3 gap-8",
|
|
208
|
+
label: "text-sm font-bold text-gray-500 mb-1",
|
|
209
|
+
string: "text-lg text-gray-900 dark:text-white",
|
|
210
|
+
link: "text-primary-600 hover:underline",
|
|
211
|
+
markdown: "prose dark:prose-invert max-w-none",
|
|
212
|
+
})
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Table Theme
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
class PostDefinition < ResourceDefinition
|
|
223
|
+
class Table < Table
|
|
224
|
+
class Theme < Plutonium::UI::Table::Theme
|
|
225
|
+
def self.theme
|
|
226
|
+
super.merge({
|
|
227
|
+
wrapper: "overflow-x-auto shadow-md rounded-lg",
|
|
228
|
+
base: "w-full text-sm text-gray-500",
|
|
229
|
+
header: "text-xs uppercase bg-gray-100 dark:bg-gray-700",
|
|
230
|
+
header_cell: "px-6 py-3",
|
|
231
|
+
body_row: "bg-white border-b dark:bg-gray-800",
|
|
232
|
+
body_cell: "px-6 py-4",
|
|
233
|
+
})
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Theme Keys Reference
|
|
241
|
+
|
|
242
|
+
#### Form Theme Keys
|
|
243
|
+
|
|
244
|
+
| Key | Description |
|
|
245
|
+
|-----|-------------|
|
|
246
|
+
| `base` | Form container |
|
|
247
|
+
| `fields_wrapper` | Grid wrapper for fields |
|
|
248
|
+
| `actions_wrapper` | Submit button container |
|
|
249
|
+
| `wrapper` | Individual field wrapper |
|
|
250
|
+
| `inner_wrapper` | Inner field wrapper |
|
|
251
|
+
| `label` | Label base styles |
|
|
252
|
+
| `invalid_label` | Label when field invalid |
|
|
253
|
+
| `valid_label` | Label when field valid |
|
|
254
|
+
| `neutral_label` | Label default state |
|
|
255
|
+
| `input` | Input base styles |
|
|
256
|
+
| `invalid_input` | Input when invalid |
|
|
257
|
+
| `valid_input` | Input when valid |
|
|
258
|
+
| `neutral_input` | Input default state |
|
|
259
|
+
| `hint` | Hint text |
|
|
260
|
+
| `error` | Error message |
|
|
261
|
+
| `button` | Submit button |
|
|
262
|
+
| `checkbox` | Checkbox input |
|
|
263
|
+
| `select` | Select dropdown |
|
|
264
|
+
|
|
265
|
+
#### Display Theme Keys
|
|
266
|
+
|
|
267
|
+
| Key | Description |
|
|
268
|
+
|-----|-------------|
|
|
269
|
+
| `fields_wrapper` | Grid wrapper |
|
|
270
|
+
| `label` | Field label |
|
|
271
|
+
| `description` | Field description |
|
|
272
|
+
| `string` | String values |
|
|
273
|
+
| `text` | Text values |
|
|
274
|
+
| `link` | URL links |
|
|
275
|
+
| `email` | Email links |
|
|
276
|
+
| `phone` | Phone links |
|
|
277
|
+
| `markdown` | Markdown content |
|
|
278
|
+
| `json` | JSON display |
|
|
279
|
+
|
|
280
|
+
#### Table Theme Keys
|
|
281
|
+
|
|
282
|
+
| Key | Description |
|
|
283
|
+
|-----|-------------|
|
|
284
|
+
| `wrapper` | Table container |
|
|
285
|
+
| `base` | Table element |
|
|
286
|
+
| `header` | Header row |
|
|
287
|
+
| `header_cell` | Header cell |
|
|
288
|
+
| `body_row` | Body row |
|
|
289
|
+
| `body_cell` | Body cell |
|
|
290
|
+
| `sort_icon` | Sort indicator |
|
|
291
|
+
|
|
292
|
+
## Using Tokens in Components
|
|
293
|
+
|
|
294
|
+
### The `tokens` Helper
|
|
295
|
+
|
|
296
|
+
Conditionally apply classes:
|
|
297
|
+
|
|
298
|
+
```ruby
|
|
299
|
+
class MyComponent < Plutonium::UI::Component::Base
|
|
300
|
+
def initialize(active:)
|
|
301
|
+
@active = active
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def view_template
|
|
305
|
+
div(class: tokens(
|
|
306
|
+
"base-class",
|
|
307
|
+
active?: "bg-primary-500 text-white",
|
|
308
|
+
inactive?: "bg-gray-200 text-gray-700"
|
|
309
|
+
)) {
|
|
310
|
+
"Content"
|
|
311
|
+
}
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
private
|
|
315
|
+
|
|
316
|
+
def active? = @active
|
|
317
|
+
def inactive? = !@active
|
|
318
|
+
end
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### The `classes` Helper
|
|
322
|
+
|
|
323
|
+
Returns a hash suitable for splatting:
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
div(**classes("p-4", "rounded", active?: "ring-2")) { }
|
|
327
|
+
# => <div class="p-4 rounded ring-2">
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Conditional Tokens with Hash
|
|
331
|
+
|
|
332
|
+
```ruby
|
|
333
|
+
tokens(
|
|
334
|
+
"base",
|
|
335
|
+
condition?: { then: "if-true", else: "if-false" }
|
|
336
|
+
)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Stimulus Controllers
|
|
340
|
+
|
|
341
|
+
Plutonium includes Stimulus controllers. Register them in your application:
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
// app/javascript/controllers/index.js
|
|
345
|
+
import { application } from "./application"
|
|
346
|
+
|
|
347
|
+
import { registerControllers } from "@radioactive-labs/plutonium"
|
|
348
|
+
registerControllers(application)
|
|
349
|
+
|
|
350
|
+
// Your custom controllers...
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Available Controllers
|
|
354
|
+
|
|
355
|
+
- `color-mode` - Dark/light mode toggle
|
|
356
|
+
- `form` - Form handling (pre-submit, etc.)
|
|
357
|
+
- `nested-resource-form-fields` - Nested form management
|
|
358
|
+
- `slim-select` - Enhanced select boxes
|
|
359
|
+
- `flatpickr` - Date/time pickers
|
|
360
|
+
- `easymde` - Markdown editor
|
|
361
|
+
- Various UI controllers
|
|
362
|
+
|
|
363
|
+
## Custom Stimulus Controllers
|
|
364
|
+
|
|
365
|
+
Add your own controllers alongside Plutonium's:
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
// app/javascript/controllers/custom_controller.js
|
|
369
|
+
import { Controller } from "@hotwired/stimulus"
|
|
370
|
+
|
|
371
|
+
export default class extends Controller {
|
|
372
|
+
connect() {
|
|
373
|
+
console.log("Custom controller connected")
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Register in your index:
|
|
379
|
+
|
|
380
|
+
```javascript
|
|
381
|
+
import CustomController from "./custom_controller"
|
|
382
|
+
application.register("custom", CustomController)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Typography
|
|
386
|
+
|
|
387
|
+
Plutonium uses Lato font by default. The layout loads it from Google Fonts.
|
|
388
|
+
|
|
389
|
+
Override in your layout:
|
|
390
|
+
|
|
391
|
+
```ruby
|
|
392
|
+
class MyLayout < Plutonium::UI::Layout::ResourceLayout
|
|
393
|
+
def render_fonts
|
|
394
|
+
# Your custom fonts
|
|
395
|
+
link(rel: "preconnect", href: "https://fonts.googleapis.com")
|
|
396
|
+
link(href: "https://fonts.googleapis.com/css2?family=Inter&display=swap", rel: "stylesheet")
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Update Tailwind config:
|
|
402
|
+
|
|
403
|
+
```javascript
|
|
404
|
+
theme: {
|
|
405
|
+
fontFamily: {
|
|
406
|
+
'body': ['Inter', 'sans-serif'],
|
|
407
|
+
'sans': ['Inter', 'sans-serif'],
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Related Skills
|
|
413
|
+
|
|
414
|
+
- `views` - Layout customization
|
|
415
|
+
- `forms` - Form theming
|
|
416
|
+
- `installation` - Initial setup
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: connect-resource
|
|
3
|
+
description: Connect existing resources to portals for web access
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Connect Resource Skill
|
|
7
|
+
|
|
8
|
+
Use the `pu:res:conn` generator to connect resources to portals. This is required to expose resources through a portal's web interface.
|
|
9
|
+
|
|
10
|
+
## Command Syntax
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
rails g pu:res:conn RESOURCE [RESOURCE...] --dest=PORTAL_NAME
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Always specify resources directly** - this avoids interactive prompts. The `--src` option is only needed for interactive mode and can be ignored.
|
|
17
|
+
|
|
18
|
+
## Usage Patterns
|
|
19
|
+
|
|
20
|
+
### Main App Resources (not in a package)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
rails g pu:res:conn PropertyAmenity --dest=admin_portal
|
|
24
|
+
rails g pu:res:conn Post Comment Tag --dest=dashboard_portal
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Namespaced Resources (from a feature package)
|
|
28
|
+
|
|
29
|
+
Use the full class name:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
rails g pu:res:conn Blogging::Post --dest=admin_portal
|
|
33
|
+
rails g pu:res:conn Blogging::Post Blogging::Comment --dest=admin_portal
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Multiple Resources at Once
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
rails g pu:res:conn Property PropertyAmenity Unit Tenant --dest=admin_portal
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## What Gets Generated
|
|
43
|
+
|
|
44
|
+
For a resource `Post` connected to `admin_portal`:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
packages/admin_portal/
|
|
48
|
+
├── app/
|
|
49
|
+
│ ├── controllers/admin_portal/
|
|
50
|
+
│ │ └── posts_controller.rb # Portal controller
|
|
51
|
+
│ ├── policies/admin_portal/
|
|
52
|
+
│ │ └── post_policy.rb # Portal policy (if needed)
|
|
53
|
+
│ └── definitions/admin_portal/
|
|
54
|
+
│ └── post_definition.rb # Portal definition (if needed)
|
|
55
|
+
└── config/
|
|
56
|
+
└── routes.rb # Updated with register_resource
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Generated Controller
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
class AdminPortal::PostsController < ::PostsController
|
|
63
|
+
include AdminPortal::Concerns::Controller
|
|
64
|
+
end
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Generated Policy
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
class AdminPortal::PostPolicy < ::PostPolicy
|
|
71
|
+
include AdminPortal::ResourcePolicy
|
|
72
|
+
|
|
73
|
+
def permitted_attributes_for_create
|
|
74
|
+
[:title, :content, :user_id]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def permitted_attributes_for_read
|
|
78
|
+
[:title, :content, :user_id, :created_at, :updated_at]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def permitted_associations
|
|
82
|
+
%i[]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Route Registration
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
# In packages/admin_portal/config/routes.rb
|
|
91
|
+
register_resource ::Post
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Typical Workflow
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 1. Create resources (always specify --dest)
|
|
98
|
+
rails g pu:res:scaffold Post user:belongs_to title:string 'content:text?' --dest=main_app
|
|
99
|
+
|
|
100
|
+
# 2. Run migrations
|
|
101
|
+
rails db:migrate
|
|
102
|
+
|
|
103
|
+
# 3. Connect resources to portal (always specify --dest)
|
|
104
|
+
rails g pu:res:conn Post --dest=admin_portal
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Important Notes
|
|
108
|
+
|
|
109
|
+
1. **Always specify resources directly** - avoids prompts, no `--src` needed
|
|
110
|
+
2. **Always use the generator** - never manually connect resources
|
|
111
|
+
3. **Run after migrations** - the generator reads model columns for policy attributes
|
|
112
|
+
4. **Portal-specific customization** - customize the generated policy/definition per-portal
|