nitro_kit 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -1
  4. data/Rakefile +6 -4
  5. data/app/components/nitro_kit/accordion.rb +69 -33
  6. data/app/components/nitro_kit/alert.rb +69 -0
  7. data/app/components/nitro_kit/avatar.rb +52 -0
  8. data/app/components/nitro_kit/badge.rb +47 -23
  9. data/app/components/nitro_kit/button.rb +97 -65
  10. data/app/components/nitro_kit/button_group.rb +18 -13
  11. data/app/components/nitro_kit/card.rb +49 -9
  12. data/app/components/nitro_kit/checkbox.rb +59 -41
  13. data/app/components/nitro_kit/checkbox_group.rb +38 -0
  14. data/app/components/nitro_kit/combobox.rb +138 -0
  15. data/app/components/nitro_kit/component.rb +46 -17
  16. data/app/components/nitro_kit/datepicker.rb +9 -0
  17. data/app/components/nitro_kit/dialog.rb +95 -0
  18. data/app/components/nitro_kit/dropdown.rb +116 -73
  19. data/app/components/nitro_kit/field.rb +281 -30
  20. data/app/components/nitro_kit/field_group.rb +10 -5
  21. data/app/components/nitro_kit/fieldset.rb +42 -7
  22. data/app/components/nitro_kit/form_builder.rb +45 -22
  23. data/app/components/nitro_kit/icon.rb +29 -8
  24. data/app/components/nitro_kit/input.rb +26 -0
  25. data/app/components/nitro_kit/label.rb +18 -5
  26. data/app/components/nitro_kit/pagination.rb +98 -0
  27. data/app/components/nitro_kit/radio_button.rb +28 -27
  28. data/app/components/nitro_kit/radio_button_group.rb +53 -0
  29. data/app/components/nitro_kit/select.rb +72 -0
  30. data/app/components/nitro_kit/switch.rb +49 -39
  31. data/app/components/nitro_kit/table.rb +56 -0
  32. data/app/components/nitro_kit/tabs.rb +98 -0
  33. data/app/components/nitro_kit/textarea.rb +26 -0
  34. data/app/components/nitro_kit/toast.rb +104 -0
  35. data/app/components/nitro_kit/tooltip.rb +53 -0
  36. data/app/helpers/nitro_kit/accordion_helper.rb +3 -1
  37. data/app/helpers/nitro_kit/alert_helper.rb +11 -0
  38. data/app/helpers/nitro_kit/avatar_helper.rb +9 -0
  39. data/app/helpers/nitro_kit/badge_helper.rb +3 -5
  40. data/app/helpers/nitro_kit/button_group_helper.rb +2 -0
  41. data/app/helpers/nitro_kit/button_helper.rb +37 -28
  42. data/app/helpers/nitro_kit/card_helper.rb +2 -0
  43. data/app/helpers/nitro_kit/checkbox_helper.rb +19 -16
  44. data/app/helpers/nitro_kit/combobox_helper.rb +9 -0
  45. data/app/helpers/nitro_kit/datepicker_helper.rb +9 -0
  46. data/app/helpers/nitro_kit/dialog_helper.rb +9 -0
  47. data/app/helpers/nitro_kit/dropdown_helper.rb +3 -1
  48. data/app/helpers/nitro_kit/field_group_helper.rb +9 -0
  49. data/app/helpers/nitro_kit/field_helper.rb +4 -2
  50. data/app/helpers/nitro_kit/fieldset_helper.rb +9 -0
  51. data/app/helpers/nitro_kit/form_helper.rb +13 -0
  52. data/app/helpers/nitro_kit/icon_helper.rb +3 -1
  53. data/app/helpers/nitro_kit/input_helper.rb +35 -0
  54. data/app/helpers/nitro_kit/label_helper.rb +12 -8
  55. data/app/helpers/nitro_kit/pagination_helper.rb +42 -0
  56. data/app/helpers/nitro_kit/radio_button_helper.rb +15 -12
  57. data/app/helpers/nitro_kit/select_helper.rb +24 -0
  58. data/app/helpers/nitro_kit/switch_helper.rb +4 -10
  59. data/app/helpers/nitro_kit/table_helper.rb +9 -0
  60. data/app/helpers/nitro_kit/tabs_helper.rb +9 -0
  61. data/app/helpers/nitro_kit/textarea_helper.rb +9 -0
  62. data/app/helpers/nitro_kit/toast_helper.rb +36 -0
  63. data/app/helpers/nitro_kit/tooltip_helper.rb +9 -0
  64. data/lib/generators/nitro_kit/add_generator.rb +38 -41
  65. data/lib/generators/nitro_kit/install_generator.rb +2 -1
  66. data/lib/nitro_kit/engine.rb +4 -0
  67. data/lib/nitro_kit/schema_builder.rb +90 -16
  68. data/lib/nitro_kit/version.rb +1 -1
  69. data/lib/nitro_kit.rb +39 -1
  70. data/lib/tasks/nitro_kit_tasks.rake +4 -0
  71. metadata +40 -12
  72. data/app/components/nitro_kit/radio_group.rb +0 -35
  73. data/app/helpers/application_helper.rb +0 -89
  74. data/lib/nitro_kit/railtie.rb +0 -8
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ class Tabs < Component
5
+ def initialize(default: nil, **attrs)
6
+ @default = default
7
+ @id = attrs[:id] || SecureRandom.hex(6)
8
+
9
+ super(
10
+ attrs,
11
+ data: {controller: "nk--tabs", nk__tabs_active_value: default},
12
+ class: base_class
13
+ )
14
+ end
15
+
16
+ attr_reader :default, :id
17
+
18
+ def view_template
19
+ div(**attrs) do
20
+ yield
21
+ end
22
+ end
23
+
24
+ def tabs(**attrs)
25
+ div(**mattr, role: "tabtabs", class: tabs_class) do
26
+ yield
27
+ end
28
+ end
29
+
30
+ def tab(key, text = nil, **attrs, &block)
31
+ button(
32
+ **mattr(
33
+ attrs,
34
+ aria: {
35
+ selected: (default == key).to_s,
36
+ controls: tab_id(key, :panel)
37
+ },
38
+ class: tab_class,
39
+ data: {
40
+ action: "nk--tabs#setActiveTab keydown.left->nk--tabs#prevTab keydown.right->nk--tabs#nextTab",
41
+ key:,
42
+ nk__tabs_key_param: key,
43
+ nk__tabs_target: "tab"
44
+ },
45
+ id: tab_id(key, :tab),
46
+ role: "tab",
47
+ tabindex: default == key ? 0 : -1
48
+ )
49
+ ) do
50
+ text_or_block(text, &block)
51
+ end
52
+ end
53
+
54
+ def panel(key, **attrs)
55
+ div(
56
+ **mattr(
57
+ attrs,
58
+ aria: {
59
+ hidden: (default != key).to_s,
60
+ labelledby: tab_id(key, :tab)
61
+ },
62
+ class: panel_class,
63
+ data: {
64
+ key:,
65
+ nk__tabs_target: "panel"
66
+ },
67
+ id: tab_id(key, :panel),
68
+ name: key,
69
+ role: "tabpanel"
70
+ )
71
+ ) do
72
+ yield
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def tab_id(key, suffix)
79
+ "#{id}-#{key}-#{suffix}"
80
+ end
81
+
82
+ def base_class
83
+ "w-full"
84
+ end
85
+
86
+ def tabs_class
87
+ "flex gap-4 border-b h-10"
88
+ end
89
+
90
+ def tab_class
91
+ "border-b-2 border-transparent hover:border-primary focus-visible:border-primary cursor-pointer text-muted-foreground aria-[selected=true]:text-foreground font-medium aria-[selected=true]:border-primary -mb-px px-2"
92
+ end
93
+
94
+ def panel_class
95
+ "aria-[hidden=true]:hidden py-4"
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ class Textarea < Component
5
+ def initialize(**attrs)
6
+ super(
7
+ attrs,
8
+ class: default_class
9
+ )
10
+ end
11
+
12
+ def view_template
13
+ textarea(**attrs)
14
+ end
15
+
16
+ private
17
+
18
+ def default_class
19
+ [
20
+ "rounded-md border bg-background border-border text-base px-3 py-2",
21
+ # Focus
22
+ "focus:outline-none ring-ring ring-offset-2 ring-offset-background focus-visible:ring-2"
23
+ ]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ class Toast < Component
5
+ class Item < Component
6
+ VARIANTS = %i[default warning error success]
7
+
8
+ def initialize(title: nil, description: nil, variant: :default, **attrs)
9
+ @title = title
10
+ @description = description
11
+ @variant = variant
12
+
13
+ super(
14
+ **mattr(
15
+ attrs,
16
+ class: [
17
+ base_class,
18
+ variant_class
19
+ ],
20
+ role: "status",
21
+ aria: {live: "off", atomic: "true"},
22
+ tabindex: "0",
23
+ data: {state: "closed"}
24
+ )
25
+ )
26
+ end
27
+
28
+ attr_reader :title, :description, :variant
29
+
30
+ def view_template(&block)
31
+ li(**attrs) do
32
+ div(class: "grid gap-1") do
33
+ div(class: "text-sm font-semibold", data: {slot: "title"}) do
34
+ title && plain(title)
35
+ end
36
+
37
+ div(class: "text-sm opacity-90", data: {slot: "description"}) do
38
+ text_or_block(description, &block)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def base_class
47
+ "shrink-0 pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md p-4 pr-8 shadow-lg transition-all border opacity-0 transition-all data-[state=open]:opacity-100 data-[state=open]:-translate-y-full"
48
+ end
49
+
50
+ def variant_class
51
+ case variant
52
+ when :default
53
+ "border-border bg-background text-foreground"
54
+ when :warning
55
+ "bg-yellow-50 dark:bg-yellow-950 text-yellow-900 dark:text-yellow-100 border-yellow-500/80 dark:border-yellow-400/50"
56
+ when :success
57
+ "bg-green-50 dark:bg-green-950 text-green-900 dark:text-green-100 border-green-500/80 dark:border-green-400/50"
58
+ when :error
59
+ "bg-red-50 dark:bg-red-950 text-red-900 dark:text-red-100 border-red-400/80 dark:border-red-400/50"
60
+ else
61
+ raise ArgumentError, "Invalid variant `#{variant}'"
62
+ end
63
+ end
64
+ end
65
+
66
+ def initialize(**attrs)
67
+ super(
68
+ attrs,
69
+ role: "region",
70
+ tabindex: "-1",
71
+ aria: {label: "Notifications"},
72
+ class: "pointer-events-none"
73
+ )
74
+ end
75
+
76
+ def view_template
77
+ div(**attrs) do
78
+ ol(class: list_class, data: {nk__toast_target: "list"})
79
+ end
80
+
81
+ flash_sink
82
+
83
+ template(data: {nk__toast_target: "template"}) do
84
+ item
85
+ end
86
+ end
87
+
88
+ def item(title: nil, description: nil, **attrs, &block)
89
+ render(Item.new(title:, description:, **attrs), &block)
90
+ end
91
+
92
+ def flash_sink
93
+ div(id: "nk--toast-sink", data: {nk__toast_target: "sink"}, hidden: true) do
94
+ helpers.nk_toast_flash_messages
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def list_class
101
+ "fixed z-[100] flex max-h-screen w-full p-5 bottom-0 right-0 flex-col h-0 md:max-w-[420px]"
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ class Tooltip < Component
5
+ def initialize(content: nil, placement: nil, **attrs)
6
+ @string_content = content
7
+ @placement = placement
8
+
9
+ super(
10
+ attrs,
11
+ data: {
12
+ action: "mouseover->nk--tooltip#open mouseout->nk--tooltip#close",
13
+ controller: "nk--tooltip",
14
+ nk__tooltip_placement_value: placement
15
+ }
16
+ )
17
+ end
18
+
19
+ attr_reader :placement, :string_content
20
+
21
+ def view_template
22
+ span(**attrs) do
23
+ content(string_content) if string_content
24
+ yield
25
+ end
26
+ end
27
+
28
+ def content(text = nil, **attrs, &block)
29
+ div(
30
+ **mattr(
31
+ attrs,
32
+ class: tooltip_class,
33
+ data: {
34
+ state: "closed",
35
+ nk__tooltip_target: "content"
36
+ }
37
+ )
38
+ ) do
39
+ text_or_block(text, &block)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def tooltip_class
46
+ [
47
+ "absolute z-50 overflow-hidden w-fit max-w-sm",
48
+ "px-3 py-1.5 text-sm bg-background rounded-md border shadow-sm",
49
+ "data-[state=closed]:hidden"
50
+ ]
51
+ end
52
+ end
53
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module AccordionHelper
3
5
  def nk_accordion(**attrs, &block)
