madmin 2.6.0 → 3.0.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 +4 -4
- data/README.md +107 -4
- data/app/assets/stylesheets/madmin/actiontext.css +31 -0
- data/app/assets/stylesheets/madmin/base.css +22 -11
- data/app/assets/stylesheets/madmin/buttons.css +9 -9
- data/app/assets/stylesheets/madmin/forms.css +263 -7
- data/app/assets/stylesheets/madmin/pagination.css +10 -23
- data/app/assets/stylesheets/madmin/reset.css +1 -1
- data/app/assets/stylesheets/madmin/sidebar.css +6 -6
- data/app/assets/stylesheets/madmin/tables.css +1 -1
- data/app/controllers/madmin/base_controller.rb +1 -5
- data/app/controllers/madmin/resource_controller.rb +38 -17
- data/app/helpers/madmin/application_helper.rb +15 -2
- data/app/helpers/madmin/filters_helper.rb +26 -0
- data/app/helpers/madmin/sort_helper.rb +1 -1
- data/app/javascript/madmin/controllers/filters_controller.js +35 -0
- data/app/javascript/madmin/controllers/nested_form_controller.js +5 -0
- data/app/javascript/madmin/controllers/select_controller.js +269 -22
- data/app/views/layouts/madmin/application.html.erb +1 -0
- data/app/views/madmin/application/_active_filters.html.erb +15 -0
- data/app/views/madmin/application/_filter.html.erb +13 -0
- data/app/views/madmin/application/_filters.html.erb +32 -0
- data/app/views/madmin/application/_javascript.html.erb +0 -2
- data/app/views/madmin/application/_pagination.html.erb +32 -0
- data/app/views/madmin/application/edit.html.erb +1 -1
- data/app/views/madmin/application/index.html.erb +13 -12
- data/app/views/madmin/application/new.html.erb +1 -1
- data/app/views/madmin/application/show.html.erb +1 -1
- data/app/views/madmin/fields/array/_form.html.erb +1 -0
- data/app/views/madmin/fields/array/_index.html.erb +1 -0
- data/app/views/madmin/fields/array/_show.html.erb +1 -0
- data/app/views/madmin/fields/attachment/_form.html.erb +0 -4
- data/app/views/madmin/fields/attachment/_show.html.erb +3 -1
- data/app/views/madmin/fields/attachments/_index.html.erb +1 -1
- data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -1
- data/app/views/madmin/fields/belongs_to/_index.html.erb +5 -2
- data/app/views/madmin/fields/belongs_to/_show.html.erb +1 -1
- data/app/views/madmin/fields/enum/_form.html.erb +1 -1
- data/app/views/madmin/fields/has_many/_form.html.erb +1 -1
- data/app/views/madmin/fields/has_many/_index.html.erb +1 -1
- data/app/views/madmin/fields/has_many/_show.html.erb +3 -11
- data/app/views/madmin/fields/has_one/_index.html.erb +5 -1
- data/app/views/madmin/fields/has_one/_show.html.erb +1 -1
- data/app/views/madmin/fields/json/_form.html.erb +1 -1
- data/app/views/madmin/fields/json/_show.html.erb +1 -1
- data/app/views/madmin/fields/nested_has_many/_index.html.erb +1 -1
- data/app/views/madmin/fields/nested_has_many/_show.html.erb +3 -11
- data/app/views/madmin/fields/nested_has_one/_form.html.erb +18 -0
- data/app/views/madmin/fields/polymorphic/_form.html.erb +1 -2
- data/app/views/madmin/fields/polymorphic/_index.html.erb +5 -1
- data/app/views/madmin/fields/polymorphic/_show.html.erb +1 -1
- data/app/views/madmin/fields/select/_form.html.erb +1 -1
- data/config/importmap.rb +0 -1
- data/config/locales/el.yml +44 -0
- data/config/locales/en.yml +44 -0
- data/config/locales/fr.yml +44 -0
- data/config/locales/ko.yml +44 -0
- data/lib/madmin/field.rb +27 -1
- data/lib/madmin/fields/array.rb +16 -0
- data/lib/madmin/fields/attachment.rb +7 -0
- data/lib/madmin/fields/belongs_to.rb +2 -1
- data/lib/madmin/fields/boolean.rb +1 -0
- data/lib/madmin/fields/currency.rb +7 -0
- data/lib/madmin/fields/date.rb +1 -0
- data/lib/madmin/fields/date_time.rb +1 -0
- data/lib/madmin/fields/decimal.rb +1 -0
- data/lib/madmin/fields/float.rb +1 -0
- data/lib/madmin/fields/has_many.rb +6 -23
- data/lib/madmin/fields/integer.rb +1 -0
- data/lib/madmin/fields/json.rb +21 -0
- data/lib/madmin/fields/nested_has_many.rb +2 -2
- data/lib/madmin/fields/nested_has_one.rb +48 -0
- data/lib/madmin/fields/polymorphic.rb +5 -0
- data/lib/madmin/fields/string.rb +2 -0
- data/lib/madmin/fields/text.rb +2 -0
- data/lib/madmin/filter.rb +96 -0
- data/lib/madmin/menu.rb +2 -1
- data/lib/madmin/page.rb +61 -0
- data/lib/madmin/pagination.rb +50 -0
- data/lib/madmin/resource.rb +85 -7
- data/lib/madmin/search.rb +5 -7
- data/lib/madmin/version.rb +1 -1
- data/lib/madmin.rb +45 -2
- metadata +17 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 502a8cbe4b6c86b1fa6f45d2f4d0f1f5b7852b48805a8d980cfb177ed4151c51
|
|
4
|
+
data.tar.gz: 41d8fbfd222f0758f81e2b90762d54ddbefd279ebd18b455ac2def6bd2a60e1e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c390c0a27fcfe25bee8b1ab32f7d53644cc68cad9ee386f17adf810839a511212dfa7fe821cf275edd63a95d1dccbdbeffb22bad56f1ffa5db6c0e67e56d3a74
|
|
7
|
+
data.tar.gz: be7ec1e7fa71db380147c44f154e539e56719b35be488f7068473dfccfeeba44175abb58ee281bf4eb1089ab8a188eb5b66c0e5d46d847f639f1bbe15895107d
|
data/README.md
CHANGED
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
Why another Ruby on Rails admin? We wanted an admin that was:
|
|
8
8
|
|
|
9
9
|
- Familiar and customizable like Rails scaffolds (less DSL)
|
|
10
|
-
- Supports
|
|
11
|
-
- Stimulus
|
|
12
|
-
-
|
|
10
|
+
- Supports Rails features out of the box (Action Text, Active Storage, Action Mailbox, has_secure_password, etc)
|
|
11
|
+
- Built with Hotwire: Turbo, Stimulus and import maps, with no Node or build step
|
|
12
|
+
- Search, filters and scopes on index pages, and dark mode
|
|
13
|
+
- Works with Propshaft and Sprockets
|
|
13
14
|
|
|
14
|
-

