biovision-base 0.11.180127 → 0.14.180326

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -0
  3. data/app/assets/javascripts/biovision/base/biovision-sliders.js +12 -9
  4. data/app/assets/javascripts/biovision/base/biovision.js +187 -2
  5. data/app/assets/stylesheets/biovision/base/admin.scss +84 -40
  6. data/app/assets/stylesheets/biovision/base/biovision.scss +104 -44
  7. data/app/assets/stylesheets/biovision/base/buttons/buttons-common.scss +95 -0
  8. data/app/assets/stylesheets/biovision/base/buttons/buttons-rounded.scss +26 -0
  9. data/app/assets/stylesheets/biovision/base/default.scss +2 -2
  10. data/app/assets/stylesheets/biovision/base/default_admin.scss +1 -1
  11. data/app/assets/stylesheets/biovision/base/default_application.scss +1 -1
  12. data/app/assets/stylesheets/biovision/base/themes/simple-layout.scss +115 -0
  13. data/app/assets/stylesheets/biovision/base/users.scss +15 -0
  14. data/app/controllers/agents_controller.rb +3 -3
  15. data/app/controllers/authentication_controller.rb +4 -4
  16. data/app/controllers/browsers_controller.rb +3 -3
  17. data/app/controllers/codes_controller.rb +2 -2
  18. data/app/controllers/editable_pages_controller.rb +6 -5
  19. data/app/controllers/index_controller.rb +1 -1
  20. data/app/controllers/media_files_controller.rb +3 -3
  21. data/app/controllers/media_folders_controller.rb +3 -3
  22. data/app/controllers/metrics_controller.rb +1 -1
  23. data/app/controllers/my/index_controller.rb +2 -0
  24. data/app/controllers/my/profiles_controller.rb +15 -9
  25. data/app/controllers/privilege_groups_controller.rb +2 -2
  26. data/app/controllers/privileges_controller.rb +3 -3
  27. data/app/controllers/stored_values_controller.rb +2 -2
  28. data/app/controllers/tokens_controller.rb +2 -2
  29. data/app/controllers/users_controller.rb +26 -10
  30. data/app/helpers/biovision_helper.rb +13 -2
  31. data/app/helpers/biovision_users_helper.rb +20 -5
  32. data/app/helpers/codes_helper.rb +1 -1
  33. data/app/helpers/editable_pages_helper.rb +1 -1
  34. data/app/helpers/languages_helper.rb +18 -0
  35. data/app/helpers/media_helper.rb +2 -2
  36. data/app/helpers/privileges_helper.rb +2 -2
  37. data/app/helpers/stored_values_helper.rb +1 -1
  38. data/app/helpers/tracking_helper.rb +2 -2
  39. data/app/models/editable_page.rb +10 -1
  40. data/app/models/user.rb +17 -23
  41. data/app/services/user_manager.rb +15 -18
  42. data/app/services/user_profile_handler.rb +28 -0
  43. data/app/uploaders/avatar_uploader.rb +1 -5
  44. data/app/uploaders/editable_page_image_uploader.rb +1 -1
  45. data/app/views/admin/agents/entity/_in_list.html.erb +3 -3
  46. data/app/views/admin/agents/show.html.erb +10 -2
  47. data/app/views/admin/browsers/entity/_in_list.html.erb +3 -3
  48. data/app/views/admin/browsers/show.html.erb +2 -2
  49. data/app/views/admin/codes/entity/_in_list.html.erb +1 -1
  50. data/app/views/admin/codes/show.html.erb +1 -1
  51. data/app/views/admin/editable_pages/entity/_in_list.html.erb +7 -1
  52. data/app/views/admin/editable_pages/show.html.erb +26 -19
  53. data/app/views/admin/feedback_requests/entity/_in_list.html.erb +1 -1
  54. data/app/views/admin/index/_biovision_base.html.erb +1 -0
  55. data/app/views/admin/media_files/entity/_in_list.html.erb +1 -1
  56. data/app/views/admin/media_files/show.html.erb +2 -2
  57. data/app/views/admin/media_folders/entity/_in_list.html.erb +2 -2
  58. data/app/views/admin/media_folders/files.html.erb +1 -1
  59. data/app/views/admin/media_folders/show.html.erb +6 -4
  60. data/app/views/admin/metrics/_list.html.erb +2 -2
  61. data/app/views/admin/metrics/show.html.erb +2 -2
  62. data/app/views/admin/privilege_groups/entity/_in_list.html.erb +1 -1
  63. data/app/views/admin/privilege_groups/show.html.erb +1 -1
  64. data/app/views/admin/privileges/entity/_in_list.html.erb +4 -4
  65. data/app/views/admin/privileges/show.html.erb +4 -4
  66. data/app/views/admin/privileges/users.html.erb +1 -1
  67. data/app/views/admin/stored_values/entity/_in_list.html.erb +1 -1
  68. data/app/views/admin/stored_values/show.html.erb +1 -1
  69. data/app/views/admin/tokens/entity/_in_list.html.erb +2 -2
  70. data/app/views/admin/tokens/show.html.erb +2 -2
  71. data/app/views/admin/users/codes.html.erb +1 -1
  72. data/app/views/admin/users/entity/_in_list.html.erb +3 -2
  73. data/app/views/admin/users/entity/_privilege.html.erb +1 -1
  74. data/app/views/admin/users/entity/_profile.html.erb +17 -0
  75. data/app/views/admin/users/privileges.html.erb +1 -1
  76. data/app/views/admin/users/search.jbuilder +2 -2
  77. data/app/views/admin/users/show.html.erb +34 -49
  78. data/app/views/admin/users/tokens.html.erb +1 -1
  79. data/app/views/agents/_agent.jbuilder +1 -1
  80. data/app/views/agents/edit.html.erb +1 -1
  81. data/app/views/authentication/_form.html.erb +1 -1
  82. data/app/views/authentication/create.jbuilder +10 -0
  83. data/app/views/browsers/edit.html.erb +1 -1
  84. data/app/views/codes/edit.html.erb +1 -1
  85. data/app/views/editable_pages/_form.html.erb +116 -61
  86. data/app/views/editable_pages/edit.html.erb +1 -1
  87. data/app/views/index/index.html.erb +8 -6
  88. data/app/views/index/index/_custom_dashboard.html.erb +0 -0
  89. data/app/views/index/index/_default_dashboard.html.erb +2 -0
  90. data/app/views/index/index/_editable.html.erb +9 -0
  91. data/app/views/layouts/admin/_header.html.erb +1 -1
  92. data/app/views/layouts/application/_header.html.erb +1 -1
  93. data/app/views/layouts/application/header/authentication/_links.html.erb +3 -3
  94. data/app/views/layouts/application/header/authentication/_plate.html.erb +1 -1
  95. data/app/views/layouts/profile.html.erb +23 -0
  96. data/app/views/layouts/profile/_footer.html.erb +11 -0
  97. data/app/views/layouts/profile/_header.html.erb +9 -0
  98. data/app/views/layouts/profile/header/_navigation.html.erb +0 -0
  99. data/app/views/media_files/edit.html.erb +1 -1
  100. data/app/views/media_folders/_form.html.erb +0 -2
  101. data/app/views/media_folders/edit.html.erb +1 -1
  102. data/app/views/media_folders/new.html.erb +1 -1
  103. data/app/views/metrics/edit.html.erb +2 -2
  104. data/app/views/my/index/index.html.erb +9 -14
  105. data/app/views/my/index/index/_dashboard.html.erb +12 -0
  106. data/app/views/my/index/index/_sidebar.html.erb +11 -0
  107. data/app/views/my/login_attempts/index.html.erb +1 -1
  108. data/app/views/my/profiles/_nav_item.html.erb +1 -1
  109. data/app/views/my/profiles/edit.js.erb +1 -0
  110. data/app/views/my/profiles/edit/_form.html.erb +130 -116
  111. data/app/views/my/profiles/edit/form/_profile_data.html.erb +53 -0
  112. data/app/views/my/profiles/new.js.erb +1 -0
  113. data/app/views/my/profiles/new/_form.html.erb +100 -53
  114. data/app/views/my/tokens/_toggleable.html.erb +1 -1
  115. data/app/views/my/tokens/index.html.erb +1 -1
  116. data/app/views/privilege_groups/edit.html.erb +1 -1
  117. data/app/views/privileges/edit.html.erb +1 -1
  118. data/app/views/profiles/_profile.html.erb +5 -6
  119. data/app/views/shared/_pagination.jbuilder +4 -0
  120. data/app/views/shared/admin/_list_with_priority.html.erb +6 -1
  121. data/app/views/shared/forms/_list_of_errors.js.erb +2 -0
  122. data/app/views/shared/forms/_wysiwyg.html.erb +11 -0
  123. data/app/views/shared/forms/errors.js.erb +5 -0
  124. data/app/views/stored_values/edit.html.erb +1 -1
  125. data/app/views/tokens/edit.html.erb +1 -1
  126. data/app/views/users/_form.html.erb +141 -83
  127. data/app/views/users/check.jbuilder +4 -0
  128. data/app/views/users/edit.html.erb +1 -1
  129. data/app/views/users/form/_profile_data.html.erb +53 -0
  130. data/app/views/users/new.html.erb +1 -1
  131. data/config/locales/common-en.yml +2 -0
  132. data/config/locales/common-ru.yml +2 -0
  133. data/config/locales/editable-pages-en.yml +5 -4
  134. data/config/locales/editable-pages-ru.yml +5 -4
  135. data/config/locales/users-en.yml +388 -0
  136. data/config/locales/users-ru.yml +8 -3
  137. data/config/routes.rb +127 -103
  138. data/db/migrate/20170302000001_create_users.rb +2 -0
  139. data/db/migrate/20170320000000_create_editable_pages.rb +1 -1
  140. data/db/migrate/20180321000000_add_profile_data_to_users.rb +31 -0
  141. data/lib/biovision/base/base_methods.rb +37 -7
  142. data/lib/biovision/base/engine.rb +1 -1
  143. data/lib/biovision/base/privilege_methods.rb +1 -1
  144. data/lib/biovision/base/version.rb +1 -1
  145. metadata +27 -6
  146. data/app/assets/stylesheets/biovision/base/buttons.scss +0 -195
  147. data/app/assets/stylesheets/biovision/base/layout.scss +0 -193
  148. data/app/views/editable_pages/form/_ckeditor.html.erb +0 -11
  149. data/db/migrate/20170302000002_create_user_profiles.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f9fa1898ab0825170025cc1c9d2c4409672fae0124dfd8eb292fa20b5d5efb0