4
6
  render(Accordion.new(**attrs), &block)
5
7
  end
6
8
  end
7
- end
9
+ end
@@ -0,0 +1,11 @@
1
+ module NitroKit
2
+ module AlertHelper
3
+ include Variants
4
+
5
+ def nk_alert(**attrs, &block)
6
+ render(Alert.new(**attrs), &block)
7
+ end
8
+
9
+ automatic_variants(Alert::VARIANTS, :nk_alert)
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module AvatarHelper
5
+ def nk_avatar(src = nil, **attrs, &block)
6
+ render(Avatar.new(src, **attrs), &block)
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module BadgeHelper
3
5
  include Variants
@@ -5,11 +7,7 @@ module NitroKit
5
7
  automatic_variants(Badge::VARIANTS, :nk_badge)
6
8
 
7
9
  def nk_badge(text = nil, **attrs, &block)
8
- content = text || capture(&block)
9
-
10
- render(NitroKit::Badge.new(**attrs)) do
11
- content
12
- end
10
+ render(NitroKit::Badge.new(text, **attrs), &block)
13
11
  end
14
12
  end
15
13
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module ButtonGroupHelper
3
5
  def nk_button_group(**attrs, &block)
@@ -1,40 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module ButtonHelper
3
5
  include Variants
4
6
 
