Skip to content

Commit

Permalink
add pagination component
Browse files Browse the repository at this point in the history
  • Loading branch information
tuan2311 committed Aug 11, 2020
1 parent 527ff6a commit e688e36
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 0 deletions.
137 changes: 137 additions & 0 deletions src/components/ui/containers/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React, { HTMLAttributes, useState } from 'react';
import 'twin.macro';
import { Icon } from '~/components/ui/icons/Icon';
import cn from 'classnames';
import { range } from '~/utils/array/range';
import { noop } from '~/utils/functions';

export function Pagination({
numPages,
onSelect = noop,
current,
marginPagesDisplayed = 3,
pageRangeDisplayed = 3,
}: {
numPages: number;
current: number;
onSelect?: (number) => void;
marginPagesDisplayed?: number;
pageRangeDisplayed?: number;
}) {
const [middlePage, setMiddlePage] = useState(current);
console.log(middlePage);
const pagesToShow: Set<any> = new Set();
for (const page of range(1, Math.min(1 + marginPagesDisplayed, numPages))) {
pagesToShow.add(page);
}

for (const page of range(
numPages,
Math.max(numPages - marginPagesDisplayed + 1, 1) - 1,
-1
)) {
pagesToShow.add(page);
}

for (const page of range(
Math.max(1, middlePage - (pageRangeDisplayed - 1) / 2),
Math.min(middlePage + (pageRangeDisplayed - 1) / 2, numPages) + 1
)) {
pagesToShow.add(page);
}

const pageArray = Array.from(pagesToShow).sort((a, b) => a - b);
let index = 0;
while (index < pageArray.length - 1) {
if (pageArray[index] + 1 < pageArray[index + 1]) {
// there is a gap, insert ...
pageArray.splice(index + 1, 0, '...');
index++;
}
index++;
}

return (
<div tw='flex flex-col items-center my-12'>
<div tw='flex text-gray-700'>
<div
tw='h-10 w-10 ml-1 flex justify-center items-center rounded-full bg-gray-200'
className={cn({
'cursor-pointer': isInRange(current - 1, 1, numPages),
'opacity-50': !isInRange(current - 1, 1, numPages),
'cursor-not-allowed': !isInRange(current - 1, 1, numPages),
})}
onClick={() => {
if (!isInRange(current - 1, 1, numPages)) {
return;
}
onSelect(current - 1);
}}
>
<Icon name={'arrow-left'} size={20} />
</div>
<div tw='flex h-10 font-medium rounded-full bg-gray-200'>
{pageArray.map((page, index) => (
<Page
text={page}
key={`${page}-${index}`}
selected={page === current}
onClick={() => {
if (page !== '...') {
onSelect(page);
} else {
if (!pageArray.slice(index + 1).includes('...')) {
// first occurence of ..., show next page
setMiddlePage(pageArray[index - 1] + 1);
} else {
// second occurence of ..., show previous page
setMiddlePage(pageArray[index + 1] - 1);
}
}
}}
/>
))}
</div>
<div
tw='h-10 w-10 ml-1 flex justify-center items-center rounded-full bg-gray-200'
className={cn({
'cursor-pointer': isInRange(current + 1, 1, numPages),
'opacity-75': !isInRange(current + 1, 1, numPages),
'cursor-not-allowed': !isInRange(current + 1, 1, numPages),
})}
onClick={() => {
if (!isInRange(current + 1, 1, numPages)) {
return;
}
onSelect(current + 1);
}}
>
<Icon name={'arrow-right'} size={20} />
</div>
</div>
</div>
);
}

function isInRange(page, start, end) {
return page >= start && page <= end;
}

function Page({
text,
selected,
...props
}: { text: string; selected: boolean } & HTMLAttributes<HTMLDivElement>) {
return (
<div
{...props}
className={cn({
'bg-accent': selected,
'text-white': selected,
})}
tw='w-10 md:flex justify-center items-center hidden cursor-pointer leading-5 transition duration-150 ease-in rounded-full'
>
{text}
</div>
);
}
2 changes: 2 additions & 0 deletions src/components/ui/icons/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export type SvgIcon =
| 'bag'
| 'calendar'
| 'arrow-narrow-left'
| 'arrow-left'
| 'arrow-right'
| 'arrow-narrow-right'
| 'check';

Expand Down
4 changes: 4 additions & 0 deletions src/icons/arrow-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/icons/arrow-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions src/utils/array/range.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export function range(start: number, stop?: number, step = 1) {
if (typeof stop === 'undefined') {
stop = start;
start = 0;
}

if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
return [];
}

const result: number[] = [];
for (
let count = start;
step > 0 ? count < stop : count > stop;
count += step
) {
result.push(count);
}

return result;
}

0 comments on commit e688e36

Please sign in to comment.