Module: BrutalistRailsUi::Helpers
- Defined in:
- lib/brutalist_rails_ui/helpers.rb
Instance Method Summary collapse
-
#card(title = nil, &block) ⇒ Object
White card with optional black header bar.
-
#card_header(title, action_text: nil, action_path: nil) ⇒ Object
Card header bar with optional right-side action.
-
#cta_banner(headline:, subtext: nil, link_text:, path:, **link_options) ⇒ Object
Yellow CTA banner with headline and action link.
-
#empty_state(icon: nil, message:, &block) ⇒ Object
Centered empty state with icon and message.
-
#kpi_box(label:, value:, dark: false) ⇒ Object
KPI stat box for summary grids.
-
#money(amount) ⇒ Object
Format a number as currency.
-
#money_class(amount) ⇒ Object
CSS class for positive/negative amounts.
-
#nav_link(label, path, mobile: false, **options) ⇒ Object
Nav link that highlights when active.
-
#page_header(title, subtitle: nil, &block) ⇒ Object
Page header row: h1 title + optional action buttons block.
-
#status_badge(status, color_map = {}) ⇒ Object
Status badge pill.
Instance Method Details
#card(title = nil, &block) ⇒ Object
White card with optional black header bar.
<%= card "Recent Transactions" do %>
<p class="p-6">Content here</p>
<% end %>
40 41 42 43 44 45 46 47 48 49 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 40 def card(title = nil, &block) content_tag :div, class: "bg-white border-2 border-black overflow-hidden" do if title concat content_tag(:div, class: "px-6 py-3 bg-black") { content_tag(:h2, title, class: "text-xs font-bold text-white uppercase tracking-wider") } end concat capture(&block) end end |
#card_header(title, action_text: nil, action_path: nil) ⇒ Object
Card header bar with optional right-side action.
<%= card_header "Accounts", action_text: "View all", action_path: accounts_path %>
54 55 56 57 58 59 60 61 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 54 def card_header(title, action_text: nil, action_path: nil) content_tag :div, class: "px-6 py-3 bg-black flex items-center justify-between" do concat content_tag(:h2, title, class: "text-xs font-bold text-white uppercase tracking-wider") if action_text && action_path concat link_to(action_text, action_path, class: "text-xs text-yellow-400 hover:text-white font-bold") end end end |
#cta_banner(headline:, subtext: nil, link_text:, path:, **link_options) ⇒ Object
Yellow CTA banner with headline and action link.
<%= cta_banner headline: "Connect a bank",
subtext: "Sync transactions automatically",
link_text: "Get Started",
path: banks_link_path %>
99 100 101 102 103 104 105 106 107 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 99 def (headline:, subtext: nil, link_text:, path:, **) content_tag :div, class: "border-2 border-black bg-yellow-400 p-6 flex items-center justify-between gap-4" do concat content_tag(:div) { concat content_tag(:p, headline, class: "font-black text-black uppercase") concat content_tag(:p, subtext, class: "text-sm text-black mt-1 font-bold") if subtext } concat link_to(link_text, path, class: "btn-primary flex-shrink-0", **) end end |
#empty_state(icon: nil, message:, &block) ⇒ Object
Centered empty state with icon and message.
<%= empty_state icon: "✓", message: "All transactions assigned" %>
<%= empty_state icon: "📭", message: "No accounts yet" do %>
<%= link_to "Connect a bank", banks_link_path, class: "btn-primary mt-4" %>
<% end %>
69 70 71 72 73 74 75 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 69 def empty_state(icon: nil, message:, &block) content_tag :div, class: "px-6 py-12 text-center" do concat content_tag(:p, icon, class: "text-3xl mb-3") if icon concat content_tag(:p, , class: "font-black text-black uppercase tracking-wide") concat capture(&block) if block end end |
#kpi_box(label:, value:, dark: false) ⇒ Object
KPI stat box for summary grids.
<div class="grid grid-cols-2 gap-4">
<%= kpi_box label: "Total Spent", value: "$12.40" %>
<%= kpi_box label: "Total Calls", value: "42", dark: true %>
</div>
83 84 85 86 87 88 89 90 91 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 83 def kpi_box(label:, value:, dark: false) bg = dark ? "bg-black text-white" : "bg-white border-2 border-black text-black" label_class = dark ? "text-xs font-bold uppercase tracking-widest text-gray-400 mb-1" \ : "text-xs font-bold uppercase tracking-widest text-gray-500 mb-1" content_tag :div, class: "#{bg} p-5" do concat content_tag(:p, label, class: label_class) concat content_tag(:p, value, class: "text-2xl font-black") end end |
#money(amount) ⇒ Object
Format a number as currency.
129 130 131 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 129 def money(amount) number_to_currency(amount, unit: "$", precision: 2) end |
#money_class(amount) ⇒ Object
CSS class for positive/negative amounts.
134 135 136 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 134 def money_class(amount) amount.to_f.negative? ? "text-red-600" : "text-black" end |
#nav_link(label, path, mobile: false, **options) ⇒ Object
Nav link that highlights when active. Pass mobile: true for the vertical mobile menu variant.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 5 def nav_link(label, path, mobile: false, **) base = path.split("?").first active = current_page?(path) || (base != "/" && request.path.start_with?(base)) if mobile classes = active \ ? "block bg-yellow-400 text-black px-4 py-3 text-sm font-bold border-b border-gray-700" \ : "block text-white hover:bg-gray-800 px-4 py-3 text-sm font-bold border-b border-gray-700" else classes = active \ ? "bg-yellow-400 text-black px-3 py-4 text-sm font-bold border-r border-l border-yellow-400" \ : "text-white hover:bg-white hover:text-black px-3 py-4 text-sm font-bold border-r border-gray-700 last:border-r-0" end link_to label, path, class: classes, ** end |
#page_header(title, subtitle: nil, &block) ⇒ Object
Page header row: h1 title + optional action buttons block.
<%= page_header "Transactions" do %>
<%= link_to "+ Add", new_transaction_path, class: "btn-primary" %>
<% end %>
25 26 27 28 29 30 31 32 33 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 25 def page_header(title, subtitle: nil, &block) content_tag :div, class: "flex flex-wrap items-center justify-between gap-3 mb-6" do concat content_tag(:div) { concat content_tag(:h1, title, class: "text-2xl font-black text-black uppercase tracking-tight") concat content_tag(:p, subtitle, class: "text-sm font-bold text-gray-500 mt-1 uppercase tracking-wide") if subtitle } concat content_tag(:div, capture(&block), class: "flex flex-wrap items-center gap-2") if block end end |
#status_badge(status, color_map = {}) ⇒ Object
Status badge pill.
<%= status_badge "pending" %>
<%= status_badge "funded", "funded" => "bg-green-600 text-white" %>
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/brutalist_rails_ui/helpers.rb', line 113 def status_badge(status, color_map = {}) defaults = { "active" => "bg-black text-white", "funded" => "bg-black text-white", "over" => "bg-red-600 text-white", "pending" => "bg-yellow-400 text-black", "income" => "bg-black text-white", "transfer" => "bg-white text-black", "untracked" => "bg-white text-black" }.merge(color_map) color = defaults[status.to_s] || "bg-white text-black" tag.span status.to_s.humanize, class: "inline-flex items-center border-2 border-black px-2 py-0.5 text-xs font-bold uppercase tracking-wide #{color}" end |