7
+ def nk_button(text = nil, **attrs, &block)
8
+ render(NitroKit::Button.new(text, **attrs), &block)
9
+ end
10
+
5
11
  automatic_variants(Button::VARIANTS, :nk_button)
6
12
 
7
- def nk_button(
8
- text_or_href = nil,
9
- href = nil,
10
- icon: nil,
11
- icon_right: nil,
12
- size: :base,
13
- type: :button,
14
- variant: :default,
15
- **attrs,
16
- &block
17
- )
18
- content = block_given? ? capture(&block) : text_or_href
19
- href = text_or_href if href.nil? && block_given?
20
-
21
- if href && !href.is_a?(String)
22
- href = url_for(href)
13
+ # Matches the API of UrlHelper#button_to
14
+ def nk_button_to(name = nil, url_for_options = nil, **attrs, &block)
15
+ url_for_options = name if block_given?
16
+
17
+ form_options = attrs.delete(:form) || {}
18
+ form_options.merge!(attrs.slice(:multipart, :data, :method, :authenticity_token, :remote, :enforce_utf8))
19
+
20
+ form_tag(url_for_options, form_options) do
21
+ nk_button(name, type: "submit", **attrs, &block)
23
22
  end
23
+ end
24
24
 
25
- render(
26
- NitroKit::Button.new(
27
- href:,
28
- icon:,
29
- icon_right:,
30
- size:,
31
- type:,
32
- variant:,
33
- **attrs
34
- )
35
- ) do
36
- content
25
+ automatic_variants(Button::VARIANTS, :nk_button_to)
26
+
27
+ # Matches the API of UrlHelper#link_to
28
+ def nk_button_link_to(*args, **attrs, &block)
29
+ case args.length
30
+ when 1
31
+ options, text = args
32
+ when 2
33
+ text, options = args
34
+ else
35
+ raise ArgumentError, "1..2 arguments expected, got #{args.length}"
37
36
  end
