Skip to content

Commit 48bc8af

Browse files
authored
Add manual component installation instructions (#142)
1 parent 3a068ff commit 48bc8af

File tree

4 files changed

+270
-32
lines changed

4 files changed

+270
-32
lines changed

app/components/component_setup/cli_steps.rb

+8-31
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,16 @@ def initialize(component_name:)
1212
def view_template
1313
div(class: "max-w-2xl mx-auto w-full py-10 space-y-6") do
1414
Heading(level: 4, class: "pb-4 border-b") { "Using RubyUI CLI" }
15-
Text do
16-
"We provide a Ruby gem with useful generators to help you to setup RubyUI components in your apps."
17-
end
18-
19-
render Steps::Builder.new do |steps|
20-
steps.add_step do
21-
render Steps::Container do
22-
Text(size: "4", weight: "semibold") do
23-
plain "Add RubyUI gem to your Gemfile if you don't have it yet"
24-
end
2515

26-
code = <<~CODE
27-
bundle add ruby_ui --group development --require false
28-
CODE
29-
div(class: "w-full") do
30-
Codeblock(code, syntax: :javascript)
31-
end
32-
end
33-
end
34-
steps.add_step do
35-
render Steps::Container do
36-
Text(size: "4", weight: "semibold") do
37-
"Run the install command"
38-
end
16+
Text(size: "4", weight: "semibold") do
17+
"Run the install command"
18+
end
3919

40-
code = <<~CODE
41-
rails g ruby_ui:component #{component_name.camelcase}
42-
CODE
43-
div(class: "w-full") do
44-
Codeblock(code, syntax: :javascript)
45-
end
46-
end
47-
end
20+
code = <<~CODE
21+
rails g ruby_ui:component #{component_name.camelcase}
22+
CODE
23+
div(class: "w-full") do
24+
Codeblock(code, syntax: :javascript)
4825
end
4926
end
5027
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
module Components
2+
module ComponentSetup
3+
class ManualSteps < Components::Base
4+
def initialize(component_name:)
5+
@component_name = component_name
6+
@dependencies = RubyUI::FileManager.dependencies(@component_name)
7+
end
8+
9+
private
10+
11+
attr_reader :component_name, :dependencies
12+
13+
def view_template
14+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-6") do
15+
Heading(level: 4, class: "pb-4 border-b") { "Manual installation" }
16+
17+
render Steps::Builder.new do |steps|
18+
main_component_step(steps)
19+
related_component_steps(steps)
20+
stimulus_controller_steps(steps)
21+
js_dependencies_steps(steps)
22+
ruby_dependencies_steps(steps)
23+
component_dependencies_steps(steps)
24+
end
25+
end
26+
end
27+
28+
def main_component_step(steps)
29+
main_component_code = RubyUI::FileManager.main_component_code(component_name)
30+
31+
return if main_component_code.blank?
32+
33+
steps.add_step do
34+
render Steps::Container do
35+
Text(size: "4", weight: "semibold") do
36+
plain "Add "
37+
InlineCode(class: "whitespace-nowrap") { "RubyUI::#{component_name.camelcase}" }
38+
plain " to "
39+
InlineCode(class: "whitespace-nowrap") { "app/components/ruby_ui/#{component_name.underscore}.rb" }
40+
end
41+
42+
div(class: "w-full") do
43+
Codeblock(main_component_code, syntax: :ruby)
44+
end
45+
end
46+
end
47+
end
48+
49+
def related_component_steps(steps)
50+
related_component_file_paths = RubyUI::FileManager.related_component_file_paths(component_name)
51+
52+
return if related_component_file_paths.empty?
53+
54+
related_component_file_paths.each do |component_path|
55+
related_component_class = component_path.split("/").last.delete_suffix(".rb").camelcase
56+
related_component_file_name = component_path.split("/").last
57+
related_component_code = RubyUI::FileManager.component_code(component_path)
58+
steps.add_step do
59+
render Steps::Container do
60+
Text(size: "4", weight: "semibold") do
61+
plain "Add "
62+
InlineCode(class: "whitespace-nowrap") { "RubyUI::#{related_component_class}" }
63+
plain " to "
64+
InlineCode(class: "whitespace-nowrap") { "app/components/ruby_ui/#{component_name.underscore}/#{related_component_file_name}" }
65+
end
66+
67+
div(class: "w-full") do
68+
Codeblock(related_component_code, syntax: :ruby)
69+
end
70+
end
71+
end
72+
end
73+
end
74+
75+
def stimulus_controller_steps(steps)
76+
stimulus_controller_file_paths = RubyUI::FileManager.stimulus_controller_file_paths(component_name)
77+
78+
return if stimulus_controller_file_paths.empty?
79+
80+
stimulus_controller_file_paths.each do |controller_path|
81+
controller_file_name = controller_path.split("/").last
82+
controller_code = RubyUI::FileManager.component_code(controller_path)
83+
steps.add_step do
84+
render Steps::Container do
85+
Text(size: "4", weight: "semibold") do
86+
plain "Add "
87+
InlineCode(class: "whitespace-nowrap") { controller_file_name }
88+
plain " to "
89+
InlineCode(class: "whitespace-nowrap") { "app/javascript/controllers/ruby_ui/#{controller_file_name}" }
90+
end
91+
92+
div(class: "w-full") do
93+
Codeblock(controller_code, syntax: :javascript)
94+
end
95+
end
96+
end
97+
end
98+
99+
steps.add_step do
100+
render Steps::Container do
101+
Text(size: "4", weight: "semibold") do
102+
plain "Update the Stimulus controllers manifest file"
103+
end
104+
105+
Alert(variant: :destructive) do
106+
AlertTitle { "Importmap!" }
107+
AlertDescription { "You don't need to run this command if you are using Importmap" }
108+
end
109+
110+
div(class: "w-full") do
111+
Codeblock("rake stimulus:manifest:update", syntax: :javascript)
112+
end
113+
end
114+
end
115+
end
116+
117+
def js_dependencies_steps(steps)
118+
return unless dependencies["js_packages"].present?
119+
120+
dependencies["js_packages"].each do |js_package|
121+
steps.add_step do
122+
code = <<~CODE
123+
// with yarn
124+
yarn add #{js_package}
125+
// with npm
126+
npm install #{js_package}
127+
// with importmaps
128+
#{pin_importmap_instructions(js_package)}
129+
CODE
130+
131+
render Steps::Container do
132+
Text(size: "4", weight: "semibold") do
133+
plain "Install "
134+
InlineCode(class: "whitespace-nowrap") { js_package }
135+
plain " Javascript dependency"
136+
end
137+
138+
div(class: "w-full") do
139+
Codeblock(code, syntax: :javascript)
140+
end
141+
end
142+
end
143+
end
144+
end
145+
146+
def ruby_dependencies_steps(steps)
147+
return unless dependencies["gems"].present?
148+
149+
dependencies["gems"].each do |gem|
150+
steps.add_step do
151+
code = <<~CODE
152+
bundle add #{gem}
153+
CODE
154+
155+
render Steps::Container do
156+
Text(size: "4", weight: "semibold") do
157+
plain "Install "
158+
InlineCode(class: "whitespace-nowrap") { gem }
159+
plain " Ruby gem"
160+
end
161+
162+
div(class: "w-full") do
163+
Codeblock(code, syntax: :javascript)
164+
end
165+
end
166+
end
167+
end
168+
end
169+
170+
def component_dependencies_steps(steps)
171+
return unless dependencies["components"].present?
172+
173+
steps.add_step do
174+
render Steps::Container do
175+
Text(size: "4", weight: "semibold") do
176+
plain "Install required components"
177+
end
178+
179+
Text do
180+
plain "Component "
181+
InlineCode(class: "whitespace-nowrap") { component_name.camelcase }
182+
plain " relies on the following RubyUI components. Refer to their individual installation guides for setup instructions:"
183+
end
184+
185+
TypographyList do
186+
dependencies["components"].each do |component|
187+
TypographyListItem do
188+
Link(size: :lg, target: "_blank", href: public_send(:"docs_#{component.underscore}_path")) do
189+
span(class: "font-bold") { component.camelcase }
190+
span { " - Installation guide" }
191+
end
192+
end
193+
end
194+
end
195+
end
196+
end
197+
end
198+
199+
# Temporary solution while we don't remove
200+
# motion adn tippy.js dependencies
201+
def pin_importmap_instructions(js_package)
202+
case js_package
203+
when "motion"
204+
<<~CODE
205+
// Add to your config/importmap.rb
206+
pin "motion", to: "https://cdn.jsdelivr.net/npm/[email protected]/+esm"
207+
CODE
208+
when "tippy.js"
209+
<<~CODE
210+
// Add to your config/importmap.rb
211+
pin "tippy.js", to: "https://cdn.jsdelivr.net/npm/[email protected]/+esm"
212+
pin "@popperjs/core", to: "https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/+esm"\n
213+
CODE
214+
else
215+
"bin/importmap pin #{js_package}"
216+
end
217+
end
218+
end
219+
end
220+
end

app/components/component_setup/tabs.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def view_template
2323
end
2424

2525
TabsContent(value: "manual") do
26-
Text { "Coming soon" }
26+
render ManualSteps.new(component_name:)
2727
end
2828
end
2929
end

app/lib/ruby_ui/file_manager.rb

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
module RubyUI
2+
module FileManager
3+
extend self
4+
5+
def main_component_code(component_name)
6+
component_code main_component_file_path(component_name)
7+
end
8+
9+
def component_code(file_path)
10+
File.read(file_path) if File.exist?(file_path)
11+
end
12+
13+
def main_component_file_path(component_name)
14+
component_name = component_name.underscore
15+
File.join(component_folder(component_name), "#{component_name}.rb")
16+
end
17+
18+
def related_component_file_paths(component_name)
19+
Dir[File.join(component_folder(component_name), "*.rb")] - [main_component_file_path(component_name)]
20+
end
21+
22+
def stimulus_controller_file_paths(component_name)
23+
Dir[File.join(component_folder(component_name), "*.js")]
24+
end
25+
26+
def component_folder(component_name)
27+
component_name = component_name.underscore
28+
File.join(gem_path, "lib", "ruby_ui", component_name)
29+
end
30+
31+
def dependencies(component_name)
32+
DEPENDENCIES[component_name.underscore].to_h
33+
end
34+
35+
def gem_path
36+
@gem_path ||= Gem::Specification.find_by_name("ruby_ui").gem_dir
37+
end
38+
39+
DEPENDENCIES = YAML.load_file(File.join(gem_path, "lib/generators/ruby_ui/dependencies.yml")).freeze
40+
end
41+
end

0 commit comments

Comments
 (0)