active_admin_prism 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Views
5
+ # Reopens ActiveAdmin::Views::ActionItems purely to mark the
6
+ # auto-registered "New <Resource>" action item with its own class —
7
+ # ActiveAdmin::Resource::ActionItems#add_default_new_action_item names
8
+ # it :new internally, but that name never reaches the rendered
9
+ # `span.action_item` itself (ActionItem#html_class only ever emits
10
+ # "action_item" plus a host's own optional :class, nothing derived
11
+ # from the name), so there'd otherwise be no way for CSS/JS to tell it
12
+ # apart from any other action_item at all.
13
+ #
14
+ # js-src/prism.js's consolidated-action-items dropdown reads this to
15
+ # always exclude the New-resource button from consolidation, leaving
16
+ # it inline in its original spot — it's the single most-used action on
17
+ # an index page, unlike the bulk-action/CSV-upload links this feature
18
+ # was actually built to tidy away, so sweeping it into a dropdown too
19
+ # would bury the one button visitors reach for constantly.
20
+ class ActionItems
21
+ def build(action_items)
22
+ action_items.each do |action_item|
23
+ classes = [action_item.html_class]
24
+ classes << "prism-action-item-new" if action_item.name == :new
25
+ span class: classes.join(" ") do
26
+ instance_exec(&action_item.block)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Filters
5
+ # ActiveAdmin core auto-registers this sidebar section on every resource
6
+ # (see active_admin/filters/resource_extension.rb#add_search_status_sidebar_section)
7
+ # to summarize the current scope + active filters inside #sidebar,
8
+ # alongside the Filters form. Skip it entirely when
9
+ # ActiveAdminPrism.configuration.active_filters_bar is on — see
10
+ # active_filters_bar.rb's Pages::Index override, which renders the same
11
+ # content next to Batch Actions instead.
12
+ class ActiveSidebar
13
+ def sidebar_options
14
+ {
15
+ only: :index,
16
+ if: -> {
17
+ active_admin_config.current_filters_enabled? &&
18
+ (params[:q] || params[:scope]) &&
19
+ !ActiveAdminPrism.configuration.active_filters_bar
20
+ }
21
+ }
22
+ end
23
+ end
24
+ end
25
+
26
+ module Views
27
+ module Pages
28
+ # Relocates the "Search status" summary (current scope + active
29
+ # filters — AA core's ActiveAdmin::Filters::ActiveSidebar, reopened
30
+ # above to skip its normal #sidebar rendering when this is on) into
31
+ # the same row as the Batch Actions button/scopes tabs (AA core's own
32
+ # ".table_tools", rendered by Pages::Index#build_table_tools) instead
33
+ # of ActiveAdmin's own #sidebar.
34
+ #
35
+ # Why not #sidebar: ActiveAdminPrism.configuration.collapsible_filters
36
+ # squeezes the *entire* #sidebar column down to a 72px icon gutter
37
+ # while the Filters form is collapsed (scss-src/_panels.scss) — every
38
+ # child of #sidebar shrinks with it, this section included. Its
39
+ # content (one "field contains value" sentence per active filter) has
40
+ # nowhere to fit in 72px and overflows out over the table instead of
41
+ # shrinking cleanly.
42
+ #
43
+ # ActiveAdminPrism::Configuration#active_filters_bar controls this —
44
+ # false restores ActiveAdmin's stock behavior (rendered inside
45
+ # #sidebar, squeezed along with it when collapsible_filters is on).
46
+ class Index
47
+ # AA core's own #build_table_tools (active_admin/views/pages/index.rb)
48
+ # only renders ".table_tools" at all `if any_table_tools?` (batch
49
+ # actions, scopes, or multiple index presenters) — grouping the
50
+ # controls it does render into their own ".table_tools_actions" wrapper
51
+ # (a new element, not AA's) is what lets scss-src/_panels.scss push
52
+ # this bar to the opposite end of the same flex row via
53
+ # `justify-content: space-between` regardless of whether that group
54
+ # is present at all, rather than only ever being able to sit beside
55
+ # it when it happens to exist.
56
+ def build_table_tools
57
+ show_bar = active_filters_bar?
58
+ return unless any_table_tools? || show_bar
59
+
60
+ div class: "table_tools" do
61
+ if any_table_tools?
62
+ div class: "table_tools_actions" do
63
+ build_batch_actions_selector
64
+ build_scopes
65
+ build_index_list
66
+ end
67
+ end
68
+ build_active_filters_bar if show_bar
69
+ end
70
+ end
71
+
72
+ def active_filters_bar?
73
+ return false unless ActiveAdminPrism.configuration.active_filters_bar
74
+ return false unless active_admin_config
75
+ # active_admin_config should always be an ActiveAdmin::Resource here
76
+ # (only a Resource's :index action ever reaches Pages::Index), but
77
+ # #current_filters_enabled? is defined via Filters::ResourceExtension
78
+ # rather than on ActiveAdmin::Config itself — guard rather than
79
+ # assume, the same defensive style as the rest of this gem.
80
+ return false unless active_admin_config.respond_to?(:current_filters_enabled?)
81
+ return false unless active_admin_config.current_filters_enabled?
82
+
83
+ (params[:q] || params[:scope]).present?
84
+ end
85
+
86
+ def build_active_filters_bar
87
+ div id: "prism_active_filters_bar", class: "prism-active-filters-bar" do
88
+ active_filters_sidebar_content
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -3,22 +3,36 @@
3
3
  module ActiveAdmin
