katalyst-navigation 1.4.0 → 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 (68) 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/db/migrate/20230727025052_update_target_syntax.rb +1 -1
  48. data/lib/katalyst/navigation/config.rb +4 -0
  49. data/lib/katalyst/navigation/engine.rb +1 -1
  50. data/lib/katalyst/navigation.rb +6 -1
  51. data/spec/factories/katalyst/navigation/menus.rb +1 -1
  52. metadata +93 -27
  53. data/app/controllers/katalyst/navigation/base_controller.rb +0 -12
  54. data/app/helpers/katalyst/navigation/editor/base.rb +0 -41
  55. data/app/helpers/katalyst/navigation/editor/errors.rb +0 -24
  56. data/app/helpers/katalyst/navigation/editor/item.rb +0 -62
  57. data/app/helpers/katalyst/navigation/editor/list.rb +0 -41
  58. data/app/helpers/katalyst/navigation/editor/menu.rb +0 -47
  59. data/app/helpers/katalyst/navigation/editor/new_item.rb +0 -53
  60. data/app/helpers/katalyst/navigation/editor_helper.rb +0 -52
  61. data/app/views/katalyst/navigation/menus/_item.html.erb +0 -15
  62. data/app/views/katalyst/navigation/menus/_new_item.html.erb +0 -3
  63. data/app/views/katalyst/navigation/menus/_new_items.html.erb +0 -5
  64. /data/app/{assets/javascripts/utils → javascript}/navigation/editor/item.js +0 -0
  65. /data/app/{assets/javascripts/controllers → javascript}/navigation/editor/list_controller.js +0 -0
  66. /data/app/{assets/javascripts/controllers → javascript}/navigation/editor/new_item_controller.js +0 -0
  67. /data/app/{assets/javascripts/utils → javascript}/navigation/editor/rules-engine.js +0 -0
  68. /data/app/{assets/javascripts/controllers → javascript}/navigation/editor/status_bar_controller.js +0 -0
@@ -2,24 +2,27 @@
2
2
 
3
3
  module Katalyst
4
4
  module Navigation
5
- class ItemsController < BaseController
6
- before_action :set_menu
5
+ class ItemsController < ApplicationController
6
+ before_action :set_menu, only: %i[new create]
7
7
  before_action :set_item, except: %i[new create]
8
8
 
9
+ attr_reader :menu, :item, :editor
10
+
11
+ layout nil
12
+
9
13
  def new
10
- render locals: { item: @menu.items.build(type: new_item_params) }
14
+ render_editor
11
15
  end
12
16
 
13
17
  def edit
14
- render locals: { item: @item }
18
+ render_editor
15
19
  end
16
20
 
17
21
  def create
18
- item = @menu.items.build(item_params)
19
22
  if item.save
20
- render :update, locals: { item: item, previous: @menu.items.build(type: item.type) }
23
+ render :update, locals: { editor:, item:, previous: @menu.items.build(type: item.type) }
21
24
  else
22
- render :new, status: :unprocessable_entity, locals: { item: item }
25
+ render_editor status: :unprocessable_entity
23
26
  end
24
27
  end
25
28
 
@@ -29,16 +32,17 @@ module Katalyst
29
32
  if @item.valid?
30
33
  previous = @item
31
34
  @item = @item.dup.tap(&:save!)
32
- render locals: { item: @item, previous: previous }
35
+
36
+ render locals: { editor:, item:, previous: }
33
37
  else
34
- render :edit, status: :unprocessable_entity, locals: { item: @item }
38
+ render_editor status: :unprocessable_entity
35
39
  end
36
40
  end
37
41
 
38
42
  private
39
43
 
40
44
  def new_item_params
41
- params[:type] || Link.name
45
+ { type: params[:type] || Link.name }
42
46
  end
43
47
 
44
48
  def item_params_type
@@ -55,11 +59,19 @@ module Katalyst
55
59
  end
56
60
 
57
61
  def set_menu
58
- @menu = Menu.find(params[:menu_id])
62
+ @menu = Menu.find(params[:menu_id])
63
+ @item = @menu.items.build(item_params)
64
+ @editor = Katalyst::Navigation::EditorComponent.new(menu:, item:)
59
65
  end
