railsui 3.2.7 → 3.3.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -1
  3. data/README.md +196 -42
  4. data/app/assets/javascripts/railsui-controllers.js +12 -0
  5. data/app/controllers/railsui/configurations_controller.rb +11 -2
  6. data/app/helpers/railsui/application_helper.rb +12 -0
  7. data/app/javascript/controllers/index.js +3 -31
  8. data/app/javascript/controllers/railsui_anchor_controller.js +4 -3
  9. data/app/javascript/controllers/railsui_auto_expand_text_area_controller.js +1 -1
  10. data/app/javascript/controllers/railsui_canvas_controller.js +1 -1
  11. data/app/javascript/controllers/railsui_code_controller.js +3 -28
  12. data/app/javascript/controllers/railsui_color_controller.js +1 -1
  13. data/app/javascript/controllers/railsui_configuration_controller.js +1 -1
  14. data/app/javascript/controllers/railsui_dialog_controller.js +1 -1
  15. data/app/javascript/controllers/railsui_flash_controller.js +1 -1
  16. data/app/javascript/controllers/railsui_helper_controller.js +1 -1
  17. data/app/javascript/controllers/railsui_loading_controller.js +1 -1
  18. data/app/javascript/controllers/railsui_modal_controller.js +4 -3
  19. data/app/javascript/controllers/railsui_nav_controller.js +4 -3
  20. data/app/javascript/controllers/railsui_pages_controller.js +1 -1
  21. data/app/javascript/controllers/railsui_prevent_controller.js +1 -1
  22. data/app/javascript/controllers/railsui_scroll_controller.js +1 -1
  23. data/app/javascript/controllers/railsui_scroll_spy_controller.js +1 -1
  24. data/app/javascript/controllers/railsui_search_controller.js +1 -1
  25. data/app/javascript/controllers/railsui_smooth_controller.js +1 -1
  26. data/app/javascript/controllers/railsui_snippet_controller.js +1 -1
  27. data/app/views/layouts/railsui/application.html.erb +7 -5
  28. data/app/views/layouts/railsui/fullwidth.html.erb +4 -4
  29. data/app/views/layouts/railsui/landing.html.erb +3 -4
  30. data/app/views/layouts/railsui/routes.html.erb +4 -3
  31. data/app/views/railsui/admin/_form.html.erb +18 -1
  32. data/app/views/railsui/admin/fields/_theme.html.erb +0 -1
  33. data/app/views/railsui/shared/_cdn_dependencies.html.erb +121 -0
  34. data/app/views/railsui/shared/_inline_controllers.html.erb +498 -0
  35. data/app/views/railsui/shared/_snippet.html.erb +23 -1
  36. data/app/views/railsui/themes/hound/forms/_input_group.html.erb +3 -1
  37. data/app/views/railsui/themes/shepherd/authentication/devise/_overview.html.erb +30 -28
  38. data/app/views/railsui/themes/shepherd/authentication/static/_overview.html.erb +8 -8
  39. data/app/views/railsui/themes/shepherd/content/typography/_headings.html.erb +23 -21
  40. data/app/views/railsui/themes/shepherd/forms/_input.html.erb +1 -1
  41. data/guides/CONFIGURATION.md +199 -0
  42. data/guides/MIGRATION_GUIDE.md +220 -0
  43. data/lib/generators/railsui/install/install_generator.rb +124 -38
  44. data/lib/generators/railsui/install/templates/Procfile.dev.build +1 -0
  45. data/lib/generators/railsui/install/templates/Procfile.dev.nobuild +2 -0
  46. data/lib/generators/railsui/install/templates/bin/dev +21 -0
  47. data/lib/generators/railsui/install/templates/themes/corgie/stylesheets/railsui/actiontext.css +0 -1
  48. data/lib/generators/railsui/install/templates/themes/corgie/views/layouts/rui/railsui.html.erb +7 -2
  49. data/lib/generators/railsui/install/templates/themes/corgie/views/layouts/rui/railsui_admin.html.erb +7 -2
  50. data/lib/generators/railsui/install/templates/themes/corgie/views/layouts/rui/railsui_auth.html.erb +6 -2
  51. data/lib/generators/railsui/install/templates/themes/corgie/views/rui/pages/{privacy.html.erb → privacy_policy.html.erb} +1 -1
  52. data/lib/generators/railsui/install/templates/themes/corgie/views/rui/pages/terms.html.erb +2 -2
  53. data/lib/generators/railsui/install/templates/themes/corgie/views/rui/shared/sidebar/_link.html.erb +4 -4
  54. data/lib/generators/railsui/install/templates/themes/hound/stylesheets/railsui/actiontext.css +0 -1
  55. data/lib/generators/railsui/install/templates/themes/hound/views/layouts/rui/railsui.html.erb +6 -2
  56. data/lib/generators/railsui/install/templates/themes/hound/views/layouts/rui/railsui_admin.html.erb +6 -2
  57. data/lib/generators/railsui/install/templates/themes/shepherd/stylesheets/railsui/actiontext.css +0 -1
  58. data/lib/generators/railsui/install/templates/themes/shepherd/views/layouts/rui/railsui.html.erb +6 -2
  59. data/lib/generators/railsui/install/templates/themes/shepherd/views/layouts/rui/railsui_admin.html.erb +6 -2
  60. data/lib/generators/railsui/update/update_generator.rb +40 -4
  61. data/lib/railsui/configuration.rb +116 -15
  62. data/lib/railsui/engine.rb +15 -0
  63. data/lib/railsui/theme_setup.rb +598 -38
  64. data/lib/railsui/version.rb +1 -1
  65. data/lib/railsui.rb +10 -7
  66. data/lib/tasks/install.rake +9 -3
  67. data/lib/tasks/migrate.rake +219 -0
  68. metadata +26 -4
  69. data/.claude/settings.local.json +0 -10
