ariadne_view_components 0.0.94.4 → 0.0.94.6

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.
@@ -6,23 +6,116 @@ module Ariadne
6
6
  module Pagination
7
7
  # Pagination is a horizontal set of links to navigate paginated content.
8
8
  class Component < Ariadne::BaseComponent
9
- option :label
10
- option :goto_label
11
-
12
- option :current_page
13
- option :pages_count
9
+ # Required props:
10
+ # - total_count: Total number of items to paginate.
11
+ # - current_page: Current page number.
12
+ # - items_per_page: Number of items per page.
13
+ # - label: Main label for screen readers (e.g., "Pagination").
14
+ # - goto_label: Label prefix for page links (e.g., "Go to page").
15
+ # - callback_page_url: Lambda that receives a page number and returns the URL.
16
+ # - callback_per_page_change: Lambda that receives a per_page value and returns the URL.
17
+ # - per_page_options: Array of allowed page sizes (e.g., [10, 25, 50, 100]).
18
+ # - frame_id: Turbo frame identifier (if applicable).
19
+ # - show_results_counter: Boolean indicating whether to display the results counter.
14
20
 
21
+ # Use dry-initializer for props
22
+ option :total_count
23
+ option :current_page, default: proc { 1 }
24
+ option :items_per_page, default: proc { 10 }
25
+ option :label, default: proc { I18n.t("pagy.aria_label.nav", default: "Pagination") }
26
+ option :goto_label, default: proc { I18n.t("pagy.goto_label", default: "Go to page") }
15
27
  option :callback_page_url
28
+ option :callback_per_page_change
29
+ option :per_page_options
30
+ option :frame_id
31
+ option :show_results_counter, default: proc { true }
32
+
33
+ def initialize(**options)
34
+ super
35
+ @calculator = Ariadne::PaginationCalculator.new(
36
+ total_count: total_count,
37
+ page: current_page,
38
+ items_per_page: items_per_page,
39
+ )
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :calculator
16
45
 
17
46
  def page_links
18
- (1..pages_count).each_with_object([]) do |page, list|
19
- if [1, pages_count].include?(page) || page.between?(current_page - 2, current_page + 2)
20
- list << page
21
- elsif list.last
22
- list << nil
23
- end
47
+ calculator.page_series
48
+ end
49
+
50
+ def component_classes
51
+ merge_tailwind_classes(
52
+ "ariadne-flex ariadne-items-center ariadne-justify-between ariadne-w-full",
53
+ )
54
+ end
55
+
56
+ def link_classes(is_active = false)
57
+ base_classes = "ariadne-inline-flex ariadne-items-center ariadne-justify-center ariadne-min-w-[2rem] ariadne-h-8 ariadne-px-2 ariadne-text-sm ariadne-font-medium ariadne-rounded-md"
58
+
59
+ active_classes = if is_active
60
+ "ariadne-bg-gray-100 dark:ariadne-bg-gray-700 ariadne-text-gray-900 dark:ariadne-text-white ariadne-cursor-default"
61
+ else
62
+ "ariadne-transition-colors ariadne-text-gray-600 hover:ariadne-bg-gray-50 dark:ariadne-text-gray-300 dark:hover:ariadne-bg-gray-700 ariadne-cursor-pointer"
63
+ end
64
+
65
+ merge_tailwind_classes([base_classes, active_classes])
66
+ end
67
+
68
+ def disabled_link_classes
69
+ merge_tailwind_classes(
70
+ "ariadne-inline-flex ariadne-items-center ariadne-justify-center ariadne-min-w-[2rem] ariadne-h-8 ariadne-px-2 ariadne-text-sm ariadne-font-medium ariadne-rounded-md ariadne-text-gray-300 dark:ariadne-text-gray-600 ariadne-cursor-not-allowed",
71
+ )
72
+ end
73
+
74
+ def ellipsis_classes
75
+ merge_tailwind_classes(
76
+ "ariadne-inline-flex ariadne-items-center ariadne-justify-center ariadne-min-w-[2rem] ariadne-h-8 ariadne-px-1 ariadne-text-sm ariadne-font-medium ariadne-text-gray-500 dark:ariadne-text-gray-400",
77
+ )
78
+ end
79
+
80
+ def select_classes
81
+ merge_tailwind_classes(
82
+ "ariadne-h-8 ariadne-pl-2 ariadne-pr-8 ariadne-text-sm ariadne-font-medium ariadne-rounded-md ariadne-border ariadne-border-gray-300 dark:ariadne-border-gray-600 ariadne-bg-white dark:ariadne-bg-gray-800 ariadne-text-gray-700 dark:ariadne-text-gray-200 hover:ariadne-border-primary-500 focus:ariadne-outline-none focus:ariadne-ring-1 focus:ariadne-ring-primary-500 focus:ariadne-border-primary-500",
83
+ )
84
+ end
85
+
86
+ def counter_classes
87
+ merge_tailwind_classes(
88
+ "ariadne-text-sm ariadne-text-gray-700 dark:ariadne-text-gray-300 ariadne-font-medium",
89
+ )
90
+ end
91
+
92
+ def formatted_info
93
+ {
94
+ text: "#{calculator.from}-#{calculator.to} of #{total_count}",
95
+ role: "status",
96
+ aria: { live: "polite" },
97
+ }
98
+ end
99
+
100
+ def select_options
101
+ per_page_options.map do |size|
102
+ {
103
+ value: callback_per_page_change.call(size),
104
+ label: "#{size} per page",
105
+ selected: size == items_per_page,
106
+ }
24
107
  end
