katalyst-content 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/controllers/content/editor/container_controller.js +38 -6
  3. data/app/assets/javascripts/controllers/content/editor/list_controller.js +6 -5
  4. data/app/assets/javascripts/controllers/content/editor/trix_controller.js +88 -0
  5. data/app/assets/javascripts/utils/content/editor/item.js +29 -24
  6. data/app/assets/javascripts/utils/content/editor/rules-engine.js +74 -31
  7. data/app/assets/stylesheets/katalyst/content/editor/_figure.scss +12 -0
  8. data/app/assets/stylesheets/katalyst/content/editor/_index.scss +7 -1
  9. data/app/assets/stylesheets/katalyst/content/editor/_item-actions.scss +24 -6
  10. data/app/assets/stylesheets/katalyst/content/editor/_new-items.scss +22 -1
  11. data/app/assets/stylesheets/katalyst/content/editor/_status-bar.scss +10 -0
  12. data/app/assets/stylesheets/katalyst/content/editor/_trix-rails.scss +4 -4
  13. data/app/controllers/katalyst/content/direct_uploads_controller.rb +8 -0
  14. data/app/controllers/katalyst/content/items_controller.rb +5 -5
  15. data/app/helpers/katalyst/content/editor/base.rb +1 -0
  16. data/app/helpers/katalyst/content/editor/container.rb +6 -4
  17. data/app/helpers/katalyst/content/editor/errors.rb +24 -0
  18. data/app/helpers/katalyst/content/editor/status_bar.rb +12 -3
  19. data/app/helpers/katalyst/content/editor_helper.rb +26 -0
  20. data/app/helpers/katalyst/content/frontend_helper.rb +59 -0
  21. data/app/models/concerns/katalyst/content/container.rb +38 -6
  22. data/app/models/concerns/katalyst/content/version.rb +14 -4
  23. data/app/{helpers/katalyst/content/application_helper.rb → models/katalyst/content/aside.rb} +1 -1
  24. data/app/models/katalyst/content/column.rb +8 -0
  25. data/app/models/katalyst/content/content.rb +4 -0
  26. data/app/models/katalyst/content/figure.rb +41 -0
  27. data/app/models/katalyst/content/group.rb +8 -0
  28. data/app/models/katalyst/content/item.rb +17 -1
  29. data/app/models/katalyst/content/layout.rb +8 -0
  30. data/app/models/katalyst/content/section.rb +8 -0
  31. data/app/views/active_storage/blobs/_blob.html.erb +1 -1
  32. data/app/views/katalyst/content/asides/_aside.html+form.erb +27 -0
  33. data/app/views/katalyst/content/asides/_aside.html.erb +14 -0
  34. data/app/views/katalyst/content/columns/_column.html+form.erb +27 -0
  35. data/app/views/katalyst/content/columns/_column.html.erb +14 -0
  36. data/app/views/katalyst/content/contents/_content.html+form.erb +3 -10
  37. data/app/views/katalyst/content/contents/_content.html.erb +3 -3
  38. data/app/views/katalyst/content/editor/_list_item.html.erb +1 -0
  39. data/app/views/katalyst/content/figures/_figure.html+form.erb +32 -0
  40. data/app/views/katalyst/content/figures/_figure.html.erb +4 -0
  41. data/app/views/katalyst/content/groups/_group.html+form.erb +27 -0
  42. data/app/views/katalyst/content/groups/_group.html.erb +7 -0
  43. data/app/views/katalyst/content/items/_form_errors.html.erb +5 -0
  44. data/app/views/katalyst/content/items/_hidden_fields.html.erb +3 -0
  45. data/app/views/katalyst/content/items/_item.html+form.erb +2 -9
  46. data/app/views/katalyst/content/items/_item.html.erb +3 -3
  47. data/app/views/katalyst/content/sections/_section.html+form.erb +27 -0
  48. data/app/views/katalyst/content/sections/_section.html.erb +7 -0
  49. data/config/locales/en.yml +15 -0
  50. data/config/routes.rb +1 -0
  51. data/db/migrate/20220926061535_add_fields_for_figure_to_katalyst_content_items.rb +7 -0
  52. data/lib/katalyst/content/config.rb +7 -0
  53. data/lib/katalyst/content/version.rb +1 -1
  54. data/spec/factories/katalyst/content/items.rb +30 -4
  55. metadata +41 -4
@@ -10,6 +10,7 @@
10
10
  flex-direction: column;
11
11
  justify-content: center;
12
12
  align-items: center;
13
+ text-align: center;
13
14
  transform: translate3d(0, 0, 0);
14
15
  cursor: grab;
15
16
  background: white;
@@ -29,7 +30,27 @@
29
30
  }
30
31
 
