ariadne_view_components 0.0.94.4 → 0.0.94.5

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