Your Teacher
Adam McCrea
Hey, I'm Adam! I spend my days coding and writing for Judoscale—the autoscaling service I created in 2016. I'm @adamlogic pretty much everywhere online.
About This Episode
Adam McCrea walks through using Phlex to build components for views in your Rails applications. Phlex is a Ruby gem for building fast object-oriented HTML and SVG components using Ruby constructs: methods, keyword arguments and blocks.
Notes
Resources
class AdapterSetupComponent < ApplicationComponent
def initialize(app, process_type)
@app = app
@process_type = process_type
end
def template
render ModalComponent.new do |modal|
modal.parts do
modal.header "Adapter Installation",
previous_href:
url_for([:new, @app, @process_type, :adapter_setup])
modal.content do
div(class: "p-8 prose max-w-none") do
render "adapter_setups/languages/#{@app.language.downcase}"
end
end
modal.footer do
form_with model: @app,
url: [@app, @process_type, :adapter_setup],
method: :get,
builder: StyledFormBuilder do |form|
plain helpers.styled_button "Finished and Deployed",
background: :gray,
icon: "circlecheckmark"
end
end
end
end
end
end
class ApplicationComponent < Phlex::HTML
include Phlex::Rails::Helpers::Routes
include Phlex::Rails::Helpers::ContentFor
include Phlex::Rails::Helpers::LinkTo
include Phlex::Rails::Helpers::FormWith
if Rails.env.development?
def before_template
comment { "Before #{self.class.name}" }
super
end
end
end
class ModalComponent < ApplicationComponent
def template(dismissable: true, &block)
content_for(:modal_content) do
render "modals/modal_wrapper", dismissable: dismissable, &block
end
end
def parts(hug: false, &block)
# This wrappers assumes three child nodes (header, content, footer).
div class: "grid grid-rows-[auto_1fr_auto] #{"min-h-[36rem]" unless hug}", &block
end
def header(title, dismissable: true, previous_href: nil)
div(class: %(relative px-4 bg-gray-100 h-16 flex justify-center items-center)) {
if previous_href
link_to previous_href, class: "absolute left-4 text-gray-400 h-8 w-8" do
plain helpers.svg(:chevronleft)
div(class: %(sr-only)) {
%(Back)
}
end
end
if dismissable
button(type: %(button), class: %(absolute right-4 text-gray-400 h-8 w-8), "click.prevent": %(modalVisible = false)) {
plain helpers.svg(:close)
}
end
h2(class: %(text-gray-600 font-medium)) {
title
}
}
end
def content(&block)
div class: "max-h-[70vh] overflow-auto", &block
end
def footer(&block)
div class: "relative p-4 bg-gray-100 flex justify-end items-center gap-4", &block
end
end