plutonium 0.8.0 → 0.9.1

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -0
  3. data/Rakefile +10 -0
  4. data/app/assets/build/plutonium.js +5122 -0
  5. data/app/assets/javascripts/controllers/index.js +34 -0
  6. data/app/assets/javascripts/controllers/resource_dismiss_controller.js +37 -0
  7. data/app/assets/javascripts/controllers/resource_drop_down_controller.js +29 -0
  8. data/app/assets/javascripts/plutonium-app.js +7 -0
  9. data/app/assets/javascripts/plutonium.js +1 -0
  10. data/app/assets/{js → javascripts}/turbo/index.js +1 -1
  11. data/app/views/application/_flash.html.erb +1 -1
  12. data/app/views/application/_flash_alerts.html.erb +51 -7
  13. data/app/views/application/_flash_toasts.html.erb +53 -23
  14. data/app/views/application/_resource_header.html.erb +563 -561
  15. data/app/views/components/form/form_builder.rb +2 -2
  16. data/app/views/components/form/form_component.html.erb +5 -6
  17. data/app/views/components/interactive_action_form/interactive_action_form_component.html.erb +1 -1
  18. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.html.erb +66 -0
  19. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.rb +23 -0
  20. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_controller.js +64 -0
  21. data/app/views/components/sidebar/sidebar_component.html.erb +61 -63
  22. data/app/views/components/table_search_input/table_search_input_component.html.erb +1 -1
  23. data/app/views/layouts/resource.html copy.erb +0 -2
  24. data/app/views/layouts/resource.html.erb +1 -3
  25. data/app/views/layouts/rodauth.html.erb +0 -1
  26. data/app/views/resource/_interactive_resource_action_form.html.erb +1 -1
  27. data/css.manifest +3 -0
  28. data/esbuild.config.js +44 -0
  29. data/exe/pug +6 -0
  30. data/lib/generators/pu/gen/component/component_generator.rb +14 -5
  31. data/lib/generators/pu/gen/pug/pug_generator.rb +1 -1
  32. data/lib/generators/pu/lib/plutonium_generators/cli.rb +42 -0
  33. data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +86 -72
  34. data/lib/generators/pu/lib/plutonium_generators/generator.rb +1 -5
  35. data/lib/generators/pu/lib/plutonium_generators.rb +8 -0
  36. data/lib/generators/pu/rodauth/install_generator.rb +1 -2
  37. data/lib/plutonium/core/actions/collection.rb +1 -1
  38. data/lib/plutonium/core/controllers/authorizable.rb +4 -4
  39. data/lib/plutonium/core/fields/inputs/base.rb +1 -1
  40. data/lib/plutonium/core/fields/inputs/nested_input.rb +57 -0
  41. data/lib/plutonium/core/fields/inputs/noop_input.rb +1 -1
  42. data/lib/plutonium/core/fields/inputs/phone_input.rb +1 -1
  43. data/lib/plutonium/core/fields/inputs/polymorphic_belongs_to_association_input.rb +1 -1
  44. data/lib/plutonium/core/fields/inputs/simple_form_association_input.rb +1 -1
  45. data/lib/plutonium/core/fields/inputs/simple_form_input.rb +1 -1
  46. data/lib/plutonium/pkg/base.rb +0 -4
  47. data/lib/plutonium/railtie.rb +10 -2
  48. data/lib/plutonium/resource/policy.rb +6 -0
  49. data/lib/plutonium/resource/presenter.rb +35 -0
  50. data/lib/plutonium/resource/record.rb +40 -7
  51. data/lib/plutonium/version.rb +1 -1
  52. data/lib/plutonium.rb +17 -14
  53. data/package.json +4 -3
  54. data/postcss.config.js +1 -1
  55. data/public/plutonium-assets/plutonium-app-36KN5FVJ.js +6 -0
  56. data/public/plutonium-assets/plutonium-app-36KN5FVJ.js.map +7 -0
  57. data/public/plutonium-assets/plutonium.50232e35b5495f5ad90d.css +3415 -0
  58. data/tailwind.config.js +11 -12
  59. data/templates/base.rb +8 -0
  60. metadata +28 -21
  61. data/app/assets/js/controllers/application.js +0 -6
  62. data/app/assets/js/controllers/dropdown_controller.js +0 -12
  63. data/app/assets/js/controllers/index.js +0 -21
  64. data/app/assets/js/plutonium.js +0 -2
  65. data/build.js +0 -12
  66. data/lib/generators/pu/gem/pagy/pagy_generator.rb +0 -25
  67. data/lib/generators/pu/gem/pagy/templates/config/initializers/pagy.rb +0 -4
  68. data/lib/generators/pu/gem/rabl/rabl_generator.rb +0 -25
  69. data/lib/generators/pu/gem/rabl/templates/.keep +0 -0
  70. data/lib/generators/pu/gem/rabl/templates/config/initializers/rabl.rb +0 -60
  71. data/lib/generators/pu/gem/simple_form/simple_form_generator.rb +0 -25
  72. data/lib/generators/pu/gem/simple_form/templates/.keep +0 -0
  73. /data/{lib/generators/pu/gem/pagy/templates → app/assets/build}/.keep +0 -0
  74. /data/app/assets/{js → javascripts}/turbo/turbo_actions.js +0 -0
  75. /data/app/assets/{js → javascripts}/turbo/turbo_debug.js +0 -0
  76. /data/app/assets/{js → javascripts}/turbo/turbo_frame_monkey_patch.js +0 -0
  77. /data/app/assets/{css → stylesheets}/plutonium.css +0 -0