4
- data.tar.gz: f9e2d769bd9ed60b43021af0c8f315a21ec381b2e258e650a26b638367a61005
3
+ metadata.gz: 1353161eefdcb8571b2b56a451e83333d79bf82583127c2d561e9ffdb1859953
4
+ data.tar.gz: 42f4e3dcab70faf1e77dc46ff68a2c248d7952c434eb85ee66228e5ad5092168
5
5
  SHA512:
6
- metadata.gz: 193adfd352a265199c0d5376068279a47640b8bc5c1e43f197b251e6bea7c7d3a809a0003946d2a9b693c6c37efb13c26f558e9aa094aabebb14b84ff1021f80
7
- data.tar.gz: 0c97feb7d31796b88bb95c92ac634adf37d9ac57e3aecd76797bcbb685f58fdfce60126dd4c0e489752147c38bfa142b1456ba7e1fc11bec32f0aadc61e58790
6
+ metadata.gz: c4242e909f0fdf4760ce0e131469cb8a92b976e02bb731166ace8a28b48ad30e6927c04118274374f694c2d43da3770dba23f7edccaedcd8a102a3e03375e37e
7
+ data.tar.gz: 43f83f5678b7705c21a54a548d19a0bcddca133f57d53a910b29e701d6b734e876344fd7c2a41d1186ea899f88952d8e70b190b7347d27216c3920c032ca6687
data/README.md CHANGED
@@ -68,6 +68,29 @@ Biovision::Base
68
68
  }