4
4
  module Views
5
5
  # Reopens ActiveAdmin::Views::SidebarSection (used for every sidebar
6
- # section, e.g. "Filters", "Search Status", any custom
7
- # `sidebar :title do ... end` block) to inject a real inline SVG icon
8
- # into the title of the *Filters* section specifically matching the
9
- # id ActiveAdmin::SidebarSection#id computes for it
10
- # ("filters_sidebar_section"). Every other sidebar section is untouched.
6
+ # section "Filters", "Search Status", and any custom
7
+ # `sidebar "Title" do ... end` block a host app registers) to collapse
8
+ # *every* section to a single icon button by default, expanding to the
9
+ # full panel on click — not just the Filters section, which is all this
10
+ # used to do.
11
11
  #
12
- # The label text is wrapped in its own span so CSS can visually hide it
13
- # while collapsed without touching the icon (see
14
- # scss-src/_panels.scss's #filters_sidebar_section rules, and
15
- # prism.js's filters-collapse handler for the actual toggle).
12
+ # Why generalize this: the #sidebar column's own width only shrinks to
13
+ # a 72px icon gutter while every one of its sections is collapsed (see
14
+ # scss-src/_panels.scss's ":has(.prism-collapsible-panel):not(:has(...open))"
15
+ # rule) a section left OUT of that treatment still renders at its
16
+ # normal full width/height inside that shrunk 72px column, wrapping
17
+ # every word onto its own line (or, depending on its own CSS, spilling
18
+ # out unclipped over the main content) instead of collapsing cleanly
19
+ # alongside Filters. A host's own custom sidebar block (e.g. a "More
20
+ # Actions" link list) hit exactly this before this file generalized
21
+ # the treatment to cover it too.
22
+ #
23
+ # A host can pass its own icon via `sidebar "Title", icon: :list do
24
+ # ... end` (any name from lib/prism_icons.rb) — anything else, plus
25
+ # every section that predates this option, falls back to a generic
26
+ # icon (:filter for the Filters section specifically, matching its
27
+ # pre-existing look; :list for everything else).
16
28
  #
17
29
  # This only runs when ActiveAdminPrism.configuration.collapsible_filters
18
- # is true — when it's false the section is left exactly as ActiveAdmin
19
- # renders it by default (plain text title, no icon).
30
+ # is true — when it's false, every section is left exactly as
31
+ # ActiveAdmin renders it by default (plain text title, no icon, never
32
+ # collapsed).
20
33
  class SidebarSection < Panel