31
32
  &[data-item-type="content"]:before {
32
- background-image: url("data:image/svg+xml,%3Csvg width='49' height='49' viewBox='0 0 49 49' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.9 0C2.28667 0 0 2.28667 0 4.9C0 6.86 1.30667 8.82008 3.26667 9.47341V39.5266C1.30667 40.1799 0 42.14 0 44.1C0 46.7133 2.28667 49 4.9 49C6.86 49 8.82 47.6933 9.47333 45.7333H39.5267C40.18 47.6933 42.14 49 44.1 49C46.7133 49 49 46.7133 49 44.1C49 42.14 47.6933 40.1799 45.7333 39.5266V9.47341C47.6933 8.82008 49 6.86 49 4.9C49 2.28667 46.7133 0 44.1 0C42.14 0 40.18 1.30667 39.5267 3.26667H9.47333C8.82 1.30667 7.18667 0 4.9 0ZM4.9 3.26667C5.88 3.26667 6.53333 3.92 6.53333 4.9C6.53333 5.88 5.88 6.53333 4.9 6.53333C3.92 6.53333 3.26667 5.88 3.26667 4.9C3.26667 3.92 3.92 3.26667 4.9 3.26667ZM44.1 3.26667C45.08 3.26667 45.7333 3.92 45.7333 4.9C45.7333 5.88 45.08 6.53333 44.1 6.53333C43.12 6.53333 42.4667 5.88 42.4667 4.9C42.4667 3.92 43.12 3.26667 44.1 3.26667ZM9.47333 6.53333H39.5267C40.18 7.84 41.16 9.14675 42.4667 9.47341V39.5266C41.16 40.1799 39.8533 41.16 39.5267 42.4667H9.47333C8.82 41.16 7.84 39.8533 6.53333 39.5266V9.47341C7.84 8.82008 8.82 7.84 9.47333 6.53333ZM4.9 42.4667C5.88 42.4667 6.53333 43.12 6.53333 44.1C6.53333 45.08 5.88 45.7333 4.9 45.7333C3.92 45.7333 3.26667 45.08 3.26667 44.1C3.26667 43.12 3.92 42.4667 4.9 42.4667ZM44.1 42.4667C45.08 42.4667 45.7333 43.12 45.7333 44.1C45.7333 45.08 45.08 45.7333 44.1 45.7333C43.12 45.7333 42.4667 45.08 42.4667 44.1C42.4667 43.12 43.12 42.4667 44.1 42.4667Z' /%3E%3Cpath d='M13 19.1667V11H35.8667V19.1667H32.6V14.2667H26.0667V33.8667H29.3333V37.1333H19.5333V33.8667H22.8V14.2667H16.2667V19.1667H13Z' /%3E%3C/svg%3E");
33
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 49 49' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.9 0C2.28667 0 0 2.28667 0 4.9C0 6.86 1.30667 8.82008 3.26667 9.47341V39.5266C1.30667 40.1799 0 42.14 0 44.1C0 46.7133 2.28667 49 4.9 49C6.86 49 8.82 47.6933 9.47333 45.7333H39.5267C40.18 47.6933 42.14 49 44.1 49C46.7133 49 49 46.7133 49 44.1C49 42.14 47.6933 40.1799 45.7333 39.5266V9.47341C47.6933 8.82008 49 6.86 49 4.9C49 2.28667 46.7133 0 44.1 0C42.14 0 40.18 1.30667 39.5267 3.26667H9.47333C8.82 1.30667 7.18667 0 4.9 0ZM4.9 3.26667C5.88 3.26667 6.53333 3.92 6.53333 4.9C6.53333 5.88 5.88 6.53333 4.9 6.53333C3.92 6.53333 3.26667 5.88 3.26667 4.9C3.26667 3.92 3.92 3.26667 4.9 3.26667ZM44.1 3.26667C45.08 3.26667 45.7333 3.92 45.7333 4.9C45.7333 5.88 45.08 6.53333 44.1 6.53333C43.12 6.53333 42.4667 5.88 42.4667 4.9C42.4667 3.92 43.12 3.26667 44.1 3.26667ZM9.47333 6.53333H39.5267C40.18 7.84 41.16 9.14675 42.4667 9.47341V39.5266C41.16 40.1799 39.8533 41.16 39.5267 42.4667H9.47333C8.82 41.16 7.84 39.8533 6.53333 39.5266V9.47341C7.84 8.82008 8.82 7.84 9.47333 6.53333ZM4.9 42.4667C5.88 42.4667 6.53333 43.12 6.53333 44.1C6.53333 45.08 5.88 45.7333 4.9 45.7333C3.92 45.7333 3.26667 45.08 3.26667 44.1C3.26667 43.12 3.92 42.4667 4.9 42.4667ZM44.1 42.4667C45.08 42.4667 45.7333 43.12 45.7333 44.1C45.7333 45.08 45.08 45.7333 44.1 45.7333C43.12 45.7333 42.4667 45.08 42.4667 44.1C42.4667 43.12 43.12 42.4667 44.1 42.4667Z' /%3E%3Cpath d='M13 19.1667V11H35.8667V19.1667H32.6V14.2667H26.0667V33.8667H29.3333V37.1333H19.5333V33.8667H22.8V14.2667H16.2667V19.1667H13Z' /%3E%3C/svg%3E");
34
+ }
35
+
36
+ &[data-item-type="figure"]:before {
37
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H56C60.4183 0 64 3.8205 64 8.53333V55.4667C64 60.1795 60.4183 64 56 64H8C3.58172 64 0 60.1795 0 55.4667V8.53333C0 3.8205 3.58172 0 8 0ZM48.8131 18.4523C48.8131 20.9113 46.9782 22.9045 44.7145 22.9045C42.4507 22.9045 40.6158 20.9113 40.6158 18.4523C40.6158 15.9934 42.4507 14 44.7145 14C46.9782 14 48.8131 15.9934 48.8131 18.4523ZM9.91404 49.8654H33.37L45.2139 50L55.2315 49.8938C56.6969 49.8783 57.5059 48.1335 56.6514 46.8391L46.4012 31.3112C45.6298 30.1427 44.0089 30.1621 43.3268 31.3485L38.8194 39.1885C34.5783 32.1588 29.6634 24.1159 27.1454 20.0031C26.391 18.7709 24.5821 18.7994 23.8591 20.0499L8.25556 47.0321C7.52586 48.2939 8.44576 49.8654 9.91404 49.8654Z' fill='black'/%3E%3C/svg%3E");
38
+ }
39
+
40
+ &[data-item-type="section"]:before {
41
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' fill='black' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M61.4263 64H58.8525C57.4799 64 56.2788 62.8021 56.2788 61.4332C56.2788 60.0642 57.4799 58.8663 58.8525 58.8663C58.8525 57.4973 60.0536 56.2995 61.4263 56.2995C62.7989 56.2995 64 57.4973 64 58.8663V61.4332C64 62.8021 62.9705 64 61.4263 64Z'/%3E%3Cpath d='M49.244 64H44.4397C43.067 64 41.866 62.8021 41.866 61.4332C41.866 60.0642 43.067 58.8663 44.4397 58.8663H49.244C50.6166 58.8663 51.8177 60.0642 51.8177 61.4332C51.8177 62.8021 50.6166 64 49.244 64ZM34.4879 64H29.6836C28.311 64 27.1099 62.8021 27.1099 61.4332C27.1099 60.0642 28.311 58.8663 29.6836 58.8663H34.4879C35.8606 58.8663 37.0617 60.0642 37.0617 61.4332C37.0617 62.8021 35.8606 64 34.4879 64ZM19.9035 64H14.9276C13.555 64 12.3539 62.8021 12.3539 61.4332C12.3539 60.0642 13.555 58.8663 14.9276 58.8663H19.7319C21.1046 58.8663 22.3056 60.0642 22.3056 61.4332C22.3056 62.8021 21.2761 64 19.9035 64Z'/%3E%3Cpath d='M5.14745 64H2.57372C1.20106 64 0 62.8021 0 61.4332V58.8663C0 57.4973 1.20106 56.2995 2.57372 56.2995C3.94637 56.2995 5.14745 57.4973 5.14745 58.8663C6.5201 58.8663 7.72117 60.0642 7.72117 61.4332C7.72117 62.8021 6.69168 64 5.14745 64Z'/%3E%3Cpath d='M2.57372 51.6791C1.20106 51.6791 0 50.4813 0 49.1123V44.3209C0 42.9519 1.20106 41.754 2.57372 41.754C3.94637 41.754 5.14745 42.9519 5.14745 44.3209V49.1123C5.14745 50.4813 4.11795 51.6791 2.57372 51.6791ZM2.57372 36.9626C1.20106 36.9626 0 35.7647 0 34.3957V29.6043C0 28.2353 1.20106 27.0375 2.57372 27.0375C3.94637 27.0375 5.14745 28.2353 5.14745 29.6043V34.3957C5.14745 35.9358 4.11795 36.9626 2.57372 36.9626ZM2.57372 22.4171C1.20106 22.4171 0 21.2193 0 19.8503V14.8877C0 13.5187 1.20106 12.3209 2.57372 12.3209C3.94637 12.3209 5.14745 13.5187 5.14745 14.8877V19.6792C5.14745 21.2193 4.11795 22.4171 2.57372 22.4171Z'/%3E%3Cpath d='M2.57372 7.70053C1.20106 7.70053 0 6.50267 0 5.13369V2.56684C0 1.19786 1.20106 0 2.57372 0H5.14745C6.5201 0 7.72117 1.19786 7.72117 2.56684C7.72117 3.93582 6.5201 5.13369 5.14745 5.13369C5.14745 6.67379 4.11795 7.70053 2.57372 7.70053Z'/%3E%3Cpath d='M49.244 5.13369H44.4397C43.067 5.13369 41.866 3.93583 41.866 2.56684C41.866 1.19786 43.067 0 44.4397 0H49.244C50.6166 0 51.8177 1.19786 51.8177 2.56684C51.8177 3.93583 50.6166 5.13369 49.244 5.13369ZM34.4879 5.13369H29.6836C28.311 5.13369 27.1099 3.93583 27.1099 2.56684C27.1099 1.19786 28.311 0 29.6836 0H34.4879C35.8606 0 37.0617 1.19786 37.0617 2.56684C37.0617 3.93583 35.8606 5.13369 34.4879 5.13369ZM19.9035 5.13369H14.9276C13.555 5.13369 12.3539 3.93583 12.3539 2.56684C12.3539 1.19786 13.555 0 14.9276 0H19.7319C21.1046 0 22.3056 1.19786 22.3056 2.56684C22.3056 3.93583 21.2761 5.13369 19.9035 5.13369Z'/%3E%3Cpath d='M61.4263 7.70053C60.0536 7.70053 58.8525 6.50267 58.8525 5.13369C57.4799 5.13369 56.2788 3.93582 56.2788 2.56684C56.2788 1.19786 57.4799 0 58.8525 0H61.4263C62.7989 0 64 1.19786 64 2.56684V5.13369C64 6.67379 62.9705 7.70053 61.4263 7.70053Z'/%3E%3Cpath d='M61.4263 51.6791C60.0536 51.6791 58.8525 50.4813 58.8525 49.1123V44.3209C58.8525 42.9519 60.0536 41.754 61.4263 41.754C62.7989 41.754 64 42.9519 64 44.3209V49.1123C64 50.4813 62.9705 51.6791 61.4263 51.6791ZM61.4263 36.9626C60.0536 36.9626 58.8525 35.7647 58.8525 34.3957V29.6043C58.8525 28.2353 60.0536 27.0375 61.4263 27.0375C62.7989 27.0375 64 28.2353 64 29.6043V34.3957C64 35.9358 62.9705 36.9626 61.4263 36.9626ZM61.4263 22.4171C60.0536 22.4171 58.8525 21.2193 58.8525 19.8503V14.8877C58.8525 13.5187 60.0536 12.3209 61.4263 12.3209C62.7989 12.3209 64 13.5187 64 14.8877V19.6792C64 21.2193 62.9705 22.4171 61.4263 22.4171Z'/%3E%3Cpath d='M35.5982 38.4425C35.5982 37.7506 35.4524 37.1641 35.1609 36.6828C34.8693 36.2015 34.3465 35.7654 33.5925 35.3743C32.8385 34.9833 31.7678 34.5872 30.3804 34.1861C29.2946 33.8753 28.3143 33.5244 27.4397 33.1333C26.5751 32.7323 25.8311 32.2761 25.2078 31.7647C24.5845 31.2533 24.1069 30.6668 23.7751 30.005C23.4434 29.3432 23.2775 28.5862 23.2775 27.7339C23.2775 26.5909 23.5841 25.5732 24.1974 24.6808C24.8207 23.7784 25.6904 23.0715 26.8063 22.5601C27.9223 22.0388 29.2292 21.7781 30.7272 21.7781C32.3861 21.7781 33.7936 22.0939 34.9497 22.7256C36.1059 23.3472 36.9856 24.1644 37.5888 25.1771C38.192 26.1798 38.4936 27.2527 38.4936 28.3957H35.553C35.553 27.5735 35.377 26.8416 35.0251 26.1999C34.6833 25.5581 34.1555 25.0568 33.4417 24.6958C32.7279 24.3249 31.8231 24.1394 30.7272 24.1394C29.7017 24.1394 28.8522 24.2948 28.1786 24.6056C27.5151 24.9164 27.0225 25.3376 26.7007 25.869C26.379 26.4004 26.2182 27.007 26.2182 27.6888C26.2182 28.3005 26.3941 28.8469 26.746 29.3282C27.0979 29.7994 27.6508 30.2256 28.4048 30.6066C29.1589 30.9876 30.1341 31.3486 31.3304 31.6895C32.9893 32.1507 34.3515 32.6871 35.4172 33.2988C36.4829 33.9104 37.2671 34.6323 37.7698 35.4646C38.2825 36.2968 38.5389 37.2794 38.5389 38.4124C38.5389 39.5956 38.2222 40.6283 37.5888 41.5107C36.9554 42.393 36.0657 43.0748 34.9196 43.5561C33.7735 44.0374 32.4263 44.278 30.878 44.278C29.8626 44.278 28.8623 44.1377 27.877 43.8569C26.9018 43.5762 26.0121 43.1551 25.2078 42.5936C24.4135 42.0321 23.7751 41.3402 23.2926 40.518C22.82 39.6858 22.5838 38.7232 22.5838 37.6303H25.5094C25.5094 38.3823 25.6552 39.0291 25.9467 39.5705C26.2383 40.1119 26.6354 40.5581 27.1381 40.9091C27.6408 41.26 28.2138 41.5207 28.8572 41.6912C29.5007 41.8516 30.1743 41.9318 30.878 41.9318C31.8934 41.9318 32.748 41.7914 33.4417 41.5107C34.1454 41.2199 34.6783 40.8138 35.0402 40.2924C35.4122 39.771 35.5982 39.1544 35.5982 38.4425Z'/%3E%3C/svg%3E%0A");
42
+ }
43
+
44
+ &[data-item-type="group"]:before {
45
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' fill='black' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M61.4263 64H58.8525C57.4799 64 56.2788 62.8021 56.2788 61.4332C56.2788 60.0642 57.4799 58.8663 58.8525 58.8663C58.8525 57.4973 60.0536 56.2995 61.4263 56.2995C62.7989 56.2995 64 57.4973 64 58.8663V61.4332C64 62.8021 62.9705 64 61.4263 64Z' /%3E%3Cpath d='M49.244 64H44.4397C43.067 64 41.866 62.8021 41.866 61.4332C41.866 60.0642 43.067 58.8663 44.4397 58.8663H49.244C50.6166 58.8663 51.8177 60.0642 51.8177 61.4332C51.8177 62.8021 50.6166 64 49.244 64ZM34.4879 64H29.6836C28.311 64 27.1099 62.8021 27.1099 61.4332C27.1099 60.0642 28.311 58.8663 29.6836 58.8663H34.4879C35.8606 58.8663 37.0617 60.0642 37.0617 61.4332C37.0617 62.8021 35.8606 64 34.4879 64ZM19.9035 64H14.9276C13.555 64 12.3539 62.8021 12.3539 61.4332C12.3539 60.0642 13.555 58.8663 14.9276 58.8663H19.7319C21.1046 58.8663 22.3056 60.0642 22.3056 61.4332C22.3056 62.8021 21.2761 64 19.9035 64Z' /%3E%3Cpath d='M5.14745 64H2.57372C1.20106 64 0 62.8021 0 61.4332V58.8663C0 57.4973 1.20106 56.2995 2.57372 56.2995C3.94637 56.2995 5.14745 57.4973 5.14745 58.8663C6.5201 58.8663 7.72117 60.0642 7.72117 61.4332C7.72117 62.8021 6.69168 64 5.14745 64Z' /%3E%3Cpath d='M2.57372 51.6791C1.20106 51.6791 0 50.4813 0 49.1123V44.3209C0 42.9519 1.20106 41.754 2.57372 41.754C3.94637 41.754 5.14745 42.9519 5.14745 44.3209V49.1123C5.14745 50.4813 4.11795 51.6791 2.57372 51.6791ZM2.57372 36.9626C1.20106 36.9626 0 35.7647 0 34.3957V29.6043C0 28.2353 1.20106 27.0375 2.57372 27.0375C3.94637 27.0375 5.14745 28.2353 5.14745 29.6043V34.3957C5.14745 35.9358 4.11795 36.9626 2.57372 36.9626ZM2.57372 22.4171C1.20106 22.4171 0 21.2193 0 19.8503V14.8877C0 13.5187 1.20106 12.3209 2.57372 12.3209C3.94637 12.3209 5.14745 13.5187 5.14745 14.8877V19.6792C5.14745 21.2193 4.11795 22.4171 2.57372 22.4171Z' /%3E%3Cpath d='M2.57372 7.70053C1.20106 7.70053 0 6.50267 0 5.13369V2.56684C0 1.19786 1.20106 0 2.57372 0H5.14745C6.5201 0 7.72117 1.19786 7.72117 2.56684C7.72117 3.93583 6.5201 5.13369 5.14745 5.13369C5.14745 6.67379 4.11795 7.70053 2.57372 7.70053Z' /%3E%3Cpath d='M49.244 5.13369H44.4397C43.067 5.13369 41.866 3.93583 41.866 2.56684C41.866 1.19786 43.067 0 44.4397 0H49.244C50.6166 0 51.8177 1.19786 51.8177 2.56684C51.8177 3.93583 50.6166 5.13369 49.244 5.13369ZM34.4879 5.13369H29.6836C28.311 5.13369 27.1099 3.93583 27.1099 2.56684C27.1099 1.19786 28.311 0 29.6836 0H34.4879C35.8606 0 37.0617 1.19786 37.0617 2.56684C37.0617 3.93583 35.8606 5.13369 34.4879 5.13369ZM19.9035 5.13369H14.9276C13.555 5.13369 12.3539 3.93583 12.3539 2.56684C12.3539 1.19786 13.555 0 14.9276 0H19.7319C21.1046 0 22.3056 1.19786 22.3056 2.56684C22.3056 3.93583 21.2761 5.13369 19.9035 5.13369Z' /%3E%3Cpath d='M61.4263 7.70053C60.0536 7.70053 58.8525 6.50267 58.8525 5.13369C57.4799 5.13369 56.2788 3.93583 56.2788 2.56684C56.2788 1.19786 57.4799 0 58.8525 0H61.4263C62.7989 0 64 1.19786 64 2.56684V5.13369C64 6.67379 62.9705 7.70053 61.4263 7.70053Z' /%3E%3Cpath d='M61.4263 51.6791C60.0536 51.6791 58.8525 50.4813 58.8525 49.1123V44.3209C58.8525 42.9519 60.0536 41.754 61.4263 41.754C62.7989 41.754 64 42.9519 64 44.3209V49.1123C64 50.4813 62.9705 51.6791 61.4263 51.6791ZM61.4263 36.9626C60.0536 36.9626 58.8525 35.7647 58.8525 34.3957V29.6043C58.8525 28.2353 60.0536 27.0375 61.4263 27.0375C62.7989 27.0375 64 28.2353 64 29.6043V34.3957C64 35.9358 62.9705 36.9626 61.4263 36.9626ZM61.4263 22.4171C60.0536 22.4171 58.8525 21.2193 58.8525 19.8503V14.8877C58.8525 13.5187 60.0536 12.3209 61.4263 12.3209C62.7989 12.3209 64 13.5187 64 14.8877V19.6792C64 21.2193 62.9705 22.4171 61.4263 22.4171Z' /%3E%3Cpath d='M40.1374 39.3934C39.866 39.7844 39.4337 40.2306 38.8405 40.7319C38.2574 41.2232 37.443 41.6544 36.3975 42.0254C35.3619 42.3863 34.0198 42.5668 32.371 42.5668C30.5915 42.5668 29.008 42.1557 27.6206 41.3335C26.2433 40.5113 25.1625 39.3232 24.3784 37.769C23.5942 36.2149 23.2021 34.3499 23.2021 32.1741V30.4445C23.2021 28.2687 23.5439 26.4087 24.2275 24.8646C24.9112 23.3105 25.9065 22.1223 27.2135 21.3001C28.5305 20.4779 30.1341 20.0668 32.0241 20.0668C33.7031 20.0668 35.1106 20.3576 36.2467 20.9392C37.3827 21.5107 38.2674 22.3028 38.9008 23.3155C39.5442 24.3282 39.9564 25.4813 40.1374 26.7747H37.2118C37.0811 25.9826 36.8197 25.2607 36.4276 24.6089C36.0456 23.9472 35.4977 23.4208 34.7839 23.0297C34.07 22.6287 33.1552 22.4281 32.0392 22.4281C30.682 22.4281 29.566 22.754 28.6914 23.4057C27.8267 24.0474 27.1833 24.9649 26.7611 26.1581C26.3489 27.3513 26.1428 28.77 26.1428 30.4144V32.1741C26.1428 33.8586 26.4042 35.3025 26.9269 36.5057C27.4497 37.6988 28.1786 38.6163 29.1136 39.258C30.0486 39.8997 31.1394 40.2206 32.3861 40.2206C33.4216 40.2206 34.256 40.1353 34.8894 39.9649C35.5328 39.7844 36.0355 39.5738 36.3975 39.3332C36.7594 39.0825 37.0359 38.8469 37.2269 38.6263V33.6932H32.1599V31.3619H40.1374V39.3934Z' /%3E%3C/svg%3E%0A");
46
+ }
47
+
48
+ &[data-item-type="column"]:before {
49
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' fill='none' stroke='black' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='6' y='12' width='26' height='44' stroke-width='4' /%3E%3Crect x='32' y='12' width='26' height='44' stroke-width='4' /%3E%3C/svg%3E");
50
+ }
51
+
52
+ &[data-item-type="aside"]:before {
53
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' fill='none' stroke='black' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='6' y='12' width='36' height='44' stroke-width='4' /%3E%3Crect x='42' y='12' width='16' height='44' stroke-width='4' /%3E%3C/svg%3E");
33
54
  }
