katalyst-navigation 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +29 -5
  3. data/app/assets/builds/katalyst/navigation.esm.js +911 -0
  4. data/app/assets/builds/katalyst/navigation.js +911 -0
  5. data/app/assets/builds/katalyst/navigation.min.js +2 -0
  6. data/app/assets/builds/katalyst/navigation.min.js.map +1 -0
  7. data/app/assets/config/katalyst-navigation.js +1 -1
  8. data/app/components/katalyst/navigation/editor/base_component.rb +48 -0
  9. data/app/components/katalyst/navigation/editor/errors_component.html.erb +12 -0
  10. data/app/components/katalyst/navigation/editor/errors_component.rb +15 -0
  11. data/app/components/katalyst/navigation/editor/item_component.html.erb +27 -0
  12. data/app/components/katalyst/navigation/editor/item_component.rb +30 -0
  13. data/app/components/katalyst/navigation/editor/item_editor_component.rb +51 -0
  14. data/app/components/katalyst/navigation/editor/new_item_component.html.erb +14 -0
  15. data/app/components/katalyst/navigation/editor/new_item_component.rb +49 -0
  16. data/app/components/katalyst/navigation/editor/new_items_component.html.erb +3 -0
  17. data/app/components/katalyst/navigation/editor/new_items_component.rb +20 -0
  18. data/app/{views/katalyst/navigation/menus/_list_item.html.erb → components/katalyst/navigation/editor/row_component.html.erb} +1 -1
  19. data/{lib/katalyst/navigation/version.rb → app/components/katalyst/navigation/editor/row_component.rb} +4 -1
  20. data/app/{helpers/katalyst/navigation/editor/status_bar.rb → components/katalyst/navigation/editor/status_bar_component.rb} +17 -13
  21. data/app/components/katalyst/navigation/editor/table_component.html.erb +11 -0
  22. data/app/components/katalyst/navigation/editor/table_component.rb +36 -0
  23. data/app/components/katalyst/navigation/editor_component.html.erb +9 -0
  24. data/app/components/katalyst/navigation/editor_component.rb +47 -0
  25. data/app/controllers/concerns/katalyst/navigation/has_navigation.rb +5 -14
  26. data/app/controllers/katalyst/navigation/items_controller.rb +24 -12
  27. data/app/controllers/katalyst/navigation/menus_controller.rb +25 -13
  28. data/app/helpers/katalyst/navigation/frontend_helper.rb +7 -7
  29. data/app/javascript/navigation/application.js +30 -0
  30. data/app/{assets/javascripts/controllers → javascript}/navigation/editor/item_controller.js +1 -1
  31. data/app/{assets/javascripts/utils → javascript}/navigation/editor/menu.js +1 -1
  32. data/app/{assets/javascripts/controllers → javascript}/navigation/editor/menu_controller.js +3 -3
  33. data/app/models/katalyst/navigation/menu.rb +2 -0
  34. data/app/models/katalyst/navigation/types/nodes_type.rb +2 -2
  35. data/app/views/katalyst/navigation/items/_button.html.erb +6 -0
  36. data/app/views/katalyst/navigation/items/_form_errors.html.erb +5 -0
  37. data/app/views/katalyst/navigation/items/_heading.html.erb +1 -0
  38. data/app/views/katalyst/navigation/items/_link.html.erb +11 -0
  39. data/app/views/katalyst/navigation/items/edit.html.erb +4 -3
  40. data/app/views/katalyst/navigation/items/edit.turbo_stream.erb +3 -0
  41. data/app/views/katalyst/navigation/items/new.html.erb +1 -1
  42. data/app/views/katalyst/navigation/items/update.turbo_stream.erb +2 -5
  43. data/app/views/katalyst/navigation/menus/edit.html.erb +1 -1
  44. data/app/views/katalyst/navigation/menus/index.html.erb +1 -1
  45. data/app/views/katalyst/navigation/menus/show.html.erb +3 -13
  46. data/config/importmap.rb +1 -4
  47. data/lib/katalyst/navigation/config.rb +4 -0
  48. data/lib/katalyst/navigation/engine.rb +1 -1
  49. data/lib/katalyst/navigation.rb +6 -1
  50. data/spec/factories/katalyst/navigation/menus.rb +1 -1
  51. metadata +93 -27
  52. data/app/controllers/katalyst/navigation/base_controller.rb +0 -12
  53. data/app/helpers/katalyst/navigation/editor/base.rb +0 -41
  54. data/app/helpers/katalyst/navigation/editor/errors.rb +0 -24
  55. data/app/helpers/katalyst/navigation/editor/item.rb +0 -62
  56. data/app/helpers/katalyst/navigation/editor/list.rb +0 -41
  57. data/app/helpers/katalyst/navigation/editor/menu.rb +0 -47
  58. data/app/helpers/katalyst/navigation/editor/new_item.rb +0 -53
  59. data/app/helpers/katalyst/navigation/editor_helper.rb +0 -52
  60. data/app/views/katalyst/navigation/menus/_item.html.erb +0 -15
  61. data/app/views/katalyst/navigation/menus/_new_item.html.erb +0 -3
  62. data/app/views/katalyst/navigation/menus/_new_items.html.erb +0 -5
  63. /data/app/{assets/javascripts/utils → javascript}/navigation/editor/item.js +0 -0
  64. /data/app/{assets/javascripts/controllers → javascript}/navigation/editor/list_controller.js +0 -0
  65. /data/app/{assets/javascripts/controllers → javascript}/navigation/editor/new_item_controller.js +0 -0
  66. /data/app/{assets/javascripts/utils → javascript}/navigation/editor/rules-engine.js +0 -0
  67. /data/app/{assets/javascripts/controllers → javascript}/navigation/editor/status_bar_controller.js +0 -0
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- class BaseController < ActionController::Base
6
- include Katalyst::Tables::Backend
7
-
8
- helper Katalyst::Navigation::EditorHelper
9
- helper Katalyst::Tables::Frontend
10
- end
11
- end
12
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- module Editor
6
- class Base
7
- MENU_CONTROLLER = "navigation--editor--menu"
8
- LIST_CONTROLLER = "navigation--editor--list"
9
- ITEM_CONTROLLER = "navigation--editor--item"
10
- STATUS_BAR_CONTROLLER = "navigation--editor--status-bar"
11
- NEW_ITEM_CONTROLLER = "navigation--editor--new-item"
12
-
13
- ATTRIBUTES_SCOPE = "menu[items_attributes][]"
14
- TURBO_FRAME = "navigation--editor--item-frame"
15
-
16
- attr_accessor :template, :menu
17
-
18
- delegate_missing_to :template
19
-
20
- def initialize(template, menu)
21
- self.template = template
22
- self.menu = menu
23
- end
24
-
25
- def menu_form_id
26
- dom_id(menu, :items)
27
- end
28
-
29
- private
30
-
31
- def add_option(options, key, *path)
32
- if path.length > 1
33
- add_option(options[key] ||= {}, *path)
34
- else
35
- options[key] = [options[key], *path].compact.join(" ")
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- module Editor
6
- class Errors < Base
7
- def build(**options)
8
- turbo_frame_tag dom_id(menu, :errors) do
9
- next unless menu.errors.any?
10
-
11
- tag.div(class: "navigation-errors", **options) do
12
- tag.h2("Errors in navigation") +
13
- tag.ul(class: "errors") do
14
- menu.errors.each do |error|
15
- concat(tag.li(error.message))
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- module Editor
6
- class Item < Base
7
- attr_accessor :item
8
-
9
- def build(item, **options, &block)
10
- self.item = item
11
- tag.div **default_options(id: dom_id(item), **options) do
12
- concat(capture { yield self }) if block
13
- concat fields(item)
14
- end
15
- end
16
-
17
- def accordion_actions
18
- tag.div role: "toolbar", data: { tree_accordion_controls: "" } do
19
- concat tag.span(role: "button", value: "collapse",
20
- data: { action: "click->#{MENU_CONTROLLER}#collapse", title: "Collapse tree" })
21
- concat tag.span(role: "button", value: "expand",
22
- data: { action: "click->#{MENU_CONTROLLER}#expand", title: "Expand tree" })
23
- end
24
- end
25
-
26
- def item_actions
27
- tag.div role: "toolbar", data: { tree_controls: "" } do
28
- concat tag.span(role: "button", value: "de-nest",
29
- data: { action: "click->#{MENU_CONTROLLER}#deNest", title: "Outdent" })
30
- concat tag.span(role: "button", value: "nest",
31
- data: { action: "click->#{MENU_CONTROLLER}#nest", title: "Indent" })
32
- concat link_to("", edit_item_link,
33
- role: "button", title: "Edit", value: "edit",
34
- data: { turbo_frame: TURBO_FRAME })
35
- concat tag.span(role: "button", value: "remove",
36
- data: { action: "click->#{MENU_CONTROLLER}#remove", title: "Remove" })
37
- end
38
- end
39
-
40
- def edit_item_link
41
- item.persisted? ? edit_menu_item_path(item.menu, item) : new_menu_item_path(item.menu, type: item.type)
42
- end
43
-
44
- def fields(item)
45
- template.fields(ATTRIBUTES_SCOPE, model: item, index: nil, skip_default_ids: true) do |f|
46
- concat f.hidden_field(:id)
47
- concat f.hidden_field(:depth)
48
- concat f.hidden_field(:index)
49
- end
50
- end
51
-
52
- private
53
-
54
- def default_options(options)
55
- add_option(options, :data, :controller, ITEM_CONTROLLER)
56
-
57
- options
58
- end
59
- end
60
- end
61
- end
62
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- module Editor
6
- class List < Base
7
- ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
8
- dragstart->#{LIST_CONTROLLER}#dragstart
9
- dragover->#{LIST_CONTROLLER}#dragover
10
- dragenter->#{LIST_CONTROLLER}#dragenter
11
- dragleave->#{LIST_CONTROLLER}#dragleave
12
- drop->#{LIST_CONTROLLER}#drop
13
- dragend->#{LIST_CONTROLLER}#dragend
14
- ACTIONS
15
-
16
- def build(options, &_block)
17
- tag.ol **default_options(id: menu_form_id, **options) do
18
- yield self
19
- end
20
- end
21
-
22
- def items(*items)
23
- render partial: "katalyst/navigation/menus/item",
24
- layout: "katalyst/navigation/menus/list_item",
25
- collection: items,
26
- as: :item
27
- end
28
-
29
- private
30
-
31
- def default_options(options)
32
- add_option(options, :data, :controller, LIST_CONTROLLER)
33
- add_option(options, :data, :action, ACTIONS)
34
- add_option(options, :data, :"#{MENU_CONTROLLER}_target", "menu")
35
-
36
- options
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- module Editor
6
- class Menu < Base
7
- ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
8
- submit->#{MENU_CONTROLLER}#reindex
9
- navigation:drop->#{MENU_CONTROLLER}#drop
10
- navigation:reindex->#{MENU_CONTROLLER}#reindex
11
- navigation:reset->#{MENU_CONTROLLER}#reset
12
- ACTIONS
13
-
14
- def build(options)
15
- form_with(model: menu, **default_options(id: menu_form_id, **options)) do |form|
16
- concat hidden_input
17
- concat errors
18
- concat(capture { yield form })
19
- end
20
- end
21
-
22
- private
23
-
24
- # Hidden input ensures that if the menu is empty then the controller
25
- # receives an empty array.
26
- def hidden_input
27
- tag.input(type: "hidden", name: "#{Item::ATTRIBUTES_SCOPE}[id]")
28
- end
29
-
30
- def errors
31
- Editor::Errors.new(self, menu).build
32
- end
33
-
34
- def default_options(options)
35
- add_option(options, :data, :controller, MENU_CONTROLLER)
36
- add_option(options, :data, :action, ACTIONS)
37
-
38
- depth = options.delete(:depth) || menu.depth
39
-
40
- add_option(options, :data, :"#{MENU_CONTROLLER}-max-depth-value", depth) if depth
41
-
42
- options
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- module Editor
6
- class NewItem < Base
7
- ACTIONS = <<~ACTIONS.gsub(/\s+/, " ").freeze
8
- dragstart->#{NEW_ITEM_CONTROLLER}#dragstart
9
- ACTIONS
10
-
11
- def build(item, **options, &block)
12
- capture do
13
- concat(tag.div(**default_options(options)) do
14
- concat capture(&block)
15
- concat item_template(item)
16
- end)
17
- concat turbo_replace_placeholder(item)
18
- end
19
- end
20
-
21
- # Remove items that are incomplete when rendering new items, this
22
- # causes incomplete items to be removed from the list when the user
23
- # cancels adding a new item by pressing 'discard' in the new item form.
24
- def turbo_replace_placeholder(item)
25
- turbo_stream.replace dom_id(item) do
26
- navigation_editor_item(item: item, data: { delete: "" })
27
- end
28
- end
29
-
30
- # Template is stored inside the new item dom, and copied into drag
31
- # events when the user initiates drag so that it can be copied into the
32
- # editor list on drop.
33
- def item_template(item)
34
- tag.template data: { "#{NEW_ITEM_CONTROLLER}-target" => "template" } do
35
- navigation_editor_items(item: item)
36
- end
37
- end
38
-
39
- private
40
-
41
- def default_options(options)
42
- add_option(options, :draggable, true)
43
- add_option(options, :role, "listitem")
44
- add_option(options, :data, :turbo_frame, TURBO_FRAME)
45
- add_option(options, :data, :controller, NEW_ITEM_CONTROLLER)
46
- add_option(options, :data, :action, ACTIONS)
47
-
48
- options
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Katalyst
4
- module Navigation
5
- module EditorHelper
6
- def navigation_editor_new_items(menu)
7
- Katalyst::Navigation.config.items.map do |item_class|
8
- item_class = item_class.safe_constantize if item_class.is_a?(String)
9
- item_class.new(menu: menu)
10
- end
11
- end
12
-
13
- def navigation_editor_menu(menu:, **options, &block)
14
- Editor::Menu.new(self, menu).build(options, &block)
15
- end
16
-
17
- def navigation_editor_list(menu:, items: menu.draft_items, **options)
18
- Editor::List.new(self, menu).build(options) do |list|
19
- list.items(*items) if items.present?
20
- end
21
- end
22
-
23
- # Generate items without their list wrapper, similar to form_with/fields
24
- def navigation_editor_items(item:, menu: item.menu)
25
- Editor::List.new(self, menu).items(item)
26
- end
27
-
28
- # Generate a turbo stream fragment that will show structural errors to the user.
29
- def navigation_editor_errors(menu:, **options)
30
- turbo_stream.replace(dom_id(menu, :errors),
31
- Editor::Errors.new(self, menu).build(**options))
32
- end
33
-
34
- # Generate a new item template.
35
- def navigation_editor_new_item(item:, menu: item.menu, **options, &block)
36
- Editor::NewItem.new(self, menu).build(item, **options, &block)
37
- end
38
-
39
- def navigation_editor_item(item:, menu: item.menu, **options, &block)
40
- Editor::Item.new(self, menu).build(item, **options, &block)
41
- end
42
-
43
- def navigation_editor_item_fields(item:, menu: item.menu)
44
- Editor::Item.new(self, menu).fields(item)
45
- end
46
-
47
- def navigation_editor_status_bar(menu:, **options)
48
- Editor::StatusBar.new(self, menu).build(**options)
49
- end
50
- end
51
- end
52
- end
@@ -1,15 +0,0 @@
1
- <%= navigation_editor_item item: item do |builder| %>
2
- <div class="tree" data-invisible="<%= !item.visible? %>">
3
- <%= builder.accordion_actions %>
4
-
5
- <span role="img" value="<%= item.model_name.param_key %>" title="Type"></span>
6
- <h4 class="title" title="<%= item.title %>"><%= item.title %></h4>
7
- <span role="img" value="invisible" title="Hidden"></span>
8
- </div>
9
-
10
- <div class="url">
11
- <%= link_to item.url || "", item.url || "", data: { turbo: false } %>
12
- </div>
13
-
14
- <%= builder.item_actions %>
15
- <% end %>
@@ -1,3 +0,0 @@
1
- <%= navigation_editor_new_item item: item, data: { item_type: item.model_name.param_key } do %>
2
- <%= item.model_name.human %>
3
- <% end %>
@@ -1,5 +0,0 @@
1
- <%= turbo_frame_tag "navigation--editor--item-frame" do %>
2
- <div class="navigation--editor--new-items" role="listbox">
3
- <%= render partial: "katalyst/navigation/menus/new_item", collection: navigation_editor_new_items(menu), as: :item %>
4
- </div>
5
- <% end %>