21
34
  FILTERS_SECTION_ID = "filters_sidebar_section"
35
+ DEFAULT_ICON = :list
22
36
 
23
37
  def build(section)
24
38
  @section = section
@@ -26,7 +40,7 @@ module ActiveAdmin
26
40
  add_class @section.custom_class if @section.custom_class
27
41
  self.id = @section.id
28
42
 
29
- if @section.id == FILTERS_SECTION_ID && ActiveAdminPrism.configuration.collapsible_filters
43
+ if ActiveAdminPrism.configuration.collapsible_filters
30
44
  add_class "prism-collapsible-panel"
31
45
 
32
46
  # Panel#build already appended the plain-text @title (h3) as the
@@ -48,7 +62,7 @@ module ActiveAdmin
48
62
  # be explicitly deleted from wherever it landed before unshifting
49
63
  # it to the front — otherwise it ends up in `children` twice.
50
64
  children.delete(@title)
51
- icon = ActiveAdminPrism::Icons.svg(:filter, css_class: "prism-filter-icon")
65
+ icon = ActiveAdminPrism::Icons.svg(icon_name, css_class: "prism-filter-icon")
52
66
  contents = @contents
53
67
  @contents = nil
54
68
  new_title = h3 do
@@ -64,6 +78,21 @@ module ActiveAdmin
64
78
 
65
79
  build_sidebar_content
66
80
  end
81
+
82
+ private
83
+
84
+ # `options[:icon]` is a new convention this gem adds to the stock
85
+ # `sidebar "Title", only: [...] do ... end` DSL — ActiveAdmin::
86
+ # SidebarSection itself just stores the whole options hash
87
+ # untouched, so a host can already pass `icon:` today without any
88
+ # of their own version needing to change; it's a no-op until this
89
+ # gem starts reading it here.
90
+ def icon_name
91
+ return @section.options[:icon] if @section.options[:icon]
92
+ return :filter if @section.id == FILTERS_SECTION_ID
93
+
94
+ DEFAULT_ICON
95
+ end
67
96
  end
68
97
  end
69
98
  end
@@ -3,17 +3,21 @@
3
3
  module ActiveAdmin
4
4
  module Views
5
5
  module Pages
6
- # Reopens ActiveAdmin::Views::Pages::Base to add a dismiss ("x")
7
- # button to each flash message, and to render the configured
8
- # auto-dismiss delay as a data attribute prism.js reads at runtime
9
- # (see ActiveAdminPrism::Configuration#flash_dismissible /
6
+ # Reopens ActiveAdmin::Views::Pages::Base to render flash messages as
7
+ # floating toast cards (icon + message + dismiss button + a
8
+ # countdown progress bar) instead of ActiveAdmin's plain inline
9
+ # banner, and to render the configured auto-dismiss delay as a data
10
+ # attribute prism.js reads at runtime (see
11
+ # ActiveAdminPrism::Configuration#flash_dismissible /
10
12
  # #flash_auto_dismiss / #flash_auto_dismiss_seconds).
11
13
  #
12
14
  # The stock #build_flash_messages just renders
13
- # `div message, class: "flash flash_#{type}"` — no room for a button.
14
- # When flash_dismissible is false, that exact stock markup is what
15
- # this renders; only when it's true (the default) does the message
16
- # get wrapped with a dismiss button alongside it.
15
+ # `div message, class: "flash flash_#{type}"` — no room for an icon,
16
+ # a button, or a progress bar. When flash_dismissible is false, the
17
+ # dismiss button is dropped; the icon and (if flash_auto_dismiss is
18
+ # on) the progress bar still render either way — see
19
+ # scss-src/_base.scss for the toast styling/positioning and the
20
+ # progress bar's CSS animation.
17
21
  #
18
22
  # Auto-dismiss timing and the click handler for the dismiss button
