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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +133 -0
- data/INTEGRATION.md +1012 -0
- data/LICENSE.txt +21 -0
- data/README.md +319 -0
- data/app/assets/javascripts/active_admin_prism/prism.js +1 -0
- data/app/assets/stylesheets/active_admin_prism/_variable_overrides.scss +43 -0
- data/app/assets/stylesheets/active_admin_prism/prism.css +1 -0
- data/app/views/active_admin/devise/confirmations/new.html.erb +26 -0
- data/app/views/active_admin/devise/passwords/edit.html.erb +29 -0
- data/app/views/active_admin/devise/passwords/new.html.erb +26 -0
- data/app/views/active_admin/devise/registrations/new.html.erb +32 -0
- data/app/views/active_admin/devise/sessions/new.html.erb +37 -0
- data/app/views/active_admin/devise/shared/_brand.html.erb +34 -0
- data/app/views/active_admin/devise/unlocks/new.html.erb +25 -0
- data/js-src/prism.js +270 -0
- data/lib/active_admin/views/filters_sidebar.rb +69 -0
- data/lib/active_admin/views/flash_messages.rb +77 -0
- data/lib/active_admin/views/index_table_actions.rb +46 -0
- data/lib/active_admin/views/prism_sidebar.rb +212 -0
- data/lib/active_admin_prism/configuration.rb +180 -0
- data/lib/active_admin_prism/engine.rb +18 -0
- data/lib/active_admin_prism/version.rb +5 -0
- data/lib/active_admin_prism.rb +33 -0
- data/lib/formtastic/inputs/prism_toggle_input.rb +31 -0
- data/lib/generators/active_admin_prism/error_pages/error_pages_generator.rb +49 -0
- data/lib/generators/active_admin_prism/error_pages/templates/404.html +164 -0
- data/lib/generators/active_admin_prism/error_pages/templates/500.html +173 -0
- data/lib/generators/active_admin_prism/install/install_generator.rb +69 -0
- data/lib/prism_icons.rb +82 -0
- data/lib/prism_login_helper.rb +31 -0
- data/lib/prism_toggle_tag.rb +35 -0
- data/scss-src/_base.scss +281 -0
- data/scss-src/_buttons.scss +134 -0
- data/scss-src/_forms.scss +272 -0
- data/scss-src/_icons.scss +27 -0
- data/scss-src/_login.scss +306 -0
- data/scss-src/_panels.scss +249 -0
- data/scss-src/_sidebar.scss +479 -0
- data/scss-src/_tables.scss +142 -0
- data/scss-src/_variables.scss +101 -0
- data/scss-src/prism.scss +15 -0
- metadata +157 -0
data/INTEGRATION.md
ADDED
|
@@ -0,0 +1,1012 @@
|
|
|
1
|
+
# Prism integration guide
|
|
2
|
+
|
|
3
|
+
A complete walkthrough of installing, configuring, and — if you ever need
|
|
4
|
+
to — switching off `active_admin_prism` in a Rails app. For a quick
|
|
5
|
+
start, see [README.md](README.md); this document goes deeper on every
|
|
6
|
+
option and the reasoning behind it.
|
|
7
|
+
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
- [Requirements](#requirements)
|
|
11
|
+
- [Install](#install)
|
|
12
|
+
- [Manual install](#manual-install)
|
|
13
|
+
- [Verifying the install](#verifying-the-install)
|
|
14
|
+
- [Configuration reference](#configuration-reference)
|
|
15
|
+
- [Plug-and-play: switching the theme on/off](#plug-and-play-switching-the-theme-onoff)
|
|
16
|
+
- [Feature guide](#feature-guide)
|
|
17
|
+
- [Error pages (404/500)](#error-pages-404500)
|
|
18
|
+
- [Markup & CSS class reference](#markup--css-class-reference)
|
|
19
|
+
- [Customizing colors](#customizing-colors)
|
|
20
|
+
- [Troubleshooting](#troubleshooting)
|
|
21
|
+
- [Upgrading](#upgrading)
|
|
22
|
+
- [Uninstalling](#uninstalling)
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
- ActiveAdmin `>= 3.0, < 4`
|
|
27
|
+
- Rails `>= 7.0`
|
|
28
|
+
- Ruby `>= 3.1`
|
|
29
|
+
- Sprockets or Propshaft asset pipeline (the theme ships precompiled CSS/JS;
|
|
30
|
+
no Sass compiler or JS bundler is required to install it). If your app
|
|
31
|
+
has its own `app/assets/stylesheets/active_admin.scss` (i.e. you ran
|
|
32
|
+
`rails g active_admin:assets`, the Sprockets/Sass path — not
|
|
33
|
+
Webpacker/importmap), you get one extra, automatic benefit: see
|
|
34
|
+
[Customizing colors](#customizing-colors).
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
# Gemfile
|
|
40
|
+
gem "active_admin_prism"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
bundle install
|
|
45
|
+
rails g active_admin_prism:install
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The generator makes two changes, both idempotent (safe to run more than
|
|
49
|
+
once):
|
|
50
|
+
|
|
51
|
+
1. Appends `ActiveAdminPrism.enable!` to
|
|
52
|
+
`config/initializers/active_admin.rb`. This is what swaps ActiveAdmin's
|
|
53
|
+
top nav bar for the Prism sidebar (unless you've disabled that — see
|
|
54
|
+
[Configuration reference](#configuration-reference)).
|
|
55
|
+
2. If `app/assets/stylesheets/active_admin.scss` exists, injects
|
|
56
|
+
`@import "active_admin_prism/variable_overrides";` immediately
|
|
57
|
+
before `@import "active_admin/mixins";`. This brings ActiveAdmin's own
|
|
58
|
+
default gray palette onto Prism's colors at the source — see
|
|
59
|
+
[Customizing colors](#customizing-colors) for why this matters.
|
|
60
|
+
|
|
61
|
+
Nothing else is required. The theme's CSS/JS are registered automatically
|
|
62
|
+
by the gem's `Rails::Engine` — there's no manifest to edit and no build
|
|
63
|
+
step, regardless of whether your app uses Sprockets or Propshaft.
|
|
64
|
+
|
|
65
|
+
## Manual install
|
|
66
|
+
|
|
67
|
+
If you'd rather not run the generator (or it skipped step 2 because you
|
|
68
|
+
don't have an `active_admin.scss` yet):
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
# config/initializers/active_admin.rb
|
|
72
|
+
ActiveAdmin.setup do |config|
|
|
73
|
+
# ... your existing config ...
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
ActiveAdminPrism.enable!
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```scss
|
|
80
|
+
// app/assets/stylesheets/active_admin.scss (only if this file exists)
|
|
81
|
+
@import "active_admin_prism/variable_overrides";
|
|
82
|
+
@import "active_admin/mixins";
|
|
83
|
+
@import "active_admin/base";
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Verifying the install
|
|
87
|
+
|
|
88
|
+
1. Start your server and sign in to `/admin`.
|
|
89
|
+
2. You should see a left sidebar (brand/logo, "PAGES" section, your
|
|
90
|
+
resources) instead of ActiveAdmin's default top bar.
|
|
91
|
+
3. View source (or DevTools → Network) and confirm two stylesheets load in
|
|
92
|
+
this order: `active_admin.css` (or `.scss` output) **then**
|
|
93
|
+
`active_admin_prism/prism.css`. Order matters — Prism's CSS must
|
|
94
|
+
load second to correctly override ActiveAdmin's own styles.
|
|
95
|
+
4. Click a row's Delete icon — you should see a purple/white styled confirm
|
|
96
|
+
dialog, not your browser's native popup.
|
|
97
|
+
|
|
98
|
+
If any of this doesn't match, see [Troubleshooting](#troubleshooting) before
|
|
99
|
+
assuming something's broken — asset caching is the most common cause.
|
|
100
|
+
|
|
101
|
+
## Configuration reference
|
|
102
|
+
|
|
103
|
+
`ActiveAdminPrism::Configuration` holds one flag per independently
|
|
104
|
+
toggleable feature. Every flag defaults to fully on; an app that never
|
|
105
|
+
touches this is unaffected.
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
# config/initializers/active_admin.rb, anywhere before `enable!`
|
|
109
|
+
ActiveAdminPrism.configure do |config|
|
|
110
|
+
config.sidebar = true # default: true
|
|
111
|
+
config.colorize_action_icons = true # default: true
|
|
112
|
+
config.styled_confirms = true # default: true
|
|
113
|
+
config.collapsible_filters = true # default: true
|
|
114
|
+
config.sidebar_footer = true # default: true
|
|
115
|
+
config.flash_dismissible = true # default: true
|
|
116
|
+
config.flash_auto_dismiss = true # default: true
|
|
117
|
+
config.flash_auto_dismiss_seconds = 5 # default: 5
|
|
118
|
+
config.flash_transition_ms = 320 # default: 320
|
|
119
|
+
config.login_page = true # default: true
|
|
120
|
+
config.login_logo = nil # default: nil (Prism's built-in mark)
|
|
121
|
+
config.login_app_name = nil # default: nil (falls back to AA's site_title)
|
|
122
|
+
config.login_tagline = "Sign in to your admin dashboard" # default shown
|
|
123
|
+
config.language_switcher = true # default: true
|
|
124
|
+
config.languages = [ # default: these 3
|
|
125
|
+
{ label: "English", locale: :en },
|
|
126
|
+
{ label: "Español", locale: :es },
|
|
127
|
+
{ label: "Français", locale: :fr }
|
|
128
|
+
]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
ActiveAdminPrism.enable!
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
| Option | Default | Effect when `false` (or, for the last two, when changed) |
|
|
135
|
+
| -------------------------------- | ------- | ---------------------------------------------------------------- |
|
|
136
|
+
| `sidebar` | `true` | `enable!` no-ops the header swap; ActiveAdmin's stock top nav renders instead. Everything else (panels, tables, forms, buttons, icons, flash/confirm styling) is unaffected. |
|
|
137
|
+
| `colorize_action_icons` | `true` | Index-table View/Edit/Delete render as ActiveAdmin's plain text links instead of color-coded icon buttons. |
|
|
138
|
+
| `styled_confirms` | `true` | Row-level `data-confirm` links (View/Edit/Delete, or anything else using Rails UJS's `data-confirm`) fall back to the browser's native `confirm()`. Batch Actions confirms are unaffected either way — they always use ActiveAdmin's own dialog. |
|
|
139
|
+
| `collapsible_filters` | `true` | The "Filters" sidebar panel always renders fully expanded (ActiveAdmin's own default) instead of collapsing to a single icon button that expands on click. |
|
|
140
|
+
| `sidebar_footer` | `true` | "Powered by Active Admin" (or your own `config.footer`) stays in ActiveAdmin's original page-level `#footer` instead of moving into the sidebar. |
|
|
141
|
+
| `flash_dismissible` | `true` | Flash messages render as ActiveAdmin's original plain `<div>` (no dismiss button). |
|
|
142
|
+
| `flash_auto_dismiss` | `true` | Flash messages stay on screen until the next page load (ActiveAdmin's default) instead of disappearing on their own. |
|
|
143
|
+
| `flash_auto_dismiss_seconds` | `5` | How long a flash stays visible before auto-dismissing (only relevant while `flash_auto_dismiss` is `true`). |
|
|
144
|
+
| `flash_transition_ms` | `320` | How long the fade/slide-out transition takes when a flash is dismissed (manually or automatically). |
|
|
145
|
+
| `login_page` | `true` | Every Devise auth page (sign in, sign up, forgot/reset password, resend confirmation, resend unlock) renders ActiveAdmin's original plain gradient-header box instead of Prism's centered card/brand mark. |
|
|
146
|
+
| `login_logo` | `nil` | `nil` renders Prism's built-in mark. A `String`/`Proc`/`Symbol` overrides it — see [Sign-in page](#sign-in-page). |
|
|
147
|
+
| `login_app_name` | `nil` | `nil` falls back to ActiveAdmin's own `config.site_title`. A `String`/`Proc`/`Symbol` overrides it. |
|
|
148
|
+
| `login_tagline` | `"Sign in to your admin dashboard"` | `nil` renders no tagline at all. |
|
|
149
|
+
| `language_switcher` | `true` | No "Languages" dropdown renders in the sidebar at all — see [Language switcher](#language-switcher). |
|
|
150
|
+
| `languages` | 3 entries (English/Español/Français) | The list the dropdown renders; an empty array (`[]`) has the same effect as `language_switcher = false`. |
|
|
151
|
+
|
|
152
|
+
**How this crosses the server/client boundary.** `sidebar`,
|
|
153
|
+
`colorize_action_icons`, and the `login_*` flags are pure server-side
|
|
154
|
+
decisions — Ruby renders different markup depending on the flag, full stop
|
|
155
|
+
(see [Sign-in page](#sign-in-page) for why `login_page` needs a Gemfile
|
|
156
|
+
ordering note despite being server-side). `styled_confirms`,
|
|
157
|
+
`collapsible_filters`, `sidebar_footer`, and the flash-related flags are
|
|
158
|
+
read by client-side JS/CSS (`prism.js` / `scss-src`), which can't see Ruby
|
|
159
|
+
config directly — so the relevant Ruby view code renders the *current*
|
|
160
|
+
value into the page on every request (a `prism-styled-confirms-disabled` /
|
|
161
|
+
`prism-filters-collapsible-disabled` / `prism-sidebar-footer-disabled`
|
|
162
|
+
class on `<body>`, and `data-prism-auto-dismiss-ms` /
|
|
163
|
+
`data-prism-transition-ms` attributes on the flash wrapper). That means all
|
|
164
|
+
of these are safe to change at runtime (e.g. from a feature-flag service)
|
|
165
|
+
without restarting your server — the very next page render picks up the
|
|
166
|
+
new value.
|
|
167
|
+
|
|
168
|
+
`flash_transition_ms` specifically is applied by `prism.js` as an inline
|
|
169
|
+
`transition-duration` on each flash (overriding the CSS default of 320ms),
|
|
170
|
+
and reused as the delay before the element is actually removed from the
|
|
171
|
+
DOM — so the fade-out animation and the removal always stay in sync
|
|
172
|
+
regardless of the configured duration.
|
|
173
|
+
|
|
174
|
+
`reset_configuration!` (mainly for test suites) resets every flag back to
|
|
175
|
+
its default:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
ActiveAdminPrism.reset_configuration!
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Plug-and-play: switching the theme on/off
|
|
182
|
+
|
|
183
|
+
Three levels, from "turn off one thing" to "fully revert to stock
|
|
184
|
+
ActiveAdmin":
|
|
185
|
+
|
|
186
|
+
**1. Turn off one feature.** Use the [Configuration reference](#configuration-reference)
|
|
187
|
+
above — e.g. `config.sidebar = false` to keep your existing top nav while
|
|
188
|
+
still getting the panel/table/form/button reskin and the flash/confirm
|
|
189
|
+
polish.
|
|
190
|
+
|
|
191
|
+
**2. Fully disable Prism, temporarily, without uninstalling.** Since every
|
|
192
|
+
Ruby-level override checks `ActiveAdminPrism.configuration` at render
|
|
193
|
+
time, setting every flag to `false` and skipping the sidebar swap gets you
|
|
194
|
+
back to (almost) stock ActiveAdmin behavior while the gem stays installed:
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
ActiveAdminPrism.configure do |config|
|
|
198
|
+
config.sidebar = false
|
|
199
|
+
config.colorize_action_icons = false
|
|
200
|
+
config.styled_confirms = false
|
|
201
|
+
config.collapsible_filters = false
|
|
202
|
+
config.sidebar_footer = false
|
|
203
|
+
config.flash_dismissible = false
|
|
204
|
+
config.flash_auto_dismiss = false
|
|
205
|
+
config.login_page = false
|
|
206
|
+
config.language_switcher = false
|
|
207
|
+
end
|
|
208
|
+
# Note: still calling enable! here would be a no-op for the sidebar since
|
|
209
|
+
# config.sidebar is false, but there's no need to call it at all in this case.
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
This is useful for a gradual rollout or A/B test — gate the whole block
|
|
213
|
+
behind your own condition:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
if Rails.env.production? && !FeatureFlag.enabled?(:active_admin_prism)
|
|
217
|
+
ActiveAdminPrism.configure do |c|
|
|
218
|
+
c.sidebar = false
|
|
219
|
+
c.colorize_action_icons = false
|
|
220
|
+
c.styled_confirms = false
|
|
221
|
+
c.collapsible_filters = false
|
|
222
|
+
c.sidebar_footer = false
|
|
223
|
+
c.flash_dismissible = false
|
|
224
|
+
c.flash_auto_dismiss = false
|
|
225
|
+
c.login_page = false
|
|
226
|
+
c.language_switcher = false
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
ActiveAdminPrism.enable!
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Note this doesn't touch the **CSS reskin** of panels/tables/forms/buttons —
|
|
233
|
+
those are unconditional (pure CSS, not gated by config) since they only
|
|
234
|
+
restyle existing ActiveAdmin markup and have no interactive behavior to
|
|
235
|
+
turn off. If you need the *visual* theme fully gone too (not just the
|
|
236
|
+
interactive bits), see level 3.
|
|
237
|
+
|
|
238
|
+
**3. Fully revert to stock ActiveAdmin, including CSS.** Remove (or
|
|
239
|
+
comment out) the two things the generator added:
|
|
240
|
+
|
|
241
|
+
```ruby
|
|
242
|
+
# config/initializers/active_admin.rb
|
|
243
|
+
# ActiveAdminPrism.enable! <- comment out or delete
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
```scss
|
|
247
|
+
// app/assets/stylesheets/active_admin.scss
|
|
248
|
+
// @import "active_admin_prism/variable_overrides"; <- comment out or delete
|
|
249
|
+
@import "active_admin/mixins";
|
|
250
|
+
@import "active_admin/base";
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The gem's CSS/JS are still *registered* (the engine does that
|
|
254
|
+
unconditionally at boot), but with nothing in the page referencing Prism's
|
|
255
|
+
classes (no `prism-sidebar`, no `prism-nav-*`, etc.) and ActiveAdmin's own
|
|
256
|
+
Sass variables back to their stock defaults, the visual result is stock
|
|
257
|
+
ActiveAdmin. You don't need to remove the gem from your Gemfile to do this
|
|
258
|
+
— it's a two-line, fully reversible toggle.
|
|
259
|
+
|
|
260
|
+
## Feature guide
|
|
261
|
+
|
|
262
|
+
### Sidebar navigation: icons & badges
|
|
263
|
+
|
|
264
|
+
Menu items are still defined the normal ActiveAdmin way — nested groups,
|
|
265
|
+
`priority`, `if:` all work unchanged. Two extra, optional conventions:
|
|
266
|
+
|
|
267
|
+
```ruby
|
|
268
|
+
# app/admin/orders.rb
|
|
269
|
+
menu label: "Orders", parent: "E-Commerce", priority: 2,
|
|
270
|
+
html_options: { icon: :receipt }
|
|
271
|
+
|
|
272
|
+
menu label: -> { "Messages #{content_tag(:span, unread_count, class: 'nav-badge')}".html_safe },
|
|
273
|
+
html_options: { icon: :message }
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`icon:` (inside `html_options:` — ActiveAdmin's own `MenuItem` already
|
|
277
|
+
passes this hash through untouched) accepts: `:dashboard`, `:users`,
|
|
278
|
+
`:cart`, `:box`, `:receipt`, `:credit_card`, `:message`, `:settings`,
|
|
279
|
+
`:home`, `:list`, `:folder`, `:bell`, `:search`, `:menu`, `:logout`,
|
|
280
|
+
`:check`, `:x`, `:chevron_down`, `:eye`, `:pencil`, `:trash`, `:filter`.
|
|
281
|
+
|
|
282
|
+
### Parent groups & submenus (nested navigation)
|
|
283
|
+
|
|
284
|
+
Nested groups (e.g. an "E-Commerce" group containing "Products" and
|
|
285
|
+
"Orders") are plain ActiveAdmin `menu` DSL — `PrismSidebar` only changes how
|
|
286
|
+
the existing `ActiveAdmin::Menu`/`MenuItem` tree is drawn, not how it's
|
|
287
|
+
built, so this works exactly like it would with the stock top nav.
|
|
288
|
+
|
|
289
|
+
**Create a child under a parent** with `parent:` (a string/symbol — it's
|
|
290
|
+
matched case-insensitively and normalized the same way ActiveAdmin
|
|
291
|
+
normalizes any menu id):
|
|
292
|
+
|
|
293
|
+
```ruby
|
|
294
|
+
# app/admin/products.rb
|
|
295
|
+
ActiveAdmin.register Product do
|
|
296
|
+
menu label: "Products", parent: "E-Commerce", priority: 1,
|
|
297
|
+
html_options: { icon: :box }
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# app/admin/orders.rb
|
|
301
|
+
ActiveAdmin.register Order do
|
|
302
|
+
menu label: "Orders", parent: "E-Commerce", priority: 2,
|
|
303
|
+
html_options: { icon: :receipt }
|
|
304
|
+
end
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
The first time either file registers, ActiveAdmin auto-creates an
|
|
308
|
+
"E-Commerce" parent item for you (non-clickable — its url defaults to `"#"`,
|
|
309
|
+
which is exactly what `PrismSidebar` checks to decide whether to render a
|
|
310
|
+
group toggle instead of a link). Both children then attach to that same
|
|
311
|
+
auto-created parent, sorted by `priority` within the group.
|
|
312
|
+
|
|
313
|
+
**Give the parent its own icon/priority** by declaring it explicitly, once,
|
|
314
|
+
with no `parent:` of its own — anywhere it'll load before (or alongside)
|
|
315
|
+
its children, e.g. in one of the resource files or in a dedicated
|
|
316
|
+
`app/admin/dashboard.rb`-style file:
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
menu label: "E-Commerce", priority: 2, html_options: { icon: :cart }
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
ActiveAdmin de-dupes by the normalized menu id (`"e-commerce"`), so this
|
|
323
|
+
becomes the *same* parent item `parent: "E-Commerce"` above attaches to —
|
|
324
|
+
whichever file happens to register first, the icon/priority you set here
|
|
325
|
+
wins for the group itself.
|
|
326
|
+
|
|
327
|
+
**Deeper nesting** — `parent:` also accepts an array for a multi-level
|
|
328
|
+
chain, auto-creating every intermediate level that doesn't already exist:
|
|
329
|
+
|
|
330
|
+
```ruby
|
|
331
|
+
menu label: "Conversion", parent: ["Analytics", "Reports"], priority: 1
|
|
332
|
+
# => Analytics > Reports > Conversion
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Active/expanded state** is automatic, not something you configure:
|
|
336
|
+
`PrismSidebar` marks a group `.active` (and starts it `.open`) whenever the
|
|
337
|
+
current page is that group or one of its descendants
|
|
338
|
+
(`ActiveAdmin::MenuItem#current?`); `prism.js` then persists whichever
|
|
339
|
+
groups a visitor has manually opened/closed to `localStorage`, keyed per
|
|
340
|
+
item, so their choice survives navigating to an unrelated page instead of
|
|
341
|
+
resetting to that server-rendered default on every request.
|
|
342
|
+
|
|
343
|
+
There's no Prism-specific config for nesting itself — the only lever that
|
|
344
|
+
affects it at all is the top-level `config.sidebar` flag (see
|
|
345
|
+
[Configuration reference](#configuration-reference)): turn it off and this
|
|
346
|
+
same `menu`/`parent:` tree renders through ActiveAdmin's own stock
|
|
347
|
+
top-nav dropdown behavior instead of the Prism sidebar.
|
|
348
|
+
|
|
349
|
+
### Language switcher
|
|
350
|
+
|
|
351
|
+
A "Languages" dropdown renders near the top of the sidebar, between the
|
|
352
|
+
brand and the Pages nav — no `admin.build_menu :utility_navigation do |menu|
|
|
353
|
+
... end` code required in your own initializer, unlike the equivalent
|
|
354
|
+
hand-rolled setup in stock ActiveAdmin. Ships with 3 languages by default;
|
|
355
|
+
replace the whole list to add, remove, reorder, or fully localize it:
|
|
356
|
+
|
|
357
|
+
```ruby
|
|
358
|
+
ActiveAdminPrism.configure do |config|
|
|
359
|
+
config.languages = [
|
|
360
|
+
{ label: "English", locale: :en },
|
|
361
|
+
{ label: "Deutsch", locale: :de },
|
|
362
|
+
{ label: "日本語", locale: :ja }
|
|
363
|
+
]
|
|
364
|
+
end
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Each entry is a `{ label:, locale:, url: }` hash (`url:` optional) —
|
|
368
|
+
`label` is the text shown (and matched against `I18n.locale` to decide
|
|
369
|
+
which option gets `.active` and shows as the dropdown's current
|
|
370
|
+
selection). With no `url:`, `locale` builds the link via
|
|
371
|
+
`url_for(locale: ...)`, appending `?locale=xx` to the *current* page
|
|
372
|
+
(preserving whatever path/params you're already on) — the same
|
|
373
|
+
query-param convention an ActiveAdmin app already reaches for by hand for
|
|
374
|
+
this.
|
|
375
|
+
|
|
376
|
+
Give an entry its own `url:` when switching locale needs to do more than
|
|
377
|
+
change a query param on the current page — hitting a remote/dedicated
|
|
378
|
+
endpoint that sets a cookie, session key, or subdomain before redirecting
|
|
379
|
+
back, for instance:
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
config.languages = [
|
|
383
|
+
{ label: "English", locale: :en },
|
|
384
|
+
{ label: "日本語", locale: :ja,
|
|
385
|
+
url: -> { "https://example.com/set_locale?locale=ja&return_to=#{request.path}" } }
|
|
386
|
+
]
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
`url:` accepts a `String`, `Proc`, or `Symbol` — same
|
|
390
|
+
`nil`/`String`/`Proc`/`Symbol` convention as `login_logo`. A `Proc` is
|
|
391
|
+
evaluated the exact same way an `ActiveAdmin::MenuItem`'s own `url:` proc
|
|
392
|
+
already is elsewhere in ActiveAdmin (bare `url_for`/`request`/any other
|
|
393
|
+
view helper is available inside it via Arbre's own delegation to the view
|
|
394
|
+
context — no `helpers.` prefix needed — matching the
|
|
395
|
+
`url: proc { url_for(locale: l.locale) }` pattern an ActiveAdmin app
|
|
396
|
+
already reaches for by hand for this).
|
|
397
|
+
|
|
398
|
+
This gem only renders the dropdown and its links; actually switching
|
|
399
|
+
`I18n.locale` based on the param your link lands on (typically a
|
|
400
|
+
`before_action { I18n.locale = params[:locale] || I18n.default_locale }`
|
|
401
|
+
in your own `ApplicationController` or `Admin::BaseController`) is your
|
|
402
|
+
app's own responsibility, same as it would be with a hand-rolled
|
|
403
|
+
utility-nav menu — this gem doesn't touch your controllers to avoid
|
|
404
|
+
guessing at a locale strategy (query param vs. subdomain vs. session vs.
|
|
405
|
+
path prefix) that varies widely between apps.
|
|
406
|
+
|
|
407
|
+
Set `config.languages = []` or `config.language_switcher = false` to
|
|
408
|
+
remove the dropdown entirely — an empty list and the flag have the exact
|
|
409
|
+
same effect, so use whichever reads more clearly for your case.
|
|
410
|
+
|
|
411
|
+
Unlike the rest of the sidebar (built once from your `menu do |m| ... end`
|
|
412
|
+
blocks each request re-renders, same as everything else here), this
|
|
413
|
+
dropdown is constructed fresh on every render directly from
|
|
414
|
+
`ActiveAdminPrism.configuration.languages` rather than through
|
|
415
|
+
ActiveAdmin's own `Menu`/`MenuItem`/`build_menu` machinery — see
|
|
416
|
+
[Language switcher markup](#language-switcher-markup) for why, and for the
|
|
417
|
+
full class/id reference.
|
|
418
|
+
|
|
419
|
+
### Icon helper
|
|
420
|
+
|
|
421
|
+
Available anywhere in your admin views (not just the sidebar):
|
|
422
|
+
|
|
423
|
+
```ruby
|
|
424
|
+
prism_icon(:cart, css_class: "prism-icon", size: 18)
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Toggle switch — form input
|
|
428
|
+
|
|
429
|
+
```ruby
|
|
430
|
+
form do |f|
|
|
431
|
+
f.input :active, as: :prism_toggle
|
|
432
|
+
end
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Only the wrapping markup changes — submitted params are identical to
|
|
436
|
+
`as: :boolean`.
|
|
437
|
+
|
|
438
|
+
### Toggle switch — read-only index/show
|
|
439
|
+
|
|
440
|
+
```ruby
|
|
441
|
+
index do
|
|
442
|
+
column :active do |product|
|
|
443
|
+
prism_toggle_tag product.active
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
show do
|
|
448
|
+
attributes_table do
|
|
449
|
+
row :active do |product|
|
|
450
|
+
prism_toggle_tag product.active
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Explicit opt-in per column/row — ActiveAdmin's default `status_tag`
|
|
457
|
+
"Yes"/"No" pill is untouched everywhere you don't call it.
|
|
458
|
+
|
|
459
|
+
### Row-level action icons
|
|
460
|
+
|
|
461
|
+
View/Edit/Delete on index pages render as color-coded icon buttons (blue
|
|
462
|
+
eye, purple pencil, red trash) automatically — no setup needed, and no
|
|
463
|
+
change to your `actions`/`index` blocks. Turn it off entirely with
|
|
464
|
+
`config.colorize_action_icons = false` if you'd rather keep plain text
|
|
465
|
+
links.
|
|
466
|
+
|
|
467
|
+
### Confirm dialogs
|
|
468
|
+
|
|
469
|
+
Every `data-confirm` link — row-level actions or your own custom ones —
|
|
470
|
+
routes through ActiveAdmin's own styled jQuery UI dialog instead of the
|
|
471
|
+
native browser `confirm()`. No-ops gracefully if your app doesn't use
|
|
472
|
+
jquery-rails/jquery-ujs. Turn off with `config.styled_confirms = false`.
|
|
473
|
+
|
|
474
|
+
### Collapsible "Filters" sidebar
|
|
475
|
+
|
|
476
|
+
The "Filters" panel (ActiveAdmin's `filters_sidebar_section`) starts
|
|
477
|
+
collapsed to a single filter-icon button; clicking it expands the full form
|
|
478
|
+
in place (also keyboard-accessible — Enter/Space toggle it, and it exposes
|
|
479
|
+
`aria-expanded`). The index table/main content area reflows to reclaim the
|
|
480
|
+
freed-up width while collapsed, and gives it back when expanded. No setup
|
|
481
|
+
needed, and it only targets that specific panel — any other sidebar section
|
|
482
|
+
(dashboard panels, custom `sidebar :title do ... end` blocks) is untouched.
|
|
483
|
+
Turn it off with `config.collapsible_filters = false` to always show it
|
|
484
|
+
fully expanded, matching ActiveAdmin's own default (and the table/content
|
|
485
|
+
area at its normal, non-reflowing width).
|
|
486
|
+
|
|
487
|
+
The reflow relies on the CSS `:has()` selector (broadly supported in
|
|
488
|
+
current browsers); without it, the Filters panel still collapses/expands
|
|
489
|
+
correctly, it just won't reclaim the extra width.
|
|
490
|
+
|
|
491
|
+
### Flash messages
|
|
492
|
+
|
|
493
|
+
Flash messages get a dismiss button, auto-hide after a configurable delay,
|
|
494
|
+
and fade/slide out with a smooth, configurable transition — see
|
|
495
|
+
[Configuration reference](#configuration-reference) for
|
|
496
|
+
`flash_dismissible`, `flash_auto_dismiss(_seconds)`, and
|
|
497
|
+
`flash_transition_ms`.
|
|
498
|
+
|
|
499
|
+
### Sidebar footer ("Powered by Active Admin")
|
|
500
|
+
|
|
501
|
+
This is moved from ActiveAdmin's own page-level `#footer` into the sidebar
|
|
502
|
+
itself, pinned below the account/logout area — a `flex: 0 0 auto` box that
|
|
503
|
+
doesn't get pushed down as the nav menu grows. Any custom
|
|
504
|
+
`config.footer = "..."` text you've set (a string, symbol, or proc) is used
|
|
505
|
+
as-is. Turn it off with `config.sidebar_footer = false` to leave the
|
|
506
|
+
original `#footer` visible in its normal place instead, matching
|
|
507
|
+
ActiveAdmin's own default.
|
|
508
|
+
|
|
509
|
+
### Sign-in page
|
|
510
|
+
|
|
511
|
+
Every Devise auth page ActiveAdmin renders — sign in (`sessions#new`,
|
|
512
|
+
usually `/admin/login`), sign up (`registrations#new`), forgot/reset
|
|
513
|
+
password (`passwords#new`/`#edit`), resend confirmation
|
|
514
|
+
(`confirmations#new`), and resend unlock (`unlocks#new`) — gets a centered
|
|
515
|
+
card, animated brand mark, full-width submit button, and a tidied-up row
|
|
516
|
+
of pill-shaped links instead of ActiveAdmin's default gradient header box.
|
|
517
|
+
No setup needed; whichever of these your app actually uses (most apps
|
|
518
|
+
don't enable Devise's `:confirmable`/`:lockable` modules, so those two
|
|
519
|
+
routes may not exist at all — that's fine, unrouted pages just never
|
|
520
|
+
render).
|
|
521
|
+
|
|
522
|
+
```ruby
|
|
523
|
+
ActiveAdminPrism.configure do |config|
|
|
524
|
+
config.login_logo = -> { image_tag "my_logo.svg", height: 40 }
|
|
525
|
+
config.login_app_name = "My Company Admin"
|
|
526
|
+
config.login_tagline = "Internal operations console"
|
|
527
|
+
end
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
The brand mark and app name are shared across *all* of these pages (one
|
|
531
|
+
consistent identity, wherever a visitor lands); only the tagline differs
|
|
532
|
+
per page — `login_tagline` is sign-in's own, independently configurable
|
|
533
|
+
line, while every other page shows its own action's own translated title
|
|
534
|
+
underneath instead (e.g. "Sign up", "Forgot your password?"), which isn't
|
|
535
|
+
a separate config option since it's just naming what the page in front of
|
|
536
|
+
you already does.
|
|
537
|
+
|
|
538
|
+
`login_logo`, `login_app_name`, and `login_tagline` each accept:
|
|
539
|
+
|
|
540
|
+
- `nil` — the built-in default (Prism's own animated prism mark for
|
|
541
|
+
`login_logo`; ActiveAdmin's own `config.site_title` for `login_app_name`;
|
|
542
|
+
a plain default sentence for `login_tagline`, or no tagline at all if you
|
|
543
|
+
explicitly set it to `nil`).
|
|
544
|
+
- A `String` — used as-is (for `login_logo` this must be trusted, already
|
|
545
|
+
html-safe markup, e.g. the result of `image_tag`, not raw untrusted
|
|
546
|
+
input).
|
|
547
|
+
- A `Proc` — `instance_exec`'d in the page's own view context, so ordinary
|
|
548
|
+
view helpers are available, including this gem's own `prism_icon`:
|
|
549
|
+
`-> { prism_icon(:cart, size: 40) }`.
|
|
550
|
+
- A `Symbol` — called as a method on the view context.
|
|
551
|
+
|
|
552
|
+
This is the same `nil`/`String`/`Proc`/`Symbol` convention ActiveAdmin
|
|
553
|
+
itself already uses for `config.footer` and `config.site_title_image`.
|
|
554
|
+
|
|
555
|
+
Turn the whole thing off with `config.login_page = false` to render
|
|
556
|
+
ActiveAdmin's original plain login box on every one of these pages instead
|
|
557
|
+
(see [Configuration reference](#configuration-reference)).
|
|
558
|
+
|
|
559
|
+
**How this actually overrides ActiveAdmin's pages.** Unlike most of Prism
|
|
560
|
+
(which reopens an existing Ruby class or targets existing CSS selectors),
|
|
561
|
+
these pages are customized by the gem shipping its own copies of
|
|
562
|
+
`app/views/active_admin/devise/{sessions/new,registrations/new,
|
|
563
|
+
passwords/new,passwords/edit,confirmations/new,unlocks/new}.html.erb` (plus
|
|
564
|
+
a shared `devise/shared/_brand` partial all six render, so they redesign
|
|
565
|
+
together instead of drifting out of sync) — Rails resolves an engine's
|
|
566
|
+
`app/views` directory as a view path, and engines initialized later end up
|
|
567
|
+
higher priority than ones initialized earlier (each engine
|
|
568
|
+
`prepend_view_path`s its own directory in turn). Since a Gemfile naturally
|
|
569
|
+
lists `gem "active_admin_prism"` after `gem "activeadmin"` (the theme
|
|
570
|
+
depends on it), this gem's copies of those views are what Rails renders,
|
|
571
|
+
without you doing anything — this has been verified against the real
|
|
572
|
+
Bundler/Rails load order in this gem's own demo app. If your Gemfile
|
|
573
|
+
somehow requires `active_admin_prism` *before* `activeadmin` (unusual,
|
|
574
|
+
but possible with certain `group`/`require:` combinations), ActiveAdmin's
|
|
575
|
+
own plain views would win instead — the rest of the theme (CSS reskin,
|
|
576
|
+
sidebar, etc.) is unaffected either way, since none of that depends on view
|
|
577
|
+
path ordering. The actual authentication forms and field lists inside
|
|
578
|
+
every one of these views are untouched, byte-for-byte identical to
|
|
579
|
+
ActiveAdmin's own templates — only the surrounding brand markup is new.
|
|
580
|
+
|
|
581
|
+
## Error pages (404/500)
|
|
582
|
+
|
|
583
|
+
```sh
|
|
584
|
+
rails g active_admin_prism:error_pages
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Copies Prism-styled `public/404.html` and `public/500.html` (matching the
|
|
588
|
+
card/blob visual language of the sign-in page) into your app.
|
|
589
|
+
|
|
590
|
+
This is deliberately **not** part of `rails g active_admin_prism:install`,
|
|
591
|
+
and **not** gated by `ActiveAdminPrism::Configuration`, unlike every
|
|
592
|
+
other piece of this theme:
|
|
593
|
+
|
|
594
|
+
- **Static exception pages can't be "registered" or overridden by a gem at
|
|
595
|
+
all.** `config.exceptions_app`'s default
|
|
596
|
+
(`ActionDispatch::PublicExceptions`) reads `public/404.html`/`500.html`
|
|
597
|
+
straight off disk from `Rails.public_path`, completely outside the asset
|
|
598
|
+
pipeline and outside Rails' view-resolution/engine-view-path mechanism —
|
|
599
|
+
the same mechanism the [sign-in page](#sign-in-page) override relies on
|
|
600
|
+
doesn't exist here. Copying the files into the host app (the same way
|
|
601
|
+
`rails new` scaffolds its own default `public/404.html`) is the only way
|
|
602
|
+
a gem can deliver this at all.
|
|
603
|
+
- **A host's `public/404.html`/`500.html` are usually already
|
|
604
|
+
customized/committed.** Silently overwriting them on every `install` run
|
|
605
|
+
— or worse, ambushing an unrelated `install` with `copy_file`'s
|
|
606
|
+
interactive overwrite prompt — would be surprising. This generator is a
|
|
607
|
+
separate, explicit opt-in you run (and re-run, if you want a newer
|
|
608
|
+
version of the gem's default templates) whenever you actually want them.
|
|
609
|
+
|
|
610
|
+
Once copied, these are plain static HTML with an inline `<style>` block —
|
|
611
|
+
no ERB, no `@import "prism.css"`, no `ActiveAdminPrism::Configuration`
|
|
612
|
+
read at request time (a truly static file has no request to read config
|
|
613
|
+
during). The colors are hand-copied from `scss-src/_variables.scss`'s
|
|
614
|
+
defaults as of this gem's current version rather than referencing them, so
|
|
615
|
+
they won't automatically track a host's own color customization
|
|
616
|
+
([Customizing colors](#customizing-colors)) — re-run the generator, or
|
|
617
|
+
hand-edit the copied files, if you want them to match. The action button
|
|
618
|
+
`href`s (`Back to Dashboard`, `Report Issue`) are placeholders — a static
|
|
619
|
+
file has no Rails route helpers available to point them at your actual
|
|
620
|
+
admin path automatically, so edit those after copying.
|
|
621
|
+
|
|
622
|
+
## Markup & CSS class reference
|
|
623
|
+
|
|
624
|
+
Everything below is either existing ActiveAdmin markup Prism reskins in
|
|
625
|
+
place (no new classes — just a CSS rule targeting AA's own selector), or a
|
|
626
|
+
`prism-*`-prefixed class/id Prism itself renders. Use this as the map for
|
|
627
|
+
writing your own CSS on top of the theme, or for understanding what a given
|
|
628
|
+
`prism-*` class in DevTools corresponds to. Source of truth for all of this
|
|
629
|
+
is `scss-src/*.scss` (edit + `bin/build-css` if you fork the gem) and the
|
|
630
|
+
Ruby view files under `lib/active_admin/views/`.
|
|
631
|
+
|
|
632
|
+
### Sidebar (`ActiveAdmin::Views::PrismSidebar`)
|
|
633
|
+
|
|
634
|
+
```
|
|
635
|
+
#header.prism-sidebar <- drop-in replacement for AA's header slot
|
|
636
|
+
span.prism-sidebar-mobile-toggle <- hamburger, ≤900px viewports only
|
|
637
|
+
div.prism-sidebar-inner
|
|
638
|
+
div.prism-sidebar-brand
|
|
639
|
+
#site_title <- AA's own site_title verb, unchanged
|
|
640
|
+
div.prism-sidebar-lang <- only if config.language_switcher and #languages is non-empty
|
|
641
|
+
div.prism-sidebar-scroll
|
|
642
|
+
div.prism-nav-section-label <- "PAGES"
|
|
643
|
+
ul.prism-nav
|
|
644
|
+
li.prism-nav-item[#prism_nav_<id>]
|
|
645
|
+
[.has-children] <- item.items.any?
|
|
646
|
+
[.active] <- item.current?(current_tab)
|
|
647
|
+
[.open] <- has-children && active, or user-toggled
|
|
648
|
+
span.prism-nav-group-toggle <- only when .has-children
|
|
649
|
+
svg.prism-nav-icon
|
|
650
|
+
span.prism-nav-label
|
|
651
|
+
svg.prism-chevron
|
|
652
|
+
a.prism-nav-link <- leaf items only (real url? see below)
|
|
653
|
+
svg.prism-nav-icon
|
|
654
|
+
span.prism-nav-label
|
|
655
|
+
ul.prism-nav-submenu <- only when .has-children, nested li.prism-nav-item...
|
|
656
|
+
div.prism-sidebar-utility <- only if the utility menu has items
|
|
657
|
+
ul.prism-nav.prism-nav-utility
|
|
658
|
+
li#prism_nav_current_user
|
|
659
|
+
li#prism_nav_logout
|
|
660
|
+
div.prism-sidebar-footer <- only if config.sidebar_footer
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
Notes:
|
|
664
|
+
- A leaf item renders as `a.prism-nav-link` only when its url is a "real"
|
|
665
|
+
url (present and not `"#"`); otherwise it renders as a plain
|
|
666
|
+
`span.prism-nav-link` (see `real_url?` in `prism_sidebar.rb`) — this is
|
|
667
|
+
also exactly how ActiveAdmin auto-created parent groups end up as
|
|
668
|
+
non-clickable toggles (see [Parent groups & submenus](#parent-groups--submenus-nested-navigation)).
|
|
669
|
+
- `#prism_nav_current_user` / `#prism_nav_logout` are ActiveAdmin's own
|
|
670
|
+
stable ids for the default utility nav (`Namespace#build_default_utility_nav`)
|
|
671
|
+
— style hooks, not Prism inventions.
|
|
672
|
+
- `.nav-badge` (not `prism-`-prefixed — it's a convention *you* opt into via
|
|
673
|
+
`label:`, see [Sidebar navigation: icons & badges](#sidebar-navigation-icons--badges)) is the
|
|
674
|
+
class used in the README/INTEGRATION examples for badge counts; it has no
|
|
675
|
+
built-in styling of its own beyond what you see in `_sidebar.scss` — it's
|
|
676
|
+
just an example class name, feel free to use your own.
|
|
677
|
+
- Body-level state: `body.prism-sidebar-open` (mobile off-canvas open,
|
|
678
|
+
toggled by `prism.js`), `body.prism-sidebar-footer-disabled` (set when
|
|
679
|
+
`config.sidebar_footer` is `false` — see [Configuration reference](#configuration-reference)).
|
|
680
|
+
|
|
681
|
+
### Language switcher markup
|
|
682
|
+
|
|
683
|
+
```
|
|
684
|
+
div.prism-sidebar-lang[.open] <- ".open" toggled by prism.js, not server-rendered
|
|
685
|
+
span.prism-lang-toggle[aria-expanded]
|
|
686
|
+
svg.prism-nav-icon <- the :globe icon
|
|
687
|
+
span.prism-lang-current <- the option whose locale matches I18n.locale (or the first one)
|
|
688
|
+
svg.prism-chevron
|
|
689
|
+
ul.prism-lang-menu
|
|
690
|
+
li
|
|
691
|
+
a.prism-lang-option[.active] <- href="<current path>?locale=<locale>", or the entry's own :url if set
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Unlike every other piece of navigation in this gem (which walks
|
|
695
|
+
ActiveAdmin's own `Menu`/`MenuItem` tree, built via `menu do |m| ... end`
|
|
696
|
+
DSL calls in `app/admin/*.rb`), this one is constructed directly from
|
|
697
|
+
`ActiveAdminPrism.configuration.languages` at render time — there's no
|
|
698
|
+
`ActiveAdmin::Menu` object backing it, no `admin.build_menu
|
|
699
|
+
:utility_navigation` call needed, and no per-namespace setup. That also
|
|
700
|
+
means it re-renders from the *current* config on every request, the same
|
|
701
|
+
as `sidebar_footer`/`collapsible_filters` elsewhere in this gem, rather
|
|
702
|
+
than being fixed at boot the way the sidebar's own header-swap
|
|
703
|
+
registration is (see [Sign-in page](#sign-in-page) for the other example
|
|
704
|
+
of that "built once at boot vs. re-read every request" distinction).
|
|
705
|
+
|
|
706
|
+
### Panels & cards
|
|
707
|
+
|
|
708
|
+
Pure CSS reskin of AA's existing `Panel`/`Component` markup — no new
|
|
709
|
+
classes:
|
|
710
|
+
|
|
711
|
+
```
|
|
712
|
+
.panel <- white card, border, shadow, border-radius
|
|
713
|
+
> h3 <- panel title bar
|
|
714
|
+
.panel_contents <- body padding
|
|
715
|
+
.header_action <- float:right slot (AA's own convention)
|
|
716
|
+
.columns > .column <- flex card grid (dashboard layout)
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
The "Filters" sidebar section specifically (`#filters_sidebar_section`) gets
|
|
720
|
+
extra markup and classes — see
|
|
721
|
+
[Filters sidebar panel](#filters-sidebar-panel-filters_sidebar_section)
|
|
722
|
+
below.
|
|
723
|
+
|
|
724
|
+
### Index tables & row actions
|
|
725
|
+
|
|
726
|
+
```
|
|
727
|
+
table.index_table
|
|
728
|
+
th[.sorted-asc/.sorted-desc]
|
|
729
|
+
tr[.even][.selected]
|
|
730
|
+
td.col-actions
|
|
731
|
+
.table_actions <- wraps View/Edit/Delete for a row
|
|
732
|
+
a.view_link <- icon: eye, color: info-blue
|
|
733
|
+
svg.prism-action-icon
|
|
734
|
+
span.prism-visually-hidden <- original text label, screen-reader only
|
|
735
|
+
a.edit_link <- icon: pencil, color: primary
|
|
736
|
+
a.delete_link <- icon: trash, color: danger
|
|
737
|
+
.status_tag[.yes/.no] <- AA's default boolean pill (untouched markup, reskinned colors)
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
`view_link` / `edit_link` / `delete_link` are ActiveAdmin's **own** classes
|
|
741
|
+
(`IndexTableFor#defaults`) — Prism's `index_table_actions.rb` override only
|
|
742
|
+
swaps the link's *content* (icon + hidden label instead of plain text) when
|
|
743
|
+
`config.colorize_action_icons` is `true`; with it `false`, `item(...)`
|
|
744
|
+
falls back to AA's plain `link_to` untouched, and none of the
|
|
745
|
+
`prism-action-icon`/`prism-visually-hidden` markup is added.
|
|
746
|
+
|
|
747
|
+
### Forms & toggle switches
|
|
748
|
+
|
|
749
|
+
```
|
|
750
|
+
form fieldset.inputs
|
|
751
|
+
li[.error] <- p.inline-errors, red border on the field
|
|
752
|
+
ul.errors <- error summary box
|
|
753
|
+
|
|
754
|
+
// as: :boolean (AA default) — reskinned checkbox, no new classes:
|
|
755
|
+
input[type="checkbox"] / input[type="radio"]
|
|
756
|
+
|
|
757
|
+
// as: :prism_toggle (opt-in, PrismToggleInput):
|
|
758
|
+
label.prism-toggle
|
|
759
|
+
input.prism-toggle-input <- visually hidden (width/height:0), still focusable
|
|
760
|
+
span.prism-toggle-track <- the visible pill+thumb, :checked~ sibling selector drives it
|
|
761
|
+
|
|
762
|
+
// prism_toggle_tag(value) (opt-in, read-only index/show helper):
|
|
763
|
+
span.prism-toggle-tag[.on/.off]
|
|
764
|
+
span.prism-toggle-track
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
`.prism-toggle-track` is shared between the live form input and the
|
|
768
|
+
read-only tag — same pill/thumb CSS, driven by a sibling `:checked`
|
|
769
|
+
selector in the form case and by the `.on`/`.off` class in the read-only
|
|
770
|
+
case (there's no real `<input>` on an index/show page).
|
|
771
|
+
|
|
772
|
+
### Filters sidebar panel (`#filters_sidebar_section`)
|
|
773
|
+
|
|
774
|
+
Only this specific `SidebarSection` (AA's built-in id for the Filters
|
|
775
|
+
panel) gets the extra icon/collapse markup — any other sidebar section
|
|
776
|
+
(dashboard panels, a host's own `sidebar :title do ... end`) is untouched:
|
|
777
|
+
|
|
778
|
+
```
|
|
779
|
+
#sidebar <- AA's own right-hand content sidebar (not Prism's left nav)
|
|
780
|
+
.panel#filters_sidebar_section.prism-collapsible-panel[.open]
|
|
781
|
+
> h3 <- the icon-only button when collapsed
|
|
782
|
+
svg.prism-filter-icon
|
|
783
|
+
span.prism-filter-label <- visually hidden (max-width:0) while collapsed
|
|
784
|
+
.panel_contents <- max-height:0 while collapsed, animates open
|
|
785
|
+
form.filter_form
|
|
786
|
+
.filter_form_field[.select_and_search][.filter_date_range]
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
`.prism-collapsible-panel` and the icon/label markup are only added when
|
|
790
|
+
`config.collapsible_filters` is `true`; `prism.js` mirrors the panel's
|
|
791
|
+
`.open` state onto `body.prism-filters-open`, which is what
|
|
792
|
+
`#active_admin_content`/`#sidebar`'s reflow rules key off (`:has()` — see
|
|
793
|
+
[Collapsible "Filters" sidebar](#collapsible-filters-sidebar)). With the config `false`,
|
|
794
|
+
`body.prism-filters-collapsible-disabled` is the backstop class that forces
|
|
795
|
+
the panel back to always-expanded.
|
|
796
|
+
|
|
797
|
+
### Flash messages markup
|
|
798
|
+
|
|
799
|
+
```
|
|
800
|
+
.flashes[data-prism-transition-ms][data-prism-auto-dismiss-ms]
|
|
801
|
+
.flash.flash_notice / .flash_error / .flash_alert [.prism-flash-hide]
|
|
802
|
+
span.prism-flash-message
|
|
803
|
+
button.prism-flash-dismiss[data-prism-flash-dismiss] <- only if config.flash_dismissible
|
|
804
|
+
svg.prism-flash-dismiss-icon
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
`flash_notice`/`flash_error`/`flash_alert` are ActiveAdmin's own type
|
|
808
|
+
classes (from `flash_messages.each { |type, ...| }`); Prism just colors
|
|
809
|
+
each one distinctly. `.prism-flash-hide` is added by `prism.js` right
|
|
810
|
+
before removal (opacity/transform transition), timed against the
|
|
811
|
+
`data-prism-transition-ms` attribute — see
|
|
812
|
+
[Flash messages](#flash-messages) / [Configuration reference](#configuration-reference).
|
|
813
|
+
|
|
814
|
+
### Confirm dialog (jQuery UI)
|
|
815
|
+
|
|
816
|
+
Not Prism markup at all — this is ActiveAdmin's own `$.fn.dialog` output
|
|
817
|
+
(`active_admin/base.js`), reskinned by targeting jQuery UI's own classes:
|
|
818
|
+
|
|
819
|
+
```
|
|
820
|
+
.ui-widget-overlay
|
|
821
|
+
.ui-dialog
|
|
822
|
+
.ui-dialog-titlebar
|
|
823
|
+
form > ul > li <- batch-action inputs, if any (empty <ul> for a plain confirm)
|
|
824
|
+
.ui-dialog-buttonpane
|
|
825
|
+
.ui-dialog-buttonset
|
|
826
|
+
button:first-child <- OK/Confirm — prism-button-primary
|
|
827
|
+
button:last-child <- Cancel — prism-button-secondary
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
### Sign-in page markup
|
|
831
|
+
|
|
832
|
+
This same structure is shared by all six auth pages (see
|
|
833
|
+
[Sign-in page](#sign-in-page)) — `form#session_new` below is whichever
|
|
834
|
+
form that particular action renders (`#registration_new` for sign up,
|
|
835
|
+
etc.), byte-for-byte ActiveAdmin's own template either way:
|
|
836
|
+
|
|
837
|
+
```
|
|
838
|
+
body.logged_out
|
|
839
|
+
#wrapper
|
|
840
|
+
#content_wrapper <- centered 400px column when .prism-login-brand is present
|
|
841
|
+
.flashes
|
|
842
|
+
#active_admin_content <- the white card itself
|
|
843
|
+
#login.prism-login
|
|
844
|
+
[devise/shared/_brand partial:]
|
|
845
|
+
div.prism-login-brand <- only when config.login_page is true
|
|
846
|
+
div.prism-login-logo
|
|
847
|
+
svg.prism-login-mark <- default mark; absent if login_logo renders something else
|
|
848
|
+
.prism-login-tri <- the triangle (animated glow)
|
|
849
|
+
.prism-login-beam <- each dispersed line (animated dash-flow)
|
|
850
|
+
h2.prism-login-title
|
|
851
|
+
p.prism-login-tagline <- login_tagline on sessions#new; the page's own action title everywhere else
|
|
852
|
+
[h2 (plain, no wrapper)] <- rendered instead of .prism-login-brand when config.login_page is false
|
|
853
|
+
#error_explanation <- ActiveAdmin's own shared error-messages partial (every page but sessions#new, which uses the flash instead)
|
|
854
|
+
form#session_new <- untouched Devise/Formtastic form markup
|
|
855
|
+
fieldset.inputs <- border/radius suppressed here (see below) — redundant inside the card
|
|
856
|
+
fieldset.actions <- submit button stretched full-width (see below)
|
|
857
|
+
div.prism-login-links <- wraps active_admin/devise/shared/_links.erb's sign-up/forgot-password/etc links, now pill-chip styled
|
|
858
|
+
#footer
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
All of the card/blob/centering CSS is scoped under
|
|
862
|
+
`body.logged_out:has(.prism-login-brand)` (see `scss-src/_login.scss`) —
|
|
863
|
+
it only ever applies on these actual auth pages, and never when
|
|
864
|
+
`config.login_page` is `false` (since `.prism-login-brand` then never
|
|
865
|
+
renders at all). `#wrapper` itself gets its `display: block` layout back
|
|
866
|
+
via a `body:not(.logged_out)` guard on the sidebar's own `#wrapper` grid
|
|
867
|
+
rule in `scss-src/_sidebar.scss`, since that id is reused (with a totally
|
|
868
|
+
different two-child structure) by the logged-out layout.
|
|
869
|
+
|
|
870
|
+
Two more fixes live in that same scoped block: `fieldset.inputs`'s own
|
|
871
|
+
card border/radius (right everywhere else a fieldset sits directly on the
|
|
872
|
+
gray page background) is suppressed here specifically, since it otherwise
|
|
873
|
+
draws a redundant second box inside the already-bordered auth-page card;
|
|
874
|
+
and the submit button (`fieldset.actions input[type="submit"]`) is
|
|
875
|
+
stretched to the full card width rather than left-aligned, so it's never
|
|
876
|
+
ambiguously off-center against the centered brand block above it or the
|
|
877
|
+
centered link chips below it.
|
|
878
|
+
|
|
879
|
+
### Body-level state classes
|
|
880
|
+
|
|
881
|
+
All of these are added/removed by `body_classes` in
|
|
882
|
+
`lib/active_admin/views/flash_messages.rb` (server-rendered, current on
|
|
883
|
+
every request) or toggled by `prism.js` at runtime — see
|
|
884
|
+
[How this crosses the server/client boundary](#configuration-reference):
|
|
885
|
+
|
|
886
|
+
| Class | Meaning |
|
|
887
|
+
| --- | --- |
|
|
888
|
+
| `prism-sidebar-open` | Mobile off-canvas sidebar is open (≤900px viewports). Runtime only, via `prism.js`. |
|
|
889
|
+
| `prism-filters-open` | Filters panel is currently expanded — drives the content-area reflow. Runtime only, mirrors `#filters_sidebar_section.open`. |
|
|
890
|
+
| `prism-styled-confirms-disabled` | `config.styled_confirms` is `false` — `prism.js`'s `$.rails.allowAction` override no-ops. |
|
|
891
|
+
| `prism-filters-collapsible-disabled` | `config.collapsible_filters` is `false` — Filters panel forced always-expanded. |
|
|
892
|
+
| `prism-sidebar-footer-disabled` | `config.sidebar_footer` is `false` — original `#footer` stays visible; the sidebar's own footer div isn't rendered at all. |
|
|
893
|
+
|
|
894
|
+
### Design tokens (Sass variables)
|
|
895
|
+
|
|
896
|
+
Defined in `scss-src/_variables.scss`, all `!default`. These compile into
|
|
897
|
+
the shipped, precompiled `prism.css` — they are **not** overridable from a
|
|
898
|
+
host app (see [Customizing colors](#customizing-colors) for why, and for
|
|
899
|
+
the separate, host-overridable set of ActiveAdmin's own variables via
|
|
900
|
+
`variable_overrides.scss`):
|
|
901
|
+
|
|
902
|
+
| Variable | Default | Used for |
|
|
903
|
+
| --- | --- | --- |
|
|
904
|
+
| `$prism-color-primary` | `#6d5bd0` | Active nav item, primary buttons, links, focus rings |
|
|
905
|
+
| `$prism-color-primary-dark` | `#5949b8` | Hover/active state of the above |
|
|
906
|
+
| `$prism-color-primary-light` | `#f2ecfd` | Active nav background, selected table row, hover backgrounds |
|
|
907
|
+
| `$prism-color-success` / `-light` | `#22c55e` / `#e8f9ee` | Notice flash, "yes" status tag |
|
|
908
|
+
| `$prism-color-danger` / `-light` | `#ef4444` / `#fdecec` | Error/alert flash, "no" status tag, delete action, field errors |
|
|
909
|
+
| `$prism-color-warning` | `#f59e0b` | Reserved (no default component uses this yet) |
|
|
910
|
+
| `$prism-color-info` | `#3b82f6` | View action icon |
|
|
911
|
+
| `$prism-bg-page` | `#f4f5f7` | Page background, table header background |
|
|
912
|
+
| `$prism-bg-card` | `#ffffff` | Panel/card/dialog background |
|
|
913
|
+
| `$prism-bg-sidebar` | `#ffffff` | Sidebar background |
|
|
914
|
+
| `$prism-text-heading` / `-body` / `-muted` / `-inverse` | `#1a1f36` / `#384250` / `#6b7280` / `#ffffff` | Text color scale |
|
|
915
|
+
| `$prism-border-color` / `-strong` | `#e6e8ec` / `#d6d9e0` | Hairline borders / stronger input borders |
|
|
916
|
+
| `$prism-sidebar-width` | `264px` | **Prism's own** sidebar column width (CSS Grid) — separate from AA's own `$sidebar-width` (320px, set in `variable_overrides.scss`, which sizes the *Filters* sidebar and is host-overridable) |
|
|
917
|
+
| `$prism-radius` / `-sm` / `-pill` | `10px` / `6px` / `999px` | Border-radius scale (cards / buttons+inputs / pills+toggles) |
|
|
918
|
+
| `$prism-shadow-card` / `-popover` | see source | Box-shadow scale |
|
|
919
|
+
| `$prism-font-family` | system font stack | Body font |
|
|
920
|
+
| `$prism-transition-fast` | `120ms ease` | Hover/focus transitions |
|
|
921
|
+
| `$prism-filters-collapsed-gutter` (`_panels.scss`) | `72px` | Width the content area reflows to when the Filters panel is collapsed |
|
|
922
|
+
|
|
923
|
+
## Customizing colors
|
|
924
|
+
|
|
925
|
+
There are two independent color surfaces, because ActiveAdmin's own CSS
|
|
926
|
+
and Prism's CSS are two separately-compiled stylesheets:
|
|
927
|
+
|
|
928
|
+
**1. Prism's own palette** (`scss-src/_variables.scss` in this gem's
|
|
929
|
+
source — `$prism-color-primary`, `$prism-bg-page`, `$prism-sidebar-width`,
|
|
930
|
+
etc.). To change these you need to fork the gem's SCSS source, edit the
|
|
931
|
+
variables, and run `bin/build-css` to produce your own `prism.css` — there's
|
|
932
|
+
no way to override these from a host app, since `prism.css` ships
|
|
933
|
+
precompiled specifically so installing the gem doesn't require a Sass
|
|
934
|
+
compiler.
|
|
935
|
+
|
|
936
|
+
**2. ActiveAdmin's own default palette**
|
|
937
|
+
(`active_admin/mixins/_variables.scss` and `_gradients.scss` in the
|
|
938
|
+
`activeadmin` gem — `$primary-color`, `$text-color`, etc.), which drives
|
|
939
|
+
things Prism doesn't have Ruby-level control over: the jQuery UI
|
|
940
|
+
batch-actions dialog, the dropdown menu popup, anything you build yourself
|
|
941
|
+
with `panel`/`section-background`. The gem ships
|
|
942
|
+
[`variable_overrides.scss`](app/assets/stylesheets/active_admin_prism/_variable_overrides.scss) —
|
|
943
|
+
Prism's values for every one of these — which the install generator wires
|
|
944
|
+
up automatically (see [Install](#install)). Every variable in that file is
|
|
945
|
+
itself `!default`, so to customize further, set your own value **before**
|
|
946
|
+
that `@import` in your `active_admin.scss` and it wins:
|
|
947
|
+
|
|
948
|
+
```scss
|
|
949
|
+
// app/assets/stylesheets/active_admin.scss
|
|
950
|
+
$primary-color: #your-brand-color;
|
|
951
|
+
@import "active_admin_prism/variable_overrides";
|
|
952
|
+
@import "active_admin/mixins";
|
|
953
|
+
@import "active_admin/base";
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
## Troubleshooting
|
|
957
|
+
|
|
958
|
+
**"I made a change and nothing looks different."** By far the most common
|
|
959
|
+
cause in practice: browser caching. The gem fingerprints its assets by
|
|
960
|
+
content hash, so a genuinely new `prism.css`/`prism.js` always gets a new
|
|
961
|
+
URL — but the *HTML page* referencing the old URL can still be served from
|
|
962
|
+
your browser's cache. Hard-refresh; if that doesn't help, open a private/
|
|
963
|
+
incognito window, which guarantees zero cached anything.
|
|
964
|
+
|
|
965
|
+
**"A button/link still shows ActiveAdmin's default gray, not Prism's
|
|
966
|
+
colors."** ActiveAdmin's own CSS uses some ID-scoped selectors (e.g.
|
|
967
|
+
`#header a`) and wraps hover/active states in `:not(.disabled)` — both add
|
|
968
|
+
specificity that a naive class-based override can lose to regardless of
|
|
969
|
+
load order. If you're overriding something yourself (custom CSS on top of
|
|
970
|
+
Prism), match ActiveAdmin's actual selector path rather than a flatter one,
|
|
971
|
+
or reach for `!important` on the specific property that's losing.
|
|
972
|
+
|
|
973
|
+
**"The confirm dialog / dismiss button isn't behaving."** These are
|
|
974
|
+
client-side JS (`prism.js`) — if `jquery-rails`/`jquery-ujs` isn't loaded
|
|
975
|
+
in your app, the confirm-dialog override no-ops silently by design (falls
|
|
976
|
+
back to the native browser confirm rather than erroring).
|
|
977
|
+
|
|
978
|
+
**"Sass compile error mentioning `$primary-color` or a missing mixin."**
|
|
979
|
+
Make sure `@import "active_admin_prism/variable_overrides"` comes
|
|
980
|
+
**before** `@import "active_admin/mixins"`, and that you haven't
|
|
981
|
+
accidentally commented out `active_admin/mixins` while leaving
|
|
982
|
+
`active_admin/base` active — `base` depends on `mixins` being loaded
|
|
983
|
+
first.
|
|
984
|
+
|
|
985
|
+
**"The sign-in page still looks like stock ActiveAdmin even though
|
|
986
|
+
`config.login_page` is `true`."** This one specific piece of Prism (see
|
|
987
|
+
[Sign-in page](#sign-in-page)) depends on Gemfile order: `gem
|
|
988
|
+
"active_admin_prism"` needs to be declared **after** `gem
|
|
989
|
+
"activeadmin"` so this gem's view overrides ActiveAdmin's own. This is the
|
|
990
|
+
natural, expected order already (the theme depends on ActiveAdmin), so it's
|
|
991
|
+
rarely an issue in practice — but if your Gemfile has an unusual `group`/
|
|
992
|
+
`require:` setup that changes load order, reordering those two lines fixes
|
|
993
|
+
it. Nothing else in the theme (CSS reskin, sidebar, tables, forms) depends
|
|
994
|
+
on this ordering — only the sign-in page's brand markup does.
|
|
995
|
+
|
|
996
|
+
## Upgrading
|
|
997
|
+
|
|
998
|
+
Since Prism is CSS/JS/light Ruby overrides on top of ActiveAdmin's public
|
|
999
|
+
extension points (`ViewFactory.register`, documented `item()` hooks,
|
|
1000
|
+
`!default` Sass variables) rather than a fork, upgrading `activeadmin` or
|
|
1001
|
+
this gem independently is expected to keep working across minor versions.
|
|
1002
|
+
After upgrading either, re-run through
|
|
1003
|
+
[Verifying the install](#verifying-the-install) once.
|
|
1004
|
+
|
|
1005
|
+
## Uninstalling
|
|
1006
|
+
|
|
1007
|
+
1. Remove `ActiveAdminPrism.enable!` from
|
|
1008
|
+
`config/initializers/active_admin.rb`.
|
|
1009
|
+
2. Remove `@import "active_admin_prism/variable_overrides";` from
|
|
1010
|
+
`active_admin.scss`, if present.
|
|
1011
|
+
3. Remove `gem "active_admin_prism"` from your Gemfile and
|
|
1012
|
+
`bundle install`.
|