69
69
  ```
70
70
 
71
+ Проверка данных до отправки всей формы
72
+ --------------------------------------
73
+
74
+ Например, при регистрации нового пользователя нужно проверить, что почта или
75
+ логин не заняты. Для этого нужно сделать несколько шагов.
76
+
77
+ 1. Маршрут и ответная часть в контроллере, обрабатывающая post-запрос.
78
+ В ответе должен быть JSON с параметром `meta.valid` (boolean) и `meta.errors`
79
+ (array), где ключ для `meta.errors` — это поле, а значение — текст ошибки.
80
+
81
+ 2. Для формы нужно задать атрибут `data-check-url` с указанием на URL проверки
82
+ правильности ввода.
83
+
84
+ 3. Для элементов формы нужно задать атибут `data-check` со значением ключа,
85
+ который проверяется.
86
+
87
+ 4. Рядом с элементом нужно добавить `div` с атрибутом `data-field` и таким же
88
+ значением, а также классом `check-result-error hidden`.
89
+
90
+ Пример — [app/views/my/profiles/new/_form.html.erb](https://github.com/Biovision/biovision-base/blob/master/app/views/my/profiles/new/_form.html.erb),
91
+ [app/controllers/users_controller.rb#check](https://github.com/Biovision/biovision-base/blob/master/app/controllers/users_controller.rb#L8),
92
+ [app/views/users/check.jbuilder](https://github.com/Biovision/biovision-base/blob/master/app/views/users/check.jbuilder)
93
+
71
94
  ## Installation
72
95
  Add this line to your application's Gemfile:
73
96
 
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- document.addEventListener('DOMContentLoaded', function () {
4
- const sliding = {
3
+ Biovision.sliders = {
4
+ behavior: {
5
5
  opacity: {
6
6
  left: function (list, delay) {
7
7
  const li = list.querySelector('li:last-of-type');
@@ -24,27 +24,30 @@ document.addEventListener('DOMContentLoaded', function () {
24
24
  setTimeout(move, delay);
25
25
  }
26
26
  }
27
- };
28
-
29
- document.querySelectorAll('.biovision-slider').forEach(function (slider) {
27
+ },
28
+ initialize: function (slider) {
30
29
  const delay = slider.getAttribute('data-delay') || 125;
31
30
  const list = slider.querySelector('ul');
32
31
  let type = slider.getAttribute('data-type') || 'opacity';
33
32
 
34
- if (!sliding.hasOwnProperty(type)) {
33
+ if (!Biovision.sliders.behavior.hasOwnProperty(type)) {
35
34
  console.log('Invalid sliding type: ' + type);
36
35
  type = 'opacity';
37
36
  }
38
37
 
39
38
  const slide_right = function () {
40
- sliding[type].right(list, delay << 1);
39
+ Biovision.sliders.behavior[type].right(list, delay << 1);
41
40
  };
42
41
 
43
42
  const slide_left = function () {
44
- sliding[type].left(list, delay);
43
+ Biovision.sliders.behavior[type].left(list, delay);
45
44
  };
46
45
 
47
46
  slider.querySelector('button.prev').addEventListener('click', slide_left);
48
47
  slider.querySelector('button.next').addEventListener('click', slide_right);
49
- });
48
+ }
49
+ };
50
+
51
+ document.addEventListener('DOMContentLoaded', function () {
52
+ document.querySelectorAll('.biovision-slider').forEach(Biovision.sliders.initialize);
50
53
  });
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const Biovision = {
4
+ locale: document.querySelector('html').getAttribute('lang'),
4
5
  storage: {
5
6
  available: function (type) {
6
7
  try {
@@ -90,7 +91,7 @@ const Biovision = {
90
91
  }
91
92
  });
92
93
  request.addEventListener('error', function () {
93
- console.log(this);
94
+ console.log('AJAX error:', this);
94
95
  });
95
96
 
96
97
  request.open(method.toUpperCase(), url);
@@ -100,7 +101,7 @@ const Biovision = {
100
101
  return request;
101
102
  },
102
103
  handle_ajax_failure: function (response) {
103
- console.log(this);
104
+ console.log('AJAX failed', this);
104
105
  if (response.hasOwnProperty('responseJSON')) {
105
106
  console.log(response['responseJSON']);
106
107
  } else {
@@ -129,6 +130,102 @@ const Biovision = {
129
130
  string = string.replace(/--+/g, '-');
130
131
 
131
132
  return string;
133
+ },
134
+ ajax_delete_button: function (element) {
135
+ const messages = {
136
+ ru: 'Вы уверены?',
137
+ en: 'Are you sure?'
138
+ };
139
+ const message = messages.hasOwnProperty(Biovision.locale) ? messages[Biovision.locale] : 'Are you sure?';
140
+ const url = element.getAttribute('data-url');
141
+ const request = Biovision.new_ajax_request('delete', url, function () {
142
+ element.closest('li[data-id]').remove();
143
+ });
144
+
145
+ element.addEventListener('click', function () {
146
+ element.disabled = true;
147
+
148
+ if (confirm(message)) {
149
+ request.send();
150
+ }
151
+
152
+ element.disabled = false;
153
+ });
154
+ },
155
+ entity_link_changer: function () {
156
+ const url = this.getAttribute('data-url');
157
+
158
+ if (url && !this.disabled) {
159
+ const method = this.checked ? 'put' : 'delete';
160
+
161
+ this.disabled = true;
162
+
163
+ Biovision.new_ajax_request(method, url, () => this.disabled = false).send();
164
+ }
165
+ },
166
+ instant_check: function (form) {
167
+ const url = form.getAttribute('data-check-url');
168
+
169
+ const perform_check = function () {
170
+ const element = this;
171
+
172
+ const request = Biovision.new_ajax_request('POST', url, function () {
173
+ if (this.responseText) {
174
+ const response = JSON.parse(this.responseText);
175
+
176
+ if (response.hasOwnProperty('meta')) {
177
+ if (response.meta.valid) {
178
+ form.querySelectorAll('[data-field]').forEach(function (field) {
179
+ field.innerHTML = '';
180
+ field.classList.add('hidden');
181
+ });
182
+ } else {
183
+ const key = element.getAttribute('data-check');
184
+ const container = form.querySelector('[data-field="' + key + '"]');
185
+
186
+ if (container) {
187
+ const errors = response.meta.errors;
188
+
189
+ if (errors.hasOwnProperty(key)) {
190
+ container.innerHTML = errors[key];
191
+ container.classList.remove('hidden');
192
+ } else {
193
+ container.classList.add('hidden');
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ });
200
+
201
+ request.send(new FormData(form));
202
+ };
203
+
204
+ form.querySelectorAll('[data-check]').forEach(function (element) {
205
+ element.addEventListener('blur', perform_check);
206
+ });
207
+ },
208
+ show_list_of_errors: function(entity_name, list) {
209
+ const form = document.getElementById(entity_name + '-form');
210
+ if (form) {
211
+ let errors = form.querySelector('ol.errors');
212
+ let data = '';
213
+
214
+ if (!errors) {
215
+ errors = document.createElement('ol');
216
+ errors.classList.add('errors');
217
+ }
218
+
219
+ list.forEach(function (message) {
220
+ data += '<li>' + message + '</li>';
221
+ });
222
+
223
+ errors.innerHTML = data;
224
+
225
+ form.prepend(errors);
226
+
227
+ errors.scrollIntoView();
228
+ }
132
229
  }
133
230
  };
134
231
 
@@ -312,6 +409,10 @@ document.addEventListener('DOMContentLoaded', function () {
312
409
  });
313
410
  });
314
411
 
412
+ document.querySelectorAll('.entity-links input[type=checkbox]').forEach(function (element) {
413
+ element.addEventListener('click', Biovision.entity_link_changer);
414
+ });
415
+
315
416
  // Кнопка удаления элемента через AJAX
316
417
  document.querySelectorAll('div[data-destroy-url] button.destroy').forEach(function (element) {
317
418
  element.addEventListener('click', function () {
@@ -326,6 +427,8 @@ document.addEventListener('DOMContentLoaded', function () {
326
427
  });
327
428
  });
328
429
 
430
+ document.querySelectorAll('button.destroy[data-url]').forEach(Biovision.ajax_delete_button);
431
+
329
432
  document.querySelectorAll('[data-transliterate]').forEach(function (element) {
330
433
  element.addEventListener('blur', function () {
331
434
  const target = document.getElementById(element.getAttribute('data-transliterate'));
@@ -349,6 +452,8 @@ document.addEventListener('DOMContentLoaded', function () {
349
452
  });
350
453
  });
351
454
 
455
+ document.querySelectorAll('form[data-check-url]').forEach(Biovision.instant_check);
456
+
352
457
  if (typeof jQuery !== 'undefined') {
353
458
  jQuery.ajaxSetup({
354
459
  headers: {
@@ -411,6 +516,70 @@ if (!Element.prototype.closest) {
411
516
  };
412
517
  }
413
518
 
519
+ /**
520
+ * ParentNode.prepend()
521
+ *
522
+ * IE
523
+ *
524
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/prepend
525
+ * @see https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/prepend()/prepend().md
526
+ */
527
+ (function (arr) {
528
+ arr.forEach(function (item) {
529
+ if (item.hasOwnProperty('prepend')) {
530
+ return;
531
+ }
532
+ Object.defineProperty(item, 'prepend', {
533
+ configurable: true,
534
+ enumerable: true,
535
+ writable: true,
536
+ value: function prepend() {
537
+ let argArr = Array.prototype.slice.call(arguments),
538
+ docFrag = document.createDocumentFragment();
539
+
540
+ argArr.forEach(function (argItem) {
541
+ let isNode = argItem instanceof Node;
542
+ docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
543
+ });
544
+
545
+ this.insertBefore(docFrag, this.firstChild);
546
+ }
547
+ });
548
+ });
549
+ })([Element.prototype, Document.prototype, DocumentFragment.prototype]);
550
+
551
+ /**
552
+ * ParentNode.append()
553
+ *
554
+ * IE 9+
555
+ *
556
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append
557
+ * @see https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/append()/append().md
558
+ */
559
+ (function (arr) {
560
+ arr.forEach(function (item) {
561
+ if (item.hasOwnProperty('append')) {
562
+ return;
563
+ }
564
+ Object.defineProperty(item, 'append', {
565
+ configurable: true,
566
+ enumerable: true,
567
+ writable: true,
568
+ value: function append() {
569
+ let argArr = Array.prototype.slice.call(arguments),
570
+ docFrag = document.createDocumentFragment();
571
+
572
+ argArr.forEach(function (argItem) {
573
+ let isNode = argItem instanceof Node;
574
+ docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
575
+ });
576
+
577
+ this.appendChild(docFrag);
578
+ }
579
+ });
580
+ });
581
+ })([Element.prototype, Document.prototype, DocumentFragment.prototype]);
582
+
414
583
  /**
415
584
  * ChildNode.remove()
416
585
  *
@@ -435,3 +604,19 @@ if (!Element.prototype.closest) {
435
604
  });
436
605
  });
437
606
  })([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
607
+
608
+ /**
609
+ * NodeList.forEach()
610
+ *
611
+ * ES5
612
+ *
613
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
614
+ */
615
+ if (window.NodeList && !NodeList.prototype.forEach) {
616
+ NodeList.prototype.forEach = function (callback, thisArg) {
617
+ thisArg = thisArg || window;
618
+ for (let i = 0; i < this.length; i++) {
619
+ callback.call(thisArg, this[i], i, this);
620
+ }
621
+ };
622
+ }
@@ -1,39 +1,17 @@
1
- * {
2
- box-sizing: border-box;
1
+ :root {
2
+ --content-width: #{$content-width};
3
+ --content-width-min: #{$content-width-min};
3
4
  }
4
5
 
5
6
  html {
6
- background-attachment: fixed;
7
+ background: linear-gradient(to bottom, #dedfe3 2%, #aeb3b9 95%) fixed, radial-gradient(farthest-corner at 33% 100%, rgba(255, 255, 255, .5) 0%, rgba(0, 0, 0, .5) 100%) fixed;
7
8
  background-blend-mode: screen;
8
- background-image: linear-gradient(to bottom, #dedfe3 2%, #aeb3b9 95%), radial-gradient(farthest-corner at 33% 100%, rgba(255, 255, 255, .5) 0%, rgba(0, 0, 0, .5) 100%);
9
9
  font: 300 10px $font-family-main;
10
- margin: 0;
11
- padding: 0;
12
- -moz-text-size-adjust: none;
13
- -ms-text-size-adjust: none;
14
- -webkit-text-size-adjust: none;
15
10
  }
16
11
 
17
12
  a:link,
18
13
  a:visited {
19
- color: $link-color;
20
14
  font-weight: 400;
21
- text-decoration: none;
22
- }
23
-
24
- a:hover {
25
- color: $link-color-hover;
26
- }
27
-
28
- img {
29
- max-width: 100%;
30
- }
31
-
32
- h1, h2, h3, h4, h5, h6 {
33
- color: $text-color-heading;
34
- font-family: $font-family-heading;
35
- font-weight: 500;
36
- margin: 0;
37
15
  }
38
16
 
39
17
  h1 {
@@ -53,8 +31,9 @@ body {
53
31
  flex-direction: column;
54
32
  font-size: $font-size-normal;
55
33
  margin: 0 auto;
56
- max-width: $content-width;
34
+ max-width: var(--content-width);
57
35
  min-height: 100vh;
36
+ min-width: var(--content-width-min);
58
37
 
59
38
  > header {
60
39
  align-items: center;
@@ -79,14 +58,9 @@ body {
79
58
  li {
80
59
  display: inline-block;
81
60
  list-style: none;
82
- margin: 0 .25rem;
61
+ margin: 0 .4rem;
83
62
  text-align: center;
84
63
  }
85
-
86
- a:link,
87
- a:visited {
88
- @include button-nav;
89
- }
90
64
  }
91
65
  }
92
66
 
@@ -100,7 +74,6 @@ body {
100
74
  font-size: $font-size-decreased;
101
75
  justify-content: space-between;
102
76
  margin: auto 0 0 0;
103
- max-width: $content-width;
104
77
  padding: .8rem;
105
78
  }
106
79
  }
@@ -111,15 +84,15 @@ body {
111
84
  }
112
85
 
113
86
  article {
114
- position: relative;
115
-
116
87
  figure {
117
- margin: 0;
88
+ max-width: 100%;
118
89
 
119
90
  &.preview {
91
+ max-width: 32rem;
92
+
120
93
  img {
121
94
  box-shadow: $block-shadow;
122
- max-width: 32rem;
95
+ max-width: 100%;
123
96
  }
124
97
  }
125
98
  }
@@ -128,7 +101,6 @@ article {
128
101
  margin: 0 0 1.6rem 0;
129
102
  padding: 0;
130
103
 
131
-
132
104
  ul {
133
105
  margin: 0;
134
106
  padding: 0;
@@ -163,7 +135,7 @@ article {
163
135
  min-width: 1ch;
164
136
  }
165
137
 
166
- input:not([type=checkbox]):not([type=radio]):not([size]):not([max]),
138
+ input:not([type=checkbox]):not([type=radio]):not([size]):not([type=date]):not([max]),
167
139
  textarea {
168
140
  width: 100%;
169
141
  }
@@ -185,6 +157,42 @@ article {
185
157
  }
186
158
  }
187
159
 
160
+ .dashboard {
161
+ nav {
162
+ margin: .4rem 0 1.6rem;
163
+ max-width: 64rem;
164
+ }
165
+
166
+ .heading {
167
+ display: block;
168
+ font: 500 1.8rem/1.5 $font-family-heading;
169
+ }
170
+
171
+ ul {
172
+ box-shadow: $block-shadow;
173
+ margin: .4rem;
174
+ padding: 0;
175
+ }
176
+
177
+ li {
178
+ background: $row-background-odd;
179
+ list-style: none;
180
+ margin: 0;
181
+ padding: .8rem;
182
+ position: relative;
183
+
184
+ &:nth-last-of-type(even) {
185
+ background: $row-background-even;
186
+ }
187
+ }
188
+
189
+ .description {
190
+ color: $text-color-secondary;
191
+ font-size: $font-size-decreased;
192
+ }
193
+ }
194
+
195
+
188
196
  nav.admin-breadcrumbs {
189
197
  margin-bottom: .8rem;
190
198
  padding: .4rem;
@@ -213,3 +221,39 @@ nav.admin-breadcrumbs {
213
221
  max-width: 8rem;
214
222
  }
215
223
  }
224
+
225
+ .entity-links {
226
+ margin: 0;
227
+ padding: 0;
228
+
229
+ li {
230
+ list-style: none;
231
+ margin: 0;
232
+ padding: .4rem;
233
+ position: relative;
234
+ }
235
+
236
+ label {
237
+ cursor: pointer;
238
+ display: inline-block;
239
+ padding: .2rem 1.6rem;
240
+ transition: .125s;
241
+ }
242
+
243
+ input[type=checkbox] {
244
+ &:not(:checked) + label {
245
+ background: #fafafa;
246
+ color: $text-color-secondary;
247
+ }
248
+
249
+ &:checked + label {
250
+ background: rgb(200, 255, 200);
251
+ box-shadow: 0 0 .3rem .1rem rgba(0, 127, 0, .25);
252
+ }
253
+
254
+ &:disabled + label {
255
+ opacity: .5;
256
+ filter: grayscale(75%);
257
+ }
258
+ }
259
+ }