codenawis-theme
Version:
A frontity theme by @mymakarim @codenawis
216 lines (188 loc) • 5.72 kB
JavaScript
import React, { useEffect } from "react";
import { connect, styled } from "frontity";
import Link from "../link";
const Pagination = ({ state, actions, libraries }) => {
const { totalPages } = state.source.get(state.router.link);
const { path, page, query } = libraries.source.parse(state.router.link);
const isThereNextPage = page < totalPages;
const isTherePreviousPage = page > 1;
/**
* Get the required page link.
*
* @param {int} pageNo Page No.
* @return {string} Post permalink.
*/
const getPageLink = pageNo => {
return libraries.source.stringify({
path,
page: pageNo,
query
});
};
/**
* Create pagination array.
*
* Example: [1, "...", 521, 522, 523, 524, 525, "...", 529]
*
* @param {int} currentPage Current page no.
* @param {int} totalPages Count of total no of pages.
* @return {Array} Array containing the indexes to be looped through to create pagination
*/
const createPaginationArray = (currentPage, totalPages) => {
let loopableArray = [];
let countOfDotItems = 0;
// If there is only one page, return an empty array.
if (1 === totalPages) {
return loopableArray;
}
/**
* Push the two inde items before the current page.
*/
if (0 < currentPage - 2) {
loopableArray.push(currentPage - 2);
}
if (0 < currentPage - 1) {
loopableArray.push(currentPage - 1);
}
// Push the current page index item.
loopableArray.push(currentPage);
/**
* Push the two index items after the current page.
*/
if (totalPages >= currentPage + 1) {
loopableArray.push(currentPage + 1);
}
if (totalPages >= currentPage + 2) {
loopableArray.push(currentPage + 2);
}
/**
* Push the '...' at the beginning of the array
* only if the difference of between the 1st and 2nd index item is greater than 1.
*/
if (1 < loopableArray[0] - 1) {
loopableArray.unshift("...");
countOfDotItems += 1;
}
/**
* Push the '...' at the end of the array.
* only if the difference of between the last and 2nd last item is greater than 1.
* We remove the count of dot items from the array to get the actual indexes, while checking the condition.
*/
if (
1 <
totalPages - loopableArray[loopableArray.length - (2 - countOfDotItems)]
) {
loopableArray.push("...");
}
// Push first index item in the array if it does not already exists.
if (-1 === loopableArray.indexOf(1)) {
loopableArray.unshift(1);
}
// Push last index item in the array if it does not already exists.
if (-1 === loopableArray.indexOf(totalPages)) {
loopableArray.push(totalPages);
}
return loopableArray;
};
const paginationArray = createPaginationArray(page, totalPages);
/**
* Fetch the next page if it hasn't been fetched yet.
*/
useEffect(() => {
if (isThereNextPage) actions.source.fetch(getPageLink(page + 1));
}, []);
return (
<PaginationContainer>
{isTherePreviousPage && (
<PaginationLinks
position="prev"
ariaLabel="Read newer posts"
link={getPageLink(page - 1)}
>
<NavText>← Prev Page</NavText>
</PaginationLinks>
)}
<>
{paginationArray &&
paginationArray.map((item, index) => {
// If item is not equal to '...' and the item value is not equal to current page.
if ("..." !== item && item !== page) {
return (
<React.Fragment key={`${item}-${index}`}>
<PageNumbers link={getPageLink(item)}>
<Text>{item}</Text>
</PageNumbers>
</React.Fragment>
);
} else {
return (
<CurrentOrDots key={`${item}-${index}`} dots={item === "..."}>
<Text>{item}</Text>
</CurrentOrDots>
);
}
})}
</>
{isThereNextPage && (
<PaginationLinks
position="next"
ariaLabel="Read older posts"
link={getPageLink(page + 1)}
>
<NavText>Next Page →</NavText>
</PaginationLinks>
)}
</PaginationContainer>
);
};
export default connect(Pagination);
const CurrentOrDots = styled.span`
display: inline-block;
padding: calc(0.5 * 1rem) ${({ dots }) => (dots ? "0" : "")};
@media (min-width: 768px) {
${({ dots }) => (dots ? "padding: 1rem 0;" : "")}
}
`;
const PageNumbers = styled(Link)`
padding: calc(0.5 * 1rem);
display: inline-block;
@media (min-width: 768px) {
padding: 1rem;
}
:hover {
transition: all .5s;
color: #dc3545;
}
`;
const PaginationLinks = styled(Link)`
display: inline-block;
@media (min-width: 768px) {
padding: 1rem;
${({ position }) =>
position === "next" ? "padding-right: 0;" : "padding-left: 0;"}
}
:hover {
transition: all .5s;
color: #dc3545;
}
`;
const NavText = styled.span`
display: none;
@media (min-width: 768px) {
display: inline-block;
}
`;
const PaginationContainer = styled.div`
padding: 0;
margin: 0 auto;
text-align: center;
font-weight: 700;
font-size: 0.88889em;
letter-spacing: -0.02em;
line-height: 1.2;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
`;
const Text = styled.span`
display: inline-block;
`;