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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15c10b4886c26310eb6a15c64f9b3c31b1b2dc312d9b4088bf530e6610ec3599
4
- data.tar.gz: 2dd1d7e5179ff4d9f53d66b8ea99cd3d19f497e078d6234da4c8525e13a25ba1
3
+ metadata.gz: 5d759a4e97d9609138eba1c1d03ad9a081cc1badb65be59b5b200a23665909e7
4
+ data.tar.gz: 848034cbe45b3fb9c0550bd452c5424cccdf5c4a7e4e9b819abaef0bed9b24a3
5
5
  SHA512:
6
- metadata.gz: 89a50df67af76c48e7978be76eee21da5100a8bf7fb69c6f580dc1868f4f644300f7d782b7cab61c2897717577e1cf4cc865a8b1f437c7d559c9b321f66b0bf0
7
- data.tar.gz: c5dbc2983e3438642f38a58351010f7b110715ed865fb5851f1c43d4e8801a8c5a0e9bc0e371f5555cad72c976a3fc53d1bbc88cb6efc260d9403f1d0751f26c
6
+ metadata.gz: 64f111753041dd647e73d863e011b23c3507cb930dcac40dd55f991d422802896cc6d515e998adf31be3a07962a38ac8b22e16490b3a56fcb3638441bd8d5d26
7
+ data.tar.gz: 24e97c6e52f38944a1947b50cb09347c3e5ebd457bcdb7bff0aff70aeac8412ed0a1ba8cfc85606d26886f30499c3981c4d4de414d2651c38d08f4104b362e79
@@ -6,9 +6,6 @@ import RulesEngine from "utils/content/editor/rules-engine";
6
6
 