25
108
  end
109
+
110
+ def current_per_page_option
111
+ select_options.find { |option| option[:selected] } || select_options.first
112
+ end
113
+
114
+ def nav_section_classes
115
+ merge_tailwind_classes(
116
+ "ariadne-flex ariadne-items-center ariadne-gap-1 ariadne-justify-center",
117
+ )
118
+ end
26
119
  end
27
120
  end
28
121
  end
@@ -0,0 +1,42 @@
1
+ import {controllerFactory} from '@utils/createController'
2
+
3
+ export default class PaginationController extends controllerFactory<HTMLElement>()({
4
+ targets: {
5
+ perPage: HTMLSelectElement,
6
+ },
7
+ }) {
8
+ connect(): void {
9
+
10
+ }
11
+
12
+ /**
13
+ * Handles changes to the per-page selector
14
+ */
15
+ perPageChange(event: Event): void {
16
+ event.preventDefault()
17
+ const select = event.target as HTMLSelectElement
18
+ const value = select.value
19
+
20
+ // Get the current URL and update it
21
+ const url = new URL(window.location.href)
22
+ const newParams = new URLSearchParams(value.split('?')[1])
23
+
24
+ // Update the URL with new parameters
25
+ newParams.forEach((value, key) => {
26
+ url.searchParams.set(key, value)
27
+ })
28
+
29
+ window.location.href = url.toString()
30
+ }
31
+
32
+ /**
33
+ * Handles clicks on pagination links
34
+ */
35
+ navigate(event: Event): void {
36
+ const link = (event.target as HTMLElement).closest('a')
37
+ if (!link) return
38
+
39
+ event.preventDefault()
40
+ window.location.href = link.href
41
+ }
42
+ }
@@ -0,0 +1,78 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Ariadne
5
+ # Handles pagination calculations and data structure
6
+ class PaginationCalculator
7
+ attr_reader :total_count, :page, :items_per_page, :pages
8
+
9
+ def initialize(total_count:, page: 1, items_per_page: 10)
10
+ @total_count = total_count
11
+ @items_per_page = items_per_page
12
+ @pages = calculate_total_pages
13
+ @page = handle_page_overflow(page)
14
+ end
15
+
16
+ def from
17
+ return 0 if total_count.zero?
18
+
19
+ (page - 1) * items_per_page + 1
20
+ end
21
+
22
+ def to
23
+ return 0 if total_count.zero?
24
+
25
+ [page * items_per_page, total_count].min
26
+ end
27
+
28
+ def next_page
29
+ page < pages ? page + 1 : nil
30
+ end
31
+
32
+ def prev_page
33
+ page > 1 ? page - 1 : nil
34
+ end
35
+
36
+ def page_series
37
+ return [] if pages <= 1
38
+ return (1..pages).to_a if pages <= 5
39
+
40
+ links = []
41
+ links << 1
42
+
43
+ if page <= 3
44
+ # Near the beginning: 1 2 3 4 5 6 7 8 ... 20
45
+ (2..8).each { |n| links << n if n <= pages }
46
+ links << nil if pages > 8
47
+ links << pages if pages > 8
48
+ elsif page >= pages - 2
49
+ # Near the end: 1 ... 13 14 15 16 17 18 19 20
50
+ links << nil
51
+ ((pages - 7)..pages).each { |n| links << n if n > 1 }
52
+ else
53
+ # Middle range: 1 ... 9 10 11 12 13 14 ... 20
54
+ links << nil
55
+ ((page - 2)..(page + 2)).each { |n| links << n }
56
+ links << nil
57
+ links << pages
58
+ end
59
+
60
+ links
61
+ end
62
+
63
+ private
64
+
65
+ def calculate_total_pages
66
+ return 1 if total_count.zero?
67
+
68
+ (total_count.to_f / items_per_page).ceil
69
+ end
70
+
71
+ def handle_page_overflow(requested_page)
72
+ return 1 if requested_page < 1
73
+ return pages if requested_page > pages
74
+
75
+ requested_page
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pagy"
4
+
5
+ # Only require the necessary extras:
6
+ require "pagy/extras/overflow" # Handles overflow scenarios gracefully.
7
+ require "pagy/extras/metadata" # Provides metadata for JSON/client-side rendering.
8
+ require "pagy/extras/headers" # Useful for API responses (if needed).
9
+ require "pagy/extras/keyset" # For efficient keyset pagination with large data sets.
10
+ require "pagy/extras/array" # Required for series method
11
+
12
+ # Customize default settings:
13
+ Pagy::DEFAULT[:limit] = 10 # Default items per page.
14
+ Pagy::DEFAULT[:size] = 9 # Number of links in the nav bar.
15
+ Pagy::DEFAULT[:overflow] = :last_page
@@ -3,6 +3,6 @@
3
3
  # :nocov:
