Class: Crm::PanelComponent
- Inherits:
-
ApplicationComponent
- Object
- ViewComponent::Base
- ApplicationComponent
- Crm::PanelComponent
- Includes:
- ActionView::Helpers::TagHelper, ActionView::Helpers::UrlHelper
- Defined in:
- app/components/crm/panel_component.rb
Overview
The single renderer behind every CRM panel: a Bootstrap card with an optional
icon + title header, optional header actions, and a body that can collapse.
Views don't instantiate this directly — CrmHelper#panel (collapsible) and
CrmHelper#simple_panel (static) are the entry points, and they translate
their legacy option hashes into these kwargs. That keeps ~1000 existing call
sites working while every panel in the CRM shares one piece of markup.
Styling lives in +client/stylesheets/crm/components/_panels.scss+; see
DESIGN.crm.md "Components" for the contract it implements.
Instance Attribute Summary collapse
-
#id ⇒ Object
readonly
rubocop:enable Metrics/ParameterLists.
-
#title ⇒ Object
readonly
rubocop:enable Metrics/ParameterLists.
Instance Method Summary collapse
-
#body_classes ⇒ String
Class list for the body element, including the Bootstrap collapse classes when the panel is collapsible.
-
#body_id ⇒ String
The collapse target.
-
#card_attributes ⇒ Hash{Symbol => Object}
HTML attributes for the card element: leftover +html+ kwargs plus the computed id and class list.
-
#decorate_title? ⇒ Boolean
A title built by the caller (dashboard widgets) supplies its own layout, so skip the icon and the collapse caret rather than fighting it.
-
#header? ⇒ Boolean
Whether the card renders a header: either a title was given or the actions slot is populated.
-
#header_classes ⇒ String
Class list for the +.card-header+ element; +header_outer_class+ replaces the defaults entirely when given.
-
#initialize(title: nil, icon: nil, collapsible: false, open: true, id: nil, anchor_name: nil, card_class: nil, header_class: nil, header_outer_class: nil, title_class: nil, body_class: nil, wrap_title: true, wrap_body: true, **html) ⇒ PanelComponent
constructor
rubocop:disable Metrics/ParameterLists -- presentational knobs, all optional.
-
#title_classes ⇒ String
Class list for the title element; carries +collapsed+ when a collapsible panel starts closed so the caret renders correctly.
-
#title_tag { ... } ⇒ String
The collapsible variant is an toggling the body; the static one a plain span.
Methods inherited from ApplicationComponent
#cms_link, #fetch_or_fallback, #image_asset_tag, #image_tag, #number_to_currency, #number_with_delimiter, #post_path, #post_url, #strip_tags
Constructor Details
#initialize(title: nil, icon: nil, collapsible: false, open: true, id: nil, anchor_name: nil, card_class: nil, header_class: nil, header_outer_class: nil, title_class: nil, body_class: nil, wrap_title: true, wrap_body: true, **html) ⇒ PanelComponent
rubocop:disable Metrics/ParameterLists -- presentational knobs, all optional
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'app/components/crm/panel_component.rb', line 40 def initialize(title: nil, icon: nil, collapsible: false, open: true, id: nil, anchor_name: nil, card_class: nil, header_class: nil, header_outer_class: nil, title_class: nil, body_class: nil, wrap_title: true, wrap_body: true, **html) @title = title @icon = icon @collapsible = collapsible @open = open != false @anchor_name = anchor_name @card_class = card_class @header_class = header_class @header_outer_class = header_outer_class @title_class = title_class @body_class = body_class @wrap_title = wrap_title @wrap_body = wrap_body @html = html.except(:class, :id) @id = (id.presence || html[:id].presence || "card-#{SecureRandom.hex(10)}").to_s @html_class = html[:class] end |
Instance Attribute Details
#id ⇒ Object (readonly)
rubocop:enable Metrics/ParameterLists
61 62 63 |
# File 'app/components/crm/panel_component.rb', line 61 def id @id end |
#title ⇒ Object (readonly)
rubocop:enable Metrics/ParameterLists
61 62 63 |
# File 'app/components/crm/panel_component.rb', line 61 def title @title end |
Instance Method Details
#body_classes ⇒ String
Class list for the body element, including the Bootstrap collapse
classes when the panel is collapsible.
97 98 99 100 |
# File 'app/components/crm/panel_component.rb', line 97 def body_classes class_names(('card-body' if @wrap_body), 'crm-panel__body', @body_class, { 'collapse' => @collapsible, 'show' => @collapsible && @open }) end |
#body_id ⇒ String
The collapse target. dashboards/_panel.html.erb reconstructs this id to
decide which widgets reopen after a Turbo Stream replace — keep both in step.
73 |
# File 'app/components/crm/panel_component.rb', line 73 def body_id = "body-#{id}" |
#card_attributes ⇒ Hash{Symbol => Object}
HTML attributes for the card element: leftover +html+ kwargs plus the
computed id and class list.
79 80 81 |
# File 'app/components/crm/panel_component.rb', line 79 def card_attributes @html.merge(id:, class: class_names('crm-panel card w-100', @card_class, @html_class)) end |
#decorate_title? ⇒ Boolean
A title built by the caller (dashboard widgets) supplies its own layout, so
skip the icon and the collapse caret rather than fighting it.
125 |
# File 'app/components/crm/panel_component.rb', line 125 def decorate_title? = @wrap_title |
#header? ⇒ Boolean
Whether the card renders a header: either a title was given or the
actions slot is populated.
67 |
# File 'app/components/crm/panel_component.rb', line 67 def header? = title.present? || actions? |
#header_classes ⇒ String
Class list for the +.card-header+ element; +header_outer_class+ replaces
the defaults entirely when given.
87 88 89 90 91 |
# File 'app/components/crm/panel_component.rb', line 87 def header_classes @header_outer_class || class_names('card-header crm-panel__header d-flex justify-content-between align-items-center', @header_class) end |
#title_classes ⇒ String
Class list for the title element; carries +collapsed+ when a collapsible
panel starts closed so the caret renders correctly.
119 120 121 |
# File 'app/components/crm/panel_component.rb', line 119 def title_classes class_names('card-title crm-panel__title', @title_class, 'collapsed' => @collapsible && !@open) end |
#title_tag { ... } ⇒ String
The collapsible variant is an toggling the body; the static one a plain
span. Both carry .card-title so existing per-page CSS keeps matching.
107 108 109 110 111 112 113 |
# File 'app/components/crm/panel_component.rb', line 107 def title_tag(&) return tag.span(capture(&), class: title_classes) unless @collapsible link_to("##{body_id}", class: title_classes, role: 'button', data: { 'bs-toggle': 'collapse', 'bs-target': "##{body_id}" }, aria: { expanded: @open, controls: body_id }, &) end |