@@ -4,12 +4,12 @@ module Plutonium::Ui
4
4
  class FormBuilder < SimpleForm::FormBuilder
5
5
  def input(attribute_name, options = {}, &block)
6
6
  label_class = options.dig(:label_html, :class)
7
- if object.errors[attribute_name].present?
7
+ if object&.errors&.[](attribute_name).present?
8
8
  # Don't show the hint
9
9
  options.delete(:hint)
10
10
  # Apply error class if there are errors
11
11
  label_class = [label_class, "text-red-700 dark:text-red-500"].compact.join(" ")
12
- elsif object.persisted? || !object.errors.empty?
12
+ elsif object&.persisted? || !object&.errors&.empty?
13
13
  # Apply success class if the object is persisted, has been validated (errors are not empty), and the field has no errors
14
14
  label_class = [label_class, "block mb-2 text-sm font-medium text-green-700 dark:text-green-500"].compact.join(" ")
15
15
  else
@@ -21,13 +21,13 @@
21
21
 
22
22
  <div>
23
23
  <% form.inputs.values.each do |input| %>
24
- <%= input.render f, form.record %>
24
+ <%= input.render self, f, form.record %>
25
25
  <% end %>
26
26
  </div>
27
27
 
28
28
  <div class="flex justify-end space-x-2">
29
29
  <%# TODO: move this into its own component %>
30
- <div class="flex">
30
+ <div class="flex" data-controller="resource-drop-down">
31
31
  <button type="submit"
32
32
  name="commit"
33
33
  value="<%= preferred_action_after_submit %>"
@@ -40,19 +40,18 @@
40
40
  </button>
41
41
  <button type="button"
42
42
  id="form-submit-options-toggle"
43
- data-dropdown-toggle="form-submit-options-dropdown"
43
+ data-resource-drop-down-target="trigger"
44
44
  class="inline-flex items-center px-4 py-2 bg-primary-600 text-white
45
45
  rounded-e-md hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-primary-500
46
46
  dark:border-gray-300
47
- border-s"
48
- >
47
+ border-s">
49
48
  <svg class="w-2.5 h-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
50
49
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
51
50
  </svg>
52
51
  </button>
53
52
 
54
53
  <!-- Dropdown menu -->
55
- <div id="form-submit-options-dropdown"
54
+ <div data-resource-drop-down-target="menu"
56
55
  class="z-10 hidden w-56 bg-white divide-y divide-gray-100 rounded-lg shadow dark:bg-gray-700 dark:divide-gray-600">
57
56
  <ul class="p-3 space-y-3 text-sm text-gray-700 dark:text-gray-200"
