active_admin_prism 0.1.0 → 0.1.2
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 +4 -4
- data/CHANGELOG.md +44 -1
- data/INTEGRATION.md +202 -1
- data/README.md +60 -1
- data/app/assets/javascripts/active_admin_prism/prism.js +3 -1
- data/app/assets/stylesheets/active_admin_prism/prism.css +1 -1
- data/js-src/prism.js +125 -0
- data/lib/active_admin/views/flash_messages.rb +5 -3
- data/lib/active_admin/views/prism_sidebar.rb +26 -0
- data/lib/active_admin_prism/configuration.rb +27 -0
- data/lib/active_admin_prism/version.rb +1 -1
- data/scss-src/_forms.scss +20 -4
- data/scss-src/_panels.scss +11 -0
- data/scss-src/_select2.scss +264 -0
- data/scss-src/_select2_vendor.scss +695 -0
- data/scss-src/_sidebar.scss +96 -2
- data/scss-src/prism.scss +2 -0
- data/vendor/select2/LICENSE.md +21 -0
- data/vendor/select2/select2.full.min.js +2 -0
- metadata +6 -2
data/js-src/prism.js
CHANGED
|
@@ -75,6 +75,103 @@
|
|
|
75
75
|
});
|
|
76
76
|
})();
|
|
77
77
|
|
|
78
|
+
// Sidebar menu search box (lib/active_admin/views/prism_sidebar.rb
|
|
79
|
+
// #render_search_box) — filters the "Pages" nav as the visitor types,
|
|
80
|
+
// matching an item's own label at ANY nesting depth, not just top-level
|
|
81
|
+
// entries. A submenu item that matches keeps every one of its ancestors
|
|
82
|
+
// visible and forced open; a parent whose own label matches instead keeps
|
|
83
|
+
// its *entire* subtree visible and expanded, even children that don't
|
|
84
|
+
// match on their own — either way via ".prism-search-open", distinct from
|
|
85
|
+
// the persisted/manual ".open" class above so clearing the search can't
|
|
86
|
+
// clobber a group the visitor had manually pinned open.
|
|
87
|
+
(function () {
|
|
88
|
+
"use strict";
|
|
89
|
+
|
|
90
|
+
function normalize(text) {
|
|
91
|
+
return (text || "").trim().toLowerCase();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function ownLabel(li) {
|
|
95
|
+
var el = li.querySelector(
|
|
96
|
+
":scope > .prism-nav-link .prism-nav-label, :scope > .prism-nav-group-toggle .prism-nav-label"
|
|
97
|
+
);
|
|
98
|
+
return el ? normalize(el.textContent) : "";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function directChildItems(li) {
|
|
102
|
+
var submenu = li.querySelector(":scope > .prism-nav-submenu");
|
|
103
|
+
if (!submenu) return [];
|
|
104
|
+
return Array.prototype.filter.call(submenu.children, function (child) {
|
|
105
|
+
return child.classList.contains("prism-nav-item");
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Recurses depth-first, carrying `ancestorOwnMatch` down (true once any
|
|
110
|
+
// ancestor's own label has matched) so a matched group reveals its whole
|
|
111
|
+
// subtree, not just itself — and returns whether this node's own label
|
|
112
|
+
// or any descendant's matched (ignoring ancestorOwnMatch), so that signal
|
|
113
|
+
// keeps bubbling up to open every group on the path to a deep match
|
|
114
|
+
// regardless of how many submenu levels separate it from the top.
|
|
115
|
+
function matchItem(li, query, ancestorOwnMatch) {
|
|
116
|
+
var ownMatch = !!query && ownLabel(li).indexOf(query) !== -1;
|
|
117
|
+
var childMatch = false;
|
|
118
|
+
|
|
119
|
+
directChildItems(li).forEach(function (child) {
|
|
120
|
+
if (matchItem(child, query, ancestorOwnMatch || ownMatch)) childMatch = true;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
var visible = !query || ancestorOwnMatch || ownMatch || childMatch;
|
|
124
|
+
li.classList.toggle("prism-nav-hidden", !visible);
|
|
125
|
+
li.classList.toggle("prism-search-open", !!query && (ownMatch || childMatch || ancestorOwnMatch));
|
|
126
|
+
|
|
127
|
+
return ownMatch || childMatch;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function applySearch(sidebar, query) {
|
|
131
|
+
var nav = sidebar.querySelector(".prism-sidebar-scroll > .prism-nav");
|
|
132
|
+
if (!nav) return;
|
|
133
|
+
|
|
134
|
+
var anyVisible = false;
|
|
135
|
+
Array.prototype.forEach.call(nav.children, function (li) {
|
|
136
|
+
if (!li.classList.contains("prism-nav-item")) return;
|
|
137
|
+
if (matchItem(li, query, false)) anyVisible = true;
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
var empty = sidebar.querySelector(".prism-nav-empty");
|
|
141
|
+
if (empty) empty.classList.toggle("prism-nav-empty-visible", !!query && !anyVisible);
|
|
142
|
+
|
|
143
|
+
var clear = sidebar.querySelector("[data-prism-nav-search-clear]");
|
|
144
|
+
if (clear) clear.classList.toggle("prism-nav-search-clear-visible", !!query);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
148
|
+
var sidebar = document.getElementById("header");
|
|
149
|
+
if (!sidebar || !sidebar.classList.contains("prism-sidebar")) return;
|
|
150
|
+
|
|
151
|
+
var input = sidebar.querySelector("[data-prism-nav-search]");
|
|
152
|
+
if (!input) return;
|
|
153
|
+
|
|
154
|
+
input.addEventListener("input", function () {
|
|
155
|
+
applySearch(sidebar, normalize(input.value));
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
input.addEventListener("keydown", function (event) {
|
|
159
|
+
if (event.key !== "Escape" || !input.value) return;
|
|
160
|
+
input.value = "";
|
|
161
|
+
applySearch(sidebar, "");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
var clearBtn = sidebar.querySelector("[data-prism-nav-search-clear]");
|
|
165
|
+
if (clearBtn) {
|
|
166
|
+
clearBtn.addEventListener("click", function () {
|
|
167
|
+
input.value = "";
|
|
168
|
+
applySearch(sidebar, "");
|
|
169
|
+
input.focus();
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
})();
|
|
174
|
+
|
|
78
175
|
// Routes every plain `data-confirm` link (row-level View/Edit/Delete
|
|
79
176
|
// actions, any other rails-ujs confirm) through ActiveAdmin's own styled
|
|
80
177
|
// jQuery UI dialog — the same one it already uses for Batch Actions —
|
|
@@ -268,3 +365,31 @@
|
|
|
268
365
|
});
|
|
269
366
|
});
|
|
270
367
|
})();
|
|
368
|
+
|
|
369
|
+
// Auto-enhances every plain <select> ActiveAdmin renders (filters, form
|
|
370
|
+
// inputs, association pickers) into a searchable Select2 widget when
|
|
371
|
+
// ActiveAdminPrism.configuration.select2 is true (the
|
|
372
|
+
// "prism-select2-enabled" body class, set in
|
|
373
|
+
// lib/active_admin/views/flash_messages.rb#body_classes). Select2 itself
|
|
374
|
+
// (vendor/select2/select2.full.min.js, MIT licensed) is concatenated just
|
|
375
|
+
// above this file in the compiled asset (see bin/build-js) — turning this
|
|
376
|
+
// flag on needs no host-side JS/npm setup of its own. Skips any <select>
|
|
377
|
+
// a host already initialized manually (the per-field
|
|
378
|
+
// input_html: { class: "..." } + own .select2() call approach predating
|
|
379
|
+
// this flag, still documented in INTEGRATION.md) so the two can coexist
|
|
380
|
+
// without double-initializing the same element.
|
|
381
|
+
(function () {
|
|
382
|
+
"use strict";
|
|
383
|
+
|
|
384
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
385
|
+
if (!document.body.classList.contains("prism-select2-enabled")) return;
|
|
386
|
+
if (typeof jQuery === "undefined" || !jQuery.fn.select2) return;
|
|
387
|
+
|
|
388
|
+
var $ = jQuery;
|
|
389
|
+
$("select").each(function () {
|
|
390
|
+
var $select = $(this);
|
|
391
|
+
if ($select.data("select2")) return;
|
|
392
|
+
$select.select2({ width: "100%" });
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
})();
|
|
@@ -47,10 +47,11 @@ module ActiveAdmin
|
|
|
47
47
|
|
|
48
48
|
# Read by prism.js / scss-src's CSS to decide whether to route
|
|
49
49
|
# data-confirm links through the styled dialog, whether the Filters
|
|
50
|
-
# sidebar panel collapses to an icon,
|
|
51
|
-
# original #footer should stay hidden
|
|
50
|
+
# sidebar panel collapses to an icon, whether ActiveAdmin's
|
|
51
|
+
# original #footer should stay hidden, and whether every plain
|
|
52
|
+
# <select> should be auto-enhanced into Select2 (see
|
|
52
53
|
# ActiveAdminPrism::Configuration #styled_confirms /
|
|
53
|
-
# #collapsible_filters / #sidebar_footer).
|
|
54
|
+
# #collapsible_filters / #sidebar_footer / #select2).
|
|
54
55
|
#
|
|
55
56
|
# Can't call `super` here — #body_classes is defined directly on
|
|
56
57
|
# this same class (not a superclass), so reopening and redefining
|
|
@@ -69,6 +70,7 @@ module ActiveAdmin
|
|
|
69
70
|
classes << "prism-styled-confirms-disabled" unless config.styled_confirms
|
|
70
71
|
classes << "prism-filters-collapsible-disabled" unless config.collapsible_filters
|
|
71
72
|
classes << "prism-sidebar-footer-disabled" unless config.sidebar_footer
|
|
73
|
+
classes << "prism-select2-enabled" if config.select2
|
|
72
74
|
classes
|
|
73
75
|
end
|
|
74
76
|
end
|
|
@@ -42,9 +42,11 @@ module ActiveAdmin
|
|
|
42
42
|
div class: "prism-sidebar-inner" do
|
|
43
43
|
div(class: "prism-sidebar-brand") { site_title @namespace }
|
|
44
44
|
render_language_switcher if ActiveAdminPrism.configuration.language_switcher
|
|
45
|
+
render_search_box if ActiveAdminPrism.configuration.menu_search
|
|
45
46
|
div(class: "prism-sidebar-scroll") do
|
|
46
47
|
div "Pages", class: "prism-nav-section-label"
|
|
47
48
|
render_menu @menu, class: "prism-nav"
|
|
49
|
+
div("No matching menu items", class: "prism-nav-empty")
|
|
48
50
|
end
|
|
49
51
|
if @utility_menu.items.any?
|
|
50
52
|
div(class: "prism-sidebar-utility") do
|
|
@@ -111,6 +113,30 @@ module ActiveAdmin
|
|
|
111
113
|
end
|
|
112
114
|
end
|
|
113
115
|
|
|
116
|
+
# A text input that filters the "Pages" nav below as the visitor
|
|
117
|
+
# types (see js-src/prism.js) — matching happens purely client-side,
|
|
118
|
+
# against every item's own label regardless of nesting level, so a
|
|
119
|
+
# long menu with several submenus doesn't force a scroll to find one
|
|
120
|
+
# item. The actual show/hide + submenu auto-expand logic lives in JS
|
|
121
|
+
# because the whole menu is already rendered up front here; there's
|
|
122
|
+
# nothing server-side left to decide once the markup exists.
|
|
123
|
+
def render_search_box
|
|
124
|
+
div(class: "prism-sidebar-search") do
|
|
125
|
+
text_node ActiveAdminPrism::Icons.svg(:search, css_class: "prism-nav-icon prism-search-icon").html_safe
|
|
126
|
+
input(
|
|
127
|
+
type: "search",
|
|
128
|
+
class: "prism-nav-search-input",
|
|
129
|
+
placeholder: "Search menu",
|
|
130
|
+
autocomplete: "off",
|
|
131
|
+
"aria-label": "Search menu",
|
|
132
|
+
data: { "prism-nav-search": true }
|
|
133
|
+
)
|
|
134
|
+
span(class: "prism-nav-search-clear", data: { "prism-nav-search-clear": true }, "aria-label": "Clear search") do
|
|
135
|
+
text_node ActiveAdminPrism::Icons.svg(:x, css_class: "prism-nav-icon").html_safe
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
114
140
|
# Each language entry's own :url (String/Proc/Symbol — same
|
|
115
141
|
# nil/String/Proc/Symbol convention as config.login_logo etc.,
|
|
116
142
|
# evaluated the same way item.url is above) wins when given, e.g. to
|
|
@@ -136,6 +136,31 @@ module ActiveAdminPrism
|
|
|
136
136
|
# as it would be if you'd wired up the utility_navigation menu by hand.
|
|
137
137
|
attr_accessor :languages
|
|
138
138
|
|
|
139
|
+
# Whether a search box renders at the top of the sidebar's "Pages" nav,
|
|
140
|
+
# letting a visitor filter menu items by label without scrolling —
|
|
141
|
+
# matching against every item regardless of nesting (a top-level item,
|
|
142
|
+
# or one buried in a submenu). A submenu item that matches keeps its
|
|
143
|
+
# parent visible (and expanded) even though the parent's own label
|
|
144
|
+
# doesn't match; a parent that matches shows all of its children. See
|
|
145
|
+
# lib/active_admin/views/prism_sidebar.rb#render_search_box for the
|
|
146
|
+
# markup and js-src/prism.js for the filtering itself (pure client-side
|
|
147
|
+
# DOM filtering — no server round trip, no change to how menu do |m|
|
|
148
|
+
# ... end is authored in app/admin/*.rb). false renders no search box at
|
|
149
|
+
# all.
|
|
150
|
+
attr_accessor :menu_search
|
|
151
|
+
|
|
152
|
+
# Whether every plain <select> ActiveAdmin renders (filters, form
|
|
153
|
+
# inputs, association pickers — anything, no per-field opt-in needed)
|
|
154
|
+
# is automatically enhanced into a searchable Select2 widget. false
|
|
155
|
+
# (the default) leaves every select exactly as ActiveAdmin renders it;
|
|
156
|
+
# you can still opt individual fields into Select2 yourself either way
|
|
157
|
+
# (see INTEGRATION.md's Select2 section) — this flag only controls the
|
|
158
|
+
# blanket, no-setup-needed behavior. Select2 itself (JS + its own base
|
|
159
|
+
# CSS) ships vendored inside this gem's assets either way — turning
|
|
160
|
+
# this on requires no extra gem/npm dependency or JS of your own;
|
|
161
|
+
# see js-src/prism.js and vendor/select2/.
|
|
162
|
+
attr_accessor :select2
|
|
163
|
+
|
|
139
164
|
def initialize
|
|
140
165
|
@sidebar = true
|
|
141
166
|
@colorize_action_icons = true
|
|
@@ -156,6 +181,8 @@ module ActiveAdminPrism
|
|
|
156
181
|
{ label: "Español", locale: :es },
|
|
157
182
|
{ label: "Français", locale: :fr }
|
|
158
183
|
]
|
|
184
|
+
@menu_search = true
|
|
185
|
+
@select2 = false
|
|
159
186
|
end
|
|
160
187
|
end
|
|
161
188
|
|
data/scss-src/_forms.scss
CHANGED
|
@@ -162,12 +162,28 @@ form {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
// ActiveAdmin's own CSS lays these out via `float: left` on each `li`
|
|
166
|
+
// (mixins/_buttons.scss's basic-button + _forms.scss's `fieldset.buttons
|
|
167
|
+
// li, fieldset.actions li { float: left; }`) — fragile in practice: it
|
|
168
|
+
// only takes one host app's own CSS reset (or a form with an unusually
|
|
169
|
+
// long submit label, or a differently-structured actions bar) for that
|
|
170
|
+
// float to be lost, at which point every `li` (a block-level list item
|
|
171
|
+
// by default) stacks vertically instead of sitting in a row. Flexbox
|
|
172
|
+
// sidesteps this rather than trying to out-specificity AA's float rule:
|
|
173
|
+
// per spec, `float` has no effect on a flex item at all, so this simply
|
|
174
|
+
// wins outright regardless of load order/specificity, and doesn't
|
|
175
|
+
// depend on every button happening to fit on one line the way floats do.
|
|
165
176
|
.buttons,
|
|
166
177
|
.actions {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
178
|
+
> ol {
|
|
179
|
+
display: flex;
|
|
180
|
+
flex-wrap: wrap;
|
|
181
|
+
align-items: center;
|
|
182
|
+
gap: 10px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
li {
|
|
186
|
+
padding: 0;
|
|
171
187
|
}
|
|
172
188
|
}
|
|
173
189
|
}
|
data/scss-src/_panels.scss
CHANGED
|
@@ -156,6 +156,15 @@ body:has(.prism-collapsible-panel):not(.prism-filters-open) {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
&.open {
|
|
159
|
+
// Both this element and .panel_contents inherit overflow:hidden from
|
|
160
|
+
// the collapsed state above (needed there to clip the height-0
|
|
161
|
+
// content and, on .panel itself, to keep the base .panel rule's
|
|
162
|
+
// rounded-corner clipping) — reset to visible once open, otherwise a
|
|
163
|
+
// filter using a Select2 dropdown (e.g. a belongs_to filter's
|
|
164
|
+
// .select_and_search field) gets its open dropdown list clipped/
|
|
165
|
+
// garbled against this panel's own bounds, since Select2 renders its
|
|
166
|
+
// dropdown as a sibling near the input rather than inside it.
|
|
167
|
+
overflow: visible;
|
|
159
168
|
background: $prism-bg-card;
|
|
160
169
|
border-color: $prism-border-color;
|
|
161
170
|
box-shadow: $prism-shadow-card;
|
|
@@ -186,6 +195,7 @@ body:has(.prism-collapsible-panel):not(.prism-filters-open) {
|
|
|
186
195
|
}
|
|
187
196
|
|
|
188
197
|
.panel_contents {
|
|
198
|
+
overflow: visible;
|
|
189
199
|
max-height: 1200px;
|
|
190
200
|
opacity: 1;
|
|
191
201
|
padding-top: 20px;
|
|
@@ -200,6 +210,7 @@ body:has(.prism-collapsible-panel):not(.prism-filters-open) {
|
|
|
200
210
|
// filters_sidebar.rb skips adding the icon/label markup entirely, so this
|
|
201
211
|
// rule is mostly a no-op safety net rather than the primary mechanism).
|
|
202
212
|
body.prism-filters-collapsible-disabled .prism-collapsible-panel {
|
|
213
|
+
overflow: visible;
|
|
203
214
|
background: $prism-bg-card;
|
|
204
215
|
border-color: $prism-border-color;
|
|
205
216
|
box-shadow: $prism-shadow-card;
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// Reskins Select2 (https://select2.org) — the jQuery widget commonly wired
|
|
2
|
+
// up for searchable belongs_to filters/inputs (host apps opt individual
|
|
3
|
+
// selects in with `input_html: { class: "your-select2-class" }` plus their
|
|
4
|
+
// own `.select2()` call; this gem does not ship the JS itself, only the
|
|
5
|
+
// CSS, since Select2 is an opt-in add-on rather than something AA bundles).
|
|
6
|
+
//
|
|
7
|
+
// Select2 replaces the (now hidden) <select> with its own
|
|
8
|
+
// `.select2-container` markup, so the plain `select { ... }` rules in
|
|
9
|
+
// _forms.scss (and the `.sidebar_section select` / `.filter_form_field`
|
|
10
|
+
// width rules) never reach it — every width/sizing/theming rule the
|
|
11
|
+
// original select relied on needs a `.select2-container` equivalent here.
|
|
12
|
+
// Without this file, a Select2-enhanced select renders at its unstyled
|
|
13
|
+
// default size (far narrower than the surrounding fields) and its open
|
|
14
|
+
// dropdown can visually clash with the theme entirely.
|
|
15
|
+
.select2-container {
|
|
16
|
+
display: block;
|
|
17
|
+
font-family: $prism-font-family;
|
|
18
|
+
|
|
19
|
+
.select2-selection--single {
|
|
20
|
+
height: auto;
|
|
21
|
+
border: 1px solid $prism-border-color-strong;
|
|
22
|
+
border-radius: $prism-radius-sm;
|
|
23
|
+
background: $prism-bg-card;
|
|
24
|
+
padding: 9px 32px 9px 12px;
|
|
25
|
+
transition: border-color $prism-transition-fast, box-shadow $prism-transition-fast;
|
|
26
|
+
|
|
27
|
+
.select2-selection__rendered {
|
|
28
|
+
padding: 0;
|
|
29
|
+
color: $prism-text-heading;
|
|
30
|
+
line-height: 1.4;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.select2-selection__placeholder {
|
|
34
|
+
color: $prism-text-muted;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.select2-selection__arrow {
|
|
38
|
+
height: 100%;
|
|
39
|
+
top: 0;
|
|
40
|
+
right: 8px;
|
|
41
|
+
|
|
42
|
+
b {
|
|
43
|
+
border-color: $prism-text-muted transparent transparent transparent;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&--open .select2-selection--single {
|
|
49
|
+
border-color: $prism-color-primary;
|
|
50
|
+
box-shadow: 0 0 0 3px rgba($prism-color-primary, 0.15);
|
|
51
|
+
|
|
52
|
+
.select2-selection__arrow b {
|
|
53
|
+
border-color: transparent transparent $prism-text-muted transparent;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&--disabled .select2-selection--single {
|
|
58
|
+
background: $prism-bg-page;
|
|
59
|
+
color: $prism-text-muted;
|
|
60
|
+
cursor: not-allowed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.select2-selection__clear {
|
|
64
|
+
position: static;
|
|
65
|
+
margin: 0 4px 0 0;
|
|
66
|
+
height: auto;
|
|
67
|
+
color: $prism-text-muted;
|
|
68
|
+
font-weight: 700;
|
|
69
|
+
|
|
70
|
+
&:hover {
|
|
71
|
+
color: $prism-color-danger;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Multi-select ("tags") mode — e.g. `f.input :subjects, as: :select2,
|
|
76
|
+
// multiple: true` in place of `as: :check_boxes`. Select2's own default
|
|
77
|
+
// theme lays this out with absolute-positioned remove buttons and
|
|
78
|
+
// per-choice margins (see its own select2-selection--multiple rules) —
|
|
79
|
+
// overridden wholesale here with a flex-wrapped row of pill chips,
|
|
80
|
+
// consistent with the toggle/badge look elsewhere in this theme, rather
|
|
81
|
+
// than patched piecemeal on top of that positioning.
|
|
82
|
+
.select2-selection--multiple {
|
|
83
|
+
min-height: auto;
|
|
84
|
+
border: 1px solid $prism-border-color-strong;
|
|
85
|
+
border-radius: $prism-radius-sm;
|
|
86
|
+
background: $prism-bg-card;
|
|
87
|
+
padding: 6px 8px;
|
|
88
|
+
cursor: text;
|
|
89
|
+
transition: border-color $prism-transition-fast, box-shadow $prism-transition-fast;
|
|
90
|
+
|
|
91
|
+
.select2-selection__rendered {
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 6px;
|
|
96
|
+
padding: 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.select2-selection__placeholder {
|
|
100
|
+
color: $prism-text-muted;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.select2-selection__choice {
|
|
104
|
+
display: flex;
|
|
105
|
+
align-items: center;
|
|
106
|
+
gap: 4px;
|
|
107
|
+
position: static;
|
|
108
|
+
max-width: 100%;
|
|
109
|
+
margin: 0;
|
|
110
|
+
padding: 3px 6px 3px 10px;
|
|
111
|
+
border: none;
|
|
112
|
+
border-radius: $prism-radius-pill;
|
|
113
|
+
background: $prism-color-primary-light;
|
|
114
|
+
overflow: hidden;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.select2-selection__choice__display {
|
|
118
|
+
padding: 0;
|
|
119
|
+
color: $prism-color-primary-dark;
|
|
120
|
+
font-weight: 600;
|
|
121
|
+
font-size: 0.85em;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
text-overflow: ellipsis;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.select2-selection__choice__remove {
|
|
127
|
+
position: static;
|
|
128
|
+
border: none;
|
|
129
|
+
border-radius: 50%;
|
|
130
|
+
background: transparent;
|
|
131
|
+
color: $prism-color-primary-dark;
|
|
132
|
+
font-weight: 700;
|
|
133
|
+
line-height: 1;
|
|
134
|
+
padding: 2px;
|
|
135
|
+
|
|
136
|
+
&:hover,
|
|
137
|
+
&:focus {
|
|
138
|
+
background: rgba($prism-color-primary-dark, 0.15);
|
|
139
|
+
color: $prism-color-primary-dark;
|
|
140
|
+
outline: none;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.select2-selection__clear {
|
|
145
|
+
position: static;
|
|
146
|
+
margin: 0 0 0 auto;
|
|
147
|
+
height: auto;
|
|
148
|
+
color: $prism-text-muted;
|
|
149
|
+
font-weight: 700;
|
|
150
|
+
|
|
151
|
+
&:hover {
|
|
152
|
+
color: $prism-color-danger;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.select2-search--inline .select2-search__field {
|
|
157
|
+
margin: 0;
|
|
158
|
+
padding: 3px 2px;
|
|
159
|
+
min-height: 0;
|
|
160
|
+
height: auto;
|
|
161
|
+
color: $prism-text-heading;
|
|
162
|
+
font-family: $prism-font-family;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&--focus .select2-selection--multiple,
|
|
167
|
+
&--open .select2-selection--multiple {
|
|
168
|
+
border-color: $prism-color-primary;
|
|
169
|
+
box-shadow: 0 0 0 3px rgba($prism-color-primary, 0.15);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
&--disabled .select2-selection--multiple {
|
|
173
|
+
background: $prism-bg-page;
|
|
174
|
+
|
|
175
|
+
.select2-selection__choice {
|
|
176
|
+
opacity: 0.75;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.select2-selection__choice__remove {
|
|
180
|
+
display: none;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Sidebar Filters panel and the standalone filter form both stack the
|
|
186
|
+
// label above the field (no float) and size the underlying <select> to
|
|
187
|
+
// fill it — same treatment for its Select2 replacement (see the
|
|
188
|
+
// equivalent `select` rules in _forms.scss).
|
|
189
|
+
.sidebar_section .select2-container,
|
|
190
|
+
form.filter_form .select2-container {
|
|
191
|
+
width: 100% !important;
|
|
192
|
+
box-sizing: border-box;
|
|
193
|
+
max-width: 100%;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
form.filter_form .filter_form_field.select_and_search .select2-container {
|
|
197
|
+
width: auto !important;
|
|
198
|
+
min-width: 0;
|
|
199
|
+
flex: 1 1 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Main "fieldset.inputs" form: ActiveAdmin's own _forms.scss floats the
|
|
203
|
+
// label left at 20% width and gives text inputs an explicit
|
|
204
|
+
// width: calc(80% - padding) so they sit in the remaining space beside it
|
|
205
|
+
// — a value this gem has no access to at compile time (it's compiled
|
|
206
|
+
// standalone, without AA's own SCSS variables/mixins in its load path; see
|
|
207
|
+
// bin/build-css). Rather than hardcode an equivalent, giving the container
|
|
208
|
+
// its own block formatting context (overflow: hidden, no explicit width)
|
|
209
|
+
// gets the same result for free: per the CSS spec, a BFC-establishing box
|
|
210
|
+
// must not overlap a preceding float's margin box, so the browser sizes it
|
|
211
|
+
// to exactly the remaining space automatically. Without this, the default
|
|
212
|
+
// 100% width above would render full-width *underneath* the floated
|
|
213
|
+
// label, visually painting over it — this is the fix for that, not just a
|
|
214
|
+
// visual nicety.
|
|
215
|
+
fieldset.inputs .select2-container {
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// The dropdown panel itself is appended to <body> (or wherever
|
|
220
|
+
// `dropdownParent` points), not inside the field/panel — its own popover
|
|
221
|
+
// styling, independent of whatever container it happens to render in.
|
|
222
|
+
.select2-dropdown {
|
|
223
|
+
border: 1px solid $prism-border-color;
|
|
224
|
+
border-radius: $prism-radius-sm;
|
|
225
|
+
box-shadow: $prism-shadow-popover;
|
|
226
|
+
overflow: hidden;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.select2-search--dropdown {
|
|
230
|
+
padding: 8px;
|
|
231
|
+
|
|
232
|
+
.select2-search__field {
|
|
233
|
+
border: 1px solid $prism-border-color-strong;
|
|
234
|
+
border-radius: $prism-radius-sm;
|
|
235
|
+
padding: 7px 10px;
|
|
236
|
+
color: $prism-text-heading;
|
|
237
|
+
|
|
238
|
+
&:focus {
|
|
239
|
+
border-color: $prism-color-primary;
|
|
240
|
+
box-shadow: 0 0 0 3px rgba($prism-color-primary, 0.15);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.select2-results__option {
|
|
246
|
+
padding: 8px 12px;
|
|
247
|
+
color: $prism-text-body;
|
|
248
|
+
|
|
249
|
+
&--highlighted {
|
|
250
|
+
background: $prism-color-primary-light !important;
|
|
251
|
+
color: $prism-color-primary-dark !important;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
&[aria-selected="true"] {
|
|
255
|
+
background: $prism-bg-page;
|
|
256
|
+
color: $prism-text-heading;
|
|
257
|
+
font-weight: 600;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.select2-results__message {
|
|
262
|
+
color: $prism-text-muted;
|
|
263
|
+
padding: 8px 12px;
|
|
264
|
+
}
|