forked from e621ng/e621ng
[Pagination] Rework the pagination styles (#886)
Now with mobile layouts!
This commit is contained in:
parent
09b46b0766
commit
af6ab947d1
29
app/helpers/icon_helper.rb
Normal file
29
app/helpers/icon_helper.rb
Normal file
@ -0,0 +1,29 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module IconHelper
|
||||
PATHS = {
|
||||
chevron_left: %(<path d="m15 18-6-6 6-6"/>),
|
||||
chevron_right: %(<path d="m9 18 6-6-6-6"/>),
|
||||
ellipsis: %(<circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/>),
|
||||
}.freeze
|
||||
|
||||
def svg_icon(name, *args)
|
||||
options = args.extract_options!
|
||||
width = options[:width] || 24
|
||||
height = options[:height] || 24
|
||||
|
||||
tag.svg(
|
||||
"xmlns": "http://www.w3.org/2000/svg",
|
||||
"width": width,
|
||||
"height": height,
|
||||
"viewbox": "0 0 24 24",
|
||||
"fill": "none",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": 2,
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round",
|
||||
) do
|
||||
raw(PATHS[name]) # rubocop:disable Rails/OutputSafety
|
||||
end
|
||||
end
|
||||
end
|
@ -2,17 +2,23 @@
|
||||
|
||||
module PaginationHelper
|
||||
def sequential_paginator(records)
|
||||
with_paginator_wrapper do
|
||||
tag.div(class: "paginator") do
|
||||
return "" if records.try(:none?)
|
||||
|
||||
html = "".html_safe
|
||||
unless records.is_first_page?
|
||||
html << tag.li(link_to("< Previous", nav_params_for("a#{records[0].id}"), rel: "prev", id: "paginator-prev", data: { shortcut: "a left" }))
|
||||
|
||||
# Previous
|
||||
html << link_to(records.is_first_page? ? "#" : nav_params_for("a#{records[0].id}"), class: "prev", id: "paginator-prev", rel: "prev", data: { shortcut: "a left", disabled: records.is_first_page? }) do
|
||||
concat svg_icon(:chevron_left)
|
||||
concat tag.span("Prev")
|
||||
end
|
||||
|
||||
unless records.is_last_page?
|
||||
html << tag.li(link_to("Next >", nav_params_for("b#{records[-1].id}"), rel: "next", id: "paginator-next", data: { shortcut: "d right" }))
|
||||
# Next
|
||||
html << link_to(records.is_last_page? ? "#" : nav_params_for("b#{records[-1].id}"), class: "next", id: "paginator-next", rel: "next", data: { shortcut: "d right", disabled: records.is_last_page? }) do
|
||||
concat tag.span("Next")
|
||||
concat svg_icon(:chevron_right)
|
||||
end
|
||||
|
||||
html
|
||||
end
|
||||
end
|
||||
@ -22,64 +28,73 @@ module PaginationHelper
|
||||
return sequential_paginator(records)
|
||||
end
|
||||
|
||||
with_paginator_wrapper do
|
||||
tag.div(class: "paginator", data: { total: [records.total_pages, records.max_numbered_pages].min, current: records.current_page }) do
|
||||
html = "".html_safe
|
||||
icon_left = tag.i(class: "fa-solid fa-chevron-left")
|
||||
if records.current_page >= 2
|
||||
html << tag.li(class: "arrow") { link_to(icon_left, nav_params_for(records.current_page - 1), rel: "prev", id: "paginator-prev", data: { shortcut: "a left" }) }
|
||||
else
|
||||
html << tag.li(class: "arrow") { tag.span(icon_left) }
|
||||
|
||||
# Previous
|
||||
has_prev = records.current_page < 2
|
||||
html << link_to(has_prev ? "#" : nav_params_for(records.current_page - 1), class: "prev", id: "paginator-prev", rel: "prev", data: { shortcut: "a left", disabled: has_prev }) do
|
||||
concat svg_icon(:chevron_left)
|
||||
concat tag.span("Prev")
|
||||
end
|
||||
|
||||
paginator_pages(records).each do |page|
|
||||
html << numbered_paginator_item(page, records)
|
||||
# Break
|
||||
html << tag.div(class: "break")
|
||||
|
||||
# Numbered
|
||||
paginator_pages(records).each do |page, klass|
|
||||
html << numbered_paginator_item(page, klass, records)
|
||||
end
|
||||
|
||||
icon_right = tag.i(class: "fa-solid fa-chevron-right")
|
||||
if records.current_page < records.total_pages
|
||||
html << tag.li(class: "arrow") { link_to(icon_right, nav_params_for(records.current_page + 1), rel: "next", id: "paginator-next", data: { shortcut: "d right" }) }
|
||||
else
|
||||
html << tag.li(class: "arrow") { tag.span(icon_right) }
|
||||
# Next
|
||||
has_next = records.current_page >= records.total_pages
|
||||
html << link_to(has_next ? "#" : nav_params_for(records.current_page + 1), class: "next", id: "paginator-next", rel: "next", data: { shortcut: "d right", disabled: has_next }) do
|
||||
concat tag.span("Next")
|
||||
concat svg_icon(:chevron_right)
|
||||
end
|
||||
|
||||
html
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def with_paginator_wrapper(&)
|
||||
tag.div(class: "paginator") do
|
||||
tag.menu(&)
|
||||
end
|
||||
end
|
||||
|
||||
def paginator_pages(records)
|
||||
window = 4
|
||||
small_window = 2
|
||||
large_window = 4
|
||||
|
||||
last_page = [records.total_pages, records.max_numbered_pages].min
|
||||
left = [2, records.current_page - window].max
|
||||
right = [records.current_page + window, last_page - 1].min
|
||||
left_sm = [2, records.current_page - small_window].max
|
||||
left_lg = [2, records.current_page - large_window].max
|
||||
right_sm = [records.current_page + small_window, last_page - 1].min
|
||||
right_lg = [records.current_page + large_window, last_page - 1].min
|
||||
small_range = left_sm..right_sm
|
||||
|
||||
[
|
||||
1,
|
||||
("..." unless left == 2),
|
||||
(left..right).to_a,
|
||||
("..." unless right == last_page - 1),
|
||||
(last_page unless last_page <= 1),
|
||||
].flatten.compact
|
||||
result = [
|
||||
[1, "first"],
|
||||
]
|
||||
result.push([0, "spacer"]) unless left_lg == 2
|
||||
(left_lg..right_lg).each do |page|
|
||||
result.push([page, small_range.member?(page) ? "sm" : "lg"])
|
||||
end
|
||||
result.push([0, "spacer"]) unless right_lg == last_page - 1
|
||||
result.push([last_page, "last"]) unless last_page <= 1
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def numbered_paginator_item(page, records)
|
||||
def numbered_paginator_item(page, klass, records)
|
||||
return "" if page.to_i > records.max_numbered_pages
|
||||
|
||||
html = "".html_safe
|
||||
if page == "..."
|
||||
html << tag.li(class: "more") { link_to(tag.i(class: "fa-solid fa-ellipsis"), nav_params_for(0)) }
|
||||
if page == 0
|
||||
html << link_to(svg_icon(:ellipsis), nav_params_for(0), class: "spacer")
|
||||
elsif page == records.current_page
|
||||
html << tag.li(class: "current-page") { tag.span(page) }
|
||||
html << tag.span(page, class: "page current")
|
||||
else
|
||||
html << tag.li(class: "numbered-page") { link_to(page, nav_params_for(page)) }
|
||||
html << link_to(page, nav_params_for(page), class: "page #{klass}")
|
||||
end
|
||||
|
||||
html
|
||||
end
|
||||
|
||||
|
@ -12,7 +12,7 @@ Paginator.init_fasttravel = function (button) {
|
||||
};
|
||||
|
||||
$(() => {
|
||||
for (const one of $(".paginator li.more a").get())
|
||||
for (const one of $(".paginator a.spacer").get())
|
||||
Paginator.init_fasttravel($(one));
|
||||
});
|
||||
|
||||
|
@ -28,6 +28,7 @@ Shortcuts.initialize_data_shortcuts = function () {
|
||||
|
||||
Shortcuts.keydown(keys, namespace, event => {
|
||||
const e = $(`[data-shortcut="${keys}"]`).get(0);
|
||||
if ($e.data("disabled")) return;
|
||||
if ($e.is("input, textarea")) {
|
||||
$e.trigger("focus").selectEnd();
|
||||
} else {
|
||||
|
@ -1,35 +1,98 @@
|
||||
.paginator {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
justify-content: space-evenly;
|
||||
background-color: themed("color-foreground");
|
||||
border-radius: 0.25rem;
|
||||
|
||||
div.paginator {
|
||||
display: block;
|
||||
padding: 2em 0 1em 0;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
|
||||
menu {
|
||||
& > a, & > span {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-width: 2.15rem;
|
||||
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
padding: 0.75rem 0.3rem; // otherwise large page numbers wrap
|
||||
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&:hover {
|
||||
background: themed("color-section");
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
a {
|
||||
margin: 0 0.25em;
|
||||
padding: 0.25em 0.75em;
|
||||
& > a[data-disabled="true"] {
|
||||
color: var(--color-text);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Ordering
|
||||
// Oh boy
|
||||
.page {
|
||||
order: 20;
|
||||
&.lg { display: none; }
|
||||
&.current { cursor: default; }
|
||||
}
|
||||
.prev {
|
||||
order: 1;
|
||||
margin-right: auto;
|
||||
}
|
||||
.spacer {
|
||||
order: 20;
|
||||
padding: 0;
|
||||
|
||||
&:last-child { display: none; }
|
||||
svg {
|
||||
height: 1rem;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
.next {
|
||||
order: 9;
|
||||
margin-left: auto;
|
||||
}
|
||||
.break {
|
||||
order: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
// Tablet
|
||||
@include window-larger-than(35rem) {
|
||||
justify-content: center;
|
||||
gap: 0.125rem;
|
||||
|
||||
a, span {
|
||||
order: 0 !important;
|
||||
min-width: 2.25rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background: $paginator-hover-background;
|
||||
color: $paginator-hover-color;
|
||||
.break { display: none; }
|
||||
.spacer {
|
||||
padding: inherit;
|
||||
svg { transform: unset; }
|
||||
}
|
||||
|
||||
&.more {
|
||||
color: $paginator-more-color;
|
||||
.prev { margin-right: 1rem; }
|
||||
.next { margin-left: 1rem; }
|
||||
}
|
||||
|
||||
@include window-larger-than(50rem) {
|
||||
a, span {
|
||||
padding: 0.75rem 0.5rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
span {
|
||||
margin: 0 0.25em;
|
||||
padding: 0.25em 0.75em;
|
||||
font-weight: bold;
|
||||
.prev, .next {
|
||||
span { display: none; }
|
||||
}
|
||||
}
|
||||
|
||||
@include window-larger-than(65rem) {
|
||||
a.page.lg { display: flex; }
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,6 @@
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 1em;
|
||||
|
||||
.paginator {
|
||||
padding: 1em 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user