58
57
  aria-labelledby="form-submit-options-toggle">
@@ -21,7 +21,7 @@
21
21
 
22
22
  <div>
23
23
  <% interactive_action.inputs.values.each do |input| %>
24
- <%= input.render f, interaction %>
24
+ <%= input.render self, f, interaction %>
25
25
  <% end %>
26
26
  </div>
27
27
 
@@ -0,0 +1,66 @@
1
+ <div data-controller="nested-resource-form-fields"
2
+ data-nested-resource-form-fields-limit-value="<%= limit %>"
3
+ <%= render_component_attributes %>>
4
+ <h2 class="text-lg font-bold dark:text-white ">
5
+ <%= label %>
6
+ </h2>
7
+ <p class="mb-4 text-md font-normal text-gray-500 dark:text-gray-400">
8
+ <%= description %>
9
+ </p>
10
+
11
+ <template data-nested-resource-form-fields-target="template">
12
+ <% new_record = resource_class.new %>
13
+ <%= form.simple_fields_for name, new_record, child_index: 'NEW_RECORD' do |nested| %>
14
+ <fieldset class="border-t mt-4 pt-4 first:border-t-0 first:pt-0 nested-resource-form-fields" data-new-record="<%= nested.object.new_record? %>">
15
+ <% inputs.values.each do |input| %>
16
+ <%= input.render self, nested, new_record %>
17
+ <% end %>
18
+
19
+ <div class="text-right">
20
+ <% if nested.object.new_record? || allow_destroy %>
21
+ <label class="text-md font-medium text-red-900">
22
+ <%= "Delete" %>
23
+ <input type="checkbox" value=""
24
+ data-action="nested-resource-form-fields#remove"
25
+ class="w-4 h-4 ms-2 text-red-600 bg-red-100 border-red-300 rounded focus:ring-red-500 dark:focus:ring-red-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
26
+ </label>
27
+ <% end %>
28
+ </div>
29
+
30
+ <%= nested.hidden_field :_destroy %>
31
+ </fieldset>
32
+ <% end %>
33
+ </template>
34
+
35
+ <div>
36
+ <%= form.simple_fields_for name do |nested| %>
37
+ <fieldset class="border-t mt-4 pt-4 first:border-t-0 first:pt-0 nested-resource-form-fields" data-new-record="<%= nested.object.new_record? %>">
38
+ <% inputs.values.each do |input| %>
39
+ <%= input.render self, nested, new_record %>
40
+ <% end %>
41
+
42
+ <div>
43
+ <% if nested.object.new_record? || allow_destroy %>
44
+ <label class="flex items-center justify-end text-md font-medium text-red-900">
45
+ <%= "Delete" %>
46
+ <input type="checkbox" value=""
47
+ data-action="nested-resource-form-fields#remove"
48
+ class="w-4 h-4 ms-2 text-red-600 bg-red-100 border-red-300 rounded focus:ring-red-500 dark:focus:ring-red-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
49
+ </label>
50
+ <% end %>
51
+ </div>
52
+
53
+ <%= nested.hidden_field :_destroy %>
54
+ </fieldset>
55
+ <% end %>
56
+
57
+ <div data-nested-resource-form-fields-target="target" hidden></div>
58
+ </div>
59
+
60
+ <%=
61
+ render_component :button, label: "Add #{name.to_s.singularize.humanize}", classname: "mt-4", data: {
62
+ action: "nested-resource-form-fields#add",
63
+ "nested-resource-form-fields-target": "addButton"
64
+ }
65
+ %>
66
+ </div>
@@ -0,0 +1,23 @@
1
+ module Plutonium::Ui
2
+ class NestedResourceFormFieldsComponent < Plutonium::Ui::Base
3
+ option :name
4
+ option :resource_class
5
+ option :form
6
+ option :inputs
7
+ option :label, optional: true
8
+ option :description, optional: true
9
+ option :allow_destroy, optional: true
10
+ option :update_only, optional: true
11
+ option :limit, optional: true
12
+
13
+ def base_classname
14
+ "mt-6 mb-4"
15
+ end
16
+
17
+ def label
18
+ super || name.to_s.humanize
19
+ end
20
+ end
21
+ end
22
+
23
+ Plutonium::ComponentRegistry.register :nested_resource_form_fields, to: Plutonium::Ui::NestedResourceFormFieldsComponent
@@ -0,0 +1,64 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="nested-resource-form-fields"
4
+ // Copied from https://github.com/stimulus-components/stimulus-rails-nested-form/blob/master/src/index.ts
5
+ export default class extends Controller {
6
+ static targets = ["target", "template", "addButton"]
7
+
8
+ static values = {
9
+ wrapperSelector: {
10
+ type: String,
11
+ default: ".nested-resource-form-fields",
12
+ },
13
+ limit: Number,
14
+ }
15
+
16
+ connect() {
17
+ this.updateState()
18
+ }
19
+
20
+ add(e) {
21
+ e.preventDefault()
22
+
23
+ const content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime().toString())
24
+ this.targetTarget.insertAdjacentHTML("beforebegin", content)
25
+
26
+ const event = new CustomEvent("nested-resource-form-fields:add", { bubbles: true })
27
+ this.element.dispatchEvent(event)
28
+
29
+ this.updateState()
30
+ }
31
+
32
+ remove(e) {
33
+ e.preventDefault()
34
+
35
+ const wrapper = e.target.closest(this.wrapperSelectorValue)
36
+
37
+ if (wrapper.dataset.newRecord === "true") {
38
+ wrapper.remove()
39
+ } else {
40
+ wrapper.style.display = "none"
41
+
42
+ const input = wrapper.querySelector("input[name*='_destroy']")
43
+ input.value = "1"
44
+ }
45
+
46
+ const event = new CustomEvent("nested-resource-form-fields:remove", { bubbles: true })
47
+ this.element.dispatchEvent(event)
48
+
49
+ this.updateState()
50
+ }
51
+
52
+ updateState() {
53
+ if (!this.hasAddButtonTarget || this.limitValue == 0) return
54
+
55
+ if (this.childCount >= this.limitValue)
56
+ this.addButtonTarget.style.display = "none"
57
+ else
58
+ this.addButtonTarget.style.display = "initial"
59
+ }
60
+
61
+ get childCount() {
62
+ return this.element.querySelectorAll(this.wrapperSelectorValue).length
63
+ }
64
+ }
@@ -86,69 +86,67 @@
86
86
  updateColorMode()