37
+
38
+ href = attrs[:href] || url_target(text, options)
39
+
40
+ render(NitroKit::Button.new(text, **attrs, href:), &block)
41
+ end
42
+
43
+ automatic_variants(Button::VARIANTS, :nk_button_link_to)
44
+
45
+ def nk_button_group(**attrs, &block)
46
+ render(ButtonGroup.new(**attrs), &block)
38
47
  end
39
48
  end
40
49
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module CardHelper
3
5
  def nk_card(**attrs, &block)
@@ -1,24 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module CheckboxHelper
3
- # Match the signature of the Rails `check_box` helper
4
- def nk_checkbox(name, *args)
5
- if args.length >= 4
6
- raise ArgumentError, "wrong number of arguments (given #{args.length + 1}, expected 1..4)"
7
- end
8
-
9
- options = args.extract_options!
10
- value, checked = args.empty? ? ["1", false] : [*args, false]
5
+ # Make API compatible with Rails' checkbox but allow empty arguments
6
+ def nk_checkbox(
7
+ compat_object_name = nil,
8
+ compat_method = nil,
9
+ compat_options = {},
10
+ compat_checked_value = "1",
11
+ compat_unchecked_value = "0",
12
+ label: nil,
13
+ **attrs
14
+ )
15
+ name = field_name(compat_object_name, compat_method)
16
+ checked = compat_options["checked"] || attrs[:checked]
11
17
 
