Module: Layered::Ui::RansackHelper
- Defined in:
- app/helpers/layered/ui/ransack_helper.rb
Constant Summary collapse
- SORT_INDICATORS =
{ "asc" => { symbol: "▲", label: ", sorted ascending", aria: "ascending" }, "desc" => { symbol: "▼", label: ", sorted descending", aria: "descending" } }.freeze
Instance Method Summary collapse
-
#l_ui_search_form(query, url: nil, fields: [], predicate: :cont, combinator: :or, label: "Search", placeholder: nil, button: "Search", clear: nil, turbo_frame: nil, html: {}, &block) ⇒ Object
Renders a styled Ransack search form.
-
#l_ui_sort_link(query, attribute, label = nil, default_order: nil, turbo_frame: nil, url: nil, html: {}) ⇒ Object
Renders a styled, accessible Ransack sort header cell.
Instance Method Details
#l_ui_search_form(query, url: nil, fields: [], predicate: :cont, combinator: :or, label: "Search", placeholder: nil, button: "Search", clear: nil, turbo_frame: nil, html: {}, &block) ⇒ Object
Renders a styled Ransack search form.
Simple usage (single input searching across fields):
l_ui_search_form(@q, url: users_path, fields: [:name, :email])
Custom usage (full control via block):
l_ui_search_form(@q, url: users_path) do |f|
render "layered_ui/shared/search_field", form: f, field: :name_cont, label: "Name"
f.submit "Go", class: "l-ui-button--primary"
end
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'app/helpers/layered/ui/ransack_helper.rb', line 14 def l_ui_search_form(query, url: nil, fields: [], predicate: :cont, combinator: :or, label: "Search", placeholder: nil, button: "Search", clear: nil, turbo_frame: nil, html: {}, &block) result = require_ransack("l_ui_search_form") { |msg| tag.p(msg, class: "l-ui-notice--warning") } return result unless result == true scope = query.context&.search_key || :q turbo_action = "advance" html = html.merge(class: ["l-ui-form", html[:class]].compact.join(" ")) if turbo_frame existing_data = (html[:data] || {}).symbolize_keys existing_controller = existing_data[:controller] controller = [existing_controller, "l-ui--search-form"].compact.join(" ") existing_action = existing_data[:action] action = [existing_action, "submit->l-ui--search-form#preserve"].compact.join(" ") turbo_action = existing_data[:turbo_action] || turbo_action html[:data] = existing_data.except(:controller, :action, :l_ui__search_form_scope_value).merge( turbo_frame: turbo_frame, turbo_action: turbo_action, controller: controller, action: action, l_ui__search_form_scope_value: scope ) end if block search_form_for(query, url: url, html: html, as: scope, &block) else raise ArgumentError, "l_ui_search_form requires at least one field in simple mode (e.g. fields: [:name])" if fields.empty? combined_field = fields.map(&:to_s).join("_#{combinator}_") + "_#{predicate}" placeholder ||= "Search by #{fields.map { |f| f.to_s.humanize.downcase }.join(', ')}" search_form_for(query, url: url, html: html, as: scope) do |f| f.label(combined_field, label, class: "l-ui-sr-only") + tag.div(class: "l-ui-search__inline") do content = f.text_field(combined_field, class: "l-ui-form__field", placeholder: placeholder) + f.submit(, class: "l-ui-button--primary") if clear raise ArgumentError, "l_ui_search_form requires an explicit url: when clear: is set" unless url = { class: "l-ui-button--outline" } [:data] = { turbo_frame: turbo_frame, turbo_action: turbo_action, action: "click->l-ui--search-form#clear" } if turbo_frame content += link_to(clear == true ? "Clear" : clear, url, **) end content end end end end |
#l_ui_sort_link(query, attribute, label = nil, default_order: nil, turbo_frame: nil, url: nil, html: {}) ⇒ Object
Renders a styled, accessible Ransack sort header cell.
Returns a <th> element containing a sort link and an accessible sort direction indicator. The aria-sort attribute is set on the <th> so screen readers announce the current sort state.
Usage:
l_ui_sort_link(@q, :name)
l_ui_sort_link(@q, :name, "Full name")
l_ui_sort_link(@q, :created_at, "Joined", default_order: :desc)
l_ui_sort_link(@q, :name, html: { data: { turbo_action: "replace" } })
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'app/helpers/layered/ui/ransack_helper.rb', line 78 def l_ui_sort_link(query, attribute, label = nil, default_order: nil, turbo_frame: nil, url: nil, html: {}) label ||= attribute.to_s.humanize link_class = ["l-ui-table__sort-link", html[:class]].compact.join(" ") result = require_ransack("l_ui_sort_link") { |msg| tag.th(tag.span(label, title: msg), class: "l-ui-table__header-cell", scope: "col") } return (result || tag.th(label, class: "l-ui-table__header-cell", scope: "col")) unless result == true current_dir = sort_direction_for(query, attribute) indicator = SORT_INDICATORS[current_dir] aria_sort = indicator&.dig(:aria) || "none" url = if url build_sort_url(url, query, attribute, default_order: default_order) else sort_url(query, attribute, { default_order: default_order }.compact) end link_html = html.except(:class) if turbo_frame existing_data = (link_html[:data] || {}).symbolize_keys link_html[:data] = existing_data.merge(turbo_frame: turbo_frame, turbo_action: existing_data[:turbo_action] || "advance") end link = link_to(url, **link_html, class: link_class) do parts = [label] if indicator parts << tag.span(indicator[:symbol], aria: { hidden: true }, class: "l-ui-table__sort-indicator") parts << tag.span(indicator[:label], class: "l-ui-sr-only") end safe_join(parts) end tag.th(link, class: "l-ui-table__header-cell l-ui-table__header-cell--sortable", scope: "col", aria: { sort: aria_sort }) end |