7
7
  export default class ContainerController extends Controller {
8
8
  static targets = ["container"];
9
- static values = {
10
- maxDepth: Number,
11
- };
12
9
 
13
10
  connect() {
14
11
  this.state = this.container.state;
@@ -29,6 +26,36 @@ export default class ContainerController extends Controller {
29
26
  this.container.reset();
30
27
  }
31
28
 
29
+ drop(event) {
30
+ this.container.reindex(); // set indexes before calculating previous
31
+
32
+ const item = getEventItem(event);
33
+ const previous = item.previousItem;
34
+
35
+ let delta = 0;
36
+ if (previous === undefined) {
37
+ // if previous does not exist, set depth to 0
38
+ delta = -item.depth;
39
+ } else if (
40
+ previous.isLayout &&
41
+ item.nextItem &&
42
+ item.nextItem.depth > previous.depth
43
+ ) {
44
+ // if previous is a layout and next is a child of previous, make item a child of previous
45
+ delta = previous.depth - item.depth + 1;
46
+ } else {
47
+ // otherwise, make item a sibling of previous
48
+ delta = previous.depth - item.depth;
49
+ }
50
+
51
+ item.traverse((child) => {
52
+ child.depth += delta;
53
+ });
54
+
55
+ this.#update();
56
+ event.preventDefault();
57
+ }
58
+
32
59
  remove(event) {
33
60
  const item = getEventItem(event);
34
61
 
@@ -41,7 +68,9 @@ export default class ContainerController extends Controller {
41
68
  nest(event) {
42
69
  const item = getEventItem(event);
43
70
 
44
- item.nest();
71
+ item.traverse((child) => {
72
+ child.depth += 1;
73
+ });
45
74
 
46
75
  this.#update();
47
76
  event.preventDefault();
@@ -50,7 +79,9 @@ export default class ContainerController extends Controller {
50
79
  deNest(event) {
51
80
  const item = getEventItem(event);
52
81
 
53
- item.deNest();
82
+ item.traverse((child) => {
83
+ child.depth -= 1;
84
+ });
54
85
 
55
86
  this.#update();
56
87
  event.preventDefault();
@@ -84,7 +115,8 @@ export default class ContainerController extends Controller {
84
115
  if (!this.updateRequested) return;
85
116
 
86
117
  this.updateRequested = false;
87
- const engine = new RulesEngine(this.maxDepthValue);
118
+ const engine = new RulesEngine();
119
+ this.container.items.forEach((item) => engine.normalize(item));
88
120
  this.container.items.forEach((item) => engine.update(item));
89
121
 
90
122
  this.#notifyChange();
@@ -46,7 +46,7 @@ export default class ListController extends Controller {
46
46
  }
47
47
 
48
48
  drop(event) {
49
- const item = this.dragItem();
49
+ let item = this.dragItem();
50
50
 
51
51
  if (!item) return;
52
52
 
@@ -55,17 +55,18 @@ export default class ListController extends Controller {
55
55
  swap(this.dropTarget(event.target), item);
56
56
 
57
57
  if (item.dataset.hasOwnProperty("newItem")) {
58
+ const placeholder = item;
58
59
  const template = document.createElement("template");
59
60
  template.innerHTML = event.dataTransfer.getData("text/html");
60
- const newItem = template.content.querySelector("li");
61
+ item = template.content.querySelector("li");
61
62
 
62
- this.element.replaceChild(newItem, item);
63
+ this.element.replaceChild(item, placeholder);
63
64
  setTimeout(() =>
64
- newItem.querySelector("[role='button'][value='edit']").click()
65
+ item.querySelector("[role='button'][value='edit']").click()
65
66
  );
66
67
  }
67
68
 
68
- this.reindex();
69
+ this.dispatch("drop", { target: item, bubbles: true, prefix: "content" });
69
70
  }
70
71
 
71
72
  dragend() {
@@ -0,0 +1,88 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ import Trix from "trix";
3
+
4
+ // Stimulus controller doesn't do anything, but having one ensures that trix
5
+ // will be lazy loaded when a trix-editor is added to the dom.
6
+ export default class TrixController extends Controller {
7
+ trixInitialize(e) {
8
+ // noop, useful as an extension point for registering behaviour on load
9
+ }
10
+ }
11
+
12
+ // Add H4 as an acceptable tag
13
+ Trix.config.blockAttributes["heading4"] = {
14
+ tagName: "h4",
15
+ terminal: true,
16
+ breakOnReturn: true,
17
+ group: false,
18
+ };
19
+
20
+ // Remove H1 from trix list of acceptable tags
21
+ delete Trix.config.blockAttributes.heading1;
22
+
23
+ /**
24
+ * Allow users to enter path and fragment URIs which the input[type=url] browser
25
+ * input does not permit. Uses a permissive regex pattern which is not suitable
26
+ * for untrusted use cases.
27
+ */
28
+ const LINK_PATTERN = "(https?|mailto:|tel:|/|#).*?";
29
+
30
+ /**
31
+ * Customize default toolbar:
32
+ *
33
+ * * headings: h4 instead of h1
34
+ * * links: use type=text instead of type=url
35
+ *
36
+ * @returns {String} toolbar html fragment
37
+ */
38
+ Trix.config.toolbar.getDefaultHTML = () => {
39
+ const { lang } = Trix.config;
40
+ return `
41
+ <div class="trix-button-row">
42
+ <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
43
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">${lang.bold}</button>
44
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
45
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
46
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
47
+ </span>
48
+ <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
49
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading4" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
50
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
51
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" title="${lang.code}" tabindex="-1">${lang.code}</button>
52
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
53
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
54
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
55
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
56
+ </span>
57
+ <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
58
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
59
+ </span>
60
+ <span class="trix-button-group-spacer"></span>
61
+ <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
62
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
63
+ <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
64
+ </span>
65
+ </div>
66
+ <div class="trix-dialogs" data-trix-dialogs>
67
+ <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
68
+ <div class="trix-dialog__link-fields">
69
+ <input type="text" name="href" pattern="${LINK_PATTERN}" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
70
+ <div class="trix-button-group">
71
+ <input type="button" class="trix-button trix-button--dialog" value="${lang.link}" data-trix-method="setAttribute">
72
+ <input type="button" class="trix-button trix-button--dialog" value="${lang.unlink}" data-trix-method="removeAttribute">
73
+ </div>
74
+ </div>
75
+ </div>
76
+ </div>
77
+ `;
78
+ };
79
+
80
+ /**
81
+ * If the <trix-editor> element is in the HTML when Trix loads, then Trix will have already injected the toolbar content
82
+ * before our code gets a chance to run. Fix that now.
83
+ *
84
+ * Note: in Trix 2 this is likely to no longer be necessary.
85
+ */
86
+ document.querySelectorAll("trix-toolbar").forEach((e) => {
87
+ e.innerHTML = Trix.config.toolbar.getDefaultHTML();
88
+ });
@@ -80,6 +80,13 @@ export default class Item {
80
80
  this.#indexInput.value = `${index}`;
81
81
  }
82
82
 
83
+ /**
84
+ * @returns {boolean} true if this item can have children
85
+ */
86
+ get isLayout() {
87
+ return this.node.hasAttribute("data-content-layout");
88
+ }
89
+
83
90
  /**
84
91
  * @returns {Item} nearest neighbour (index - 1)
85
92
  */
@@ -120,26 +127,25 @@ export default class Item {
120
127
  traverse(callback) {
121
128
  // capture descendants before traversal in case of side-effects
122
129
  // specifically, setting depth affects calculation
123
- const collapsed = this.#collapsedChildren;
124
130
  const expanded = this.#expandedDescendants;
125
131
 
126
132
  callback(this);
127
- collapsed.forEach((item) => item.traverse(callback));
128
- expanded.forEach((item) => item.traverse(callback));
133
+ this.#traverseCollapsed(callback);
134
+ expanded.forEach((item) => item.#traverseCollapsed(callback));
129
135
  }
130
136
 
131
137
  /**
132
- * Increase the depth of this item and its descendants.
133
- * If this causes it to become a child of a collapsed item, then collapse this item.
138
+ * Recursively traverse the node's collapsed descendants, if any.
139
+ *
140
+ * @callback {Item}
134
141
  */
135
- nest() {
136
- this.traverse((child) => {
137
- child.depth += 1;
138
- });
142
+ #traverseCollapsed(callback) {
143
+ if (!this.hasCollapsedDescendants()) return;
139
144
 
140
- if (this.previousItem.hasCollapsedDescendants()) {
141
- this.previousItem.collapseChild(this);
142
- }
145
+ this.#collapsedDescendants.forEach((item) => {
146
+ callback(item);
147
+ item.#traverseCollapsed(callback);
148
+ });
143
149
  }
144
150
 
145
151
  /**
@@ -152,15 +158,6 @@ export default class Item {
152
158
  this.#childrenListElement.appendChild(item.node);
153
159
  }
154
160
 
155
- /**
156
- * Decrease the depth of this item (and its descendants).
157
- */
158
- deNest() {
159
- this.traverse((child) => {
160
- child.depth -= 1;
161
- });
162
- }
163
-
164
161
  /**
165
162
  * Collapses visible (logical) children into this element's hidden children
166
163
  * list, creating it if it doesn't already exist.
@@ -195,10 +192,12 @@ export default class Item {
195
192
  * @param deny {boolean}
196
193
  */
197
194
  toggleRule(rule, deny = false) {
198
- if (this.node.dataset.hasOwnProperty(rule) && !deny)
195
+ if (this.node.dataset.hasOwnProperty(rule) && !deny) {
199
196
  delete this.node.dataset[rule];
200
- if (!this.node.dataset.hasOwnProperty(rule) && deny)
197
+ }
198
+ if (!this.node.dataset.hasOwnProperty(rule) && deny) {
201
199
  this.node.dataset[rule] = "";
200
+ }
202
201
 
203
202
  if (rule === "denyDrag") {
204
203
  if (!this.node.hasAttribute("draggable") && !deny) {
@@ -238,6 +237,9 @@ export default class Item {
238
237
  return this.node.querySelector(`:scope > [data-content-children]`);
239
238
  }
240
239
 
240
+ /**
241
+ * @returns {Item[]} all items that follow this element that have a greater depth.
242
+ */
241
243
  get #expandedDescendants() {
242
244
  const descendants = [];
243
245
 
@@ -250,7 +252,10 @@ export default class Item {
250
252
  return descendants;
251
253
  }
252
254
 
253
- get #collapsedChildren() {
255
+ /**
256
+ * @returns {Item[]} all items directly contained inside this element's hidden children element.
257
+ */
258
+ get #collapsedDescendants() {
254
259
  if (!this.hasCollapsedDescendants()) return [];
255
260
 
256
261
  return Array.from(this.#childrenListElement.children).map(
@@ -9,30 +9,42 @@ export default class RulesEngine {
9
9
  "denyEdit",
10
10
  ];
11
11
 
12
- constructor(maxDepth = null) {
13
- this.maxDepth = maxDepth;
12
+ constructor(debug = false) {
13
+ if (debug) {
14
+ this.debug = (...args) => console.log(...args);
15
+ } else {
16
+ this.debug = () => {};
17
+ }
14
18
  }
15
19
 
16
20
  /**
17
- * Apply rules to the given item by computing a ruleset then merging it
18
- * with the item's current state.
21
+ * Enforce structural rules to ensure that the given item is currently in a
22
+ * valid state.
19
23
  *
20
24
  * @param {Item} item
21
25
  */
22
- update(item) {
23
- this.rules = {};
24
-
26
+ normalize(item) {
25
27
  // structural rules enforce a valid tree structure
26
28
  this.firstItemDepthZero(item);
27
29
  this.depthMustBeSet(item);
28
30
  this.itemCannotHaveInvalidDepth(item);
29
- this.itemCannotExceedDepthLimit(item);
31
+ this.parentMustBeLayout(item);
32
+ this.parentCannotHaveExpandedAndCollapsedChildren(item);
33
+ }
34
+
35
+ /**
36
+ * Apply rules to the given item to determine what operations are permitted.
37
+ *
38
+ * @param {Item} item
39
+ */
40
+ update(item) {
41
+ this.rules = {};
30
42
 
31
43
  // behavioural rules define what the user is allowed to do
32
44
  this.parentsCannotDeNest(item);
33
45
  this.rootsCannotDeNest(item);
46
+ this.onlyLastItemCanDeNest(item);
34
47
  this.nestingNeedsParent(item);
35
- this.nestingCannotExceedMaxDepth(item);
36
48
  this.leavesCannotCollapse(item);
37
49
  this.needHiddenItemsToExpand(item);
38
50
  this.parentsCannotBeDeleted(item);
@@ -47,7 +59,9 @@ export default class RulesEngine {
47
59
  * First item can't have a parent, so its depth should always be 0
48
60
  */
49
61
  firstItemDepthZero(item) {
50
- if (item.index === 0) {
62
+ if (item.index === 0 && item.depth !== 0) {
63
+ this.debug(`enforce depth on item ${item.index}: ${item.depth} => 0`);
64
+
51
65
  item.depth = 0;
52
66
  }
53
67
  }
@@ -59,6 +73,8 @@ export default class RulesEngine {
59
73
  */
60
74
  depthMustBeSet(item) {
61
75
  if (isNaN(item.depth) || item.depth < 0) {
76
+ this.debug(`unset depth on item ${item.index}: => 0`);
77
+
62
78
  item.depth = 0;
63
79
  }
64
80
  }
@@ -71,23 +87,44 @@ export default class RulesEngine {
71
87
  itemCannotHaveInvalidDepth(item) {
72
88
  const previous = item.previousItem;
73
89
  if (previous && previous.depth < item.depth - 1) {
90
+ this.debug(
91
+ `invalid depth on item ${item.index}: ${item.depth} => ${
92
+ previous.depth + 1
93
+ }`
94
+ );
95
+
74
96
  item.depth = previous.depth + 1;
75
97
  }
76
98
  }
77
99
 
78
100
  /**
79
- * Depth must not exceed container's depth limit.
101
+ * Parent item, if any, must be a layout.
102
+ *
103
+ * @param {Item} item
104
+ */
105
+ parentMustBeLayout(item) {
106
+ // if we're the first child, make sure our parent is a layout
107
+ // if we're a sibling, we know the previous item is valid so we must be too
108
+ const previous = item.previousItem;
109
+ if (previous && previous.depth < item.depth && !previous.isLayout) {
110
+ this.debug(
111
+ `invalid parent for item ${item.index}: ${item.depth} => ${previous.depth}`
112
+ );
113
+
114
+ item.depth = previous.depth;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * If a parent has expanded and collapsed children, expand.
80
120
  *
81
121
  * @param {Item} item
82
122
  */
83
- itemCannotExceedDepthLimit(item) {
84
- if (this.maxDepth > 0 && this.maxDepth <= item.depth) {
85
- // Note: this change can cause an issue where the previous item is treated
86
- // like a parent even though it no longer has children. This is because
87
- // items are processed in order. This issue does not seem worth solving
88
- // as it only occurs if the max depth is altered. The issue can be worked
89
- // around by saving the container.
90
- item.depth = this.maxDepth - 1;
123
+ parentCannotHaveExpandedAndCollapsedChildren(item) {
124
+ if (item.hasCollapsedDescendants() && item.hasExpandedDescendants()) {
125
+ this.debug(`expanding collapsed children of item ${item.index}`);
126
+
127
+ item.expand();
91
128
  }
92
129
  }
93
130
 
@@ -109,6 +146,17 @@ export default class RulesEngine {
109
146
  if (item.depth === 0) this.#deny("denyDeNest");
110
147
  }
111
148
 
149
+ /**
150
+ * De-nesting an item that has siblings would make it a container.
151
+ *
152
+ * @param {Item} item
153
+ */
154
+ onlyLastItemCanDeNest(item) {
155
+ const next = item.nextItem;
156
+ if (next && next.depth === item.depth && !item.isLayout)
157
+ this.#deny("denyDeNest");
158
+ }
159
+
112
160
  /**
113
161
  * If an item doesn't have children it can't be collapsed.
114
162
  *
@@ -134,18 +182,13 @@ export default class RulesEngine {
134
182
  */
135
183
  nestingNeedsParent(item) {
136
184
  const previous = item.previousItem;
137
- if (!previous || previous.depth < item.depth) this.#deny("denyNest");
138
- }
139
-
140
- /**
141
- * An item can't be nested (indented) if doing so would exceed the max depth.
142
- *
143
- * @param {Item} item
144
- */
145
- nestingCannotExceedMaxDepth(item) {
146
- if (this.maxDepth > 0 && this.maxDepth <= item.depth + 1) {
185
+ // no previous, so cannot nest
186
+ if (!previous) this.#deny("denyNest");
187
+ // previous is too shallow, nesting would increase depth too much
188
+ else if (previous.depth < item.depth) this.#deny("denyNest");
189
+ // new parent is not a layout
190
+ else if (previous.depth === item.depth && !previous.isLayout)
147
191
  this.#deny("denyNest");
148
- }
149
192
  }
150
193
 
151
194
  /**
@@ -154,7 +197,7 @@ export default class RulesEngine {
154
197
  * @param {Item} item
155
198
  */
156
199
  parentsCannotBeDeleted(item) {
157
- if (item.hasExpandedDescendants()) this.#deny("denyRemove");
200
+ if (!item.itemId || item.hasExpandedDescendants()) this.#deny("denyRemove");
158
201
  }
159
202
 
160
203
  /**
@@ -0,0 +1,12 @@
1
+ [data-controller="content--editor--image-field"] {
2
+ &.droppable {
3
+ box-shadow: inset 0 0 0 2px var(--icon-passive-color);
4
+ background-image: url("data:image/svg+xml,%3Csvg width='64' height='64' viewBox='0 0 33 31' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0.973145' width='32' height='30' rx='4' fill='grey'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M22.9506 10.5053C24.135 10.5053 25.0951 9.45219 25.0951 8.15306C25.0951 6.85393 24.135 5.80078 22.9506 5.80078C21.7661 5.80078 20.806 6.85393 20.806 8.15306C20.806 9.45219 21.7661 10.5053 22.9506 10.5053ZM17.0148 24.7495H4.74196C3.97371 24.7495 3.49239 23.9192 3.87419 23.2526L12.0384 8.99711C12.4167 8.33644 13.3632 8.32137 13.7579 8.9724C15.0754 11.1453 17.647 15.3946 19.8661 19.1086L22.2245 14.9665C22.5814 14.3397 23.4295 14.3294 23.8331 14.9468L29.1963 23.1506C29.6434 23.8345 29.2201 24.7563 28.4534 24.7645L23.2119 24.8206L17.0148 24.7495Z' fill='%23F3F5F8'/%3E%3C/svg%3E");
5
+ background-position: center center;
6
+ background-repeat: no-repeat;
7
+
8
+ > * {
9
+ visibility: hidden;
10
+ }
11
+ }
12
+ }
@@ -1,5 +1,6 @@
1
1
  @use "icon";
2
2
 
3
+ @use "figure";
3
4
  @use "item-actions";
4
5
  @use "item-rules";
5
6
  @use "new-items";
@@ -159,7 +160,8 @@ $status-dirty-color: #aaa !default;
159
160
  --color: #{$status-published-border-color};
160
161
  --border: #{$status-published-color};
161
162
 
162
- &[data-state="draft"] {
163
+ &[data-state="draft"],
164
+ &[data-state="unpublished"] {
163
165
  --background: #{$status-draft-background-color};
164
166
  --color: #{$status-draft-border-color};
165
167
  --border: #{$status-draft-color};
@@ -171,3 +173,7 @@ $status-dirty-color: #aaa !default;
171
173
  --border: #{$status-dirty-color};
172
174
  }
173
175
  }
176
+
177
+ [data-controller="content--editor--image-field"] {
178
+ --icon-passive-color: #{$icon-passive-color};
179
+ }
@@ -23,7 +23,7 @@
23
23
  }
24
24
  }
25
25
 
26
- [role="img"][value="content"] {
26
+ [role="img"][title="Type"] {
27
27
  width: 1.5rem;
28
28
  height: 1.5rem;
29
29
  display: grid;
@@ -44,12 +44,30 @@
44
44
  line-height: 1.125rem;
45
45
  text-align: center;
46
46
  }
47
+ }
47
48
 
48
- &[value="content"] {
49
- &::before {
50
- background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 49 49' fill='none' 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' fill='white'/%3E%3Cpath d='M13 19.1667V11H35.8667V19.1667H32.6V14.2667H26.0667V33.8667H29.3333V37.1333H19.5333V33.8667H22.8V14.2667H16.2667V19.1667H13Z' fill='white'/%3E%3C/svg%3E");
51
- }
52
- }
49
+ [role="img"][value="content"]::before {
50
+ background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 49 49' fill='none' 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' fill='white'/%3E%3Cpath d='M13 19.1667V11H35.8667V19.1667H32.6V14.2667H26.0667V33.8667H29.3333V37.1333H19.5333V33.8667H22.8V14.2667H16.2667V19.1667H13Z' fill='white'/%3E%3C/svg%3E");
51
+ }
52
+
53
+ [role="img"][value="figure"]::before {
54
+ background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' 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='white'/%3E%3C/svg%3E");
55
+ }
56
+
57
+ [role="img"][value="section"]::before {
58
+ background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 64 64' fill='white' 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");
59
+ }
60
+
61
+ [role="img"][value="group"]:before {
62
+ background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 64 64' fill='white' 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");
63
+ }
64
+
65
+ [role="img"][value="column"]:before {
66
+ background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 64 64' fill='none' stroke='white' 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");
67
+ }
68
+
69
+ [role="img"][value="aside"]::before {
70
+ background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 64 64' fill='none' stroke='white' 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");
53
71
  }
54
72
 
55
73
  [role="img"][value="invisible"] {