Skip to content

Commit

Permalink
Merge pull request #21 from jebbaited/feature/MoveToSpecificPage
Browse files Browse the repository at this point in the history
feature: add the ability to go to the specific page in pagination
  • Loading branch information
olexh authored May 15, 2024
2 parents 76f2b82 + 7db740a commit 3c575e0
Showing 1 changed file with 119 additions and 20 deletions.
139 changes: 119 additions & 20 deletions components/ui/pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use client';

import clsx from 'clsx';
import { ChangeEvent, FC, useEffect, useState } from 'react';
import AntDesignArrowLeftOutlined from '~icons/ant-design/arrow-left-outlined';
import AntDesignArrowRightOutlined from '~icons/ant-design/arrow-right-outlined';

import { range } from '@antfu/utils';

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { cn } from '@/utils/utils';

interface Props {
Expand All @@ -15,35 +16,122 @@ interface Props {
setPage: (page: number) => void;
}

const Component = ({ page, pages, setPage }: Props) => {
type PaginationType = number | 'empty' | 'input';

const PaginationEmpty: FC = () => {
return (
<Button
size="icon-md"
variant="outline"
disabled
className={cn('size-9 sm:size-10')}
>
...
</Button>
);
};

interface PaginationButtonProps {
value: number;
page: number;
setPage: (page: number) => void;
}

const PaginationButton: FC<PaginationButtonProps> = ({
value,
page,
setPage,
}) => {
return (
<Button
size="icon-md"
variant={value === page ? 'default' : 'outline'}
disabled={!value}
onClick={() => value && setPage(value)}
className={cn('size-9 sm:size-10')}
>
{value}
</Button>
);
};

interface PaginationInputProps {
pages: number;
page: number;
setPage: (page: number) => void;
}

const PaginationInput: FC<PaginationInputProps> = ({
page,
setPage,
pages,
}) => {
const [pageToMove, setPageToMove] = useState<string>('');

const handleMoveToPage = (event: ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
const digitsOnlyRegex = /^(?!0)\d+$/;

if (!digitsOnlyRegex.test(value)) return setPageToMove('');

if (parseInt(value) > pages) return;

setPageToMove(value);
};

useEffect(() => {
setPageToMove('');
}, [page]);

return (
<Input
value={pageToMove}
placeholder="..."
onChange={handleMoveToPage}
onKeyDown={(e) => {
if (!pageToMove) return;

if (e.key === 'Enter') {
e.preventDefault();
setPage(parseInt(pageToMove));
setPageToMove('');
}
}}
className={cn('size-9 sm:size-10', pageToMove && ' w-16 sm:w-16')}
/>
);
};

const Pagination = ({ page, pages, setPage }: Props) => {
const generatePaginationArr = () => {
const pagArr: (number | undefined)[] = [1];
const pagArr: PaginationType[] = [1];

if (pages >= 7) {
if (pages - page <= 3) {
pagArr.push(undefined);
pagArr.push('input');
pagArr.push(...range(pages - 4, pages + 1));

return pagArr;
}

if (page < 5) {
pagArr.push(...range(2, 6));
pagArr.push(undefined);
pagArr.push('input');
pagArr.push(pages);

return pagArr;
}

pagArr.push(undefined);
pagArr.push('empty');
pagArr.push(...range(page - 1, page + 2));
pagArr.push(undefined);
pagArr.push('input');
pagArr.push(pages);

return pagArr;
}

pagArr.push(...range(2, pages + 1));

return pagArr;
};

Expand All @@ -54,35 +142,46 @@ const Component = ({ page, pages, setPage }: Props) => {
variant="outline"
onClick={() => setPage(page - 1)}
disabled={page === 1}
className={clsx('text-xs h-9 w-9 sm:h-10 sm:w-10')}
className={cn('size-9 text-xs sm:size-10')}
>
<AntDesignArrowLeftOutlined />
</Button>
{generatePaginationArr().map((v, index) => {
{generatePaginationArr().map((value, index) => {
if (typeof value === 'number') {
return (
<PaginationButton
key={index}
value={value}
page={page}
setPage={setPage}
/>
);
}

if (value === 'empty') {
return <PaginationEmpty key={index} />;
}

return (
<Button
size="icon-md"
variant={page === v ? 'default' : 'outline'}
disabled={!v}
onClick={() => v && setPage(v)}
<PaginationInput
page={page}
setPage={setPage}
pages={pages}
key={index}
className={cn('size-9 sm:size-10', !v && 'w-auto')}
>
{v ? v : '...'}
</Button>
/>
);
})}
<Button
size="icon-md"
variant="outline"
onClick={() => setPage(page + 1)}
disabled={page === pages}
className={clsx('text-xs h-9 w-9 sm:h-10 sm:w-10')}
className={cn('size-9 text-xs sm:size-10')}
>
<AntDesignArrowRightOutlined />
</Button>
</div>
);
};

export default Component;
export default Pagination;

0 comments on commit 3c575e0

Please sign in to comment.