katalyst-navigation 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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