openproject-primer_view_components 0.83.1 → 0.84.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/app/assets/styles/primer_view_components.css +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/open_project/pagination.css +1 -0
- data/app/components/primer/open_project/pagination.css.json +24 -0
- data/app/components/primer/open_project/pagination.css.map +1 -0
- data/app/components/primer/open_project/pagination.html.erb +15 -0
- data/app/components/primer/open_project/pagination.pcss +86 -0
- data/app/components/primer/open_project/pagination.rb +277 -0
- data/app/components/primer/primer.pcss +1 -0
- data/config/locales/en.yml +8 -0
- data/lib/primer/view_components/version.rb +2 -2
- data/previews/primer/open_project/pagination_preview/default.html.erb +7 -0
- data/previews/primer/open_project/pagination_preview/playground.html.erb +10 -0
- data/previews/primer/open_project/pagination_preview.rb +53 -0
- data/static/arguments.json +9 -0
- data/static/audited_at.json +1 -0
- data/static/classes.json +6 -0
- data/static/constants.json +10 -0
- data/static/info_arch.json +83 -0
- data/static/previews.json +34 -0
- data/static/statuses.json +1 -0
- metadata +11 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.Page{align-items:center;border-radius:var(--borderRadius-medium,.375rem);color:var(--fgColor-default);cursor:pointer;display:inline-flex;height:var(--base-size-32);justify-content:center;margin-right:var(--base-size-4);min-width:var(--base-size-32);padding:var(--base-size-8) var(--base-size-6);transition:background-color .2s cubic-bezier(.3,0,.5,1);vertical-align:middle;white-space:nowrap}.Page[rel=next]>svg,.Page[rel=prev]>svg{height:var(--base-size-16);width:var(--base-size-16)}.Page[rel=prev]>svg{margin-inline-end:var(--base-size-4)}.Page[rel=next]>svg{margin-inline-start:var(--base-size-4)}.Page:last-child{margin-right:0}.Page:focus,.Page:hover{background-color:var(--control-transparent-bgColor-hover);outline:0;-webkit-text-decoration:none;text-decoration:none;transition-duration:.1s}.Page:focus-visible{outline:2px solid var(--bgColor-accent-emphasis)}.Page:active{border-color:var(--borderColor-muted)}.Page[rel=next],.Page[rel=prev]{color:var(--fgColor-accent)}.Page[aria-current],.Page[aria-current]:hover{background-color:var(--bgColor-accent-emphasis);border-color:#0000;color:var(--fgColor-onEmphasis)}.Page[aria-current]:focus-visible{box-shadow:inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis);outline:2px solid var(--bgColor-accent-emphasis)}.Page[aria-hidden],.Page[aria-hidden]:hover,.Page[role=presentation],.Page[role=presentation]:hover{background-color:initial;color:var(--fgColor-disabled);cursor:default}.PaginationContainer{margin:var(--base-size-16) 0;text-align:center}@media (max-width:543.98px){.Page:not([rel=prev]):not([rel=next]){display:none}}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "open_project/pagination",
|
|
3
|
+
"selectors": [
|
|
4
|
+
".Page",
|
|
5
|
+
".Page[rel=next]>svg",
|
|
6
|
+
".Page[rel=prev]>svg",
|
|
7
|
+
".Page:last-child",
|
|
8
|
+
".Page:focus",
|
|
9
|
+
".Page:hover",
|
|
10
|
+
".Page:focus-visible",
|
|
11
|
+
".Page:active",
|
|
12
|
+
".Page[rel=next]",
|
|
13
|
+
".Page[rel=prev]",
|
|
14
|
+
".Page[aria-current]",
|
|
15
|
+
".Page[aria-current]:hover",
|
|
16
|
+
".Page[aria-current]:focus-visible",
|
|
17
|
+
".Page[aria-hidden]",
|
|
18
|
+
".Page[aria-hidden]:hover",
|
|
19
|
+
".Page[role=presentation]",
|
|
20
|
+
".Page[role=presentation]:hover",
|
|
21
|
+
".PaginationContainer",
|
|
22
|
+
".Page:not([rel=prev]):not([rel=next])"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["pagination.pcss"],"names":[],"mappings":"AAAA,MAYE,kBAAmB,CAHnB,gDAAiD,CAJjD,4BAA6B,CAG7B,cAAe,CAGf,mBAAoB,CATpB,0BAA2B,CAW3B,sBAAuB,CATvB,+BAAgC,CAHhC,6BAA8B,CAE9B,6CAA8C,CAO9C,uDAA8D,CAH9D,qBAAsB,CADtB,kBAQF,CAEA,wCAEE,0BAA2B,CAC3B,yBACF,CAEA,oBACE,oCACF,CAEA,oBACE,sCACF,CAEA,iBACE,cACF,CAEA,wBAGE,yDAA0D,CAC1D,SAAU,CAFV,4BAAqB,CAArB,oBAAqB,CAGrB,uBACF,CAEA,oBACE,gDACF,CAEA,aACE,qCACF,CAEA,gCAEE,2BACF,CAEA,8CAGE,+CAAgD,CAChD,kBAAyB,CAFzB,+BAGF,CAEA,kCAEE,mEAAoE,CADpE,gDAEF,CAEA,oGAME,wBAA6B,CAF7B,6BAA8B,CAC9B,cAEF,CAEA,qBACE,4BAA6B,CAC7B,iBACF,CAEA,4BACE,sCACE,YACF,CACF","file":"pagination.css","sourcesContent":[".Page {\n min-width: var(--base-size-32);\n height: var(--base-size-32);\n padding: var(--base-size-8) var(--base-size-6);\n margin-right: var(--base-size-4);\n color: var(--fgColor-default);\n white-space: nowrap;\n vertical-align: middle;\n cursor: pointer;\n border-radius: var(--borderRadius-medium,.375rem);\n transition: background-color 0.2s cubic-bezier(0.3, 0, 0.5, 1);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.Page[rel='prev'] > svg,\n.Page[rel='next'] > svg {\n height: var(--base-size-16);\n width: var(--base-size-16);\n}\n\n.Page[rel='prev'] > svg {\n margin-inline-end: var(--base-size-4);\n}\n\n.Page[rel='next'] > svg {\n margin-inline-start: var(--base-size-4);\n}\n\n.Page:last-child {\n margin-right: 0;\n}\n\n.Page:hover,\n.Page:focus {\n text-decoration: none;\n background-color: var(--control-transparent-bgColor-hover);\n outline: 0;\n transition-duration: 0.1s;\n}\n\n.Page:focus-visible {\n outline: 2px solid var(--bgColor-accent-emphasis);\n}\n\n.Page:active {\n border-color: var(--borderColor-muted);\n}\n\n.Page[rel='prev'],\n.Page[rel='next'] {\n color: var(--fgColor-accent);\n}\n\n.Page[aria-current],\n.Page[aria-current]:hover {\n color: var(--fgColor-onEmphasis);\n background-color: var(--bgColor-accent-emphasis);\n border-color: transparent;\n}\n\n.Page[aria-current]:focus-visible {\n outline: 2px solid var(--bgColor-accent-emphasis);\n box-shadow: inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis);\n}\n\n.Page[aria-hidden],\n.Page[aria-hidden]:hover,\n.Page[role='presentation'],\n.Page[role='presentation']:hover {\n color: var(--fgColor-disabled);\n cursor: default;\n background-color: transparent;\n}\n\n.PaginationContainer {\n margin: var(--base-size-16) 0;\n text-align: center;\n}\n\n@media (max-width: 543.98px){\n .Page:not([rel='prev']):not([rel='next']) {\n display: none;\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<%= render(Primer::BaseComponent.new(**@system_arguments)) do %>
|
|
2
|
+
<% pages.each do |page| %>
|
|
3
|
+
<%= content_tag(page.props[:href].present? ? :a : :span, **page.props) do %>
|
|
4
|
+
<% if page.key == PAGE_TYPE__PREV %>
|
|
5
|
+
<%= render(Primer::Beta::Octicon.new(icon: "chevron-left", "aria-hidden": true)) %>
|
|
6
|
+
<% end %>
|
|
7
|
+
|
|
8
|
+
<%= page.content %>
|
|
9
|
+
|
|
10
|
+
<% if page.key == PAGE_TYPE__NEXT %>
|
|
11
|
+
<%= render(Primer::Beta::Octicon.new(icon: "chevron-right", "aria-hidden": true)) %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% end %>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
.Page {
|
|
2
|
+
min-width: var(--base-size-32);
|
|
3
|
+
height: var(--base-size-32);
|
|
4
|
+
padding: var(--base-size-8) var(--base-size-6);
|
|
5
|
+
margin-right: var(--base-size-4);
|
|
6
|
+
color: var(--fgColor-default);
|
|
7
|
+
white-space: nowrap;
|
|
8
|
+
vertical-align: middle;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
border-radius: var(--borderRadius-medium,.375rem);
|
|
11
|
+
transition: background-color 0.2s cubic-bezier(0.3, 0, 0.5, 1);
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.Page[rel='prev'] > svg,
|
|
18
|
+
.Page[rel='next'] > svg {
|
|
19
|
+
height: var(--base-size-16);
|
|
20
|
+
width: var(--base-size-16);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.Page[rel='prev'] > svg {
|
|
24
|
+
margin-inline-end: var(--base-size-4);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.Page[rel='next'] > svg {
|
|
28
|
+
margin-inline-start: var(--base-size-4);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.Page:last-child {
|
|
32
|
+
margin-right: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.Page:hover,
|
|
36
|
+
.Page:focus {
|
|
37
|
+
text-decoration: none;
|
|
38
|
+
background-color: var(--control-transparent-bgColor-hover);
|
|
39
|
+
outline: 0;
|
|
40
|
+
transition-duration: 0.1s;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.Page:focus-visible {
|
|
44
|
+
outline: 2px solid var(--bgColor-accent-emphasis);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.Page:active {
|
|
48
|
+
border-color: var(--borderColor-muted);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.Page[rel='prev'],
|
|
52
|
+
.Page[rel='next'] {
|
|
53
|
+
color: var(--fgColor-accent);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.Page[aria-current],
|
|
57
|
+
.Page[aria-current]:hover {
|
|
58
|
+
color: var(--fgColor-onEmphasis);
|
|
59
|
+
background-color: var(--bgColor-accent-emphasis);
|
|
60
|
+
border-color: transparent;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.Page[aria-current]:focus-visible {
|
|
64
|
+
outline: 2px solid var(--bgColor-accent-emphasis);
|
|
65
|
+
box-shadow: inset 0 0 0 var(--base-size-2) var(--fgColor-onEmphasis);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.Page[aria-hidden],
|
|
69
|
+
.Page[aria-hidden]:hover,
|
|
70
|
+
.Page[role='presentation'],
|
|
71
|
+
.Page[role='presentation']:hover {
|
|
72
|
+
color: var(--fgColor-disabled);
|
|
73
|
+
cursor: default;
|
|
74
|
+
background-color: transparent;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.PaginationContainer {
|
|
78
|
+
margin: var(--base-size-16) 0;
|
|
79
|
+
text-align: center;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@media (max-width: 543.98px){
|
|
83
|
+
.Page:not([rel='prev']):not([rel='next']) {
|
|
84
|
+
display: none;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Primer
|
|
4
|
+
module OpenProject
|
|
5
|
+
class Pagination < Primer::Component
|
|
6
|
+
status :open_project
|
|
7
|
+
|
|
8
|
+
PageData = Struct.new(:key, :content, :props, keyword_init: true)
|
|
9
|
+
|
|
10
|
+
DEFAULT_MARGIN_PAGE_COUNT = 1
|
|
11
|
+
DEFAULT_SURROUNDING_PAGE_COUNT = 2
|
|
12
|
+
|
|
13
|
+
PAGE_TYPE__BREAK = :break
|
|
14
|
+
PAGE_TYPE__PREV = :prev
|
|
15
|
+
PAGE_TYPE__NEXT = :next
|
|
16
|
+
PAGE_TYPE__NUM = :num
|
|
17
|
+
|
|
18
|
+
attr_reader :page_count,
|
|
19
|
+
:current_page,
|
|
20
|
+
:href_builder,
|
|
21
|
+
:margin_page_count,
|
|
22
|
+
:show_pages,
|
|
23
|
+
:surrounding_page_count
|
|
24
|
+
|
|
25
|
+
def initialize(
|
|
26
|
+
page_count:,
|
|
27
|
+
current_page:,
|
|
28
|
+
href_builder: nil,
|
|
29
|
+
margin_page_count: DEFAULT_MARGIN_PAGE_COUNT,
|
|
30
|
+
show_pages: true,
|
|
31
|
+
surrounding_page_count: DEFAULT_SURROUNDING_PAGE_COUNT,
|
|
32
|
+
**system_arguments
|
|
33
|
+
)
|
|
34
|
+
@page_count = cast_integer!(page_count, "page_count")
|
|
35
|
+
@current_page = cast_integer!(current_page, "current_page")
|
|
36
|
+
@href_builder = href_builder || method(:default_href_builder)
|
|
37
|
+
@margin_page_count = cast_integer!(margin_page_count, "margin_page_count")
|
|
38
|
+
@show_pages = show_pages
|
|
39
|
+
@surrounding_page_count = cast_integer!(surrounding_page_count, "surrounding_page_count")
|
|
40
|
+
@system_arguments = system_arguments
|
|
41
|
+
|
|
42
|
+
@system_arguments[:tag] = :nav
|
|
43
|
+
@system_arguments[:classes] = class_names(
|
|
44
|
+
"PaginationContainer",
|
|
45
|
+
@system_arguments[:classes]
|
|
46
|
+
)
|
|
47
|
+
@system_arguments["aria-label"] = I18n.t("pagination.label")
|
|
48
|
+
|
|
49
|
+
validate_arguments!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def pages
|
|
53
|
+
build_pagination_model.map do |page|
|
|
54
|
+
build_component_data(page)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def cast_integer!(value, name)
|
|
61
|
+
Integer(value)
|
|
62
|
+
rescue ArgumentError, TypeError
|
|
63
|
+
raise ArgumentError, "#{name} must be a number"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def validate_arguments!
|
|
67
|
+
raise ArgumentError, "page_count must be >= 0" if page_count < 0
|
|
68
|
+
raise ArgumentError, "current_page must be >= 1" if current_page < 1
|
|
69
|
+
raise ArgumentError, "margin_page_count must be >= 0" if margin_page_count < 0
|
|
70
|
+
raise ArgumentError, "surrounding_page_count must be >= 0" if surrounding_page_count < 0
|
|
71
|
+
raise ArgumentError, "href_builder must respond to #call" unless href_builder.respond_to?(:call)
|
|
72
|
+
raise ArgumentError, "show_pages must be a boolean" unless [true, false].include?(show_pages)
|
|
73
|
+
raise ArgumentError, "current_page can't be larger than page_count" if current_page > page_count
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def default_href_builder(page_num)
|
|
77
|
+
"##{page_num}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def build_pagination_model
|
|
81
|
+
prev_page = previous_page_item
|
|
82
|
+
next_page = next_page_item
|
|
83
|
+
|
|
84
|
+
return [prev_page, next_page] unless show_pages || page_count <= 0
|
|
85
|
+
|
|
86
|
+
pages = if all_pages_fit?
|
|
87
|
+
full_pagination_without_breaks
|
|
88
|
+
else
|
|
89
|
+
paginated_number_items
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
[prev_page, *pages, next_page]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def previous_page_item
|
|
96
|
+
{
|
|
97
|
+
type: PAGE_TYPE__PREV,
|
|
98
|
+
num: current_page - 1,
|
|
99
|
+
disabled: current_page == 1
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def next_page_item
|
|
104
|
+
{
|
|
105
|
+
type: PAGE_TYPE__NEXT,
|
|
106
|
+
num: current_page + 1,
|
|
107
|
+
disabled: current_page == page_count
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def full_pagination_without_breaks
|
|
112
|
+
pages = []
|
|
113
|
+
add_pages(pages, 1, page_count)
|
|
114
|
+
pages
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def paginated_number_items
|
|
118
|
+
pages = []
|
|
119
|
+
|
|
120
|
+
add_start_pages_and_ellipsis(pages)
|
|
121
|
+
add_middle_pages(pages)
|
|
122
|
+
add_end_pages_and_ellipsis(pages)
|
|
123
|
+
|
|
124
|
+
pages
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def add_start_pages_and_ellipsis(pages)
|
|
128
|
+
add_pages(pages, 1, margin_page_count, has_start_ellipsis?)
|
|
129
|
+
add_ellipsis(pages, margin_page_count) if has_start_ellipsis?
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def add_middle_pages(pages)
|
|
133
|
+
add_pages(
|
|
134
|
+
pages,
|
|
135
|
+
middle_start_page,
|
|
136
|
+
middle_end_page,
|
|
137
|
+
has_end_ellipsis?
|
|
138
|
+
)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def add_end_pages_and_ellipsis(pages)
|
|
142
|
+
add_ellipsis(pages, middle_end_page) if has_end_ellipsis?
|
|
143
|
+
add_pages(pages, ending_start_page, page_count)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def all_pages_fit?
|
|
147
|
+
page_count <= max_visible_pages
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def max_visible_pages
|
|
151
|
+
# The standard gap on the left and the right +
|
|
152
|
+
# current page + 2 boundary pages (one on each side before an ellipsis would appear)
|
|
153
|
+
(standard_gap * 2) + 3
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def standard_gap
|
|
157
|
+
surrounding_page_count + margin_page_count
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def has_start_ellipsis?
|
|
161
|
+
start_gap.positive?
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def has_end_ellipsis?
|
|
165
|
+
end_gap.positive?
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def start_gap
|
|
169
|
+
@start_gap ||= near_start? ? 0 : current_page - standard_gap - 1
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def start_offset
|
|
173
|
+
@start_offset ||= near_start? ? current_page - standard_gap - 2 : 0
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def end_gap
|
|
177
|
+
@end_gap ||= near_end? ? 0 : page_count - current_page - standard_gap
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def end_offset
|
|
181
|
+
@end_offset ||= near_end? ? page_count - current_page - standard_gap - 1 : 0
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def near_start?
|
|
185
|
+
current_page - standard_gap - 1 <= 1
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def near_end?
|
|
189
|
+
page_count - current_page - standard_gap <= 1
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def middle_start_page
|
|
193
|
+
margin_page_count + start_gap + end_offset + 1
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def middle_end_page
|
|
197
|
+
page_count - start_offset - end_gap - margin_page_count
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def ending_start_page
|
|
201
|
+
page_count - margin_page_count + 1
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def add_ellipsis(pages, previous_page)
|
|
205
|
+
pages << {
|
|
206
|
+
type: PAGE_TYPE__BREAK,
|
|
207
|
+
num: previous_page + 1
|
|
208
|
+
}
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def add_pages(pages, start_page, end_page, precedes_break = false)
|
|
212
|
+
(start_page..end_page).each do |i|
|
|
213
|
+
pages << {
|
|
214
|
+
type: PAGE_TYPE__NUM,
|
|
215
|
+
num: i,
|
|
216
|
+
selected: i == current_page,
|
|
217
|
+
precedes_break: i == end_page && precedes_break
|
|
218
|
+
}
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def build_component_data(page)
|
|
223
|
+
props = {}
|
|
224
|
+
content = ""
|
|
225
|
+
key = ""
|
|
226
|
+
|
|
227
|
+
case page[:type]
|
|
228
|
+
when PAGE_TYPE__PREV, PAGE_TYPE__NEXT
|
|
229
|
+
key = page[:type]
|
|
230
|
+
key_string = key.to_s
|
|
231
|
+
content = I18n.t("pagination.#{key_string}")
|
|
232
|
+
|
|
233
|
+
if page[:disabled]
|
|
234
|
+
props.merge!(
|
|
235
|
+
rel: key_string,
|
|
236
|
+
"aria-hidden": "true",
|
|
237
|
+
"aria-disabled": "true"
|
|
238
|
+
)
|
|
239
|
+
else
|
|
240
|
+
props.merge!(
|
|
241
|
+
rel: key_string,
|
|
242
|
+
href: href_builder.call(page[:num]),
|
|
243
|
+
"aria-label": I18n.t("pagination.#{key_string}_page")
|
|
244
|
+
)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
when PAGE_TYPE__NUM
|
|
248
|
+
key = :"page-#{page[:num]}"
|
|
249
|
+
content = page[:num].to_s
|
|
250
|
+
|
|
251
|
+
props.merge!(
|
|
252
|
+
href: href_builder.call(page[:num]),
|
|
253
|
+
"aria-label": page[:precedes_break] ? I18n.t("pagination.page_with_more", number: page[:num]) : I18n.t("pagination.page", number: page[:num])
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
props[:"aria-current"] = "page" if page[:selected]
|
|
257
|
+
|
|
258
|
+
when PAGE_TYPE__BREAK
|
|
259
|
+
key = :"page-#{page[:num]}-break"
|
|
260
|
+
content = "…"
|
|
261
|
+
|
|
262
|
+
props.merge!(
|
|
263
|
+
role: "presentation"
|
|
264
|
+
)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
props[:class] = class_names("Page", props[:class])
|
|
268
|
+
|
|
269
|
+
PageData.new(
|
|
270
|
+
key: key,
|
|
271
|
+
content: content,
|
|
272
|
+
props: props
|
|
273
|
+
)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
data/config/locales/en.yml
CHANGED
|
@@ -30,3 +30,11 @@ en:
|
|
|
30
30
|
danger_dialog:
|
|
31
31
|
confirmation_live_message_checked: "The button to proceed is now active."
|
|
32
32
|
confirmation_live_message_unchecked: "The button to proceed is now inactive. You need to tick the checkbox to continue."
|
|
33
|
+
pagination:
|
|
34
|
+
label: "Pagination"
|
|
35
|
+
prev: "Previous"
|
|
36
|
+
prev_page: "Previous Page"
|
|
37
|
+
next: "Next"
|
|
38
|
+
next_page: "Next Page"
|
|
39
|
+
page: "Page %{number}"
|
|
40
|
+
page_with_more: "Page %{number}..."
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%= render(
|
|
2
|
+
Primer::OpenProject::Pagination.new(
|
|
3
|
+
current_page: current_page,
|
|
4
|
+
page_count: page_count,
|
|
5
|
+
margin_page_count: margin_page_count,
|
|
6
|
+
surrounding_page_count: surrounding_page_count,
|
|
7
|
+
show_pages: show_pages,
|
|
8
|
+
href_builder: ->(page) { "#page-#{page}" }
|
|
9
|
+
)
|
|
10
|
+
) %>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Primer
|
|
4
|
+
module OpenProject
|
|
5
|
+
# @label Pagination
|
|
6
|
+
class PaginationPreview < ViewComponent::Preview
|
|
7
|
+
# @label Playground
|
|
8
|
+
#
|
|
9
|
+
# @param current_page number
|
|
10
|
+
# @param page_count number
|
|
11
|
+
# @param margin_page_count number
|
|
12
|
+
# @param surrounding_page_count number
|
|
13
|
+
# @param show_pages toggle
|
|
14
|
+
def playground(
|
|
15
|
+
current_page: 6,
|
|
16
|
+
page_count: 20,
|
|
17
|
+
margin_page_count: 1,
|
|
18
|
+
surrounding_page_count: 2,
|
|
19
|
+
show_pages: true
|
|
20
|
+
)
|
|
21
|
+
current_page = (current_page.presence || 6).to_i
|
|
22
|
+
page_count = (page_count.presence || 20).to_i
|
|
23
|
+
margin_page_count = (margin_page_count.presence || 1).to_i
|
|
24
|
+
surrounding_page_count = (surrounding_page_count.presence || 2).to_i
|
|
25
|
+
|
|
26
|
+
render(
|
|
27
|
+
Primer::OpenProject::Pagination.new(
|
|
28
|
+
current_page: current_page,
|
|
29
|
+
page_count: page_count,
|
|
30
|
+
margin_page_count: margin_page_count,
|
|
31
|
+
surrounding_page_count: surrounding_page_count,
|
|
32
|
+
show_pages: show_pages,
|
|
33
|
+
href_builder: ->(page) { "#page-#{page}" }
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @snapshot
|
|
39
|
+
# @label Default
|
|
40
|
+
def default
|
|
41
|
+
render(
|
|
42
|
+
Primer::OpenProject::Pagination.new(
|
|
43
|
+
current_page: 6,
|
|
44
|
+
page_count: 20,
|
|
45
|
+
href_builder: ->(page) { "#page-#{page}" }
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
#
|
|
50
|
+
# @!endgroup
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/static/arguments.json
CHANGED
|
@@ -6462,6 +6462,15 @@
|
|
|
6462
6462
|
}
|
|
6463
6463
|
]
|
|
6464
6464
|
},
|
|
6465
|
+
{
|
|
6466
|
+
"component": "OpenProject::Pagination",
|
|
6467
|
+
"status": "open_project",
|
|
6468
|
+
"a11y_reviewed": false,
|
|
6469
|
+
"short_name": "OpenProjectPagination",
|
|
6470
|
+
"source": "https://github.com/primer/view_components/tree/main/app/components/primer/open_project/pagination.rb",
|
|
6471
|
+
"lookbook": "https://primer.style/view-components/lookbook/inspect/primer/open_project/pagination/default/",
|
|
6472
|
+
"parameters": []
|
|
6473
|
+
},
|
|
6465
6474
|
{
|
|
6466
6475
|
"component": "OpenProject::SidePanel",
|
|
6467
6476
|
"status": "open_project",
|
data/static/audited_at.json
CHANGED
|
@@ -165,6 +165,7 @@
|
|
|
165
165
|
"Primer::OpenProject::PageHeader::Dialog": "",
|
|
166
166
|
"Primer::OpenProject::PageHeader::Menu": "",
|
|
167
167
|
"Primer::OpenProject::PageHeader::Title": "",
|
|
168
|
+
"Primer::OpenProject::Pagination": "",
|
|
168
169
|
"Primer::OpenProject::SidePanel": "",
|
|
169
170
|
"Primer::OpenProject::SidePanel::Section": "",
|
|
170
171
|
"Primer::OpenProject::SubHeader": "",
|
data/static/classes.json
CHANGED
|
@@ -497,6 +497,9 @@
|
|
|
497
497
|
"Overlay-headerFilter": [
|
|
498
498
|
"Primer::Alpha::Dialog"
|
|
499
499
|
],
|
|
500
|
+
"Page": [
|
|
501
|
+
"Primer::OpenProject::Pagination"
|
|
502
|
+
],
|
|
500
503
|
"PageHeader": [
|
|
501
504
|
"Primer::OpenProject::PageHeader"
|
|
502
505
|
],
|
|
@@ -539,6 +542,9 @@
|
|
|
539
542
|
"PageHeader-titleBar": [
|
|
540
543
|
"Primer::OpenProject::PageHeader"
|
|
541
544
|
],
|
|
545
|
+
"PaginationContainer": [
|
|
546
|
+
"Primer::OpenProject::Pagination"
|
|
547
|
+
],
|
|
542
548
|
"Popover": [
|
|
543
549
|
"Primer::Beta::Popover"
|
|
544
550
|
],
|
data/static/constants.json
CHANGED
|
@@ -1939,6 +1939,16 @@
|
|
|
1939
1939
|
"h6"
|
|
1940
1940
|
]
|
|
1941
1941
|
},
|
|
1942
|
+
"Primer::OpenProject::Pagination": {
|
|
1943
|
+
"DEFAULT_MARGIN_PAGE_COUNT": 1,
|
|
1944
|
+
"DEFAULT_SURROUNDING_PAGE_COUNT": 2,
|
|
1945
|
+
"GeneratedSlotMethods": "Primer::OpenProject::Pagination::GeneratedSlotMethods",
|
|
1946
|
+
"PAGE_TYPE__BREAK": "break",
|
|
1947
|
+
"PAGE_TYPE__NEXT": "next",
|
|
1948
|
+
"PAGE_TYPE__NUM": "num",
|
|
1949
|
+
"PAGE_TYPE__PREV": "prev",
|
|
1950
|
+
"PageData": "Primer::OpenProject::Pagination::PageData"
|
|
1951
|
+
},
|
|
1942
1952
|
"Primer::OpenProject::SidePanel": {
|
|
1943
1953
|
"GeneratedSlotMethods": "Primer::OpenProject::SidePanel::GeneratedSlotMethods",
|
|
1944
1954
|
"Section": "Primer::OpenProject::SidePanel::Section"
|
data/static/info_arch.json
CHANGED
|
@@ -21440,6 +21440,89 @@
|
|
|
21440
21440
|
"previews": [],
|
|
21441
21441
|
"subcomponents": []
|
|
21442
21442
|
},
|
|
21443
|
+
{
|
|
21444
|
+
"fully_qualified_name": "Primer::OpenProject::Pagination",
|
|
21445
|
+
"description": "",
|
|
21446
|
+
"accessibility_docs": null,
|
|
21447
|
+
"is_form_component": false,
|
|
21448
|
+
"is_published": true,
|
|
21449
|
+
"requires_js": false,
|
|
21450
|
+
"component": "OpenProject::Pagination",
|
|
21451
|
+
"status": "open_project",
|
|
21452
|
+
"a11y_reviewed": false,
|
|
21453
|
+
"short_name": "OpenProjectPagination",
|
|
21454
|
+
"source": "https://github.com/primer/view_components/tree/main/app/components/primer/open_project/pagination.rb",
|
|
21455
|
+
"lookbook": "https://primer.style/view-components/lookbook/inspect/primer/open_project/pagination/default/",
|
|
21456
|
+
"parameters": [],
|
|
21457
|
+
"slots": [],
|
|
21458
|
+
"methods": [
|
|
21459
|
+
{
|
|
21460
|
+
"name": "page_count",
|
|
21461
|
+
"description": "Returns the value of attribute page_count.",
|
|
21462
|
+
"parameters": [],
|
|
21463
|
+
"return_types": []
|
|
21464
|
+
},
|
|
21465
|
+
{
|
|
21466
|
+
"name": "current_page",
|
|
21467
|
+
"description": "Returns the value of attribute current_page.",
|
|
21468
|
+
"parameters": [],
|
|
21469
|
+
"return_types": []
|
|
21470
|
+
},
|
|
21471
|
+
{
|
|
21472
|
+
"name": "href_builder",
|
|
21473
|
+
"description": "Returns the value of attribute href_builder.",
|
|
21474
|
+
"parameters": [],
|
|
21475
|
+
"return_types": []
|
|
21476
|
+
},
|
|
21477
|
+
{
|
|
21478
|
+
"name": "margin_page_count",
|
|
21479
|
+
"description": "Returns the value of attribute margin_page_count.",
|
|
21480
|
+
"parameters": [],
|
|
21481
|
+
"return_types": []
|
|
21482
|
+
},
|
|
21483
|
+
{
|
|
21484
|
+
"name": "show_pages",
|
|
21485
|
+
"description": "Returns the value of attribute show_pages.",
|
|
21486
|
+
"parameters": [],
|
|
21487
|
+
"return_types": []
|
|
21488
|
+
},
|
|
21489
|
+
{
|
|
21490
|
+
"name": "surrounding_page_count",
|
|
21491
|
+
"description": "Returns the value of attribute surrounding_page_count.",
|
|
21492
|
+
"parameters": [],
|
|
21493
|
+
"return_types": []
|
|
21494
|
+
}
|
|
21495
|
+
],
|
|
21496
|
+
"previews": [
|
|
21497
|
+
{
|
|
21498
|
+
"preview_path": "primer/open_project/pagination/playground",
|
|
21499
|
+
"name": "playground",
|
|
21500
|
+
"snapshot": "false",
|
|
21501
|
+
"skip_rules": {
|
|
21502
|
+
"wont_fix": [
|
|
21503
|
+
"region"
|
|
21504
|
+
],
|
|
21505
|
+
"will_fix": [
|
|
21506
|
+
"color-contrast"
|
|
21507
|
+
]
|
|
21508
|
+
}
|
|
21509
|
+
},
|
|
21510
|
+
{
|
|
21511
|
+
"preview_path": "primer/open_project/pagination/default",
|
|
21512
|
+
"name": "default",
|
|
21513
|
+
"snapshot": "true",
|
|
21514
|
+
"skip_rules": {
|
|
21515
|
+
"wont_fix": [
|
|
21516
|
+
"region"
|
|
21517
|
+
],
|
|
21518
|
+
"will_fix": [
|
|
21519
|
+
"color-contrast"
|
|
21520
|
+
]
|
|
21521
|
+
}
|
|
21522
|
+
}
|
|
21523
|
+
],
|
|
21524
|
+
"subcomponents": []
|
|
21525
|
+
},
|
|
21443
21526
|
{
|
|
21444
21527
|
"fully_qualified_name": "Primer::OpenProject::SidePanel",
|
|
21445
21528
|
"description": "Add a general description of component here\nAdd additional usage considerations or best practices that may aid the user to use the component correctly.",
|