trestle 0.10.0.pre → 0.10.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +26 -0
  3. data/.github/workflows/rspec.yml +6 -2
  4. data/Gemfile +14 -5
  5. data/README.md +1 -1
  6. data/app/assets/bundle/trestle/admin.css +9 -9
  7. data/app/assets/bundle/trestle/admin.js +13 -13
  8. data/app/assets/bundle/trestle/fa-brands-400.ttf +0 -0
  9. data/app/assets/bundle/trestle/fa-brands-400.woff2 +0 -0
  10. data/app/assets/bundle/trestle/fa-regular-400.ttf +0 -0
  11. data/app/assets/bundle/trestle/fa-regular-400.woff2 +0 -0
  12. data/app/assets/bundle/trestle/fa-solid-900.ttf +0 -0
  13. data/app/assets/bundle/trestle/fa-solid-900.woff2 +0 -0
  14. data/app/assets/bundle/trestle/photoswipe-063ce7be40e10b3e6848.digested.js +6 -0
  15. data/app/assets/sprockets/trestle/icons/font-awesome.css.erb +1 -1
  16. data/app/controllers/concerns/trestle/controller/modal.rb +3 -1
  17. data/app/controllers/concerns/trestle/controller/turbo_stream.rb +12 -0
  18. data/app/controllers/concerns/trestle/resource/controller/actions.rb +3 -3
  19. data/app/controllers/trestle/application_controller.rb +1 -1
  20. data/app/helpers/trestle/modal_helper.rb +0 -5
  21. data/app/helpers/trestle/turbo/frame_helper.rb +29 -0
  22. data/app/helpers/trestle/turbo/stream_helper.rb +9 -0
  23. data/app/helpers/trestle/turbo/tag_builder.rb +21 -0
  24. data/app/helpers/trestle/url_helper.rb +2 -2
  25. data/app/views/layouts/trestle/admin.html.erb +1 -1
  26. data/app/views/layouts/trestle/admin.turbo_stream.erb +2 -9
  27. data/app/views/trestle/application/_header.html.erb +12 -10
  28. data/app/views/trestle/resource/create.turbo_stream.erb +1 -5
  29. data/app/views/trestle/resource/destroy.turbo_stream.erb +1 -1
  30. data/app/views/trestle/resource/edit.html.erb +2 -0
  31. data/app/views/trestle/resource/index.html.erb +5 -0
  32. data/app/views/trestle/resource/new.html.erb +5 -0
  33. data/app/views/trestle/resource/show.html.erb +2 -0
  34. data/app/views/trestle/resource/update.turbo_stream.erb +1 -5
  35. data/app/views/trestle/shared/_sidebar.html.erb +2 -2
  36. data/frontend/css/components/_alerts.scss +22 -20
  37. data/frontend/css/components/_avatar.scss +12 -12
  38. data/frontend/css/components/_background.scss +1 -1
  39. data/frontend/css/components/_breadcrumbs.scss +8 -29
  40. data/frontend/css/components/_buttons.scss +3 -3
  41. data/frontend/css/components/_datepicker.scss +3 -3
  42. data/frontend/css/components/_dropdown.scss +18 -26
  43. data/frontend/css/components/_forms.scss +4 -4
  44. data/frontend/css/components/_grid.scss +29 -0
  45. data/frontend/css/components/_media-grid.scss +1 -1
  46. data/frontend/css/components/_modal.scss +4 -4
  47. data/frontend/css/components/_pagination.scss +4 -8
  48. data/frontend/css/components/_popover.scss +1 -1
  49. data/frontend/css/components/_scopes.scss +4 -10
  50. data/frontend/css/components/_select.scss +8 -9
  51. data/frontend/css/components/_sort.scss +1 -1
  52. data/frontend/css/components/_table.scss +5 -5
  53. data/frontend/css/components/_tabs.scss +11 -18
  54. data/frontend/css/components/_tags.scss +16 -6
  55. data/frontend/css/components/_toolbars.scss +9 -9
  56. data/frontend/css/core/_functions.scss +0 -8
  57. data/frontend/css/core/_theme.scss +3 -0
  58. data/frontend/css/core/_typography.scss +12 -19
  59. data/frontend/css/index.scss +3 -1
  60. data/frontend/css/layout/_base.scss +4 -2
  61. data/frontend/css/layout/_content-header.scss +71 -0
  62. data/frontend/css/layout/_footer.scss +5 -7
  63. data/frontend/css/layout/_main-content.scss +107 -0
  64. data/frontend/css/layout/_navigation.scss +111 -49
  65. data/frontend/css/layout/_sidebar.scss +60 -34
  66. data/frontend/css/variables/_bootstrap.scss +30 -21
  67. data/frontend/css/variables/_trestle.scss +20 -17
  68. data/frontend/js/controllers/batch_action_controller.js +59 -0
  69. data/frontend/js/controllers/checkbox_select_controller.js +3 -0
  70. data/frontend/js/controllers/confirm_delete_controller.js +4 -4
  71. data/frontend/js/controllers/gallery_controller.js +2 -0
  72. data/frontend/js/controllers/lightbox_controller.js +0 -2
  73. data/lib/trestle/engine.rb +18 -16
  74. data/lib/trestle/form/renderer.rb +1 -1
  75. data/lib/trestle/resource/toolbar.rb +18 -8
  76. data/lib/trestle/sprockets_compressor.rb +16 -0
  77. data/lib/trestle/toolbar/context.rb +7 -4
  78. data/lib/trestle/toolbar/menu.rb +8 -5
  79. data/lib/trestle/version.rb +1 -1
  80. data/package.json +1 -1
  81. data/trestle.gemspec +5 -9
  82. data/yarn.lock +350 -363
  83. metadata +35 -70
  84. data/app/assets/bundle/trestle/photoswipe-7aa1aec9c3c1fd65c382.digested.js +0 -6
  85. data/app/controllers/concerns/trestle/controller/turbo.rb +0 -21
  86. data/app/helpers/trestle/turbo_frame_helper.rb +0 -34
  87. data/frontend/css/layout/_content.scss +0 -173