87
87
  </script>
88
88
 
89
-
90
- <button
91
- type="button"
92
- data-dropdown-toggle="color-mode-dropdown"
93
- class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:hover:text-white dark:text-gray-200 hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600"
94
- >
95
- <svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
96
- <path d="M5 13.17a3.001 3.001 0 0 0 0 5.66V20a1 1 0 1 0 2 0v-1.17a3.001 3.001 0 0 0 0-5.66V4a1 1 0 0 0-2 0v9.17ZM11 20v-9.17a3.001 3.001 0 0 1 0-5.66V4a1 1 0 1 1 2 0v1.17a3.001 3.001 0 0 1 0 5.66V20a1 1 0 1 1-2 0Zm6-1.17V20a1 1 0 1 0 2 0v-1.17a3.001 3.001 0 0 0 0-5.66V4a1 1 0 1 0-2 0v9.17a3.001 3.001 0 0 0 0 5.66Z"/>
97
- </svg>
98
- </button>
99
-
100
-
101
- <div
102
- class="hidden z-50 my-4 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700"
103
- id="color-mode-dropdown"
104
- >
105
- <ul class="py-1" role="none">
106
- <li>
107
- <button
108
- type="button"
109
- class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
110
- role="menuitem"
111
- onclick="setLightColorMode()"
112
- >
113
- <div class="flex justify-start">
114
- <svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
115
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5V3m0 18v-2M7.05 7.05 5.636 5.636m12.728 12.728L16.95 16.95M5 12H3m18 0h-2M7.05 16.95l-1.414 1.414M18.364 5.636 16.95 7.05M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"/>
116
- </svg>
117
- Light
118
- </div>
119
- </a>
120
- </li>
121
- <li>
122
- <button
123
- type="button"
124
- class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
125
- role="menuitem"
126
- onclick="setDarkColorMode()"
127
- >
128
- <div class="flex justify-start">
129
- <svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
130
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 21a9 9 0 0 1-.5-17.986V3c-.354.966-.5 1.911-.5 3a9 9 0 0 0 9 9c.239 0 .254.018.488 0A9.004 9.004 0 0 1 12 21Z"/>
131
- </svg>
132
- Dark
133
- </div>
134
- </a>
135
- </li>
136
- <li>
137
- <button
138
- type="button"
139
- class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
140
- role="menuitem"
141
- onclick="setSystemColorMode()"
142
- >
143
- <div class="flex justify-start">
144
- <svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
145
- <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 16H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v1M9 12H4m8 8V9h8v11h-8Zm0 0H9m8-4a1 1 0 1 0-2 0 1 1 0 0 0 2 0Z"/>
146
- </svg>
147
- System
148
- </div>
149
- </a>
150
- </li>
151
- </ul>
89
+ <!-- Color Modes -->
90
+ <div data-controller="resource-drop-down">
91
+ <button
92
+ type="button"
93
+ data-resource-drop-down-target="trigger"
94
+ class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:hover:text-white dark:text-gray-200 hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600">
95
+ <svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
96
+ <path d="M5 13.17a3.001 3.001 0 0 0 0 5.66V20a1 1 0 1 0 2 0v-1.17a3.001 3.001 0 0 0 0-5.66V4a1 1 0 0 0-2 0v9.17ZM11 20v-9.17a3.001 3.001 0 0 1 0-5.66V4a1 1 0 1 1 2 0v1.17a3.001 3.001 0 0 1 0 5.66V20a1 1 0 1 1-2 0Zm6-1.17V20a1 1 0 1 0 2 0v-1.17a3.001 3.001 0 0 0 0-5.66V4a1 1 0 1 0-2 0v9.17a3.001 3.001 0 0 0 0 5.66Z"/>
97
+ </svg>
98
+ </button>
99
+ <div
100
+ class="hidden z-50 my-4 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700"
101
+ data-resource-drop-down-target="menu">
102
+ <ul class="py-1" role="none">
103
+ <li>
104
+ <button
105
+ type="button"
106
+ class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
107
+ role="menuitem"
108
+ onclick="setLightColorMode()"
109
+ >
110
+ <div class="flex justify-start">
111
+ <svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
112
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5V3m0 18v-2M7.05 7.05 5.636 5.636m12.728 12.728L16.95 16.95M5 12H3m18 0h-2M7.05 16.95l-1.414 1.414M18.364 5.636 16.95 7.05M16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z"/>
113
+ </svg>
114
+ Light
115
+ </div>
116
+ </a>
117
+ </li>
118
+ <li>
119
+ <button
120
+ type="button"
121
+ class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
122
+ role="menuitem"
123
+ onclick="setDarkColorMode()"
124
+ >
125
+ <div class="flex justify-start">
126
+ <svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
127
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 21a9 9 0 0 1-.5-17.986V3c-.354.966-.5 1.911-.5 3a9 9 0 0 0 9 9c.239 0 .254.018.488 0A9.004 9.004 0 0 1 12 21Z"/>
128
+ </svg>
129
+ Dark
130
+ </div>
131
+ </a>
132
+ </li>
133
+ <li>
134
+ <button
135
+ type="button"
136
+ class="w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
137
+ role="menuitem"
138
+ onclick="setSystemColorMode()"
139
+ >
140
+ <div class="flex justify-start">
141
+ <svg class="w-6 h-6 me-2 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
142
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 16H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v1M9 12H4m8 8V9h8v11h-8Zm0 0H9m8-4a1 1 0 1 0-2 0 1 1 0 0 0 2 0Z"/>
143
+ </svg>
144
+ System
145
+ </div>
146
+ </a>
147
+ </li>
148
+ </ul>
149
+ </div>
152
150
  </div>