34
55
  }
35
56
  }
@@ -17,9 +17,11 @@
17
17
  display: none;
18
18
  grid-area: status;
19
19
  font-weight: bold;
20
+ color: var(--color);
20
21
  }
21
22
 
22
23
  &[data-state="published"] .status-text[data-published],
24
+ &[data-state="unpublished"] .status-text[data-unpublished],
23
25
  &[data-state="draft"] .status-text[data-draft],
24
26
  &[data-state="dirty"] .status-text[data-dirty] {
25
27
  display: unset;
@@ -72,6 +74,14 @@
72
74
  }
73
75
  }
74
76
 
77
+ &[data-state="unpublished"] {
78
+ [value="save"],
79
+ [value="discard"],
80
+ [value="revert"] {
81
+ display: none;
82
+ }
83
+ }
84
+
75
85
  &[data-state="draft"] {
76
86
  [value="save"],
77
87
  [value="discard"] {
@@ -13,12 +13,12 @@
13
13
  }
14
14
 
15
15
  .trix-content
16
- .attachment-gallery.attachment-gallery--2
17
- > action-text-attachment,
16
+ .attachment-gallery.attachment-gallery--2
17
+ > action-text-attachment,
18
18
  .trix-content .attachment-gallery.attachment-gallery--2 > .attachment,
19
19
  .trix-content
20
- .attachment-gallery.attachment-gallery--4
21
- > action-text-attachment,
20
+ .attachment-gallery.attachment-gallery--4
21
+ > action-text-attachment,
22
22
  .trix-content .attachment-gallery.attachment-gallery--4 > .attachment {
23
23
  flex-basis: 50%;
24
24
  max-width: 50%;
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Content
5
+ class DirectUploadsController < ActiveStorage::DirectUploadsController
6
+ end
7
+ end
8
+ end
@@ -13,8 +13,12 @@ module Katalyst
13
13
  render locals: { item: @container.items.build(item_params) }
14
14
  end
15
15
 
16
+ def edit
17
+ render locals: { item: @item }
18
+ end
19
+
16
20
  def create
17
- item = @container.items.build(item_params)
21
+ @item = item = @container.items.build(item_params)
18
22
  if item.save
19
23
  render :update, locals: { item: item, previous: @container.items.build(type: item.type) }
20
24
  else
@@ -22,10 +26,6 @@ module Katalyst
22
26
  end
23
27
  end
24
28
 
25
- def edit
26
- render locals: { item: @item }
27
- end
28
-
29
29
  def update
30
30
  @item.attributes = item_params
31
31
 
@@ -14,6 +14,7 @@ module Katalyst
14
14
 
15
15
  attr_accessor :template, :container
16
16
 
17
+ delegate :config, to: ::Katalyst::Content
17
18
  delegate_missing_to :template
18
19
 
19
20
  def initialize(template, container)
@@ -6,6 +6,7 @@ module Katalyst
6
6
  class Container < Base
7
7
  ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
8
8
  submit->#{CONTAINER_CONTROLLER}#reindex
9
+ content:drop->#{CONTAINER_CONTROLLER}#drop
9
10
  content:reindex->#{CONTAINER_CONTROLLER}#reindex
10
11
  content:reset->#{CONTAINER_CONTROLLER}#reset
11
12
  ACTIONS
@@ -13,12 +14,17 @@ module Katalyst
13
14
  def build(options)
14
15
  form_with(model: container, **default_options(id: container_form_id, **options)) do |form|
15
16
  concat hidden_input
17
+ concat errors
16
18
  concat(capture { yield form })
17
19
  end
18
20
  end
19
21
 
20
22
  private
21
23
 
24
+ def errors
25
+ Editor::Errors.new(self, container).build
26
+ end
27
+
22
28
  # Hidden input ensures that if the container is empty then the controller
23
29
  # receives an empty array.
24
30
  def hidden_input
@@ -29,10 +35,6 @@ module Katalyst
29
35
  add_option(options, :data, :controller, CONTAINER_CONTROLLER)
30
36
  add_option(options, :data, :action, ACTIONS)
31
37
 
32
- # depth = options.delete(:depth) || container.depth
33
- #
34
- # add_option(options, :data, :"#{CONTAINER_CONTROLLER}-max-depth-value", depth) if depth
35
-
36
38
  options
37
39
  end
38
40
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Content
5
+ module Editor
6
+ class Errors < Base
7
+ def build(**options)
8
+ turbo_frame_tag dom_id(container, :errors) do
9
+ next unless container.errors.any?
10
+
11
+ tag.div(class: "content-errors", **options) do
12
+ tag.h2("Errors in content") +
13
+ tag.ul(class: "errors") do
14
+ container.errors.each do |error|
15
+ concat(tag.li(error.full_message))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -11,6 +11,7 @@ module Katalyst
11
11
  def build(**options)
12
12
  tag.div **default_options(**options) do
13
13
  concat status(:published, last_update: l(container.updated_at, format: :short))
14
+ concat status(:unpublished)
14
15
  concat status(:draft)
15
16
  concat status(:dirty)
16
17
  concat actions
@@ -18,9 +19,17 @@ module Katalyst
18
19
  end
19
20
 
20
21
  def status(state, **options)
21
- tag.span(t("views.katalyst.content.editor.#{state}_html", **options),
22
- class: "status-text",
23
- data: { state => "" })
22
+ status_text = t("views.katalyst.content.editor.#{state}_html", **options)
23
+ html_options = { class: "status-text", data: { state => "", turbo: false } }
24
+
25
+ case state
26
+ when :published
27
+ link_to status_text, url_for(container), **html_options
28
+ when :unpublished, :draft
29
+ link_to status_text, "#{url_for(container)}/preview", **html_options
30
+ else
31
+ tag.span status_text, **html_options
32
+ end
24
33
  end
25
34
 
26
35
  def actions
@@ -25,6 +25,12 @@ module Katalyst
25
25
  Editor::List.new(self, container).items(item)
26
26
  end
27
27
 
28
+ # Generate a turbo stream fragment that will show structural errors to the user.
29
+ def content_editor_errors(container:, **options)
30
+ turbo_stream.replace(dom_id(container, :errors),
31
+ Editor::Errors.new(self, container).build(**options))
32
+ end
33
+
28
34
  # Gene
29
35
  def content_editor_new_item(item:, container: item.container, **options, &block)
30
36
  Editor::NewItem.new(self, container).build(item, **options, &block)
@@ -37,6 +43,26 @@ module Katalyst
37
43
  def content_editor_status_bar(container:, **options)
38
44
  Editor::StatusBar.new(self, container).build(**options)
39
45
  end
46
+
47
+ def content_editor_rich_text_options(options = {})
48
+ defaults = {
49
+ data: {
50
+ direct_upload_url: direct_uploads_url,
51
+ controller: "content--editor--trix",
52
+ action: "trix-initialize->content--editor--trix#trixInitialize",
53
+ },
54
+ }
55
+ defaults.deep_merge(options)
56
+ end
57
+
58
+ def content_editor_image_field(item:, method:, **options, &block)
59
+ Editor::ImageField.new(self, item.container).build(item, method, **options, &block)
60
+ end
61
+
62
+ # When rendering item forms do not include the controller namespace prefix (katalyst/content)
63
+ def prefix_partial_path_with_controller_namespace
64
+ false
65
+ end
40
66
  end
41
67
  end
42
68
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Content
5
+ module FrontendHelper
6
+ def render_content(version)
7
+ render partial: version.tree.select(&:visible?)
8
+ end
9
+
10
+ def render_content_items(items)
11
+ items = items.select(&:visible?)
12
+ render partial: items if items.any?
13
+ end
14
+
15
+ def content_item_tag(item, **options, &block)
16
+ FrontendBuilder.new(self, item).render(**options, &block)
17
+ end
18
+ end
19
+
20
+ class FrontendBuilder
21
+ attr_accessor :template, :item
22
+
23
+ delegate_missing_to :@template
24
+
25
+ def initialize(template, item)
26
+ self.template = template
27
+ self.item = item
28
+ end
29
+
30
+ def render(**options, &block)
31
+ content_tag tag, **default_options(**options) do
32
+ content_tag :div, &block
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def default_options(**options)
39
+ {
40
+ id: item.heading&.parameterize,
41
+ class: ["content-item", item.model_name.param_key, item.background, options[:class]],
42
+ data: { content_index: item.index, content_depth: item.depth, **options.fetch(:data, {}) },
43
+ **options.except(:class, :data, :root),
44
+ }
45
+ end
46
+
47
+ def tag
48
+ case item
49
+ when Figure
50
+ :figure
51
+ when Section
52
+ :section
53
+ else
54
+ :div
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -20,8 +20,8 @@ module Katalyst
20
20
  inverse_of: :parent,
21
21
  optional: true
22
22
 
23
- delegate :nodes, :items, :tree, to: :published_version, prefix: :published, allow_nil: true
24
- delegate :nodes, :items, :tree, to: :draft_version, prefix: :draft, allow_nil: true
23
+ delegate :nodes, :items, :tree, :text, to: :published_version, prefix: :published, allow_nil: true
24
+ delegate :nodes, :items, :tree, :text, to: :draft_version, prefix: :draft, allow_nil: true
25
25
 
26
26
  has_many :versions,
27
27
  class_name: "#{name}::Version",
@@ -46,18 +46,37 @@ module Katalyst
46
46
  class_name: "Katalyst::Content::Item",
47
47
  dependent: :destroy,
48
48
  validate: true
49
+
50
+ scope :order_by_state, ->(dir) do
51
+ dir = :asc unless %w[asc desc].include?(dir.to_s)
52
+ unpublished = arel_table[:published_version_id].eq(nil)
53
+ draft = arel_table[:published_version_id].not_eq(arel_table[:draft_version_id])
54
+ case_statement = Arel::Nodes::Case.new
55
+ .when(unpublished).then(3)
56
+ .when(draft).then(2)
57
+ .else(1)
58
+ order(case_statement.public_send(dir)).order(updated_at: dir)
59
+ end
60
+
61
+ scope :published, -> { where.not(published_version_id: nil) }
49
62
  end
50
63
 
51
64
  # A resource is in draft mode if it has an unpublished draft or it has no published version.
52
65
  # @return the current state of the resource, either `published` or `draft`
53
66
  def state
54
- if published_version_id && published_version_id == draft_version_id
55
- :published
56
- else
67
+ if !published_version_id
68
+ :unpublished
69
+ elsif published_version_id != draft_version_id
57
70
  :draft
71
+ else
72
+ :published
58
73
  end
59
74
  end
60
75
 
76
+ def published?
77
+ published_version_id.present?
78
+ end
79
+
61
80
  # Promotes the draft version to become the published version
62
81
  def publish!
63
82
  update!(published_version: draft_version)
@@ -70,6 +89,17 @@ module Katalyst
70
89
  self
71
90
  end
72
91
 
92
+ # Sets the currently published version to nil
93
+ def unpublish!
94
+ update!(published_version_id: nil)
95
+ self
96
+ end
97
+
98
+ # Required for testing items validation
99
+ def items_attributes
100
+ draft_version&.nodes&.as_json
101
+ end
102
+
73
103
  # Updates the current draft version with new structure. Attributes should be structural information about the
74
104
  # items, e.g. `{index => {id:, depth:}` or `[{id:, depth:}]`.
75
105
  #
@@ -82,7 +112,9 @@ module Katalyst
82
112
  private
83
113
 
84
114
  def unset_versions
85
- update(draft_version: nil, published_version: nil)
115
+ self.draft_version_id = nil
116
+ self.published_version_id = nil
117
+ save!(validate: false)
86
118
  end
87
119
 
88
120
  # Returns an unsaved copy of draft version for accumulating changes.
@@ -13,6 +13,12 @@ module Katalyst
13
13
  # rubocop:enable Rails/ReflectionClassName
14
14
 
15
15
  attribute :nodes, Katalyst::Content::Types::NodesType.new, default: -> { [] }
16
+
17
+ validate :ensure_items_exists
18
+ end
19
+
20
+ def ensure_items_exists
21
+ parent.errors.add(:items, :missing_item) unless items.all?(&:present?)
16
22
  end
17
23
 
18
24
  def items
@@ -22,12 +28,16 @@ module Katalyst
22
28
 
23
29
  items = parent.items.where(id: nodes.map(&:id)).index_by(&:id)
24
30
  nodes.map do |node|
25
- item = items[node.id]
26
- item.index = node.index
27
- item.depth = node.depth
28
- item
31
+ items[node.id]&.tap do |item|
32
+ item.index = node.index
33
+ item.depth = node.depth
34
+ end
29
35
  end
30
36
  end
37
+
38
+ def text
39
+ items.filter_map(&:to_plain_text).join("\n")
40
+ end
31
41
  end
32
42
  end
33
43
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Katalyst
4
4
  module Content
5
- module ApplicationHelper
5
+ class Aside < Layout
6
6
  end
7
7
  end
8
8
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Content
5
+ class Column < Layout
6
+ end
7
+ end
8
+ end
@@ -16,6 +16,10 @@ module Katalyst
16
16
  def self.permitted_params
17
17
  super + %i[content]
18
18
  end
19
+
20
+ def to_plain_text
21
+ [super, content.to_plain_text].compact.join("\n") if visible?
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_storage_validations"
4
+
5
+ module Katalyst
6
+ module Content
7
+ class Figure < Item
8
+ has_one_attached :image
9
+
10
+ validates :image,
11
+ presence: true,
12
+ content_type: config.image_mime_types,
13
+ size: { less_than: config.max_image_size.megabytes }
14
+
15
+ default_scope { with_attached_image }
16
+
17
+ def initialize_dup(source)
18
+ super
19
+
20
+ # if image has changed, duplicate the change, otherwise attach the existing blob
21
+ if source.attachment_changes["image"]
22
+ self.image = source.attachment_changes["image"].attachable
23
+ elsif source.image.attached? && !source.image.marked_for_destruction?
24
+ image.attach(source.image.blob)
25
+ end
26
+ end
27
+
28
+ def self.permitted_params
29
+ super - %i[show_heading] + %i[image caption]
30
+ end
31
+
32
+ alias_attribute :alt, :heading
33
+
34
+ def to_plain_text
35
+ text = ["Image: #{alt}"]
36
+ text << "Caption: #{caption}" if caption.present?
37
+ text.compact.join("\n") if visible?
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Content
5
+ class Group < Layout
6
+ end
7
+ end
8
+ end
@@ -4,10 +4,14 @@ module Katalyst
4
4
  module Content
5
5
  # STI base class for content items
6
6
  class Item < ApplicationRecord
7
+ def self.config
8
+ Katalyst::Content.config
9
+ end
10
+
7
11
  belongs_to :container, polymorphic: true
8
12
 
9
13
  validates :heading, presence: true
10
- validates :background, presence: true, inclusion: { in: Katalyst::Content.config.backgrounds }
14
+ validates :background, presence: true, inclusion: { in: config.backgrounds }, if: :validate_background?
11
15
 
12
16
  after_initialize :initialize_tree
13
17
 
@@ -25,12 +29,24 @@ module Katalyst
25
29
  ]
26
30
  end
27
31
 
32
+ def to_plain_text
33
+ heading if show_heading? && visible?
34
+ end
35
+
36
+ def layout?
37
+ is_a? Layout
38
+ end
39
+
28
40
  private
29
41
 
30
42
  def initialize_tree
31
43
  self.parent ||= nil
32
44
  self.children ||= []
33
45
  end
46
+
47
+ def validate_background?
48
+ true
49
+ end
34
50
  end
35
51
  end
36
52
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Content
5
+ class Layout < Item
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Katalyst
4
+ module Content
5
+ class Section < Layout
6
+ end
7
+ end
8
+ end
@@ -1,6 +1,6 @@
1
1
  <figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
2
2
  <% if blob.representable? %>
3
- <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
3
+ <%= image_tag main_app.url_for(blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ])) %>
4
4
  <% end %>
