katalyst-content 2.8.0 → 3.0.0.alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -3
  3. data/app/assets/builds/katalyst/content.esm.js +61 -2
  4. data/app/assets/builds/katalyst/content.js +61 -2
  5. data/app/assets/builds/katalyst/content.min.js +1 -1
  6. data/app/assets/builds/katalyst/content.min.js.map +1 -1
  7. data/app/assets/images/katalyst/content/icons/aside.svg +1 -0
  8. data/app/assets/images/katalyst/content/icons/collapse.svg +3 -0
  9. data/app/assets/images/katalyst/content/icons/column.svg +1 -0
  10. data/app/assets/images/katalyst/content/icons/content.svg +1 -0
  11. data/app/assets/images/katalyst/content/icons/edit.svg +1 -0
  12. data/app/assets/images/katalyst/content/icons/expand.svg +3 -0
  13. data/app/assets/images/katalyst/content/icons/figure.svg +1 -0
  14. data/app/assets/images/katalyst/content/icons/group.svg +1 -0
  15. data/app/assets/images/katalyst/content/icons/hidden.svg +1 -0
  16. data/app/assets/images/katalyst/content/icons/indent.svg +3 -0
  17. data/app/assets/images/katalyst/content/icons/outdent.svg +4 -0
  18. data/app/assets/images/katalyst/content/icons/remove.svg +1 -0
  19. data/app/assets/images/katalyst/content/icons/section.svg +1 -0
  20. data/app/assets/images/katalyst/content/icons/table.svg +1 -0
  21. data/app/assets/images/katalyst/content/icons/theme.svg +1 -0
  22. data/app/assets/stylesheets/katalyst/content/_editor.scss +4 -0
  23. data/app/assets/stylesheets/katalyst/content/_frontend.scss +1 -0
  24. data/app/assets/stylesheets/katalyst/content/editor/editor.css +200 -0
  25. data/app/assets/stylesheets/katalyst/content/editor/icons.css +79 -0
  26. data/app/assets/stylesheets/katalyst/content/editor/{_status-bar.scss → status-bar.css} +31 -37
  27. data/app/assets/stylesheets/katalyst/content/editor/{_table.scss → table.css} +3 -5
  28. data/app/assets/stylesheets/katalyst/content/editor.css +4 -0
  29. data/app/assets/stylesheets/katalyst/content/frontend/frontend.css +46 -0
  30. data/app/assets/stylesheets/katalyst/content/frontend.css +1 -0
  31. data/app/components/katalyst/content/editor/base_component.rb +0 -6
  32. data/app/components/katalyst/content/editor/item_component.html.erb +33 -15
  33. data/app/components/katalyst/content/editor/item_component.rb +1 -3
  34. data/app/components/katalyst/content/editor/item_editor_component.rb +8 -22
  35. data/app/components/katalyst/content/editor/new_item_component.html.erb +13 -10
  36. data/app/components/katalyst/content/editor/new_item_component.rb +7 -8
  37. data/app/components/katalyst/content/editor/new_items_component.html.erb +40 -18
  38. data/app/components/katalyst/content/editor/new_items_component.rb +0 -2
  39. data/app/components/katalyst/content/editor/row_component.html.erb +2 -1
  40. data/app/components/katalyst/content/editor/status_bar_component.rb +9 -11
  41. data/app/components/katalyst/content/editor/table_component.html.erb +0 -6
  42. data/app/components/katalyst/content/editor/table_component.rb +12 -12
  43. data/app/components/katalyst/content/editor_component.html.erb +5 -0
  44. data/app/components/katalyst/content/editor_component.rb +12 -11
  45. data/app/controllers/katalyst/content/items_controller.rb +0 -1
  46. data/app/helpers/katalyst/content/frontend_helper.rb +40 -24
  47. data/app/javascript/content/application.js +5 -0
  48. data/app/javascript/content/editor/item.js +1 -1
  49. data/app/javascript/content/editor/item_editor_controller.js +57 -0
  50. data/app/javascript/content/editor/new_items_controller.js +1 -1
  51. data/app/models/concerns/katalyst/content/has_tree.rb +16 -3
  52. data/app/models/katalyst/content/item.rb +15 -7
  53. data/app/views/katalyst/content/asides/_aside.html+form.erb +22 -26
  54. data/app/views/katalyst/content/asides/_aside.html.erb +5 -7
  55. data/app/views/katalyst/content/columns/_column.html+form.erb +18 -22
  56. data/app/views/katalyst/content/columns/_column.html.erb +3 -3
  57. data/app/views/katalyst/content/contents/_content.html+form.erb +22 -26
  58. data/app/views/katalyst/content/contents/_content.html.erb +2 -2
  59. data/app/views/katalyst/content/figures/_figure.html+form.erb +27 -31
  60. data/app/views/katalyst/content/figures/_figure.html.erb +1 -1
  61. data/app/views/katalyst/content/groups/_group.html+form.erb +18 -22
  62. data/app/views/katalyst/content/groups/_group.html.erb +1 -3
  63. data/app/views/katalyst/content/items/_form.html.erb +6 -0
  64. data/app/views/katalyst/content/items/_item.html+form.erb +18 -22
  65. data/app/views/katalyst/content/items/edit.html.erb +40 -2
  66. data/app/views/katalyst/content/items/edit.turbo_stream.erb +2 -0
  67. data/app/views/katalyst/content/items/update.turbo_stream.erb +0 -1
  68. data/app/views/katalyst/content/sections/_section.html+form.erb +18 -22
  69. data/app/views/katalyst/content/sections/_section.html.erb +3 -5
  70. data/app/views/katalyst/content/tables/_table.html+form.erb +9 -11
  71. data/db/migrate/20250321045027_rename_background_to_theme.rb +7 -0
  72. data/lib/katalyst/content/config.rb +4 -1
  73. data/lib/katalyst/content/engine.rb +0 -1
  74. data/spec/factories/katalyst/content/items.rb +1 -1
  75. metadata +29 -27
  76. data/app/assets/stylesheets/katalyst/content/_index.scss +0 -1
  77. data/app/assets/stylesheets/katalyst/content/editor/_figure.scss +0 -12
  78. data/app/assets/stylesheets/katalyst/content/editor/_icon.scss +0 -17
  79. data/app/assets/stylesheets/katalyst/content/editor/_index.scss +0 -157
  80. data/app/assets/stylesheets/katalyst/content/editor/_item-actions.scss +0 -110
  81. data/app/assets/stylesheets/katalyst/content/editor/_item-rules.scss +0 -19
  82. data/app/assets/stylesheets/katalyst/content/editor/_new-items.scss +0 -160
  83. data/app/assets/stylesheets/katalyst/content/editor/_trix-rails.scss +0 -30
  84. data/app/assets/stylesheets/katalyst/content/editor/_variables.scss +0 -26