153
151
  </div>
154
152
  </aside>
@@ -7,7 +7,7 @@
7
7
  <path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
8
8
  </svg>
9
9
  </div>
10
- <%= search_object.search_filter.input_definitions[:search].render f, nil,
10
+ <%= search_object.search_filter.input_definitions[:search].render self, f, nil,
11
11
  wrapper: false, label: false,
12
12
  as: :string, # force string for search
13
13
  placeholder: "search...",
@@ -15,8 +15,6 @@
15
15
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.css" integrity="sha512-GvqWM4KWH8mbgWIyvwdH8HgjUbyZTXrCq0sjGij9fDNiXz3vJoy3jCcAaWNekH2rJe4hXVWCJKN+bEW8V7AAEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
16
16
  <script src="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.js" integrity="sha512-0E8oaoA2v32h26IycsmRDShtQ8kMgD91zWVBxdIvUCjU3xBw81PV61QBsBqNQpWkp/zYJZip8Ag3ifmzz1wCKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
17
17
 
18
- <script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
19
-
20
18
  <%== Plutonium::Config.stylesheet_tag.call self %>
21
19
  <%== Plutonium::Config.script_tag.call self %>
22
20
  <%= yield(:head) %>
@@ -21,8 +21,6 @@
21
21
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.css" integrity="sha512-GvqWM4KWH8mbgWIyvwdH8HgjUbyZTXrCq0sjGij9fDNiXz3vJoy3jCcAaWNekH2rJe4hXVWCJKN+bEW8V7AAEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
22
22
  <script src="https://cdnjs.cloudflare.com/ajax/libs/slim-select/2.6.0/slimselect.min.js" integrity="sha512-0E8oaoA2v32h26IycsmRDShtQ8kMgD91zWVBxdIvUCjU3xBw81PV61QBsBqNQpWkp/zYJZip8Ag3ifmzz1wCKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
