active_admin_prism 0.1.0

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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +133 -0
  3. data/INTEGRATION.md +1012 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +319 -0
  6. data/app/assets/javascripts/active_admin_prism/prism.js +1 -0
  7. data/app/assets/stylesheets/active_admin_prism/_variable_overrides.scss +43 -0
  8. data/app/assets/stylesheets/active_admin_prism/prism.css +1 -0
  9. data/app/views/active_admin/devise/confirmations/new.html.erb +26 -0
  10. data/app/views/active_admin/devise/passwords/edit.html.erb +29 -0
  11. data/app/views/active_admin/devise/passwords/new.html.erb +26 -0
  12. data/app/views/active_admin/devise/registrations/new.html.erb +32 -0
  13. data/app/views/active_admin/devise/sessions/new.html.erb +37 -0
  14. data/app/views/active_admin/devise/shared/_brand.html.erb +34 -0
  15. data/app/views/active_admin/devise/unlocks/new.html.erb +25 -0
  16. data/js-src/prism.js +270 -0
  17. data/lib/active_admin/views/filters_sidebar.rb +69 -0
  18. data/lib/active_admin/views/flash_messages.rb +77 -0
  19. data/lib/active_admin/views/index_table_actions.rb +46 -0
  20. data/lib/active_admin/views/prism_sidebar.rb +212 -0
  21. data/lib/active_admin_prism/configuration.rb +180 -0
  22. data/lib/active_admin_prism/engine.rb +18 -0
  23. data/lib/active_admin_prism/version.rb +5 -0
  24. data/lib/active_admin_prism.rb +33 -0
  25. data/lib/formtastic/inputs/prism_toggle_input.rb +31 -0
  26. data/lib/generators/active_admin_prism/error_pages/error_pages_generator.rb +49 -0
  27. data/lib/generators/active_admin_prism/error_pages/templates/404.html +164 -0
  28. data/lib/generators/active_admin_prism/error_pages/templates/500.html +173 -0
  29. data/lib/generators/active_admin_prism/install/install_generator.rb +69 -0
  30. data/lib/prism_icons.rb +82 -0
  31. data/lib/prism_login_helper.rb +31 -0
  32. data/lib/prism_toggle_tag.rb +35 -0
  33. data/scss-src/_base.scss +281 -0
  34. data/scss-src/_buttons.scss +134 -0
  35. data/scss-src/_forms.scss +272 -0
  36. data/scss-src/_icons.scss +27 -0
  37. data/scss-src/_login.scss +306 -0
  38. data/scss-src/_panels.scss +249 -0
  39. data/scss-src/_sidebar.scss +479 -0
  40. data/scss-src/_tables.scss +142 -0
  41. data/scss-src/_variables.scss +101 -0
  42. data/scss-src/prism.scss +15 -0
  43. metadata +157 -0
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Views
5
+ # Renders ActiveAdmin's existing Menu/MenuItem data (built by the
6
+ # standard `menu do |m| ... end` DSL in app/admin/*.rb, untouched) as a
7
+ # collapsible left sidebar instead of the default top nav bar.
8
+ #
9
+ # This is a drop-in replacement for ActiveAdmin::Views::Header: its
10
+ # #build(namespace, menu) signature matches Header#build exactly, so it
11
+ # can be swapped in via the supported extension point
12
+ #
13
+ # ActiveAdmin::ViewFactory.register(header: ActiveAdmin::Views::PrismSidebar)
14
+ #
15
+ # (see ActiveAdminPrism.enable!) without touching Pages::Base or any
16
+ # layout template.
17
+ #
18
+ # It does not reuse ActiveAdmin::Views::Menu/MenuItem's Arbre builder
19
+ # verbs (`menu`/`menu_item`) because those are shared globally with
20
+ # ActiveAdmin::Views::TabbedNavigation; walking the ActiveAdmin::Menu
21
+ # data structure directly here keeps this theme fully isolated from
22
+ # anything else that might rely on the stock nav rendering.
23
+ class PrismSidebar < Component
24
+ # Fallback icons for ActiveAdmin's own default utility-nav items
25
+ # (id: "current_user" / id: "logout", added by
26
+ # Namespace#build_default_utility_nav) when the host hasn't set one
27
+ # explicitly via html_options: { icon: ... }.
28
+ DEFAULT_ITEM_ICONS = { "current_user" => :users, "logout" => :logout }.freeze
29
+
30
+ def build(namespace, menu)
31
+ super(id: "header", class: "prism-sidebar")
32
+
33
+ @namespace = namespace
34
+ @menu = menu
35
+ @utility_menu = namespace.fetch_menu(:utility_navigation)
36
+ @current_tab = assigns[:current_tab]
37
+
38
+ span(class: "prism-sidebar-mobile-toggle", data: { "prism-toggle-sidebar": true }) do
39
+ text_node ActiveAdminPrism::Icons.svg(:menu, css_class: "prism-nav-icon").html_safe
40
+ end
41
+
42
+ div class: "prism-sidebar-inner" do
43
+ div(class: "prism-sidebar-brand") { site_title @namespace }
44
+ render_language_switcher if ActiveAdminPrism.configuration.language_switcher
45
+ div(class: "prism-sidebar-scroll") do
46
+ div "Pages", class: "prism-nav-section-label"
47
+ render_menu @menu, class: "prism-nav"
48
+ end
49
+ if @utility_menu.items.any?
50
+ div(class: "prism-sidebar-utility") do
51
+ render_menu @utility_menu, class: "prism-nav prism-nav-utility"
52
+ end
53
+ end
54
+ if ActiveAdminPrism.configuration.sidebar_footer
55
+ div(class: "prism-sidebar-footer") { text_node footer_message }
56
+ end
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ # Same content ActiveAdmin::Views::Footer renders into the page's own
63
+ # #footer (custom config.footer text, or the default "Powered by
64
+ # Active Admin X.Y.Z") — moved here instead, so it's pinned below the
65
+ # nav/account area rather than trailing after the main content. The
66
+ # original #footer is hidden via CSS (scss-src/_sidebar.scss) rather
67
+ # than suppressed here, since Pages::Base#build_page always renders it
68
+ # and overriding that too is more surface area than a display:none.
69
+ def footer_message
70
+ custom = @namespace.footer(self)
71
+ return custom.html_safe if custom.present?
72
+
73
+ helpers.t(
74
+ "active_admin.powered_by",
75
+ active_admin: helpers.link_to("Active Admin", "https://activeadmin.info"),
76
+ version: ActiveAdmin::VERSION
77
+ ).html_safe
78
+ end
79
+
80
+ # A small "Languages" dropdown near the top of the sidebar — see
81
+ # ActiveAdminPrism::Configuration#language_switcher/#languages. Built
82
+ # here directly (rather than via the `admin.build_menu
83
+ # :utility_navigation do |menu| ... end` pattern ActiveAdmin apps
84
+ # normally use for this by hand) so it needs no per-namespace
85
+ # initializer code and stays in sync with runtime config changes —
86
+ # every render reads the current config, the same as
87
+ # sidebar_footer/collapsible_filters elsewhere in this gem.
88
+ def render_language_switcher
89
+ languages = ActiveAdminPrism.configuration.languages
90
+ return if languages.blank?
91
+
92
+ current = languages.find { |lang| lang[:locale].to_s == I18n.locale.to_s } || languages.first
93
+
94
+ div(class: "prism-sidebar-lang") do
95
+ span(class: "prism-lang-toggle", data: { "prism-toggle-lang": true }, "aria-expanded": "false") do
96
+ text_node ActiveAdminPrism::Icons.svg(:globe, css_class: "prism-nav-icon").html_safe
97
+ span(current[:label], class: "prism-lang-current")
98
+ text_node chevron_svg
99
+ end
100
+
101
+ ul(class: "prism-lang-menu") do
102
+ languages.each do |lang|
103
+ classes = ["prism-lang-option"]
104
+ classes << "active" if lang == current
105
+
106
+ li do
107
+ text_node helpers.link_to(lang[:label], language_url(lang), class: classes.join(" "))
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ # Each language entry's own :url (String/Proc/Symbol — same
115
+ # nil/String/Proc/Symbol convention as config.login_logo etc.,
116
+ # evaluated the same way item.url is above) wins when given, e.g. to
117
+ # hit a remote endpoint that switches the locale server-side before
118
+ # redirecting back:
119
+ #
120
+ # { label: "English", locale: :en,
121
+ # url: -> { "https://example.com/set_locale?locale=en&return_to=#{request.path}" } }
122
+ #
123
+ # With no :url, this defaults to url_for(locale: lang[:locale]) —
124
+ # appending "?locale=xx" to the *current* page, the same convention
125
+ # ActiveAdmin apps already reach for by hand for this (see the
126
+ # `url: proc { url_for(locale: l.locale) }` pattern in a hand-rolled
127
+ # `admin.build_menu :utility_navigation` block).
128
+ def language_url(lang)
129
+ return evaluated(lang[:url]) if lang[:url]
130
+
131
+ helpers.url_for(locale: lang[:locale])
132
+ end
133
+
134
+ def render_menu(menu_node, html_options = {})
135
+ ul(html_options) do
136
+ visible_items(menu_node).each { |item| render_item(item) }
137
+ end
138
+ end
139
+
140
+ def visible_items(menu_node)
141
+ menu_node.items
142
+ .select { |item| helpers.render_in_context(self, item.should_display) }
143
+ .sort_by { |item| [item.priority, evaluated(item.label).to_s] }
144
+ end
145
+
146
+ def render_item(item)
147
+ label = evaluated(item.label)
148
+ url = evaluated(item.url)
149
+ has_children = item.items.any?
150
+ active = item.current?(@current_tab)
151
+
152
+ classes = ["prism-nav-item"]
153
+ classes << "has-children" if has_children
154
+ classes << "active" if active
155
+ classes << "open" if has_children && active
156
+
157
+ li(id: "prism_nav_#{item.id}", class: classes.join(" ")) do
158
+ if has_children
159
+ render_group_toggle(item, label)
160
+ render_menu item, class: "prism-nav-submenu"
161
+ else
162
+ render_leaf(item, label, url)
163
+ end
164
+ end
165
+ end
166
+
167
+ def render_group_toggle(item, label)
168
+ span(class: "prism-nav-group-toggle", data: { "prism-toggle": true }) do
169
+ text_node icon_for(item)
170
+ span(label, class: "prism-nav-label")
171
+ text_node chevron_svg
172
+ end
173
+ end
174
+
175
+ def render_leaf(item, label, url)
176
+ link_options = item.html_options.except(:icon)
177
+ link_options[:class] = ["prism-nav-link", link_options[:class]].compact.join(" ")
178
+
179
+ if real_url?(url)
180
+ text_node helpers.link_to(link_body(item, label), url, **link_options)
181
+ else
182
+ span(class: "prism-nav-link") { link_body(item, label) }
183
+ end
184
+ end
185
+
186
+ def link_body(item, label)
187
+ helpers.safe_join([icon_for(item), helpers.content_tag(:span, label, class: "prism-nav-label")])
188
+ end
189
+
190
+ # Always returns an html_safe string (possibly empty) — never escape-able
191
+ # raw markup should cross a text_node/content_tag boundary unmarked.
192
+ def icon_for(item)
193
+ name = item.html_options[:icon] || DEFAULT_ITEM_ICONS[item.id]
194
+ return "".html_safe unless name
195
+
196
+ (ActiveAdminPrism::Icons.svg(name, css_class: "prism-nav-icon") || "").html_safe
197
+ end
198
+
199
+ def chevron_svg
200
+ ActiveAdminPrism::Icons.svg(:chevron_down, css_class: "prism-chevron").html_safe
201
+ end
202
+
203
+ def evaluated(value)
204
+ helpers.render_in_context(self, value)
205
+ end
206
+
207
+ def real_url?(url)
208
+ url.present? && url != "#"
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdminPrism
4
+ # Per-feature toggles, so a host can turn off individual pieces of the
5
+ # theme without forking it. Every flag defaults to the theme's normal,
6
+ # fully-on behavior — an app that never touches this class gets exactly
7
+ # what it got before this class existed.
8
+ #
9
+ # ActiveAdminPrism.configure do |config|
10
+ # config.sidebar = false # keep AA's stock top nav
11
+ # config.colorize_action_icons = false # plain text View/Edit/Delete
12
+ # config.flash_auto_dismiss_seconds = 8
13
+ # end
14
+ #
15
+ # `sidebar` and `colorize_action_icons` are pure server-side toggles
16
+ # (they just change what Ruby renders). `sidebar_footer` is server-side
17
+ # for whether the sidebar renders its own footer, plus a body class (like
18
+ # `styled_confirms`/`collapsible_filters`) so the CSS knows whether to
19
+ # keep hiding ActiveAdmin's original #footer. The flash_* flags are read
20
+ # by the client-side prism.js via data attributes on ".flashes". See
21
+ # lib/active_admin/views/flash_messages.rb for all of the body
22
+ # class/data-attribute rendering.
23
+ class Configuration
24
+ # Whether ActiveAdminPrism.enable! swaps ActiveAdmin's top nav for
25
+ # the Prism sidebar. Set to false to keep AA's stock header/TabbedNavigation
26
+ # while still getting the rest of the theme (panels, tables, forms,
27
+ # buttons, icons, flash/confirm styling) — useful for adopting Prism
28
+ # incrementally, or reverting just the navigation without uninstalling
29
+ # the gem.
30
+ attr_accessor :sidebar
31
+
32
+ # Whether index-table View/Edit/Delete links render as color-coded icon
33
+ # buttons (see lib/active_admin/views/index_table_actions.rb). false
34
+ # falls back to ActiveAdmin's plain text links.
35
+ attr_accessor :colorize_action_icons
36
+
37
+ # Whether row-level data-confirm links (View/Edit/Delete, or any other
38
+ # rails-ujs confirm) are routed through ActiveAdmin's own styled jQuery
39
+ # UI dialog instead of the native browser confirm(). Batch Actions
40
+ # confirms are unaffected either way — they always use that dialog.
41
+ attr_accessor :styled_confirms
42
+
43
+ # Whether flash messages get a dismiss ("x") button.
44
+ attr_accessor :flash_dismissible
45
+
46
+ # Whether flash messages disappear on their own after
47
+ # flash_auto_dismiss_seconds. Set to false to require a manual dismiss
48
+ # (or, if flash_dismissible is also false, to leave them on screen
49
+ # until the next page load, matching ActiveAdmin's own default).
50
+ attr_accessor :flash_auto_dismiss
51
+ attr_accessor :flash_auto_dismiss_seconds
52
+
53
+ # How long the fade/slide-out transition takes (in milliseconds) when a
54
+ # flash is dismissed — manually or automatically. Rendered as a data
55
+ # attribute and read by prism.js, which sets it as an inline
56
+ # transition-duration and uses the same value to time the element's
57
+ # actual removal from the DOM, so the two always stay in sync.
58
+ attr_accessor :flash_transition_ms
59
+
60
+ # Whether ActiveAdmin's "Filters" sidebar panel starts collapsed to a
61
+ # single icon button, expanding to the full form on click. false shows
62
+ # it fully expanded at all times, matching ActiveAdmin's own default.
63
+ attr_accessor :collapsible_filters
64
+
65
+ # Whether "Powered by Active Admin" (or your own config.footer text)
66
+ # moves from ActiveAdmin's page-level #footer into the sidebar, pinned
67
+ # below the account/logout area. false leaves the original #footer
68
+ # visible in its normal place instead (ActiveAdmin's own default).
69
+ attr_accessor :sidebar_footer
70
+
71
+ # Whether the sign-in page (Devise's sessions#new) gets Prism's
72
+ # centered-card/brand-mark treatment. false renders ActiveAdmin's
73
+ # original plain gradient-header login box instead (see
74
+ # app/views/active_admin/devise/sessions/new.html.erb).
75
+ attr_accessor :login_page
76
+
77
+ # Customizes the mark shown above the sign-in form. One of:
78
+ # nil - Prism's own built-in mark (default)
79
+ # String - raw HTML, e.g. a pre-rendered image_tag/svg — used as-is,
80
+ # so make sure it's from a trusted source (html_safe)
81
+ # Proc - instance_exec'd in the view's own context (so helpers like
82
+ # `image_tag`/`prism_icon` are available), e.g.:
83
+ # config.login_logo = -> { image_tag "logo.svg", height: 40 }
84
+ # Symbol - a method name called on the view context
85
+ # Same nil/String/Proc/Symbol convention ActiveAdmin itself uses for
86
+ # config.footer / config.site_title_image.
87
+ attr_accessor :login_logo
88
+
89
+ # The name/title shown on the sign-in page. nil (default) falls back to
90
+ # ActiveAdmin's own `config.site_title`. Accepts a String, Proc, or
91
+ # Symbol — same convention as login_logo.
92
+ attr_accessor :login_app_name
93
+
94
+ # The line of text shown under the title on the sign-in page. nil means
95
+ # no tagline is rendered. Accepts a String, Proc, or Symbol — same
96
+ # convention as login_logo.
97
+ attr_accessor :login_tagline
98
+
99
+ # Whether a "Languages" dropdown renders near the top of the sidebar
100
+ # (below the brand, above the Pages nav), letting a visitor switch
101
+ # `locale` without your own `admin.build_menu :utility_navigation` code
102
+ # — see lib/active_admin/views/prism_sidebar.rb for the actual link
103
+ # (`url_for(locale: ...)`, the same query-param convention ActiveAdmin
104
+ # apps already use for this by hand). false renders no dropdown at all.
105
+ attr_accessor :language_switcher
106
+
107
+ # The options the dropdown lists — an array of
108
+ # `{ label:, locale:, url: }` hashes (`url:` is optional). Defaults to
109
+ # 3 common ones; replace the whole array to add, remove, or reorder
110
+ # languages:
111
+ #
112
+ # ActiveAdminPrism.configure do |config|
113
+ # config.languages = [
114
+ # { label: "English", locale: :en },
115
+ # { label: "Deutsch", locale: :de },
116
+ # { label: "日本語", locale: :ja,
117
+ # url: -> { "https://example.com/set_locale?locale=ja&return_to=#{request.path}" } }
118
+ # ]
119
+ # end
120
+ #
121
+ # `url:` accepts a String, Proc, or Symbol (same nil/String/Proc/Symbol
122
+ # convention as login_logo, evaluated the same way an
123
+ # ActiveAdmin::MenuItem's own `url:` proc is — bare `url_for`/`request`/
124
+ # any other view helper is available inside it, same as in the
125
+ # `url: proc { url_for(locale: l.locale) }` pattern an ActiveAdmin app
126
+ # already reaches for by hand for this). With no `url:`, this defaults
127
+ # to `url_for(locale: lang[:locale])` — appending `?locale=xx` to the
128
+ # *current* page. Use `url:` when switching locale needs to hit a
129
+ # remote/dedicated endpoint (e.g. one that sets a cookie or session key
130
+ # and redirects back) rather than just changing a query param on the
131
+ # current URL.
132
+ #
133
+ # This only renders the switcher itself — actually honoring the
134
+ # `locale` param (e.g. a `before_action { I18n.locale = params[:locale]
135
+ # || I18n.default_locale }`) is your own app's responsibility, the same
136
+ # as it would be if you'd wired up the utility_navigation menu by hand.
137
+ attr_accessor :languages
138
+
139
+ def initialize
140
+ @sidebar = true
141
+ @colorize_action_icons = true
142
+ @styled_confirms = true
143
+ @flash_dismissible = true
144
+ @flash_auto_dismiss = true
145
+ @flash_auto_dismiss_seconds = 5
146
+ @flash_transition_ms = 320
147
+ @collapsible_filters = true
148
+ @sidebar_footer = true
149
+ @login_page = true
150
+ @login_logo = nil
151
+ @login_app_name = nil
152
+ @login_tagline = "Sign in to your admin dashboard"
153
+ @language_switcher = true
154
+ @languages = [
155
+ { label: "English", locale: :en },
156
+ { label: "Español", locale: :es },
157
+ { label: "Français", locale: :fr }
158
+ ]
159
+ end
160
+ end
161
+
162
+ class << self
163
+ # @return [ActiveAdminPrism::Configuration]
164
+ def configuration
165
+ @configuration ||= Configuration.new
166
+ end
167
+
168
+ # ActiveAdminPrism.configure do |config|
169
+ # config.sidebar = false
170
+ # end
171
+ def configure
172
+ yield(configuration)
173
+ end
174
+
175
+ # Mainly for test suites: resets every flag back to its default.
176
+ def reset_configuration!
177
+ @configuration = Configuration.new
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdminPrism
4
+ class Engine < ::Rails::Engine
5
+ engine_name "active_admin_prism"
6
+
7
+ # Must run before ActiveAdmin's own "active_admin.precompile" initializer,
8
+ # which copies every registered stylesheet/javascript path into
9
+ # app.config.assets.precompile. Registering here means a host app never
10
+ # has to touch config.assets.precompile or add a manifest line itself.
11
+ initializer "active_admin_prism.register_assets", before: "active_admin.precompile" do
12
+ next unless defined?(ActiveAdmin)
13
+
14
+ ActiveAdmin.application.register_stylesheet "active_admin_prism/prism.css", media: "all"
15
+ ActiveAdmin.application.register_javascript "active_admin_prism/prism.js"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdminPrism
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_admin"
4
+
5
+ require_relative "active_admin_prism/version"
6
+ require_relative "active_admin_prism/configuration"
7
+ require_relative "active_admin_prism/engine"
8
+ require_relative "prism_icons"
9
+ require_relative "prism_toggle_tag"
10
+ require_relative "prism_login_helper"
11
+ require_relative "active_admin/views/prism_sidebar"
12
+ require_relative "active_admin/views/index_table_actions"
13
+ require_relative "active_admin/views/flash_messages"
14
+ require_relative "active_admin/views/filters_sidebar"
15
+ require_relative "formtastic/inputs/prism_toggle_input"
16
+
17
+ module ActiveAdminPrism
18
+ class Error < StandardError; end
19
+
20
+ # Swaps ActiveAdmin's default top navigation ("header") for Prism's
21
+ # collapsible left sidebar, unless disabled via
22
+ # `configure { |c| c.sidebar = false }`. Call once from
23
+ # config/initializers/active_admin.rb (the install generator does this
24
+ # automatically).
25
+ #
26
+ # This is a supported ActiveAdmin extension point, not a monkeypatch: see
27
+ # ActiveAdmin::ViewFactory / AbstractViewFactory#add_writer, which wires the
28
+ # "header" builder verb used by ActiveAdmin::Views::Pages::Base#build_page.
29
+ def self.enable!
30
+ ActiveAdmin::ViewFactory.register(header: ActiveAdmin::Views::PrismSidebar) if configuration.sidebar
31
+ true
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formtastic
4
+ module Inputs
5
+ # An opt-in boolean input rendered as an iOS-style switch instead of a
6
+ # checkbox, matching the "Toggle switches" section of the Prism theme.
7
+ #
8
+ # f.input :active, as: :prism_toggle
9
+ #
10
+ # Reuses BooleanInput's hidden-field/checked-value/name logic verbatim —
11
+ # only the wrapping markup changes, so submitted params are identical to
12
+ # a normal `as: :boolean` input.
13
+ class PrismToggleInput < Formtastic::Inputs::BooleanInput
14
+ def label_with_nested_checkbox
15
+ builder.label(
16
+ method,
17
+ check_box_html + template.content_tag(:span, "", class: "prism-toggle-track") + label_text,
18
+ label_html_options
19
+ )
20
+ end
21
+
22
+ def input_html_options
23
+ super.merge(class: [super[:class], "prism-toggle-input"].reject(&:blank?).join(" "))
24
+ end
25
+
26
+ def label_html_options
27
+ super.merge(class: [super[:class], "prism-toggle"].reject(&:blank?).join(" "))
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdminPrism
4
+ module Generators
5
+ # rails g active_admin_prism:error_pages
6
+ #
7
+ # Copies Prism-styled public/404.html and public/500.html into this
8
+ # app. Unlike the rest of the theme, static exception pages
9
+ # (config.exceptions_app's default, ActionDispatch::PublicExceptions)
10
+ # are read straight off disk from Rails.public_path, completely
11
+ # outside the asset pipeline and Rails' view-resolution/engine-view-path
12
+ # mechanism — there's no way for a gem to "register" or override them
13
+ # the way ActiveAdminPrism::Engine registers stylesheets/
14
+ # javascripts, or the way this gem's own sign-in page view shadows
15
+ # ActiveAdmin's. Copying them into the host app (the same way `rails
16
+ # new` scaffolds its own default public/404.html) is the only option.
17
+ #
18
+ # Not run automatically by the `install` generator, unlike everything
19
+ # else in this theme: a host's public/404.html and public/500.html are
20
+ # typically already customized/committed, and silently overwriting them
21
+ # (or ambushing an unrelated `install` run with copy_file's overwrite
22
+ # prompt) would be surprising. This is an explicit, separate opt-in.
23
+ #
24
+ # These are plain static HTML/CSS, not ERB — no Ruby config, no
25
+ # ActiveAdminPrism::Configuration flag, and no @import of
26
+ # prism.css (impossible for a file with no Rails request cycle behind
27
+ # it). Edit the copied files directly for any further changes; a
28
+ # future gem upgrade never touches them again once copied.
29
+ class ErrorPagesGenerator < ::Rails::Generators::Base
30
+ desc "Copies Prism-styled public/404.html and public/500.html into this app"
31
+
32
+ source_root File.expand_path("templates", __dir__)
33
+
34
+ def copy_error_pages
35
+ copy_file "404.html", "public/404.html"
36
+ copy_file "500.html", "public/500.html"
37
+ end
38
+
39
+ def show_notes
40
+ say_status :note,
41
+ "these are plain static files now living in public/ — edit them " \
42
+ "directly for further changes, and re-run this generator " \
43
+ "(it will prompt before overwriting) to pick up a newer version " \
44
+ "of the gem's default templates",
45
+ :yellow
46
+ end
47
+ end
48
+ end
49
+ end