@@ -1,12 +1,15 @@
1
- <%= tag.button(**html_attributes) do %>
2
- <%= label %>
3
- <%#
1
+ <li>
2
+ <%= tag.button(**html_attributes) do %>
3
+ <icon class="icon" data-icon="<%= icon_name %>" role="img">&nbsp;</icon>
4
+ <%= label %>
5
+ <%#
4
6
  # Template is stored inside the new item dom, and copied into the dom when
5
7
  # the user selects the item.
6
- %>
7
- <template>
8
- <%= render row_component do %>
9
- <%= render item_component %>
10
- <% end %>
11
- </template>
12
- <% end %>
8
+ %>
9
+ <template>
10
+ <%= render row_component do %>
11
+ <%= render item_component %>
12
+ <% end %>
13
+ </template>
14
+ <% end %>
15
+ </li>
@@ -8,10 +8,6 @@ module Katalyst
8
8
 
9
9
  with_collection_parameter :item
10
10
 
11
- ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
12
- #{NEW_ITEMS_CONTROLLER}#add
13
- ACTIONS
14
-
15
11
  def initialize(item:, container: item.container)
16
12
  super
17
13
  end
@@ -32,14 +28,17 @@ module Katalyst
32
28
  item.model_name.param_key
33
29
  end
34
30
 
