quicksilver_ui 0.1.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 +7 -0
- data/app/assets/tailwind/alert.css +35 -0
- data/app/assets/tailwind/badge.css +27 -0
- data/app/assets/tailwind/button.css +35 -0
- data/app/assets/tailwind/form.css +35 -0
- data/app/assets/tailwind/link.css +23 -0
- data/app/assets/tailwind/modal.css +43 -0
- data/app/assets/tailwind/quicksilver_ui/engine.css +7 -0
- data/app/assets/tailwind/typography.css +112 -0
- data/app/helpers/app_form_builder.rb +94 -0
- data/app/helpers/app_form_helper.rb +7 -0
- data/app/javascript/controllers/autogrow_controller.js +19 -0
- data/app/javascript/controllers/dismissable_controller.js +35 -0
- data/app/javascript/controllers/dropdown_controller.js +59 -0
- data/app/javascript/controllers/modal_controller.js +45 -0
- data/app/javascript/controllers/tabs_controller.js +62 -0
- data/app/javascript/mixins/use_floating_ui.js +104 -0
- data/app/views/form/base_tag.rb +42 -0
- data/app/views/form/checkbox.rb +62 -0
- data/app/views/form/date_field.rb +11 -0
- data/app/views/form/email_field.rb +7 -0
- data/app/views/form/error.rb +15 -0
- data/app/views/form/file_field.rb +12 -0
- data/app/views/form/group.rb +97 -0
- data/app/views/form/hint.rb +15 -0
- data/app/views/form/input.rb +11 -0
- data/app/views/form/label.rb +19 -0
- data/app/views/form/password_field.rb +7 -0
- data/app/views/form/phone_field.rb +7 -0
- data/app/views/form/radio_button.rb +37 -0
- data/app/views/form/search_field.rb +7 -0
- data/app/views/form/select.rb +46 -0
- data/app/views/form/text_field.rb +7 -0
- data/app/views/form/textarea.rb +27 -0
- data/app/views/form/toggle.rb +35 -0
- data/app/views/ui/accordion.rb +67 -0
- data/app/views/ui/alert.rb +84 -0
- data/app/views/ui/avatar.rb +57 -0
- data/app/views/ui/badge.rb +35 -0
- data/app/views/ui/base.rb +29 -0
- data/app/views/ui/dropdown/item.rb +49 -0
- data/app/views/ui/dropdown.rb +111 -0
- data/app/views/ui/icon.rb +46 -0
- data/app/views/ui/modal.rb +96 -0
- data/app/views/ui/toast.rb +90 -0
- data/lib/generators/quicksilver_ui/affordance/affordance_generator.rb +102 -0
- data/lib/generators/quicksilver_ui/component/all_generator.rb +32 -0
- data/lib/generators/quicksilver_ui/component/component_generator.rb +194 -0
- data/lib/generators/quicksilver_ui/form/all_generator.rb +32 -0
- data/lib/generators/quicksilver_ui/form/form_generator.rb +164 -0
- data/lib/generators/quicksilver_ui/form/templates/app_form_builder.rb +39 -0
- data/lib/generators/quicksilver_ui/form/templates/app_form_helper.rb +7 -0
- data/lib/generators/quicksilver_ui/install/install_generator.rb +42 -0
- data/lib/generators/quicksilver_ui/install/templates/base.rb +29 -0
- data/lib/generators/quicksilver_ui/install/templates/initializer.rb +16 -0
- data/lib/quicksilver_ui/dependencies.rb +191 -0
- data/lib/quicksilver_ui/engine.rb +18 -0
- data/lib/quicksilver_ui/version.rb +5 -0
- data/lib/quicksilver_ui.rb +37 -0
- metadata +98 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module QuicksilverUI
|
|
6
|
+
module Generators
|
|
7
|
+
module Component
|
|
8
|
+
class AllGenerator < Rails::Generators::Base
|
|
9
|
+
namespace "quicksilver_ui:component:all"
|
|
10
|
+
|
|
11
|
+
class_option :force, type: :boolean, default: false
|
|
12
|
+
|
|
13
|
+
def generate_all_components
|
|
14
|
+
say "Generating all components..."
|
|
15
|
+
|
|
16
|
+
available_components.each do |component|
|
|
17
|
+
run "bin/rails generate quicksilver_ui:component #{component}#{" --force" if options["force"]}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def available_components
|
|
24
|
+
Dir.glob(File.join(QuicksilverUI.ui_path, "*.rb"))
|
|
25
|
+
.map { |f| File.basename(f, ".rb") }
|
|
26
|
+
.reject { |name| name == "base" }
|
|
27
|
+
.sort
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module QuicksilverUI
|
|
6
|
+
module Generators
|
|
7
|
+
class ComponentGenerator < Rails::Generators::Base
|
|
8
|
+
namespace "quicksilver_ui:component"
|
|
9
|
+
|
|
10
|
+
source_root QuicksilverUI.ui_path.to_s
|
|
11
|
+
|
|
12
|
+
def self.banner
|
|
13
|
+
"rails generate quicksilver_ui:component NAME [options]"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc <<~DESC
|
|
17
|
+
Generate a QuicksilverUI component into your application.
|
|
18
|
+
|
|
19
|
+
Available components:
|
|
20
|
+
DESC
|
|
21
|
+
|
|
22
|
+
def self.desc(description = nil)
|
|
23
|
+
return super if description
|
|
24
|
+
|
|
25
|
+
components = Dir.glob(File.join(QuicksilverUI.ui_path, "*.rb"))
|
|
26
|
+
.map { |f| File.basename(f, ".rb") }
|
|
27
|
+
.reject { |n| n == "base" }
|
|
28
|
+
.sort
|
|
29
|
+
.map { |c| " #{c}" }
|
|
30
|
+
.join("\n")
|
|
31
|
+
|
|
32
|
+
"#{super}\n#{components}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
argument :component_name, type: :string, required: true
|
|
36
|
+
class_option :force, type: :boolean, default: false
|
|
37
|
+
|
|
38
|
+
def generate_component
|
|
39
|
+
if component_not_found?
|
|
40
|
+
say "Component not found: #{component_name}", :red
|
|
41
|
+
say ""
|
|
42
|
+
say "Available components:", :green
|
|
43
|
+
available_components.each { |c| say " - #{c}" }
|
|
44
|
+
exit 1
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
say "Generating #{component_name} component..."
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def add_gems
|
|
51
|
+
all_gems.each do |gem_name|
|
|
52
|
+
unless gem_installed?(gem_name)
|
|
53
|
+
say "Adding #{gem_name} to Gemfile...", :yellow
|
|
54
|
+
run "bundle add #{gem_name}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def copy_component_files
|
|
60
|
+
all_components.each do |name|
|
|
61
|
+
paths = file_paths_for(name)
|
|
62
|
+
paths.each do |file_path|
|
|
63
|
+
relative = Pathname.new(file_path).relative_path_from(self.class.source_root)
|
|
64
|
+
copy_file file_path, Rails.root.join("app/views/ui", relative), force: options["force"]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def copy_stylesheets
|
|
70
|
+
all_stylesheets.each do |name|
|
|
71
|
+
source = File.join(QuicksilverUI.stylesheets_path, "#{name}.css")
|
|
72
|
+
next unless File.exist?(source)
|
|
73
|
+
|
|
74
|
+
dest = Rails.root.join("app/assets/tailwind", "#{name}.css")
|
|
75
|
+
copy_file source, dest, force: options["force"]
|
|
76
|
+
add_css_import(name)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def copy_controllers
|
|
81
|
+
all_controllers.each do |name|
|
|
82
|
+
source = File.join(QuicksilverUI.javascript_controllers_path, "#{name}_controller.js")
|
|
83
|
+
next unless File.exist?(source)
|
|
84
|
+
|
|
85
|
+
copy_file source, Rails.root.join("app/javascript/controllers", "#{name}_controller.js"), force: options["force"]
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def copy_mixins
|
|
90
|
+
all_mixins.each do |name|
|
|
91
|
+
source = File.join(QuicksilverUI.javascript_mixins_path, "#{name}.js")
|
|
92
|
+
next unless File.exist?(source)
|
|
93
|
+
|
|
94
|
+
copy_file source, Rails.root.join("app/javascript/mixins", "#{name}.js"), force: options["force"]
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def done
|
|
99
|
+
say ""
|
|
100
|
+
say "#{component_name} component generated!", :green
|
|
101
|
+
|
|
102
|
+
deps = all_components - [component_folder_name]
|
|
103
|
+
if deps.any?
|
|
104
|
+
say " Dependencies copied: #{deps.join(", ")}", :cyan
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def all_components
|
|
111
|
+
@all_components ||= QuicksilverUI.resolve_dependencies(component_folder_name)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def all_stylesheets
|
|
115
|
+
all_components.flat_map { |name| QuicksilverUI::DEPENDENCIES.dig(name, :stylesheets) || [] }.uniq
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def all_controllers
|
|
119
|
+
all_components.flat_map { |name| QuicksilverUI::DEPENDENCIES.dig(name, :controllers) || [] }.uniq
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def all_mixins
|
|
123
|
+
all_components.flat_map { |name| QuicksilverUI::DEPENDENCIES.dig(name, :mixins) || [] }.uniq
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def all_gems
|
|
127
|
+
all_components.flat_map { |name| QuicksilverUI::DEPENDENCIES.dig(name, :gems) || [] }.uniq
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def gem_installed?(name)
|
|
131
|
+
Gem::Specification.find_all_by_name(name).any?
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def add_css_import(name)
|
|
135
|
+
app_css = Rails.root.join("app/assets/tailwind/application.css")
|
|
136
|
+
import_line = "@import \"./#{name}.css\" layer(affordances);"
|
|
137
|
+
|
|
138
|
+
if File.exist?(app_css)
|
|
139
|
+
content = File.read(app_css)
|
|
140
|
+
return if content.include?(import_line)
|
|
141
|
+
|
|
142
|
+
# Insert after the last existing @import line
|
|
143
|
+
lines = content.lines
|
|
144
|
+
last_import_index = lines.rindex { |l| l.start_with?("@import") }
|
|
145
|
+
|
|
146
|
+
if last_import_index
|
|
147
|
+
lines.insert(last_import_index + 1, "#{import_line}\n")
|
|
148
|
+
else
|
|
149
|
+
lines.unshift("#{import_line}\n")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
File.write(app_css, lines.join)
|
|
153
|
+
else
|
|
154
|
+
create_file app_css, "#{import_line}\n"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
say " Added import for #{name}.css to application.css", :green
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def component_not_found?
|
|
161
|
+
!File.exist?(component_file_path) && !Dir.exist?(component_folder_path)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def component_folder_name
|
|
165
|
+
component_name.underscore
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def component_file_path
|
|
169
|
+
File.join(self.class.source_root, "#{component_folder_name}.rb")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def component_folder_path
|
|
173
|
+
File.join(self.class.source_root, component_folder_name)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def file_paths_for(name)
|
|
177
|
+
paths = []
|
|
178
|
+
file = File.join(self.class.source_root, "#{name}.rb")
|
|
179
|
+
folder = File.join(self.class.source_root, name)
|
|
180
|
+
|
|
181
|
+
paths << file if File.exist?(file)
|
|
182
|
+
paths.concat Dir.glob(File.join(folder, "**/*.rb")) if Dir.exist?(folder)
|
|
183
|
+
paths
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def available_components
|
|
187
|
+
Dir.glob(File.join(self.class.source_root, "*.rb"))
|
|
188
|
+
.map { |f| File.basename(f, ".rb") }
|
|
189
|
+
.reject { |name| name == "base" }
|
|
190
|
+
.sort
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module QuicksilverUI
|
|
6
|
+
module Generators
|
|
7
|
+
module Form
|
|
8
|
+
class AllGenerator < Rails::Generators::Base
|
|
9
|
+
namespace "quicksilver_ui:form:all"
|
|
10
|
+
|
|
11
|
+
class_option :force, type: :boolean, default: false
|
|
12
|
+
|
|
13
|
+
def generate_all_form_components
|
|
14
|
+
say "Generating all form components..."
|
|
15
|
+
|
|
16
|
+
available_form_components.each do |component|
|
|
17
|
+
run "bin/rails generate quicksilver_ui:form #{component}#{" --force" if options["force"]}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def available_form_components
|
|
24
|
+
Dir.glob(File.join(QuicksilverUI.form_path, "*.rb"))
|
|
25
|
+
.map { |f| File.basename(f, ".rb") }
|
|
26
|
+
.reject { |name| name == "base_tag" }
|
|
27
|
+
.sort
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module QuicksilverUI
|
|
6
|
+
module Generators
|
|
7
|
+
class FormGenerator < Rails::Generators::Base
|
|
8
|
+
namespace "quicksilver_ui:form"
|
|
9
|
+
|
|
10
|
+
source_root QuicksilverUI.form_path.to_s
|
|
11
|
+
|
|
12
|
+
def self.banner
|
|
13
|
+
"rails generate quicksilver_ui:form NAME [options]"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc <<~DESC
|
|
17
|
+
Generate a QuicksilverUI form component into your application.
|
|
18
|
+
|
|
19
|
+
Available form components:
|
|
20
|
+
DESC
|
|
21
|
+
|
|
22
|
+
def self.desc(description = nil)
|
|
23
|
+
return super if description
|
|
24
|
+
|
|
25
|
+
components = Dir.glob(File.join(QuicksilverUI.form_path, "*.rb"))
|
|
26
|
+
.map { |f| File.basename(f, ".rb") }
|
|
27
|
+
.reject { |n| n == "base_tag" }
|
|
28
|
+
.sort
|
|
29
|
+
.map { |c| " #{c}" }
|
|
30
|
+
.join("\n")
|
|
31
|
+
|
|
32
|
+
"#{super}\n#{components}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
argument :form_component_name, type: :string, required: true
|
|
36
|
+
class_option :force, type: :boolean, default: false
|
|
37
|
+
|
|
38
|
+
def generate_form_component
|
|
39
|
+
if form_component_not_found?
|
|
40
|
+
say "Form component not found: #{form_component_name}", :red
|
|
41
|
+
say ""
|
|
42
|
+
say "Available form components:", :green
|
|
43
|
+
available_form_components.each { |c| say " - #{c}" }
|
|
44
|
+
exit 1
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
say "Generating #{form_component_name} form component..."
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def add_gems
|
|
51
|
+
all_gems.each do |gem_name|
|
|
52
|
+
unless gem_installed?(gem_name)
|
|
53
|
+
say "Adding #{gem_name} to Gemfile...", :yellow
|
|
54
|
+
run "bundle add #{gem_name}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def copy_form_component_files
|
|
60
|
+
all_form_components.each do |name|
|
|
61
|
+
source = File.join(self.class.source_root, "#{name}.rb")
|
|
62
|
+
next unless File.exist?(source)
|
|
63
|
+
|
|
64
|
+
copy_file source, Rails.root.join("app/views/form", "#{name}.rb"), force: options["force"]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def copy_stylesheets
|
|
69
|
+
all_stylesheets.each do |name|
|
|
70
|
+
source = File.join(QuicksilverUI.stylesheets_path, "#{name}.css")
|
|
71
|
+
next unless File.exist?(source)
|
|
72
|
+
|
|
73
|
+
dest = Rails.root.join("app/assets/tailwind", "#{name}.css")
|
|
74
|
+
copy_file source, dest, force: options["force"]
|
|
75
|
+
add_css_import(name)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def copy_form_builder
|
|
80
|
+
source = File.join(templates_path, "app_form_builder.rb")
|
|
81
|
+
dest = Rails.root.join("app/helpers/app_form_builder.rb")
|
|
82
|
+
copy_file source, dest, force: options["force"]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def copy_form_helper
|
|
86
|
+
source = File.join(templates_path, "app_form_helper.rb")
|
|
87
|
+
dest = Rails.root.join("app/helpers/app_form_helper.rb")
|
|
88
|
+
copy_file source, dest, force: options["force"]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def done
|
|
92
|
+
say ""
|
|
93
|
+
say "#{form_component_name} form component generated!", :green
|
|
94
|
+
|
|
95
|
+
deps = all_form_components - [file_name]
|
|
96
|
+
if deps.any?
|
|
97
|
+
say " Dependencies copied: #{deps.join(", ")}", :cyan
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
def all_form_components
|
|
104
|
+
@all_form_components ||= QuicksilverUI.resolve_form_dependencies(file_name)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def all_stylesheets
|
|
108
|
+
all_form_components.flat_map { |name| QuicksilverUI::FORM_DEPENDENCIES.dig(name, :stylesheets) || [] }.uniq
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def all_gems
|
|
112
|
+
all_form_components.flat_map { |name| QuicksilverUI::FORM_DEPENDENCIES.dig(name, :gems) || [] }.uniq
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def gem_installed?(name)
|
|
116
|
+
Gem::Specification.find_all_by_name(name).any?
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def add_css_import(name)
|
|
120
|
+
app_css = Rails.root.join("app/assets/tailwind/application.css")
|
|
121
|
+
import_line = "@import \"./#{name}.css\" layer(affordances);"
|
|
122
|
+
|
|
123
|
+
if File.exist?(app_css)
|
|
124
|
+
content = File.read(app_css)
|
|
125
|
+
return if content.include?(import_line)
|
|
126
|
+
|
|
127
|
+
lines = content.lines
|
|
128
|
+
last_import_index = lines.rindex { |l| l.start_with?("@import") }
|
|
129
|
+
|
|
130
|
+
if last_import_index
|
|
131
|
+
lines.insert(last_import_index + 1, "#{import_line}\n")
|
|
132
|
+
else
|
|
133
|
+
lines.unshift("#{import_line}\n")
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
File.write(app_css, lines.join)
|
|
137
|
+
else
|
|
138
|
+
create_file app_css, "#{import_line}\n"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
say " Added import for #{name}.css to application.css", :green
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def form_component_not_found?
|
|
145
|
+
!File.exist?(File.join(self.class.source_root, "#{file_name}.rb"))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def templates_path
|
|
149
|
+
File.join(File.dirname(__FILE__), "templates")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def file_name
|
|
153
|
+
form_component_name.underscore
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def available_form_components
|
|
157
|
+
Dir.glob(File.join(self.class.source_root, "*.rb"))
|
|
158
|
+
.map { |f| File.basename(f, ".rb") }
|
|
159
|
+
.reject { |name| name == "base_tag" }
|
|
160
|
+
.sort
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
class AppFormBuilder < ActionView::Helpers::FormBuilder
|
|
2
|
+
delegate :render, to: :@template
|
|
3
|
+
|
|
4
|
+
def self.with_blank_error_proc(&block)
|
|
5
|
+
old_error_proc = ActionView::Base.field_error_proc
|
|
6
|
+
begin
|
|
7
|
+
ActionView::Base.field_error_proc = proc do |tag, instance|
|
|
8
|
+
tag
|
|
9
|
+
end
|
|
10
|
+
block.call
|
|
11
|
+
ensure
|
|
12
|
+
ActionView::Base.field_error_proc = old_error_proc
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def group(method, options = {})
|
|
17
|
+
render Form::Group.new(form: self, method:, type: options[:type] || :text, **options.except(:type))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def text_field(method, options = {})
|
|
21
|
+
render Form::TextField.new(form: self, method:, **options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def label(method, text = nil, options = {}, &block)
|
|
25
|
+
render Form::Label.new(form: self, method:, text:, **options)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def hint(method, text = nil, options = {}, &block)
|
|
29
|
+
render Form::Hint.new(form: self, method:, text:, **options)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def error(method, text = nil, options = {}, &block)
|
|
33
|
+
render Form::Error.new(form: self, method:, text:, **options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def submit(value = nil, options = {})
|
|
37
|
+
super(value, options.with_defaults(class: "ui-button ui-button-primary"))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module QuicksilverUI
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
namespace "quicksilver_ui:install"
|
|
9
|
+
|
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
|
11
|
+
|
|
12
|
+
def add_gems
|
|
13
|
+
%w[phlex-rails literal tailwind_merge].each do |gem_name|
|
|
14
|
+
unless gem_installed?(gem_name)
|
|
15
|
+
say "Adding #{gem_name} to Gemfile...", :yellow
|
|
16
|
+
run "bundle add #{gem_name}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_initializer
|
|
22
|
+
template "initializer.rb", Rails.root.join("config/initializers/quicksilver_ui.rb")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def create_base_component
|
|
26
|
+
template "base.rb", Rails.root.join("app/views/ui/base.rb")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def done
|
|
30
|
+
say ""
|
|
31
|
+
say "Quicksilver UI installed successfully!", :green
|
|
32
|
+
say "Run `bin/rails g quicksilver_ui:component Alert` to generate a component.", :green
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def gem_installed?(name)
|
|
38
|
+
Gem::Specification.find_all_by_name(name).any?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class UI::Base < Phlex::HTML
|
|
4
|
+
TAILWIND_MERGER = ::TailwindMerge::Merger.new.freeze unless defined?(TAILWIND_MERGER)
|
|
5
|
+
|
|
6
|
+
extend Literal::Properties
|
|
7
|
+
include Phlex::Rails::Helpers::Routes
|
|
8
|
+
include Phlex::Rails::Helpers::ClassNames
|
|
9
|
+
include Phlex::Rails::Helpers::LinkTo
|
|
10
|
+
|
|
11
|
+
if Rails.env.development?
|
|
12
|
+
def before_template
|
|
13
|
+
comment { "Before #{self.class.name}" }
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
prop :class, _Nilable(String)
|
|
19
|
+
prop :data, Hash, default: {}.freeze, reader: :private
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def classes
|
|
24
|
+
TAILWIND_MERGER.merge [default_classes, @class].join(" ")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def default_classes
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UI
|
|
4
|
+
extend Phlex::Kit
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Look for Phlex components in the views folder
|
|
8
|
+
Rails.autoloaders.main.push_dir(
|
|
9
|
+
Rails.root.join("app/views")
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# Add a folder specifically for UI components, that are generalized and
|
|
13
|
+
# reusable, like modals and accordions.
|
|
14
|
+
Rails.autoloaders.main.push_dir(
|
|
15
|
+
Rails.root.join("app/views/ui"), namespace: UI
|
|
16
|
+
)
|