@@ -8,7 +8,7 @@ module Railsui
8
8
  include ActiveModel::Model
9
9
  include Thor::Actions
10
10
 
11
- attr_accessor :application_name, :support_email, :theme, :body_classes
11
+ attr_accessor :application_name, :support_email, :theme, :body_classes, :build_mode
12
12
  attr_writer :pages
13
13
 
14
14
  def initialize(options = {})
@@ -16,6 +16,7 @@ module Railsui
16
16
  assign_attributes(options)
17
17
  self.application_name ||= "Rails UI"
18
18
  self.support_email ||= "support@example.com"
19
+ self.build_mode ||= detect_build_mode
19
20
  theme
20
21
  initialize_theme_classes if theme
21
22
  end
@@ -26,10 +27,16 @@ module Railsui
26
27
 
27
28
  def self.load!
28
29
  if File.exist?(config_path)
29
- config = Psych.load_file(config_path, permitted_classes: [Hash, Railsui::Configuration])
30
- return config if config.is_a?(Railsui::Configuration)
31
-
32
- new(config)
30
+ begin
31
+ config = Psych.load_file(config_path, permitted_classes: [Hash, Railsui::Configuration])
32
+ return config if config.is_a?(Railsui::Configuration)
33
+
34
+ new(config)
35
+ rescue Psych::SyntaxError => e
36
+ raise "❌ Failed to parse config/railsui.yml: #{e.message}. Please check the YAML syntax."
37
+ rescue => e
38
+ raise "❌ Failed to load Rails UI configuration: #{e.message}"
39
+ end
33
40
  else
34
41
  new
35
42
  end
@@ -63,25 +70,45 @@ module Railsui
63
70
  Rails.root.join("config", "railsui.yml")
64
71
  end
65
72
 
66
- def save
67
- # Create config/railsui.yml
68
- File.write(self.class.config_path, to_yaml)
73
+ def save(skip_build: false)
74
+ # Validate configuration before saving
75
+ validate_configuration!
76
+
77
+ begin
78
+ # Create config/railsui.yml
79
+ File.write(self.class.config_path, to_yaml)
80
+ rescue => e
81
+ raise "❌ Failed to save configuration to config/railsui.yml: #{e.message}"
82
+ end
69
83
 
70
84
  # Change the Rails UI config to the latest version
71
85
  Railsui.config = self
72
86
 
73
87
  sleep 1
74
88
 
75
- Railsui.build_css
89
+ # Only build CSS if not explicitly skipped and CSS file exists
90
+ if !skip_build && should_build_css? && File.exist?(Rails.root.join("app/assets/tailwind/application.css"))
91
+ begin
92
+ Railsui.build_css
93
+ rescue => e
94
+ puts "⚠️ Warning: CSS build failed: #{e.message}"
95
+ puts "You can rebuild manually with: rails tailwindcss:build"
96
+ end
97
+ end
76
98
  end
77
99
 
78
100
  def self.update(params = {})