31
+ alias icon_name item_type
32
+
35
33
  private
36
34
 
37
35
  def default_html_attributes
38
36
  {
39
- role: "listitem",
40
- data: {
41
- item_type:,
42
- action: ACTIONS,
37
+ class: "button",
38
+ role: "listitem",
39
+ data: {
40
+ ghost_button: "",
41
+ action: "content--editor--new-items#add",
43
42
  },
44
43
  }
45
44
  end
@@ -1,20 +1,42 @@
1
1
  <div class="content--editor--new-items"
2
- data-controller="<%= NEW_ITEMS_CONTROLLER %>"
3
- data-action="turbo:before-morph-element-><%= NEW_ITEMS_CONTROLLER %>#morph">
4
- <%= tag.button(aria: { controls: "#{NEW_ITEMS_CONTROLLER}-dialog" },
5
- class: "content--editor--add-button",
6
- data: { action: "#{NEW_ITEMS_CONTROLLER}#open" }) do %>
7
- Add content
8
- <% end %>
9
- <%= tag.div(class: "content--editor--inline-add",
10
- data: { "#{NEW_ITEMS_CONTROLLER}_target" => "inline" },
11
- hidden: "") do %>
12
- <%= tag.button(aria: { controls: "#{NEW_ITEMS_CONTROLLER}-dialog", label: "Add content here" },
13
- data: { action: "#{NEW_ITEMS_CONTROLLER}#open" }) %>
14
- <% end %>
15
- <%= tag.dialog(id: "#{NEW_ITEMS_CONTROLLER}-dialog", data: { action: "click->#{NEW_ITEMS_CONTROLLER}#close"}) do %>
16
- <%= tag.div(role: "list", data: { action: "click->#{NEW_ITEMS_CONTROLLER}#noop:stop" }) do %>
17
- <%= render Katalyst::Content::Editor::NewItemComponent.with_collection(items) %>
18
- <% end %>
19
- <% end %>
2
+ data-controller="content--editor--new-items"
3
+ data-action="turbo:before-morph-element->content--editor--new-items#morph">
4
+ <button aria-controls="content--editor--new-items-dialog"
5
+ class="button"
6
+ data-action="click->content--editor--new-items#open"
7
+ data-button-padding="tight"
8
+ data-text-button>
9
+ <icon aria-hidden="true" class="icon" data-icon="add">&nbsp;</icon>
10
+ Add item
11
+ </button>
12
+ <div class="content--editor--inline-add" data-content--editor--new-items-target="inline" hidden>
13
+ <button aria-controls="content--editor--new-items-dialog"
14
+ class="button"
15
+ data-action="content--editor--new-items#open"
16
+ data-button-padding="tight">
17
+ <icon aria-hidden="true" class="icon" data-icon="add">&nbsp;</icon>
18
+ <span class="visually-hidden">Add item here</span>
19
+ </button>
20
+ </div>
21
+ <dialog id="content--editor--new-items-dialog" class="modal" data-action="click->content--editor--new-items#close">
22
+ <article class="flow" data-action="click->content--editor--new-items#noop:stop">
23
+ <header class="repel" data-nowrap>
24
+ <h2>Add item</h2>
25
+ <button class="button"
26
+ data-action="click->content--editor--new-items#close"
27
+ data-button-padding="tight"
28
+ data-text-button>
29
+ <icon aria-hidden="true" class="icon" data-icon="close">&nbsp;</icon>
30
+ <span class="visually-hidden">Close</span>
31
+ </button>
32
+ </header>
33
+ <main>
34
+ <%= tag.div(role: "list", data: { action: "click->content--editor--new-items#noop:stop" }) do %>
35
+ <ul role="list" class="items-list">
36
+ <%= render Katalyst::Content::Editor::NewItemComponent.with_collection(items) %>
37
+ </ul>
38
+ <% end %>
39
+ </main>
40
+ </article>
41
+ </dialog>
20
42
  </div>
@@ -4,8 +4,6 @@ module Katalyst
4
4
  module Content
5
5
  module Editor
6
6
  class NewItemsComponent < BaseComponent
7
- include ::Turbo::FramesHelper
8
-
9
7
  renders_many :items, Editor::NewItemComponent
10
8
 
11
9
  def items
@@ -1,4 +1,5 @@
1
- <li draggable="true"
1
+ <li class="content--editor--item"
2
+ draggable="true"
2
3
  data-content-item
3
4
  data-content-item-id="<%= item.id %>"
4
5
  data-content-index="<%= item.index %>"
@@ -4,11 +4,6 @@ module Katalyst
4
4
  module Content
5
5
  module Editor
6
6
  class StatusBarComponent < BaseComponent
7
- ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
8
- content:change@document->#{STATUS_BAR_CONTROLLER}#change
9
- turbo:morph-element->#{STATUS_BAR_CONTROLLER}#morph
10
- ACTIONS
11
-
12
7
  attr_reader :container
13
8
 
14
9
  def call
@@ -37,10 +32,10 @@ module Katalyst
37
32
 
38
33
  def actions
39
34
  tag.menu do
40
- concat action(:discard, class: "button button--text")
41
- concat action(:revert, class: "button button--text") if container.draft?
42
- concat action(:save, class: "button button--secondary")
43
- concat action(:publish, class: "button button--primary")
35
+ concat action(:discard, class: "button", data: { text_button: "" })
36
+ concat action(:revert, class: "button", data: { text_button: "" })
37
+ concat action(:save, class: "button", data: { ghost_button: "" })
38
+ concat action(:publish, class: "button")
44
39
  end
45
40
  end
46
41
 
@@ -59,8 +54,11 @@ module Katalyst
59
54
  def default_html_attributes
60
55
  {
61
56
  data: {
62
- controller: STATUS_BAR_CONTROLLER,
63
- action: ACTIONS,
57
+ controller: "content--editor--status-bar",
58
+ action: %w[
59
+ content:change@document->content--editor--status-bar#change
60
+ turbo:morph-element->content--editor--status-bar#morph
61
+ ],
64
62
  state: container.state,
65
63
  },
66
64
  }
@@ -1,9 +1,3 @@
1
- <div role="rowheader">
2
- <h4>Heading</h4>
3
- <h4></h4>
4
- <h4>Actions</h4>
5
- </div>
6
-
7
1
  <%= tag.ol(id: container_form_id, **html_attributes) do %>
8
2
  <% items.each do |item| %>
9
3
  <%= item %>
@@ -4,14 +4,6 @@ module Katalyst
4
4
  module Content
5
5
  module Editor
6
6
  class TableComponent < BaseComponent
7
- ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
8
- dragstart->#{LIST_CONTROLLER}#dragstart
9
- dragover->#{LIST_CONTROLLER}#dragover
10
- drop->#{LIST_CONTROLLER}#drop
11
- dragend->#{LIST_CONTROLLER}#dragend
12
- keyup.esc@document->#{LIST_CONTROLLER}#dragend
13
- ACTIONS
14
-
15
7
  renders_many :items, ->(item) do
16
8
  row = RowComponent.new(item:, container:)
17
9
  row.with_content(render(ItemComponent.new(item:, container:)))
@@ -22,11 +14,19 @@ module Katalyst
22
14
 
23
15
  def default_html_attributes
24
16
  {
25
- data: {
26
- controller: LIST_CONTROLLER,
27
- action: ACTIONS,
28
- "#{CONTAINER_CONTROLLER}_target": "container",
17
+ class: "katalyst--content--editor",
18
+ data: {
19
+ controller: "content--editor--list",
20
+ action: %w[
21
+ dragstart->content--editor--list#dragstart
22
+ dragover->content--editor--list#dragover
23
+ drop->content--editor--list#drop
24
+ dragend->content--editor--list#dragend
25
+ keyup.esc@document->content--editor--list#dragend
26
+ ],
27
+ content__editor__container_target: "container",
29
28
  },
29
+ role: "list",
30
30
  }
31
31
  end
32
32
  end
@@ -9,3 +9,8 @@
9
9
 
10
10
  <%= render Katalyst::Content::Editor::NewItemsComponent.new(container:) %>
11
11
  <% end %>
12
+
13
+ <%= turbo_frame_tag(
14
+ "content--editor--item-editor",
15
+ data: { controller: "content--editor--item-editor" },
16
+ ) %>
@@ -3,13 +3,7 @@
3
3
  module Katalyst
4
4
  module Content
5
5
  class EditorComponent < Editor::BaseComponent
6
- ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
7
- submit->#{CONTAINER_CONTROLLER}#reindex
8
- content:drop->#{CONTAINER_CONTROLLER}#drop
9
- content:reindex->#{CONTAINER_CONTROLLER}#reindex
10
- turbo:render@document->#{CONTAINER_CONTROLLER}#connect
11
- content:reset->#{CONTAINER_CONTROLLER}#reset
12
- ACTIONS
6
+ include ::Turbo::FramesHelper
13
7
 
14
8
  attr_reader :url, :scope
15
9
 
@@ -44,10 +38,17 @@ module Katalyst
44
38
 
45
39
  def default_html_attributes
46
40
  {
47
- id: container_form_id,
48
- data: {
49
- controller: CONTAINER_CONTROLLER,
50
- action: ACTIONS,
41
+ id: container_form_id,
42
+ class: "content--editor",
43
+ data: {
44
+ controller: "content--editor--container",
45
+ action: %w[
46
+ submit->content--editor--container#reindex
47
+ content:drop->content--editor--container#drop
48
+ content:reindex->content--editor--container#reindex
49
+ turbo:render@document->content--editor--container#connect
50
+ content:reset->content--editor--container#reset
51
+ ],
51
52
  },
52
53
  }
53
54
  end
@@ -6,7 +6,6 @@ module Katalyst
6
6
  before_action :set_container, only: %i[new create]
7
7
  before_action :set_item, except: %i[new create]
8
8
  before_action :set_editor_variant
9
- before_action :require_kpop, only: %i[new edit]
10
9
 
11
10
  attr_reader :container, :item, :editor
12
11
 
@@ -5,6 +5,8 @@ module Katalyst
5
5
  module FrontendHelper
6
6
  include TableHelper
7
7
 
8
+ using Katalyst::HtmlAttributes::HasHtmlAttributes
9
+
8
10
  # Render all items from a content version as HTML
9
11
  # @param version [Katalyst::Content::Version] The content version to render
10
12
  # @return [ActiveSupport::SafeBuffer,String,nil] Content as HTML
@@ -14,16 +16,24 @@ module Katalyst
14
16
  capture do
15
17
  cache version do
16
18
  without_partial_path_prefix do
17
- concat render partial: version.tree.select(&:visible?)
19
+ concat(render_content_items(*version.tree.select(&:visible?), class: "flow"))
18
20
  end
19
21
  end
20
22
  end
21
23
  end
22
24
 
23
- def render_content_items(items)
24
- items = items.select(&:visible?)
25
- without_partial_path_prefix do
26
- render partial: items if items.any?
25
+ def render_content_items(*items, tag: :div, theme: nil, **)
26
+ items = items.flatten.select(&:visible?)
27
+
28
+ grouped_items = items.slice_when { |first, second| first.theme != second.theme }
29
+
30
+ grouped_items.each do |siblings|
31
+ content_theme = (siblings.first.theme if siblings.first.theme != theme)
32
+ concat(content_items_tag(tag, content_theme:, **) do
33
+ without_partial_path_prefix do
34
+ concat(render(partial: siblings))
35
+ end
36
+ end)
27
37
  end
28
38
  end
29
39
 
@@ -31,7 +41,15 @@ module Katalyst
31
41
  FrontendBuilder.new(self, item).render(...)
32
42
  end
33
43
 
34
- private
44
+ def content_items_tag(tag, content_theme:, **attributes, &)
45
+ html_attributes = {
46
+ class: "content-items",
47
+ data: {
48
+ content_theme:,
49
+ },
50
+ }.merge_html(attributes)
51
+ content_tag(tag, **html_attributes, &)
52
+ end
35
53
 
36
54
  def without_partial_path_prefix
37
55
  current = prefix_partial_path_with_controller_namespace
@@ -44,6 +62,8 @@ module Katalyst
44
62
  end
45
63
 
46
64
  class FrontendBuilder
65
+ include Katalyst::HtmlAttributes
66
+
47
67
  attr_accessor :template, :item
48
68
 
49
69
  delegate_missing_to :@template
@@ -53,32 +73,28 @@ module Katalyst
53
73
  self.item = item
54
74
  end
55
75
 
56
- def render(**, &)
57
- content_tag tag, **default_options(**) do
58
- content_tag(:div, &)
59
- end
76
+ def render(tag: :div, **, &)
77
+ update_html_attributes(**)
78
+
79
+ content_tag(tag, **html_attributes, &)
60
80
  end
61
81
 
62
82
  private
63
83
 
64
- def default_options(**options)
84
+ def default_html_attributes
65
85
  {
66
- id: item.heading&.parameterize,
67
- class: ["content-item", item.model_name.param_key, item.background, options[:class]],
68
- data: { content_index: item.index, content_depth: item.depth, **options.fetch(:data, {}) },
69
- **options.except(:class, :data, :root),
86
+ id: item.dom_id,
87
+ class: ["content-item", wrapper_class],
88
+ data: {
89
+ content_index: item.index,
90
+ content_depth: item.depth,
91
+ content_item_type: item.item_type,
92
+ },
70
93
  }
71
94
  end
72
95
 
73
- def tag
74
- case item
75
- when Figure
76
- :figure
77
- when Section
78
- :section
79
- else
80
- :div
81
- end
96
+ def wrapper_class
97
+ "wrapper" if item.depth.zero?
82
98
  end
83
99
  end
84
100
  end
@@ -1,5 +1,6 @@
1
1
  import ContainerController from "./editor/container_controller";
2
2
  import ItemController from "./editor/item_controller";
3
+ import ItemEditorController from "./editor/item_editor_controller";
3
4
  import ListController from "./editor/list_controller";
4
5
  import NewItemsController from "./editor/new_items_controller";
5
6
  import StatusBarController from "./editor/status_bar_controller";
@@ -15,6 +16,10 @@ const Definitions = [
15
16
  identifier: "content--editor--item",
16
17
  controllerConstructor: ItemController,
17
18
  },
19
+ {
20
+ identifier: "content--editor--item-editor",
21
+ controllerConstructor: ItemEditorController,
22
+ },
18
23
  {
19
24
  identifier: "content--editor--list",
20
25
  controllerConstructor: ListController,
@@ -272,7 +272,7 @@ export default class Item {
272
272
  */
273
273
  function createChildrenList(node) {
274
274
  const childrenList = document.createElement("ol");
275
- childrenList.setAttribute("class", "hidden");
275
+ childrenList.toggleAttribute("hidden", true);
276
276
 
277
277
  // if objectType is "rich-content" set richContentChildren as a data attribute
278
278
  childrenList.dataset[`contentChildren`] = "";
@@ -0,0 +1,57 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ import Item from "./item";
3
+
4
+ export default class ItemEditorController extends Controller {
5
+ static targets = ["dialog"];
6
+
7
+ connect() {
8
+ this.element.addEventListener("turbo:submit-end", this.onSubmit);
9
+ }
10
+
11
+ disconnect() {
12
+ this.element.removeEventListener("turbo:submit-end", this.onSubmit);
13
+ }
14
+
15
+ dismiss() {
16
+ if (!this.dialogTarget) return;
17
+ if (!this.dialogTarget.open) this.dialogTarget.close();
18
+
19
+ if (!("itemPersisted" in this.dialogTarget.dataset)) {
20
+ this.#removeTargetItem();
21
+ }
22
+
23
+ this.element.removeAttribute("src");
24
+ this.dialogTarget.remove();
25
+ }
26
+
27
+ dialogTargetConnected(dialog) {
28
+ dialog.showModal();
29
+ }
30
+
31
+ onSubmit = (event) => {
32
+ if (
33
+ event.detail.success &&
34
+ "closeDialog" in event.detail.formSubmission?.submitter?.dataset
35
+ ) {
36
+ this.dialogTarget.close();
37
+ this.element.removeAttribute("src");
38
+ this.dialogTarget.remove();
39
+ }
40
+ };
41
+
42
+ noop() {}
43
+
44
+ #removeTargetItem() {
45
+ const el = document.getElementById(this.dialogTarget.dataset.itemId);
46
+ const item = new Item(el.closest("[data-content-item]"));
47
+ const list = item.node.parentElement;
48
+
49
+ item.node.remove();
50
+
51
+ this.dispatch("reindex", {
52
+ target: list,
53
+ bubbles: true,
54
+ prefix: "content",
55
+ });
56
+ }
57
+ }
@@ -32,7 +32,7 @@ export default class NewItemsController extends Controller {
32
32
  add(e) {
33
33
  e.preventDefault();
34
34
 
35
- const template = e.target.querySelector("template");
35
+ const template = e.target.closest("li").querySelector("template");
36
36
  const item = template.content.querySelector("li").cloneNode(true);
37
37
  const target = this.currentItem;
38
38
 
@@ -20,9 +20,7 @@ module Katalyst
20
20
 
21
21
  def add(node)
22
22
  if node.depth == depth
23
- node.parent = current
24
- children << node
25
- self
23
+ add_sibling(node)
26
24
  elsif node.depth > depth
27
25
  push(children.last)
28
26
  add(node)
@@ -32,6 +30,21 @@ module Katalyst
32
30
  end
33
31
  end
34
32
 
33
+ def add_sibling(node)
34
+ node.parent = current
35
+
36
+ previous = children.last
37
+
38
+ children << node
39
+
40
+ if previous
41
+ previous.next_sibling = node
42
+ node.previous_sibling = previous
43
+ end
44
+
45
+ self
46
+ end
47
+
35
48
  private
36
49
 
37
50
  attr_writer :current, :depth, :children
@@ -16,12 +16,12 @@ module Katalyst
16
16
 
17
17
  validates :heading, presence: true
18
18
  validates :heading_style, inclusion: { in: config.heading_styles }
19
- validates :background, presence: true, inclusion: { in: config.backgrounds }, if: :validate_background?
19
+ validates :theme, inclusion: { in: config.themes, allow_blank: true }
20
20
 
21
21
  after_initialize :initialize_tree
22
22
  before_validation :set_defaults
23
23
 
24
- attr_accessor :parent, :children, :index, :depth
24
+ attr_accessor :parent, :children, :index, :depth, :previous_sibling, :next_sibling
25
25
 
26
26
  def self.permitted_params
27
27
  %i[
@@ -30,7 +30,7 @@ module Katalyst
30
30
  type
31
31
  heading
32
32
  heading_style
33
- background
33
+ theme
34
34
  visible
35
35
  ]
36
36
  end
@@ -51,6 +51,18 @@ module Katalyst
51
51
  is_a? Layout
52
52
  end
53
53
 
54
+ def dom_id
55
+ heading&.parameterize
56
+ end
57
+
58
+ def item_type
59
+ model_name.param_key
60
+ end
61
+
62
+ def theme
63
+ super.presence || parent&.theme
64
+ end
65
+
54
66
  private
55
67
 
56
68
  def initialize_tree
@@ -61,10 +73,6 @@ module Katalyst
61
73
  def set_defaults
62
74
  self.heading_style = "none" if heading_style.blank?
63
75
  end
64
-
65
- def validate_background?
66
- true
67
- end
68
76
  end
69
77
  end
70
78
  end
@@ -1,32 +1,28 @@
1
- <%= form_with model: aside, scope: :item, url: path do |form| %>
2
- <%= render "hidden_fields", form: %>
3
- <%= render "form_errors", form: %>
1
+ <%# locals: (form:, aside:) %>
4
2
 
5
- <div class="field">
6
- <%= form.label :heading %>
7
- <%= form.text_field :heading %>
8
- </div>
3
+ <%= render "form_errors", form: %>
9
4
 
10
- <div class="field">
11
- <%= form.label :heading_style %>
12
- <%= form.collection_radio_buttons :heading_style, Katalyst::Content.config.heading_styles, :itself, :itself %>
13
- </div>
5
+ <div class="field">
6
+ <%= form.label :heading %>
7
+ <%= form.text_field :heading %>
8
+ </div>
14
9
 
15
- <div class="field">
16
- <%= form.label :background %>
17
- <%= form.select :background, Katalyst::Content.config.backgrounds %>
18
- </div>
10
+ <div class="field">
11
+ <%= form.label :heading_style %>
12
+ <%= form.collection_radio_buttons :heading_style, Katalyst::Content.config.heading_styles, :itself, :itself %>
13
+ </div>
19
14
 
20
- <div class="field">
21
- <%= form.label :visible %>
22
- <%= form.check_box :visible %>
23
- </div>
15
+ <div class="field">
16
+ <%= form.label :theme %>
17
+ <%= form.select :theme, Katalyst::Content.config.themes %>
18
+ </div>
24
19
 
25
- <div class="field">
26
- <%= form.label :reverse %>
27
- <%= form.check_box :reverse %>
28
- </div>
20
+ <div class="field">
21
+ <%= form.label :visible %>
22
+ <%= form.check_box :visible %>
23
+ </div>
29
24
 
30
- <%= form.submit "Done" %>
31
- <%= link_to "Discard", :back %>
32
- <% end %>
25
+ <div class="field">
26
+ <%= form.label :reverse %>
27
+ <%= form.check_box :reverse %>
28
+ </div>
@@ -1,16 +1,14 @@
1
- <%= content_item_tag aside do %>
1
+ <%= content_item_tag(aside, data: { aside_reverse: ("" if aside.reverse) }) do %>
2
2
  <%= tag.h3 aside.heading, class: aside.heading_style_class if aside.show_heading? %>
3
3
 
4
4
  <% if aside.children.any? %>
5
5
  <% items = aside.children.select(&:visible?) %>
6
6
  <% last = items.pop %>
7
- <div role="aside-container" <%= "class=reverse" if aside.reverse %>>
8
- <div>
9
- <%= render_content_items items %>
7
+ <div class="sidebar">
8
+ <div class="aside--main">
9
+ <%= render_content_items(*items, theme: aside.theme, class: "flow") %>
10
10
  </div>
11
- <aside>
12
- <%= render_content_items [last] %>
13
- </aside>
11
+ <%= render_content_items(last, tag: :aside, class: "aside--sidebar", theme: aside.theme) %>
14
12
  </div>
15
13
  <% end %>
16
14
  <% end %>