katalyst-navigation 1.2.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6424bb96df0ceb96b40aa6d225dbe12461784edb41c1b83863435a56db02fd68
4
- data.tar.gz: 6a46bbd339f8c171fe7a9791ad94281c6e0cb6f846f8bab04bd62edb8e8c339c
3
+ metadata.gz: faf8cc382bdaae60ca2a35d93dcdfe970e36d317912ed13038607e74cf68da45
4
+ data.tar.gz: '05539e1025ee15510fb6952a3bfec19534daa834af0dd80f303081badb3a68cf'
5
5
  SHA512:
6
- metadata.gz: 173290becb5111777b887baeefe3a93642d8b154cb6463fd0a84a83e0246be7159568cc836d3eb2ca4ca7b9d7a2b616eff69c284d7abbaa93f7f2a26e0f81f76
7
- data.tar.gz: cad3f1cf87f00b7868aac073b71d192345b341feb73a0d28de332fccd932278988c256cc9228d2f30eadc55b2de0c4070d8a263c323e235b22f18f087bbc9abb
6
+ metadata.gz: dd9484b91afa4c6e80347513fe063989b00f838b9b6ca7bd3ff448879f444a89a7789e9e3fe7216987f67ea23fa4ae036797841b6e8631be37b157b6000b807f
7
+ data.tar.gz: 650999ce4d2ead2f82c80ec97458edbc326c0c43c57c62a5bb72f86f1c79c7c8c0adee7dba0653b4ea09b05d135677ad4de582209b13d7d9a66592ca8b49a058
@@ -22,8 +22,7 @@
22
22
  }
23
23
  }
24
24
 
25
- [role="img"][value="link"],
26
- [role="img"][value="title"] {
25
+ [role="img"][title="Type"] {
27
26
  width: 1.5rem;
28
27
  height: 1.5rem;
29
28
  display: grid;
@@ -44,18 +43,18 @@
44
43
  line-height: 1.125rem;
45
44
  text-align: center;
46
45
  }
46
+ }
47
47
 
48
- &[value="link"] {
49
- &::before {
50
- content: "#";
51
- }
52
- }
48
+ [role="img"][value="heading"]::before {
49
+ content: "H";
50
+ }
53
51
 
54
- &[value="title"] {
55
- &::before {
56
- content: "T";
57
- }
58
- }
52
+ [role="img"][value="link"]::before {
53
+ content: "#";
54
+ }
55
+
56
+ [role="img"][value="button"]::before {
57
+ content: "#";
59
58
  }
60
59
 
61
60
  [role="img"][value="invisible"] {
@@ -28,6 +28,10 @@
28
28
  position: unset;
29
29
  }
30
30
 
31
+ &[data-item-type="heading"]:before {
32
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 64 64' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3Etext %7B font: 72px serif %7D%3C/style%3E%3Ctext x='7' y='56' textLength='48'%3EH%3C/text%3E%3C/svg%3E%0A");
33
+ }
34
+
31
35
  &[data-item-type="link"]:before {
32
36
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 48 48' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0_67_1273)'%3E%3Cpath d='M16 22H32V26H16V22ZM40.2 24H44C44 18.48 39.52 14 34 14H26V17.8H34C37.42 17.8 40.2 20.58 40.2 24ZM7.8 24C7.8 20.58 10.58 17.8 14 17.8H22V14H14C8.48 14 4 18.48 4 24C4 29.52 8.48 34 14 34H22V30.2H14C10.58 30.2 7.8 27.42 7.8 24ZM38 24H34V30H28V34H34V40H38V34H44V30H38V24Z' /%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0_67_1273'%3E%3Crect width='48' height='48' /%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E");
33
37
  }
@@ -10,6 +10,10 @@ module Katalyst
10
10
  render locals: { item: @menu.items.build(type: new_item_params) }
11
11
  end
12
12
 
13
+ def edit
14
+ render locals: { item: @item }
15
+ end
16
+
13
17
  def create
14
18
  item = @menu.items.build(item_params)
