-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* adds all, very inspired by shadcn * removes unused code * adds Pagination to outer barrel file * removed more unused code and comments * improved / simplified story * adds supress unique key * refactors styling * adds margin to component * Update frontend/src/Components/Pagination/components/PaginationEllipsis/PaginationEllipsis.tsx … Co-authored-by: Robin <[email protected]> * add classnames * added classname to ellipsis * added ellipsis icon, same width as chevrons in pagination control (in DrfPagination) * uses classNames in PaginationContent * adds whitespace in PaginationContent * adds classNames in Pagination * whitespace in pagination * style to make button width consistent * renamed PaginationControl * renamed controllText to controlSymbol * removed style modularity from pagination control (removes props) * PaginationControllProps -> PaginationControlProps * newline between import and comp * newline between pagination imte comp and imports * barrel x 6 * use useMemo * fix storybook * sibling count and boundry count * klink siblings with boundries * changes to good ol regular function * better styling * renamed to paged pagination * renamed PaginationControll * more renaming * more rename * extend button prop * rename --------- Co-authored-by: Robin <[email protected]>
- Loading branch information
Showing
23 changed files
with
396 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export { Button } from './Button'; | ||
export type { ButtonProps } from './Button'; | ||
export type { ButtonDisplay, ButtonTheme } from './types'; |
6 changes: 6 additions & 0 deletions
6
frontend/src/Components/Pagination/PagedPagination.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.container { | ||
display: flex; | ||
justify-content: center; | ||
margin: 1rem; | ||
width: 100%; | ||
} |
153 changes: 153 additions & 0 deletions
153
frontend/src/Components/Pagination/PagedPagination.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import type { ComponentMeta, ComponentStory } from '@storybook/react'; | ||
import { useState } from 'react'; | ||
import { PagedPagination } from './PagedPagination'; | ||
|
||
export default { | ||
title: 'Components/DRFPagination', | ||
component: PagedPagination, | ||
argTypes: { | ||
currentPage: { | ||
control: 'number', | ||
description: 'Current active page', | ||
}, | ||
totalItems: { | ||
control: 'number', | ||
description: 'Total number of items to paginate', | ||
}, | ||
pageSize: { | ||
control: 'number', | ||
description: 'Number of items per page', | ||
}, | ||
siblingCount: { | ||
control: 'number', | ||
description: 'Number of sibling pages around the current page', | ||
defaultValue: 1, | ||
}, | ||
boundaryCount: { | ||
control: 'number', | ||
description: 'Number of pages to display at the start and end', | ||
defaultValue: 1, | ||
}, | ||
className: { | ||
control: 'text', | ||
description: 'Custom class for the pagination container', | ||
}, | ||
itemClassName: { | ||
control: 'text', | ||
description: 'Custom class for individual pagination items', | ||
}, | ||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
component: 'A pagination component designed to work with Django Rest Framework pagination.', | ||
}, | ||
}, | ||
}, | ||
} as ComponentMeta<typeof PagedPagination>; | ||
|
||
// Template with state management | ||
const Template: ComponentStory<typeof PagedPagination> = (args) => { | ||
const [currentPage, setCurrentPage] = useState(args.currentPage); | ||
|
||
return ( | ||
<div> | ||
<PagedPagination {...args} currentPage={currentPage} onPageChange={setCurrentPage} /> | ||
<p>Current page: {currentPage}</p> | ||
</div> | ||
); | ||
}; | ||
|
||
// Basic usage | ||
export const Basic = Template.bind({}); | ||
Basic.args = { | ||
currentPage: 1, | ||
totalItems: 100, | ||
pageSize: 10, | ||
}; | ||
Basic.parameters = { | ||
docs: { | ||
description: { | ||
story: 'Basic pagination with default styling', | ||
}, | ||
}, | ||
}; | ||
|
||
// Many pages example | ||
export const ManyPages = Template.bind({}); | ||
ManyPages.args = { | ||
...Basic.args, | ||
totalItems: 2500, | ||
currentPage: 7, | ||
}; | ||
ManyPages.parameters = { | ||
docs: { | ||
description: { | ||
story: 'Pagination with many pages showing ellipsis', | ||
}, | ||
}, | ||
}; | ||
|
||
// Minimal pages example | ||
export const MinimalPages = Template.bind({}); | ||
MinimalPages.args = { | ||
...Basic.args, | ||
totalItems: 30, | ||
pageSize: 10, | ||
}; | ||
MinimalPages.parameters = { | ||
docs: { | ||
description: { | ||
story: 'Pagination with only a few pages using text theme', | ||
}, | ||
}, | ||
}; | ||
|
||
// Example with increased sibling count | ||
export const SiblingCountTwo = Template.bind({}); | ||
SiblingCountTwo.args = { | ||
...Basic.args, | ||
totalItems: 250, | ||
siblingCount: 2, | ||
currentPage: 5, | ||
}; | ||
SiblingCountTwo.parameters = { | ||
docs: { | ||
description: { | ||
story: 'Pagination showing two sibling pages around the current page.', | ||
}, | ||
}, | ||
}; | ||
|
||
// Example with increased boundary count | ||
export const BoundaryCountTwo = Template.bind({}); | ||
BoundaryCountTwo.args = { | ||
...Basic.args, | ||
totalItems: 250, | ||
boundaryCount: 2, | ||
currentPage: 10, | ||
}; | ||
BoundaryCountTwo.parameters = { | ||
docs: { | ||
description: { | ||
story: 'Pagination with two boundary pages displayed at the start and end.', | ||
}, | ||
}, | ||
}; | ||
|
||
// Combination of increased sibling and boundary count | ||
export const SiblingAndBoundary = Template.bind({}); | ||
SiblingAndBoundary.args = { | ||
...Basic.args, | ||
totalItems: 250, | ||
siblingCount: 2, | ||
boundaryCount: 2, | ||
currentPage: 12, | ||
}; | ||
SiblingAndBoundary.parameters = { | ||
docs: { | ||
description: { | ||
story: 'Pagination showing two sibling pages and two boundary pages.', | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { Icon } from '@iconify/react'; | ||
import classNames from 'classnames'; | ||
import { useMemo } from 'react'; | ||
import styles from './PagedPagination.module.scss'; | ||
import { Pagination, PaginationButton, PaginationContent, PaginationEllipsis, PaginationItem } from './components'; | ||
|
||
type PagedPaginationPaginationItemType = (number | 'ellipsis')[]; | ||
|
||
interface PagedPaginationnProps { | ||
currentPage: number; | ||
totalItems: number; | ||
pageSize: number; | ||
onPageChange: (page: number) => void; | ||
siblingCount?: number; // Controls the number of sibling pages around the current page | ||
boundaryCount?: number; // Controls the number of boundary pages on each end | ||
paginationClassName?: string; | ||
itemClassName?: string; | ||
} | ||
|
||
// Helper function to generate sequential page numbers | ||
const generateSequentialPages = (start: number, end: number): number[] => { | ||
return Array.from({ length: end - start + 1 }, (_, i) => start + i); | ||
}; | ||
|
||
// Adjusted ellipsis helper functions | ||
const showStartEllipsis = (current: number, boundaryCount: number, siblingCount: number): boolean => | ||
boundaryCount > 0 && siblingCount > 0 && current > boundaryCount + siblingCount + 1; | ||
const showEndEllipsis = (current: number, total: number, boundaryCount: number, siblingCount: number): boolean => | ||
boundaryCount > 0 && siblingCount > 0 && current < total - boundaryCount - siblingCount; | ||
|
||
export function PagedPagination({ | ||
currentPage, | ||
totalItems, | ||
pageSize, | ||
onPageChange, | ||
siblingCount = 1, | ||
boundaryCount = 1, | ||
paginationClassName, | ||
itemClassName, | ||
}: PagedPaginationnProps) { | ||
const totalPages = Math.ceil(totalItems / pageSize); | ||
|
||
const paginationItems = useMemo(() => { | ||
const pages: PagedPaginationPaginationItemType = []; | ||
const startPages = generateSequentialPages(1, Math.min(boundaryCount, totalPages)); | ||
const endPages = generateSequentialPages(Math.max(totalPages - boundaryCount + 1, boundaryCount + 1), totalPages); | ||
|
||
// Early return for simple pagination case | ||
if (totalPages <= 7 + siblingCount * 2 + boundaryCount * 2) { | ||
return generateSequentialPages(1, totalPages); | ||
} | ||
|
||
// Add boundary pages at the start | ||
pages.push(...startPages); | ||
|
||
// Conditionally add start ellipsis | ||
if (showStartEllipsis(currentPage, boundaryCount, siblingCount)) { | ||
pages.push('ellipsis'); | ||
} | ||
|
||
// Add sibling pages around the current page | ||
const startSibling = Math.max(boundaryCount + 1, currentPage - siblingCount); | ||
const endSibling = Math.min(totalPages - boundaryCount, currentPage + siblingCount); | ||
pages.push(...generateSequentialPages(startSibling, endSibling)); | ||
|
||
// Conditionally add end ellipsis | ||
if (showEndEllipsis(currentPage, totalPages, boundaryCount, siblingCount)) { | ||
pages.push('ellipsis'); | ||
} | ||
|
||
// Add boundary pages at the end | ||
pages.push(...endPages); | ||
|
||
return pages; | ||
}, [currentPage, totalPages, siblingCount, boundaryCount]); | ||
|
||
return ( | ||
<div className={styles.container}> | ||
<Pagination className={classNames(paginationClassName)}> | ||
<PaginationContent> | ||
<PaginationItem className={classNames(itemClassName)}> | ||
<PaginationButton | ||
buttonSymbol={<Icon icon={'mdi:chevron-left'} />} | ||
onClick={() => currentPage > 1 && onPageChange(currentPage - 1)} | ||
disabled={currentPage === 1} | ||
/> | ||
</PaginationItem> | ||
|
||
{paginationItems.map((page, index) => ( | ||
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation> | ||
<PaginationItem key={index} className={classNames(itemClassName)}> | ||
{page === 'ellipsis' ? ( | ||
<PaginationEllipsis /> | ||
) : ( | ||
<PaginationButton | ||
isActive={page === currentPage} | ||
buttonSymbol={String(page)} | ||
onClick={() => onPageChange(page)} | ||
/> | ||
)} | ||
</PaginationItem> | ||
))} | ||
|
||
<PaginationItem className={classNames(itemClassName)}> | ||
<PaginationButton | ||
buttonSymbol={<Icon icon={'mdi:chevron-right'} />} | ||
onClick={() => currentPage < totalPages && onPageChange(currentPage + 1)} | ||
disabled={currentPage === totalPages} | ||
/> | ||
</PaginationItem> | ||
</PaginationContent> | ||
</Pagination> | ||
</div> | ||
); | ||
} |
5 changes: 5 additions & 0 deletions
5
frontend/src/Components/Pagination/components/Pagination/Pagination.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.nav { | ||
display: flex; | ||
align-items: center; | ||
width: 100%; | ||
} |
8 changes: 8 additions & 0 deletions
8
frontend/src/Components/Pagination/components/Pagination/Pagination.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import classNames from 'classnames'; | ||
import React from 'react'; | ||
import styles from './Pagination.module.scss'; | ||
|
||
export const Pagination = React.forwardRef<HTMLElement, React.ComponentProps<'nav'>>(({ className, ...props }, ref) => ( | ||
<nav ref={ref} aria-label="pagination" className={classNames(styles.nav, className)} {...props} /> | ||
)); | ||
Pagination.displayName = 'Pagination'; |
1 change: 1 addition & 0 deletions
1
frontend/src/Components/Pagination/components/Pagination/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { Pagination } from './Pagination'; |
9 changes: 9 additions & 0 deletions
9
frontend/src/Components/Pagination/components/PaginationButton/PaginationButton.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.control { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
padding: 0.25rem 0.5rem; | ||
width: 100%; | ||
min-width: 2.5rem; | ||
text-align: center; | ||
} |
33 changes: 33 additions & 0 deletions
33
frontend/src/Components/Pagination/components/PaginationButton/PaginationButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import classNames from 'classnames'; | ||
import type { ReactNode } from 'react'; | ||
import type { ButtonProps } from '~/Components'; | ||
import { Button } from '~/Components/Button'; | ||
import styles from './PaginationButton.module.scss'; | ||
|
||
type PaginationButtonProps = Omit<ButtonProps, 'theme' | 'display'> & { | ||
isActive?: boolean; | ||
buttonSymbol: string | ReactNode; | ||
}; | ||
|
||
export function PaginationButton({ | ||
isActive, | ||
className, | ||
buttonSymbol, | ||
disabled, | ||
onClick, | ||
...props | ||
}: PaginationButtonProps) { | ||
return ( | ||
<Button | ||
theme={isActive ? 'basic' : 'samf'} | ||
display={'basic'} | ||
rounded={false} | ||
onClick={onClick} | ||
disabled={disabled} | ||
className={classNames(styles.control, className)} | ||
{...props} | ||
> | ||
{buttonSymbol} | ||
</Button> | ||
); | ||
} |
1 change: 1 addition & 0 deletions
1
frontend/src/Components/Pagination/components/PaginationButton/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { PaginationButton } from './PaginationButton'; |
9 changes: 9 additions & 0 deletions
9
...tend/src/Components/Pagination/components/PaginationContent/PaginationContent.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.list { | ||
display: flex; | ||
gap: 0.5rem; | ||
align-items: center; | ||
list-style: none; | ||
padding: 0; | ||
margin: 0; | ||
width: 100%; | ||
} |
8 changes: 8 additions & 0 deletions
8
frontend/src/Components/Pagination/components/PaginationContent/PaginationContent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import classNames from 'classnames'; | ||
import React from 'react'; | ||
import styles from './PaginationContent.module.scss'; | ||
|
||
export const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<'ul'>>( | ||
({ className, ...props }, ref) => <ul ref={ref} className={classNames(styles.list, className)} {...props} />, | ||
); | ||
PaginationContent.displayName = 'PaginationContent'; |
1 change: 1 addition & 0 deletions
1
frontend/src/Components/Pagination/components/PaginationContent/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { PaginationContent } from './PaginationContent'; |
6 changes: 6 additions & 0 deletions
6
...nd/src/Components/Pagination/components/PaginationEllipsis/PaginationEllipsis.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.ellipsis { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
border: 1px solid transparent; | ||
} |
13 changes: 13 additions & 0 deletions
13
frontend/src/Components/Pagination/components/PaginationEllipsis/PaginationEllipsis.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Icon } from '@iconify/react'; | ||
import classNames from 'classnames'; | ||
import React from 'react'; | ||
import styles from './PaginationEllipsis.module.scss'; | ||
|
||
export const PaginationEllipsis = React.forwardRef<HTMLSpanElement, React.ComponentProps<'span'>>( | ||
({ className, ...props }, ref) => ( | ||
<span ref={ref} className={classNames(styles.ellipsis, className)} {...props}> | ||
<Icon icon={'lucide:ellipsis'} /> | ||
</span> | ||
), | ||
); | ||
PaginationEllipsis.displayName = 'PaginationEllipsis'; |
1 change: 1 addition & 0 deletions
1
frontend/src/Components/Pagination/components/PaginationEllipsis/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { PaginationEllipsis } from './PaginationEllipsis'; |
Oops, something went wrong.