ui/pager: rewrite the pagination button distribution algorithm to better control the length

This commit is contained in:
Adorian Doran 2026-02-16 01:51:32 +02:00
parent 0b8cba78d5
commit 82576c9703
2 changed files with 49 additions and 24 deletions

View File

@ -2190,7 +2190,6 @@
"percentage": "%"
},
"pagination": {
"page_title": "Page of {{startIndex}} - {{endIndex}}",
"total_notes": "{{count}} notes",
"prev_page": "Previous page",
"next_page": "Next page"

View File

@ -19,28 +19,7 @@ interface PaginationContext {
export function Pager({ page, pageSize, setPage, pageCount, totalNotes }: Omit<PaginationContext, "pageNotes">) {
if (pageCount < 2) return;
let lastPrinted = false;
let children: ComponentChildren[] = [];
for (let i = 1; i <= pageCount; i++) {
if (pageCount < 20 || i <= 5 || pageCount - i <= 5 || Math.abs(page - i) <= 2) {
lastPrinted = true;
const startIndex = (i - 1) * pageSize + 1;
const endIndex = Math.min(totalNotes, i * pageSize);
children.push((
<Button
text={i.toString()}
title={t("pagination.page_title", { startIndex, endIndex })}
disabled={(i === page)}
onClick={() => setPage(i)}
/>
))
} else if (lastPrinted) {
children.push(<>{"... "}&nbsp;{" "}</>);
lastPrinted = false;
}
}
const children = createPageButtons(page, setPage, pageCount);
return (
<div class="note-list-pager">
@ -59,12 +38,59 @@ export function Pager({ page, pageSize, setPage, pageCount, totalNotes }: Omit<P
text={t("pagination.next_page")}
onClick={() => {setPage(++page)}}
/>
<span className="note-list-pager-total-count">({t("pagination.total_notes", { count: totalNotes })})</span>
</div>
)
}
function createPageButtons(page: number, setPage: Dispatch<StateUpdater<number>>, pageCount: number): ComponentChildren[] {
const maxButtonCount = 9;
const maxLeftRightSegmentLength = 2;
// The left-side segment
const leftLength = Math.min(pageCount, maxLeftRightSegmentLength);
const leftStart = 1;
// The middle segment
const middleMaxLength = maxButtonCount - maxLeftRightSegmentLength * 2;
const middleLength = Math.min(pageCount - leftLength, middleMaxLength);
let middleStart = page - Math.floor(middleLength / 2);
middleStart = Math.max(middleStart, leftLength + 1);
// The right-side segment
const rightLength = Math.min(pageCount - (middleLength + leftLength), maxLeftRightSegmentLength);
const rightStart = pageCount - rightLength + 1;
middleStart = Math.min(middleStart, rightStart - middleLength);
return [
...createSegment(leftStart, leftLength, page, setPage, false),
...createSegment(middleStart, middleLength, page, setPage, (middleStart - leftLength > 1)),
...createSegment(rightStart, rightLength, page, setPage, (rightStart - (middleStart + middleLength) > 1)),
];
}
function createSegment(start: number, length: number, currentPage: number, setPage: Dispatch<StateUpdater<number>>, prependEllipsis: boolean): ComponentChildren[] {
const children: ComponentChildren[] = [];
if (prependEllipsis) {
children.push("...");
}
for (let i = 0; i < length; i++) {
const pageNum = start + i;
children.push((
<Button
text={pageNum.toString()}
disabled={(pageNum === currentPage)}
onClick={() => setPage(pageNum)}
/>
));
}
return children;
}
export function usePagination(note: FNote, noteIds: string[]): PaginationContext {
const [ page, setPage ] = useState(1);
const [ pageNotes, setPageNotes ] = useState<FNote[]>();