19
23
  # both live in active_admin_prism/prism.js (CSS alone can't
@@ -22,29 +26,43 @@ module ActiveAdmin
22
26
  def build_flash_messages
23
27
  config = ActiveAdminPrism.configuration
24
28
  flashes_data = { "prism-transition-ms": config.flash_transition_ms.to_i }
25
- if config.flash_auto_dismiss
26
- flashes_data[:"prism-auto-dismiss-ms"] = (config.flash_auto_dismiss_seconds.to_f * 1000).round
27
- end
29
+ auto_dismiss_ms = config.flash_auto_dismiss_ms
30
+ flashes_data[:"prism-auto-dismiss-ms"] = auto_dismiss_ms if auto_dismiss_ms
28
31
 
29
32
  div class: "flashes", data: flashes_data do
30
33
  flash_messages.each do |type, messages|
31
34
  [*messages].each do |message|
32
- if config.flash_dismissible
33
- div class: "flash flash_#{type}" do
34
- span message, class: "prism-flash-message"
35
- button class: "prism-flash-dismiss", type: "button",
36
- "aria-label": "Dismiss", data: { "prism-flash-dismiss": true } do
37
- text_node ActiveAdminPrism::Icons.svg(:x, css_class: "prism-flash-dismiss-icon", size: 14).html_safe
38
- end
39
- end
40
- else
41
- div message, class: "flash flash_#{type}"
42
- end
35
+ build_flash(type, message, config, auto_dismiss_ms)
43
36
  end
44
37
  end
45
38
  end
46
39
  end
47
40
 
41
+ def build_flash(type, message, config, auto_dismiss_ms)
42
+ flash_options = { class: "flash flash_#{type}" }
43
+ flash_options[:style] = "--prism-flash-duration: #{auto_dismiss_ms}ms" if auto_dismiss_ms
44
+
45
+ div flash_options do
46
+ text_node flash_icon(type)
47
+ span message, class: "prism-flash-message"
48
+ if config.flash_dismissible
49
+ button class: "prism-flash-dismiss", type: "button",
50
+ "aria-label": "Dismiss", data: { "prism-flash-dismiss": true } do
51
+ text_node ActiveAdminPrism::Icons.svg(:x, css_class: "prism-flash-dismiss-icon", size: 14).html_safe
52
+ end
53
+ end
54
+ div class: "prism-flash-progress" if auto_dismiss_ms
55
+ end
56
+ end
57
+
58
+ # See lib/prism_icons.rb's ActiveAdminPrism::Icons.flash_icon_name —
59
+ # shared with the plain-ERB logged-out layout, which needs the same
60
+ # mapping but can't reach this Arbre-only method.
61
+ def flash_icon(type)
62
+ name = ActiveAdminPrism::Icons.flash_icon_name(type)
63
+ (ActiveAdminPrism::Icons.svg(name, css_class: "prism-flash-icon") || "").html_safe
64
+ end
65
+
48
66
  # Read by prism.js / scss-src's CSS to decide whether to route
49
67
  # data-confirm links through the styled dialog, whether the Filters
50
68
  # sidebar panel collapses to an icon, whether ActiveAdmin's
@@ -40,7 +40,10 @@ module ActiveAdmin
40
40
  end
41
41
 
42
42
  div class: "prism-sidebar-inner" do
43
- div(class: "prism-sidebar-brand") { site_title @namespace }
43
+ div(class: "prism-sidebar-brand") do
44
+ render_collapse_toggle if ActiveAdminPrism.configuration.sidebar_collapsible
45
+ site_title @namespace
46
+ end
44
47
  render_language_switcher if ActiveAdminPrism.configuration.language_switcher
45
48
  render_search_box if ActiveAdminPrism.configuration.menu_search
46
49
  div(class: "prism-sidebar-scroll") do
@@ -79,6 +82,27 @@ module ActiveAdmin
79
82
  ).html_safe
