Not-so-ugly styles code in your Rails app
Serhii Jun
Posted on May 28, 2023
Let's say, u already normally human and didn't use tailwindcss for your Rails app. Well, I just want to show you how I uses a feature from ruby-3.2 introduced by @zverok. It names Data and I use it together with ViewComponent and Rux to have a little less ugly code.
Gemfile:
group :development, :test do
...
gem 'view_component', '~> 2.82'
gem 'rux-rails', '~> 1.2', '>= 1.2.2'
gem 'birdel', '~> 3.1'
end
- Generate new component by ViewComponent or by Birdel
$ birdel gcom Ui::Mix::BarComponent
# app/
# ├─ components/
# │ ├─ ui/
# │ │ ├─ mix/
# │ │ │ ├─ bar_component/
# │ │ │ │ ├─ bar_component.rb
# │ │ │ │ ├─ bar_component.js
# │ │ │ │ ├─ bar_component.css
# │ │ │ │ ├─ bar_component.html.erb
# │ │ │ │ ├─ bar_component_controller.js
# │ │ │ │ └─ bar_component_actor.js
remove your
bar_component.html.erb
fileWrite your styles into
bar_component.css
Rename
bar_component.rb
file tobar_component.rux
#app/components/ui/mix/bar_component/bar_component.rux
class Ui::Mix::BarComponent::BarComponent < ViewComponent::Base
Styles = Data.define(
:nav_bar,
:nav_item,
:btn,
:btn_active,
:nav_item__logo
)
attr_reader :styles
def initialize()
end
def styles
@styles ||= Styles.new(
nav_bar: 'nav-bar',
nav_item: 'nav-item',
btn: 'nav-item-btn',
btn_active: 'nav-item-btn--active',
nav_item__logo: 'nav-item-logo'
)
end
def call
<div class={css_class} data-controller={css_class}>
<div class={styles.nav_bar}>
<div class="#{styles.nav_item} #{styles.nav_item__logo}">
</div>
<div class={styles.nav_item}>
<div class={styles.btn} data-action="click->#{css_class}#handleLeftBtn">Left</div>
<div class="#{styles.btn} #{styles.btn_active}">Center</div>
<div class={styles.btn}>Right</div>
</div>
<div class={styles.nav_item}>
</div>
</div>
</div>
end
def css_class
@css_class ||= "ui--mix--blabla..."
end
end
Explanation:
In this part we define a custom Data class named Styles with fields, which will be used as the names of classes from our style file:
Styles = Data.define(
:nav_bar,
:nav_item,
:btn,
:btn_active,
:nav_item__logo
)
And here we just set a value for each field of our Styles data object:
def styles
@styles ||= Styles.new(
nav_bar: 'nav-bar',
nav_item: 'nav-item',
btn: 'nav-item-btn',
btn_active: 'nav-item-btn--active',
nav_item__logo: 'nav-item-logo'
)
end
Great now we can use that @styles
object inside #call
method which allows us to write the same to JSX-styled syntax code. Like:
<div class={styles.nav_item}>
Example rendered HTML:
<div class="nav-bar">
<div class="nav-item nav-item-logo">
</div>
<div class="nav-item">
<div class="nav-item-btn" data_action="click->ui--mix--bar-component#handleLeftBtn">
Left
</div>
<div class="nav-item-btn nav-item-btn--active">
Center
</div>
<div class="nav-item-btn">
Right
</div>
</div>
<div class="nav-item">
</div>
</div>
Btw, Birdel (https://github.com/serhiijun/birdel) is my microframework which is not ready yet and you can help me by contributing. It's revolutionized tool for rails assets management and WebSocket components rendering which will replace sucks rails-turbo.
Posted on May 28, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.