15
19
  if item.save
@@ -19,10 +23,6 @@ module Katalyst
19
23
  end
20
24
  end
21
25
 
22
- def edit
23
- render locals: { item: @item }
24
- end
25
-
26
26
  def update
27
27
  @item.attributes = item_params
28
28
 
@@ -41,8 +41,17 @@ module Katalyst
41
41
  params[:type] || Link.name
42
42
  end
43
43
 
44
+ def item_params_type
45
+ type = params.require(:item).fetch(:type, "")
46
+ if Katalyst::Navigation.config.items.include?(type)
47
+ type.safe_constantize
48
+ else
49
+ Item
50
+ end
51
+ end
52
+
44
53
  def item_params
45
- params.require(:item).permit(%i[title url visible http_method new_tab type])
54
+ params.require(:item).permit(item_params_type.permitted_params)
46
55
  end
47
56
 
48
57
  def set_menu
@@ -9,10 +9,22 @@ module Katalyst
9
9
  render locals: { menus: menus, sort: sort }
10
10
  end
11
11
 
12
+ def show
13
+ menu = Menu.find(params[:id])
14
+
15
+ render locals: { menu: menu }
16
+ end
17
+
12
18
  def new
13
19
  render locals: { menu: Menu.new }
14
20
  end
15
21
 
22
+ def edit
23
+ menu = Menu.find(params[:id])
24
+
25
+ render locals: { menu: menu }
26
+ end
27
+
16
28
  def create
17
29
  @menu = Menu.new(menu_params)
18
30
 
@@ -23,18 +35,6 @@ module Katalyst
23
35
  end
24
36
  end
25
37
 
26
- def show
27
- menu = Menu.find(params[:id])
28
-
29
- render locals: { menu: menu }
30
- end
31
-
32
- def edit
33
- menu = Menu.find(params[:id])
34
-
35
- render locals: { menu: menu }
36
- end
37
-
38
38
  # PATCH /admins/navigation_menus/:slug
39
39
  def update
40
40
  menu = Menu.find(params[:id])
@@ -42,7 +42,8 @@ module Katalyst
42
42
  menu.attributes = menu_params
43
43
 
44
44
  unless menu.valid?
45
- return render :show, locals: { menu: menu }, status: :unprocessable_entity
45
+ return render turbo_stream: helpers.navigation_editor_errors(menu: menu),
46
+ status: :unprocessable_entity
46
47
  end
47
48
 
48
49
  case params[:commit]
@@ -0,0 +1,24 @@
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
@@ -14,6 +14,7 @@ module Katalyst
14
14
  def build(options)
15
15
  form_with(model: menu, **default_options(id: menu_form_id, **options)) do |form|
16
16
  concat hidden_input
17
+ concat errors
17
18
  concat(capture { yield form })
18
19
  end
19
20
  end
@@ -26,6 +27,10 @@ module Katalyst
26
27
  tag.input(type: "hidden", name: "#{Item::ATTRIBUTES_SCOPE}[id]")
27
28
  end
28
29
 
30
+ def errors
31
+ Editor::Errors.new(self, menu).build
32
+ end
33
+
29
34
  def default_options(options)
30
35
  add_option(options, :data, :controller, MENU_CONTROLLER)
31
36
  add_option(options, :data, :action, ACTIONS)
@@ -4,11 +4,10 @@ module Katalyst
4
4
  module Navigation
5
5
  module EditorHelper
6
6
  def navigation_editor_new_items(menu)
7
- [
8
- Heading.new(menu: menu),
9
- Link.new(menu: menu),
10
- Button.new(menu: menu),
11
- ]
7
+ Katalyst::Navigation.config.items.map do |item_class|
8
+ item_class = item_class.is_a?(String) ? item_class.safe_constantize : item_class
9
+ item_class.new(menu: menu)
10
+ end
12
11
  end
13
12
 
14
13
  def navigation_editor_menu(menu:, **options, &block)
@@ -26,7 +25,13 @@ module Katalyst
26
25
  Editor::List.new(self, menu).items(item)