80
83
  end
81
84
 
85
+ # A hamburger icon button at the top of the sidebar, beside the brand
86
+ # — the same :menu icon the mobile off-canvas toggle uses, so both
87
+ # read as "the sidebar toggle" at a glance even though they're two
88
+ # separate buttons for two separate behaviors (this one only ever
89
+ # renders/matters at desktop widths; see scss-src/_sidebar.scss).
90
+ # Toggles the whole sidebar between full width and a narrow
91
+ # icon-only rail — see ActiveAdminPrism::Configuration
92
+ # #sidebar_collapsible and js-src/prism.js for the click handler
93
+ # (persists to localStorage) and scss-src/_sidebar.scss for the
94
+ # collapsed-state styling.
95
+ def render_collapse_toggle
96
+ span(
97
+ class: "prism-sidebar-collapse-toggle",
98
+ data: { "prism-toggle-sidebar-collapse": true },
99
+ role: "button", tabindex: "0", "aria-expanded": "true",
100
+ "aria-label": "Collapse sidebar"
101
+ ) do
102
+ text_node ActiveAdminPrism::Icons.svg(:menu, css_class: "prism-sidebar-collapse-icon").html_safe
103
+ end
104
+ end
105
+
82
106
  # A small "Languages" dropdown near the top of the sidebar — see
83
107
  # ActiveAdminPrism::Configuration#language_switcher/#languages. Built
84
108
  # here directly (rather than via the `admin.build_menu
@@ -191,8 +215,13 @@ module ActiveAdmin
191
215
  end
192
216
 
193
217
  def render_group_toggle(item, label)
194
- span(class: "prism-nav-group-toggle", data: { "prism-toggle": true }) do
195
- text_node icon_for(item)
218
+ # title: a plain native tooltip inert most of the time (the
219
+ # sidebar already shows this label as text), but the only way to
220
+ # identify this item by hover once ActiveAdminPrism::Configuration
221
+ # #sidebar_collapsible has shrunk the sidebar to its icon-only rail
222
+ # and .prism-nav-label itself is hidden (see scss-src/_sidebar.scss).
223
+ span(class: "prism-nav-group-toggle", data: { "prism-toggle": true }, title: label) do
224
+ text_node icon_for(item, label)
196
225
  span(label, class: "prism-nav-label")
197
226
  text_node chevron_svg
198
227
  end
@@ -201,22 +230,26 @@ module ActiveAdmin
201
230
  def render_leaf(item, label, url)
202
231
  link_options = item.html_options.except(:icon)
203
232
  link_options[:class] = ["prism-nav-link", link_options[:class]].compact.join(" ")
233
+ # Same rail-collapse tooltip as render_group_toggle above — a host's
234
+ # own explicit :title (via html_options) wins over the label.
235
+ link_options[:title] ||= label
204
236
 
205
237
  if real_url?(url)
206
238
  text_node helpers.link_to(link_body(item, label), url, **link_options)
207
239
  else
208
- span(class: "prism-nav-link") { link_body(item, label) }
240
+ span(class: "prism-nav-link", title: label) { link_body(item, label) }
209
241
  end
210
242
  end
211
243
 
212
244
  def link_body(item, label)
213
- helpers.safe_join([icon_for(item), helpers.content_tag(:span, label, class: "prism-nav-label")])
245
+ helpers.safe_join([icon_for(item, label), helpers.content_tag(:span, label, class: "prism-nav-label")])
214
246
  end
215
247
 
216
248
  # Always returns an html_safe string (possibly empty) — never escape-able
217
249
  # raw markup should cross a text_node/content_tag boundary unmarked.
218
- def icon_for(item)
250
+ def icon_for(item, label)
219
251
  name = item.html_options[:icon] || DEFAULT_ITEM_ICONS[item.id]
252
+ name ||= ActiveAdminPrism::Icons.auto_nav_icon_name(label) if ActiveAdminPrism.configuration.auto_nav_icons
220
253
  return "".html_safe unless name
