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
|
module PaginationHelper
|
||||||
def sequential_paginator(records)
|
def sequential_paginator(records)
|
||||||
with_paginator_wrapper do
|
tag.div(class: "paginator") do
|
||||||
return "" if records.try(:none?)
|
return "" if records.try(:none?)
|
||||||
|
|
||||||
html = "".html_safe
|
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
|
end
|
||||||
|
|
||||||
unless records.is_last_page?
|
# Next
|
||||||
html << tag.li(link_to("Next >", nav_params_for("b#{records[-1].id}"), rel: "next", id: "paginator-next", data: { shortcut: "d right" }))
|
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
|
end
|
||||||
|
|
||||||
html
|
html
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -22,64 +28,73 @@ module PaginationHelper
|
|||||||
return sequential_paginator(records)
|
return sequential_paginator(records)
|
||||||
end
|
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
|
html = "".html_safe
|
||||||
icon_left = tag.i(class: "fa-solid fa-chevron-left")
|
|
||||||
if records.current_page >= 2
|
# Previous
|
||||||
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" }) }
|
has_prev = records.current_page < 2
|
||||||
else
|
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
|
||||||
html << tag.li(class: "arrow") { tag.span(icon_left) }
|
concat svg_icon(:chevron_left)
|
||||||
|
concat tag.span("Prev")
|
||||||
end
|
end
|
||||||
|
|
||||||
paginator_pages(records).each do |page|
|
# Break
|
||||||
html << numbered_paginator_item(page, records)
|
html << tag.div(class: "break")
|
||||||
|
|
||||||
|
# Numbered
|
||||||
|
paginator_pages(records).each do |page, klass|
|
||||||
|
html << numbered_paginator_item(page, klass, records)
|
||||||
end
|
end
|
||||||
|
|
||||||
icon_right = tag.i(class: "fa-solid fa-chevron-right")
|
# Next
|
||||||
if records.current_page < records.total_pages
|
has_next = 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" }) }
|
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
|
||||||
else
|
concat tag.span("Next")
|
||||||
html << tag.li(class: "arrow") { tag.span(icon_right) }
|
concat svg_icon(:chevron_right)
|
||||||
end
|
end
|
||||||
|
|
||||||
html
|
html
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def with_paginator_wrapper(&)
|
|
||||||
tag.div(class: "paginator") do
|
|
||||||
tag.menu(&)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def paginator_pages(records)
|
def paginator_pages(records)
|
||||||
window = 4
|
small_window = 2
|
||||||
|
large_window = 4
|
||||||
|
|
||||||
last_page = [records.total_pages, records.max_numbered_pages].min
|
last_page = [records.total_pages, records.max_numbered_pages].min
|
||||||
left = [2, records.current_page - window].max
|
left_sm = [2, records.current_page - small_window].max
|
||||||
right = [records.current_page + window, last_page - 1].min
|
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
|
||||||
|
|
||||||
[
|
result = [
|
||||||
1,
|
[1, "first"],
|
||||||
("..." unless left == 2),
|
]
|
||||||
(left..right).to_a,
|
result.push([0, "spacer"]) unless left_lg == 2
|
||||||
("..." unless right == last_page - 1),
|
(left_lg..right_lg).each do |page|
|
||||||
(last_page unless last_page <= 1),
|
result.push([page, small_range.member?(page) ? "sm" : "lg"])
|
||||||
].flatten.compact
|
end
|
||||||
|
result.push([0, "spacer"]) unless right_lg == last_page - 1
|
||||||
|
result.push([last_page, "last"]) unless last_page <= 1
|
||||||
|
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def numbered_paginator_item(page, records)
|
def numbered_paginator_item(page, klass, records)
|
||||||
return "" if page.to_i > records.max_numbered_pages
|
return "" if page.to_i > records.max_numbered_pages
|
||||||
|
|
||||||
html = "".html_safe
|
html = "".html_safe
|
||||||
if page == "..."
|
if page == 0
|
||||||
html << tag.li(class: "more") { link_to(tag.i(class: "fa-solid fa-ellipsis"), nav_params_for(0)) }
|
html << link_to(svg_icon(:ellipsis), nav_params_for(0), class: "spacer")
|
||||||
elsif page == records.current_page
|
elsif page == records.current_page
|
||||||
html << tag.li(class: "current-page") { tag.span(page) }
|
html << tag.span(page, class: "page current")
|
||||||
else
|
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
|
end
|
||||||
|
|
||||||
html
|
html
|
||||||
end
|
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));
|
Paginator.init_fasttravel($(one));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ Shortcuts.initialize_data_shortcuts = function () {
|
|||||||
|
|
||||||
Shortcuts.keydown(keys, namespace, event => {
|
Shortcuts.keydown(keys, namespace, event => {
|
||||||
const e = $(`[data-shortcut="${keys}"]`).get(0);
|
const e = $(`[data-shortcut="${keys}"]`).get(0);
|
||||||
|
if ($e.data("disabled")) return;
|
||||||
if ($e.is("input, textarea")) {
|
if ($e.is("input, textarea")) {
|
||||||
$e.trigger("focus").selectEnd();
|
$e.trigger("focus").selectEnd();
|
||||||
} else {
|
} 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 {
|
& > a, & > span {
|
||||||
display: block;
|
|
||||||
padding: 2em 0 1em 0;
|
|
||||||
text-align: center;
|
|
||||||
clear: both;
|
|
||||||
|
|
||||||
menu {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
box-sizing: border-box;
|
||||||
justify-content: center;
|
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[data-disabled="true"] {
|
||||||
a {
|
color: var(--color-text);
|
||||||
margin: 0 0.25em;
|
pointer-events: none;
|
||||||
padding: 0.25em 0.75em;
|
}
|
||||||
|
|
||||||
|
// 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 {
|
.break { display: none; }
|
||||||
background: $paginator-hover-background;
|
.spacer {
|
||||||
color: $paginator-hover-color;
|
padding: inherit;
|
||||||
|
svg { transform: unset; }
|
||||||
}
|
}
|
||||||
|
|
||||||
&.more {
|
.prev { margin-right: 1rem; }
|
||||||
color: $paginator-more-color;
|
.next { margin-left: 1rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@include window-larger-than(50rem) {
|
||||||
|
a, span {
|
||||||
|
padding: 0.75rem 0.5rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
.prev, .next {
|
||||||
margin: 0 0.25em;
|
span { display: none; }
|
||||||
padding: 0.25em 0.75em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include window-larger-than(65rem) {
|
||||||
|
a.page.lg { display: flex; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
|
|
||||||
.paginator {
|
|
||||||
padding: 1em 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user