|
|
16
|
+
|
|
17
|
+

|
|
15
18
|
|
|
16
19
|
## Installation
|
|
17
20
|
|
|
@@ -72,6 +75,66 @@ end
|
|
|
72
75
|
|
|
73
76
|
The new, edit, and delete links are hidden for read-only resources, and any write actions redirect back to the index.
|
|
74
77
|
|
|
78
|
+
### Scopes
|
|
79
|
+
|
|
80
|
+
Declare scopes on a resource to render filter buttons on the index page. Each scope must be a scope or class method on the model:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
class PostResource < Madmin::Resource
|
|
84
|
+
scope :published
|
|
85
|
+
scope :draft
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Button labels default to the humanized scope name. To customize or translate them, define an I18n key — `madmin.scopes.<param_key>.<scope>` for one resource, or `madmin.scopes.<scope>` shared across resources:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
en:
|
|
93
|
+
madmin:
|
|
94
|
+
scopes:
|
|
95
|
+
post:
|
|
96
|
+
published: Live
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Filters
|
|
100
|
+
|
|
101
|
+
Index pages have a Filters button for narrowing records by their columns, like "Admin is true" or "Created at after Aug 15". Filters combine with search, scopes and sorting, and they're kept in the URL so filtered lists can be bookmarked and shared.
|
|
102
|
+
|
|
103
|
+
String, text, number, date, datetime and boolean columns can be filtered. Encrypted columns and attributes that aren't database columns are left out. Turn filtering off for an attribute with `filter: false`:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
class UserResource < Madmin::Resource
|
|
107
|
+
attribute :api_token, filter: false
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Custom fields can offer a filter by returning `:string`, `:number`, `:date`, `:datetime` or `:boolean` from `self.filter_type`.
|
|
112
|
+
|
|
113
|
+
### Resource Names
|
|
114
|
+
|
|
115
|
+
Resource names in the menu, headings and buttons come from the model's translation when it has one, so they follow Rails' own `activerecord.models` keys:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
en:
|
|
119
|
+
activerecord:
|
|
120
|
+
models:
|
|
121
|
+
post:
|
|
122
|
+
one: Article
|
|
123
|
+
other: Articles
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Models without a translation keep their default names, like `Posts` and `Active Storage / Blobs`.
|
|
127
|
+
|
|
128
|
+
For labels that need logic (e.g. looking up a record name), override `scope_label`:
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
class PostResource < Madmin::Resource
|
|
132
|
+
def self.scope_label(name)
|
|
133
|
+
name.to_s.titleize
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
75
138
|
## Configuring Views
|
|
76
139
|
|
|
77
140
|
The views packaged within the gem are a great starting point, but inevitably people will need to be able to customize those views.
|
|
@@ -147,6 +210,25 @@ class BookResource < Madmin::Resource
|
|
|
147
210
|
end
|
|
148
211
|
```
|
|
149
212
|
|
|
213
|
+
### Nested Forms
|
|
214
|
+
|
|
215
|
+
Use `:nested_has_many` or `:nested_has_one` to edit associated records inside the parent's form. The model needs `accepts_nested_attributes_for`, with `allow_destroy: true` for the Remove link to work, and the associated model needs a resource. Use `skip` to leave out attributes of the associated resource:
|
|
216
|
+
|
|
217
|
+
```ruby
|
|
218
|
+
class User < ApplicationRecord
|
|
219
|
+
has_many :posts
|
|
220
|
+
has_one :profile
|
|
221
|
+
accepts_nested_attributes_for :posts, :profile, allow_destroy: true
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
class UserResource < Madmin::Resource
|
|
225
|
+
attribute :posts, :nested_has_many, skip: %I[user]
|
|
226
|
+
attribute :profile, :nested_has_one, skip: %I[user]
|
|
227
|
+
end
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
A nested has one shows its fields when the record exists, or an "Add" link when it doesn't, so saving the parent doesn't create an empty record.
|
|
231
|
+
|
|
150
232
|
## Custom Fields
|
|
151
233
|
|
|
152
234
|
You can generate a custom field with:
|
|
@@ -250,6 +332,27 @@ Hooks registered after a class has already loaded run immediately, so ordering i
|
|
|
250
332
|
You can use a couple of strategies to authenticate users who are trying to
|
|
251
333
|
access your madmin panel: [Authentication Docs](docs/authentication.md)
|
|
252
334
|
|
|
335
|
+
## Dark Mode
|
|
336
|
+
|
|
337
|
+
Madmin follows the system's light or dark setting. To always use one, add a stylesheet with `Madmin.stylesheets << "madmin_overrides"` (see [Assets](docs/assets.md)) and set `color-scheme`:
|
|
338
|
+
|
|
339
|
+
```css
|
|
340
|
+
:root {
|
|
341
|
+
color-scheme: light;
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Madmin's colors are CSS variables on `:root`, defined with `light-dark()` so each has a light and a dark value. Custom fields and views can use them to match both modes, and you can override them to change the theme:
|
|
346
|
+
|
|
347
|
+
```css
|
|
348
|
+
:root {
|
|
349
|
+
--primary-color: rgb(79 70 229); /* Button backgrounds */
|
|
350
|
+
--link-color: light-dark(rgb(79 70 229), rgb(129 140 248));
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
The variables are `--primary-color`, `--link-color`, `--text-color`, `--light-text-color`, `--surface-color` (page and input backgrounds), `--background-color` (table headers), `--hover-color`, `--border-color`, `--input-border-color` and `--danger-color`.
|
|
355
|
+
|
|
253
356
|
## Assets
|
|
254
357
|
You can customize the JavaScript and CSS assets used by Madmin for your application. To learn how
|
|
255
358
|
see the [Assets Doc](docs/assets.md)
|
|
@@ -29,3 +29,34 @@
|
|
|
29
29
|
padding: 0 !important;
|
|
30
30
|
max-width: 100% !important;
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
/* Trix draws its toolbar icons in black, so its buttons stay light */
|
|
34
|
+
trix-toolbar .trix-button-group {
|
|
35
|
+
background: light-dark(transparent, rgb(209 213 219));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
trix-toolbar .trix-dialog {
|
|
39
|
+
background: var(--background-color);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Lexxy has no dark palette. `html:root` outranks Lexxy's own :root variables, which load after Madmin's */
|
|
43
|
+
html:root {
|
|
44
|
+
--lexxy-color-ink: light-dark(oklch(20% 0 0), var(--text-color));
|
|
45
|
+
--lexxy-color-ink-medium: light-dark(oklch(40% 0 0), rgb(209 213 219));
|
|
46
|
+
--lexxy-color-ink-light: light-dark(oklch(60% 0 0), var(--light-text-color));
|
|
47
|
+
--lexxy-color-ink-lighter: light-dark(oklch(85% 0 0), var(--border-color));
|
|
48
|
+
--lexxy-color-ink-lightest: light-dark(oklch(96% 0 0), var(--background-color));
|
|
49
|
+
--lexxy-color-ink-inverted: var(--surface-color);
|
|
50
|
+
|
|
51
|
+
--lexxy-color-accent-light: light-dark(oklch(88% 0.026 254), rgb(30 64 175));
|
|
52
|
+
--lexxy-color-accent-lightest: light-dark(oklch(92% 0.026 254), rgb(30 58 138));
|
|
53
|
+
|
|
54
|
+
--lexxy-color-code-token-att: light-dark(#d73a49, #f97583);
|
|
55
|
+
--lexxy-color-code-token-comment: light-dark(#6a737d, #959da5);
|
|
56
|
+
--lexxy-color-code-token-function: light-dark(#6f42c1, #b392f0);
|
|
57
|
+
--lexxy-color-code-token-operator: light-dark(#d73a49, #f97583);
|
|
58
|
+
--lexxy-color-code-token-property: light-dark(#005cc5, #79b8ff);
|
|
59
|
+
--lexxy-color-code-token-punctuation: light-dark(#24292e, #e1e4e8);
|
|
60
|
+
--lexxy-color-code-token-selector: light-dark(#22863a, #85e89d);
|
|
61
|
+
--lexxy-color-code-token-variable: light-dark(#e36209, #ffab70);
|
|
62
|
+
}
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
:root {
|
|
2
|
+
/* Follows the system setting. Set `color-scheme: light` or `dark` on :root to force one */
|
|
3
|
+
color-scheme: light dark;
|
|
4
|
+
|
|
5
|
+
/* Button backgrounds, with white text */
|
|
2
6
|
--primary-color: rgb(37 99 235);
|
|
3
|
-
--
|
|
4
|
-
--
|
|
5
|
-
--
|
|
6
|
-
--
|
|
7
|
+
--link-color: light-dark(rgb(37 99 235), rgb(96 165 250));
|
|
8
|
+
--border-color: light-dark(rgb(229 231 235), rgb(55 65 81));
|
|
9
|
+
--input-border-color: rgb(156 163 175);
|
|
10
|
+
--surface-color: light-dark(white, rgb(17 24 39));
|
|
11
|
+
--background-color: light-dark(rgb(249 250 251), rgb(31 41 55));
|
|
12
|
+
--hover-color: light-dark(rgb(243 244 246), rgb(31 41 55));
|
|
13
|
+
--text-color: light-dark(rgb(2 6 23), rgb(243 244 246));
|
|
14
|
+
--light-text-color: light-dark(rgb(71 85 105), rgb(156 163 175));
|
|
15
|
+
--danger-color: light-dark(rgb(239 68 68), rgb(248 113 113));
|
|
7
16
|
--sidebar-width: 16rem;
|
|
8
17
|
}
|
|
9
18
|
|
|
10
19
|
body {
|
|
20
|
+
background-color: var(--surface-color);
|
|
11
21
|
color: var(--text-color);
|
|
12
22
|
font-size: 14px;
|
|
13
23
|
-webkit-font-smoothing: antialiased;
|
|
@@ -19,7 +29,7 @@ body {
|
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
a {
|
|
22
|
-
color: var(--
|
|
32
|
+
color: var(--link-color);
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
.size-5 {
|
|
@@ -46,8 +56,8 @@ a {
|
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
&.alert-danger {
|
|
49
|
-
background-color: oklch(.936 .032 17.717);
|
|
50
|
-
color: oklch(.444 .177 26.899);
|
|
59
|
+
background-color: light-dark(oklch(.936 .032 17.717), oklch(.258 .092 26.042));
|
|
60
|
+
color: light-dark(oklch(.444 .177 26.899), oklch(.885 .062 18.334));
|
|
51
61
|
|
|
52
62
|
svg {
|
|
53
63
|
color: oklch(.637 .237 25.331);
|
|
@@ -55,13 +65,14 @@ a {
|
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
&.alert-notice {
|
|
58
|
-
background-color: oklch(.962 .044 156.743);
|
|
59
|
-
color: oklch(.448 .119 151.328);
|
|
68
|
+
background-color: light-dark(oklch(.962 .044 156.743), oklch(.266 .065 152.934));
|
|
69
|
+
color: light-dark(oklch(.448 .119 151.328), oklch(.925 .084 155.995));
|
|
60
70
|
|
|
61
71
|
svg {
|
|
62
72
|
color: oklch(.723 .219 149.579);
|
|
63
73
|
}
|
|
64
74
|
}
|
|
75
|
+
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
.search {
|
|
@@ -104,14 +115,14 @@ a {
|
|
|
104
115
|
|
|
105
116
|
|
|
106
117
|
.metric {
|
|
107
|
-
border: 1px solid
|
|
118
|
+
border: 1px solid var(--border-color);
|
|
108
119
|
border-radius: 0.25rem;
|
|
109
120
|
padding: 1rem;
|
|
110
121
|
margin: 1rem;
|
|
111
122
|
flex: 1 1 0%;
|
|
112
123
|
|
|
113
124
|
h4 {
|
|
114
|
-
color:
|
|
125
|
+
color: var(--light-text-color);
|
|
115
126
|
font-weight: 600;
|
|
116
127
|
margin-top: 0;
|
|
117
128
|
margin-bottom: 0.5rem;
|
|
@@ -28,26 +28,26 @@
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
&.btn-secondary {
|
|
31
|
-
background-color:
|
|
32
|
-
color:
|
|
33
|
-
box-shadow: inset 0 0 0 1px
|
|
31
|
+
background-color: var(--surface-color);
|
|
32
|
+
color: var(--text-color);
|
|
33
|
+
box-shadow: inset 0 0 0 1px var(--input-border-color);
|
|
34
34
|
|
|
35
35
|
&:hover {
|
|
36
|
-
background-color:
|
|
36
|
+
background-color: var(--hover-color);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
&.active {
|
|
40
|
-
background-color:
|
|
40
|
+
background-color: var(--hover-color);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
&.btn-danger {
|
|
45
|
-
background-color:
|
|
46
|
-
color:
|
|
47
|
-
box-shadow: inset 0 0 0 1px
|
|
45
|
+
background-color: var(--surface-color);
|
|
46
|
+
color: var(--danger-color);
|
|
47
|
+
box-shadow: inset 0 0 0 1px var(--danger-color);
|
|
48
48
|
|
|
49
49
|
&:hover {
|
|
50
|
-
background-color:
|
|
50
|
+
background-color: var(--hover-color);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
.error {
|
|
2
|
-
color:
|
|
2
|
+
color: var(--danger-color);
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.form-hint {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
label {
|
|
23
|
-
color:
|
|
23
|
+
color: var(--text-color);
|
|
24
24
|
line-height: 1.5rem;
|
|
25
25
|
font-weight: 500;
|
|
26
26
|
font-size: 0.875rem;
|
|
@@ -62,10 +62,10 @@ select {
|
|
|
62
62
|
-webkit-appearance: none;
|
|
63
63
|
-moz-appearance: none;
|
|
64
64
|
appearance: none;
|
|
65
|
-
background-color:
|
|
65
|
+
background-color: var(--surface-color);
|
|
66
66
|
|
|
67
67
|
border-radius: 0.375rem;
|
|
68
|
-
box-shadow: inset 0 0 0 1px
|
|
68
|
+
box-shadow: inset 0 0 0 1px var(--input-border-color);
|
|
69
69
|
line-height: 1.5rem;
|
|
70
70
|
padding-bottom: 0.375rem;
|
|
71
71
|
padding-left: 0.75rem;
|
|
@@ -73,18 +73,274 @@ select {
|
|
|
73
73
|
padding-top: 0.375rem;
|
|
74
74
|
|
|
75
75
|
&:focus {
|
|
76
|
-
box-shadow: inset 0 0 0 1px
|
|
76
|
+
box-shadow: inset 0 0 0 1px var(--primary-color);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
.required {
|
|
81
|
-
color:
|
|
81
|
+
color: var(--danger-color);
|
|
82
82
|
font-weight: 600;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
.nested-fields {
|
|
86
|
-
border: 1px solid
|
|
86
|
+
border: 1px solid var(--border-color);
|
|
87
87
|
border-radius: 0.5rem;
|
|
88
88
|
padding: 1.25rem;
|
|
89
89
|
margin-bottom: 1rem;
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
/* Native selects lose their arrow with `appearance: none` */
|
|
93
|
+
select:not([multiple]) {
|
|
94
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%239ca3af' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
|
95
|
+
background-position: right 0.5rem center;
|
|
96
|
+
background-repeat: no-repeat;
|
|
97
|
+
background-size: 1.5em 1.5em;
|
|
98
|
+
padding-right: 2.5rem;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Combobox (select_controller.js) */
|
|
102
|
+
.combobox {
|
|
103
|
+
position: relative;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.combobox-control {
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-wrap: wrap;
|
|
109
|
+
align-items: center;
|
|
110
|
+
gap: 0.25rem;
|
|
111
|
+
background-color: var(--surface-color);
|
|
112
|
+
border-radius: 0.375rem;
|
|
113
|
+
box-shadow: inset 0 0 0 1px var(--input-border-color);
|
|
114
|
+
padding: 0.375rem 0.75rem;
|
|
115
|
+
cursor: text;
|
|
116
|
+
|
|
117
|
+
&:focus-within {
|
|
118
|
+
box-shadow: inset 0 0 0 1px var(--primary-color);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.combobox .combobox-input,
|
|
123
|
+
.combobox .combobox-input:focus {
|
|
124
|
+
flex: 1;
|
|
125
|
+
min-width: 8rem;
|
|
126
|
+
background: transparent;
|
|
127
|
+
box-shadow: none;
|
|
128
|
+
outline: none;
|
|
129
|
+
padding: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.combobox-chip {
|
|
133
|
+
display: inline-flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: 0.25rem;
|
|
136
|
+
background-color: var(--hover-color);
|
|
137
|
+
border-radius: 0.25rem;
|
|
138
|
+
padding-left: 0.5rem;
|
|
139
|
+
font-size: 0.875rem;
|
|
140
|
+
|
|
141
|
+
button {
|
|
142
|
+
background: none;
|
|
143
|
+
border: none;
|
|
144
|
+
color: var(--light-text-color);
|
|
145
|
+
cursor: pointer;
|
|
146
|
+
padding: 0 0.5rem;
|
|
147
|
+
|
|
148
|
+
&:hover {
|
|
149
|
+
color: var(--text-color);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.combobox-listbox {
|
|
155
|
+
position: absolute;
|
|
156
|
+
z-index: 10;
|
|
157
|
+
top: 100%;
|
|
158
|
+
left: 0;
|
|
159
|
+
right: 0;
|
|
160
|
+
margin-top: 0.25rem;
|
|
161
|
+
max-height: 16rem;
|
|
162
|
+
overflow-y: auto;
|
|
163
|
+
list-style: none;
|
|
164
|
+
padding: 0.25rem 0;
|
|
165
|
+
background-color: var(--surface-color);
|
|
166
|
+
border: 1px solid var(--border-color);
|
|
167
|
+
border-radius: 0.375rem;
|
|
168
|
+
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
|
169
|
+
|
|
170
|
+
&[hidden] {
|
|
171
|
+
display: none;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
li {
|
|
175
|
+
padding: 0.375rem 0.75rem;
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
[aria-selected="true"] {
|
|
180
|
+
background-color: var(--hover-color);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.combobox-empty {
|
|
184
|
+
color: var(--light-text-color);
|
|
185
|
+
cursor: default;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Index filters (filters_controller.js) */
|
|
190
|
+
.filters-count {
|
|
191
|
+
background-color: var(--primary-color);
|
|
192
|
+
border-radius: 999px;
|
|
193
|
+
color: white;
|
|
194
|
+
display: inline-block;
|
|
195
|
+
font-size: 0.75rem;
|
|
196
|
+
line-height: 1.125rem;
|
|
197
|
+
margin-left: 0.25rem;
|
|
198
|
+
min-width: 1.125rem;
|
|
199
|
+
padding: 0 0.3rem;
|
|
200
|
+
text-align: center;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.filters {
|
|
204
|
+
background-color: var(--surface-color);
|
|
205
|
+
border: 1px solid var(--border-color);
|
|
206
|
+
border-radius: 0.5rem;
|
|
207
|
+
box-shadow: 0 10px 25px -5px rgb(0 0 0 / 0.2);
|
|
208
|
+
color: var(--text-color);
|
|
209
|
+
inset: auto;
|
|
210
|
+
margin: 0;
|
|
211
|
+
padding: 1rem;
|
|
212
|
+
right: 1rem;
|
|
213
|
+
top: 4.5rem;
|
|
214
|
+
width: min(44rem, calc(100vw - 2rem));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Place it under the button where anchor positioning is supported */
|
|
218
|
+
@supports (position-anchor: --filters) {
|
|
219
|
+
#filters-button {
|
|
220
|
+
anchor-name: --filters;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.filters {
|
|
224
|
+
position-anchor: --filters;
|
|
225
|
+
right: anchor(right);
|
|
226
|
+
top: calc(anchor(bottom) + 0.5rem);
|
|
227
|
+
|
|
228
|
+
/* Phones use the full width instead of lining up with the button */
|
|
229
|
+
@media (max-width: 767px) {
|
|
230
|
+
left: 1rem;
|
|
231
|
+
right: 1rem;
|
|
232
|
+
width: auto;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.filters-heading {
|
|
238
|
+
font-weight: 600;
|
|
239
|
+
margin: 0 0 0.75rem;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.filter-rows {
|
|
243
|
+
display: grid;
|
|
244
|
+
gap: 0.5rem;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.filter-row {
|
|
248
|
+
align-items: center;
|
|
249
|
+
display: grid;
|
|
250
|
+
gap: 0.5rem;
|
|
251
|
+
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1.2fr) auto;
|
|
252
|
+
|
|
253
|
+
select, input {
|
|
254
|
+
min-width: 0;
|
|
255
|
+
width: 100%;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.filter-remove {
|
|
259
|
+
grid-column: 4;
|
|
260
|
+
grid-row: 1;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
@media (max-width: 767px) {
|
|
264
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
|
|
265
|
+
|
|
266
|
+
input {
|
|
267
|
+
grid-column: 1 / 3;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.filter-remove {
|
|
271
|
+
grid-column: 3;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.filter-remove {
|
|
277
|
+
background: none;
|
|
278
|
+
border: none;
|
|
279
|
+
border-radius: 0.375rem;
|
|
280
|
+
color: var(--light-text-color);
|
|
281
|
+
cursor: pointer;
|
|
282
|
+
font-size: 1.125rem;
|
|
283
|
+
height: 2rem;
|
|
284
|
+
width: 2rem;
|
|
285
|
+
|
|
286
|
+
&:hover {
|
|
287
|
+
background-color: var(--hover-color);
|
|
288
|
+
color: var(--danger-color);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.filters-footer {
|
|
293
|
+
align-items: center;
|
|
294
|
+
border-top: 1px solid var(--border-color);
|
|
295
|
+
display: flex;
|
|
296
|
+
flex-wrap: wrap;
|
|
297
|
+
gap: 0.5rem;
|
|
298
|
+
justify-content: space-between;
|
|
299
|
+
margin-top: 0.875rem;
|
|
300
|
+
padding-top: 0.875rem;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.btn.btn-link {
|
|
304
|
+
background: none;
|
|
305
|
+
color: var(--link-color);
|
|
306
|
+
font-weight: 500;
|
|
307
|
+
padding-left: 0.25rem;
|
|
308
|
+
padding-right: 0.25rem;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.active-filters {
|
|
312
|
+
align-items: center;
|
|
313
|
+
display: flex;
|
|
314
|
+
flex-wrap: wrap;
|
|
315
|
+
gap: 0.5rem;
|
|
316
|
+
margin-bottom: 1rem;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.filter-chip {
|
|
320
|
+
align-items: center;
|
|
321
|
+
background-color: light-dark(rgb(239 246 255), rgb(30 41 82));
|
|
322
|
+
border-radius: 999px;
|
|
323
|
+
color: light-dark(rgb(30 64 175), rgb(191 219 254));
|
|
324
|
+
display: inline-flex;
|
|
325
|
+
font-size: 0.8125rem;
|
|
326
|
+
font-weight: 500;
|
|
327
|
+
gap: 0.25rem;
|
|
328
|
+
padding: 0.125rem 0.25rem 0.125rem 0.75rem;
|
|
329
|
+
|
|
330
|
+
strong {
|
|
331
|
+
font-weight: 600;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
a {
|
|
335
|
+
border-radius: 999px;
|
|
336
|
+
color: inherit;
|
|
337
|
+
line-height: 1.5rem;
|
|
338
|
+
text-align: center;
|
|
339
|
+
text-decoration: none;
|
|
340
|
+
width: 1.5rem;
|
|
341
|
+
|
|
342
|
+
&:hover {
|
|
343
|
+
background-color: var(--surface-color);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
padding: 0.5rem;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
-
.
|
|
5
|
+
.pagination .pages {
|
|
6
6
|
display: inline-flex;
|
|
7
7
|
isolation: isolate;
|
|
8
8
|
border-radius: 0.375rem;
|
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
align-items: center;
|
|
18
18
|
box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
|
19
19
|
--tw-ring-inset: inset;
|
|
20
|
-
--tw-ring-color:
|
|
20
|
+
--tw-ring-color: var(--input-border-color);
|
|
21
21
|
font-size: 0.875rem;
|
|
22
22
|
line-height: 1.25rem;
|
|
23
|
-
color:
|
|
24
|
-
background-color:
|
|
23
|
+
color: var(--text-color);
|
|
24
|
+
background-color: var(--surface-color);
|
|
25
25
|
border-radius: 0.25rem;
|
|
26
26
|
text-decoration: none;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
a:hover {
|
|
30
|
-
background-color:
|
|
30
|
+
background-color: var(--hover-color);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
a
|
|
34
|
-
color:
|
|
33
|
+
a[aria-disabled="true"] {
|
|
34
|
+
color: var(--input-border-color);
|
|
35
35
|
cursor: default;
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -39,21 +39,8 @@
|
|
|
39
39
|
color: #ffffff;
|
|
40
40
|
background-color: var(--primary-color);
|
|
41
41
|
}
|
|
42
|
+
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
padding-top: 0.125rem;
|
|
46
|
-
padding-bottom: 0.125rem;
|
|
47
|
-
padding-left: 0.75rem;
|
|
48
|
-
padding-right: 0.75rem;
|
|
49
|
-
border-radius: 0.5rem;
|
|
50
|
-
white-space: nowrap;
|
|
51
|
-
background-color: #E5E7EB;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
label input {
|
|
55
|
-
border-radius: 0.375rem;
|
|
56
|
-
border-style: none;
|
|
57
|
-
background-color: #F3F4F6;
|
|
58
|
-
}
|
|
44
|
+
.pagination-info {
|
|
45
|
+
margin-left: 0.5rem;
|
|
59
46
|
}
|