Blog page search pagination
This commit is contained in:
parent
a48b5f02ba
commit
174d1600b5
|
@ -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',
|
||||
|
|
|
@ -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>),
|
||||
];
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Reference in New Issue