23
23
 
24
- <script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
25
-
26
24
  <%= yield(:assets) %>
27
25
 
28
26
  <%== Plutonium::Config.stylesheet_tag.call self %>
@@ -34,6 +32,7 @@
34
32
  <%= render("resource_header") %>
35
33
  <%= render("resource_sidebar") %>
36
34
  <main class="p-4 lg:ml-64 h-auto pt-20">
35
+ <%= render "flash" %>
37
36
  <%= yield %>
38
37
  </main>
39
38
  </body>
@@ -45,6 +44,5 @@
45
44
  <%= modal_frame_tag do %>
46
45
  <%= yield(:modal) %>
47
46
  <% end %>
48
- <%= render "flash" %>
49
47
 
50
48
  -->
@@ -12,7 +12,6 @@
12
12
  <link rel="preconnect" href="https://fonts.googleapis.com">
13
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
14
  <link href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet">
15
- <script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
16
15
  <%== Plutonium::Config.stylesheet_tag.call self %>
17
16
  <%== Plutonium::Config.script_tag.call self %>
18
17
  </head>
@@ -25,7 +25,7 @@
25
25
  </div>
26
26
  <div class="form-inputs">
27
27
  <% interactive_action.inputs.values.each do |input| %>
28
- <%= input.render f, @interaction %>
28
+ <%= input.render self, f, @interaction %>
29
29
  <% end %>
30
30
  </div>
31
31
  </div>
