@frontity/twentytwenty-theme
Version:
The WordPress Twenty Twenty starter theme for Frontity
168 lines (139 loc) • 3.87 kB
JavaScript
import { useEffect } from "react";
import { connect, styled, css } from "frontity";
import Link from "../link";
const paginate = (totalPages, currentPage) => {
const delta = 1;
const pagination = [];
// Push items from "current - 1" (if available) to current + 1 (if available)
for (
let i = Math.max(2, currentPage - delta);
i <= Math.min(totalPages - 1, currentPage + delta);
i++
) {
// if current = 1, total = 7, pagination[] => [2]
// if current = 5, total = 7, pagination[] => [4, 5, 6];
// current = 7, total = 7, pagination[] => [6];
pagination.push(i);
}
// if 3 or more pages exist before current page
// items from 2 to current - 2 will be "..."
if (currentPage - delta > 2) {
// add "..." to the beginning
pagination.unshift("...");
}
// if 3 or more exists after current page
// items from current + 2 to lastPage(totalPage) - 1 will be "..."
if (currentPage + delta < totalPages - 1) {
// add "..." to the end
pagination.push("...");
}
// Always add 1 (first page) to the beginning
pagination.unshift(1);
// Always add totalPage (last page) to the end
pagination.push(totalPages);
return pagination;
};
const Pagination = ({ state, actions, libraries }) => {
const { route, query, totalPages, next, previous, page } = state.source.get(
state.router.link
);
// get page link with page number
const getPageLink = (page) =>
libraries.source.stringify({ route, query, page });
// Pagination - array of numbers/dots for pages
const paginationArray = paginate(totalPages, page);
// Prefetch next page if it hasn't been fetched yet.
useEffect(() => {
if (next) actions.source.fetch(next);
}, []);
return (
<Container>
<Direction>
{previous && (
<StyledLink link={previous}>
← <DirectionItem>Newer</DirectionItem>
</StyledLink>
)}
</Direction>
<div css={inlineBlock}>
<PagingList>
{paginationArray.map((item, index) => {
// if item is dots, "..."
if (item === "...") {
return <PagingItem key={index}>{`...`}</PagingItem>;
}
// if item is current page
if (item === page) {
return <PagingItem key={index}>{item}</PagingItem>;
}
return (
<PagingItem key={index}>
<StyledLink link={getPageLink(item)}>{item}</StyledLink>
</PagingItem>
);
})}
</PagingList>
</div>
<Direction>
{next && (
<StyledLink link={next}>
<DirectionItem>Older</DirectionItem> →
</StyledLink>
)}
</Direction>
</Container>
);
};
const getMaxWidth = (props) => maxWidths[props.size] || maxWidths["medium"];
const maxWidths = {
thin: "58rem",
small: "80rem",
medium: "100rem",
};
const inlineBlock = css`
display: inline-block;
`;
const Container = styled.div`
font-size: 1em;
font-weight: 600;
margin: 0 auto;
line-height: 30px;
width: calc(100% - 4rem);
max-width: ${getMaxWidth};
@media (min-width: 700px) {
display: flex;
align-items: center;
justify-content: space-between;
width: calc(100% - 8rem);
font-size: 1.3em;
font-weight: 700;
}
`;
const PagingList = styled.ul`
list-style: none;
margin: 0 2rem;
`;
const PagingItem = styled.li`
display: inline-block;
margin: 0;
&:not(:last-of-type) {
margin-right: 2rem;
}
`;
const Direction = styled.div`
display: inline-block;
`;
const DirectionItem = styled.span`
@media (min-width: 700px) {
&:after {
content: " Posts";
}
}
`;
const StyledLink = styled(Link)`
text-decoration: none;
&:hover {
text-decoration: underline;
}
`;
export default connect(Pagination);