plutonium 0.8.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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