Components
Lato provides a set of reusable functional components.
By using Lato components, you can save development time and simplify maintenance tasks.
All components are available via the Lato::ComponentsHelper
helper.
Source code: Lato::ComponentsHelper
Navbar
Navbar nav item
Component to render a menu item in the navbar.
Parameters:
- key: the menu item's key. Used to activate the item via the active_navbar
function from the Lato::Layoutable
concern.
- path: a path or absolute URL to redirect the user.
- &block: block of HTML to render inside the menu item.
<%= lato_navbar_nav_item :account, lato.account_path do %> Account <% end %>
Sidebar
Sidebar nav item
Component to render a menu item in the sidebar.
Parameters:
- key: the menu item's key. Used to activate the item via the active_sidebar
function from the Lato::Layoutable
concern.
- path: a path or absolute URL to redirect the user.
- &block: block of HTML to render inside the menu item.
<%= lato_sidebar_nav_item :account, lato.account_path do %> Account <% end %>
Page
Page head
<%= lato_page_head 'Page title' %>
Page title
<%= lato_page_head 'Page title', [{ label: 'Title 1', path: main_app.page_path }, { label: 'Title 2' }] %>
Page title
<%= lato_page_head 'Page title' do %> <p class="lead">Welcome to this page</p> <% end %>
Page title
Welcome to this page
Form
Forms can be generated using the lato_form
components.
lato_form
components are a set of utilities designed to work with Rails' form_with
helper and the Stimulus controller lato_form_controller
.
Below is a list of available components with usage examples:
-
lato_form_notices
displays success feedback (notices set by the controller action). -
lato_form_errors
displays error feedback (based on model instance errors). -
lato_form_item_label
renders the field label. -
lato_form_item_input_text
renders a text input. -
lato_form_item_input_number
renders a number input. -
lato_form_item_input_email
renders an email input. -
lato_form_item_input_password
renders a password input. -
lato_form_item_input_check
renders a checkbox input. -
lato_form_item_input_select
renders a select input. -
lato_form_item_input_file
renders a file input. -
lato_form_item_input_textarea
renders a textarea input. -
lato_form_item_input_date
renders a date input. -
lato_form_item_input_datetime
renders a datetime input. -
lato_form_item_input_time
renders a time input. -
lato_form_item_input_color
renders a color input. -
lato_form_submit
renders the submit button.
<% user ||= @session.user %> <%= turbo_frame_tag 'tutorial_form-example' do %> <%= form_with model: user, url: main_app.components_update_user_action_path, data: { turbo_frame: '_self', controller: 'lato-form' } do |form| %> <%= lato_form_notices class: %w[mb-3] %> <%= lato_form_errors user, class: %w[mb-3] %> <div class="row"> <div class="col col-12 col-lg-6 mb-3"> <%= lato_form_item_label form, :first_name, 'Name' %> <%= lato_form_item_input_text form, :first_name, required: true %> </div> <div class="col col-12 col-lg-6 mb-3"> <%= lato_form_item_label form, :last_name, 'Surname' %> <%= lato_form_item_input_text form, :last_name, required: true %> </div> </div> <div class="row"> <div class="col col-12 col-lg-6 mb-3"> <%= lato_form_item_label form, :select, 'Select' %> <%= lato_form_item_input_select form, :select, [['Type 1', '1'], ['Type 2', '2']], required: true %> </div> <div class="col col-12 col-lg-6 mb-3"> <%= lato_form_item_label form, :file, 'File' %> <%= lato_form_item_input_file form, :file, required: true %> </div> </div> <div class="row"> <div class="col col-12 mb-3"> <%= lato_form_item_label form, :textarea, 'Textarea' %> <%= lato_form_item_input_textarea form, :textarea, required: true %> </div> </div> <div class="row"> <div class="col col-12 col-lg-4 mb-3"> <%= lato_form_item_label form, :date, 'Date' %> <%= lato_form_item_input_date form, :date, required: true %> </div> <div class="col col-12 col-lg-4 mb-3"> <%= lato_form_item_label form, :datetime, 'Datetime' %> <%= lato_form_item_input_datetime form, :datetime, required: true %> </div> <div class="col col-12 col-lg-4 mb-3"> <%= lato_form_item_label form, :time, 'Time' %> <%= lato_form_item_input_time form, :time, required: true %> </div> </div> <div class="row"> <div class="col col-12 mb-3"> <%= lato_form_item_label form, :color, 'Color' %> <%= lato_form_item_input_color form, :color, required: true %> </div> </div> <div class="row"> <div class="col col-12 mb-3"> <%= lato_form_item_label form, :first_name, 'Name with auto-complete' %> <%= lato_form_item_input_text form, :first_name, required: true, data: { controller: 'lato-input-autocomplete', lato_input_autocomplete_path_value: products_autocomplete_path } %> </div> </div> <div class="row"> <div class="col col-12 mb-3"> <%= lato_form_item_label form, :first_name, 'Name with auto-complete V2' %> <%= lato_form_item_input_text form, :first_name, required: true, data: { controller: 'lato-input-autocomplete2', lato_input_autocomplete2_path_value: products_autocomplete_path } %> </div> </div> <div class="d-flex justify-content-end"> <%= lato_form_submit form, 'Update', class: %w[btn-success] %> </div> <% end %> <% end %>
Index
The lato_index
component allows easy visualization of database records.
Index (front-end)
The simplest way to use the component is to pass it an ActiveRecord
collection:
<%= lato_index Product.all.limit(5) %>
Customizing columns
Columns can be customized using the :columns
parameter:
<%= lato_index Product.all.limit(5), columns: %i[id code status] %>
Notes
Column titles can be customized using Rails translation files.
Example:
en: activerecord: attributes: product: code: Code status: Status
Customizing column content
You can customize column content by creating helper methods with the format model_column(record)
.
For example, to customize the output of the :lato_user_id column, define the following helper in ProductsHelper
:
class ProductsHelper def product_lato_user_id(product) product.lato_user.full_name end end
Adding custom columns
To add custom columns, declare a method in the model that provides the value.
For example, after adding a lifetime
method to the Product
model, you can use the :lifetime
column:
class Product < ApplicationRecord def lifetime Time.now - created_at end end
class ProductsHelper def product_lifetime(product) Time.at(product.lifetime).utc.strftime('%H h %M m') end end
<%= lato_index Product.all.limit(5), columns: %i[id code status lifetime] %>
Notes
Custom columns can also be translated using Rails translation files, just like database-backed columns.
To add columns that don't map to real attributes, use attr_accessor :column_name
instead of defining a method in the model:
class Product < ApplicationRecord attr_accessor :lifetime end
Adding actions
<%= lato_index Product.all.limit(5), custom_actions: { create: { path: products_create_path, icon: 'bi bi-plus', aria_label: 'Create product', title: 'Create product' } } %>
Adding in-page actions
<%= lato_index Product.all.limit(5), custom_actions: { create: { path: products_create_path, icon: 'bi bi-plus', data: { lato_action_target: 'trigger', turbo_frame: dom_id(Product.new, 'form') }, aria_label: 'Create product', title: 'Create product' } } %>
Notes
The :create_turbo_frame
option specifies the turbo-frame ID in the products_create_path
page that should be inserted into the overlay.
Adding row-specific actions
Row-specific actions can be added through custom columns (as shown above).
These actions can also be opened in-page via overlays using data-lato-index-target="action"
and data-turbo-frame="turbo-frame-ID"
.
class ProductsHelper def product_actions(product) content_tag(:div, class: 'btn-group btn-group-sm') do concat link_to( 'Edit', products_update_path(product), class: 'btn btn-primary', data: { lato_action_target: 'trigger', turbo_frame: dom_id(product, 'form') } ) end end end
<%= lato_index Product.all.limit(5), columns: %i[id code status lifetime actions] %>
Index (back-end)
To make the index fully interactive, use the lato_index_collection
function from the Lato::Componentable
concern in the controller.
def index @products = lato_index_collection(Product.all, pagination: true) end
<%= lato_index @products %>
Customizing columns
def index @products_columns = lato_index_collection( Product.all, pagination: true, columns: %i[code status id] ) end
<%= lato_index @products_columns %>
Customizing pagination size
Users can choose how many items to display per page using a selector enabled via the :pagination_options
parameter in lato_index_collection
.
def index @products_pagination_options = lato_index_collection( Product.all, pagination: 10, columns: %i[code status id], key: 'products_pagination_options' ) end
<%= lato_index @products_pagination_options, pagination_options: [10,20,50,100] %>
Making columns sortable
def index @products_sortable_columns = lato_index_collection( Product.all, pagination: true, columns: %i[code status lato_user_id], sortable_columns: %i[code status lato_user_id] ) end
<%= lato_index @products_sortable_columns %>
Notes
To customize sorting logic, define the lato_index_order
scope inside the model.
Example:
class Product < ApplicationRecord belongs_to :lato_user, class_name: 'Lato::User' scope :lato_index_order, ->(column, order) do return joins(:lato_user).order("lato_users.last_name #{order}, lato_users.first_name #{order}") if column == :lato_user_id order("#{column} #{order}") end end
Notes
To set a default sorting column, use the default_sort_by
option in the lato_index_collection
method.
Example:
def index @products_default_sort = lato_index_collection( Product.all, pagination: true, columns: %i[code status lato_user_id], sortable_columns: %i[code status lato_user_id], default_sort_by: 'code|asc' # 'column|direction' ) end
Making columns searchable
def index @products_searchable_columns = lato_index_collection( Product.all, pagination: true, columns: %i[code status lato_user_id], sortable_columns: %i[code status lato_user_id], searchable_columns: %i[code lato_user_id] ) end
<%= lato_index @products_searchable_columns %>
Notes
To customize search logic, define the lato_index_search
scope inside the model.
Example:
class Product < ApplicationRecord belongs_to :lato_user, class_name: 'Lato::User' scope :lato_index_search, ->(search) do joins(:lato_user).where(" lower(code) LIKE :search OR lower(lato_users.first_name) LIKE :search OR lower(lato_users.last_name) LIKE :search ", search: "%#{search.downcase.strip}%") end end