5
5
 
6
6
  <figcaption class="attachment__caption">
@@ -0,0 +1,27 @@
1
+ <%= form_with model: aside, scope: :item, url: path do |form| %>
2
+ <%= render "hidden_fields", form: form %>
3
+ <%= render "form_errors", form: form %>
4
+
5
+ <div class="field">
6
+ <%= form.label :heading %>
7
+ <%= form.text_field :heading %>
8
+ </div>
9
+
10
+ <div class="field">
11
+ <%= form.label :show_heading %>
12
+ <%= form.check_box :show_heading %>
13
+ </div>
14
+
15
+ <div class="field">
16
+ <%= form.label :background %>
17
+ <%= form.select :background, Katalyst::Content.config.backgrounds %>
18
+ </div>
19
+
20
+ <div class="field">
21
+ <%= form.label :visible %>
22
+ <%= form.check_box :visible %>
23
+ </div>
24
+
25
+ <%= form.submit "Done" %>
26
+ <%= link_to "Discard", :back %>
27
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <%= content_item_tag aside do %>
2
+ <%= tag.h3 aside.heading if aside.show_heading? %>
3
+
4
+ <% items = aside.children.select(&:visible?) %>
5
+ <% last = items.pop %>
6
+ <div role="aside-container">
7
+ <div>
8
+ <%= render_content_items items %>
9
+ </div>
10
+ <aside>
11
+ <%= render_content_items [last] %>
12
+ </aside>
13
+ </div>
14
+ <% end %>