mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(console): pagination (#453)
* feat(console): pagination * fix: large number * fix: new icon
This commit is contained in:
parent
a08abfd4c6
commit
fd8ea43f0b
8 changed files with 137 additions and 5 deletions
|
@ -36,6 +36,7 @@
|
|||
"react-i18next": "^11.15.4",
|
||||
"react-markdown": "^8.0.0",
|
||||
"react-modal": "^3.14.4",
|
||||
"react-paginate": "^8.1.2",
|
||||
"react-router-dom": "^6.2.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"swr": "^1.2.2"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { I18nKey } from '@logto/phrases';
|
||||
import { conditionalString } from '@silverhand/essentials';
|
||||
import classNames from 'classnames';
|
||||
import React, { HTMLProps, ReactNode } from 'react';
|
||||
import React, { HTMLProps, ReactElement, ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import DangerousRaw from '../DangerousRaw';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type BaseProps = Omit<HTMLProps<HTMLButtonElement>, 'type' | 'size' | 'title'> & {
|
||||
|
@ -13,12 +14,12 @@ type BaseProps = Omit<HTMLProps<HTMLButtonElement>, 'type' | 'size' | 'title'> &
|
|||
};
|
||||
|
||||
type TitleButtonProps = BaseProps & {
|
||||
title: I18nKey;
|
||||
title: I18nKey | ReactElement<typeof DangerousRaw>;
|
||||
icon?: ReactNode;
|
||||
};
|
||||
|
||||
type IconButtonProps = BaseProps & {
|
||||
title?: I18nKey;
|
||||
title?: I18nKey | ReactElement<typeof DangerousRaw>;
|
||||
icon: ReactNode;
|
||||
};
|
||||
|
||||
|
@ -30,6 +31,7 @@ const Button = ({
|
|||
size = 'medium',
|
||||
title,
|
||||
icon,
|
||||
className,
|
||||
...rest
|
||||
}: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -40,13 +42,14 @@ const Button = ({
|
|||
styles.button,
|
||||
styles[type],
|
||||
styles[size],
|
||||
conditionalString(icon && styles.withIcon)
|
||||
conditionalString(icon && styles.withIcon),
|
||||
className
|
||||
)}
|
||||
type={htmlType}
|
||||
{...rest}
|
||||
>
|
||||
{icon && <span className={styles.icon}>{icon}</span>}
|
||||
{title && <span>{t(title)}</span>}
|
||||
{title && (typeof title === 'string' ? <span>{t(title)}</span> : title)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
|
9
packages/console/src/components/DangerousRaw/index.tsx
Normal file
9
packages/console/src/components/DangerousRaw/index.tsx
Normal file
|
@ -0,0 +1,9 @@
|
|||
import React, { ReactNode } from 'react';
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const DangerousRaw = ({ children }: Props) => <span>{children}</span>;
|
||||
|
||||
export default DangerousRaw;
|
14
packages/console/src/components/Pagination/Next.tsx
Normal file
14
packages/console/src/components/Pagination/Next.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
const Next = () => {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12.9509 9.40832L8.23425 4.69999C8.15679 4.62188 8.06462 4.55989 7.96307 4.51758C7.86152 4.47527 7.7526 4.45349 7.64259 4.45349C7.53258 4.45349 7.42366 4.47527 7.32211 4.51758C7.22056 4.55989 7.12839 4.62188 7.05092 4.69999C6.89571 4.85613 6.80859 5.06734 6.80859 5.28749C6.80859 5.50764 6.89571 5.71885 7.05092 5.87499L11.1759 10.0417L7.05092 14.1667C6.89571 14.3228 6.80859 14.534 6.80859 14.7542C6.80859 14.9743 6.89571 15.1855 7.05092 15.3417C7.1281 15.4204 7.22014 15.483 7.3217 15.526C7.42326 15.5689 7.53233 15.5912 7.64259 15.5917C7.75284 15.5912 7.86191 15.5689 7.96348 15.526C8.06504 15.483 8.15708 15.4204 8.23425 15.3417L12.9509 10.6333C13.0355 10.5553 13.103 10.4606 13.1492 10.3552C13.1954 10.2497 13.2192 10.1359 13.2192 10.0208C13.2192 9.90574 13.1954 9.7919 13.1492 9.68648C13.103 9.58107 13.0355 9.48636 12.9509 9.40832Z"
|
||||
fill="#747778"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default Next;
|
14
packages/console/src/components/Pagination/Previous.tsx
Normal file
14
packages/console/src/components/Pagination/Previous.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
const Previous = () => {
|
||||
return (
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M7.04908 9.40832L11.7657 4.69999C11.8432 4.62188 11.9354 4.55989 12.0369 4.51758C12.1385 4.47527 12.2474 4.45349 12.3574 4.45349C12.4674 4.45349 12.5763 4.47527 12.6779 4.51758C12.7794 4.55989 12.8716 4.62188 12.9491 4.69999C13.1043 4.85613 13.1914 5.06734 13.1914 5.28749C13.1914 5.50764 13.1043 5.71885 12.9491 5.87499L8.82408 10.0417L12.9491 14.1667C13.1043 14.3228 13.1914 14.534 13.1914 14.7542C13.1914 14.9743 13.1043 15.1855 12.9491 15.3417C12.8719 15.4204 12.7799 15.483 12.6783 15.526C12.5767 15.5689 12.4677 15.5912 12.3574 15.5917C12.2472 15.5912 12.1381 15.5689 12.0365 15.526C11.935 15.483 11.8429 15.4204 11.7657 15.3417L7.04908 10.6333C6.96449 10.5553 6.89698 10.4606 6.85081 10.3552C6.80464 10.2497 6.7808 10.1359 6.7808 10.0208C6.7808 9.90574 6.80464 9.7919 6.85081 9.68648C6.89698 9.58107 6.96449 9.48636 7.04908 9.40832Z"
|
||||
fill="#747778"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default Previous;
|
37
packages/console/src/components/Pagination/index.module.scss
Normal file
37
packages/console/src/components/Pagination/index.module.scss
Normal file
|
@ -0,0 +1,37 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-left: _.unit(2);
|
||||
}
|
||||
|
||||
.button {
|
||||
border-radius: 6px;
|
||||
min-width: 32px;
|
||||
padding: 0 6px;
|
||||
height: 32px;
|
||||
text-overflow: unset;
|
||||
|
||||
> span {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
.button {
|
||||
cursor: not-allowed;
|
||||
background: var(--color-neutral-95);
|
||||
|
||||
&:hover {
|
||||
background: var(--color-neutral-95);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
packages/console/src/components/Pagination/index.tsx
Normal file
43
packages/console/src/components/Pagination/index.tsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
import React from 'react';
|
||||
import ReactPaginate from 'react-paginate';
|
||||
|
||||
import Button from '../Button';
|
||||
import DangerousRaw from '../DangerousRaw';
|
||||
import Next from './Next';
|
||||
import Previous from './Previous';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
type Props = {
|
||||
pageIndex: number;
|
||||
pageCount: number;
|
||||
onChange?: (pageIndex: number) => void;
|
||||
};
|
||||
|
||||
const Pagination = ({ pageIndex, pageCount, onChange }: Props) => {
|
||||
return (
|
||||
<ReactPaginate
|
||||
className={styles.pagination}
|
||||
pageCount={pageCount}
|
||||
forcePage={pageIndex - 1}
|
||||
pageLabelBuilder={(page: number) => (
|
||||
<Button
|
||||
type={page === pageIndex ? 'outline' : 'default'}
|
||||
className={styles.button}
|
||||
size="small"
|
||||
title={<DangerousRaw>{page}</DangerousRaw>}
|
||||
/>
|
||||
)}
|
||||
previousLabel={<Button className={styles.button} size="small" icon={<Previous />} />}
|
||||
nextLabel={<Button className={styles.button} size="small" icon={<Next />} />}
|
||||
breakLabel={
|
||||
<Button className={styles.button} size="small" title={<DangerousRaw>...</DangerousRaw>} />
|
||||
}
|
||||
disabledClassName={styles.disabled}
|
||||
onPageChange={({ selected }) => {
|
||||
onChange?.(selected + 1);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Pagination;
|
|
@ -57,6 +57,7 @@ importers:
|
|||
react-i18next: ^11.15.4
|
||||
react-markdown: ^8.0.0
|
||||
react-modal: ^3.14.4
|
||||
react-paginate: ^8.1.2
|
||||
react-router-dom: ^6.2.2
|
||||
remark-gfm: ^3.0.1
|
||||
stylelint: ^13.13.1
|
||||
|
@ -82,6 +83,7 @@ importers:
|
|||
react-i18next: 11.15.4_2c37a602a29bb6bd53f3de707a8cfcc5
|
||||
react-markdown: 8.0.0_cfedea9b3ed0faf0dded75c187406c5e
|
||||
react-modal: 3.14.4_react-dom@17.0.2+react@17.0.2
|
||||
react-paginate: 8.1.2_react@17.0.2
|
||||
react-router-dom: 6.2.2_react-dom@17.0.2+react@17.0.2
|
||||
remark-gfm: 3.0.1
|
||||
swr: 1.2.2_react@17.0.2
|
||||
|
@ -11982,6 +11984,15 @@ packages:
|
|||
warning: 4.0.3
|
||||
dev: false
|
||||
|
||||
/react-paginate/8.1.2_react@17.0.2:
|
||||
resolution: {integrity: sha512-buBkBiN9J8gvZYwYNixlTGRmWOC5C6+tH2XHTN8B5qGkRPOSYFkAqxhWUnxSVAeLKxpVZGPya/gOL2eJQNZGvg==}
|
||||
peerDependencies:
|
||||
react: ^16 || ^17
|
||||
dependencies:
|
||||
prop-types: 15.8.1
|
||||
react: 17.0.2
|
||||
dev: false
|
||||
|
||||
/react-phone-number-input/3.1.46_react-dom@17.0.2+react@17.0.2:
|
||||
resolution: {integrity: sha512-afYl7BMy/0vMqWtzsZBmOgiPdqQAGyPO/Z3auorFs4K/zgFSBq3YoaASleodBkeRO/PygJ4ML8Wnb4Ce+3dlVQ==}
|
||||
peerDependencies:
|
||||
|
|
Loading…
Reference in a new issue