@@ -1,9 +1,19 @@
1
1
  @use "sass:math";
2
2
 
3
+ .app-wrapper {
4
+ --sidebar-width: #{$sidebar-width};
5
+ --sidebar-width-collapsed: #{$sidebar-width-collapsed};
6
+ --sidebar-padding: #{$sidebar-padding};
7
+ --sidebar-padding-collapsed: #{$sidebar-padding-collapsed};
8
+ --sidebar-transition-duration: #{$sidebar-transition-duration};
9
+ --sidebar-transition-timing: ease-out;
10
+ --sidebar-bg: #{$sidebar-bg};
11
+ }
12
+
3
13
  .app-sidebar {
4
- background: $sidebar-bg;
14
+ background: var(--sidebar-bg);
5
15
 
6
- width: $sidebar-width;
16
+ width: var(--sidebar-width);
7
17
  padding: 0;
8
18
 
9
19
  flex-shrink: 0;
@@ -15,6 +25,8 @@
15
25
  flex-wrap: nowrap;
16
26
 
17
27
  align-items: stretch;
28
+
29
+ transition: width var(--sidebar-transition-duration) var(--sidebar-transition-timing);
18
30
  }
19
31
 
20
32
  .app-sidebar-header {
@@ -25,10 +37,12 @@
25
37
  display: flex;
26
38
  align-items: stretch;
27
39
 
40
+ overflow: hidden;
41
+
28
42
  .navbar-toggler {
29
- --bs-navbar-toggler-bg: #{$sidebar-mobile-toggle-bg};
30
- --bs-navbar-toggler-color: #{$sidebar-mobile-toggle-border-color};
31
- --bs-navbar-toggler-border-color: #{$sidebar-mobile-toggle-border-color};
43
+ --#{$prefix}navbar-toggler-bg: #{$sidebar-mobile-toggle-bg};
44
+ --#{$prefix}navbar-toggler-color: #{$sidebar-mobile-toggle-border-color};
45
+ --#{$prefix}navbar-toggler-border-color: #{$sidebar-mobile-toggle-border-color};
32
46
 
33
47
  outline: none;
34
48
 
@@ -37,28 +51,29 @@
37
51
  margin-left: math.div($grid-gutter-width, 2);
38
52
  margin-right: math.div($grid-gutter-width, 2);
39
53
 
40
- background: var(--bs-navbar-toggler-bg);
54
+ background: var(--#{$prefix}navbar-toggler-bg);
41
55
 
42
56
  &:hover, &:focus {
43
- --bs-navbar-toggler-border-color: #{$sidebar-mobile-toggle-active-border-color};
44
- --bs-navbar-toggler-bg: #{$sidebar-mobile-toggle-active-bg};
57
+ --#{$prefix}navbar-toggler-border-color: #{$sidebar-mobile-toggle-active-border-color};
58
+ --#{$prefix}navbar-toggler-bg: #{$sidebar-mobile-toggle-active-bg};
45
59
  }
46
60
  }
47
61
 
48
62
  .navbar-toggler-icon {
49
- --bs-navbar-toggler-icon-bg: #{$sidebar-mobile-toggle-icon-bg};
63
+ --#{$prefix}navbar-toggler-icon-bg: #{$sidebar-mobile-toggle-icon-bg};
50
64
  }
51
65
  }
52
66
 
53
67
  .app-sidebar-title {
54
- flex: 1;
68
+ flex: 1 0 var(--sidebar-width);
69
+ width: var(--sidebar-width);
55
70
 
56
71
  display: flex;
57
72
  align-items: center;
58
73
 
59
- padding: 10px 15px;
74
+ padding: var(--sidebar-padding);
60
75
 
61
- font-size: 1.4rem;
76
+ font-size: 1.25rem;
62
77
  font-weight: 500;
63
78
  text-shadow: rgba(black, 0.5) 0 1px 1px;
64
79
  color: white;
@@ -72,7 +87,7 @@
72
87
  max-height: 100%;
73
88
 
74
89
  & + .title-large {
75
- margin-left: 10px;
90
+ margin-left: 0.75rem;
76
91
  }
77
92
  }
78
93
 
@@ -112,8 +127,9 @@
112
127
  color: $sidebar-toggle-color;
113
128
  border: none;
114
129
 
115
- font-size: 1.4rem;
116
- padding: 10px 20px;
130
+ font-size: 1.25rem;
131
+ width: var(--sidebar-width-collapsed);
132
+ padding: 0.625rem;
117
133
 
118
134
  cursor: pointer;
119
135
 
@@ -138,19 +154,13 @@
138
154
  }
