feat: added manual page selection and changed functionality of pagination

This commit is contained in:
Moyasee
2025-10-26 17:26:25 +02:00
parent ee35bc24b2
commit 7f2343413e
2 changed files with 121 additions and 20 deletions

View File

@@ -1,3 +1,5 @@
@use "../../scss/globals.scss";
.pagination {
display: flex;
gap: 4px;
@@ -18,4 +20,31 @@
font-size: 16px;
}
}
&__page-input {
box-sizing: border-box;
width: 40px;
min-width: 40px;
max-width: 40px;
min-height: 40px;
border-radius: 8px;
border: solid 1px globals.$border-color;
background-color: transparent;
color: globals.$muted-color;
text-align: center;
font-size: 12px;
padding: 0 6px;
outline: none;
}
&__double-chevron {
display: flex;
align-items: center;
justify-content: center;
font-size: 0; // remove whitespace node width between SVGs
}
&__double-chevron > svg + svg {
margin-left: -8px; // pull the second chevron closer
}
}

View File

@@ -1,6 +1,7 @@
import { Button } from "@renderer/components/button/button";
import { ChevronLeftIcon, ChevronRightIcon } from "@primer/octicons-react";
import { useFormat } from "@renderer/hooks/use-format";
import { useEffect, useRef, useState } from "react";
import "./pagination.scss";
interface PaginationProps {
@@ -16,6 +17,17 @@ export function Pagination({
}: PaginationProps) {
const { formatNumber } = useFormat();
const [isJumpOpen, setIsJumpOpen] = useState(false);
const [jumpValue, setJumpValue] = useState<string>("");
const jumpInputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
if (isJumpOpen) {
setJumpValue("");
setTimeout(() => jumpInputRef.current?.focus(), 0);
}
}, [isJumpOpen, page]);
if (totalPages <= 1) return null;
const visiblePages = 3;
@@ -30,6 +42,19 @@ export function Pagination({
return (
<div className="pagination">
{startPage > 1 && (
<Button
theme="outline"
onClick={() => onPageChange(1)}
className="pagination__button"
>
<span className="pagination__double-chevron">
<ChevronLeftIcon />
<ChevronLeftIcon />
</span>
</Button>
)}
<Button
theme="outline"
onClick={() => onPageChange(page - 1)}
@@ -39,23 +64,6 @@ export function Pagination({
<ChevronLeftIcon />
</Button>
{page > 2 && (
<>
<Button
theme="outline"
onClick={() => onPageChange(1)}
className="pagination__button"
disabled={page === 1}
>
{1}
</Button>
<div className="pagination__ellipsis">
<span className="pagination__ellipsis-text">...</span>
</div>
</>
)}
{Array.from(
{ length: endPage - startPage + 1 },
(_, i) => startPage + i
@@ -72,9 +80,60 @@ export function Pagination({
{page < totalPages - 1 && (
<>
<div className="pagination__ellipsis">
<span className="pagination__ellipsis-text">...</span>
</div>
{isJumpOpen ? (
<input
ref={jumpInputRef}
type="number"
min={1}
max={totalPages}
className="pagination__page-input"
value={jumpValue}
onChange={(e) => {
const val = e.target.value;
if (val === "") {
setJumpValue("");
return;
}
const num = Number(val);
if (Number.isNaN(num)) {
return;
}
if (num < 1) {
setJumpValue("1");
return;
}
if (num > totalPages) {
setJumpValue(String(totalPages));
return;
}
setJumpValue(val);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
if (jumpValue.trim() === "") return;
const parsed = Number(jumpValue);
if (Number.isNaN(parsed)) return;
const target = Math.max(1, Math.min(totalPages, parsed));
onPageChange(target);
setIsJumpOpen(false);
} else if (e.key === "Escape") {
setIsJumpOpen(false);
}
}}
onBlur={() => {
setIsJumpOpen(false);
}}
aria-label="Go to page"
/>
) : (
<Button
theme="outline"
className="pagination__button"
onClick={() => setIsJumpOpen(true)}
>
...
</Button>
)}
<Button
theme="outline"
@@ -95,6 +154,19 @@ export function Pagination({
>
<ChevronRightIcon />
</Button>
{endPage < totalPages && (
<Button
theme="outline"
onClick={() => onPageChange(totalPages)}
className="pagination__button"
>
<span className="pagination__double-chevron">
<ChevronRightIcon />
<ChevronRightIcon />
</span>
</Button>
)}
</div>
);
}