221
254
 
222
255
  (ActiveAdminPrism::Icons.svg(name, css_class: "prism-nav-icon") || "").html_safe
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Views
5
+ # Reopens ActiveAdmin::Views::TitleBar purely to render
6
+ # ActiveAdminPrism::Configuration#action_items_dropdown_threshold as a
7
+ # data attribute on "#titlebar_right" — js-src/prism.js reads it at
8
+ # runtime to decide whether the action_item buttons it finds inside
9
+ # need consolidating into a dropdown (see that file, and
10
+ # scss-src/_buttons.scss for the dropdown's own styling). Nothing else
11
+ # about title bar rendering changes; this can't be done in CSS alone
12
+ # since deciding whether to consolidate depends on *counting* how many
13
+ # action_items actually rendered, not just their presence.
14
+ class TitleBar
15
+ def build_titlebar_right
16
+ config = ActiveAdminPrism.configuration
17
+ data = {}
18
+ data[:"prism-action-items-threshold"] = config.action_items_dropdown_threshold if config.action_items_dropdown
19
+
20
+ div id: "titlebar_right", data: data do
21
+ build_action_items
22
+ end
23
+ end
24
+ private :build_titlebar_right
25
+ end
26
+ end
27
+ end
@@ -161,6 +161,81 @@ module ActiveAdminPrism
161
161
  # see js-src/prism.js and vendor/select2/.
162
162
  attr_accessor :select2
163
163
 
164
+ # Whether the "current scope + active filters" summary (AA core's own
165
+ # "Search status" sidebar section, auto-added to every resource) renders
166
+ # as a compact bar above the index table instead of inside #sidebar.
167
+ # true (the default) avoids it getting squeezed/overflowing alongside
168
+ # the Filters panel when collapsible_filters is on (see
169
+ # lib/active_admin/views/active_filters_bar.rb). false restores
170
+ # ActiveAdmin's stock behavior — rendered inside #sidebar as its own
171
+ # panel, above/below the Filters form depending on registration order.
172
+ attr_accessor :active_filters_bar
173
+
174
+ # Whether a toggle button renders at the bottom of the Prism sidebar
175
+ # (below the nav/account area) that collapses it to a narrow icon-only
176
+ # rail on desktop, expanding back to full width (with labels) on
177
+ # another click — state persists across page loads via localStorage,
178
+ # the same convention already used for per-group nav expand/collapse
179
+ # state (see lib/active_admin/views/prism_sidebar.rb and js-src/prism.js).
180
+ # Purely a desktop feature: the existing off-canvas mobile toggle
181
+ # (below 900px) is unaffected either way. false renders no toggle at
182
+ # all — the sidebar is always full width, matching this gem's behavior
183
+ # before this flag existed.
184
+ attr_accessor :sidebar_collapsible
185
+
186
+ # Whether a title bar with more than #action_items_dropdown_threshold
187
+ # `action_item` buttons collapses them into a single "Actions"
188
+ # dropdown instead of rendering every one inline. A resource that
189
+ # registers many (a dozen+ CSV upload / bulk-action links is a real
190
+ # example this was built for) turns the title bar into a multi-row
191
+ # wall of buttons otherwise — see js-src/prism.js's action-items
192
+ # handler, which does the actual consolidation client-side, and
193
+ # lib/active_admin/views/title_bar.rb for the threshold this reads.
194
+ # false never consolidates — every action_item always renders inline,
195
+ # matching this gem's behavior before this flag existed.
196
+ attr_accessor :action_items_dropdown
197
+
198
+ # How many `action_item`s (not counting the auto-added "New Resource"
199
+ # button, which is never counted or consolidated — see
200
+ # lib/active_admin/views/action_items.rb) a title bar can have before
201
+ # #action_items_dropdown (if true) collapses them into a dropdown.
202
+ # Default 0 means the "Actions" Select2 dropdown is what a host sees
203
+ # by default the moment they add even a single custom action_item,
204
+ # rather than only once they've piled up "many" of them — raise this
205
+ # if you'd rather a page with just one or two extra actions kept
206
+ # rendering them inline instead.
207
+ attr_accessor :action_items_dropdown_threshold
208
+
209
+ # Whether a Pages nav item with no explicit `icon:` (and not one of
210
+ # the handful this gem itself always icons — the current-user/logout
211
+ # rows) gets one anyway instead of rendering label-less, or as just a
212
+ # bare dot once the sidebar is collapsed to its icon-only rail (see
213
+ # ActiveAdminPrism::Configuration#sidebar_collapsible). Deterministic
214
+ # per item, not re-rolled on every request — the same menu label
215
+ # always picks the same icon from lib/prism_icons.rb's
216
+ # ActiveAdminPrism::Icons::NAV_ICON_POOL (see
217
+ # lib/active_admin/views/prism_sidebar.rb#icon_for), so it doesn't
218
+ # visibly shuffle around between page loads. false renders no icon at
219
+ # all for such an item, matching this gem's behavior before this flag
220
+ # existed.
221
+ attr_accessor :auto_nav_icons
222
+
223
+ # Milliseconds equivalent of #flash_auto_dismiss_seconds, or nil when
224
+ # #flash_auto_dismiss is off — the exact number both flash-rendering
225
+ # paths this gem ships (lib/active_admin/views/flash_messages.rb's
226
+ # Arbre override for logged-in pages, and the plain-ERB
227
+ # app/views/layouts/active_admin_logged_out.html.erb for Devise's
228
+ # sign-in/password/etc pages) need to render identically: as the
229
+ # "data-prism-auto-dismiss-ms" attribute js-src/prism.js reads to
230
+ # schedule removal, and as each flash's own
231
+ # "--prism-flash-duration" inline style the countdown bar
232
+ # (scss-src/_base.scss's ".prism-flash-progress") animates against.
233
+ def flash_auto_dismiss_ms
234
+ return nil unless flash_auto_dismiss
235
+
236
+ (flash_auto_dismiss_seconds.to_f * 1000).round
237
+ end
238
+
164
239
  def initialize
