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
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ram Yadav
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # active_admin_prism
2
+
3
+ Prism is a plug-and-play [ActiveAdmin](https://activeadmin.info) theme:
4
+ a collapsible left sidebar with grouped navigation, card-style panels and
5
+ tables, and reskinned Formtastic forms — no Sass compiler, no JS bundler,
6
+ no manual asset manifest edits.
7
+
8
+ **→ See [INTEGRATION.md](INTEGRATION.md) for the full integration guide**
9
+ (configuration reference, feature-by-feature usage, switching/disabling the
10
+ theme, troubleshooting). This README is a quick start.
11
+
12
+ ## Requirements
13
+
14
+ - ActiveAdmin `>= 3.0, < 4`
15
+ - Rails `>= 7.0`
16
+ - Ruby `>= 3.1`
17
+
18
+ ## Install
19
+
20
+ Add to your Gemfile:
21
+
22
+ ```ruby
23
+ gem "active_admin_prism"
24
+ ```
25
+
26
+ ```sh
27
+ bundle install
28
+ rails g active_admin_prism:install
29
+ ```
30
+
31
+ That's it. The generator:
32
+
33
+ - adds one line — `ActiveAdminPrism.enable!` — to your
34
+ `config/initializers/active_admin.rb`. The theme's CSS and JS are
35
+ registered automatically by the gem's Rails engine; there's no Sass/webpack
36
+ build step required, regardless of whether your app uses Sprockets or
37
+ Propshaft.
38
+ - if you have `app/assets/stylesheets/active_admin.scss` (generated by
39
+ `rails g active_admin:assets`, i.e. you're on the Sprockets/Sass path, not
40
+ Webpacker/importmap), adds one `@import` line there too — see
41
+ [below](#activeadmins-own-default-colors) for what it does.
42
+
43
+ If you'd rather do either by hand, skip the generator and just add
44
+ `ActiveAdminPrism.enable!` anywhere in your
45
+ `config/initializers/active_admin.rb` (after the `ActiveAdmin.setup` block
46
+ is fine), and `@import "active_admin_prism/variable_overrides";`
47
+ before `@import "active_admin/mixins";` in your `active_admin.scss`.
48
+
49
+ ## What it changes, and how
50
+
51
+ Prism follows a "light touch" philosophy: it changes as little of
52
+ ActiveAdmin's internals as possible, so it keeps working across ActiveAdmin
53
+ upgrades.
54
+
55
+ - **Sidebar** — `ActiveAdminPrism.enable!` swaps ActiveAdmin's `header`
56
+ slot (normally the top nav bar) for `ActiveAdmin::Views::PrismSidebar`,
57
+ using ActiveAdmin's own supported view-registration mechanism
58
+ (`ActiveAdmin::ViewFactory.register`). It renders your **existing**
59
+ `menu do |m| ... end` blocks from `app/admin/*.rb` — nested groups,
60
+ `priority`, `if:` — completely unchanged; only how that menu is drawn is
61
+ different. No other page structure (title bar, content, footer) is
62
+ touched.
63
+ - **Panels, tables, buttons, forms** — pure CSS reskin of ActiveAdmin's
64
+ existing markup (`.panel`, `.index_table`, Formtastic's `li.input.*`,
65
+ etc.). No Ruby view overrides here at all.
66
+ - **Icons** — a small curated set of inline SVG icons (no icon font, no
67
+ build step). Available anywhere in your admin views as
68
+ `prism_icon(:cart)`.
69
+ - **Confirm dialogs** — every `data-confirm` link (row-level View/Edit/Delete,
70
+ and anything else using Rails UJS's `data-confirm`) is routed through
71
+ ActiveAdmin's own styled jQuery UI dialog — the same one it already uses
72
+ for Batch Actions — instead of the native, unstylable browser `confirm()`.
73
+ This overrides `$.rails.allowAction`, jquery-ujs's own documented
74
+ extension point for custom confirm dialogs; Batch Actions links are left
75
+ untouched since they already run their own confirm flow. No-ops
76
+ gracefully if your app doesn't use jquery-rails/jquery-ujs.
77
+
78
+ ## Configuration
79
+
80
+ Every feature is individually toggleable via
81
+ `ActiveAdminPrism::Configuration` — including a `sidebar` flag that
82
+ lets you keep ActiveAdmin's stock top nav while still getting everything
83
+ else, and a full off switch for reverting to stock ActiveAdmin without
84
+ uninstalling the gem. All default to on:
85
+
86
+ ```ruby
87
+ ActiveAdminPrism.configure do |config|
88
+ config.sidebar = true # swap AA's top nav for the Prism sidebar
89
+ config.colorize_action_icons = true # color-coded View/Edit/Delete icons
90
+ config.styled_confirms = true # route data-confirm through the styled dialog
91
+ config.collapsible_filters = true # "Filters" panel collapses to an icon until clicked
92
+ config.sidebar_footer = true # "Powered by Active Admin" moves into the sidebar
93
+ config.flash_dismissible = true # dismiss (x) button on flash messages
94
+ config.flash_auto_dismiss = true # auto-hide flash messages
95
+ config.flash_auto_dismiss_seconds = 5
96
+ config.flash_transition_ms = 320 # fade/slide duration when a flash is dismissed
97
+ config.login_page = true # centered card + brand mark on the sign-in page
98
+ config.login_logo = nil # nil = Prism's built-in mark; or a String/Proc/Symbol
99
+ config.login_app_name = nil # nil = falls back to AA's own config.site_title
100
+ config.login_tagline = "Sign in to your admin dashboard"
101
+ config.language_switcher = true # "Languages" dropdown near the top of the sidebar
102
+ config.languages = [ # defaults to these 3 — replace freely
103
+ { label: "English", locale: :en },
104
+ { label: "Español", locale: :es },
105
+ { label: "Français", locale: :fr }
106
+ ]
107
+ end
108
+
109
+ ActiveAdminPrism.enable!
110
+ ```
111
+
112
+ See [INTEGRATION.md](INTEGRATION.md#configuration-reference) for the full
113
+ reference, and [INTEGRATION.md](INTEGRATION.md#plug-and-play-switching-the-theme-onoff)
114
+ for switching the whole theme on/off (including a full revert to stock
115
+ ActiveAdmin, gem still installed).
116
+
117
+ ## Sidebar navigation: icons & badges
118
+
119
+ Menu items are still defined the normal ActiveAdmin way. Two extra,
120
+ optional conventions:
121
+
122
+ ```ruby
123
+ # app/admin/dashboard.rb / any resource file
124
+ menu label: "Orders", priority: 2, html_options: { icon: :box }
125
+
126
+ menu label: -> { "Messages #{content_tag(:span, unread_count, class: 'nav-badge')}".html_safe },
127
+ html_options: { icon: :message }
128
+ ```
129
+
130
+ `icon:` (inside `html_options:` — ActiveAdmin's own `MenuItem` already passes
131
+ this hash through untouched, so no new DSL is introduced) accepts any symbol
132
+ from the bundled set: `:dashboard`, `:users`,
133
+ `:cart`, `:box`, `:receipt`, `:credit_card`, `:message`, `:settings`,
134
+ `:home`, `:list`, `:folder`, `:bell`, `:search`, `:menu`, `:logout`,
135
+ `:check`, `:x`, `:chevron_down`, `:eye`, `:pencil`, `:trash`, `:filter`,
136
+ `:globe`.
137
+
138
+ ## Language switcher
139
+
140
+ A "Languages" dropdown renders near the top of the sidebar (below the
141
+ brand, above the Pages nav) — no `admin.build_menu :utility_navigation`
142
+ code needed. Ships with 3 languages; replace the list freely:
143
+
144
+ ```ruby
145
+ ActiveAdminPrism.configure do |config|
146
+ config.languages = [
147
+ { label: "English", locale: :en },
148
+ { label: "Deutsch", locale: :de },
149
+ { label: "日本語", locale: :ja }
150
+ ]
151
+ end
152
+ ```
153
+
154
+ By default, each option links to the current page with `?locale=xx`
155
+ appended (the same convention you'd use by hand with
156
+ `url_for(locale: ...)`) — actually switching `I18n.locale` based on that
157
+ param is your own app's responsibility (typically a `before_action`), same
158
+ as it would be if you'd wired the menu up yourself. Give any entry its own
159
+ `url:` (String/Proc/Symbol) to hit something else instead, e.g. a remote
160
+ endpoint that sets the locale server-side:
161
+
162
+ ```ruby
163
+ { label: "日本語", locale: :ja,
164
+ url: -> { "https://example.com/set_locale?locale=ja&return_to=#{request.path}" } }
165
+ ```
166
+
167
+ Turn the whole thing off with `config.language_switcher = false`.
168
+
169
+ ## Toggle switches
170
+
171
+ Boolean fields render as regular (reskinned) checkboxes by default. Opt in
172
+ to a switch-style toggle per field:
173
+
174
+ ```ruby
175
+ form do |f|
176
+ f.input :active, as: :prism_toggle
177
+ end
178
+ ```
179
+
180
+ This only changes the wrapping markup — submitted params are identical to
181
+ `as: :boolean`.
182
+
183
+ For **index columns** and **show attributes_table rows**, use the matching
184
+ read-only `prism_toggle_tag` helper in place of ActiveAdmin's default
185
+ `status_tag` "Yes"/"No" pill:
186
+
187
+ ```ruby
188
+ index do
189
+ column :active do |product|
190
+ prism_toggle_tag product.active
191
+ end
192
+ end
193
+
194
+ show do
195
+ attributes_table do
196
+ row :active do |product|
197
+ prism_toggle_tag product.active
198
+ end
199
+ end
200
+ end
201
+ ```
202
+
203
+ It's an explicit opt-in per column/row (like everything else in Prism) —
204
+ ActiveAdmin's default boolean rendering is untouched everywhere you don't
205
+ call it.
206
+
207
+ ## Sign-in page
208
+
209
+ Every Devise auth page (sign in, sign up, forgot/reset password, resend
210
+ confirmation, resend unlock — whichever of these your app actually uses)
211
+ gets a centered card, an animated brand mark, a full-width submit button,
212
+ and a row of pill-shaped links instead of ActiveAdmin's default gradient
213
+ header box — no setup needed. The icon and app name are shared across all
214
+ of them; the tagline underneath is sign-in's own configurable line, while
215
+ every other page just names its own action ("Sign up", "Forgot your
216
+ password?", etc.):
217
+
218
+ ```ruby
219
+ ActiveAdminPrism.configure do |config|
220
+ config.login_logo = -> { image_tag "my_logo.svg", height: 40 }
221
+ config.login_app_name = "My Company Admin"
222
+ config.login_tagline = "Internal operations console"
223
+ end
224
+ ```
225
+
226
+ `login_logo`/`login_app_name`/`login_tagline` each accept a `String`, `Proc`
227
+ (instance_exec'd in the view — `image_tag`/`prism_icon` are both available),
228
+ or `Symbol` (a method name) — the same convention ActiveAdmin itself uses
229
+ for `config.footer`. Turn the whole thing off with `config.login_page =
230
+ false` to keep ActiveAdmin's original plain login box. See
231
+ [INTEGRATION.md](INTEGRATION.md#sign-in-page) for the Gemfile-ordering note
232
+ behind how this view override works.
233
+
234
+ ## Error pages (404/500)
235
+
236
+ ```sh
237
+ rails g active_admin_prism:error_pages
238
+ ```
239
+
240
+ Copies Prism-styled `public/404.html` and `public/500.html` into your app.
241
+ This one is a separate, explicit step (not part of `install`, and not
242
+ config-driven) because static exception pages are read straight off disk by
243
+ Rails — there's no engine hook to override them automatically, and a host's
244
+ existing `public/404.html`/`500.html` are usually already customized, so
245
+ silently touching them on every `install` run would be surprising. The
246
+ generator prompts before overwriting either file. Once copied, they're
247
+ plain static HTML/CSS with no Ruby behind them — edit them directly for
248
+ further changes.
249
+
250
+ ## Customizing colors
251
+
252
+ The shipped `prism.css` is compiled from Sass variables (see
253
+ `scss-src/_variables.scss` in this gem's source) such as
254
+ `$prism-color-primary`, `$prism-bg-page`, `$prism-sidebar-width`. To use
255
+ your own palette, fork the SCSS source, adjust the variables, and run
256
+ `bin/build-css` to produce your own `prism.css` — see
257
+ [CONTRIBUTING](#development) below.
258
+
259
+ ### ActiveAdmin's own default colors
260
+
261
+ Prism reskins ActiveAdmin's existing markup with CSS, but a few things
262
+ ActiveAdmin renders itself — the jQuery UI batch-actions confirm dialog, the
263
+ dropdown menu popup, any custom page you write with `panel`/`section-background`
264
+ — are built from ActiveAdmin's own Sass variables
265
+ (`active_admin/mixins/_variables.scss` and `_gradients.scss`), not from
266
+ anything a precompiled CSS file can reach into.
267
+
268
+ Rather than chase every individual AA component that might leak its default
269
+ gray through, the gem ships
270
+ [`variable_overrides.scss`](app/assets/stylesheets/active_admin_prism/_variable_overrides.scss) —
271
+ Prism's values for every one of those variables. Since they're all declared
272
+ `!default` in the activeadmin gem, `@import`-ing this file **before**
273
+ `@import "active_admin/mixins"` in your `active_admin.scss` means everything
274
+ ActiveAdmin generates from that point on inherits Prism's palette as its
275
+ baseline instead of gray:
276
+
277
+ ```scss
278
+ // app/assets/stylesheets/active_admin.scss
279
+ @import "active_admin_prism/variable_overrides";
280
+ @import "active_admin/mixins";
281
+ @import "active_admin/base";
282
+ ```
283
+
284
+ The install generator adds this line for you automatically if this file
285
+ exists in your app. Every variable in `variable_overrides.scss` is itself
286
+ `!default`, so you can customize further — set your own value (including
287
+ `$sidebar-width`, which it widens from AA's default 270px to 320px to fit a
288
+ "select + input" filter row comfortably) before that `@import` and it wins.
289
+
290
+ This only works inside your own app's Sass compilation (where
291
+ `active_admin/mixins` is actually `@import`-ed) — it's a one-time addition to
292
+ your app, not something a precompiled CSS file can do on your behalf.
293
+
294
+ ## Development
295
+
296
+ ```sh
297
+ bin/build-css # compiles + minifies scss-src/*.scss -> app/assets/stylesheets/active_admin_prism/prism.css
298
+ bin/build-js # minifies js-src/prism.js -> app/assets/javascripts/active_admin_prism/prism.js
299
+ bundle install
300
+ bundle exec rspec # or: rake
301
+ ```
302
+
303
+ Never hand-edit the committed `prism.css`/`prism.js` — edit
304
+ `scss-src/*.scss`/`js-src/prism.js` and rebuild. Both committed assets are
305
+ shipped pre-minified (not just for Sprockets hosts, who'd normally
306
+ re-minify on their own `assets:precompile` anyway, but for Propshaft hosts
307
+ too, since Propshaft has no built-in minification step at all) — all the
308
+ documentation comments explaining the theme's various CSS-specificity
309
+ fixes etc. live in the `scss-src`/`js-src` sources, not the compiled
310
+ output.
311
+
312
+ The test suite boots a minimal Rails + ActiveAdmin + Devise app
313
+ (`spec/dummy`) and exercises the gem against real HTTP requests — no
314
+ mocking of ActiveAdmin/Arbre internals. See `spec/rails_helper.rb` for how
315
+ it's wired up.
316
+
317
+ ## License
318
+
319
+ MIT
@@ -0,0 +1 @@
1
+ !function(){"use strict";function t(t){return a+t.id}function e(e,n){e.classList.toggle("open",n);try{window.localStorage.setItem(t(e),n?"1":"0")}catch(t){}}function n(e){e.querySelectorAll(".prism-nav-item.has-children").forEach(function(e){var n;try{n=window.localStorage.getItem(t(e))}catch(t){n=null}"1"===n?e.classList.add("open"):"0"===n&&e.classList.remove("open")})}function s(t){var n=t.target.closest("[data-prism-toggle]");if(n){var s=n.closest(".prism-nav-item");s&&e(s,!s.classList.contains("open"))}}function i(t){t.target.closest("[data-prism-toggle-sidebar]")&&document.body.classList.toggle("prism-sidebar-open")}var a="prism_sidebar_";document.addEventListener("DOMContentLoaded",function(){var t=document.getElementById("header");t&&t.classList.contains("prism-sidebar")&&(n(t),t.addEventListener("click",s),t.addEventListener("click",i))})}(),function(){"use strict";document.addEventListener("DOMContentLoaded",function(){if(!document.body.classList.contains("prism-styled-confirms-disabled")&&"undefined"!=typeof jQuery&&jQuery.rails&&window.ActiveAdmin&&window.ActiveAdmin.ModalDialog){var t=jQuery,e=t.rails.allowAction;t.rails.allowAction=function(n){var s=n.data("confirm");return s?n.closest(".batch_actions_selector").length?e.call(t.rails,n):n.data("prismConfirmed")?(n.removeData("prismConfirmed"),!0):(new window.ActiveAdmin.ModalDialog(s,{},function(){n.data("prismConfirmed",!0),n[0].click()}),!1):e.call(t.rails,n)}}})}(),function(){"use strict";function t(t,e){t.dataset.prismDismissed||(t.dataset.prismDismissed="true",t.style.transitionDuration=e+"ms",t.classList.add("prism-flash-hide"),setTimeout(function(){t.remove()},e))}var e=320;document.addEventListener("DOMContentLoaded",function(){var n=document.querySelector(".flashes"),s=document.querySelectorAll(".flashes .flash");if(s.length){var i=n&&parseInt(n.dataset.prismTransitionMs,10)||e,a=n&&parseInt(n.dataset.prismAutoDismissMs,10);a&&s.forEach(function(e){setTimeout(function(){t(e,i)},a)}),document.addEventListener("click",function(e){var n=e.target.closest("[data-prism-flash-dismiss]");n&&t(n.closest(".flash"),i)})}})}(),function(){"use strict";document.addEventListener("DOMContentLoaded",function(){function t(){var t=e.classList.toggle("open");n.setAttribute("aria-expanded",t?"true":"false"),document.body.classList.toggle("prism-filters-open",t)}if(!document.body.classList.contains("prism-filters-collapsible-disabled")){var e=document.getElementById("filters_sidebar_section");if(e){var n=e.querySelector(":scope > h3");n&&(n.setAttribute("role","button"),n.setAttribute("tabindex","0"),n.setAttribute("aria-expanded",e.classList.contains("open")?"true":"false"),document.body.classList.toggle("prism-filters-open",e.classList.contains("open")),n.addEventListener("click",t),n.addEventListener("keydown",function(e){"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),t())}))}}})}(),function(){"use strict";function t(t){document.querySelectorAll(".prism-sidebar-lang.open").forEach(function(e){if(e!==t){e.classList.remove("open");var n=e.querySelector(".prism-lang-toggle");n&&n.setAttribute("aria-expanded","false")}})}document.addEventListener("DOMContentLoaded",function(){function e(){var e=s.classList.toggle("open");n.setAttribute("aria-expanded",e?"true":"false"),e&&t(s)}var n=document.querySelector(".prism-lang-toggle");if(n){var s=n.closest(".prism-sidebar-lang");n.setAttribute("role","button"),n.setAttribute("tabindex","0"),n.addEventListener("click",function(t){t.stopPropagation(),e()}),n.addEventListener("keydown",function(t){"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),e())}),document.addEventListener("click",function(){t()})}})}();
@@ -0,0 +1,43 @@
1
+ // Prism's override of ActiveAdmin's own default (grayscale) Sass palette.
2
+ //
3
+ // Every variable below is declared `!default` in the activeadmin gem itself
4
+ // — active_admin/mixins/_variables.scss and _gradients.scss — and used
5
+ // throughout its own component partials (buttons, dropdown menus, tables,
6
+ // panels, dialogs, breadcrumbs, blank slates...). Because they're `!default`,
7
+ // whichever assignment runs FIRST wins; @import-ing this file before
8
+ // "active_admin/mixins" means ActiveAdmin's own generated CSS inherits
9
+ // Prism's palette as its baseline from the start, rather than gray — even
10
+ // in places this theme's own compiled CSS doesn't explicitly reskin.
11
+ //
12
+ // Usage — in your app's app/assets/stylesheets/active_admin.scss:
13
+ //
14
+ // @import "active_admin_prism/variable_overrides";
15
+ // @import "active_admin/mixins";
16
+ // @import "active_admin/base";
17
+ //
18
+ // Every variable here is itself `!default`, so you can customize further:
19
+ // set your own value before this @import and it wins over Prism's.
20
+
21
+ // Colors
22
+ $primary-color: #6d5bd0 !default;
23
+ $text-color: #384250 !default;
24
+ $link-color: #6d5bd0 !default;
25
+ $body-background-color: #f4f5f7 !default;
26
+ $secondary-color: #f4f5f7 !default;
27
+ $error-color: #ef4444 !default;
28
+ $table-selected-color: #f2ecfd !default;
29
+ $blank-slate-primary-color: #6b7280 !default;
30
+ $breadcrumbs-color: #6b7280 !default;
31
+ $breadcrumbs-separator-color: #d6d9e0 !default;
32
+ $required-field-marker-color: #9aa1ab !default;
33
+
34
+ // Gradients (active_admin/mixins/_gradients.scss — used by the
35
+ // section-background / section-header mixins behind panels & dialogs)
36
+ $secondary-gradient-start: #ffffff !default;
37
+ $secondary-gradient-stop: #f4f5f7 !default;
38
+
39
+ // Sizes
40
+ // AA's default 270px is too narrow for a "select + input" filter row at
41
+ // Prism's padding/font size; #main_content's right margin is calculated
42
+ // from this same variable, so widening it here keeps both in sync.
43
+ $sidebar-width: 320px !default;
@@ -0,0 +1 @@
1
+ body{background:#f4f5f7;color:#384250;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}#active_admin_content h2,#active_admin_content h3{color:#1a1f36;font-weight:600}a{color:#6d5bd0}a:hover{color:#5949b8}#title_bar{background:transparent;border:none;box-shadow:none;text-shadow:none;padding:10px 10px 8px}#title_bar h2#page_title{color:#1a1f36;font-weight:700;font-size:1.6em;letter-spacing:-0.01em}#footer{color:#6b7280;font-size:0.85em;padding:10px;border-top:1px solid #e6e8ec}#footer a{color:#6b7280;text-decoration:underline}#footer a:hover{color:#6d5bd0}.flashes{padding:10px 10px 0}body.active_admin .flash{position:relative;display:flex;align-items:flex-start;gap:12px;background:#f4f5f7;border:1px solid #e6e8ec;border-left:3px solid #6b7280;border-radius:6px;box-shadow:none;text-shadow:none;color:#1a1f36;font-size:0.9em;font-weight:600;line-height:1.4;padding:10px 16px;margin-bottom:0;opacity:1;transform:translateY(0) scale(1);transition:opacity 320ms cubic-bezier(0.4, 0, 0.2, 1),transform 320ms cubic-bezier(0.4, 0, 0.2, 1)}body.active_admin .flash.prism-flash-hide{opacity:0;transform:translateY(-6px) scale(0.98)}body.active_admin .flash.flash_notice{background:#e8f9ee;border-left-color:#22c55e;color:#136e34}body.active_admin .flash.flash_error,body.active_admin .flash.flash_alert{background:#fdecec;border-left-color:#ef4444;color:#eb1515}.prism-flash-message{flex:1 1 auto}.prism-flash-dismiss{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin:-2px -4px -2px 0;padding:0;border:none;border-radius:6px;background:transparent !important;color:inherit !important;opacity:0.6;cursor:pointer;transition:opacity 120ms ease,background 120ms ease}.prism-flash-dismiss:hover{opacity:1;background:rgba(0,0,0,0.06) !important}.prism-flash-dismiss-icon{display:block;margin:0}.ui-widget-overlay{background:rgba(15,18,26,0.45)}.ui-dialog{background:#fff;border:1px solid #e6e8ec;border-radius:10px;box-shadow:0 4px 6px rgba(16,24,40,0.05),0 10px 24px rgba(16,24,40,0.08);padding:0;overflow:hidden;outline:none}.ui-dialog:focus{outline:none}.ui-dialog .ui-dialog-titlebar{background:#fff;border:none;border-bottom:1px solid #e6e8ec;box-shadow:none;text-shadow:none;color:#1a1f36;font-weight:700;padding:16px 20px}.ui-dialog .ui-dialog-titlebar span{color:inherit}.ui-dialog form{padding:0}.ui-dialog ul{margin:0;padding:0}.ui-dialog ul li{padding:10px 20px;margin:0}.ui-dialog label{color:#384250;font-weight:600}.ui-dialog .ui-dialog-buttonpane{background:#f4f5f7;padding:12px 20px;display:flex;justify-content:flex-end;gap:8px}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{display:flex;gap:8px}.ui-dialog .ui-dialog-buttonpane button,.ui-dialog .ui-dialog-buttonset button{margin:0}.ui-dialog .ui-dialog-buttonpane button:first-child,.ui-dialog .ui-dialog-buttonset button:first-child{background:#6d5bd0 !important;background-image:none !important;border:1px solid #6d5bd0;border-radius:6px;color:#fff !important;text-shadow:none;box-shadow:none;font-weight:600;padding:9px 16px;transition:background 120ms ease,border-color 120ms ease}.ui-dialog .ui-dialog-buttonpane button:first-child:hover,.ui-dialog .ui-dialog-buttonset button:first-child:hover{background:#5949b8 !important;border-color:#5949b8;color:#fff !important}.ui-dialog .ui-dialog-buttonpane button:first-child:active,.ui-dialog .ui-dialog-buttonset button:first-child:active{background:#5949b8 !important;box-shadow:none}.ui-dialog .ui-dialog-buttonpane button:last-child,.ui-dialog .ui-dialog-buttonset button:last-child{background:#fff !important;background-image:none !important;border:1px solid #d6d9e0;border-radius:6px;color:#384250 !important;text-shadow:none;box-shadow:none;font-weight:600;padding:8px 15px;transition:background 120ms ease,border-color 120ms ease}.ui-dialog .ui-dialog-buttonpane button:last-child:hover,.ui-dialog .ui-dialog-buttonset button:last-child:hover{background:#f4f5f7 !important;border-color:#6b7280;color:#1a1f36 !important}.ui-dialog .ui-dialog-buttonpane button:last-child:active,.ui-dialog .ui-dialog-buttonset button:last-child:active{background:#f4f5f7 !important;box-shadow:none}.breadcrumb{font-size:0.85em;font-weight:600;letter-spacing:0.02em;text-transform:uppercase;color:#6b7280;margin-bottom:6px}.breadcrumb a,.breadcrumb a:link,.breadcrumb a:visited,.breadcrumb a:active{color:#6b7280;text-decoration:none}.breadcrumb a:hover,.breadcrumb a:link:hover,.breadcrumb a:visited:hover,.breadcrumb a:active:hover{color:#6d5bd0;text-decoration:none}.breadcrumb .breadcrumb_sep{color:#d6d9e0}body:not(.logged_out) #wrapper,body.index:not(.logged_out) #wrapper{display:grid;grid-template-columns:264px 1fr;grid-template-rows:auto auto auto 1fr auto;min-height:100vh;width:100%}#header.prism-sidebar{grid-column:1;grid-row:1 / -1;display:flex;background:#fff !important;background-image:none !important;border-right:1px solid #e6e8ec;padding:0;height:auto;width:264px;position:sticky;top:0;align-self:stretch;max-height:100vh;overflow:hidden;z-index:100;text-shadow:none !important;box-shadow:none !important;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}#title_bar{grid-column:2;grid-row:2}.flashes{grid-column:2;grid-row:3;align-self:start}#active_admin_content{grid-column:2;grid-row:4;min-width:0;padding:10px}body:not(.prism-sidebar-footer-disabled) #footer{display:none}#header.prism-sidebar .prism-sidebar-inner{display:flex;flex-direction:column;width:100%;height:100%;max-height:100vh}#header.prism-sidebar .prism-sidebar-brand{flex:0 0 auto;padding:20px 24px;border-bottom:1px solid #e6e8ec}#header.prism-sidebar .prism-sidebar-brand #site_title{margin:0;padding:0;font-size:1.15em;font-weight:700;color:#1a1f36}#header.prism-sidebar .prism-sidebar-brand #site_title a{color:inherit;text-decoration:none}#header.prism-sidebar .prism-sidebar-lang{position:relative;flex:0 0 auto;padding:10px 12px;border-bottom:1px solid #e6e8ec}#header.prism-sidebar .prism-sidebar-lang.open .prism-chevron{transform:rotate(180deg)}#header.prism-sidebar .prism-sidebar-lang.open .prism-lang-menu{display:block}#header.prism-sidebar .prism-lang-toggle{display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;border-radius:6px;color:#384250;font-size:0.85em;font-weight:600;cursor:pointer;user-select:none;transition:background 120ms ease}#header.prism-sidebar .prism-lang-toggle:hover{background:#f4f5f7}#header.prism-sidebar .prism-lang-toggle .prism-nav-icon{flex:0 0 auto;color:#6b7280}#header.prism-sidebar .prism-lang-toggle .prism-chevron{flex:0 0 auto;margin-left:auto;transition:transform 120ms ease}#header.prism-sidebar .prism-lang-current{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#header.prism-sidebar .prism-lang-menu{display:none;list-style:none;margin:4px 0 0;padding:4px;position:absolute;left:12px;right:12px;z-index:50;background:#fff;border:1px solid #e6e8ec;border-radius:6px;box-shadow:0 4px 6px rgba(16,24,40,0.05),0 10px 24px rgba(16,24,40,0.08)}#header.prism-sidebar .prism-lang-menu li{margin:0}#header.prism-sidebar .prism-lang-option{display:block;padding:8px 10px;border-radius:6px;color:#384250;font-size:0.85em;font-weight:600;text-decoration:none}#header.prism-sidebar .prism-lang-option:hover{background:#f4f5f7}#header.prism-sidebar .prism-lang-option.active{background:#f2ecfd;color:#5949b8}#header.prism-sidebar .prism-sidebar-scroll{flex:1 1 auto;overflow-y:auto;padding:20px 12px}#header.prism-sidebar .prism-sidebar-utility{flex:0 0 auto;padding:12px;border-top:1px solid #e6e8ec}#header.prism-sidebar .prism-sidebar-utility ul.prism-nav-utility{background:#f4f5f7;border-radius:10px;padding:4px}#header.prism-sidebar .prism-sidebar-utility .prism-nav-item{margin:0}#header.prism-sidebar .prism-sidebar-utility #prism_nav_current_user>.prism-nav-link{padding:10px 10px 6px;font-weight:600;color:#1a1f36;font-size:0.88em}#header.prism-sidebar .prism-sidebar-utility #prism_nav_current_user>.prism-nav-link:hover{background:transparent}#header.prism-sidebar .prism-sidebar-utility #prism_nav_current_user>.prism-nav-link .prism-nav-label{white-space:normal;word-break:break-word}#header.prism-sidebar .prism-sidebar-utility #prism_nav_logout>.prism-nav-link{padding:6px 10px 8px;font-size:0.85em;color:#6b7280}#header.prism-sidebar .prism-sidebar-utility #prism_nav_logout>.prism-nav-link:hover{color:#ef4444;background:transparent}#header.prism-sidebar .prism-sidebar-footer{flex:0 0 auto;padding:10px 16px;border-top:1px solid #e6e8ec;color:#6b7280;font-size:0.72em;line-height:1.4;text-align:center}#header.prism-sidebar .prism-sidebar-footer a{color:#6b7280;text-decoration:underline}#header.prism-sidebar .prism-sidebar-footer a:hover{color:#6d5bd0}#header.prism-sidebar .prism-nav-section-label{padding:0 12px 8px;font-size:0.72em;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:#6b7280}#header.prism-sidebar ul.prism-nav{list-style:none;margin:0;padding:0}#header.prism-sidebar .prism-nav-item{margin:2px 0}#header.prism-sidebar .prism-nav-item>.prism-nav-link,#header.prism-sidebar .prism-nav-item>.prism-nav-group-toggle{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:6px;color:#1a1f36;font-size:0.92em;font-weight:600;text-decoration:none;cursor:pointer;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;transition:background 120ms ease,color 120ms ease}#header.prism-sidebar .prism-nav-item>.prism-nav-link:hover,#header.prism-sidebar .prism-nav-item>.prism-nav-group-toggle:hover{background:#f4f5f7;color:#1a1f36}#header.prism-sidebar .prism-nav-item.active>.prism-nav-link,#header.prism-sidebar .prism-nav-item.active>.prism-nav-group-toggle{background:#f2ecfd;color:#5949b8;font-weight:700}#header.prism-sidebar .prism-nav-item .prism-nav-icon{flex:0 0 auto;color:inherit}#header.prism-sidebar .prism-nav-item .prism-nav-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#header.prism-sidebar .prism-nav-item .prism-chevron{flex:0 0 auto;transition:transform 120ms ease}#header.prism-sidebar .prism-nav-item.open>.prism-nav-group-toggle .prism-chevron{transform:rotate(180deg)}#header.prism-sidebar .prism-nav-item .prism-nav-submenu{list-style:none;margin:2px 0 2px 30px;padding:0;display:none}#header.prism-sidebar .prism-nav-item.open>.prism-nav-submenu{display:block}#header.prism-sidebar .prism-nav-item.has-children>.prism-nav-submenu .prism-nav-item>.prism-nav-link{font-size:0.88em}#header.prism-sidebar .prism-nav-utility .prism-nav-item>.prism-nav-link,#header.prism-sidebar .prism-nav-utility .prism-nav-item>.prism-nav-group-toggle{color:#6b7280}#header.prism-sidebar .nav-badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;margin-left:auto;border-radius:999px;background:#6d5bd0;color:#fff;font-size:0.72em;font-weight:700;line-height:20px}.prism-sidebar-mobile-toggle{display:none}@media (max-width: 900px){.prism-sidebar-mobile-toggle{display:flex;align-items:center;justify-content:center;position:fixed;top:14px;left:14px;width:38px;height:38px;border-radius:6px;background:#fff;color:#384250;box-shadow:0 1px 2px rgba(16,24,40,0.04), 0 1px 6px rgba(16,24,40,0.04);cursor:pointer;z-index:200}#wrapper,.index #wrapper{grid-template-columns:1fr}#header.prism-sidebar{position:fixed;left:0;top:0;bottom:0;transform:translateX(-100%);transition:transform 120ms ease;box-shadow:0 4px 6px rgba(16,24,40,0.05), 0 10px 24px rgba(16,24,40,0.08)}#title_bar,.flashes,#active_admin_content,#footer{grid-column:1}body.prism-sidebar-open #header.prism-sidebar{transform:translateX(0)}}.panel{background:#fff;border:1px solid #e6e8ec;border-radius:10px;box-shadow:0 1px 2px rgba(16,24,40,0.04),0 1px 6px rgba(16,24,40,0.04);margin-bottom:20px;overflow:hidden}.panel>h3{margin:0;padding:16px 20px;background:transparent;border-bottom:1px solid #e6e8ec;color:#1a1f36;font-size:1em;font-weight:600}.panel .panel_contents{padding:20px}.panel .header_action{float:right}.columns{display:flex;flex-wrap:wrap;gap:20px;margin:0}.columns .column{flex:1 1 260px;min-width:0}#sidebar{box-sizing:border-box;overflow-x:hidden}#sidebar .panel{box-sizing:border-box}#active_admin_content #main_content_wrapper #main_content,#active_admin_content #sidebar{transition:margin-right 280ms cubic-bezier(0.4, 0, 0.2, 1),width 280ms cubic-bezier(0.4, 0, 0.2, 1),margin-left 280ms cubic-bezier(0.4, 0, 0.2, 1)}body:has(.prism-collapsible-panel):not(.prism-filters-open) #active_admin_content:not(.without_sidebar) #main_content_wrapper #main_content{margin-right:72px}body:has(.prism-collapsible-panel):not(.prism-filters-open) #active_admin_content #sidebar{width:72px;margin-left:-72px}.prism-collapsible-panel{background:transparent;border-color:transparent;box-shadow:none;margin-bottom:10px;transition:background 120ms ease,border-color 120ms ease,box-shadow 120ms ease,margin 120ms ease}.prism-collapsible-panel>h3{display:flex;align-items:center;gap:8px;width:40px;height:40px;margin:0 0 0 auto;padding:0;justify-content:center;border:1px solid #e6e8ec;border-radius:6px;background:#fff;box-shadow:0 1px 2px rgba(16,24,40,0.04),0 1px 6px rgba(16,24,40,0.04);color:#1a1f36;cursor:pointer;user-select:none;overflow:hidden;transition:width 120ms ease,padding 120ms ease,justify-content 120ms ease,background 120ms ease,border-color 120ms ease}.prism-collapsible-panel>h3:hover{background:#f2ecfd;color:#5949b8}.prism-collapsible-panel .prism-filter-icon{flex:0 0 auto;order:-1}.prism-collapsible-panel .prism-filter-label{max-width:0;overflow:hidden;opacity:0;white-space:nowrap;transition:max-width 200ms ease, opacity 150ms ease}.prism-collapsible-panel .panel_contents{overflow:hidden;max-height:0;opacity:0;padding-top:0;padding-bottom:0;transition:max-height 280ms cubic-bezier(0.4, 0, 0.2, 1),opacity 200ms ease,padding 200ms ease}.prism-collapsible-panel.open{background:#fff;border-color:#e6e8ec;box-shadow:0 1px 2px rgba(16,24,40,0.04),0 1px 6px rgba(16,24,40,0.04);margin-bottom:20px}.prism-collapsible-panel.open>h3{width:100%;height:auto;margin:0;justify-content:flex-start;padding:16px 20px;border:none;border-bottom:1px solid #e6e8ec;background:transparent;box-shadow:none;color:#1a1f36;border-radius:0}.prism-collapsible-panel.open>h3:hover{background:transparent;color:#1a1f36}.prism-collapsible-panel.open .prism-filter-label{max-width:200px;opacity:1}.prism-collapsible-panel.open .panel_contents{max-height:1200px;opacity:1;padding-top:20px;padding-bottom:20px}body.prism-filters-collapsible-disabled .prism-collapsible-panel{background:#fff;border-color:#e6e8ec;box-shadow:0 1px 2px rgba(16,24,40,0.04),0 1px 6px rgba(16,24,40,0.04);margin-bottom:20px}body.prism-filters-collapsible-disabled .prism-collapsible-panel>h3{width:100%;height:auto;margin:0;justify-content:flex-start;padding:16px 20px;border:none;border-bottom:1px solid #e6e8ec;box-shadow:none;cursor:default}body.prism-filters-collapsible-disabled .prism-collapsible-panel .panel_contents{max-height:none;opacity:1;overflow:visible;padding:20px}.blank_slate_container .blank_slate{background:#fff;border:1px dashed #d6d9e0;border-radius:10px;color:#6b7280;font-weight:600;box-shadow:none}.comments .active_admin_comment_meta{color:#6b7280}.comments .active_admin_comment_meta .active_admin_comment_author{color:#1a1f36}.paginated_collection_contents{overflow-x:auto}table.index_table{background:#fff;border:1px solid #e6e8ec;border-radius:10px;border-spacing:0;border-collapse:separate;overflow:hidden}table.index_table th,table.index_table td{padding:12px 16px}table.index_table th{background:#f4f5f7;color:#6b7280;font-size:0.78em;font-weight:700;letter-spacing:0.04em;text-transform:uppercase;border:none;border-bottom:1px solid #e6e8ec;white-space:nowrap}table.index_table th a{white-space:nowrap}table.index_table th:last-child{border-right:none}table.index_table th.sorted-asc,table.index_table th.sorted-desc{background:#f4f5f7}table.index_table td{border-bottom:1px solid #e6e8ec;color:#384250}table.index_table tr:last-child td{border-bottom:none}table.index_table tr.even td{background:transparent}table.index_table tr.selected td{background:#f2ecfd}table.index_table tbody tr:hover td{background:#f4f5f7}table.index_table td.col-actions{white-space:nowrap}.table_actions{display:flex;align-items:center;gap:4px}.table_actions a{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:6px;transition:background 120ms ease,color 120ms ease}.table_actions a.view_link{color:#3b82f6}.table_actions a.view_link:hover{background:rgba(59,130,246,0.12);color:#0b63f3}.table_actions a.edit_link{color:#6d5bd0}.table_actions a.edit_link:hover{background:#f2ecfd;color:#5949b8}.table_actions a.delete_link{color:#ef4444}.table_actions a.delete_link:hover{background:#fdecec;color:#eb1515}.table_actions .prism-action-icon{margin:0}.status_tag{border-radius:999px;background:#d6d9e0;color:#1a1f36;text-transform:none;letter-spacing:0;font-weight:600;padding:3px 10px}.status_tag.yes{background:#e8f9ee;color:#17843f}.status_tag.no{background:#fdecec;color:#ed2d2d}form fieldset.inputs{background:#fff;border:1px solid #e6e8ec;border-radius:10px;padding:20px}form fieldset legend span{color:#1a1f36;font-weight:700;font-size:1.05em;text-transform:none;letter-spacing:normal}form fieldset ol>li label{color:#384250;font-weight:600;font-size:0.9em}form input[type="text"],form input[type="password"],form input[type="email"],form input[type="number"],form input[type="url"],form input[type="tel"],form input[type="date"],form input[type="time"],form input[type="search"],form select,form textarea{border:1px solid #d6d9e0;border-radius:6px;color:#1a1f36;padding:9px 12px;box-shadow:none;transition:border-color 120ms ease,box-shadow 120ms ease}form input[type="text"]:focus,form input[type="password"]:focus,form input[type="email"]:focus,form input[type="number"]:focus,form input[type="url"]:focus,form input[type="tel"]:focus,form input[type="date"]:focus,form input[type="time"]:focus,form input[type="search"]:focus,form select:focus,form textarea:focus{border-color:#6d5bd0;box-shadow:0 0 0 3px rgba(109,91,208,0.15)}form fieldset>ol>li.error input[type="text"],form fieldset>ol>li.error input[type="password"],form fieldset>ol>li.error input[type="email"],form fieldset>ol>li.error input[type="number"],form fieldset>ol>li.error input[type="url"],form fieldset>ol>li.error input[type="tel"],form fieldset>ol>li.error textarea,form fieldset>ol>li.error select{border-color:#ef4444}form fieldset>ol>li.error input[type="text"]:focus,form fieldset>ol>li.error input[type="password"]:focus,form fieldset>ol>li.error input[type="email"]:focus,form fieldset>ol>li.error input[type="number"]:focus,form fieldset>ol>li.error input[type="url"]:focus,form fieldset>ol>li.error input[type="tel"]:focus,form fieldset>ol>li.error textarea:focus,form fieldset>ol>li.error select:focus{box-shadow:0 0 0 3px rgba(239,68,68,0.15)}form fieldset>ol>li p.inline-errors{color:#ef4444;font-weight:600}form ul.errors{background:#fdecec;color:#ef4444;border-radius:6px}form input[type="checkbox"],form input[type="radio"]{appearance:none;position:relative;width:18px;height:18px;margin:0 8px 0 0;border:1px solid #d6d9e0;background:#fff;vertical-align:middle;cursor:pointer;flex:0 0 auto}form input[type="checkbox"]:checked,form input[type="radio"]:checked{background:#6d5bd0;border-color:#6d5bd0}form input[type="checkbox"]:checked::after,form input[type="radio"]:checked::after{content:"";position:absolute;left:5px;top:1px;width:5px;height:10px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg)}form input[type="checkbox"]:focus-visible,form input[type="radio"]:focus-visible{box-shadow:0 0 0 3px rgba(109,91,208,0.2)}form input[type="checkbox"]{border-radius:5px}form input[type="radio"]{border-radius:50%}form input[type="radio"]:checked::after{left:5px;top:5px;width:6px;height:6px;border:none;border-radius:50%;background:#fff;transform:none}form fieldset>ol>li.boolean label{display:flex;align-items:center}form label.prism-toggle{display:flex;align-items:center;gap:10px}form label.prism-toggle input.prism-toggle-input{appearance:none;position:relative;width:0;height:0;margin:0;border:none}form label.prism-toggle input.prism-toggle-input:checked~.prism-toggle-track{background:#6d5bd0}form label.prism-toggle input.prism-toggle-input:checked~.prism-toggle-track::after{transform:translateX(16px)}form .buttons input[type="submit"],form .buttons input[type="button"],form .buttons button,form .actions input[type="submit"],form .actions input[type="button"],form .actions button{margin-right:10px}.prism-toggle-track{position:relative;display:inline-block;width:38px;height:22px;border-radius:999px;background:#d6d9e0;transition:background 120ms ease;flex:0 0 auto}.prism-toggle-track::after{content:"";position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.25);transition:transform 120ms ease}.prism-toggle-tag{display:inline-flex;align-items:center;vertical-align:middle}.prism-toggle-tag.on .prism-toggle-track{background:#6d5bd0}.prism-toggle-tag.on .prism-toggle-track::after{transform:translateX(16px)}.sidebar_section label{color:#6b7280;font-size:0.72em;font-weight:700;letter-spacing:0.06em}.sidebar_section select,.sidebar_section input[type="text"],.sidebar_section input[type="number"]{box-sizing:border-box;width:100%;max-width:100%}form.filter_form .filter_form_field{margin-bottom:14px}form.filter_form .filter_form_field.select_and_search{display:flex;gap:8px}form.filter_form .filter_form_field.select_and_search select,form.filter_form .filter_form_field.select_and_search input[type="text"]{width:auto;min-width:0;flex:1 1 0;margin-left:0}form.filter_form .filter_form_field.filter_date_range{display:flex;gap:8px}form.filter_form .filter_form_field.filter_date_range input[type="text"]{width:auto;min-width:0;flex:1 1 0}form.filter_form .filter_form_field.filter_date_range input[type="text"]+input{margin-left:0}a.button,a.button:link,a.button:visited,input[type="submit"],input[type="button"],button,form input[type="submit"],form input[type="button"],form button{background:#6d5bd0 !important;background-image:none !important;border:1px solid #6d5bd0;border-radius:6px;color:#fff !important;text-shadow:none;box-shadow:none;font-weight:600;padding:9px 16px;transition:background 120ms ease,border-color 120ms ease}a.button:hover,a.button:link:hover,a.button:visited:hover,input[type="submit"]:hover,input[type="button"]:hover,button:hover,form input[type="submit"]:hover,form input[type="button"]:hover,form button:hover{background:#5949b8 !important;border-color:#5949b8;color:#fff !important}a.button:active,a.button:link:active,a.button:visited:active,input[type="submit"]:active,input[type="button"]:active,button:active,form input[type="submit"]:active,form input[type="button"]:active,form button:active{background:#5949b8 !important;box-shadow:none}a.button.danger,input.danger[type="submit"],form input.danger[type="submit"]{background:#ef4444;border-color:#ef4444}a.button.danger:hover,input.danger[type="submit"]:hover,form input.danger[type="submit"]:hover{background:#ec1e1e;border-color:#ec1e1e}#title_bar .action_items span.action_item>a,#title_bar .action_items span.action_item>.dropdown_menu>a{background:#6d5bd0 !important;background-image:none !important;border:1px solid #6d5bd0;border-radius:6px;color:#fff !important;text-shadow:none;box-shadow:none;font-weight:600;padding:9px 16px;transition:background 120ms ease,border-color 120ms ease;padding:9px 16px;margin:0}#title_bar .action_items span.action_item>a:hover,#title_bar .action_items span.action_item>.dropdown_menu>a:hover{background:#5949b8 !important;border-color:#5949b8;color:#fff !important}#title_bar .action_items span.action_item>a:active,#title_bar .action_items span.action_item>.dropdown_menu>a:active{background:#5949b8 !important;box-shadow:none}.dropdown_menu .dropdown_menu_button,form.filter_form a.clear_filters_btn,fieldset.buttons li.cancel a,fieldset.actions li.cancel a,.pagination a,.pagination span.page.current,.pagination_per_page select{background:#fff !important;background-image:none !important;border:1px solid #d6d9e0;border-radius:6px;color:#384250 !important;text-shadow:none;box-shadow:none;font-weight:600;padding:8px 15px;transition:background 120ms ease,border-color 120ms ease}.dropdown_menu .dropdown_menu_button:hover,form.filter_form a.clear_filters_btn:hover,fieldset.buttons li.cancel a:hover,fieldset.actions li.cancel a:hover,.pagination a:hover,.pagination span.page.current:hover,.pagination_per_page select:hover{background:#f4f5f7 !important;border-color:#6b7280;color:#1a1f36 !important}.dropdown_menu .dropdown_menu_button:active,form.filter_form a.clear_filters_btn:active,fieldset.buttons li.cancel a:active,fieldset.actions li.cancel a:active,.pagination a:active,.pagination span.page.current:active,.pagination_per_page select:active{background:#f4f5f7 !important;box-shadow:none}.dropdown_menu .dropdown_menu_button{padding-right:26px !important}.dropdown_menu .dropdown_menu_button::before,.dropdown_menu .dropdown_menu_button::after{border-color:#6b7280 transparent}.dropdown_menu_list_wrapper{border-radius:6px;box-shadow:0 4px 6px rgba(16,24,40,0.05),0 10px 24px rgba(16,24,40,0.08);border:1px solid #e6e8ec;background:#fff;padding:4px}.dropdown_menu_list_wrapper .dropdown_menu_list{background:transparent;border:none;box-shadow:none;border-radius:0}.dropdown_menu_list_wrapper .dropdown_menu_list li{border-bottom:none}.dropdown_menu_list_wrapper .dropdown_menu_list li a{border-radius:6px;color:#384250;font-weight:600;text-align:left;text-shadow:none;padding:8px 12px}.dropdown_menu_list_wrapper .dropdown_menu_list li a:hover,.dropdown_menu_list_wrapper .dropdown_menu_list li a:active{background:#f2ecfd;color:#5949b8;text-shadow:none}.dropdown_menu_list_wrapper .dropdown_menu_list li:first-child a,.dropdown_menu_list_wrapper .dropdown_menu_list li:last-child a{border-radius:6px}.pagination a,.pagination span.page.current{border-radius:6px;margin-right:4px;padding:5px 11px}.pagination span.page.current{background:#f2ecfd;border-color:#f2ecfd;color:#5949b8}.pagination_information{color:#6b7280}.pagination_information b{color:#1a1f36}.prism-icon,.prism-nav-icon,.prism-chevron,.prism-action-icon{display:inline-block;vertical-align:middle;flex-shrink:0}.prism-icon{margin-right:6px}.prism-visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}body.logged_out:has(.prism-login-brand){min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f4f5f7;overflow:hidden;position:relative}body.logged_out:has(.prism-login-brand)::before,body.logged_out:has(.prism-login-brand)::after{content:"";position:fixed;z-index:0;border-radius:50%;filter:blur(70px);opacity:0.35;pointer-events:none}body.logged_out:has(.prism-login-brand)::before{width:420px;height:420px;top:-140px;left:-120px;background:radial-gradient(circle at 30% 30%, #6d5bd0, transparent 70%);animation:prism-login-blob-a 16s ease-in-out infinite}body.logged_out:has(.prism-login-brand)::after{width:360px;height:360px;bottom:-120px;right:-100px;background:radial-gradient(circle at 70% 70%, #f2ecfd, transparent 70%);animation:prism-login-blob-b 18s ease-in-out infinite}body.logged_out:has(.prism-login-brand) #wrapper{position:relative;z-index:1;display:block;min-height:0;width:auto}body.logged_out:has(.prism-login-brand) #content_wrapper{display:flex;flex-direction:column;align-items:center;width:400px;max-width:90vw;margin:0 auto}body.logged_out:has(.prism-login-brand) .flashes{width:100%;padding:0 0 10px}body.logged_out:has(.prism-login-brand) #active_admin_content{width:100%;box-sizing:border-box;background:#fff;border:1px solid #e6e8ec;border-radius:10px;box-shadow:0 4px 6px rgba(16,24,40,0.05),0 10px 24px rgba(16,24,40,0.08);padding:40px 36px 32px}body.logged_out:has(.prism-login-brand) #footer{position:relative;z-index:1;border-top:none;text-align:center}body.logged_out:has(.prism-login-brand) #login fieldset.inputs{border:none;border-radius:0}body.logged_out:has(.prism-login-brand) #login fieldset.actions{margin-top:4px;text-align:center}body.logged_out:has(.prism-login-brand) #login fieldset.actions li{float:none}body.logged_out:has(.prism-login-brand) #login fieldset.actions li.input_action{padding:20px 0;margin-left:30px;margin-bottom:15px}body.logged_out:has(.prism-login-brand) #login fieldset.actions input[type="submit"]{display:inline-block;width:auto;min-width:200px;padding:12px 28px;font-size:0.95em}body.logged_out:has(.prism-login-brand) #error_explanation{background:#fdecec;border:1px solid rgba(239,68,68,0.3);border-radius:6px;padding:12px 16px;margin-bottom:20px;color:#eb1515}body.logged_out:has(.prism-login-brand) #error_explanation h2{background:none !important;box-shadow:none !important;text-shadow:none !important;border:none !important;margin:0 0 6px !important;padding:0 !important;color:inherit;font-size:0.95em;font-weight:700}body.logged_out:has(.prism-login-brand) #error_explanation ul{margin:0;padding-left:18px;font-size:0.88em;font-weight:600}@keyframes prism-login-blob-a{0%,100%{transform:translate(0, 0) scale(1)}50%{transform:translate(60px, 40px) scale(1.1)}}@keyframes prism-login-blob-b{0%,100%{transform:translate(0, 0) scale(1)}50%{transform:translate(-50px, -30px) scale(1.08)}}.prism-login-brand{text-align:center;margin-bottom:28px}.prism-login-logo{width:64px;height:64px;margin:0 auto 14px;color:#6d5bd0}.prism-login-mark{display:block;width:100%;height:100%}.prism-login-beam{stroke-dasharray:40;animation:prism-login-beam-flow 2.4s linear infinite}@keyframes prism-login-beam-flow{to{stroke-dashoffset:-80}}.prism-login-tri{transform-origin:center;animation:prism-login-tri-glow 3.2s ease-in-out infinite}@keyframes prism-login-tri-glow{0%,100%{filter:drop-shadow(0 0 0 rgba(0,0,0,0))}50%{filter:drop-shadow(0 0 6px rgba(109,91,208,0.45))}}body.logged_out #login .prism-login-brand h2{background:none !important;box-shadow:none !important;text-shadow:none !important;border:none !important;margin:0 !important;padding:0 !important;color:#1a1f36}.prism-login-title{font-size:1.6em;font-weight:800;letter-spacing:-0.01em}.prism-login-tagline{margin:4px 0 0;color:#6b7280;font-size:0.9em}.prism-login-links{margin-top:24px;display:flex;flex-wrap:wrap;justify-content:center;gap:10px;text-align:center}.prism-login-links a{display:inline-flex;align-items:center;padding:7px 14px;border:1px solid #e6e8ec;border-radius:999px;background:#f4f5f7;color:#384250;font-size:0.82em;font-weight:600;text-decoration:none;transition:background 120ms ease,border-color 120ms ease,color 120ms ease}.prism-login-links a:hover{background:#f2ecfd;border-color:#6d5bd0;color:#5949b8}.prism-login-links br{display:none}
@@ -0,0 +1,26 @@
1
+ <%#
2
+ Overrides ActiveAdmin's own active_admin/devise/confirmations/new.html.erb
3
+ the same way sessions/new.html.erb does (see that file's header comment
4
+ for the Gemfile-order mechanism this relies on). Form fields/behavior
5
+ below are byte-for-byte ActiveAdmin's own template; only the header
6
+ markup (shared devise/shared/_brand partial) and the links wrapper are
7
+ new.
8
+ %>
9
+ <div id="login" class="prism-login">
10
+ <% action_title = title t('active_admin.devise.resend_confirmation_instructions.title') %>
11
+ <%= render "active_admin/devise/shared/brand", action_title: action_title, subtitle: action_title %>
12
+
13
+ <%= render partial: "active_admin/devise/shared/error_messages", resource: resource %>
14
+ <%= active_admin_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
15
+ f.inputs do
16
+ f.input :email
17
+ end
18
+ f.actions do
19
+ f.action :submit, label: t('active_admin.devise.resend_confirmation_instructions.submit'), button_html: { value: t('active_admin.devise.resend_confirmation_instructions.submit') }
20
+ end
21
+ end %>
22
+
23
+ <div class="prism-login-links">
24
+ <%= render partial: "active_admin/devise/shared/links" %>
25
+ </div>
26
+ </div>
@@ -0,0 +1,29 @@
1
+ <%#
2
+ Overrides ActiveAdmin's own active_admin/devise/passwords/edit.html.erb
3
+ the same way sessions/new.html.erb does (see that file's header comment
4
+ for the Gemfile-order mechanism this relies on). Form fields/behavior
5
+ below are byte-for-byte ActiveAdmin's own template; only the header
6
+ markup (shared devise/shared/_brand partial) and the links wrapper are
7
+ new.
8
+ %>
9
+ <div id="login" class="prism-login">
10
+ <% action_title = title t('active_admin.devise.change_password.title') %>
11
+ <%= render "active_admin/devise/shared/brand", action_title: action_title, subtitle: action_title %>
12
+
13
+ <%= render partial: "active_admin/devise/shared/error_messages", resource: resource %>
14
+ <%= active_admin_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
15
+ f.inputs do
16
+ f.input :password
17
+ f.input :password_confirmation
18
+ f.input :reset_password_token, as: :hidden, input_html: { value: resource.reset_password_token }
19
+ end
20
+ f.actions do
21
+ f.action :submit, label: t('active_admin.devise.change_password.submit'), button_html: { value: t('active_admin.devise.change_password.submit') }
22
+ end
23
+ end
24
+ %>
25
+
26
+ <div class="prism-login-links">
27
+ <%= render 'active_admin/devise/shared/links' %>
28
+ </div>
29
+ </div>
@@ -0,0 +1,26 @@
1
+ <%#
2
+ Overrides ActiveAdmin's own active_admin/devise/passwords/new.html.erb
3
+ the same way sessions/new.html.erb does (see that file's header comment
4
+ for the Gemfile-order mechanism this relies on). Form fields/behavior
5
+ below are byte-for-byte ActiveAdmin's own template; only the header
6
+ markup (shared devise/shared/_brand partial) and the links wrapper are
7
+ new.
8
+ %>
9
+ <div id="login" class="prism-login">
10
+ <% action_title = title t('active_admin.devise.reset_password.title') %>
11
+ <%= render "active_admin/devise/shared/brand", action_title: action_title, subtitle: action_title %>
12
+
13
+ <%= render partial: "active_admin/devise/shared/error_messages", resource: resource %>
14
+ <%= active_admin_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
15
+ f.inputs do
16
+ f.input :email
17
+ end
18
+ f.actions do
19
+ f.action :submit, label: t('active_admin.devise.reset_password.submit'), button_html: { value: t('active_admin.devise.reset_password.submit') }
20
+ end
21
+ end %>
22
+
23
+ <div class="prism-login-links">
24
+ <%= render partial: "active_admin/devise/shared/links" %>
25
+ </div>
26
+ </div>
@@ -0,0 +1,32 @@
1
+ <%#
2
+ Overrides ActiveAdmin's own active_admin/devise/registrations/new.html.erb
3
+ the same way sessions/new.html.erb does (see that file's header comment
4
+ for the Gemfile-order mechanism this relies on). Form fields/behavior
5
+ below are byte-for-byte ActiveAdmin's own template; only the header
6
+ markup (shared devise/shared/_brand partial) and the links wrapper are
7
+ new.
8
+ %>
9
+ <div id="login" class="prism-login">
10
+ <% action_title = title t('active_admin.devise.sign_up.title') %>
11
+ <%= render "active_admin/devise/shared/brand", action_title: action_title, subtitle: action_title %>
12
+
13
+ <% scope = Devise::Mapping.find_scope!(resource_name) %>
14
+ <%= render partial: "active_admin/devise/shared/error_messages", resource: resource %>
15
+ <%= active_admin_form_for(resource, as: resource_name, url: send(:"#{scope}_registration_path"), html: { id: "registration_new" }) do |f|
16
+ f.inputs do
17
+ resource.class.authentication_keys.each_with_index { |key, index|
18
+ f.input key, label: t('active_admin.devise.'+key.to_s+'.title'), input_html: { autofocus: index.zero? }
19
+ }
20
+ f.input :password, label: t('active_admin.devise.password.title')
21
+ f.input :password_confirmation, label: t('active_admin.devise.password_confirmation.title')
22
+ end
23
+ f.actions do
24
+ f.action :submit, label: t('active_admin.devise.login.submit'), button_html: { value: t('active_admin.devise.sign_up.submit') }
25
+ end
26
+ end
27
+ %>
28
+
29
+ <div class="prism-login-links">
30
+ <%= render partial: "active_admin/devise/shared/links" %>
31
+ </div>
32
+ </div>
@@ -0,0 +1,37 @@
1
+ <%#
2
+ Overrides ActiveAdmin's own active_admin/devise/sessions/new.html.erb
3
+ (shipped in the activeadmin gem at the same relative view path) so the
4
+ gem's Rails::Engine view path — added after ActiveAdmin's own, since this
5
+ gem is required after "activeadmin" in a host's Gemfile — takes priority
6
+ over it. See INTEGRATION.md's "Sign-in page" section for the Gemfile-order
7
+ note and the config.login_page escape hatch.
8
+
9
+ The actual authentication form below (`active_admin_form_for` block, the
10
+ devise `f.inputs`/`f.actions` calls) is byte-for-byte what ActiveAdmin's
11
+ own template renders — only the markup around it (the brand block, from
12
+ the shared devise/shared/_brand partial) is new — so sign-in behavior,
13
+ field list, and error rendering are untouched.
14
+ %>
15
+ <div id="login" class="prism-login">
16
+ <% action_title = title t('active_admin.devise.login.title') %>
17
+ <%= render "active_admin/devise/shared/brand", action_title: action_title, subtitle: prism_login_tagline %>
18
+
19
+ <% scope = Devise::Mapping.find_scope!(resource_name) %>
20
+ <%= active_admin_form_for(resource, as: resource_name, url: send(:"#{scope}_session_path"), html: { id: "session_new" }) do |f|
21
+ f.inputs do
22
+ resource.class.authentication_keys.each_with_index { |key, index|
23
+ f.input key, label: t("active_admin.devise.#{key}.title"), input_html: { autofocus: index.zero? }
24
+ }
25
+ f.input :password, label: t('active_admin.devise.password.title')
26
+ f.input :remember_me, label: t('active_admin.devise.login.remember_me'), as: :boolean if devise_mapping.rememberable?
27
+ end
28
+ f.actions do
29
+ f.action :submit, label: t('active_admin.devise.login.submit'), button_html: { value: t('active_admin.devise.login.submit') }
30
+ end
31
+ end
32
+ %>
33
+
34
+ <div class="prism-login-links">
35
+ <%= render partial: "active_admin/devise/shared/links" %>
36
+ </div>
37
+ </div>