12
- attrs = {
13
- :type => "checkbox",
14
- :name => name,
15
- :id => sanitize_to_id(name),
16
- :value => value
17
- }.update(options.symbolize_keys)
18
+ # TODO: multiple, unchecked hidden field
18
19
 
19
- attrs[:checked] = "checked" if checked
20
+ render(Checkbox.new(name:, label:, value: compat_checked_value, checked:, **attrs))
21
+ end
20
22
 
21
- render(NitroKit::Checkbox.new(name, value:, **attrs))
23
+ def nk_checkbox_group(**attrs, &block)
24
+ render(CheckboxGroup.new(**attrs), &block)
22
25
  end
23
26
  end
24
27
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module ComboboxHelper
5
+ def nk_combobox(name = nil, options = [], **attrs)
6
+ render(NitroKit::Combobox.new(name:, options:, **attrs))
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module DatepickerHelper
5
+ def nk_datepicker(**attrs, &block)
6
+ render(Datepicker.new(**attrs), &block)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module DialogHelper
5
+ def nk_dialog(**attrs, &block)
6
+ render(Dialog.new(**attrs), &block)
7
+ end
8
+ end
9
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module DropdownHelper
3
5
  def nk_dropdown(**attrs, &block)
4
- render(NitroKit::Dropdown.new(**attrs), &block)
6
+ render(Dropdown.new(**attrs), &block)
5
7
  end
6
8
  end
7
9
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module FieldGroupHelper
5
+ def nk_field_group(**attrs)
6
+ render(NitroKit::FieldGroup.new(**attrs)) { yield }
7
+ end
8
+ end
9
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module FieldHelper
3
- def nk_field(attribute, **options)
4
- render(NitroKit::Field.new(attribute, **options))
5
+ def nk_field(*args, **attrs, &block)
6
+ render(NitroKit::Field.new(*args, **attrs), &block)
5
7
  end