139
155
 
140
156
  .app-wrapper {
141
- margin-left: -$sidebar-width;
142
- margin-right: 0;
157
+ width: calc(100% + var(--sidebar-width));
143
158
 
144
- &.animate {
145
- transition: all $sidebar-transition-duration ease-out;
146
- transition-property: margin-left, margin-right;
147
- }
148
- }
159
+ translate: calc(var(--sidebar-width) * -1);
160
+ transition: translate var(--sidebar-transition-duration) ease-out;
149
161
 
150
- .mobile-nav-expanded {
151
- .app-wrapper {
152
- margin-left: 0;
153
- margin-right: -$sidebar-width;
162
+ .mobile-nav-expanded & {
163
+ translate: 0;
154
164
  }
155
165
  }
156
166
 
@@ -161,14 +171,14 @@
161
171
  .app-sidebar-header {
162
172
  position: absolute;
163
173
  top: 0;
164
- left: $sidebar-width;
174
+ left: var(--sidebar-width);
165
175
  right: 0;
166
176
  z-index: 1;
167
177
  }
168
178
 
169
179
  .app-sidebar-title {
170
180
  justify-content: center;
171
- padding: 10px 5px;
181
+ padding: var(--sidebar-padding-collapsed);
172
182
 
173
183
  // Match right margin with navbar toggler width:
174
184
  // (margin + border + font-size * icon-width + padding)
@@ -182,14 +192,17 @@
182
192
 
183
193
  @include media-breakpoint-between(md, xl) {
184
194
  .app-sidebar {
185
- width: $sidebar-width-collapsed;
195
+ width: var(--sidebar-width-collapsed);
186
196
 
187
197
  .app-sidebar-header {
188
198
  text-align: center;
189
199
  }
190
200
 
191
201
  .app-sidebar-title {
192
- padding: 10px 5px;
202
+ width: var(--sidebar-width-collapsed);
203
+ flex-basis: var(--sidebar-width-collapsed);
204
+
205
+ padding: var(--sidebar-padding-collapsed);
193
206
  justify-content: center;
194
207
 
195
208
  img {
@@ -210,14 +223,17 @@
210
223
  }
211
224
 
212
225
  .sidebar-expanded & {
213
- width: $sidebar-width;
226
+ width: var(--sidebar-width);
214
227
 
215
228
  .app-sidebar-header {
216
229
  text-align: left;
217
230
  }
218
231
 
219
232
  .app-sidebar-title {
220
- padding: 10px 15px;
233
+ width: var(--sidebar-width);
234
+ flex-basis: var(--sidebar-width);
235
+
236
+ padding: var(--sidebar-padding);
221
237
  justify-content: flex-start;
222
238
 
223
239
  img {
@@ -243,14 +259,17 @@
243
259
  @include media-breakpoint-up(xl) {
244
260
  .app-sidebar {
245
261
  .sidebar-collapsed & {
246
- width: $sidebar-width-collapsed;
262
+ width: var(--sidebar-width-collapsed);
247
263
 
248
264
  .app-sidebar-header {
249
265
  text-align: center;
250
266
  }
251
267
 
252
268
  .app-sidebar-title {
253
- padding: 10px 5px;
269
+ width: var(--sidebar-width-collapsed);
270
+ flex-basis: var(--sidebar-width-collapsed);
271
+
272
+ padding: var(--sidebar-padding-collapsed);
254
273
  justify-content: center;
255
274
 
256
275
  img {
@@ -272,3 +291,10 @@
272
291
  }
273
292
  }
274
293
  }
294
+
295
+ @media (prefers-reduced-motion) {
296
+ .app-sidebar,
297
+ .app-wrapper {
298
+ transition: none;
299
+ }
300
+ }
@@ -23,7 +23,7 @@ $min-contrast-ratio: 1.7;
23
23
  $enable-shadows: true;
24
24
 
25
25
  // Decrease default grid spacing
26
- $grid-gutter-width: 1.375rem;
26
+ $grid-gutter-width: 1.25rem;
27
27
 
28
28
 
29
29
  // Characters which are escaped by the escape-svg function
@@ -49,15 +49,17 @@ $link-decoration: none;
49
49
  $headings-font-weight: 400;
50
50
  $headings-margin-bottom: 1rem;
51
51
 
52
- $h1-font-size: 2rem;
53
- $h2-font-size: 1.75rem;
54
- $h3-font-size: 1.5rem;
55
- $h4-font-size: 1.25rem;
56
- $h5-font-size: 1.1rem;
57
- $h6-font-size: 1rem;
52
+ $font-size-base: 0.875rem;
53
+
54
+ $h1-font-size: 1.75rem;
55
+ $h2-font-size: 1.5rem;
56
+ $h3-font-size: 1.25rem;
57
+ $h4-font-size: 1.125rem;
58
+ $h5-font-size: 0.95rem;
59
+ $h6-font-size: 0.875rem;
58
60
 
59
61
  $hr-color: rgba(black, 0.375);
60
- $hr-margin-y: 1.5rem;
62
+ $hr-margin-y: 1.25rem;
61
63
 
62
64
 
63
65
  // Navs
@@ -80,8 +82,11 @@ $nav-tabs-link-active-color: $body-color;
80
82
 
81
83
  // Navbar
82
84
 
83
- $navbar-toggler-padding-x: 0.4rem;
84
- $navbar-dark-color: rgba(white, 0.75);
85
+ $navbar-light-color: rgba(white, 0.75);
86
+ $navbar-dark-color: rgba(white, 0.75);
87
+
88
+ $navbar-toggler-padding-x: 0.375rem;
89
+ $navbar-toggler-focus-width: 0.25rem;
85
90
 
86
91
 
87
92
  // Breadcrumbs
@@ -94,7 +99,7 @@ $breadcrumb-divider-color: #cccccc;
94
99
 
95
100
  // Tables
96
101
 
97
- $table-cell-padding-x: 0.625rem;
102
+ $table-cell-padding-x: 0.5rem;
98
103
  $table-cell-padding-y: 0.375rem;
99
104
 
100
105
  $table-bg: transparent;
@@ -105,7 +110,7 @@ $table-border-color: rgba(black, 0.13);
105
110
 
106
111
  // Alerts
107
112
 
108
- $alert-padding-y: 1.5rem;
113
+ $alert-padding-y: 1.25rem;
109
114
  $alert-border-radius: 0.1rem;
110
115
 
111
116
 
@@ -134,7 +139,8 @@ $badge-padding-x: 0.6em;
134
139
 
135
140
  // Buttons
136
141
 
137
- $btn-padding-x-sm: 0.65rem;
142
+ $btn-padding-x-sm: 0.625rem;
143
+ $btn-padding-y-sm: 0.25rem;
138
144
 
139
145
 
140
146
  // Forms
@@ -163,7 +169,7 @@ $form-check-padding-start: $form-check-input-width + 0.6em;
163
169
  $form-switch-width: 2.25em;
164
170
  $form-switch-focus-color: #aaaaaa;
165
171
 
166
- $form-select-padding-x-sm: 0.62rem;
172
+ $form-select-padding-x-sm: 0.625rem;
167
173
  $form-select-padding-x-lg: 0.75rem;
168
174
 
169
175
 
@@ -175,7 +181,7 @@ $dropdown-box-shadow: $box-shadow-sm;
175
181
  $dropdown-arrow-width: 7px;
176
182
  $dropdown-arrow-outer-width: $dropdown-arrow-width + 1px;
177
183
  $dropdown-header-color: #111111;
178
- $dropdown-font-size: 0.9rem;
184
+ $dropdown-font-size: 0.8125rem;
179
185
 
180
186
  $dropdown-link-active-bg: var(--primary);
181
187
 
@@ -208,24 +214,27 @@ $tooltip-color: white;
208
214
 
209
215
  // Popovers
210
216
 
211
- $popover-font-size: 0.9rem;
217
+ $popover-font-size: 0.75rem;
212
218
  $popover-box-shadow: $dropdown-box-shadow;
213
219
 
214
220
  $popover-header-bg: #f7f7f7;
215
221
  $popover-header-border: #ebebeb;
216
222
 
223
+ $popover-header-padding-x: 0.625rem;
224
+ $popover-header-padding-y: 0.375rem;
225
+
226
+ $popover-body-padding-x: 0.625rem;
217
227
  $popover-body-padding-y: 0.5rem;
218
- $popover-body-padding-x: 0.75rem;
219
228
 
220
229
  $popover-arrow-width: $dropdown-arrow-width;
221
230
 
222
231
 
223
232
  // Modals
224
233
 
225
- $modal-inner-padding: 1.5rem;
234
+ $modal-inner-padding: 1.25rem;
226
235
 
227
- $modal-header-padding-x: 1.5rem;
228
- $modal-header-padding-y: 1.05rem;
236
+ $modal-header-padding-x: 1.25rem;
237
+ $modal-header-padding-y: 1rem;
229
238
 
230
239
  $modal-content-bg: white;
231
240
  $modal-content-border-radius: 0;
@@ -262,7 +271,7 @@ $s2bs5-clear-hover-bg-lg: $s2bs5-clear-bg-lg;
262
271
  $s2bs5-clear-tag-icon: $btn-close-bg;
263
272
  $s2bs5-clear-tag-bg: transparent escape-svg($s2bs5-clear-tag-icon) center / $s2b25-clear-height-sm auto no-repeat;
264
273
 
265
- $s2bs5-padding-x: 0.75rem;
274
+ $s2bs5-padding-x: 0.625rem;
266
275
  $s2bs5-padding-y: 0.375rem;
267
276
 
268
277
  $s2bs5-multi-item-padding-x: 0.375rem;
@@ -21,7 +21,7 @@ $theme-bg-variations: (
21
21
  $header-bg: white;
22
22
  $header-color: #333333;
23
23
 
24
- $header-height: 50px;
24
+ $header-height: 3.125rem;
25
25
 
26
26
 
27
27
  // Footer
@@ -29,13 +29,15 @@ $header-height: 50px;
29
29
  $footer-bg: #f9f9f9;
30
30
  $footer-color: #888888;
31
31
 
32
+ $footer-padding: 0.375rem 1.25rem;
33
+
32
34
 
33
35
  // Sidebar
34
36
 
35
37
  $sidebar-bg: #222222;
36
38
  $sidebar-hover-bg: #1a1a1a;
37
39
  $sidebar-active-bg: #393939;
38
- $sidebar-active-border: 4px;
40
+ $sidebar-active-border: 0.25rem;
39
41
 
40
42
  $sidebar-link-color: #919191;
41
43
  $sidebar-group-color: #595959;
@@ -56,10 +58,13 @@ $sidebar-mobile-toggle-active-border-width: $sidebar-mobile-toggle-border-width;
56
58
  $sidebar-mobile-toggle-active-border-color: $sidebar-mobile-toggle-border-color;
57
59
  $sidebar-mobile-toggle-active-border: $sidebar-mobile-toggle-border-width solid $sidebar-mobile-toggle-active-border-color;
58
60
 
59
- $sidebar-width: 250px;
60
- $sidebar-width-collapsed: 54px;
61
+ $sidebar-width: 15.625rem;
62
+ $sidebar-width-collapsed: 3.5rem;
63
+
64
+ $sidebar-padding: 0.5rem 0.875rem;
65
+ $sidebar-padding-collapsed: 0.5rem 0.25rem;
61
66
 
62
- $sidebar-transition-duration: 250ms;
67
+ $sidebar-transition-duration: 200ms;
63
68
 
64
69
 
65
70
  // Content
@@ -67,23 +72,21 @@ $sidebar-transition-duration: 250ms;
67
72
  $content-header-bg: #fafafa;
68
73
  $content-sidebar-bg: #f9f9f9;
69
74
 
70
- $content-sidebar-width: 285px;
75
+ $content-sidebar-width: 17.5rem;
71
76
 
72
- $main-content-header-bg: $content-sidebar-bg;
73
- $main-content-header-padding: 12px 20px;
74
- $main-content-header-border: 1px solid rgba(black, 0.1);
77
+ $main-content-header-bg: $content-sidebar-bg;
78
+ $main-content-header-border: 1px solid rgba(black, 0.1);
75
79
 
76
- $main-content-footer-bg: $content-sidebar-bg;
77
- $main-content-footer-padding: 12px 20px;
78
- $main-content-footer-border: 1px solid rgba(black, 0.1);
80
+ $main-content-footer-bg: $content-sidebar-bg;
81
+ $main-content-footer-border: 1px solid rgba(black, 0.1);
79
82
 
80
83
 
81
84
  // Typography
82
85
 
83
86
  $headings-border: 1px solid rgba(black, 0.1);
84
87
 
85
- $header-font-size-scale: 0.925;
86
- $sidebar-font-size-scale: 0.925;
88
+ $header-font-size-scale: 0.8125;
89
+ $sidebar-font-size-scale: 0.8125;
87
90
 
88
91
  $badge-hover-scale: -15%;
89
92
 
@@ -96,13 +99,13 @@ $tag-border-scale: 0;
96
99
  $tag-hover-bg-scale: -15%;
97
100
  $tag-hover-border-scale: 15%;
98
101
 
99
- $tag-spacing-x: 0.325rem;
100
- $tag-spacing-y: 0.25rem;
102
+ $tag-spacing-x: 0.25rem;
103
+ $tag-spacing-y: 0.2rem;
101
104
 
102
105
 
103
106
  // Scopes
104
107
 
105
- $scope-padding: 0.25rem 0.675rem;
108
+ $scope-padding: 0.2rem 0.625rem;
106
109
 
107
110
  $scope-color: rgba(black, 0.4);
108
111
  $scope-bg: rgba(black, 0.035);
@@ -0,0 +1,59 @@
1
+ import ApplicationController from './application_controller'
2
+
3
+ export default class extends ApplicationController {
4
+ static outlets = ['checkbox-select']
5
+
6
+ connect () {
7
+ if (!this.hasCheckboxSelectOutlet) {
8
+ // Set default outlet if none specified
9
+ this.element.setAttribute(`data-${this.identifier}-checkbox-select-outlet`, '.trestle-table')
10
+ }
11
+
12
+ this.baseHref = this.element.href
13
+
14
+ this.update()
15
+ }
16
+
17
+ update () {
18
+ this.toggleEnabled()
19
+ this.updateHref()
20
+ }
21
+
22
+ toggleEnabled () {
23
+ this.element.classList.toggle('disabled', this.checkboxes.length === 0)
24
+ }
25
+
26
+ updateHref () {
27
+ this.element.href = this.hrefWithSelectedIds
28
+ }
29
+
30
+ get checkboxes () {
31
+ if (this.hasCheckboxSelectOutlet) {
32
+ return this.checkboxSelectOutlet.checked
33
+ } else {
34
+ return []
35
+ }
36
+ }
37
+
38
+ get selectedIds () {
39
+ return this.checkboxes.map(c => c.value)
40
+ }
41
+
42
+ get hrefWithSelectedIds () {
43
+ const ids = this.selectedIds
44
+
45
+ if (ids.length) {
46
+ return `${this.baseHref}?ids=${ids.join(',')}`
47
+ } else {
48
+ return this.baseHref
49
+ }
50
+ }
51
+
52
+ checkboxSelectOutletConnected (outlet, element) {
53
+ element.addEventListener('checkbox-select:change', this.update.bind(this))
54
+ }
55
+
56
+ checkboxSelectOutletDisconnected (outlet, element) {
57
+ element.removeEventListener('checkbox-select:change', this.update.bind(this))
58
+ }
59
+ }
@@ -5,6 +5,7 @@ export default class extends ApplicationController {
5
5
 
6
6
  toggle () {
7
7
  this.updateSelectAllState()
8
+ this.dispatch('change')
8
9
  }
9
10
 
10
11
  toggleAll () {
@@ -13,6 +14,8 @@ export default class extends ApplicationController {
13
14
  this.checkboxTargets.forEach((checkbox) => {
14
15
  checkbox.checked = isChecked
15
16
  })
17
+
18
+ this.dispatch('change')
16
19
  }
17
20
 
18
21
  updateSelectAllState () {
@@ -3,9 +3,9 @@ import ConfirmController from './confirm_controller'
3
3
  import { i18n } from '../core/i18n'
4
4
 
5
5
  export default class extends ConfirmController {
6
- static values = {
7
- confirmLabel: i18n['trestle.confirmation.delete'] || 'Delete'
8
- }
9
-
10
6
  static defaultConfirmClass = 'btn-danger'
7
+
8
+ get confirmLabel () {
9
+ return this.confirmLabelValue || i18n.t('trestle.confirmation.delete', { defaultValue: 'Delete' })
10
+ }
11
11
  }
@@ -1,6 +1,8 @@
1
1
  import LightboxController from './lightbox_controller'
2
2
 
3
3
  export default class extends LightboxController {
4
+ static targets = ["image"]
5
+
4
6
  get options () {
5
7
  return {
6
8
  ...super.options,
@@ -26,8 +26,6 @@ const VideoIframeUrl = {
26
26
  }
27
27
 
28
28
  export default class extends ApplicationController {
29
- static targets = ["image"]
30
-
31
29
  static values = {
32
30
  animationType: { type: String, default: 'zoom' },
33
31
  animationDuration: { type: Number, default: 150 },
@@ -1,3 +1,5 @@
1
+ require "turbo-rails"
2
+
1
3
  module Trestle
2
4
  class Engine < ::Rails::Engine
3
5
  isolate_namespace Trestle
@@ -30,22 +32,6 @@ module Trestle
30
32
  end
31
33
  end
32
34
 
33
- initializer "turbo.mimetype" do
34
- Mime::Type.register "text/vnd.turbo-stream.html", :turbo_stream unless Mime[:turbo_stream]
35
- end
36
-
37
- initializer "turbo.renderer" do
38
- ActiveSupport.on_load(:action_controller) do
39
- # Compatibility fix for Rails 5.2
40
- delegate :media_type, to: "@_response" unless instance_methods.include?(:media_type)
41
-
42
- ActionController::Renderers.add :turbo_stream do |turbo_streams_html, options|
43
- self.content_type = Mime[:turbo_stream] if media_type.nil?
44
- turbo_streams_html
45
- end
46
- end
47
- end
48
-
49
35
  config.to_prepare do
50
36
  Engine.reset_helpers!
51
37
  end
@@ -55,6 +41,22 @@ module Trestle
55
41
  reloader.install(app) unless app.config.eager_load
56
42
  end
57
43
 
44
+ # For compatibility with the `sassc-rails`` gem, register a custom compressor that excludes the
45
+ # Trestle admin stylesheets as a) they are already minimized and b) libsass is not compatible with
46
+ # some of the newer CSS syntax that is used.
47
+ #
48
+ # To avoid this being necessary, it is recommended that either
49
+ # 1) `sassc-rails` is removed from the Gemfile (if not required),
50
+ # 2) the `sassc-embedded` gem is added to the Gemfile, or
51
+ # 3) `sassc-rails` is replaced with `dartsass-sprockets`
52
+ config.assets.configure do |env|
53
+ if original_compressor = config.assets.css_compressor
54
+ require "trestle/sprockets_compressor"
55
+ original_compressor = Sprockets.compressors['text/css'][original_compressor] if original_compressor.is_a?(Symbol)
56
+ config.assets.css_compressor = Trestle::SprocketsCompressor.new(original_compressor)
57
+ end
58
+ end if defined?(SassC::Rails)
59
+
58
60
  def reset_helpers!
59
61
  @helpers = nil
60
62
  end
@@ -14,7 +14,7 @@ module Trestle
14
14
  include Hook::Helpers
15
15
 
16
16
  # Whitelisted helpers will concatenate their result to the output buffer when called.
17
- WHITELISTED_HELPERS = [:row, :col, :render, :tab, :table, :divider, :h1, :h2, :h3, :h4, :h5, :h6, :card, :panel, :well]
17
+ WHITELISTED_HELPERS = [:row, :col, :render, :tab, :table, :divider, :h1, :h2, :h3, :h4, :h5, :h6, :card, :panel, :well, :turbo_frame_tag]
18
18
 
19
19
  # Raw block helpers will pass their block argument directly to the method without wrapping it in a new output buffer.
20
20
  RAW_BLOCK_HELPERS = [:table, :toolbar]
@@ -5,20 +5,30 @@ module Trestle
5
5
  delegate :admin, :instance, to: :@template
6
6
  delegate :translate, :t, to: :admin
7
7
 
8
- def new
9
- link(t("buttons.new", default: "New %{model_name}"), action: :new, style: :light, icon: "fa fa-plus", class: "btn-new-resource") if action?(:new)
8
+ def new(label: t("buttons.new", default: "New %{model_name}"), **attrs)
9
+ return unless action?(:new)
10
+
11
+ defaults = { action: :new, style: :light, icon: "fa fa-plus", class: "btn-new-resource" }
12
+ link(label, defaults.merge(attrs))
10
13
  end
11
14
 
12
- def save
13
- button(t("buttons.save", default: "Save %{model_name}"), style: :success)
15
+ def save(label: t("buttons.save", default: "Save %{model_name}"), **attrs)
16
+ defaults = { style: :success }
17
+ button(label, defaults.merge(attrs))
14
18
  end
15
19
 
16
- def delete
17
- link(t("buttons.delete", default: "Delete %{model_name}"), instance, action: :destroy, style: :danger, icon: "fa fa-trash", data: { turbo_method: "delete", controller: "confirm-delete", confirm_delete_placement_value: "bottom" }) if action?(:destroy)
20
+ def delete(label: t("buttons.delete", default: "Delete %{model_name}"), **attrs)
21
+ return unless action?(:destroy)
22
+
23
+ defaults = Trestle::Options.new(action: :destroy, style: :danger, icon: "fa fa-trash", data: { turbo_method: "delete", turbo_frame: "_top", controller: "confirm-delete", confirm_delete_placement_value: "bottom" })
24
+ link(label, instance, defaults.merge(attrs))
18
25
  end
19
26
 
20
- def dismiss
21
- button(t("buttons.ok", default: "OK"), style: :light, data: { bs_dismiss: "modal" }) if @template.modal_request?
27
+ def dismiss(label: t("buttons.ok", default: "OK"), **attrs)
28
+ return unless @template.modal_request?
29
+
30
+ defaults = Trestle::Options.new(type: :button, style: :light, data: { bs_dismiss: "modal" })
31
+ button(label, defaults.merge(attrs))
22
32
  end
23
33
  alias ok dismiss
24
34
 
@@ -0,0 +1,16 @@
1
+ module Trestle
2
+ class SprocketsCompressor
3
+ def initialize(original_compressor, excluded_files: ["trestle/admin"])
4
+ @original_compressor = original_compressor
5
+ @excluded_files = excluded_files
6
+ end
7
+
8
+ def call(input)
9
+ if @excluded_files.include?(input[:name])
10
+ input[:data]
11
+ else
12
+ @original_compressor.call(input)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -21,11 +21,10 @@ module Trestle
21
21
  end
22
22
 
23
23
  private
24
- def respond_to_missing?(name, include_all=false)
25
- builder.respond_to?(name) || super
26
- end
24
+ def self.ruby2_keywords(*)
25
+ end unless respond_to?(:ruby2_keywords, true)
27
26
 
28
- def method_missing(name, *args, &block)
27
+ ruby2_keywords def method_missing(name, *args, &block)
29
28
  result = builder.send(name, *args, &block)
30
29
 
31
30
  if builder.builder_methods.include?(name)
@@ -34,6 +33,10 @@ module Trestle
34
33
  result
35
34
  end
36
35
  end
36
+
37
+ def respond_to_missing?(name, include_all=false)
38
+ builder.respond_to?(name) || super
39
+ end
37
40
  end
38
41
  end
39
42
  end