Commit a75ee466 authored by tom's avatar tom

list pagination

parent ed2e5189
......@@ -7,19 +7,18 @@ export interface IconButtonProps extends ButtonProps {}
export const IconButton = React.forwardRef<HTMLDivElement, IconButtonProps>(
function IconButton(props, ref) {
const { loading, ...rest } = props;
const { loading, size, variant = 'plain', ...rest } = props;
return (
<Skeleton loading={ loading } asChild ref={ ref }>
<Skeleton loading={ loading } ref={ ref }>
<Button
display="inline-flex"
px="0"
py="0"
height="auto"
minW="auto"
{ ...(size ? { size } : { height: 'auto', minW: 'auto' }) }
flexShrink="0"
variant={ variant }
{ ...rest }
variant={ props.variant ?? 'plain' }
/>
</Skeleton>
);
......
'use client';
import type { HTMLChakraProps, RecipeProps } from '@chakra-ui/react';
import { createRecipeContext } from '@chakra-ui/react';
export interface LinkButtonProps
extends HTMLChakraProps<'a', RecipeProps<'button'>> {}
const { withContext } = createRecipeContext({ key: 'button' });
// TODO @tom2drum style and use this component
// Replace "a" with your framework's link component
export const LinkButton = withContext<HTMLAnchorElement, LinkButtonProps>('a');
......@@ -8,7 +8,7 @@ import { route } from 'nextjs-routes';
import useApiQuery from 'lib/api/useApiQuery';
import { nbsp } from 'lib/html-entities';
import { HOMEPAGE_STATS } from 'stubs/stats';
import Skeleton from 'ui/shared/chakra/Skeleton';
import { Skeleton } from 'toolkit/chakra/skeleton';
import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal';
import Pagination from 'ui/shared/pagination/Pagination';
......@@ -31,7 +31,7 @@ const BlocksTabSlot = ({ pagination }: Props) => {
<Text as="span" fontSize="sm">
Network utilization (last 50 blocks):{ nbsp }
</Text>
<Skeleton display="inline-block" fontSize="sm" color="blue.400" fontWeight={ 600 } isLoaded={ !statsQuery.isPlaceholderData }>
<Skeleton display="inline-block" fontSize="sm" color="blue.400" fontWeight={ 600 } loading={ statsQuery.isPlaceholderData }>
<span>{ statsQuery.data.network_utilization_percentage.toFixed(2) }%</span>
</Skeleton>
</Box>
......
......@@ -25,6 +25,7 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import AlertsShowcase from 'ui/showcases/Alerts';
import BadgesShowcase from 'ui/showcases/Badges';
import ButtonShowcase from 'ui/showcases/Button';
import PaginationShowcase from 'ui/showcases/Pagination';
import TabsShowcase from 'ui/showcases/Tabs';
const TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
......@@ -53,6 +54,7 @@ const ChakraShowcases = () => {
<TabsTrigger value="alerts">Alerts</TabsTrigger>
<TabsTrigger value="badges">Badges</TabsTrigger>
<TabsTrigger value="buttons">Buttons</TabsTrigger>
<TabsTrigger value="pagination">Pagination</TabsTrigger>
<TabsTrigger value="tabs">Tabs</TabsTrigger>
<TabsTrigger value="unsorted">Unsorted</TabsTrigger>
</TabsList>
......@@ -60,6 +62,7 @@ const ChakraShowcases = () => {
<BadgesShowcase/>
<ButtonShowcase/>
<TabsShowcase/>
<PaginationShowcase/>
<TabsContent value="unsorted">
<VStack align="flex-start" gap={ 6 }>
......
import { Button, Flex, IconButton, chakra } from '@chakra-ui/react';
import type { HTMLChakraProps } from '@chakra-ui/react';
import { Center, Flex } from '@chakra-ui/react';
import React from 'react';
import type { PaginationParams } from './types';
import Skeleton from 'ui/shared/chakra/Skeleton';
import { Button } from 'toolkit/chakra/button';
import { IconButton } from 'toolkit/chakra/icon-button';
import { Skeleton } from 'toolkit/chakra/skeleton';
import IconSvg from 'ui/shared/IconSvg';
interface Props extends PaginationParams {
className?: string;
}
interface Props extends PaginationParams, Omit<HTMLChakraProps<'div'>, 'page' | 'direction'> {}
const Pagination = ({ page, onNextPageClick, onPrevPageClick, resetPage, hasPages, hasNextPage, className, canGoBackwards, isLoading, isVisible }: Props) => {
const Pagination = (props: Props) => {
const { page, onNextPageClick, onPrevPageClick, resetPage, hasPages, hasNextPage, canGoBackwards, isLoading, isVisible, ...rest } = props;
if (!isVisible) {
return null;
......@@ -20,63 +22,62 @@ const Pagination = ({ page, onNextPageClick, onPrevPageClick, resetPage, hasPage
return (
<Flex
className={ className }
fontSize="sm"
as="nav"
alignItems="center"
{ ...rest }
>
<Skeleton isLoaded={ !showSkeleton } display="inline-block" mr={ 4 } borderRadius="base">
<Skeleton loading={ showSkeleton } mr={ 4 }>
<Button
variant="outline"
size="sm"
onClick={ resetPage }
isDisabled={ page === 1 || isLoading }
disabled={ page === 1 || isLoading }
>
First
</Button>
</Skeleton>
<Skeleton isLoaded={ !showSkeleton } display="inline-block" mr={ 3 } borderRadius="base">
<IconButton
variant="outline"
onClick={ onPrevPageClick }
size="sm"
aria-label="Prev page"
w="36px"
icon={ <IconSvg name="arrows/east-mini" w={ 5 } h={ 5 }/> }
isDisabled={ !canGoBackwards || isLoading }
/>
</Skeleton>
<Skeleton isLoaded={ !showSkeleton } display="inline-block" borderRadius="base">
<Button
variant="outline"
size="sm"
data-selected={ true }
borderWidth="1px"
fontWeight={ 400 }
<IconButton
aria-label="Prev page"
variant="outline"
w={ 9 }
size="sm"
onClick={ onPrevPageClick }
disabled={ !canGoBackwards || isLoading || page === 1 }
loading={ showSkeleton }
>
<IconSvg name="arrows/east-mini" boxSize={ 5 }/>
</IconButton>
<Skeleton loading={ showSkeleton } mx={ 2 } >
<Center
display="flex"
alignItems="center"
justifyContent="center"
h={ 8 }
minW="36px"
cursor="unset"
minW={ 9 }
px={ 2 }
bgColor={{ _light: 'blue.50', _dark: 'whiteAlpha.100' }}
color={{ _light: 'blackAlpha.800', _dark: 'gray.50' }}
borderRadius="base"
textStyle="sm"
>
{ page }
</Button>
</Skeleton>
<Skeleton isLoaded={ !showSkeleton } display="inline-block" ml={ 3 } borderRadius="base">
<IconButton
variant="outline"
onClick={ onNextPageClick }
size="sm"
aria-label="Next page"
w="36px"
icon={ <IconSvg name="arrows/east-mini" w={ 5 } h={ 5 } transform="rotate(180deg)"/> }
isDisabled={ !hasNextPage || isLoading }
/>
</Center>
</Skeleton>
{ /* not implemented yet */ }
{ /* <Flex alignItems="center" width="132px" ml={ 16 } display={{ base: 'none', lg: 'flex' }}>
Go to <Input w="84px" size="xs" ml={ 2 }/>
</Flex> */ }
<IconButton
aria-label="Next page"
variant="outline"
w={ 9 }
size="sm"
onClick={ onNextPageClick }
disabled={ !hasNextPage || isLoading }
loading={ showSkeleton }
>
<IconSvg name="arrows/east-mini" boxSize={ 5 } transform="rotate(180deg)"/>
</IconButton>
</Flex>
);
};
export default chakra(Pagination);
export default React.memo(Pagination);
import type { UseQueryResult } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import { omit } from 'es-toolkit';
import { clamp, omit } from 'es-toolkit';
import { useRouter } from 'next/router';
import React, { useCallback } from 'react';
import { animateScroll } from 'react-scroll';
......@@ -131,7 +131,7 @@ export default function useQueryWithPages<Resource extends PaginatedResources>({
scrollToTop();
router.push({ pathname: router.pathname, query: nextPageQuery }, undefined, { shallow: true })
.then(() => {
setPage(prev => prev - 1);
setPage(prev => clamp(prev - 1, 1, Infinity));
page === 2 && queryClient.removeQueries({ queryKey: [ resourceName ] });
});
}, [ router, page, pageParams, scrollToTop, queryClient, resourceName ]);
......
import React from 'react';
import Pagination from 'ui/shared/pagination/Pagination';
import { Section, Container, SectionHeader, SamplesStack, Sample, SectionSubHeader } from './parts';
const PaginationShowcase = () => {
const [ page, setPage ] = React.useState(1);
const handleNextPageClick = () => {
setPage(page + 1);
};
const handlePrevPageClick = () => {
setPage(page - 1);
};
const props = {
page,
onNextPageClick: handleNextPageClick,
onPrevPageClick: handlePrevPageClick,
resetPage: () => setPage(1),
hasNextPage: page < 10,
hasPages: true,
isVisible: true,
canGoBackwards: true,
isLoading: false,
};
return (
<Container value="pagination">
<Section>
<SectionHeader>Examples</SectionHeader>
<SectionSubHeader>List pagination</SectionSubHeader>
<SamplesStack>
<Sample label="Loaded state">
<Pagination { ...props }/>
</Sample>
<Sample label="Initial loading state">
<Pagination { ...props } hasPages={ false } page={ 1 } isLoading/>
</Sample>
<Sample label="Next page loading state">
<Pagination { ...props } isLoading/>
</Sample>
</SamplesStack>
</Section>
</Container>
);
};
export default React.memo(PaginationShowcase);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment