File size: 2,645 Bytes
25a7ba5
 
08e8583
25a7ba5
 
 
 
 
 
 
 
2468399
25a7ba5
2468399
25a7ba5
2468399
25a7ba5
 
 
 
 
2468399
25a7ba5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
08e8583
25a7ba5
 
 
 
 
 
 
 
 
 
 
 
 
 
08e8583
25a7ba5
 
 
 
 
 
 
08e8583
25a7ba5
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<script lang="ts">
	import { page } from "$app/stores";
	import { getHref } from "$lib/utils/getHref";
	import PaginationArrow from "./PaginationArrow.svelte";

	export let classNames = "";
	export let numItemsPerPage: number;
	export let numTotalItems: number;

	const ELLIPSIS_IDX = -1 as const;

	$: numTotalPages = Math.ceil(numTotalItems / numItemsPerPage);
	$: pageIndex = parseInt($page.url.searchParams.get("p") ?? "0");
	$: pageIndexes = getPageIndexes(pageIndex, numTotalPages);

	function getPageIndexes(pageIdx: number, nTotalPages: number) {
		let pageIdxs: number[] = [];

		const NUM_EXTRA_BUTTONS = 2; // The number of page links to show on either side of the current page link.

		const minIdx = 0;
		const maxIdx = nTotalPages - 1;

		pageIdxs = [pageIdx];

		// forward
		for (let i = 1; i < NUM_EXTRA_BUTTONS + 1; i++) {
			const newPageIdx = pageIdx + i;
			if (newPageIdx > maxIdx) {
				continue;
			}
			pageIdxs.push(newPageIdx);
		}
		if (maxIdx - pageIdxs[pageIdxs.length - 1] > 1) {
			pageIdxs.push(...[ELLIPSIS_IDX, maxIdx]);
		} else if (maxIdx - pageIdxs[pageIdxs.length - 1] === 1) {
			pageIdxs.push(maxIdx);
		}

		// backward
		for (let i = 1; i < NUM_EXTRA_BUTTONS + 1; i++) {
			const newPageIdx = pageIdx - i;
			if (newPageIdx < minIdx) {
				continue;
			}
			pageIdxs.unshift(newPageIdx);
		}
		if (pageIdxs[0] - minIdx > 1) {
			pageIdxs.unshift(...[minIdx, ELLIPSIS_IDX]);
		} else if (pageIdxs[0] - minIdx === 1) {
			pageIdxs.unshift(minIdx);
		}
		return pageIdxs;
	}
</script>

{#if numTotalPages > 1}
	<nav>
		<ul
			class="flex select-none items-center justify-between space-x-2 text-gray-700 sm:justify-center dark:text-gray-300 {classNames}"
		>
			<li>
				<PaginationArrow
					href={getHref($page.url, { newKeys: { p: (pageIndex - 1).toString() } })}
					direction="previous"
					isDisabled={pageIndex - 1 < 0}
				/>
			</li>
			{#each pageIndexes as pageIdx}
				<li class="hidden sm:block">
					<a
						class="
							rounded-lg px-2.5 py-1
							{pageIndex === pageIdx
							? 'bg-gray-50 font-semibold ring-1 ring-inset ring-gray-200 dark:bg-gray-800 dark:text-yellow-500 dark:ring-gray-700'
							: ''}
						"
						class:pointer-events-none={pageIdx === ELLIPSIS_IDX || pageIndex === pageIdx}
						href={getHref($page.url, { newKeys: { p: pageIdx.toString() } })}
					>
						{pageIdx === ELLIPSIS_IDX ? "..." : pageIdx + 1}
					</a>
				</li>
			{/each}
			<li>
				<PaginationArrow
					href={getHref($page.url, { newKeys: { p: (pageIndex + 1).toString() } })}
					direction="next"
					isDisabled={pageIndex + 1 >= numTotalPages}
				/>
			</li>
		</ul>
	</nav>
{/if}