Blog page search pagination

This commit is contained in:
Vince 2021-02-23 18:20:00 +11:00
parent a48b5f02ba
commit 174d1600b5
4 changed files with 84 additions and 55 deletions

View File

@ -33,6 +33,7 @@ export function ArticleCard(props: IPost): JSX.Element {
return (
<div
ref={ref}
style={{ wordBreak: 'break-word' }}
className={classNames(
'overflow-hidden w-full bg-opacity-75',
isSmall ? 'pb-3' : 'pb-1',

View File

@ -8,29 +8,30 @@ import { Contained } from '../Contained';
import { HorizontalScrollable } from '../HorizontalScrollable';
interface Props {
rows?: number;
children: JSX.Element[];
}
export function CardGrid({ children }: Props) {
export function CardGrid({ rows, children }: Props) {
const { isMobile, isDesktop, isHuge } = useContext(ScreenContext);
const [ref, { width }] = useMeasure();
const widthOfCardPx = 200;
const grouping = Math.max(1, Math.min(4, Math.floor(width / widthOfCardPx)));
const numPaddingCards =
Math.ceil(children.length / grouping) * grouping - children.length;
const spacing = isHuge ? 3 : isDesktop ? 6 : 4;
const spacingY = `space-y-${spacing}`;
const spacingX = `space-x-${spacing}`;
// const grouping = isHuge ? 3 : isDesktop ? 2 : isTablet ? 1 : 1;
const numPaddingCards =
Math.ceil(children.length / grouping) * grouping - children.length;
const items =
rows && rows > 0 ? children.slice(0, grouping * rows) : children;
console.log('CardGrid ➡️ grouping:', grouping);
// Add cards to ensure we fill up each row. Hidden where the row is incomplete
// to keep even widths
const cards = [
...children,
...items,
...Array.from(Array(numPaddingCards).keys()).map(i => <div key={i}></div>),
];

View File

@ -23,18 +23,41 @@ export const getServerSideProps: GetServerSideProps = async context => {
const page = Math.ceil(Number(context.query.page ?? 1));
// Fetch posts even when tag, for related etc
const { posts, total } = await api.fetchBlogEntries(
CMS.BLOG_RESULTS_PER_PAGE,
page,
// Pagination only occurs when tag isnt defined.
// If tag is defined, pagination is for tag results
const { posts, total: totalPosts } = await api.fetchBlogEntries(
tag ? 8 : CMS.BLOG_RESULTS_PER_PAGE,
tag ? 1 : page,
);
// Get tags for pagination
let tagPosts = [];
let tagTotalPosts;
if (tag) {
const {
posts: _tagPosts = [],
total: _tagTotalPosts,
} = await api.fetchBlogEntriesByTag(
tag ?? '',
CMS.BLOG_RESULTS_PER_PAGE,
page,
);
tagPosts = _tagPosts;
tagTotalPosts = _tagTotalPosts;
}
const total = tagTotalPosts ?? totalPosts;
const pageCount = Math.floor(total / CMS.BLOG_RESULTS_PER_PAGE);
// Todo, instead of making 2 reqs, filter over 1 req
const tagPosts = tag ? await api.fetchBlogEntriesByTag(tag ?? '') : [];
return {
props: { posts, tagPosts, tag, pageCount, currentPage: page },
props: {
posts,
pageCount,
currentPage: page,
tag,
tagPosts,
},
};
};
@ -76,6 +99,29 @@ const Blog = (props: Props) => {
});
};
const pagination = (
<Contained>
<div className="flex justify-center mb-4">
<div className="mt-4 mobile:mt-6">
<ReactPaginate
previousLabel={'<'}
nextLabel={'>'}
breakLabel={'...'}
breakClassName={'break-me'}
activeClassName={'active bg-secondary'}
containerClassName={'pagination bg-primary text-white front-prompt'}
subContainerClassName={''}
initialPage={currentPage - 1}
pageCount={pageCount}
marginPagesDisplayed={2}
pageRangeDisplayed={5}
onPageChange={paginationHandler}
/>
</div>
</div>
</Contained>
);
return (
<div>
<Head>
@ -102,52 +148,33 @@ const Blog = (props: Props) => {
{/* Tag has posts */}
{tag && tagHasPosts && (
<CardGrid>
{tagPosts?.map(post => (
<ArticleCard key={post.id} {...post} />
))}
</CardGrid>
<>
<CardGrid>
{tagPosts?.map(post => (
<ArticleCard key={post.id} {...post} />
))}
</CardGrid>
{pagination}
</>
)}
<Contained>
{tag && (
<h3 className="mb-1 text-3xl font-prompt text-primary">
<h3 className="-mb-2 text-3xl font-prompt text-primary">
Recent Posts
</h3>
)}
</Contained>
{/* Posts, or recent posts if tag */}
<CardGrid>
{(tag ? posts : otherPosts).slice(0, tag ? 4 : 100)?.map(post => (
<CardGrid rows={2}>
{(tag ? posts : otherPosts)?.map(post => (
<ArticleCard key={post.id} {...post} />
))}
</CardGrid>
<Contained>
<div className="flex justify-center mb-4">
{showPagination && (
<div className="mt-4 mobile:mt-6">
<ReactPaginate
previousLabel={'<'}
nextLabel={'>'}
breakLabel={'...'}
breakClassName={'break-me'}
activeClassName={'active bg-secondary'}
containerClassName={
'pagination bg-primary text-white front-prompt'
}
subContainerClassName={''}
initialPage={currentPage - 1}
pageCount={pageCount}
marginPagesDisplayed={2}
pageRangeDisplayed={5}
onPageChange={paginationHandler}
/>
</div>
)}
</div>
</Contained>
{!tagHasPosts && pagination}
</div>
</div>
);

View File

@ -79,25 +79,25 @@ export class CmsApi {
return null;
}
public async fetchBlogEntriesByTag(tag: string): Promise<IPost[]> {
public async fetchBlogEntriesByTag(
tag: string,
quantity = CMS.BLOG_RESULTS_PER_PAGE,
page = 1,
): Promise<IFetchBlogEntriesReturn> {
const entries = await this.client.getEntries({
content_type: 'post',
'fields.tags[in]': tag,
order: '-fields.date',
'fields.tags[in]': tag,
limit: quantity,
skip: (page - 1) * quantity,
});
console.log(
'cms ➡️ entries:',
Object.values(entries?.items).map(item => (item.fields as any).tags),
);
console.log('cms ➡️ tag:', tag);
if (entries?.items?.length > 0) {
const posts = entries.items.map(entry => this.convertPost(entry));
return posts;
return { posts, total: entries.total };
}
return [];
return { posts: [], total: 0 } as IFetchBlogEntriesReturn;
}
public async fetchPageEntries(): Promise<TPages> {