165
240
  @sidebar = true
166
241
  @colorize_action_icons = true
@@ -183,6 +258,11 @@ module ActiveAdminPrism
183
258
  ]
184
259
  @menu_search = true
185
260
  @select2 = false
261
+ @active_filters_bar = true
262
+ @sidebar_collapsible = true
263
+ @action_items_dropdown = true
264
+ @action_items_dropdown_threshold = 0
265
+ @auto_nav_icons = true
186
266
  end
187
267
  end
188
268
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveAdminPrism
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
@@ -12,6 +12,9 @@ require_relative "active_admin/views/prism_sidebar"
12
12
  require_relative "active_admin/views/index_table_actions"
13
13
  require_relative "active_admin/views/flash_messages"
14
14
  require_relative "active_admin/views/filters_sidebar"
15
+ require_relative "active_admin/views/active_filters_bar"
16
+ require_relative "active_admin/views/title_bar"
17
+ require_relative "active_admin/views/action_items"
15
18
  require_relative "formtastic/inputs/prism_toggle_input"
16
19
 
17
20
  module ActiveAdminPrism
data/lib/prism_icons.rb CHANGED
@@ -36,9 +36,34 @@ module ActiveAdminPrism
36
36
  '<path d="M10 11v6M14 11v6"/>',
37
37
  filter: '<path d="M4 5h16l-6.5 7.5v6l-3 1.5v-7.5Z"/>',