27
26
  end
28
27
 
29
- # Gene
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.
30
35
  def navigation_editor_new_item(item:, menu: item.menu, **options, &block)
31
36
  Editor::NewItem.new(self, menu).build(item, **options, &block)
32
37
  end
@@ -1,22 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable Rails/HelperInstanceVariable
3
4
  module Katalyst
4
5
  module Navigation
5
6
  module Frontend
6
7
  class Builder
7
- attr_accessor :template, :menu_options, :list_options, :item_options
8
+ attr_accessor :template
8
9
 
9
10
  delegate_missing_to :@template
10
11
 
11
12
  def initialize(template, list: {}, item: {}, **menu_options)
12
- self.template = template
13
- self.menu_options = menu_options
14
- self.list_options = list
15
- self.item_options = item
13
+ self.template = template
14
+ @menu_options = menu_options.freeze
15
+ @list_options = list.freeze
16
+ @item_options = item.freeze
16
17
  end
17
18
 
18
19
  def render(tree)
19
- tag.ul **menu_options do
20
+ tag.ul(**menu_options(tree)) do
20
21
  tree.each do |item|
21
22
  concat render_item(item)
22
23
  end
@@ -26,32 +27,47 @@ module Katalyst
26
27
  def render_item(item)
27
28
  return unless item.visible?
28
29
 
29
- tag.li **item_options do
30
+ tag.li(**item_options(item)) do
30
31
  concat public_send("render_#{item.model_name.param_key}", item)
31
- concat render_list(item.children) if item.children.any?
32
+ concat render_children(item) if item.children.any?
32
33
  end
33
34
  end
34
35
 
35
- def render_list(items)
36
- tag.ul **list_options do
37
- items.each do |child|
36
+ def render_children(item)
37
+ tag.ul(**list_options(item)) do
38
+ item.children.each do |child|
38
39
  concat render_item(child)
39
40
  end
40
41
  end
41
42
  end
42
43
 
43
44
  def render_heading(heading)
44
- tag.header { tag.p heading.title }
45
+ tag.span(heading.title)
45
46
  end
46
47
 
47
48
  def render_link(link)
48
- link_to(link.title, link.url, item_options)
49
+ link_to(link.title, link.url)
49
50
  end
50
51
 
51
52
  def render_button(link)
52
- link_to(link.title, link.url, **item_options, method: link.http_method)
53
+ link_to(link.title, link.url, method: link.http_method)
54
+ end
55
+
56
+ private
57
+
58
+ def menu_options(_tree)
59
+ @menu_options
60
+ end
61
+
62
+ def list_options(_item)
63
+ @list_options
64
+ end
65
+
66
+ def item_options(_item)
67
+ @item_options
53
68
  end
54
69
  end
55
70
  end
56
71
  end
57
72
  end
73
+ # rubocop:enable Rails/HelperInstanceVariable
@@ -10,6 +10,10 @@ module Katalyst
10
10
 
11
11
  validates :title, :url, :http_method, presence: true
12
12
  validates :http_method, inclusion: { in: HTTP_METHODS.values.map(&:to_s) }
13
+
14
+ def self.permitted_params
15
+ super + %i[http_method]
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -10,6 +10,16 @@ module Katalyst
10
10
 
11
11
  attr_accessor :parent, :children, :index, :depth
12
12
 
13
+ def self.permitted_params
14
+ %i[
15
+ title
16
+ url
17
+ visible
18
+ new_tab
19
+ type
20
+ ]
21
+ end
22
+
13
23
  def layout?
14
24
  is_a? Layout
15
25
  end
@@ -69,6 +69,11 @@ module Katalyst
69
69
  self
70
70
  end
71
71
 
72
+ # Required for testing items validation
73
+ def items_attributes
74
+ draft_version&.nodes&.as_json
75
+ end
76
+
72
77
  # Updates the current draft version with new structure. Attributes should be structural information about the
73
78
  # items, e.g. `{index => {id:, depth:}` or `[{id:, depth:}]`.
