ee93ff8ea0
#61 #61 Merge remote-tracking branch 'origin/main' into feature/061 #61 #61 #61 #61 #61 #61 #61 #61 #61 #61 日づけ不詳の表示修正 Co-authored-by: miteruzo <miteruzo@naver.com> Reviewed-on: #298
128 lines
2.8 KiB
TypeScript
128 lines
2.8 KiB
TypeScript
import { useLocation } from 'react-router-dom'
|
|
|
|
import PrefetchLink from '@/components/PrefetchLink'
|
|
|
|
import type { FC } from 'react'
|
|
|
|
type Props = { page: number
|
|
totalPages: number
|
|
siblingCount?: number }
|
|
|
|
|
|
const range = (start: number, end: number): number[] =>
|
|
[...Array (end - start + 1).keys ()].map (i => start + i)
|
|
|
|
|
|
const getPages = (
|
|
page: number,
|
|
total: number,
|
|
siblingCount: number,
|
|
): (number | '…')[] => {
|
|
if (total <= 1)
|
|
return [1]
|
|
|
|
const first = 1
|
|
const last = total
|
|
|
|
const left = Math.max (page - siblingCount, first)
|
|
const right = Math.min (page + siblingCount, last)
|
|
|
|
const pages: (number | '…')[] = []
|
|
|
|
pages.push (first)
|
|
|
|
if (left > first + 1)
|
|
pages.push ('…')
|
|
|
|
const midStart = Math.max (left, first + 1)
|
|
const midEnd = Math.min (right, last - 1)
|
|
pages.push (...range (midStart, midEnd))
|
|
|
|
if (right < last - 1)
|
|
pages.push ('…')
|
|
|
|
if (last !== first)
|
|
pages.push (last)
|
|
|
|
return pages.filter ((v, i, arr) => i === 0 || v !== arr[i - 1])
|
|
}
|
|
|
|
|
|
export default (({ page, totalPages, siblingCount = 3 }) => {
|
|
const location = useLocation ()
|
|
|
|
const buildTo = (p: number) => {
|
|
const qs = new URLSearchParams (location.search)
|
|
qs.set ('page', String (p))
|
|
return `${ location.pathname }?${ qs.toString () }`
|
|
}
|
|
|
|
const pages = getPages (page, totalPages, siblingCount)
|
|
|
|
return (
|
|
<nav className="mt-4 flex justify-center" aria-label="Pagination">
|
|
<div className="flex items-center gap-2">
|
|
{(page > 1)
|
|
? (
|
|
<>
|
|
<PrefetchLink
|
|
className="md:hidden p-2"
|
|
to={buildTo (1)}
|
|
aria-label="最初のページ">
|
|
|<
|
|
</PrefetchLink>
|
|
<PrefetchLink
|
|
className="p-2"
|
|
to={buildTo (page - 1)}
|
|
aria-label="前のページ">
|
|
<
|
|
</PrefetchLink>
|
|
</>)
|
|
: (
|
|
<>
|
|
<span className="md:hidden p-2" aria-hidden>
|
|
|<
|
|
</span>
|
|
<span className="p-2" aria-hidden>
|
|
<
|
|
</span>
|
|
</>)}
|
|
|
|
{pages.map ((p, idx) => (
|
|
(p === '…')
|
|
? <span key={`dots-${ idx }`} className="hidden md:block p-2">…</span>
|
|
: ((p === page)
|
|
? <span key={p} className="font-bold p-2" aria-current="page">{p}</span>
|
|
: (
|
|
<PrefetchLink
|
|
key={p}
|
|
className="hidden md:block p-2"
|
|
to={buildTo (p)}>
|
|
{p}
|
|
</PrefetchLink>))))}
|
|
|
|
{(page < totalPages)
|
|
? (
|
|
<>
|
|
<PrefetchLink
|
|
className="p-2"
|
|
to={buildTo (page + 1)}
|
|
aria-label="次のページ">
|
|
>
|
|
</PrefetchLink>
|
|
<PrefetchLink
|
|
className="md:hidden p-2"
|
|
to={buildTo (totalPages)}
|
|
aria-label="最後のページ">
|
|
>|
|
|
</PrefetchLink>
|
|
</>)
|
|
: (
|
|
<>
|
|
<span className="p-2" aria-hidden>></span>
|
|
<span className="md:hidden p-2" aria-hidden>>|</span>
|
|
</>)}
|
|
</div>
|
|
</nav>)
|
|
}) satisfies FC<Props>
|