38
38
  globe: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18"/>' \
39
- '<path d="M12 3c2.5 2.4 4 5.6 4 9s-1.5 6.6-4 9c-2.5-2.4-4-5.6-4-9s1.5-6.6 4-9Z"/>'
39
+ '<path d="M12 3c2.5 2.4 4 5.6 4 9s-1.5 6.6-4 9c-2.5-2.4-4-5.6-4-9s1.5-6.6 4-9Z"/>',
40
+ check_circle: '<circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.5 2.5L16 9"/>',
41
+ alert_circle: '<circle cx="12" cy="12" r="9"/><path d="M12 7.5v6"/><circle cx="12" cy="16.5" r="0.1" fill="currentColor" stroke-width="2.5"/>',
42
+ alert_triangle: '<path d="M12 4 2.5 20h19L12 4Z"/><path d="M12 10v4.5"/><circle cx="12" cy="17.2" r="0.1" fill="currentColor" stroke-width="2.5"/>',
43
+ info: '<circle cx="12" cy="12" r="9"/><path d="M12 11v5.5"/><circle cx="12" cy="7.8" r="0.1" fill="currentColor" stroke-width="2.5"/>'
40
44
  }.freeze
41
45
 
46
+ # Candidates for ActiveAdminPrism::Configuration#auto_nav_icons — a
47
+ # generic-enough subset of ICONS above that any of them reads as
48
+ # plausible next to an arbitrary menu label (excludes chevron_down,
49
+ # check/x, the alert/info trio and logout: purpose-specific shapes
50
+ # that would look wrong or actively misleading picked at random for,
51
+ # say, a "Reports" link).
52
+ NAV_ICON_POOL = %i[
53
+ dashboard users cart box receipt credit_card message settings
54
+ home list folder bell search globe eye pencil filter
55
+ ].freeze
56
+
57
+ # Deterministic, not actually random — the same `label` always maps
58
+ # to the same icon (a simple sum-of-bytes hash, stable across
59
+ # processes/restarts unlike Ruby's own salted String#hash), so a
60
+ # nav item's auto-picked icon doesn't visibly shuffle between page
61
+ # loads. See lib/active_admin/views/prism_sidebar.rb#icon_for, the
62
+ # only caller.
63
+ def self.auto_nav_icon_name(label)
64
+ NAV_ICON_POOL[label.to_s.each_byte.sum % NAV_ICON_POOL.length]
65
+ end
66
+
42
67
  # Returns an inline <svg>...</svg> string for `name`, or nil if unknown.
43
68
  def self.svg(name, css_class: "prism-icon", size: 18)
44
69
  inner = ICONS[name.to_sym]
@@ -49,6 +74,27 @@ module ActiveAdminPrism
49
74
  %(stroke-linejoin="round" aria-hidden="true">#{inner}</svg>)
50
75
  end
51
76
 
77
+ # Maps a flash's key (Rails' own :notice/:alert conventions, plus
78
+ # :error/:warning/:success/:info as an app might set directly) to one
79
+ # of the four icons above — anything else (a host's own custom flash
80
+ # key) falls back to the neutral :info icon rather than none at all.
81
+ # Shared by both flash-rendering paths this gem ships: the Arbre-based
82
+ # one for logged-in pages (lib/active_admin/views/flash_messages.rb)
83
+ # and the plain-ERB logged-out layout (app/views/layouts/
84
+ # active_admin_logged_out.html.erb) — Devise's sign-in/password/etc
85
+ # pages render through a completely separate layout ActiveAdmin
86
+ # itself ships, not through Pages::Base/Arbre at all, so that
87
+ # Ruby-side override alone never reaches them.
88
+ FLASH_ICONS = {
89
+ notice: :check_circle, success: :check_circle,
90
+ alert: :alert_triangle, warning: :alert_triangle,
91
+ error: :alert_circle
92
+ }.freeze
93
+
94
+ def self.flash_icon_name(type)
95
+ FLASH_ICONS[type.to_sym] || :info
96
+ end
97
+
52
98
  # The default sign-in page mark (see ActiveAdminPrism::Configuration
53
99
  # #login_logo) — a generic glass-prism-with-spectrum motif distinct from
54
100
  # the 24x24 line-icon set above (bigger, multi-color, animated via