mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-24 10:46:30 -05:00
History pagination (#58)
Adds pagination for the history page. fixes #32
This commit is contained in:
parent
70ab02431c
commit
11f01094b4
7 changed files with 185 additions and 37 deletions
|
@ -1,18 +1,23 @@
|
|||
import React, {Fragment} from 'react'
|
||||
import React from 'react'
|
||||
import {HistoryEntriesProps} from "../history-content/history-content";
|
||||
import {HistoryCard} from "./history-card";
|
||||
import {Pager} from '../../../../pagination/pager';
|
||||
import {Row} from 'react-bootstrap';
|
||||
|
||||
export const HistoryCardList: React.FC<HistoryEntriesProps> = ({entries, onPinClick, pageIndex, onLastPageIndexChange}) => {
|
||||
|
||||
export const HistoryCardList: React.FC<HistoryEntriesProps> = ({entries, onPinClick}) => {
|
||||
return (
|
||||
<Fragment>
|
||||
{
|
||||
entries.map((entry) => (
|
||||
<HistoryCard
|
||||
key={entry.id}
|
||||
entry={entry}
|
||||
onPinClick={onPinClick}
|
||||
/>))
|
||||
}
|
||||
</Fragment>
|
||||
)
|
||||
<Row className="justify-content-center">
|
||||
<Pager numberOfElementsPerPage={6} pageIndex={pageIndex} onLastPageIndexChange={onLastPageIndexChange}>
|
||||
{
|
||||
entries.map((entry) => (
|
||||
<HistoryCard
|
||||
key={entry.id}
|
||||
entry={entry}
|
||||
onPinClick={onPinClick}
|
||||
/>))
|
||||
}
|
||||
</Pager>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from "react";
|
||||
import React, {Fragment, useState} from "react";
|
||||
import {HistoryEntry, pinClick} from "../history";
|
||||
import {HistoryTable} from "../history-table/history-table";
|
||||
import {Alert} from "react-bootstrap";
|
||||
import {Alert, Row} from "react-bootstrap";
|
||||
import {Trans} from "react-i18next";
|
||||
import {HistoryCardList} from "../history-card/history-card-list";
|
||||
import {ViewStateEnum} from "../history-toolbar/history-toolbar";
|
||||
import {PagerPagination} from "../../../../pagination/pager-pagination";
|
||||
|
||||
export interface HistoryContentProps {
|
||||
viewState: ViewStateEnum
|
||||
|
@ -20,23 +21,43 @@ export interface HistoryEntryProps {
|
|||
export interface HistoryEntriesProps {
|
||||
entries: HistoryEntry[]
|
||||
onPinClick: pinClick
|
||||
pageIndex: number
|
||||
onLastPageIndexChange: (lastPageIndex: number) => void
|
||||
}
|
||||
|
||||
|
||||
export const HistoryContent: React.FC<HistoryContentProps> = ({viewState, entries, onPinClick}) => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [lastPageIndex, setLastPageIndex] = useState(0);
|
||||
|
||||
if (entries.length === 0) {
|
||||
return (
|
||||
<Alert variant={"secondary"}>
|
||||
<Trans i18nKey={"noHistory"}/>
|
||||
</Alert>
|
||||
<Row className={"justify-content-center"}>
|
||||
<Alert variant={"secondary"}>
|
||||
<Trans i18nKey={"noHistory"}/>
|
||||
</Alert>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
switch (viewState) {
|
||||
default:
|
||||
case ViewStateEnum.card:
|
||||
return <HistoryCardList entries={entries} onPinClick={onPinClick}/>
|
||||
case ViewStateEnum.table:
|
||||
return <HistoryTable entries={entries} onPinClick={onPinClick}/>;
|
||||
const mapViewStateToComponent = (viewState: ViewStateEnum) => {
|
||||
switch (viewState) {
|
||||
default:
|
||||
case ViewStateEnum.card:
|
||||
return <HistoryCardList entries={entries} onPinClick={onPinClick} pageIndex={pageIndex}
|
||||
onLastPageIndexChange={setLastPageIndex}/>
|
||||
case ViewStateEnum.table:
|
||||
return <HistoryTable entries={entries} onPinClick={onPinClick} pageIndex={pageIndex}
|
||||
onLastPageIndexChange={setLastPageIndex}/>
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{mapViewStateToComponent(viewState)}
|
||||
<Row className="justify-content-center">
|
||||
<PagerPagination numberOfPageButtonsToShowAfterAndBeforeCurrent={2} lastPageIndex={lastPageIndex}
|
||||
onPageChange={setPageIndex}/>
|
||||
</Row>
|
||||
</Fragment>);
|
||||
}
|
|
@ -3,8 +3,9 @@ import {Table} from "react-bootstrap"
|
|||
import {HistoryTableRow} from "./history-table-row";
|
||||
import {HistoryEntriesProps} from "../history-content/history-content";
|
||||
import {Trans} from "react-i18next";
|
||||
import {Pager} from "../../../../pagination/pager";
|
||||
|
||||
const HistoryTable: React.FC<HistoryEntriesProps> = ({entries, onPinClick}) => {
|
||||
export const HistoryTable: React.FC<HistoryEntriesProps> = ({entries, onPinClick, pageIndex, onLastPageIndexChange}) => {
|
||||
return (
|
||||
<Table striped bordered hover size="sm" variant="dark">
|
||||
<thead>
|
||||
|
@ -16,17 +17,17 @@ const HistoryTable: React.FC<HistoryEntriesProps> = ({entries, onPinClick}) => {
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
entries.map((entry) =>
|
||||
<HistoryTableRow
|
||||
key={entry.id}
|
||||
entry={entry}
|
||||
onPinClick={onPinClick}
|
||||
/>)
|
||||
}
|
||||
<Pager numberOfElementsPerPage={6} pageIndex={pageIndex} onLastPageIndexChange={onLastPageIndexChange}>
|
||||
{
|
||||
entries.map((entry) =>
|
||||
<HistoryTableRow
|
||||
key={entry.id}
|
||||
entry={entry}
|
||||
onPinClick={onPinClick}
|
||||
/>)
|
||||
}
|
||||
</Pager>
|
||||
</tbody>
|
||||
</Table>
|
||||
)
|
||||
}
|
||||
|
||||
export {HistoryTable}
|
||||
|
|
|
@ -57,11 +57,9 @@ export const History: React.FC = () => {
|
|||
<Row className={"justify-content-center mb-3"}>
|
||||
<HistoryToolbar onSettingsChange={setViewState} tags={tags}/>
|
||||
</Row>
|
||||
<div className="d-flex flex-wrap justify-content-center">
|
||||
<HistoryContent viewState={viewState.viewState}
|
||||
entries={entriesToShow}
|
||||
onPinClick={pinClick}/>
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
17
src/components/pagination/pager-item.tsx
Normal file
17
src/components/pagination/pager-item.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import React from "react";
|
||||
|
||||
export interface PageItemProps {
|
||||
onClick: (index: number) => void
|
||||
index: number
|
||||
}
|
||||
|
||||
|
||||
export const PagerItem: React.FC<PageItemProps> = ({index, onClick}) => {
|
||||
return (
|
||||
<li className="page-item">
|
||||
<span className="page-link" role="button" onClick={() => onClick(index)}>
|
||||
{index + 1}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
82
src/components/pagination/pager-pagination.tsx
Normal file
82
src/components/pagination/pager-pagination.tsx
Normal file
|
@ -0,0 +1,82 @@
|
|||
import React, {Fragment, useEffect, useState} from "react";
|
||||
import {Pagination} from "react-bootstrap";
|
||||
import {PagerItem} from "./pager-item";
|
||||
|
||||
export interface PaginationProps {
|
||||
numberOfPageButtonsToShowAfterAndBeforeCurrent: number
|
||||
onPageChange: (pageIndex: number) => void
|
||||
lastPageIndex: number
|
||||
}
|
||||
|
||||
export const PagerPagination: React.FC<PaginationProps> = ({numberOfPageButtonsToShowAfterAndBeforeCurrent, onPageChange, lastPageIndex}) => {
|
||||
if (numberOfPageButtonsToShowAfterAndBeforeCurrent % 2 !== 0) {
|
||||
throw new Error("number of pages to show must be even!")
|
||||
}
|
||||
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const correctedPageIndex = Math.min(pageIndex, lastPageIndex);
|
||||
const wantedUpperPageIndex = correctedPageIndex + numberOfPageButtonsToShowAfterAndBeforeCurrent;
|
||||
const wantedLowerPageIndex = correctedPageIndex - numberOfPageButtonsToShowAfterAndBeforeCurrent;
|
||||
|
||||
useEffect(() => {
|
||||
onPageChange(pageIndex)
|
||||
}, [onPageChange, pageIndex])
|
||||
|
||||
const correctedLowerPageIndex =
|
||||
Math.min(
|
||||
Math.max(
|
||||
Math.min(
|
||||
wantedLowerPageIndex,
|
||||
wantedLowerPageIndex + lastPageIndex - wantedUpperPageIndex
|
||||
),
|
||||
0
|
||||
),
|
||||
lastPageIndex
|
||||
);
|
||||
|
||||
const correctedUpperPageIndex =
|
||||
Math.max(
|
||||
Math.min(
|
||||
Math.max(
|
||||
wantedUpperPageIndex,
|
||||
wantedUpperPageIndex - wantedLowerPageIndex
|
||||
),
|
||||
lastPageIndex
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
const paginationItemsBefore = Array.from(new Array(correctedPageIndex - correctedLowerPageIndex)).map((k, index) => {
|
||||
const itemIndex = correctedLowerPageIndex + index;
|
||||
return <PagerItem key={itemIndex} index={itemIndex} onClick={setPageIndex}/>
|
||||
});
|
||||
|
||||
const paginationItemsAfter = Array.from(new Array(correctedUpperPageIndex - correctedPageIndex)).map((k, index) => {
|
||||
const itemIndex = correctedPageIndex + index + 1;
|
||||
return <PagerItem key={itemIndex} index={itemIndex} onClick={setPageIndex}/>
|
||||
});
|
||||
|
||||
return (
|
||||
<Pagination>
|
||||
{
|
||||
correctedLowerPageIndex > 0 ?
|
||||
<Fragment>
|
||||
<PagerItem key={0} index={0} onClick={setPageIndex}/>
|
||||
<Pagination.Ellipsis disabled/>
|
||||
</Fragment>
|
||||
: null
|
||||
}
|
||||
{paginationItemsBefore}
|
||||
<Pagination.Item active>{correctedPageIndex + 1}</Pagination.Item>
|
||||
{paginationItemsAfter}
|
||||
{
|
||||
correctedUpperPageIndex < lastPageIndex ?
|
||||
<Fragment>
|
||||
<Pagination.Ellipsis disabled/>
|
||||
<PagerItem key={lastPageIndex} index={lastPageIndex} onClick={setPageIndex}/>
|
||||
</Fragment>
|
||||
: null
|
||||
}
|
||||
</Pagination>
|
||||
);
|
||||
}
|
24
src/components/pagination/pager.tsx
Normal file
24
src/components/pagination/pager.tsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import React, {Fragment, useEffect} from "react";
|
||||
|
||||
export interface PagerPageProps {
|
||||
pageIndex: number
|
||||
numberOfElementsPerPage: number
|
||||
onLastPageIndexChange: (lastPageIndex: number) => void
|
||||
}
|
||||
|
||||
export const Pager: React.FC<PagerPageProps> = ({children, numberOfElementsPerPage, pageIndex, onLastPageIndexChange}) => {
|
||||
|
||||
useEffect(() => {
|
||||
const lastPageIndex = Math.ceil(React.Children.count(children) / numberOfElementsPerPage) - 1;
|
||||
onLastPageIndexChange(lastPageIndex)
|
||||
}, [children, numberOfElementsPerPage, onLastPageIndexChange])
|
||||
|
||||
return <Fragment>
|
||||
{
|
||||
React.Children.toArray(children).filter((value, index) => {
|
||||
const pageOfElement = Math.floor((index) / numberOfElementsPerPage);
|
||||
return (pageOfElement === pageIndex);
|
||||
})
|
||||
}
|
||||
</Fragment>
|
||||
}
|
Loading…
Reference in a new issue