Module: Railspress::AdminHelper

Defined in:
app/helpers/railspress/admin_helper.rb

Overview

Helper methods for building consistent admin views. Use these helpers to ensure styling consistency across all entity views.

Instance Method Summary collapse

Instance Method Details

#rp_attachment_badge(attachment) ⇒ String

Shows attachment status badge.

Examples:

Usage

rp_attachment_badge(post.header_image)  # => "Attached" or "None"
rp_attachment_badge(project.gallery)    # => "5 images" or "None"

Parameters:

  • attachment (ActiveStorage::Attached)

    the attachment or attachments

Returns:

  • (String)

    rendered HTML



494
495
496
497
498
499
500
501
502
503
504
505
# File 'app/helpers/railspress/admin_helper.rb', line 494

def rp_attachment_badge(attachment)
  if attachment.respond_to?(:attached?) && attachment.attached?
    if attachment.respond_to?(:count)
      count = attachment.count
      rp_badge(pluralize(count, "file"), status: :published)
    else
      rp_badge("Attached", status: :published)
    end
  else
    rp_badge("None", status: :draft)
  end
end

#rp_attachment_field(form, name, multiple: false, accept: "image/*", record: nil, param_key: nil, label: nil, hint: nil, **options) ⇒ String

Renders a file attachment field with preview and removal option.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • multiple (Boolean) (defaults to: false)

    whether to allow multiple files

  • accept (String) (defaults to: "image/*")

    accepted file types (e.g., “image/*”)

  • record (ActiveRecord::Base) (defaults to: nil)

    the record (defaults to form.object)

  • param_key (String) (defaults to: nil)

    the param key for removal checkbox

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'app/helpers/railspress/admin_helper.rb', line 268

def rp_attachment_field(form, name, multiple: false, accept: "image/*", record: nil, param_key: nil, label: nil, hint: nil, **options)
  record ||= form.object
  param_key ||= record.model_name.param_key
  attachment = record.public_send(name)

  (:div, class: "rp-form-group") do
    output = "".html_safe

    if multiple && attachment.attached?
      # Multiple attachments preview
      output += (:div, class: "rp-gallery-preview") do
        attachment.map do |att|
          (:div, class: "rp-gallery-item") do
            item = if att.image?
              image_tag(main_app.url_for(att), class: "rp-gallery-thumb")
            else
              (:div, class: "rp-gallery-file") do
                (:span, "📄", class: "rp-gallery-file-icon") +
                (:span, att.filename, class: "rp-gallery-file-name")
              end
            end
            item += (:label, class: "rp-gallery-remove") do
              check_box_tag("#{param_key}[remove_#{name}][]", att.id, false) + " Remove"
            end
            item
          end
        end.join.html_safe
      end
      output += form.label(name, label || "Add images", class: "rp-label")
      output += form.file_field(name, multiple: true, accept: accept, class: "rp-file-input", direct_upload: true, **options)
      output += rp_hint(hint || "Select multiple images to upload") if hint != false
    elsif !multiple && attachment.attached?
      # Single attachment preview
      output += (:div, class: "rp-attachment-preview") do
        preview = if attachment.image?
          image_tag(main_app.url_for(attachment), class: "rp-attachment-thumb")
        else
          (:div, class: "rp-attachment-file") do
            (:span, attachment.filename, class: "rp-attachment-file-name")
          end
        end
        preview += (:label, class: "rp-attachment-remove") do
          check_box_tag("#{param_key}[remove_#{name}]", "1", false) + " Remove"
        end
        preview
      end
      output += form.label(name, label, class: "rp-label")
      output += form.file_field(name, accept: accept, class: "rp-file-input", direct_upload: true, **options)
      output += rp_hint(hint) if hint
    else
      # No attachment yet
      output += form.label(name, label, class: "rp-label")
      if multiple
        output += form.file_field(name, multiple: true, accept: accept, class: "rp-file-input", direct_upload: true, **options)
      else
        output += form.file_field(name, accept: accept, class: "rp-file-input", direct_upload: true, **options)
      end
      output += rp_hint(hint) if hint
    end

    output
  end
end

#rp_badge(text, status:) ⇒ String

Renders a badge with the appropriate status styling.

Parameters:

  • text (String)

    the badge text

  • status (Symbol, String)

    the status type (:draft, :published, :pending, etc.)

Returns:

  • (String)

    rendered HTML



663
664
665
# File 'app/helpers/railspress/admin_helper.rb', line 663

def rp_badge(text, status:)
  (:span, text, class: "rp-badge rp-badge--#{status}")
end

#rp_boolean_badge(value) ⇒ String

Shows “Yes” / “No” badge with appropriate styling.

Examples:

Usage

rp_boolean_badge(post.featured)  # => green "Yes" or gray "No"

Parameters:

  • value (Boolean)

    the boolean value

Returns:

  • (String)

    rendered HTML



479
480
481
482
483
484
485
# File 'app/helpers/railspress/admin_helper.rb', line 479

def rp_boolean_badge(value)
  if value
    rp_badge("Yes", status: :published)
  else
    rp_badge("No", status: :draft)
  end
end

#rp_boolean_field(form, name, label: nil, hint: nil, **options) ⇒ String

Renders a boolean checkbox field.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • label (String) (defaults to: nil)

    custom label text

Returns:

  • (String)

    rendered HTML



117
118
119
120
121
122
123
124
125
126
# File 'app/helpers/railspress/admin_helper.rb', line 117

def rp_boolean_field(form, name, label: nil, hint: nil, **options)
  label_text = label || name.to_s.humanize

  (:div, class: "rp-form-group") do
    (:label, class: "rp-checkbox-label") do
      form.check_box(name, options) + " ".html_safe + label_text
    end +
    (hint ? (:span, hint, class: "rp-hint") : "".html_safe)
  end
end

#rp_card(padded: false, **options) { ... } ⇒ String

Renders a card wrapper for content.

Examples:

Basic card

<%= rp_card do %>
  <table>...</table>
<% end %>

Padded card for forms

<%= rp_card(padded: true) do %>
  <%= render "form" %>
<% end %>

Parameters:

  • padded (Boolean) (defaults to: false)

    whether to add internal padding

  • options (Hash)

    additional HTML attributes

Yields:

  • the card content

Returns:

  • (String)

    rendered HTML



592
593
594
595
596
597
598
# File 'app/helpers/railspress/admin_helper.rb', line 592

def rp_card(padded: false, **options, &block)
  classes = [ "rp-card" ]
  classes << "rp-card--padded" if padded
  classes << options.delete(:class) if options[:class]

  (:div, options.merge(class: classes.join(" ")), &block)
end

#rp_date_field(form, name, label: nil, hint: nil, **options) ⇒ String

Renders a date input field with label.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



149
150
151
152
153
154
155
156
# File 'app/helpers/railspress/admin_helper.rb', line 149

def rp_date_field(form, name, label: nil, hint: nil, **options)
  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: "rp-label")
    output += form.date_field(name, class: "rp-input", **options)
    output += rp_hint(hint) if hint
    output
  end
end

#rp_datetime_field(form, name, label: nil, hint: nil, **options) ⇒ String

Renders a datetime-local input field with label.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



134
135
136
137
138
139
140
141
# File 'app/helpers/railspress/admin_helper.rb', line 134

def rp_datetime_field(form, name, label: nil, hint: nil, **options)
  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: "rp-label")
    output += form.datetime_local_field(name, class: "rp-input", **options)
    output += rp_hint(hint) if hint
    output
  end
end

#rp_decimal_field(form, name, label: nil, hint: nil, **options) ⇒ String

Renders a decimal number input field with label.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



179
180
181
182
183
184
185
186
# File 'app/helpers/railspress/admin_helper.rb', line 179

def rp_decimal_field(form, name, label: nil, hint: nil, **options)
  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: "rp-label")
    output += form.number_field(name, class: "rp-input", step: "any", **options)
    output += rp_hint(hint) if hint
    output
  end
end

#rp_delete_icon(path, confirm: "Delete this item?", title: "Delete", disabled: false, disabled_title: nil) ⇒ String

Renders the standard delete icon button for table rows.

Parameters:

  • path (String)

    the delete path

  • confirm (String) (defaults to: "Delete this item?")

    confirmation message

  • title (String) (defaults to: "Delete")

    tooltip text

Returns:

  • (String)

    rendered HTML



405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'app/helpers/railspress/admin_helper.rb', line 405

def rp_delete_icon(path, confirm: "Delete this item?", title: "Delete", disabled: false, disabled_title: nil)
  if disabled
    (:span, class: "rp-icon-btn rp-icon-btn--danger rp-icon-btn--disabled",
                       title: disabled_title || title) do
      rp_icon(:trash)
    end
  else
    button_to path, method: :delete,
      data: { turbo_confirm: confirm },
      class: "rp-icon-btn rp-icon-btn--danger", title: title do
      rp_icon(:trash)
    end
  end
end

#rp_edit_icon(path, title: "Edit") ⇒ String

Renders the standard edit icon button for table rows.

Parameters:

  • path (String)

    the edit path

  • title (String) (defaults to: "Edit")

    tooltip text

Returns:

  • (String)

    rendered HTML



394
395
396
397
398
# File 'app/helpers/railspress/admin_helper.rb', line 394

def rp_edit_icon(path, title: "Edit")
  link_to path, class: "rp-icon-btn", title: title do
    rp_icon(:edit)
  end
end

#rp_empty_state(message, link_text: nil, link_path: nil) ⇒ String

Renders an empty state message for lists with no items.

Parameters:

  • message (String)

    the message to display

  • link_text (String, nil) (defaults to: nil)

    optional link text

  • link_path (String, nil) (defaults to: nil)

    optional link path

Returns:

  • (String)

    rendered HTML



652
653
654
655
656
657
# File 'app/helpers/railspress/admin_helper.rb', line 652

def rp_empty_state(message, link_text: nil, link_path: nil)
  content = message
  content += " " + link_to(link_text, link_path, class: "rp-link") + "." if link_text && link_path

  (:p, content.html_safe, class: "rp-empty-state")
end

#rp_flash_messagesString

Renders all flash message types with appropriate styling.

Examples:

Usage (in layout)

<%= rp_flash_messages %>

Returns:

  • (String)

    rendered HTML



516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
# File 'app/helpers/railspress/admin_helper.rb', line 516

def rp_flash_messages
  return unless flash.any?

  flash_type_classes = {
    notice: "rp-flash--success",
    alert: "rp-flash--danger",
    warning: "rp-flash--warning",
    info: "rp-flash--info"
  }

  (:div, class: "rp-flash-container") do
    flash.map do |type, message|
      css_class = flash_type_classes[type.to_sym] || "rp-flash--info"
      (:div, message, class: "rp-flash #{css_class}")
    end.join.html_safe
  end
end

#rp_focal_point_image_field(form, name, record: nil, label: nil, **options) ⇒ String

Renders a focal point image field with the compact/editor UI. For persisted records with images, shows the compact view with Edit button. For new records or no image, shows a dropzone upload.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the attachment field name (e.g., :main_image)

  • record (ActiveRecord::Base) (defaults to: nil)

    the record (defaults to form.object)

  • label (String) (defaults to: nil)

    custom label text

Returns:

  • (String)

    rendered HTML



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'app/helpers/railspress/admin_helper.rb', line 340

def rp_focal_point_image_field(form, name, record: nil, label: nil, **options)
  record ||= form.object
  label ||= name.to_s.humanize
  attachment = record.public_send(name)
  has_image = attachment.attached? && attachment.blob&.persisted?

  if record.persisted? && has_image
    # Persisted record with image - render focal point compact view
    render partial: "railspress/admin/shared/image_section_compact",
           locals: {
             record: record,
             attachment_name: name,
             label: label
           }
  else
    # New record or no image - render dropzone
    (:div, class: "rp-form-group") do
      output = (:label, label, class: "rp-label")
      if has_image
        # Image uploaded but record not saved yet - show preview
        output += (:div, class: "rp-image-section__compact") do
          preview = (:div, class: "rp-image-section__thumb") do
            image_tag(main_app.url_for(attachment.variant(resize_to_limit: [ 120, 80 ])), alt: "")
          end
          preview += (:div, class: "rp-image-section__info") do
            (:span, attachment.filename, class: "rp-image-section__filename") +
            (:span, number_to_human_size(attachment.byte_size), class: "rp-image-section__meta")
          end
          preview += (:div, class: "rp-image-section__actions") do
            (:label, class: "rp-btn rp-btn--outline rp-btn--sm") do
              "Change".html_safe + form.file_field(name, accept: "image/*", class: "rp-sr-only", direct_upload: true)
            end
          end
          preview
        end
        output += rp_hint("Save to enable focal point editing.")
      else
        # No image - show dropzone
        output += render(partial: "railspress/admin/shared/dropzone",
                       locals: { form: form, field_name: name, prompt: "Click to upload #{label.downcase}" })
      end
      output
    end
  end
end

#rp_form_actions(form, cancel_path, submit_text: nil) ⇒ String

Renders form actions (submit + cancel) with consistent styling.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • cancel_path (String)

    path for cancel link

  • submit_text (String) (defaults to: nil)

    text for submit button (defaults to form default)

Returns:

  • (String)

    rendered HTML



627
628
629
630
631
632
633
634
# File 'app/helpers/railspress/admin_helper.rb', line 627

def rp_form_actions(form, cancel_path, submit_text: nil)
  (:div, class: "rp-form-actions") do
    submit_options = { class: "rp-btn rp-btn--primary" }
    buttons = form.submit(submit_text, submit_options)
    buttons += link_to("Cancel", cancel_path, class: "rp-btn rp-btn--secondary")
    buttons
  end
end

#rp_form_errors(record) ⇒ String?

Renders form errors in the standard style.

Parameters:

  • record (ActiveRecord::Base)

    the record to check for errors

Returns:

  • (String, nil)

    rendered HTML or nil if no errors



603
604
605
606
607
608
609
610
611
612
613
# File 'app/helpers/railspress/admin_helper.rb', line 603

def rp_form_errors(record)
  return unless record.errors.any?

  (:div, class: "rp-form-errors") do
    (:ul) do
      record.errors.full_messages.map do |msg|
        (:li, msg)
      end.join.html_safe
    end
  end
end

#rp_form_group { ... } ⇒ String

Renders a form group (label + input wrapper) with consistent styling.

Yields:

  • the form group content (label and input)

Returns:

  • (String)

    rendered HTML



618
619
620
# File 'app/helpers/railspress/admin_helper.rb', line 618

def rp_form_group(&block)
  (:div, class: "rp-form-group", &block)
end

#rp_hint(text) ⇒ String

Renders a hint/help text below a form input.

Parameters:

  • text (String)

    the hint text

Returns:

  • (String)

    rendered HTML



670
671
672
# File 'app/helpers/railspress/admin_helper.rb', line 670

def rp_hint(text)
  (:p, text, class: "rp-hint")
end

#rp_icon(name) ⇒ String

Renders an SVG icon.

Parameters:

  • name (Symbol)

    the icon name (:edit, :trash, :plus, :search)

Returns:

  • (String)

    rendered SVG HTML



438
439
440
441
442
443
444
445
446
# File 'app/helpers/railspress/admin_helper.rb', line 438

def rp_icon(name)
  icons = {
    edit: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>',
    trash: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>',
    plus: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>',
    search: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>'
  }
  icons[name]&.html_safe || ""
end

#rp_input_class(primary: false, mono: false, size: nil) ⇒ String

CSS classes for a standard text input.

Parameters:

  • primary (Boolean) (defaults to: false)

    whether this is the primary/title input

  • mono (Boolean) (defaults to: false)

    whether to use monospace font (for slugs, codes)

  • size (Symbol) (defaults to: nil)

    input size (:sm, :lg, or nil for default)

Returns:

  • (String)

    CSS class string



679
680
681
682
683
684
685
# File 'app/helpers/railspress/admin_helper.rb', line 679

def rp_input_class(primary: false, mono: false, size: nil)
  classes = [ "rp-input" ]
  classes << "rp-input--title" if primary
  classes << "rp-input--mono" if mono
  classes << "rp-input--#{size}" if size
  classes.join(" ")
end

#rp_integer_field(form, name, label: nil, hint: nil, **options) ⇒ String

Renders an integer number input field with label.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



164
165
166
167
168
169
170
171
# File 'app/helpers/railspress/admin_helper.rb', line 164

def rp_integer_field(form, name, label: nil, hint: nil, **options)
  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: "rp-label")
    output += form.number_field(name, class: "rp-input", step: 1, **options)
    output += rp_hint(hint) if hint
    output
  end
end

#rp_label_class(large: false, required: false) ⇒ String

CSS classes for a label.

Parameters:

  • large (Boolean) (defaults to: false)

    whether to use large label style

  • required (Boolean) (defaults to: false)

    whether to show required indicator

Returns:

  • (String)

    CSS class string



691
692
693
694
695
696
# File 'app/helpers/railspress/admin_helper.rb', line 691

def rp_label_class(large: false, required: false)
  classes = [ "rp-label" ]
  classes << "rp-label--lg" if large
  classes << "rp-label--required" if required
  classes.join(" ")
end

#rp_lines_field(form, name, rows: 5, placeholder: nil, label: nil, hint: nil, **options) ⇒ String

Renders a line-separated list textarea field with label. Uses the virtual attribute ‘#name_list` for form binding.

Examples:

Usage

rp_lines_field(f, :highlights)
rp_lines_field(f, :highlights, rows: 6, hint: "Each line becomes one item")

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name (e.g., :highlights)

  • rows (Integer) (defaults to: 5)

    number of textarea rows

  • placeholder (String) (defaults to: nil)

    placeholder text

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



246
247
248
249
250
251
252
253
254
255
256
# File 'app/helpers/railspress/admin_helper.rb', line 246

def rp_lines_field(form, name, rows: 5, placeholder: nil, label: nil, hint: nil, **options)
  virtual_name = "#{name}_list"
  placeholder ||= "One item per line"

  (:div, class: "rp-form-group") do
    output = form.label(virtual_name, label || name.to_s.humanize, class: "rp-label")
    output += form.text_area(virtual_name, rows: rows, class: "rp-input", placeholder: placeholder, **options)
    output += rp_hint(hint || "Enter one item per line")
    output
  end
end

#rp_list_field(form, name, placeholder: nil, label: nil, hint: nil, **options) ⇒ String

Renders a comma-separated list input field with label. Uses the virtual attribute ‘#name_list` for form binding.

Examples:

Usage

rp_list_field(f, :tech_stack)
rp_list_field(f, :tech_stack, hint: "Add technologies separated by commas")

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name (e.g., :tech_stack)

  • placeholder (String) (defaults to: nil)

    placeholder text

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



221
222
223
224
225
226
227
228
229
230
231
# File 'app/helpers/railspress/admin_helper.rb', line 221

def rp_list_field(form, name, placeholder: nil, label: nil, hint: nil, **options)
  virtual_name = "#{name}_list"
  placeholder ||= "Item 1, Item 2, Item 3"

  (:div, class: "rp-form-group") do
    output = form.label(virtual_name, label || name.to_s.humanize, class: "rp-label")
    output += form.text_field(virtual_name, class: "rp-input", placeholder: placeholder, **options)
    output += rp_hint(hint || "Separate items with commas")
    output
  end
end

#rp_page_header(title, actions = {}) ⇒ String

LAYOUT HELPERS (existing methods below)

Renders a page header with title and optional action buttons.

Examples:

Basic usage

<%= rp_page_header "Posts" %>

With primary action

<%= rp_page_header "Posts", "New Post" => new_admin_post_path %>

With multiple actions

<%= rp_page_header "Posts",
  "Export" => [admin_exports_path, class: "rp-btn rp-btn--secondary"],
  "New Post" => new_admin_post_path %>

Parameters:

  • title (String)

    the page title

  • actions (Hash) (defaults to: {})

    action links to render (label => path or label => [path, options])

Returns:

  • (String)

    rendered HTML



552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'app/helpers/railspress/admin_helper.rb', line 552

def rp_page_header(title, actions = {})
  (:div, class: "rp-page-header") do
    header_content = (:h1, title, class: "rp-page-title")

    if actions.any?
      action_links = actions.map do |label, target|
        path, options = target.is_a?(Array) ? target : [ target, {} ]
        btn_class = options.delete(:class) || "rp-btn rp-btn--primary"
        link_to(label, path, options.merge(class: btn_class))
      end.join.html_safe

      header_content += (:div, action_links, class: "rp-page-actions")
    end

    header_content
  end
end

#rp_page_title(title) ⇒ String

Renders a standalone page title (for new/edit pages without actions).

Parameters:

  • title (String)

    the page title

Returns:

  • (String)

    rendered HTML



573
574
575
# File 'app/helpers/railspress/admin_helper.rb', line 573

def rp_page_title(title)
  (:h1, title, class: "rp-page-title rp-page-title--standalone")
end

#rp_render_field(form, name, type:, **options) ⇒ String

Master dispatcher that renders the appropriate input based on type.

Examples:

Basic usage

rp_render_field(f, :title, type: :string)
rp_render_field(f, :content, type: :rich_text)
rp_render_field(f, :featured, type: :boolean, label: "Featured post?")

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • type (Symbol)

    the field type (:string, :text, :rich_text, :boolean, :datetime, :date, :integer, :decimal, :attachment, :attachments, :select)

  • options (Hash)

    additional options passed to the specific renderer

Returns:

  • (String)

    rendered HTML



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
# File 'app/helpers/railspress/admin_helper.rb', line 20

def rp_render_field(form, name, type:, **options)
  case type
  when :string
    rp_string_field(form, name, **options)
  when :text
    rp_text_field(form, name, **options)
  when :rich_text
    rp_rich_text_field(form, name, **options)
  when :boolean
    rp_boolean_field(form, name, **options)
  when :datetime
    rp_datetime_field(form, name, **options)
  when :date
    rp_date_field(form, name, **options)
  when :integer
    rp_integer_field(form, name, **options)
  when :decimal
    rp_decimal_field(form, name, **options)
  when :attachment
    rp_attachment_field(form, name, multiple: false, **options)
  when :attachments
    rp_attachment_field(form, name, multiple: true, **options)
  when :focal_point_image
    rp_focal_point_image_field(form, name, **options)
  when :select
    rp_select_field(form, name, **options)
  when :list
    rp_list_field(form, name, **options)
  when :lines
    rp_lines_field(form, name, **options)
  else
    rp_string_field(form, name, **options)
  end
end

#rp_rich_text_field(form, name, placeholder: nil, label: nil, hint: nil, **options) ⇒ String

Renders a rich text (Trix) editor field with label.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • placeholder (String) (defaults to: nil)

    placeholder text

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



103
104
105
106
107
108
109
110
# File 'app/helpers/railspress/admin_helper.rb', line 103

def rp_rich_text_field(form, name, placeholder: nil, label: nil, hint: nil, **options)
  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: "rp-label")
    output += form.rich_text_area(name, class: "rp-rich-text", **options)
    output += rp_hint(hint) if hint
    output
  end
end

#rp_select_field(form, name, choices:, include_blank: false, label: nil, hint: nil, **options) ⇒ String

Renders a select dropdown field with label.

Examples:

Basic usage

rp_select_field(f, :status, choices: Post.statuses.keys)
rp_select_field(f, :category_id, choices: Category.pluck(:name, :id), include_blank: "No category")

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • choices (Array)

    options for select (array of [text, value] or just values)

  • include_blank (Boolean, String) (defaults to: false)

    whether to include blank option

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



200
201
202
203
204
205
206
207
# File 'app/helpers/railspress/admin_helper.rb', line 200

def rp_select_field(form, name, choices:, include_blank: false, label: nil, hint: nil, **options)
  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: "rp-label")
    output += form.select(name, choices, { include_blank: include_blank }, { class: "rp-select" }.merge(options))
    output += rp_hint(hint) if hint
    output
  end
end

#rp_sidebar_section(title) { ... } ⇒ String

Renders a sidebar section for complex forms.

Parameters:

  • title (String)

    the section title

Yields:

  • the section content

Returns:

  • (String)

    rendered HTML



640
641
642
643
644
645
# File 'app/helpers/railspress/admin_helper.rb', line 640

def rp_sidebar_section(title, &block)
  (:div, class: "rp-sidebar-section") do
    (:h3, title, class: "rp-sidebar-title") +
      capture(&block)
  end
end

#rp_sortable_header(column, label, current_sort:, current_direction:) ⇒ String

Renders a sortable table header link. Clicking toggles between ascending and descending order.

Examples:

Basic usage

<%= rp_sortable_header(:title, "Title", current_sort: @sort, current_direction: @direction) %>

Parameters:

  • column (Symbol, String)

    the column name for sorting

  • label (String)

    the display text for the header

  • current_sort (String, nil)

    the currently sorted column

  • current_direction (String)

    current sort direction (“asc” or “desc”)

Returns:

  • (String)

    rendered HTML



708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# File 'app/helpers/railspress/admin_helper.rb', line 708

def rp_sortable_header(column, label, current_sort:, current_direction:)
  column = column.to_s
  is_active = current_sort == column
  # Toggle direction if clicking the same column, otherwise default to asc
  new_direction = is_active && current_direction == "asc" ? "desc" : "asc"

  classes = [ "rp-sortable" ]
  classes << "rp-sortable--active" if is_active
  classes << "rp-sortable--#{current_direction}" if is_active

  link_to(
    label,
    url_for(request.query_parameters.merge(sort: column, direction: new_direction)),
    class: classes.join(" ")
  )
end

#rp_status_badge(value, type: nil) ⇒ String

Shows a colored badge for status values.

Examples:

Usage

rp_status_badge(post.status)
rp_status_badge("Active", type: :success)

Parameters:

  • value (String, Symbol)

    the status value

  • type (Symbol) (defaults to: nil)

    badge type (:success, :warning, :danger, :default, or status name like :published, :draft)

Returns:

  • (String)

    rendered HTML



468
469
470
471
# File 'app/helpers/railspress/admin_helper.rb', line 468

def rp_status_badge(value, type: nil)
  type ||= value.to_s.downcase.to_sym
  rp_badge(value.to_s.titleize, status: type)
end

#rp_string_field(form, name, primary: false, mono: false, placeholder: nil, required: false, label: nil, hint: nil, **options) ⇒ String

Renders a string input field with label.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • primary (Boolean) (defaults to: false)

    whether this is the primary/title input

  • mono (Boolean) (defaults to: false)

    whether to use monospace font

  • placeholder (String) (defaults to: nil)

    placeholder text

  • required (Boolean) (defaults to: false)

    whether field is required

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



65
66
67
68
69
70
71
72
73
74
75
# File 'app/helpers/railspress/admin_helper.rb', line 65

def rp_string_field(form, name, primary: false, mono: false, placeholder: nil, required: false, label: nil, hint: nil, **options)
  placeholder ||= "Enter #{name.to_s.humanize.downcase}..."
  input_class = rp_input_class(primary: primary, mono: mono)

  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: rp_label_class(required: required))
    output += form.text_field(name, class: input_class, placeholder: placeholder, required: required, **options)
    output += rp_hint(hint) if hint
    output
  end
end

#rp_table_action_icons(edit_path:, delete_path:, confirm: "Delete this item?", delete_disabled: false, disabled_title: nil) ⇒ String

Renders standard edit and delete action icons for table rows.

Examples:

Usage

rp_table_actions(edit_admin_category_path(category), admin_category_path(category), confirm: "Delete this category?")

Parameters:

  • edit_path (String)

    the edit path

  • delete_path (String)

    the delete path

  • confirm (String) (defaults to: "Delete this item?")

    confirmation message for delete

Returns:

  • (String)

    rendered HTML



428
429
430
431
432
433
# File 'app/helpers/railspress/admin_helper.rb', line 428

def rp_table_action_icons(edit_path:, delete_path:, confirm: "Delete this item?",
                          delete_disabled: false, disabled_title: nil)
  rp_edit_icon(edit_path) +
    rp_delete_icon(delete_path, confirm: confirm,
                   disabled: delete_disabled, disabled_title: disabled_title)
end

#rp_table_header(label, **options) ⇒ String

Renders a non-sortable table header.

Parameters:

  • label (String)

    the display text for the header

  • options (Hash)

    additional HTML attributes

Returns:

  • (String)

    rendered HTML



729
730
731
# File 'app/helpers/railspress/admin_helper.rb', line 729

def rp_table_header(label, **options)
  (:span, label, options)
end

#rp_text_field(form, name, rows: 4, placeholder: nil, label: nil, hint: nil, **options) ⇒ String

Renders a text area field with label.

Parameters:

  • form (ActionView::Helpers::FormBuilder)

    the form builder

  • name (Symbol)

    the field name

  • rows (Integer) (defaults to: 4)

    number of rows

  • placeholder (String) (defaults to: nil)

    placeholder text

  • label (String) (defaults to: nil)

    custom label text

  • hint (String) (defaults to: nil)

    hint text shown below input

Returns:

  • (String)

    rendered HTML



85
86
87
88
89
90
91
92
93
94
# File 'app/helpers/railspress/admin_helper.rb', line 85

def rp_text_field(form, name, rows: 4, placeholder: nil, label: nil, hint: nil, **options)
  placeholder ||= "Enter #{name.to_s.humanize.downcase}..."

  (:div, class: "rp-form-group") do
    output = form.label(name, label, class: "rp-label")
    output += form.text_area(name, rows: rows, class: "rp-input", placeholder: placeholder, **options)
    output += rp_hint(hint) if hint
    output
  end
end

#rp_truncated_text(text, length: 50) ⇒ String

Truncates text with ellipsis, HTML-safe.

Parameters:

  • text (String)

    the text to truncate

  • length (Integer) (defaults to: 50)

    maximum length

Returns:

  • (String)

    truncated text



456
457
458
# File 'app/helpers/railspress/admin_helper.rb', line 456

def rp_truncated_text(text, length: 50)
  truncate(text.to_s, length: length)
end