4
4
  module Ariadne
5
5
  module ViewComponents
6
- VERSION = "0.0.94.4"
6
+ VERSION = "0.0.94.6"
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ariadne_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.94.4
4
+ version: 0.0.94.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen J. Torikian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-20 00:00:00.000000000 Z
11
+ date: 2025-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tailwind_merge
@@ -265,6 +265,7 @@ files:
265
265
  - app/frontend/ariadne/theme.ts
266
266
  - app/frontend/controllers/form_autosubmit_controller.ts
267
267
  - app/frontend/controllers/form_validity_controller.ts
268
+ - app/frontend/controllers/pagination_controller.ts
268
269
  - app/frontend/controllers/tooltip_controller.ts
269
270
  - app/frontend/entrypoints/application.ts
270
271
  - app/frontend/stylesheets/ariadne_view_components.css
@@ -281,9 +282,11 @@ files:
281
282
  - app/lib/ariadne/form.rb
282
283
  - app/lib/ariadne/icon_helper.rb
283
284
  - app/lib/ariadne/logger_helper.rb
285
+ - app/lib/ariadne/pagination_calculator.rb
284
286
  - app/lib/ariadne/view_component/html_attrs.rb
285
287
  - app/lib/ariadne/view_component/style_variants.rb
286
288
  - app/lib/ariadne/view_helper.rb
289
+ - config/initializers/pagy.rb
287
290
  - lib/ariadne/accessibility.rb
288
291
  - lib/ariadne/forms/acts_as_component.rb
289
292
  - lib/ariadne/forms/base.html.erb