74
79
  #
@@ -105,6 +110,8 @@ module Katalyst
105
110
 
106
111
  attribute :nodes, Types::NodesType.new, default: -> { [] }
107
112
 
113
+ validate :ensure_items_exists
114
+
108
115
  def items
109
116
  # support building menus in memory
110
117
  # requires that items are added in order and index and depth are set
@@ -112,12 +119,18 @@ module Katalyst
112
119
 
113
120
  items = parent.items.where(id: nodes.map(&:id)).index_by(&:id)
114
121
  nodes.map do |node|
115
- item = items[node.id]
116
- item.index = node.index
117
- item.depth = node.depth
118
- item
122
+ items[node.id]&.tap do |item|
123
+ item.index = node.index
124
+ item.depth = node.depth
125
+ end
119
126
  end
120
127
  end
128
+
129
+ private
130
+
131
+ def ensure_items_exists
132
+ parent.errors.add(:items, :missing_item) unless items.all?(&:present?)
133
+ end
121
134
  end
122
135
  end
123
136
  end
@@ -2,7 +2,7 @@
2
2
  <div class="tree" data-invisible="<%= !item.visible? %>">
3
3
  <%= builder.accordion_actions %>
4
4
 
5
- <span role="img" value="<%= item.url.present? ? "link" : "title" %>" title="Type"></span>
5
+ <span role="img" value="<%= item.model_name.param_key %>" title="Type"></span>
6
6
  <h4 class="title" title="<%= item.title %>"><%= item.title %></h4>
7
7
  <span role="img" value="invisible" title="Hidden"></span>
8
8
  </div>
@@ -1,4 +1,8 @@
1
1
  en:
2
+ activerecord:
3
+ errors:
4
+ messages:
5
+ missing_item: Items are missing or invalid
2
6
  views:
3
7
  katalyst:
4
8
  navigation:
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/configurable"
4
+
5
+ module Katalyst
6
+ module Navigation
7
+ class Config
8
+ include ActiveSupport::Configurable
9
+
10
+ config_accessor(:items) do
11
+ %w[
12
+ Katalyst::Navigation::Heading
13
+ Katalyst::Navigation::Link
14
+ Katalyst::Navigation::Button
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Katalyst
4
4
  module Navigation
5
- VERSION = "1.2.0"
5
+ VERSION = "1.3.1"
6
6
  end
7
7
  end
@@ -1,9 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "katalyst/navigation/config"
3
4
  require "katalyst/navigation/engine"
4
5
  require "katalyst/navigation/version"
5
6
 
6
7
  module Katalyst
7
8
  module Navigation # :nodoc:
9
+ extend self
10
+
11
+ def config
12
+ @config ||= Config.new
13
+ end
14
+
15
+ def configure
16
+ yield config
17
+ end
8
18
  end
9
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katalyst-navigation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katalyst Interactive
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-25 00:00:00.000000000 Z
11
+ date: 2022-11-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -39,6 +39,7 @@ files:
39
39
  - app/controllers/katalyst/navigation/items_controller.rb
40
40
  - app/controllers/katalyst/navigation/menus_controller.rb
41
41
  - app/helpers/katalyst/navigation/editor/base.rb
42
+ - app/helpers/katalyst/navigation/editor/errors.rb
42
43
  - app/helpers/katalyst/navigation/editor/item.rb
43
44
  - app/helpers/katalyst/navigation/editor/list.rb
44
45
  - app/helpers/katalyst/navigation/editor/menu.rb
@@ -78,6 +79,7 @@ files:
78
79
  - db/migrate/20220826034507_create_katalyst_navigation_items.rb
79
80
  - db/migrate/20220908044500_add_depth_limit_to_menus.rb
80
81
  - lib/katalyst/navigation.rb
82
+ - lib/katalyst/navigation/config.rb
81
83
  - lib/katalyst/navigation/engine.rb
82
84
  - lib/katalyst/navigation/version.rb
83
85
  - lib/tasks/yarn.rake