data/css.manifest ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "plutonium.css": "plutonium.50232e35b5495f5ad90d.css"
3
+ }
data/esbuild.config.js ADDED
@@ -0,0 +1,44 @@
1
+ const esbuild = require('esbuild');
2
+ const manifestPlugin = require('esbuild-plugin-manifest')
3
+
4
+
5
+ if (process.argv.includes("--prod")) {
6
+ esbuild.build({
7
+ outdir: "public/plutonium-assets",
8
+ entryPoints: [
9
+ "app/assets/javascripts/plutonium-app.js"
10
+ ],
11
+ plugins: [
12
+ manifestPlugin({
13
+ filename: `${__dirname}/js.manifest`,
14
+ shortNames: true,
15
+ })
16
+ ],
17
+ minify: true,
18
+ sourcemap: true,
19
+ bundle: true,
20
+ })
21
+
22
+ esbuild.build({
23
+ outdir: "app/assets/build",
24
+ entryPoints: [
25
+ "app/assets/javascripts/plutonium.js"
26
+ ],
27
+ bundle: true,
28
+ })
29
+ }
30
+ else {
31
+ esbuild.context({
32
+ outdir: "public/plutonium-assets/build",
33
+ entryPoints: [
34
+ "app/assets/javascripts/plutonium-app.js"
35
+ ],
36
+ plugins: [
37
+ manifestPlugin({
38
+ filename: `${__dirname}/js.dev.manifest`,
39
+ shortNames: true,
40
+ })
41
+ ],
42
+ bundle: true,
43
+ }).then((context) => context.watch().catch((e) => console.error(e.message)))
44
+ }
data/exe/pug ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path("../lib/generators/pu/lib/plutonium_generators.rb", __dir__)
4
+
5
+ ENV["PU_CLI"] = "1"
6
+ PlutoniumGenerators::CLI.start(ARGV)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- return if PlutoniumGenerators.rails?
3
+ return unless PlutoniumGenerators.cli?
4
4
 
5
5
  module Pu
6
6
  module Gen
@@ -20,8 +20,10 @@ module Pu
20
20
  template "component.html.erb", "#{component_path}.html.erb"
21
21
  template "controller.js", controller_path
22
22
 
23
- controllers_file = File.join __dir__, "../../../../../app/assets/js/controllers/index.js"
24
- insert_into_file controllers_file, controller_registration, after: /.*Register controllers here.*\n\n/
23
+ controllers_index_file = File.join __dir__, "../../../../../app/assets/javascripts/controllers/index.js"
24
+ insert_into_file controllers_index_file, controller_import, after: /.*Import controllers here*\n/
25
+ insert_into_file controllers_index_file, controller_registration, after: /.*Register controllers here*\n/
26
+ insert_into_file controllers_index_file, controller_export, after: /.*Export controllers here*\n/
25
27
  end
26
28
 
27
29
  protected
@@ -78,9 +80,16 @@ module Pu
78
80
  [component_module, "#{component_name}Controller"].compact.join("::").gsub("::", "_")
79
81
  end
80
82
 
83
+ def controller_import
84
+ "import #{controller_reference} from \"../../../../#{controller_path}\"\n"
85
+ end
86
+
81
87
  def controller_registration
82
- %(import #{controller_reference} from "../../../../#{controller_path}"\n) +
83
- %(application.register("#{controller_identifier}", #{controller_reference})\n\n)
88
+ " application.register(\"#{controller_identifier}\", #{controller_reference})\n"
89
+ end
90
+
91
+ def controller_export
92
+ "export { #{controller_reference} }\n"
84
93
  end
85
94
  end
86
95
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- return if PlutoniumGenerators.rails?
3
+ return unless PlutoniumGenerators.cli?
4
4
 
5
5
  module Pu
6
6
  module Gen
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require File.expand_path("../plutonium_generators", __dir__)
5
+
6
+ module PlutoniumGenerators
7
+ class CLI < Thor
8
+ map "i" => :install
9
+ map "g" => :generate
10
+ map "ls" => :list
11
+ map %w[--version -v] => :__print_version
12
+
13
+ # desc "install", "Install Plutonium"
14
+ # def install
15
+ # Rails::Generators.invoke("pu:install")
16
+ # end
17
+
18
+ desc "generate, g GENERATOR [options]", "Run plutonium generator"
19
+ def generate(generator, *options)
20
+ Rails::Generators.invoke("pu:#{generator}", options)
21
+ end
22
+
23
+ desc "list, ls", "View list of available generators"
24
+ def list
25
+ generators = Rails::Generators.sorted_groups.to_h["pu"]
26
+ puts
27
+ generators.each { |gen| puts gen.sub(/^pu:/, "") }
28
+ puts
29
+ end
30
+
31
+ desc "--version, -v", "Print gem version"
32
+ def __print_version
33
+ puts "Plutonium generators #{PlutoniumGenerators::VERSION}"
34
+ end
35
+
36
+ class << self
37
+ def exit_on_failure?
38
+ true
39
+ end
40
+ end
41
+ end
42
+ end