6
8
  end
7
9
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module FieldsetHelper
5
+ def nk_fieldset(**attrs, &block)
6
+ render(NitroKit::Fieldset.new(**attrs), &block)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module FormHelper
5
+ def nk_form_with(**attrs, &block)
6
+ form_with(**attrs, builder: NitroKit::FormBuilder, &block)
7
+ end
8
+
9
+ def nk_form_for(*args, **attrs, &block)
10
+ form_for(*args, **attrs, builder: NitroKit::FormBuilder, &block)
11
+ end
12
+ end
13
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module IconHelper
3
5
  def nk_icon(name, **attrs)
4
- render(NitroKit::Icon.new(name: name, **attrs))
6
+ render(NitroKit::Icon.new(name, **attrs))
5
7
  end
6
8
  end
7
9
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module InputHelper
5
+ def nk_input(**attrs)
6
+ render(Input.new(**attrs))
7
+ end
8
+
9
+ %w[
10
+ color
11
+ date
12
+ datetime
13
+ datetime_local
14
+ email
15
+ file
16
+ hidden
17
+ month
18
+ number
19
+ password
20
+ phone
21
+ range
22
+ search
23
+ telephone
24
+ text
25
+ time
26
+ url
27
+ week
28
+ ]
29
+ .each do |type|
30
+ define_method("nk_#{type}_field") do |**attrs|
31
+ nk_input(type:, **attrs)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,15 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module NitroKit
2
4
  module LabelHelper
3
- def nk_label(name = nil, content_or_options = nil, options = nil, &block)
4
- if block_given? && content_or_options.is_a?(Hash)
5
- options = content_or_options = content_or_options.symbolize_keys
6
- else
7
- options ||= {}
8
- options = options.symbolize_keys
5
+ def nk_label(compat_object_name = nil, compat_method = nil, content_or_options = nil, **attrs, &block)
6
+ name = field_name(compat_object_name, compat_method)
7
+
8
+ case content_or_options
9
+ when String
10
+ text = content_or_options
11
+ when Hash
12
+ text = nil
13
+ attrs.merge!(content_or_options)
9
14
  end
10
15
 
11
- options[:for] = sanitize_to_id(name) unless name.blank? || options.has_key?("for")
12
- render(Label.new(**options)) { content_or_options || name.to_s.humanize || yield }
16
+ render(Label.new(text, for: name, **attrs), &block)
13
17
  end
14
18
  end
15
19
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NitroKit
4
+ module PaginationHelper
5
+ include Pagy::UrlHelpers if defined?(Pagy)
6
+
7
+ def nk_pagination(**attrs, &block)
8
+ render(Pagination.new(**attrs), &block)
9
+ end
10
+
11
+ def nk_pagy_nav(pagy, id: nil, aria_label: nil, **attrs)
12
+ attrs[:aria] ||= {label: aria_label}
13
+
14
+ nk_pagination(id:, **attrs) do |p|
15
+ if prev_page = pagy.prev
16
+ p.prev(href: pagy_url_for(pagy, prev_page))
17
+ else
18
+ p.prev(disabled: true)
19
+ end
20
+
21
+ pagy.series.each do |item|
22
+ case item
23
+ when Integer
24
+ p.page(item.to_s, href: pagy_url_for(pagy, item))
25
+ when String
26
+ p.page(item, current: true)
27
+ when :gap
28
+ p.ellipsis
29
+ else
30
+ raise ArgumentError, "Unknown item type: #{item.class}"
31
+ end
32
+ end
33
+
34
+ if next_page = pagy.next
35
+ p.next(href: pagy_url_for(pagy, next_page))
36
+ else
37
+ p.next(disabled: true)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end