79
- config = load!
80
- config.assign_attributes(params)
81
- config.pages = Railsui::Pages.theme_pages.keys
82
- config.save
83
-
84
- Railsui.run_command "rails g railsui:update"
101
+ begin
102
+ config = load!
103
+ config.assign_attributes(params)
104
+ config.pages = Railsui::Pages.theme_pages.keys
105
+ config.save
106
+
107
+ Railsui.run_command "rails g railsui:update"
108
+ rescue => e
109
+ puts "❌ Failed to update configuration: #{e.message}"
110
+ raise
111
+ end
85
112
  end
86
113
 
87
114
  def self.synchronize_pages
@@ -115,8 +142,82 @@ module Railsui
115
142
  end
116
143
  end
117
144
 
145
+ # Validate build mode
146
+ def build_mode=(value)
147
+ valid_modes = ["build", "nobuild", :build, :nobuild]
148
+ unless valid_modes.include?(value)
149
+ raise ArgumentError, "❌ Invalid build_mode: '#{value}'. Must be 'build' or 'nobuild'"
150
+ end
151
+ @build_mode = value.to_s
152
+ end
153
+
154
+ # Validate entire configuration
155
+ def validate_configuration!
156
+ errors = []
157
+
158
+ errors << "Application name cannot be blank" if application_name.blank?
159
+ errors << "Support email cannot be blank" if support_email.blank?
160
+ errors << "Theme cannot be blank" if theme.blank?
161
+
162
+ # Validate theme exists (check against available themes)
163
+ available_themes = ["hound", "shepherd", "corgie"]
164
+ unless available_themes.include?(theme)
165
+ errors << "Invalid theme: '#{theme}'. Available themes: #{available_themes.join(', ')}"
166
+ end
167
+
168
+ # Validate build mode
169
+ unless ["build", "nobuild"].include?(build_mode.to_s)
170
+ errors << "Invalid build_mode: '#{build_mode}'. Must be 'build' or 'nobuild'"
171
+ end
172
+
173
+ # Validate email format
174
+ unless support_email =~ URI::MailTo::EMAIL_REGEXP
175
+ errors << "Invalid email format for support_email: '#{support_email}'"
176
+ end
177
+
178
+ if errors.any?
179
+ raise ArgumentError, "❌ Configuration validation failed:\n - #{errors.join("\n - ")}"
180
+ end
181
+ end
182
+
183
+ # Check if build mode is nobuild
184
+ def nobuild?
185
+ build_mode.to_s == "nobuild"
186
+ end
187
+
188
+ # Check if build mode is build
189
+ def build?
190
+ build_mode.to_s == "build"
191
+ end
192
+
118
193
  private
119
194
 
195
+ def detect_build_mode
196
+ return "build" unless defined?(Rails) && Rails.root
197
+
198
+ # Check for importmap.rb existence
199
+ if File.exist?(Rails.root.join("config", "importmap.rb"))
200
+ "nobuild"
201
+ else
202
+ "build"
203
+ end
204
+ rescue
205
+ # Fallback to build mode if detection fails
206
+ "build"
207
+ end
208
+
209
+ def should_build_css?
210
+ # Always try to build CSS if tailwindcss-rails is available
211
+ return true if defined?(Tailwindcss)
212
+
213
+ # Fallback to checking for package.json in build mode
214
+ return false unless defined?(Rails) && Rails.root
215
+
216
+ build? && File.exist?(Rails.root.join("package.json"))
217
+ rescue
218
+ false
219
+ end
220
+
120
221
  def copy_template(filename)
121
222
  return if File.exist?(Rails.root.join(filename))
122
223
 
@@ -26,9 +26,24 @@ module Railsui
26
26
  end
27
27
 
28
28
  initializer "railsui.assets.precompile" do |app|
29
+ # Add engine builds path
29
30
  app.config.assets.paths << root.join("builds").to_s
31
+
32
+ # Add engine JavaScript path for propshaft to serve
33
+ app.config.assets.paths << root.join("app/javascript").to_s
34
+
35
+ # Precompile Rails UI assets
30
36
  app.config.assets.precompile << "railsui/application.css"
31
37
  app.config.assets.precompile << %w[*.svg]
38
+
39
+ # Support for both importmap and JS bundling modes
40
+ # Importmap: JavaScript loaded via importmap pins (no precompilation needed)
41
+ # Build mode: JavaScript bundled via jsbundling-rails (handled by bundler)
42
+
43
+ # Ensure propshaft compatibility (Rails 7+)
44
+ if defined?(Propshaft)
45
+ app.config.assets.excluded_paths << Rails.root.join("node_modules")
46
+ end
32
47
  end
33
48
  end
34
49
  end