60
66
 
61
67
  def set_item
62
- @item = @menu.items.find(params[:id])
68
+ @item = Item.find(params[:id])
69
+ @menu = @item.menu
70
+ @editor = Katalyst::Navigation::EditorComponent.new(menu:, item:)
71
+ end
72
+
73
+ def render_editor(**)
74
+ render(:edit, locals: { item_editor: editor.item_editor(item:) }, **)
63
75
  end
64
76
  end
65
77
  end
@@ -2,55 +2,67 @@
2
2
 
3
3
  module Katalyst
4
4
  module Navigation
5
- class MenusController < BaseController
5
+ class MenusController < Katalyst::Navigation.config.base_controller.constantize
6
+ include Katalyst::Tables::Backend
7
+
6
8
  def index
7
9
  collection = Katalyst::Tables::Collection::Base.new(sorting: :title).with_params(params).apply(Menu.all)
8
- table = Katalyst::Turbo::TableComponent.new(collection: collection,
10
+ table = Katalyst::Turbo::TableComponent.new(collection:,
9
11
  id: "index-table",
10
12
  class: "index-table",
11
13
  caption: true)
12
14
 
13
15
  respond_to do |format|
14
16
  format.turbo_stream { render(table) } if self_referred?
15
- format.html { render :index, locals: { table: table } }
17
+ format.html { render :index, locals: { table: } }
16
18
  end
17
19
  end
18
20
 
19
21
  def show
20
- menu = Menu.find(params[:id])
22
+ menu = Menu.find(params[:id])
23
+ editor = Katalyst::Navigation::EditorComponent.new(menu:)
21
24
 
22
- render locals: { menu: menu }
25
+ render locals: { menu:, editor: }
23
26
  end
24
27
 
25
28
  def new
26
- render locals: { menu: Menu.new }
29
+ menu = Menu.new
30
+ editor = Katalyst::Navigation::EditorComponent.new(menu:)
31
+
32
+ render locals: { menu:, editor: }
27
33
  end
28
34
 
29
35
  def edit
30
- menu = Menu.find(params[:id])
36
+ menu = Menu.find(params[:id])
37
+ editor = Katalyst::Navigation::EditorComponent.new(menu:)
31
38
 
32
- render locals: { menu: menu }
39
+ render locals: { menu:, editor: }
33
40
  end
34
41
 
35
42
  def create
36
43
  @menu = Menu.new(menu_params)
44
+ editor = Katalyst::Navigation::EditorComponent.new(menu: @menu)
37
45
 
38
46
  if @menu.save
39
- redirect_to @menu
47
+ @menu.build_draft_version
48
+ @menu.save!
49
+ redirect_to @menu, status: :see_other
40
50
  else
41
- render :new, locals: { menu: @menu }, status: :unprocessable_entity
51
+ render :new, locals: { menu: @menu, editor: }, status: :unprocessable_entity
42
52
  end
43
53
  end
44
54
 
45
55
  # PATCH /admins/navigation_menus/:slug
46
56
  def update
47
57
  menu = Menu.find(params[:id])
58
+ editor = Katalyst::Navigation::EditorComponent.new(menu:)
48
59
 
49
60
  menu.attributes = menu_params
50
61
 
51
62
  unless menu.valid?
52
- return render turbo_stream: helpers.navigation_editor_errors(menu: menu),
53
- status: :unprocessable_entity
63
+ return respond_to do |format|
64
+ format.turbo_stream { render editor.errors, status: :unprocessable_entity }
65
+ end
54
66
  end
55
67
 
56
68
  case params[:commit]
@@ -62,7 +74,7 @@ module Katalyst
62
74
  when "revert"
63
75
  menu.revert!
64
76
  end
65
- redirect_to menu
77
+ redirect_to menu, status: :see_other
66
78
  end
67
79
 
68
80
  def destroy
@@ -11,14 +11,14 @@ module Katalyst
11
11
  #
12
12
  # @param(menu: Katalyst::Navigation::Menu)
13
13
  # @return Structured HTML containing top level + nested navigation links
14
- def navigation_menu_with(menu:, **options)
15
- builder = navigation_builder(**options)
14
+ def navigation_menu_with(menu:, **)
15
+ builder = navigation_builder(**)
16
16
  menu = navigation_menu_for(menu) if menu.is_a?(Symbol)
17
17
 
18
- return if menu&.published_version.blank?
18
+ return if menu.blank?
19
19
 
20
- cache menu.published_version do
21
- concat builder.render(menu.published_tree)
20
+ cache menu do
21
+ concat builder.render(menu.published_tree) if menu.published_version.present?
22
22
  end
23
23
  end
24
24
 
@@ -26,8 +26,8 @@ module Katalyst
26
26
  #
27
27
  # @param(items: [Katalyst::Navigation::Item])
28
28
  # @return Structured HTML containing top level + nested navigation links
29
- def navigation_items_with(items:, **options)
30
- builder = navigation_builder(**options)
29
+ def navigation_items_with(items:, **)
30
+ builder = navigation_builder(**)
31
31
 
32
32
  capture do
33
33
  items.each do |item|
@@ -0,0 +1,30 @@
1
+ import MenuController from "./editor/menu_controller";
2
+ import ItemController from "./editor/item_controller";
3
+ import ListController from "./editor/list_controller";
4
+ import NewItemController from "./editor/new_item_controller";
5
+ import StatusBarController from "./editor/status_bar_controller";
6
+
7
+ const Definitions = [
8
+ {
9
+ identifier: "navigation--editor--menu",
10
+ controllerConstructor: MenuController,
11
+ },
12
+ {
13
+ identifier: "navigation--editor--item",
14
+ controllerConstructor: ItemController,
15
+ },
16
+ {
17
+ identifier: "navigation--editor--list",
18
+ controllerConstructor: ListController,
19
+ },
20
+ {
21
+ identifier: "navigation--editor--new-item",
22
+ controllerConstructor: NewItemController,
23
+ },
24
+ {
25
+ identifier: "navigation--editor--status-bar",
26
+ controllerConstructor: StatusBarController,
27
+ },
28
+ ];
29
+
30
+ export { Definitions as default };
@@ -1,5 +1,5 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
- import Item from "utils/navigation/editor/item";
2
+ import Item from "./item";
3
3
 
4
4
  export default class ItemController extends Controller {
5
5
  get item() {
@@ -1,4 +1,4 @@
1
- import Item from "utils/navigation/editor/item";
1
+ import Item from "./item";
2
2
 
3
3
  /**
4
4
  * @param nodes {NodeList}
@@ -1,8 +1,8 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
2
 
3
- import Item from "utils/navigation/editor/item";
4
- import Menu from "utils/navigation/editor/menu";
5
- import RulesEngine from "utils/navigation/editor/rules-engine";
3
+ import Item from "./item";
4
+ import Menu from "./menu";
5
+ import RulesEngine from "./rules-engine";
6
6
 
7
7
  export default class MenuController extends Controller {
8
8
  static targets = ["menu"];
@@ -43,6 +43,8 @@ module Katalyst
43
43
  inverse_of: :menu,
44
44
  validate: true
45
45
 
46
+ scope :published, -> { where.not(published_version_id: nil) }
47
+
46
48
  validates :title, :slug, presence: true
47
49
  validates :slug, uniqueness: true
48
50
  validates :depth, numericality: { greater_than: 0, only_integer: true, allow_nil: true }
@@ -27,13 +27,13 @@ module Katalyst
27
27
  # Deserialize a params-style array, e.g. "0" => { ... }
28
28
  def deserialize_params(value)
29
29
  value.map do |index, attributes|
30
- Node.new(index: index, **attributes)
30
+ Node.new(index:, **attributes)
31
31
  end.select(&:id).sort_by(&:index)
32
32
  end
33
33
 
34
34
  def deserialize_array(value)
35
35
  value.map.with_index do |attributes, index|
36
- Node.new(index: index, **attributes)
36
+ Node.new(index:, **attributes)
37
37
  end.select(&:id).sort_by(&:index)
38
38
  end
39
39
  end
@@ -1,5 +1,6 @@
1
1
  <%= form_with model: item, scope: :item, url: path do |form| %>
2
2
  <%= form.hidden_field :type %>
3
+ <%= render "form_errors", form: %>
3
4
 
4
5
  <div class="input">
5
6
  <%= form.label :title %>
@@ -16,6 +17,11 @@
16
17
  <%= form.select :http_method, Katalyst::Navigation::Button::HTTP_METHODS %>
17
18
  </div>
18
19
 
20
+ <div class="field">
21
+ <%= form.label :target %>
22
+ <%= form.select :target, Katalyst::Navigation::Button::TARGETS %>
23
+ </div>
24
+
19
25
  <div class="input">
20
26
  <%= form.check_box :visible %>
21
27
  <%= form.label :visible %>
@@ -0,0 +1,5 @@
1
+ <%= tag.ul class: "errors" do %>
2
+ <% form.object.errors.full_messages.each do |error| %>
3
+ <li class="error"><%= error %></li>
4
+ <% end %>
5
+ <% end if form.object.errors.any? %>
@@ -1,5 +1,6 @@
1
1
  <%= form_with model: item, scope: :item, url: path do |form| %>
2
2
  <%= form.hidden_field :type %>
3
+ <%= render "form_errors", form: %>
3
4
 
4
5
  <div class="field">
5
6
  <%= form.label :title %>
@@ -1,5 +1,6 @@
1
1
  <%= form_with model: item, scope: :item, url: path do |form| %>
2
2
  <%= form.hidden_field :type %>
3
+ <%= render "form_errors", form: %>
3
4
 
4
5
  <div class="field">
5
6
  <%= form.label :title %>
@@ -11,6 +12,16 @@
11
12
  <%= form.text_field :url %>
12
13
  </div>
13
14
 
15
+ <div class="input">
16
+ <%= form.label :http_method %>
17
+ <%= form.select :http_method, Katalyst::Navigation::Link::HTTP_METHODS %>
18
+ </div>
19
+
20
+ <div class="field">
21
+ <%= form.label :target %>
22
+ <%= form.select :target, Katalyst::Navigation::Link::TARGETS %>
23
+ </div>
24
+
14
25
  <div class="field">
15
26
  <%= form.label :visible %>
16
27
  <%= form.check_box :visible %>
@@ -1,4 +1,5 @@
1
- <%= turbo_frame_tag "navigation--editor--item-frame" do %>
2
- <h3 class="heading-three">Edit <%= item.model_name.human.downcase %></h3>
3
- <%= render item.model_name.param_key, item: item, path: menu_item_path(item.menu, item) %>
1
+ <%= render Kpop::FrameComponent.new do %>
2
+ <%= render Kpop::ModalComponent.new(title: item_editor.title, layout: "side-panel") do %>
3
+ <%= render item_editor %>
4
+ <% end %>
4
5
  <% end %>
@@ -0,0 +1,3 @@
1
+ <%= turbo_stream.replace item_editor.id do %>
2
+ <%= render item_editor %>
3
+ <% end %>
@@ -1,4 +1,4 @@
1
1
  <%= turbo_frame_tag "navigation--editor--item-frame" do %>
2
2
  <h3 class="heading-three">New <%= item.model_name.human.downcase %></h3>
3
- <%= render item.model_name.param_key, item: item, path: menu_items_path(item.menu) %>
3
+ <%= render item.model_name.param_key, item:, path: menu_items_path(item.menu) %>
4
4
  <% end %>
@@ -1,7 +1,4 @@
1
- <%= turbo_stream.replace "navigation--editor--item-frame" do %>
2
- <%= render "katalyst/navigation/menus/new_items", menu: item.menu %>
3
- <% end %>
4
-
1
+ <%= turbo_stream.kpop.dismiss %>
5
2
  <%= turbo_stream.replace dom_id(previous) do %>
6
- <%= render "katalyst/navigation/menus/item", item: item %>
3
+ <%= render editor.item(item:) %>
7
4
  <% end %>
@@ -20,6 +20,6 @@
20
20
  <%= form.submit :save %>
21
21
  <%= link_to "Delete", url_for(action: :show),
22
22
  class: "button button-secondary",
23
- data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %>
23
+ data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %>
24
24
  </div>
25
25
  <% end %>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <nav class="index-table-actions">
4
4
  <div class="item-actions">
5
- <%= link_to "Add", [:new, :menu], class: "button button--primary" %>
5
+ <%= link_to "Add", %i[new menu], class: "button button--primary" %>
6
6
  </div>
7
7
  </nav>
8
8
 
@@ -1,15 +1,5 @@
1
1
  <% content_for :title, menu.title %>
2
2
 
3
- <%= navigation_editor_status_bar menu: menu %>
4
-
5
- <%= navigation_editor_menu menu: menu do |form| %>
6
- <div role="rowheader">
7
- <h4>Title</h4>
8
- <h4>Url</h4>
9
- <h4>Actions</h4>
10
- </div>
11
-
12
- <%= navigation_editor_list menu: menu %>
13
- <% end %>
14
-
15
- <%= render "katalyst/navigation/menus/new_items", menu: menu %>
3
+ <%= render editor.status_bar %>
4
+ <%= render editor %>
5
+ <%= render editor.new_items %>
data/config/importmap.rb CHANGED
@@ -1,5 +1,2 @@
1
1
  # frozen_string_literal: true
2
-
3
- pin_all_from Katalyst::Navigation::Engine.root.join("app/assets/javascripts"),
4
- # preload in tests so that we don't start clicking before controllers load
5
- preload: Rails.env.test?
2
+ pin "@katalyst/navigation", to: "katalyst/navigation.js"
@@ -3,7 +3,7 @@
3
3
  # Ensures that all navigation items have a valid target and http_method.
4
4
  class UpdateTargetSyntax < ActiveRecord::Migration[7.0]
5
5
  def change
6
- Katalyst::Navigation::Item.where(http_method: nil).update_all(target: "get")
6
+ Katalyst::Navigation::Item.where(http_method: nil).update_all(http_method: "get")
7
7
  Katalyst::Navigation::Item.where(target: nil).update_all(target: "self")
8
8
  Katalyst::Navigation::Item.where(target: "_blank").update_all(target: "blank")
9
9
  Katalyst::Navigation::Item.where(target: "_top").update_all(target: "top")
@@ -14,6 +14,10 @@ module Katalyst
14
14
  Katalyst::Navigation::Button
15
15
  ]
16
16
  end
17
+
18
+ config_accessor(:errors_component) { "Katalyst::Navigation::Editor::ErrorsComponent" }
19
+
20
+ config_accessor(:base_controller) { "ApplicationController" }
17
21
  end
18
22
  end
19
23
  end
@@ -18,7 +18,7 @@ module Katalyst
18
18
  initializer "katalyst-navigation.importmap", before: "importmap" do |app|
19
19
  if app.config.respond_to?(:importmap)
20
20
  app.config.importmap.paths << root.join("config/importmap.rb")
21
- app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
21
+ app.config.importmap.cache_sweepers << root.join("app/assets/builds")
22
22
  end
23
23
  end
24
24
 
@@ -1,8 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support"
4
+ require "katalyst/html_attributes"
5
+ require "katalyst/kpop"
6
+ require "katalyst/tables"
7
+ require "view_component"
8
+
3
9
  require "katalyst/navigation/config"
4
10
  require "katalyst/navigation/engine"
5
- require "katalyst/navigation/version"
6
11
 
7
12
  module Katalyst
8
13
  module Navigation # :nodoc:
@@ -10,7 +10,7 @@ FactoryBot.define do
10
10
  end
11
11
 
12
12
  after(:create) do |menu, _context|
13
- menu.items_attributes = menu.items.map.with_index { |item, index| { id: item.id, index: index, depth: 0 } }
13
+ menu.items_attributes = menu.items.map.with_index { |item, index| { id: item.id, index:, depth: 0 } }
14
14
  menu.publish!
15
15
  end
16
16
  end